811 lines
22 KiB
C++
811 lines
22 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
*/
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLT_translation.h"
|
|
|
|
#include "BLI_ghash.h"
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_string_utils.hh"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "DNA_armature_types.h"
|
|
#include "DNA_cloth_types.h"
|
|
#include "DNA_curve_types.h"
|
|
#include "DNA_gpencil_legacy_types.h"
|
|
#include "DNA_lattice_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_modifier_types.h"
|
|
#include "DNA_object_force_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_particle_types.h"
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "BKE_action.h"
|
|
#include "BKE_deform.h"
|
|
#include "BKE_editmesh.hh"
|
|
#include "BKE_gpencil_legacy.h"
|
|
#include "BKE_mesh.hh"
|
|
#include "BKE_modifier.hh"
|
|
#include "BKE_object.hh"
|
|
#include "BKE_object_deform.h" /* own include */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Misc helpers
|
|
* \{ */
|
|
|
|
static Lattice *object_defgroup_lattice_get(ID *id)
|
|
{
|
|
Lattice *lt = (Lattice *)id;
|
|
BLI_assert(GS(id->name) == ID_LT);
|
|
return (lt->editlatt) ? lt->editlatt->latt : lt;
|
|
}
|
|
|
|
void BKE_object_defgroup_remap_update_users(Object *ob, const int *map)
|
|
{
|
|
/* these cases don't use names to refer to vertex groups, so when
|
|
* they get removed the numbers get out of sync, this corrects that */
|
|
|
|
if (ob->soft) {
|
|
ob->soft->vertgroup = map[ob->soft->vertgroup];
|
|
}
|
|
|
|
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
|
|
if (md->type == eModifierType_Explode) {
|
|
ExplodeModifierData *emd = (ExplodeModifierData *)md;
|
|
emd->vgroup = map[emd->vgroup];
|
|
}
|
|
else if (md->type == eModifierType_Cloth) {
|
|
ClothModifierData *clmd = (ClothModifierData *)md;
|
|
ClothSimSettings *clsim = clmd->sim_parms;
|
|
|
|
if (clsim) {
|
|
clsim->vgroup_mass = map[clsim->vgroup_mass];
|
|
clsim->vgroup_bend = map[clsim->vgroup_bend];
|
|
clsim->vgroup_struct = map[clsim->vgroup_struct];
|
|
}
|
|
}
|
|
}
|
|
|
|
LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
|
|
for (int a = 0; a < PSYS_TOT_VG; a++) {
|
|
psys->vgroup[a] = map[psys->vgroup[a]];
|
|
}
|
|
}
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Group creation
|
|
* \{ */
|
|
|
|
bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
|
|
{
|
|
bDeformGroup *defgroup;
|
|
|
|
if (!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type)) {
|
|
return nullptr;
|
|
}
|
|
|
|
defgroup = BKE_object_defgroup_new(ob, name);
|
|
BKE_object_defgroup_active_index_set(ob, BKE_object_defgroup_count(ob));
|
|
|
|
return defgroup;
|
|
}
|
|
|
|
bDeformGroup *BKE_object_defgroup_add(Object *ob)
|
|
{
|
|
return BKE_object_defgroup_add_name(ob, DATA_("Group"));
|
|
}
|
|
|
|
MDeformVert *BKE_object_defgroup_data_create(ID *id)
|
|
{
|
|
if (GS(id->name) == ID_ME) {
|
|
return BKE_mesh_deform_verts_for_write((Mesh *)id);
|
|
}
|
|
if (GS(id->name) == ID_LT) {
|
|
Lattice *lt = (Lattice *)id;
|
|
lt->dvert = static_cast<MDeformVert *>(MEM_callocN(
|
|
sizeof(MDeformVert) * lt->pntsu * lt->pntsv * lt->pntsw, "lattice deformVert"));
|
|
return lt->dvert;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Group clearing
|
|
* \{ */
|
|
|
|
bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_selection)
|
|
{
|
|
MDeformVert *dv;
|
|
const ListBase *defbase = BKE_object_defgroup_list(ob);
|
|
const int def_nr = BLI_findindex(defbase, dg);
|
|
bool changed = false;
|
|
|
|
if (ob->type == OB_MESH) {
|
|
Mesh *me = static_cast<Mesh *>(ob->data);
|
|
|
|
if (me->edit_mesh) {
|
|
BMEditMesh *em = me->edit_mesh;
|
|
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
|
|
|
|
if (cd_dvert_offset != -1) {
|
|
BMVert *eve;
|
|
BMIter iter;
|
|
|
|
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
|
|
dv = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
|
|
|
|
if (dv && dv->dw && (!use_selection || BM_elem_flag_test(eve, BM_ELEM_SELECT))) {
|
|
MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
|
|
BKE_defvert_remove_group(dv, dw); /* dw can be nullptr */
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (BKE_mesh_deform_verts(me)) {
|
|
const bool *select_vert = (const bool *)CustomData_get_layer_named(
|
|
&me->vert_data, CD_PROP_BOOL, ".select_vert");
|
|
int i;
|
|
|
|
dv = BKE_mesh_deform_verts_for_write(me);
|
|
|
|
for (i = 0; i < me->totvert; i++, dv++) {
|
|
if (dv->dw && (!use_selection || (select_vert && select_vert[i]))) {
|
|
MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
|
|
BKE_defvert_remove_group(dv, dw); /* dw can be nullptr */
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (ob->type == OB_LATTICE) {
|
|
Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
|
|
|
|
if (lt->dvert) {
|
|
BPoint *bp;
|
|
int i, tot = lt->pntsu * lt->pntsv * lt->pntsw;
|
|
|
|
for (i = 0, bp = lt->def; i < tot; i++, bp++) {
|
|
if (!use_selection || (bp->f1 & SELECT)) {
|
|
MDeformWeight *dw;
|
|
|
|
dv = <->dvert[i];
|
|
|
|
dw = BKE_defvert_find_index(dv, def_nr);
|
|
BKE_defvert_remove_group(dv, dw); /* dw can be nullptr */
|
|
changed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
|
|
{
|
|
bool changed = false;
|
|
|
|
const ListBase *defbase = BKE_object_defgroup_list(ob);
|
|
|
|
LISTBASE_FOREACH (bDeformGroup *, dg, defbase) {
|
|
if (BKE_object_defgroup_clear(ob, dg, use_selection)) {
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Group removal
|
|
* \{ */
|
|
|
|
static void object_defgroup_remove_update_users(Object *ob, const int idx)
|
|
{
|
|
int i, defbase_tot = BKE_object_defgroup_count(ob) + 1;
|
|
int *map = static_cast<int *>(MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del"));
|
|
|
|
map[idx] = map[0] = 0;
|
|
for (i = 1; i < idx; i++) {
|
|
map[i] = i;
|
|
}
|
|
for (i = idx + 1; i < defbase_tot; i++) {
|
|
map[i] = i - 1;
|
|
}
|
|
|
|
BKE_object_defgroup_remap_update_users(ob, map);
|
|
MEM_freeN(map);
|
|
}
|
|
|
|
static void object_defgroup_remove_common(Object *ob, bDeformGroup *dg, const int def_nr)
|
|
{
|
|
object_defgroup_remove_update_users(ob, def_nr + 1);
|
|
|
|
/* Remove the group */
|
|
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
|
|
|
|
BLI_freelinkN(defbase, dg);
|
|
|
|
/* Update the active deform index if necessary */
|
|
const int active_index = BKE_object_defgroup_active_index_get(ob);
|
|
if (active_index > def_nr) {
|
|
BKE_object_defgroup_active_index_set(ob, active_index - 1);
|
|
}
|
|
|
|
/* Remove all deform-verts. */
|
|
if (BLI_listbase_is_empty(defbase)) {
|
|
if (ob->type == OB_MESH) {
|
|
Mesh *me = static_cast<Mesh *>(ob->data);
|
|
CustomData_free_layer_active(&me->vert_data, CD_MDEFORMVERT, me->totvert);
|
|
}
|
|
else if (ob->type == OB_LATTICE) {
|
|
Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
|
|
MEM_SAFE_FREE(lt->dvert);
|
|
}
|
|
}
|
|
else if (BKE_object_defgroup_active_index_get(ob) < 1) {
|
|
/* Keep a valid active index if we still have some vgroups. */
|
|
BKE_object_defgroup_active_index_set(ob, 1);
|
|
}
|
|
}
|
|
|
|
static void object_defgroup_remove_object_mode(Object *ob, bDeformGroup *dg)
|
|
{
|
|
MDeformVert *dvert_array = nullptr;
|
|
int dvert_tot = 0;
|
|
const ListBase *defbase = BKE_object_defgroup_list(ob);
|
|
|
|
const int def_nr = BLI_findindex(defbase, dg);
|
|
|
|
BLI_assert(def_nr != -1);
|
|
|
|
BKE_object_defgroup_array_get(static_cast<ID *>(ob->data), &dvert_array, &dvert_tot);
|
|
|
|
if (dvert_array) {
|
|
int i, j;
|
|
MDeformVert *dv;
|
|
for (i = 0, dv = dvert_array; i < dvert_tot; i++, dv++) {
|
|
MDeformWeight *dw;
|
|
|
|
dw = BKE_defvert_find_index(dv, def_nr);
|
|
BKE_defvert_remove_group(dv, dw); /* dw can be nullptr */
|
|
|
|
/* inline, make into a function if anything else needs to do this */
|
|
for (j = 0; j < dv->totweight; j++) {
|
|
if (dv->dw[j].def_nr > def_nr) {
|
|
dv->dw[j].def_nr--;
|
|
}
|
|
}
|
|
/* done */
|
|
}
|
|
}
|
|
|
|
object_defgroup_remove_common(ob, dg, def_nr);
|
|
}
|
|
|
|
static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg)
|
|
{
|
|
int i;
|
|
const ListBase *defbase = BKE_object_defgroup_list(ob);
|
|
const int def_nr = BLI_findindex(defbase, dg);
|
|
|
|
BLI_assert(def_nr != -1);
|
|
|
|
/* Make sure that no verts are using this group - if none were removed,
|
|
* we can skip next per-vert update. */
|
|
if (!BKE_object_defgroup_clear(ob, dg, false)) {
|
|
/* Nothing to do. */
|
|
}
|
|
/* Else, make sure that any groups with higher indices are adjusted accordingly */
|
|
else if (ob->type == OB_MESH) {
|
|
Mesh *me = static_cast<Mesh *>(ob->data);
|
|
BMEditMesh *em = me->edit_mesh;
|
|
const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
|
|
|
|
BMIter iter;
|
|
BMVert *eve;
|
|
MDeformVert *dvert;
|
|
|
|
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
|
|
dvert = static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
|
|
|
|
if (dvert) {
|
|
for (i = 0; i < dvert->totweight; i++) {
|
|
if (dvert->dw[i].def_nr > def_nr) {
|
|
dvert->dw[i].def_nr--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (ob->type == OB_LATTICE) {
|
|
Lattice *lt = ((Lattice *)(ob->data))->editlatt->latt;
|
|
BPoint *bp;
|
|
MDeformVert *dvert = lt->dvert;
|
|
int a, tot;
|
|
|
|
if (dvert) {
|
|
tot = lt->pntsu * lt->pntsv * lt->pntsw;
|
|
for (a = 0, bp = lt->def; a < tot; a++, bp++, dvert++) {
|
|
for (i = 0; i < dvert->totweight; i++) {
|
|
if (dvert->dw[i].def_nr > def_nr) {
|
|
dvert->dw[i].def_nr--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
object_defgroup_remove_common(ob, dg, def_nr);
|
|
}
|
|
|
|
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
|
|
{
|
|
if (ob->type == OB_GPENCIL_LEGACY) {
|
|
BKE_gpencil_vgroup_remove(ob, defgroup);
|
|
}
|
|
else {
|
|
if (BKE_object_is_in_editmode_vgroup(ob)) {
|
|
object_defgroup_remove_edit_mode(ob, defgroup);
|
|
}
|
|
else {
|
|
object_defgroup_remove_object_mode(ob, defgroup);
|
|
}
|
|
|
|
BKE_object_batch_cache_dirty_tag(ob);
|
|
}
|
|
}
|
|
|
|
void BKE_object_defgroup_remove_all_ex(Object *ob, bool only_unlocked)
|
|
{
|
|
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
|
|
|
|
bDeformGroup *dg = (bDeformGroup *)defbase->first;
|
|
const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
|
|
|
|
if (dg) {
|
|
while (dg) {
|
|
bDeformGroup *next_dg = dg->next;
|
|
|
|
if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) {
|
|
if (edit_mode) {
|
|
object_defgroup_remove_edit_mode(ob, dg);
|
|
}
|
|
else {
|
|
object_defgroup_remove_object_mode(ob, dg);
|
|
}
|
|
}
|
|
|
|
dg = next_dg;
|
|
}
|
|
}
|
|
else { /* `defbase` is empty. */
|
|
/* Remove all deform-verts. */
|
|
if (ob->type == OB_MESH) {
|
|
Mesh *me = static_cast<Mesh *>(ob->data);
|
|
CustomData_free_layer_active(&me->vert_data, CD_MDEFORMVERT, me->totvert);
|
|
}
|
|
else if (ob->type == OB_LATTICE) {
|
|
Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
|
|
MEM_SAFE_FREE(lt->dvert);
|
|
}
|
|
/* Fix counters/indices */
|
|
BKE_object_defgroup_active_index_set(ob, 0);
|
|
}
|
|
}
|
|
|
|
void BKE_object_defgroup_remove_all(Object *ob)
|
|
{
|
|
BKE_object_defgroup_remove_all_ex(ob, false);
|
|
}
|
|
|
|
int *BKE_object_defgroup_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
|
|
{
|
|
const ListBase *src_defbase = BKE_object_defgroup_list(ob_src);
|
|
const ListBase *dst_defbase = BKE_object_defgroup_list(ob_dst);
|
|
|
|
/* Build src to merged mapping of vgroup indices. */
|
|
if (BLI_listbase_is_empty(src_defbase) || BLI_listbase_is_empty(dst_defbase)) {
|
|
*r_map_len = 0;
|
|
return nullptr;
|
|
}
|
|
|
|
bDeformGroup *dg_src;
|
|
*r_map_len = BLI_listbase_count(src_defbase);
|
|
int *vgroup_index_map = static_cast<int *>(
|
|
MEM_malloc_arrayN(*r_map_len, sizeof(*vgroup_index_map), "defgroup index map create"));
|
|
bool is_vgroup_remap_needed = false;
|
|
int i;
|
|
|
|
for (dg_src = static_cast<bDeformGroup *>(src_defbase->first), i = 0; dg_src;
|
|
dg_src = dg_src->next, i++)
|
|
{
|
|
vgroup_index_map[i] = BKE_object_defgroup_name_index(ob_dst, dg_src->name);
|
|
is_vgroup_remap_needed = is_vgroup_remap_needed || (vgroup_index_map[i] != i);
|
|
}
|
|
|
|
if (!is_vgroup_remap_needed) {
|
|
MEM_freeN(vgroup_index_map);
|
|
vgroup_index_map = nullptr;
|
|
*r_map_len = 0;
|
|
}
|
|
|
|
return vgroup_index_map;
|
|
}
|
|
|
|
void BKE_object_defgroup_index_map_apply(MDeformVert *dvert,
|
|
int dvert_len,
|
|
const int *map,
|
|
int map_len)
|
|
{
|
|
if (map == nullptr || map_len == 0) {
|
|
return;
|
|
}
|
|
|
|
MDeformVert *dv = dvert;
|
|
for (int i = 0; i < dvert_len; i++, dv++) {
|
|
int totweight = dv->totweight;
|
|
for (int j = 0; j < totweight; j++) {
|
|
int def_nr = dv->dw[j].def_nr;
|
|
if (uint(def_nr) < uint(map_len) && map[def_nr] != -1) {
|
|
dv->dw[j].def_nr = map[def_nr];
|
|
}
|
|
else {
|
|
totweight--;
|
|
dv->dw[j] = dv->dw[totweight];
|
|
j--;
|
|
}
|
|
}
|
|
if (totweight != dv->totweight) {
|
|
if (totweight) {
|
|
dv->dw = static_cast<MDeformWeight *>(MEM_reallocN(dv->dw, sizeof(*dv->dw) * totweight));
|
|
}
|
|
else {
|
|
MEM_SAFE_FREE(dv->dw);
|
|
}
|
|
dv->totweight = totweight;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool BKE_object_defgroup_array_get(ID *id, MDeformVert **dvert_arr, int *dvert_tot)
|
|
{
|
|
if (id) {
|
|
switch (GS(id->name)) {
|
|
case ID_ME: {
|
|
Mesh *me = (Mesh *)id;
|
|
*dvert_arr = BKE_mesh_deform_verts_for_write(me);
|
|
*dvert_tot = me->totvert;
|
|
return true;
|
|
}
|
|
case ID_LT: {
|
|
Lattice *lt = object_defgroup_lattice_get(id);
|
|
*dvert_arr = lt->dvert;
|
|
*dvert_tot = lt->pntsu * lt->pntsv * lt->pntsw;
|
|
return true;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
*dvert_arr = nullptr;
|
|
*dvert_tot = 0;
|
|
return false;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* --- functions for getting vgroup aligned maps --- */
|
|
|
|
bool *BKE_object_defgroup_lock_flags_get(Object *ob, const int defbase_tot)
|
|
{
|
|
bool is_locked = false;
|
|
int i;
|
|
ListBase *defbase = BKE_object_defgroup_list_mutable(ob);
|
|
bool *lock_flags = static_cast<bool *>(MEM_mallocN(defbase_tot * sizeof(bool), "defflags"));
|
|
bDeformGroup *defgroup;
|
|
|
|
for (i = 0, defgroup = static_cast<bDeformGroup *>(defbase->first); i < defbase_tot && defgroup;
|
|
defgroup = defgroup->next, i++)
|
|
{
|
|
lock_flags[i] = ((defgroup->flag & DG_LOCK_WEIGHT) != 0);
|
|
is_locked |= lock_flags[i];
|
|
}
|
|
if (is_locked) {
|
|
return lock_flags;
|
|
}
|
|
|
|
MEM_freeN(lock_flags);
|
|
return nullptr;
|
|
}
|
|
|
|
bool *BKE_object_defgroup_validmap_get(Object *ob, const int defbase_tot)
|
|
{
|
|
bDeformGroup *dg;
|
|
ModifierData *md;
|
|
bool *defgroup_validmap;
|
|
GHash *gh;
|
|
int i, step1 = 1;
|
|
const ListBase *defbase = BKE_object_defgroup_list(ob);
|
|
VirtualModifierData virtual_modifier_data;
|
|
|
|
if (BLI_listbase_is_empty(defbase)) {
|
|
return nullptr;
|
|
}
|
|
|
|
gh = BLI_ghash_str_new_ex(__func__, defbase_tot);
|
|
|
|
/* add all names to a hash table */
|
|
LISTBASE_FOREACH (bDeformGroup *, dg, defbase) {
|
|
BLI_ghash_insert(gh, dg->name, nullptr);
|
|
}
|
|
|
|
BLI_assert(BLI_ghash_len(gh) == defbase_tot);
|
|
|
|
/* now loop through the armature modifiers and identify deform bones */
|
|
for (md = static_cast<ModifierData *>(ob->modifiers.first); md;
|
|
md = !md->next && step1 ? (step1 = 0),
|
|
BKE_modifiers_get_virtual_modifierlist(ob, &virtual_modifier_data) :
|
|
md->next)
|
|
{
|
|
if (!(md->mode & (eModifierMode_Realtime | eModifierMode_Virtual))) {
|
|
continue;
|
|
}
|
|
|
|
if (md->type == eModifierType_Armature) {
|
|
ArmatureModifierData *amd = (ArmatureModifierData *)md;
|
|
|
|
if (amd->object && amd->object->pose) {
|
|
bPose *pose = amd->object->pose;
|
|
|
|
LISTBASE_FOREACH (bPoseChannel *, chan, &pose->chanbase) {
|
|
void **val_p;
|
|
if (chan->bone->flag & BONE_NO_DEFORM) {
|
|
continue;
|
|
}
|
|
|
|
val_p = BLI_ghash_lookup_p(gh, chan->name);
|
|
if (val_p) {
|
|
*val_p = POINTER_FROM_INT(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
defgroup_validmap = static_cast<bool *>(
|
|
MEM_mallocN(sizeof(*defgroup_validmap) * defbase_tot, "wpaint valid map"));
|
|
|
|
/* add all names to a hash table */
|
|
for (dg = static_cast<bDeformGroup *>(defbase->first), i = 0; dg; dg = dg->next, i++) {
|
|
defgroup_validmap[i] = (BLI_ghash_lookup(gh, dg->name) != nullptr);
|
|
}
|
|
|
|
BLI_assert(i == BLI_ghash_len(gh));
|
|
|
|
BLI_ghash_free(gh, nullptr, nullptr);
|
|
|
|
return defgroup_validmap;
|
|
}
|
|
|
|
bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_flags_sel_tot)
|
|
{
|
|
bool *dg_selection = static_cast<bool *>(MEM_mallocN(defbase_tot * sizeof(bool), __func__));
|
|
bDeformGroup *defgroup;
|
|
uint i;
|
|
Object *armob = BKE_object_pose_armature_get(ob);
|
|
(*r_dg_flags_sel_tot) = 0;
|
|
|
|
const ListBase *defbase = BKE_object_defgroup_list(ob);
|
|
|
|
if (armob) {
|
|
bPose *pose = armob->pose;
|
|
for (i = 0, defgroup = static_cast<bDeformGroup *>(defbase->first);
|
|
i < defbase_tot && defgroup;
|
|
defgroup = defgroup->next, i++)
|
|
{
|
|
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, defgroup->name);
|
|
if (pchan && (pchan->bone->flag & BONE_SELECTED)) {
|
|
dg_selection[i] = true;
|
|
(*r_dg_flags_sel_tot) += 1;
|
|
}
|
|
else {
|
|
dg_selection[i] = false;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
memset(dg_selection, false, sizeof(*dg_selection) * defbase_tot);
|
|
}
|
|
|
|
return dg_selection;
|
|
}
|
|
|
|
bool BKE_object_defgroup_check_lock_relative(const bool *lock_flags,
|
|
const bool *validmap,
|
|
int index)
|
|
{
|
|
return validmap && validmap[index] && !(lock_flags && lock_flags[index]);
|
|
}
|
|
|
|
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
|
|
const bool *lock_flags,
|
|
const bool *selected,
|
|
int sel_tot)
|
|
{
|
|
if (lock_flags == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
if (selected == nullptr || sel_tot <= 1) {
|
|
return true;
|
|
}
|
|
|
|
for (int i = 0; i < defbase_tot; i++) {
|
|
if (selected[i] && lock_flags[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool BKE_object_defgroup_active_is_locked(const Object *ob)
|
|
{
|
|
Mesh *me = static_cast<Mesh *>(ob->data);
|
|
bDeformGroup *dg = static_cast<bDeformGroup *>(
|
|
BLI_findlink(&me->vertex_group_names, me->vertex_group_active_index - 1));
|
|
return dg->flag & DG_LOCK_WEIGHT;
|
|
}
|
|
|
|
void BKE_object_defgroup_split_locked_validmap(
|
|
int defbase_tot, const bool *locked, const bool *deform, bool *r_locked, bool *r_unlocked)
|
|
{
|
|
if (!locked) {
|
|
if (r_unlocked != deform) {
|
|
memcpy(r_unlocked, deform, sizeof(bool) * defbase_tot);
|
|
}
|
|
if (r_locked) {
|
|
memset(r_locked, 0, sizeof(bool) * defbase_tot);
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < defbase_tot; i++) {
|
|
bool is_locked = locked[i];
|
|
bool is_deform = deform[i];
|
|
|
|
r_locked[i] = is_deform && is_locked;
|
|
r_unlocked[i] = is_deform && !is_locked;
|
|
}
|
|
}
|
|
|
|
void BKE_object_defgroup_mirror_selection(Object *ob,
|
|
int defbase_tot,
|
|
const bool *dg_selection,
|
|
bool *dg_flags_sel,
|
|
int *r_dg_flags_sel_tot)
|
|
{
|
|
const ListBase *defbase = BKE_object_defgroup_list(ob);
|
|
|
|
bDeformGroup *defgroup;
|
|
uint i;
|
|
int i_mirr;
|
|
|
|
for (i = 0, defgroup = static_cast<bDeformGroup *>(defbase->first); i < defbase_tot && defgroup;
|
|
defgroup = defgroup->next, i++)
|
|
{
|
|
if (dg_selection[i]) {
|
|
char name_flip[MAXBONENAME];
|
|
|
|
BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip));
|
|
i_mirr = STREQ(name_flip, defgroup->name) ? i :
|
|
BKE_object_defgroup_name_index(ob, name_flip);
|
|
|
|
if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) {
|
|
dg_flags_sel[i_mirr] = true;
|
|
(*r_dg_flags_sel_tot) += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
|
|
eVGroupSelect subset_type,
|
|
int *r_defgroup_tot,
|
|
int *r_subset_count)
|
|
{
|
|
bool *defgroup_validmap = nullptr;
|
|
|
|
*r_defgroup_tot = BKE_object_defgroup_count(ob);
|
|
|
|
switch (subset_type) {
|
|
case WT_VGROUP_ACTIVE: {
|
|
const int def_nr_active = BKE_object_defgroup_active_index_get(ob) - 1;
|
|
defgroup_validmap = static_cast<bool *>(
|
|
MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__));
|
|
memset(defgroup_validmap, false, *r_defgroup_tot * sizeof(*defgroup_validmap));
|
|
if ((def_nr_active >= 0) && (def_nr_active < *r_defgroup_tot)) {
|
|
*r_subset_count = 1;
|
|
defgroup_validmap[def_nr_active] = true;
|
|
}
|
|
else {
|
|
*r_subset_count = 0;
|
|
}
|
|
break;
|
|
}
|
|
case WT_VGROUP_BONE_SELECT: {
|
|
defgroup_validmap = BKE_object_defgroup_selected_get(ob, *r_defgroup_tot, r_subset_count);
|
|
break;
|
|
}
|
|
case WT_VGROUP_BONE_DEFORM: {
|
|
int i;
|
|
defgroup_validmap = BKE_object_defgroup_validmap_get(ob, *r_defgroup_tot);
|
|
*r_subset_count = 0;
|
|
for (i = 0; i < *r_defgroup_tot; i++) {
|
|
if (defgroup_validmap[i] == true) {
|
|
*r_subset_count += 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case WT_VGROUP_BONE_DEFORM_OFF: {
|
|
int i;
|
|
defgroup_validmap = BKE_object_defgroup_validmap_get(ob, *r_defgroup_tot);
|
|
*r_subset_count = 0;
|
|
for (i = 0; i < *r_defgroup_tot; i++) {
|
|
defgroup_validmap[i] = !defgroup_validmap[i];
|
|
if (defgroup_validmap[i] == true) {
|
|
*r_subset_count += 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case WT_VGROUP_ALL:
|
|
default: {
|
|
defgroup_validmap = static_cast<bool *>(
|
|
MEM_mallocN(*r_defgroup_tot * sizeof(*defgroup_validmap), __func__));
|
|
memset(defgroup_validmap, true, *r_defgroup_tot * sizeof(*defgroup_validmap));
|
|
*r_subset_count = *r_defgroup_tot;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return defgroup_validmap;
|
|
}
|
|
|
|
void BKE_object_defgroup_subset_to_index_array(const bool *defgroup_validmap,
|
|
const int defgroup_tot,
|
|
int *r_defgroup_subset_map)
|
|
{
|
|
int i, j = 0;
|
|
for (i = 0; i < defgroup_tot; i++) {
|
|
if (defgroup_validmap[i]) {
|
|
r_defgroup_subset_map[j++] = i;
|
|
}
|
|
}
|
|
}
|