2011-10-10 09:38:02 +00:00
|
|
|
/*
|
2008-04-16 22:40:48 +00:00
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* 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
|
2008-04-16 22:40:48 +00:00
|
|
|
* of the License, or (at your option) any later version.
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* 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,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
2011-10-10 09:38:02 +00:00
|
|
|
* Contributor(s): Reevan McKay
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
2008-04-16 22:40:48 +00:00
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
2002-10-12 11:37:38 +00:00
|
|
|
*/
|
|
|
|
|
2011-02-27 20:40:57 +00:00
|
|
|
/** \file blender/blenkernel/intern/deform.c
|
|
|
|
* \ingroup bke
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#include <string.h>
|
2004-11-06 21:59:35 +00:00
|
|
|
#include <math.h>
|
2010-01-15 17:28:00 +00:00
|
|
|
#include "ctype.h"
|
2004-09-14 19:03:11 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
2004-09-14 19:03:11 +00:00
|
|
|
|
|
|
|
#include "DNA_meshdata_types.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "DNA_object_types.h"
|
2004-09-14 19:03:11 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#include "BKE_deform.h"
|
2004-09-14 19:03:11 +00:00
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
2011-10-27 12:37:14 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
void defgroup_copy_list(ListBase *outbase, ListBase *inbase)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
bDeformGroup *defgroup, *defgroupn;
|
|
|
|
|
2011-02-13 10:52:18 +00:00
|
|
|
outbase->first= outbase->last= NULL;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
for (defgroup = inbase->first; defgroup; defgroup=defgroup->next){
|
2010-01-26 13:50:17 +00:00
|
|
|
defgroupn= defgroup_duplicate(defgroup);
|
2002-10-12 11:37:38 +00:00
|
|
|
BLI_addtail(outbase, defgroupn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
bDeformGroup *defgroup_duplicate(bDeformGroup *ingroup)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
bDeformGroup *outgroup;
|
|
|
|
|
|
|
|
if (!ingroup)
|
|
|
|
return NULL;
|
|
|
|
|
2005-10-20 20:38:08 +00:00
|
|
|
outgroup=MEM_callocN(sizeof(bDeformGroup), "copy deformGroup");
|
2011-11-30 07:39:54 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
/* For now, just copy everything over. */
|
|
|
|
memcpy (outgroup, ingroup, sizeof(bDeformGroup));
|
|
|
|
|
|
|
|
outgroup->next=outgroup->prev=NULL;
|
|
|
|
|
|
|
|
return outgroup;
|
|
|
|
}
|
|
|
|
|
2010-01-26 17:07:47 +00:00
|
|
|
/* copy & overwrite weights */
|
2011-11-30 07:39:54 +00:00
|
|
|
void defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
|
2010-01-15 17:28:00 +00:00
|
|
|
{
|
2011-11-30 07:39:54 +00:00
|
|
|
if (dvert_dst->totweight == dvert_src->totweight) {
|
|
|
|
if (dvert_src->totweight)
|
|
|
|
memcpy(dvert_dst->dw, dvert_src->dw, dvert_src->totweight * sizeof(MDeformWeight));
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-11-30 07:39:54 +00:00
|
|
|
if (dvert_dst->dw)
|
|
|
|
MEM_freeN(dvert_dst->dw);
|
2010-01-15 17:28:00 +00:00
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
if (dvert_src->totweight)
|
|
|
|
dvert_dst->dw= MEM_dupallocN(dvert_src->dw);
|
2010-01-15 17:28:00 +00:00
|
|
|
else
|
2011-11-30 07:39:54 +00:00
|
|
|
dvert_dst->dw= NULL;
|
2010-01-15 17:28:00 +00:00
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
dvert_dst->totweight = dvert_src->totweight;
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-30 07:11:29 +00:00
|
|
|
/* copy an index from one dvert to another
|
|
|
|
* - do nothing if neither are set.
|
|
|
|
* - add destination weight if needed.
|
|
|
|
*/
|
2011-11-30 07:39:54 +00:00
|
|
|
void defvert_copy_index(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const int defgroup)
|
2011-11-30 07:11:29 +00:00
|
|
|
{
|
|
|
|
MDeformWeight *dw_src, *dw_dst;
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
dw_src= defvert_find_index(dvert_src, defgroup);
|
2011-11-30 07:11:29 +00:00
|
|
|
|
|
|
|
if (dw_src) {
|
|
|
|
/* source is valid, verify destination */
|
2011-11-30 07:39:54 +00:00
|
|
|
dw_dst= defvert_verify_index(dvert_dst, defgroup);
|
2011-11-30 07:11:29 +00:00
|
|
|
dw_dst->weight= dw_src->weight;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* source was NULL, assign zero, could also remove */
|
2011-11-30 07:39:54 +00:00
|
|
|
dw_dst= defvert_find_index(dvert_dst, defgroup);
|
2011-11-30 07:11:29 +00:00
|
|
|
|
|
|
|
if (dw_dst) {
|
|
|
|
dw_dst->weight= 0.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-26 17:07:47 +00:00
|
|
|
/* only sync over matching weights, don't add or remove groups
|
|
|
|
* warning, loop within loop.
|
|
|
|
*/
|
2011-11-30 07:39:54 +00:00
|
|
|
void defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, int use_verify)
|
2010-01-26 17:07:47 +00:00
|
|
|
{
|
2011-11-30 07:39:54 +00:00
|
|
|
if (dvert_src->totweight && dvert_dst->totweight) {
|
2010-01-26 17:07:47 +00:00
|
|
|
int i;
|
2011-11-30 07:39:54 +00:00
|
|
|
MDeformWeight *dw_src;
|
|
|
|
for (i=0, dw_src=dvert_src->dw; i < dvert_src->totweight; i++, dw_src++) {
|
|
|
|
MDeformWeight *dw_dst;
|
|
|
|
if (use_verify) dw_dst= defvert_verify_index(dvert_dst, dw_src->def_nr);
|
|
|
|
else dw_dst= defvert_find_index(dvert_dst, dw_src->def_nr);
|
|
|
|
|
|
|
|
if (dw_dst) {
|
|
|
|
dw_dst->weight= dw_src->weight;
|
2010-01-26 17:07:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* be sure all flip_map values are valid */
|
2011-11-30 07:39:54 +00:00
|
|
|
void defvert_sync_mapped(MDeformVert *dvert_dst, const MDeformVert *dvert_src,
|
|
|
|
const int *flip_map, const int flip_map_len, const int use_verify)
|
2010-01-26 17:07:47 +00:00
|
|
|
{
|
2011-11-30 07:39:54 +00:00
|
|
|
if (dvert_src->totweight && dvert_dst->totweight) {
|
2010-01-26 17:07:47 +00:00
|
|
|
int i;
|
2011-11-30 07:39:54 +00:00
|
|
|
MDeformWeight *dw_src;
|
|
|
|
for (i=0, dw_src=dvert_src->dw; i < dvert_src->totweight; i++, dw_src++) {
|
|
|
|
if (dw_src->def_nr < flip_map_len) {
|
|
|
|
MDeformWeight *dw_dst;
|
|
|
|
if (use_verify) dw_dst= defvert_verify_index(dvert_dst, flip_map[dw_src->def_nr]);
|
|
|
|
else dw_dst= defvert_find_index(dvert_dst, flip_map[dw_src->def_nr]);
|
|
|
|
|
|
|
|
if (dw_dst) {
|
|
|
|
dw_dst->weight= dw_src->weight;
|
2011-10-27 07:54:32 +00:00
|
|
|
}
|
2010-01-26 17:07:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-02 21:43:26 +00:00
|
|
|
/* be sure all flip_map values are valid */
|
2011-12-09 08:20:27 +00:00
|
|
|
void defvert_remap(MDeformVert *dvert, int *map, const int map_len)
|
2010-02-02 21:43:26 +00:00
|
|
|
{
|
2011-12-14 21:08:08 +00:00
|
|
|
MDeformWeight *dw= dvert->dw;
|
|
|
|
unsigned int i;
|
|
|
|
for (i= dvert->totweight; i != 0; i--, dw++) {
|
2011-12-09 08:20:27 +00:00
|
|
|
if (dw->def_nr < map_len) {
|
|
|
|
dw->def_nr= map[dw->def_nr];
|
2011-12-14 21:08:08 +00:00
|
|
|
|
|
|
|
/* just incase */
|
|
|
|
BLI_assert(dw->def_nr >= 0);
|
2011-12-09 08:20:27 +00:00
|
|
|
}
|
2010-02-02 21:43:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
void defvert_normalize(MDeformVert *dvert)
|
2010-01-25 23:12:02 +00:00
|
|
|
{
|
2011-12-14 21:08:08 +00:00
|
|
|
if (dvert->totweight <= 0) {
|
2010-01-25 23:12:02 +00:00
|
|
|
/* nothing */
|
|
|
|
}
|
|
|
|
else if (dvert->totweight==1) {
|
|
|
|
dvert->dw[0].weight= 1.0f;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
MDeformWeight *dw;
|
2011-12-14 21:08:08 +00:00
|
|
|
unsigned int i;
|
|
|
|
float tot_weight= 0.0f;
|
|
|
|
|
|
|
|
for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) {
|
|
|
|
tot_weight += dw->weight;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tot_weight > 0.0f) {
|
|
|
|
float scalar= 1.0f / tot_weight;
|
|
|
|
for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) {
|
|
|
|
dw->weight *= scalar;
|
|
|
|
|
|
|
|
/* incase of division errors with very low weights */
|
|
|
|
CLAMP(dw->weight, 0.0f, 1.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void defvert_normalize_lock(MDeformVert *dvert, const int def_nr_lock)
|
|
|
|
{
|
|
|
|
if (dvert->totweight <= 0) {
|
|
|
|
/* nothing */
|
|
|
|
}
|
|
|
|
else if (dvert->totweight==1) {
|
|
|
|
dvert->dw[0].weight= 1.0f;
|
|
|
|
}
|
|
|
|
else {
|
2011-12-17 16:22:08 +00:00
|
|
|
MDeformWeight *dw_lock = NULL;
|
2011-12-14 21:08:08 +00:00
|
|
|
MDeformWeight *dw;
|
|
|
|
unsigned int i;
|
|
|
|
float tot_weight= 0.0f;
|
|
|
|
float lock_iweight= 1.0f;
|
|
|
|
|
|
|
|
for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) {
|
|
|
|
if(dw->def_nr != def_nr_lock) {
|
|
|
|
tot_weight += dw->weight;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
dw_lock= dw;
|
|
|
|
lock_iweight = (1.0f - dw_lock->weight);
|
|
|
|
CLAMP(lock_iweight, 0.0f, 1.0f);
|
|
|
|
}
|
|
|
|
}
|
2010-01-25 23:12:02 +00:00
|
|
|
|
2011-12-14 21:08:08 +00:00
|
|
|
if (tot_weight > 0.0f) {
|
|
|
|
/* paranoid, should be 1.0 but incase of float error clamp anyway */
|
|
|
|
|
|
|
|
float scalar= (1.0f / tot_weight) * lock_iweight;
|
|
|
|
for (i= dvert->totweight, dw= dvert->dw; i != 0; i--, dw++) {
|
|
|
|
if(dw != dw_lock) {
|
|
|
|
dw->weight *= scalar;
|
|
|
|
|
|
|
|
/* incase of division errors with very low weights */
|
|
|
|
CLAMP(dw->weight, 0.0f, 1.0f);
|
|
|
|
}
|
|
|
|
}
|
2010-01-25 23:12:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
void defvert_flip(MDeformVert *dvert, const int *flip_map, const int flip_map_len)
|
2010-01-15 17:28:00 +00:00
|
|
|
{
|
|
|
|
MDeformWeight *dw;
|
|
|
|
int i;
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
for (dw= dvert->dw, i=0; i<dvert->totweight; dw++, i++) {
|
2011-12-09 08:20:27 +00:00
|
|
|
if (dw->def_nr < flip_map_len) {
|
|
|
|
if (flip_map[dw->def_nr] >= 0) {
|
|
|
|
dw->def_nr= flip_map[dw->def_nr];
|
|
|
|
}
|
2011-10-27 07:54:32 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
bDeformGroup *defgroup_find_name(Object *ob, const char *name)
|
2005-01-12 23:57:33 +00:00
|
|
|
{
|
|
|
|
/* return a pointer to the deform group with this name
|
|
|
|
* or return NULL otherwise.
|
|
|
|
*/
|
|
|
|
bDeformGroup *curdef;
|
|
|
|
|
2007-04-27 11:16:35 +00:00
|
|
|
for (curdef = ob->defbase.first; curdef; curdef=curdef->next) {
|
|
|
|
if (!strcmp(curdef->name, name)) {
|
2005-01-12 23:57:33 +00:00
|
|
|
return curdef;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
int defgroup_name_index(Object *ob, const char *name)
|
2007-08-17 11:23:48 +00:00
|
|
|
{
|
|
|
|
/* Return the location of the named deform group within the list of
|
2011-12-14 21:08:08 +00:00
|
|
|
* deform groups. This function is a combination of BLI_findlink and
|
2010-01-26 13:50:17 +00:00
|
|
|
* defgroup_find_name. The other two could be called instead, but that
|
2007-08-17 11:23:48 +00:00
|
|
|
* require looping over the vertexgroups twice.
|
|
|
|
*/
|
|
|
|
bDeformGroup *curdef;
|
|
|
|
int def_nr;
|
2011-11-30 07:39:54 +00:00
|
|
|
|
|
|
|
if (name && name[0] != '\0') {
|
2010-01-26 09:36:33 +00:00
|
|
|
for (curdef=ob->defbase.first, def_nr=0; curdef; curdef=curdef->next, def_nr++) {
|
|
|
|
if (!strcmp(curdef->name, name))
|
|
|
|
return def_nr;
|
|
|
|
}
|
2007-08-17 11:23:48 +00:00
|
|
|
}
|
2010-01-26 09:36:33 +00:00
|
|
|
|
2007-08-17 11:23:48 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-01-15 17:28:00 +00:00
|
|
|
/* note, must be freed */
|
2011-10-27 07:54:32 +00:00
|
|
|
int *defgroup_flip_map(Object *ob, int *flip_map_len, int use_default)
|
2010-01-15 17:28:00 +00:00
|
|
|
{
|
2011-12-09 08:20:27 +00:00
|
|
|
int defbase_tot= *flip_map_len= BLI_countlist(&ob->defbase);
|
2010-01-15 17:28:00 +00:00
|
|
|
|
2011-12-09 08:20:27 +00:00
|
|
|
if (defbase_tot==0) {
|
2010-01-15 17:28:00 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else {
|
2011-11-01 08:11:55 +00:00
|
|
|
bDeformGroup *dg;
|
2010-01-15 17:28:00 +00:00
|
|
|
char name[sizeof(dg->name)];
|
2011-12-09 08:20:27 +00:00
|
|
|
int i, flip_num, *map= MEM_mallocN(defbase_tot * sizeof(int), __func__);
|
2010-01-26 17:07:47 +00:00
|
|
|
|
2011-12-09 08:20:27 +00:00
|
|
|
for (i=0; i < defbase_tot; i++) {
|
2011-11-01 08:11:55 +00:00
|
|
|
map[i]= -1;
|
|
|
|
}
|
2010-01-15 17:28:00 +00:00
|
|
|
|
|
|
|
for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) {
|
2011-11-30 07:39:54 +00:00
|
|
|
if (map[i] == -1) { /* may be calculated previously */
|
2010-01-26 17:07:47 +00:00
|
|
|
|
|
|
|
/* incase no valid value is found, use this */
|
2011-11-30 07:39:54 +00:00
|
|
|
if (use_default)
|
2010-01-26 17:07:47 +00:00
|
|
|
map[i]= i;
|
|
|
|
|
2011-11-01 08:11:55 +00:00
|
|
|
flip_side_name(name, dg->name, FALSE);
|
2011-11-30 07:39:54 +00:00
|
|
|
if (strcmp(name, dg->name)) {
|
2010-01-26 13:50:17 +00:00
|
|
|
flip_num= defgroup_name_index(ob, name);
|
2011-11-30 07:39:54 +00:00
|
|
|
if (flip_num >= 0) {
|
2010-01-15 17:28:00 +00:00
|
|
|
map[i]= flip_num;
|
|
|
|
map[flip_num]= i; /* save an extra lookup */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return map;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-01 08:11:55 +00:00
|
|
|
/* note, must be freed */
|
|
|
|
int *defgroup_flip_map_single(Object *ob, int *flip_map_len, int use_default, int defgroup)
|
|
|
|
{
|
2011-12-09 08:20:27 +00:00
|
|
|
int defbase_tot= *flip_map_len= BLI_countlist(&ob->defbase);
|
2011-11-01 08:11:55 +00:00
|
|
|
|
2011-12-09 08:20:27 +00:00
|
|
|
if (defbase_tot==0) {
|
2011-11-01 08:11:55 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bDeformGroup *dg;
|
|
|
|
char name[sizeof(dg->name)];
|
2011-12-09 08:20:27 +00:00
|
|
|
int i, flip_num, *map= MEM_mallocN(defbase_tot * sizeof(int), __func__);
|
2011-11-01 08:11:55 +00:00
|
|
|
|
2011-12-09 08:20:27 +00:00
|
|
|
for (i=0; i < defbase_tot; i++) {
|
2011-11-01 08:11:55 +00:00
|
|
|
if (use_default) map[i]= i;
|
|
|
|
else map[i]= -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dg= BLI_findlink(&ob->defbase, defgroup);
|
|
|
|
|
|
|
|
flip_side_name(name, dg->name, FALSE);
|
2011-11-30 07:39:54 +00:00
|
|
|
if (strcmp(name, dg->name)) {
|
2011-11-01 08:11:55 +00:00
|
|
|
flip_num= defgroup_name_index(ob, name);
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
if (flip_num >= 0) {
|
2011-11-01 08:11:55 +00:00
|
|
|
map[defgroup]= flip_num;
|
|
|
|
map[flip_num]= defgroup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return map;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-26 17:07:47 +00:00
|
|
|
int defgroup_flip_index(Object *ob, int index, int use_default)
|
|
|
|
{
|
|
|
|
bDeformGroup *dg= BLI_findlink(&ob->defbase, index);
|
|
|
|
int flip_index = -1;
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
if (dg) {
|
2010-01-26 17:07:47 +00:00
|
|
|
char name[sizeof(dg->name)];
|
|
|
|
flip_side_name(name, dg->name, 0);
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
if (strcmp(name, dg->name))
|
2010-01-26 17:07:47 +00:00
|
|
|
flip_index= defgroup_name_index(ob, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (flip_index==-1 && use_default) ? index : flip_index;
|
|
|
|
}
|
|
|
|
|
2010-11-01 07:19:41 +00:00
|
|
|
static int defgroup_find_name_dupe(const char *name, bDeformGroup *dg, Object *ob)
|
2007-04-27 11:16:35 +00:00
|
|
|
{
|
|
|
|
bDeformGroup *curdef;
|
2011-11-30 07:39:54 +00:00
|
|
|
|
2010-11-01 07:19:41 +00:00
|
|
|
for (curdef = ob->defbase.first; curdef; curdef=curdef->next) {
|
|
|
|
if (dg!=curdef) {
|
|
|
|
if (!strcmp(curdef->name, name)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-11-07 08:49:07 +00:00
|
|
|
static int defgroup_unique_check(void *arg, const char *name)
|
|
|
|
{
|
|
|
|
struct {Object *ob; void *dg;} *data= arg;
|
|
|
|
return defgroup_find_name_dupe(name, data->dg, data->ob);
|
|
|
|
}
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
void defgroup_unique_name(bDeformGroup *dg, Object *ob)
|
2010-11-07 08:49:07 +00:00
|
|
|
{
|
|
|
|
struct {Object *ob; void *dg;} data;
|
|
|
|
data.ob= ob;
|
|
|
|
data.dg= dg;
|
2008-07-04 19:56:31 +00:00
|
|
|
|
2010-11-07 08:49:07 +00:00
|
|
|
BLI_uniquename_cb(defgroup_unique_check, &data, "Group", '.', dg->name, sizeof(dg->name));
|
2010-11-01 07:19:41 +00:00
|
|
|
}
|
2010-01-15 17:28:00 +00:00
|
|
|
|
|
|
|
/* finds the best possible flipped name. For renaming; check for unique names afterwards */
|
2011-02-13 13:07:12 +00:00
|
|
|
/* if strip_number: removes number extensions
|
|
|
|
* note: dont use sizeof() for 'name' or 'from_name' */
|
2011-11-30 07:39:54 +00:00
|
|
|
void flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME], int strip_number)
|
2010-01-15 17:28:00 +00:00
|
|
|
{
|
|
|
|
int len;
|
2011-02-13 13:07:12 +00:00
|
|
|
char prefix[MAX_VGROUP_NAME]= ""; /* The part before the facing */
|
|
|
|
char suffix[MAX_VGROUP_NAME]= ""; /* The part after the facing */
|
|
|
|
char replace[MAX_VGROUP_NAME]= ""; /* The replacement string */
|
|
|
|
char number[MAX_VGROUP_NAME]= ""; /* The number extension string */
|
2010-01-15 17:28:00 +00:00
|
|
|
char *index=NULL;
|
|
|
|
|
2011-12-09 07:35:56 +00:00
|
|
|
/* always copy the name, since this can be called with an uninitialized string */
|
2011-02-13 13:07:12 +00:00
|
|
|
BLI_strncpy(name, from_name, MAX_VGROUP_NAME);
|
2010-01-17 16:00:54 +00:00
|
|
|
|
2011-12-09 07:35:56 +00:00
|
|
|
len= BLI_strnlen(from_name, MAX_VGROUP_NAME);
|
|
|
|
if (len < 3) {
|
|
|
|
/* we don't do names like .R or .L */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-01-15 17:28:00 +00:00
|
|
|
/* We first check the case with a .### extension, let's find the last period */
|
2011-11-30 07:39:54 +00:00
|
|
|
if (isdigit(name[len-1])) {
|
2010-01-15 17:28:00 +00:00
|
|
|
index= strrchr(name, '.'); // last occurrence
|
|
|
|
if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
|
2011-11-30 07:39:54 +00:00
|
|
|
if (strip_number==0)
|
2011-04-21 15:53:30 +00:00
|
|
|
BLI_strncpy(number, index, sizeof(number));
|
2010-01-15 17:28:00 +00:00
|
|
|
*index= 0;
|
2011-02-13 13:07:12 +00:00
|
|
|
len= BLI_strnlen(name, MAX_VGROUP_NAME);
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-13 13:07:12 +00:00
|
|
|
BLI_strncpy(prefix, name, sizeof(prefix));
|
2010-01-15 17:28:00 +00:00
|
|
|
|
|
|
|
#define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_')
|
|
|
|
|
|
|
|
/* first case; separator . - _ with extensions r R l L */
|
2011-11-30 07:39:54 +00:00
|
|
|
if (IS_SEPARATOR(name[len-2]) ) {
|
2010-01-15 17:28:00 +00:00
|
|
|
switch(name[len-1]) {
|
|
|
|
case 'l':
|
|
|
|
prefix[len-1]= 0;
|
|
|
|
strcpy(replace, "r");
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
prefix[len-1]= 0;
|
|
|
|
strcpy(replace, "l");
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
prefix[len-1]= 0;
|
|
|
|
strcpy(replace, "R");
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
prefix[len-1]= 0;
|
|
|
|
strcpy(replace, "L");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* case; beginning with r R l L , with separator after it */
|
2011-11-30 07:39:54 +00:00
|
|
|
else if (IS_SEPARATOR(name[1]) ) {
|
2010-01-15 17:28:00 +00:00
|
|
|
switch(name[0]) {
|
|
|
|
case 'l':
|
|
|
|
strcpy(replace, "r");
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_strncpy(suffix, name+1, sizeof(suffix));
|
2010-01-15 17:28:00 +00:00
|
|
|
prefix[0]= 0;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
strcpy(replace, "l");
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_strncpy(suffix, name+1, sizeof(suffix));
|
2010-01-15 17:28:00 +00:00
|
|
|
prefix[0]= 0;
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
strcpy(replace, "R");
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_strncpy(suffix, name+1, sizeof(suffix));
|
2010-01-15 17:28:00 +00:00
|
|
|
prefix[0]= 0;
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
strcpy(replace, "L");
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_strncpy(suffix, name+1, sizeof(suffix));
|
2010-01-15 17:28:00 +00:00
|
|
|
prefix[0]= 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-11-30 07:39:54 +00:00
|
|
|
else if (len > 5) {
|
2010-01-15 17:28:00 +00:00
|
|
|
/* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
|
|
|
|
index = BLI_strcasestr(prefix, "right");
|
|
|
|
if (index==prefix || index==prefix+len-5) {
|
2011-11-30 07:39:54 +00:00
|
|
|
if (index[0]=='r')
|
2012-01-11 12:33:51 +00:00
|
|
|
strcpy(replace, "left");
|
2010-01-15 17:28:00 +00:00
|
|
|
else {
|
2011-11-30 07:39:54 +00:00
|
|
|
if (index[1]=='I')
|
2012-01-11 12:33:51 +00:00
|
|
|
strcpy(replace, "LEFT");
|
2010-01-15 17:28:00 +00:00
|
|
|
else
|
2012-01-11 12:33:51 +00:00
|
|
|
strcpy(replace, "Left");
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
*index= 0;
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_strncpy(suffix, index+5, sizeof(suffix));
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
index = BLI_strcasestr(prefix, "left");
|
|
|
|
if (index==prefix || index==prefix+len-4) {
|
2011-11-30 07:39:54 +00:00
|
|
|
if (index[0]=='l')
|
2012-01-11 12:33:51 +00:00
|
|
|
strcpy(replace, "right");
|
2010-01-15 17:28:00 +00:00
|
|
|
else {
|
2011-11-30 07:39:54 +00:00
|
|
|
if (index[1]=='E')
|
2012-01-11 12:33:51 +00:00
|
|
|
strcpy(replace, "RIGHT");
|
2010-01-15 17:28:00 +00:00
|
|
|
else
|
2012-01-11 12:33:51 +00:00
|
|
|
strcpy(replace, "Right");
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
*index= 0;
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_strncpy(suffix, index + 4, sizeof(suffix));
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef IS_SEPARATOR
|
|
|
|
|
2011-02-13 13:07:12 +00:00
|
|
|
BLI_snprintf (name, MAX_VGROUP_NAME, "%s%s%s%s", prefix, replace, suffix, number);
|
2010-01-15 17:28:00 +00:00
|
|
|
}
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
|
2010-01-26 17:07:47 +00:00
|
|
|
{
|
2011-11-30 07:39:54 +00:00
|
|
|
MDeformWeight *dw= defvert_find_index(dvert, defgroup);
|
2010-01-28 12:16:35 +00:00
|
|
|
return dw ? dw->weight : 0.0f;
|
2010-01-26 17:07:47 +00:00
|
|
|
}
|
2010-01-15 17:28:00 +00:00
|
|
|
|
2011-12-14 22:54:38 +00:00
|
|
|
/* take care with this the rationale is:
|
|
|
|
* - if the object has no vertex group. act like vertex group isnt set and return 1.0,
|
|
|
|
* - if the vertex group exists but the 'defgroup' isnt found on this vertex, _still_ return 0.0
|
|
|
|
*
|
|
|
|
* This is a bit confusing, just saves some checks from the caller.
|
|
|
|
*/
|
2011-11-30 07:39:54 +00:00
|
|
|
float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup)
|
2010-01-26 17:07:47 +00:00
|
|
|
{
|
2011-11-30 07:39:54 +00:00
|
|
|
if (defgroup == -1 || dvert == NULL)
|
2010-01-30 03:47:13 +00:00
|
|
|
return 1.0f;
|
2010-01-15 17:28:00 +00:00
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
return defvert_find_weight(dvert+index, defgroup);
|
2010-01-26 17:07:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-03 01:52:28 +00:00
|
|
|
MDeformWeight *defvert_find_index(const MDeformVert *dvert, const int defgroup)
|
2008-07-04 19:56:31 +00:00
|
|
|
{
|
2011-11-30 07:39:54 +00:00
|
|
|
if (dvert && defgroup >= 0) {
|
2010-01-26 17:07:47 +00:00
|
|
|
MDeformWeight *dw = dvert->dw;
|
2011-12-14 21:08:08 +00:00
|
|
|
unsigned int i;
|
2008-07-04 19:56:31 +00:00
|
|
|
|
2011-12-14 21:08:08 +00:00
|
|
|
for (i= dvert->totweight; i != 0; i--, dw++) {
|
2011-11-30 07:39:54 +00:00
|
|
|
if (dw->def_nr == defgroup) {
|
2010-01-26 17:07:47 +00:00
|
|
|
return dw;
|
2011-11-30 07:39:54 +00:00
|
|
|
}
|
|
|
|
}
|
2008-07-04 19:56:31 +00:00
|
|
|
}
|
|
|
|
|
2010-01-26 17:07:47 +00:00
|
|
|
return NULL;
|
2008-07-04 19:56:31 +00:00
|
|
|
}
|
|
|
|
|
2010-01-26 17:07:47 +00:00
|
|
|
/* Ensures that mv has a deform weight entry for the specified defweight group */
|
|
|
|
/* Note this function is mirrored in editmesh_tools.c, for use for editvertices */
|
2011-11-30 07:39:54 +00:00
|
|
|
MDeformWeight *defvert_verify_index(MDeformVert *dvert, const int defgroup)
|
2008-07-04 19:56:31 +00:00
|
|
|
{
|
2011-11-30 07:39:54 +00:00
|
|
|
MDeformWeight *dw_new;
|
2008-07-04 19:56:31 +00:00
|
|
|
|
2010-01-26 17:07:47 +00:00
|
|
|
/* do this check always, this function is used to check for it */
|
2011-11-30 07:39:54 +00:00
|
|
|
if (!dvert || defgroup < 0)
|
2010-01-26 17:07:47 +00:00
|
|
|
return NULL;
|
2008-07-04 19:56:31 +00:00
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
dw_new= defvert_find_index(dvert, defgroup);
|
|
|
|
if (dw_new)
|
|
|
|
return dw_new;
|
2010-01-26 17:07:47 +00:00
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
dw_new= MEM_callocN(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
|
|
|
|
if (dvert->dw) {
|
|
|
|
memcpy(dw_new, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
|
|
|
|
MEM_freeN(dvert->dw);
|
2010-01-26 17:07:47 +00:00
|
|
|
}
|
2011-11-30 07:39:54 +00:00
|
|
|
dvert->dw= dw_new;
|
|
|
|
dw_new += dvert->totweight;
|
|
|
|
dw_new->weight= 0.0f;
|
|
|
|
dw_new->def_nr= defgroup;
|
2010-01-26 17:07:47 +00:00
|
|
|
/* Group index */
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
dvert->totweight++;
|
|
|
|
|
|
|
|
return dw_new;
|
|
|
|
}
|
2010-01-26 17:07:47 +00:00
|
|
|
|
2011-12-08 03:47:45 +00:00
|
|
|
/* TODO. merge with code above! */
|
|
|
|
|
|
|
|
/* Adds the given vertex to the specified vertex group, with given weight.
|
|
|
|
* warning, this does NOT check for existign, assume caller already knows its not there */
|
|
|
|
void defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weight)
|
2011-11-30 07:39:54 +00:00
|
|
|
{
|
|
|
|
MDeformWeight *dw_new;
|
|
|
|
|
2011-12-08 03:47:45 +00:00
|
|
|
/* do this check always, this function is used to check for it */
|
|
|
|
if (!dvert || defgroup < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dw_new = MEM_callocN(sizeof(MDeformWeight)*(dvert->totweight+1), "defvert_add_to group, new deformWeight");
|
|
|
|
if(dvert->dw) {
|
|
|
|
memcpy(dw_new, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
|
|
|
|
MEM_freeN(dvert->dw);
|
2011-11-30 07:39:54 +00:00
|
|
|
}
|
2011-12-08 03:47:45 +00:00
|
|
|
dvert->dw = dw_new;
|
|
|
|
dw_new += dvert->totweight;
|
|
|
|
dw_new->weight = weight;
|
|
|
|
dw_new->def_nr = defgroup;
|
|
|
|
dvert->totweight++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Removes the given vertex from the vertex group.
|
|
|
|
* WARNING: This function frees the given MDeformWeight, do not use it afterward! */
|
|
|
|
void defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
|
|
|
|
{
|
|
|
|
if (dvert && dw) {
|
|
|
|
MDeformWeight *dw_new;
|
|
|
|
int i = dw - dvert->dw;
|
|
|
|
|
2011-11-30 07:39:54 +00:00
|
|
|
/* Security check! */
|
2011-12-08 03:47:45 +00:00
|
|
|
if(i < 0 || i >= dvert->totweight) {
|
2011-11-30 07:39:54 +00:00
|
|
|
return;
|
2011-12-08 03:47:45 +00:00
|
|
|
}
|
2011-11-30 07:39:54 +00:00
|
|
|
|
2011-12-08 03:47:45 +00:00
|
|
|
dvert->totweight--;
|
|
|
|
/* If there are still other deform weights attached to this vert then remove
|
|
|
|
* this deform weight, and reshuffle the others.
|
|
|
|
*/
|
|
|
|
if (dvert->totweight) {
|
|
|
|
dw_new = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), __func__);
|
2011-12-14 21:08:08 +00:00
|
|
|
if (dvert->dw) {
|
2011-12-14 23:53:46 +00:00
|
|
|
#if 1 /* since we dont care about order, swap this with the last, save a memcpy */
|
|
|
|
if (i != dvert->totweight) {
|
|
|
|
dvert->dw[i]= dvert->dw[dvert->totweight];
|
|
|
|
}
|
|
|
|
memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
|
|
|
|
MEM_freeN(dvert->dw);
|
|
|
|
#else
|
2011-12-08 03:47:45 +00:00
|
|
|
memcpy(dw_new, dvert->dw, sizeof(MDeformWeight)*i);
|
|
|
|
memcpy(dw_new+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i));
|
2011-12-14 23:53:46 +00:00
|
|
|
#endif
|
2011-12-08 03:47:45 +00:00
|
|
|
}
|
|
|
|
dvert->dw = dw_new;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* If there are no other deform weights left then just remove this one. */
|
2011-11-30 07:39:54 +00:00
|
|
|
MEM_freeN(dvert->dw);
|
2011-12-08 03:47:45 +00:00
|
|
|
dvert->dw = NULL;
|
2011-11-30 07:39:54 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-26 17:07:47 +00:00
|
|
|
}
|