This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/blenkernel/intern/object_deform.c
Hans Goudey 3b6ee8cee7 Refactor: Move vertex group names to object data
This commit moves the storage of `bDeformGroup` and the active index
to `Mesh`, `Lattice`, and `bGPdata` instead of `Object`. Utility
functions are added to allow easy access to the vertex groups given
an object or an ID.

As explained in T88951, the list of vertex group names is currently
stored separately per object, even though vertex group data is stored
on the geometry. This tends to complicate code and cause bugs,
especially as geometry is created procedurally and tied less closely
to an object.

The "Copy Vertex Groups to Linked" operator is removed, since they
are stored on the geometry anyway.

This patch leaves the object-level python API for vertex groups in
place. Creating a geometry-level RNA API can be a separate step;
the changes in this commit are invasive enough as it is.

Note that opening a file saved in 3.0 in an earlier version means
the vertex groups will not be available.

Differential Revision: https://developer.blender.org/D11689
2021-07-13 12:10:34 -04:00

896 lines
25 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.
*/
/** \file
* \ingroup bke
*/
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLT_translation.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "DNA_armature_types.h"
#include "DNA_cloth_types.h"
#include "DNA_curve_types.h"
#include "DNA_gpencil_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.h"
#include "BKE_gpencil.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#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;
}
/**
* Update users of vgroups from this object, according to given map.
*
* Use it when you remove or reorder vgroups in the object.
*
* \param map: an array mapping old indices to new indices.
*/
void BKE_object_defgroup_remap_update_users(Object *ob, const int *map)
{
ModifierData *md;
ParticleSystem *psys;
int a;
/* 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];
}
for (md = ob->modifiers.first; md; md = md->next) {
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];
}
}
}
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
for (a = 0; a < PSYS_TOT_VG; a++) {
psys->vgroup[a] = map[psys->vgroup[a]];
}
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Group creation
* \{ */
/**
* Add a vgroup of given name to object. *Does not* handle MDeformVert data at all!
*/
bDeformGroup *BKE_object_defgroup_add_name(Object *ob, const char *name)
{
bDeformGroup *defgroup;
if (!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type)) {
return NULL;
}
defgroup = BKE_object_defgroup_new(ob, name);
BKE_object_defgroup_active_index_set(ob, BKE_object_defgroup_count(ob));
return defgroup;
}
/**
* Add a vgroup of default name to object. *Does not* handle MDeformVert data at all!
*/
bDeformGroup *BKE_object_defgroup_add(Object *ob)
{
return BKE_object_defgroup_add_name(ob, DATA_("Group"));
}
/**
* Create MDeformVert data for given ID. Work in Object mode only.
*/
MDeformVert *BKE_object_defgroup_data_create(ID *id)
{
if (GS(id->name) == ID_ME) {
Mesh *me = (Mesh *)id;
me->dvert = CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
return me->dvert;
}
if (GS(id->name) == ID_LT) {
Lattice *lt = (Lattice *)id;
lt->dvert = MEM_callocN(sizeof(MDeformVert) * lt->pntsu * lt->pntsv * lt->pntsw,
"lattice deformVert");
return lt->dvert;
}
return NULL;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Group clearing
* \{ */
/**
* Remove all verts (or only selected ones) from given vgroup. Work in Object and Edit modes.
*
* \param use_selection: Only operate on selection.
* \return True if any vertex was removed, false otherwise.
*/
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 = 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 = 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 NULL */
changed = true;
}
}
}
}
else {
if (me->dvert) {
MVert *mv;
int i;
mv = me->mvert;
dv = me->dvert;
for (i = 0; i < me->totvert; i++, mv++, dv++) {
if (dv->dw && (!use_selection || (mv->flag & SELECT))) {
MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
BKE_defvert_remove_group(dv, dw); /* dw can be NULL */
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 = &lt->dvert[i];
dw = BKE_defvert_find_index(dv, def_nr);
BKE_defvert_remove_group(dv, dw); /* dw can be NULL */
changed = true;
}
}
}
}
return changed;
}
/**
* Remove all verts (or only selected ones) from all vgroups. Work in Object and Edit modes.
*
* \param use_selection: Only operate on selection.
* \return True if any vertex was removed, false otherwise.
*/
bool BKE_object_defgroup_clear_all(Object *ob, const bool use_selection)
{
bDeformGroup *dg;
bool changed = false;
const ListBase *defbase = BKE_object_defgroup_list(ob);
for (dg = defbase->first; dg; dg = dg->next) {
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 = 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 dverts */
if (BLI_listbase_is_empty(defbase)) {
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
me->dvert = NULL;
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
if (lt->dvert) {
MEM_freeN(lt->dvert);
lt->dvert = NULL;
}
}
}
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 = NULL;
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(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 NULL */
/* 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 = 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 = 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);
}
/**
* Remove given vgroup from object. Work in Object and Edit modes.
*/
void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup)
{
if (ob->type == OB_GPENCIL) {
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);
}
}
/**
* Remove all vgroups from object. Work in Object and Edit modes.
* When only_unlocked=true, locked vertex groups are not removed.
*/
void BKE_object_defgroup_remove_all_ex(struct 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 dverts */
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
me->dvert = NULL;
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = object_defgroup_lattice_get((ID *)(ob->data));
if (lt->dvert) {
MEM_freeN(lt->dvert);
lt->dvert = NULL;
}
}
/* Fix counters/indices */
BKE_object_defgroup_active_index_set(ob, 0);
}
}
/**
* Remove all vgroups from object. Work in Object and Edit modes.
*/
void BKE_object_defgroup_remove_all(struct Object *ob)
{
BKE_object_defgroup_remove_all_ex(ob, false);
}
/**
* Compute mapping for vertex groups with matching name, -1 is used for no remapping.
* Returns null if no remapping is required.
* The returned array has to be freed.
*/
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 NULL;
}
bDeformGroup *dg_src;
*r_map_len = BLI_listbase_count(src_defbase);
int *vgroup_index_map = 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 = 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 = NULL;
*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 == NULL || 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 = MEM_reallocN(dv->dw, sizeof(*dv->dw) * totweight);
}
else {
MEM_SAFE_FREE(dv->dw);
}
dv->totweight = totweight;
}
}
}
/**
* Get MDeformVert vgroup data from given object. Should only be used in Object mode.
*
* \return True if the id type supports weights.
*/
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 = me->dvert;
*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 = NULL;
*dvert_tot = 0;
return false;
}
/** \} */
/* --- functions for getting vgroup aligned maps --- */
/**
* gets the status of "flag" for each bDeformGroup
* in the object data's vertex group list and returns an array containing them
*/
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 = MEM_mallocN(defbase_tot * sizeof(bool), "defflags");
bDeformGroup *defgroup;
for (i = 0, defgroup = 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 NULL;
}
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 virtualModifierData;
if (BLI_listbase_is_empty(defbase)) {
return NULL;
}
gh = BLI_ghash_str_new_ex(__func__, defbase_tot);
/* add all names to a hash table */
for (dg = defbase->first; dg; dg = dg->next) {
BLI_ghash_insert(gh, dg->name, NULL);
}
BLI_assert(BLI_ghash_len(gh) == defbase_tot);
/* now loop through the armature modifiers and identify deform bones */
for (md = ob->modifiers.first; md; md = !md->next && step1 ? (step1 = 0),
BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData) :
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;
bPoseChannel *chan;
for (chan = pose->chanbase.first; chan; chan = chan->next) {
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 = MEM_mallocN(sizeof(*defgroup_validmap) * defbase_tot, "wpaint valid map");
/* add all names to a hash table */
for (dg = defbase->first, i = 0; dg; dg = dg->next, i++) {
defgroup_validmap[i] = (BLI_ghash_lookup(gh, dg->name) != NULL);
}
BLI_assert(i == BLI_ghash_len(gh));
BLI_ghash_free(gh, NULL, NULL);
return defgroup_validmap;
}
/* Returns total selected vgroups,
* wpi.defbase_sel is assumed malloc'd, all values are set */
bool *BKE_object_defgroup_selected_get(Object *ob, int defbase_tot, int *r_dg_flags_sel_tot)
{
bool *dg_selection = MEM_mallocN(defbase_tot * sizeof(bool), __func__);
bDeformGroup *defgroup;
unsigned int 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 = 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;
}
/**
* Checks if the lock relative mode is applicable.
*
* \return true if an unlocked deform group is active.
*/
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]);
}
/**
* Additional check for whether the lock relative mode is applicable in multi-paint mode.
*
* \return true if none of the selected groups are locked.
*/
bool BKE_object_defgroup_check_lock_relative_multi(int defbase_tot,
const bool *lock_flags,
const bool *selected,
int sel_tot)
{
if (lock_flags == NULL) {
return true;
}
if (selected == NULL || sel_tot <= 1) {
return true;
}
for (int i = 0; i < defbase_tot; i++) {
if (selected[i] && lock_flags[i]) {
return false;
}
}
return true;
}
/**
* Takes a pair of boolean masks of all locked and all deform groups, and computes
* a pair of masks for locked deform and unlocked deform groups. Output buffers may
* reuse the input ones.
*/
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;
}
}
/**
* Marks mirror vgroups in output and counts them.
* Output and counter assumed to be already initialized.
* Designed to be usable after BKE_object_defgroup_selected_get to extend selection to mirror.
*/
void BKE_object_defgroup_mirror_selection(struct 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;
unsigned int i;
int i_mirr;
for (i = 0, defgroup = 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;
}
}
}
}
/**
* Return the subset type of the Vertex Group Selection
*/
bool *BKE_object_defgroup_subset_from_select_type(Object *ob,
eVGroupSelect subset_type,
int *r_defgroup_tot,
int *r_subset_count)
{
bool *defgroup_validmap = NULL;
*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 = 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 = 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;
}
/**
* store indices from the defgroup_validmap (faster lookups in some cases)
*/
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;
}
}
}