Merging r46096 through r46110 from trunk into soc-2011-tomato
[blender.git] / source / blender / blenkernel / intern / deform.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Reevan McKay
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenkernel/intern/deform.c
29  *  \ingroup bke
30  */
31
32
33 #include <string.h>
34 #include <math.h>
35 #include <ctype.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_meshdata_types.h"
40 #include "DNA_object_types.h"
41
42 #include "BKE_deform.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_utildefines.h"
46
47
48 void defgroup_copy_list(ListBase *outbase, ListBase *inbase)
49 {
50         bDeformGroup *defgroup, *defgroupn;
51
52         outbase->first = outbase->last = NULL;
53
54         for (defgroup = inbase->first; defgroup; defgroup = defgroup->next) {
55                 defgroupn = defgroup_duplicate(defgroup);
56                 BLI_addtail(outbase, defgroupn);
57         }
58 }
59
60 bDeformGroup *defgroup_duplicate(bDeformGroup *ingroup)
61 {
62         bDeformGroup *outgroup;
63
64         if (!ingroup)
65                 return NULL;
66
67         outgroup = MEM_callocN(sizeof(bDeformGroup), "copy deformGroup");
68
69         /* For now, just copy everything over. */
70         memcpy(outgroup, ingroup, sizeof(bDeformGroup));
71
72         outgroup->next = outgroup->prev = NULL;
73
74         return outgroup;
75 }
76
77 /* copy & overwrite weights */
78 void defvert_copy(MDeformVert *dvert_dst, const MDeformVert *dvert_src)
79 {
80         if (dvert_dst->totweight == dvert_src->totweight) {
81                 if (dvert_src->totweight)
82                         memcpy(dvert_dst->dw, dvert_src->dw, dvert_src->totweight * sizeof(MDeformWeight));
83         }
84         else {
85                 if (dvert_dst->dw)
86                         MEM_freeN(dvert_dst->dw);
87
88                 if (dvert_src->totweight)
89                         dvert_dst->dw = MEM_dupallocN(dvert_src->dw);
90                 else
91                         dvert_dst->dw = NULL;
92
93                 dvert_dst->totweight = dvert_src->totweight;
94         }
95 }
96
97 /* copy an index from one dvert to another
98  * - do nothing if neither are set.
99  * - add destination weight if needed.
100  */
101 void defvert_copy_index(MDeformVert *dvert_dst, const MDeformVert *dvert_src, const int defgroup)
102 {
103         MDeformWeight *dw_src, *dw_dst;
104
105         dw_src = defvert_find_index(dvert_src, defgroup);
106
107         if (dw_src) {
108                 /* source is valid, verify destination */
109                 dw_dst = defvert_verify_index(dvert_dst, defgroup);
110                 dw_dst->weight = dw_src->weight;
111         }
112         else {
113                 /* source was NULL, assign zero, could also remove */
114                 dw_dst = defvert_find_index(dvert_dst, defgroup);
115
116                 if (dw_dst) {
117                         dw_dst->weight = 0.0f;
118                 }
119         }
120 }
121
122 /* only sync over matching weights, don't add or remove groups
123  * warning, loop within loop.
124  */
125 void defvert_sync(MDeformVert *dvert_dst, const MDeformVert *dvert_src, int use_verify)
126 {
127         if (dvert_src->totweight && dvert_dst->totweight) {
128                 int i;
129                 MDeformWeight *dw_src;
130                 for (i = 0, dw_src = dvert_src->dw; i < dvert_src->totweight; i++, dw_src++) {
131                         MDeformWeight *dw_dst;
132                         if (use_verify) dw_dst = defvert_verify_index(dvert_dst, dw_src->def_nr);
133                         else            dw_dst = defvert_find_index(dvert_dst, dw_src->def_nr);
134
135                         if (dw_dst) {
136                                 dw_dst->weight = dw_src->weight;
137                         }
138                 }
139         }
140 }
141
142 /* be sure all flip_map values are valid */
143 void defvert_sync_mapped(MDeformVert *dvert_dst, const MDeformVert *dvert_src,
144                          const int *flip_map, const int flip_map_len, const int use_verify)
145 {
146         if (dvert_src->totweight && dvert_dst->totweight) {
147                 int i;
148                 MDeformWeight *dw_src;
149                 for (i = 0, dw_src = dvert_src->dw; i < dvert_src->totweight; i++, dw_src++) {
150                         if (dw_src->def_nr < flip_map_len) {
151                                 MDeformWeight *dw_dst;
152                                 if (use_verify) dw_dst = defvert_verify_index(dvert_dst, flip_map[dw_src->def_nr]);
153                                 else            dw_dst = defvert_find_index(dvert_dst, flip_map[dw_src->def_nr]);
154
155                                 if (dw_dst) {
156                                         dw_dst->weight = dw_src->weight;
157                                 }
158                         }
159                 }
160         }
161 }
162
163 /* be sure all flip_map values are valid */
164 void defvert_remap(MDeformVert *dvert, int *map, const int map_len)
165 {
166         MDeformWeight *dw = dvert->dw;
167         unsigned int i;
168         for (i = dvert->totweight; i != 0; i--, dw++) {
169                 if (dw->def_nr < map_len) {
170                         dw->def_nr = map[dw->def_nr];
171
172                         /* just in case */
173                         BLI_assert(dw->def_nr >= 0);
174                 }
175         }
176 }
177
178 void defvert_normalize(MDeformVert *dvert)
179 {
180         if (dvert->totweight <= 0) {
181                 /* nothing */
182         }
183         else if (dvert->totweight == 1) {
184                 dvert->dw[0].weight = 1.0f;
185         }
186         else {
187                 MDeformWeight *dw;
188                 unsigned int i;
189                 float tot_weight = 0.0f;
190
191                 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
192                         tot_weight += dw->weight;
193                 }
194
195                 if (tot_weight > 0.0f) {
196                         float scalar = 1.0f / tot_weight;
197                         for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
198                                 dw->weight *= scalar;
199
200                                 /* in case of division errors with very low weights */
201                                 CLAMP(dw->weight, 0.0f, 1.0f);
202                         }
203                 }
204         }
205 }
206
207 void defvert_normalize_lock(MDeformVert *dvert, const int def_nr_lock)
208 {
209         if (dvert->totweight <= 0) {
210                 /* nothing */
211         }
212         else if (dvert->totweight == 1) {
213                 dvert->dw[0].weight = 1.0f;
214         }
215         else {
216                 MDeformWeight *dw_lock = NULL;
217                 MDeformWeight *dw;
218                 unsigned int i;
219                 float tot_weight = 0.0f;
220                 float lock_iweight = 1.0f;
221
222                 for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
223                         if (dw->def_nr != def_nr_lock) {
224                                 tot_weight += dw->weight;
225                         }
226                         else {
227                                 dw_lock = dw;
228                                 lock_iweight = (1.0f - dw_lock->weight);
229                                 CLAMP(lock_iweight, 0.0f, 1.0f);
230                         }
231                 }
232
233                 if (tot_weight > 0.0f) {
234                         /* paranoid, should be 1.0 but in case of float error clamp anyway */
235
236                         float scalar = (1.0f / tot_weight) * lock_iweight;
237                         for (i = dvert->totweight, dw = dvert->dw; i != 0; i--, dw++) {
238                                 if (dw != dw_lock) {
239                                         dw->weight *= scalar;
240
241                                         /* in case of division errors with very low weights */
242                                         CLAMP(dw->weight, 0.0f, 1.0f);
243                                 }
244                         }
245                 }
246         }
247 }
248
249 void defvert_flip(MDeformVert *dvert, const int *flip_map, const int flip_map_len)
250 {
251         MDeformWeight *dw;
252         int i;
253
254         for (dw = dvert->dw, i = 0; i<dvert->totweight; dw++, i++) {
255                 if (dw->def_nr < flip_map_len) {
256                         if (flip_map[dw->def_nr] >= 0) {
257                                 dw->def_nr = flip_map[dw->def_nr];
258                         }
259                 }
260         }
261 }
262
263 void defvert_flip_merged(MDeformVert *dvert, const int *flip_map, const int flip_map_len)
264 {
265         MDeformWeight *dw, *dw_cpy;
266         float weight;
267         int i, totweight = dvert->totweight;
268
269         /* copy weights */
270         for (dw = dvert->dw, i = 0; i < totweight; dw++, i++) {
271                 if (dw->def_nr < flip_map_len) {
272                         if (flip_map[dw->def_nr] >= 0) {
273                                 /* error checkers complain of this but we'll never get NULL return */
274                                 dw_cpy = defvert_verify_index(dvert, flip_map[dw->def_nr]);
275                                 dw = &dvert->dw[i]; /* in case array got realloced */
276
277                                 /* distribute weights: if only one of the vertex groups was
278                                  * assigned this will halve the weights, otherwise it gets
279                                  * evened out. this keeps it proportional to other groups */
280                                 weight = 0.5f * (dw_cpy->weight + dw->weight);
281                                 dw_cpy->weight = weight;
282                                 dw->weight = weight;
283                         }
284                 }
285         }
286 }
287
288 bDeformGroup *defgroup_find_name(Object *ob, const char *name)
289 {
290         /* return a pointer to the deform group with this name
291          * or return NULL otherwise.
292          */
293         bDeformGroup *curdef;
294
295         for (curdef = ob->defbase.first; curdef; curdef = curdef->next) {
296                 if (!strcmp(curdef->name, name)) {
297                         return curdef;
298                 }
299         }
300         return NULL;
301 }
302
303 int defgroup_name_index(Object *ob, const char *name)
304 {
305         /* Return the location of the named deform group within the list of
306          * deform groups. This function is a combination of BLI_findlink and
307          * defgroup_find_name. The other two could be called instead, but that
308          * require looping over the vertexgroups twice.
309          */
310         bDeformGroup *curdef;
311         int def_nr;
312
313         if (name && name[0] != '\0') {
314                 for (curdef = ob->defbase.first, def_nr = 0; curdef; curdef = curdef->next, def_nr++) {
315                         if (!strcmp(curdef->name, name))
316                                 return def_nr;
317                 }
318         }
319
320         return -1;
321 }
322
323 /* note, must be freed */
324 int *defgroup_flip_map(Object *ob, int *flip_map_len, int use_default)
325 {
326         int defbase_tot = *flip_map_len = BLI_countlist(&ob->defbase);
327
328         if (defbase_tot == 0) {
329                 return NULL;
330         }
331         else {
332                 bDeformGroup *dg;
333                 char name[sizeof(dg->name)];
334                 int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);
335
336                 for (i = 0; i < defbase_tot; i++) {
337                         map[i] = -1;
338                 }
339
340                 for (dg = ob->defbase.first, i = 0; dg; dg = dg->next, i++) {
341                         if (map[i] == -1) { /* may be calculated previously */
342
343                                 /* in case no valid value is found, use this */
344                                 if (use_default)
345                                         map[i] = i;
346
347                                 flip_side_name(name, dg->name, FALSE);
348                                 if (strcmp(name, dg->name)) {
349                                         flip_num = defgroup_name_index(ob, name);
350                                         if (flip_num >= 0) {
351                                                 map[i] = flip_num;
352                                                 map[flip_num] = i; /* save an extra lookup */
353                                         }
354                                 }
355                         }
356                 }
357                 return map;
358         }
359 }
360
361 /* note, must be freed */
362 int *defgroup_flip_map_single(Object *ob, int *flip_map_len, int use_default, int defgroup)
363 {
364         int defbase_tot = *flip_map_len = BLI_countlist(&ob->defbase);
365
366         if (defbase_tot == 0) {
367                 return NULL;
368         }
369         else {
370                 bDeformGroup *dg;
371                 char name[sizeof(dg->name)];
372                 int i, flip_num, *map = MEM_mallocN(defbase_tot * sizeof(int), __func__);
373
374                 for (i = 0; i < defbase_tot; i++) {
375                         map[i] = use_default ? i : -1;
376                 }
377
378                 dg = BLI_findlink(&ob->defbase, defgroup);
379
380                 flip_side_name(name, dg->name, FALSE);
381                 if (strcmp(name, dg->name)) {
382                         flip_num = defgroup_name_index(ob, name);
383
384                         if (flip_num >= 0) {
385                                 map[defgroup] = flip_num;
386                                 map[flip_num] = defgroup;
387                         }
388                 }
389
390                 return map;
391         }
392 }
393
394 int defgroup_flip_index(Object *ob, int index, int use_default)
395 {
396         bDeformGroup *dg = BLI_findlink(&ob->defbase, index);
397         int flip_index = -1;
398
399         if (dg) {
400                 char name[sizeof(dg->name)];
401                 flip_side_name(name, dg->name, 0);
402
403                 if (strcmp(name, dg->name))
404                         flip_index = defgroup_name_index(ob, name);
405         }
406
407         return (flip_index == -1 && use_default) ? index : flip_index;
408 }
409
410 static int defgroup_find_name_dupe(const char *name, bDeformGroup *dg, Object *ob)
411 {
412         bDeformGroup *curdef;
413
414         for (curdef = ob->defbase.first; curdef; curdef = curdef->next) {
415                 if (dg != curdef) {
416                         if (!strcmp(curdef->name, name)) {
417                                 return 1;
418                         }
419                 }
420         }
421
422         return 0;
423 }
424
425 static int defgroup_unique_check(void *arg, const char *name)
426 {
427         struct {Object *ob; void *dg;} *data = arg;
428         return defgroup_find_name_dupe(name, data->dg, data->ob);
429 }
430
431 void defgroup_unique_name(bDeformGroup *dg, Object *ob)
432 {
433         struct {Object *ob; void *dg;} data;
434         data.ob = ob;
435         data.dg = dg;
436
437         BLI_uniquename_cb(defgroup_unique_check, &data, "Group", '.', dg->name, sizeof(dg->name));
438 }
439
440 static int is_char_sep(const char c)
441 {
442         return ELEM4(c, '.', ' ', '-', '_');
443 }
444
445 /* based on BLI_split_dirfile() / os.path.splitext(), "a.b.c" -> ("a.b", ".c") */
446
447 void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME], char suf[MAX_VGROUP_NAME])
448 {
449         size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
450         size_t i;
451
452         body[0] = suf[0] = '\0';
453
454         for (i = len - 1; i > 1; i--) {
455                 if (is_char_sep(string[i])) {
456                         BLI_strncpy(body, string, i + 1);
457                         BLI_strncpy(suf, string + i,  (len + 1) - i);
458                         return;
459                 }
460         }
461
462         BLI_strncpy(body, string, len);
463 }
464
465 /* "a.b.c" -> ("a.", "b.c") */
466 void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char pre[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME])
467 {
468         size_t len = BLI_strnlen(string, MAX_VGROUP_NAME);
469         size_t i;
470
471         body[0] = pre[0] = '\0';
472
473         for (i = 1; i < len; i++) {
474                 if (is_char_sep(string[i])) {
475                         i++;
476                         BLI_strncpy(pre, string, i + 1);
477                         BLI_strncpy(body, string + i, (len + 1) - i);
478                         return;
479                 }
480         }
481
482         BLI_strncpy(body, string, len);
483 }
484
485 /* finds the best possible flipped name. For renaming; check for unique names afterwards */
486 /* if strip_number: removes number extensions
487  * note: don't use sizeof() for 'name' or 'from_name' */
488 void flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME], int strip_number)
489 {
490         int     len;
491         char    prefix[MAX_VGROUP_NAME]  = "";   /* The part before the facing */
492         char    suffix[MAX_VGROUP_NAME]  = "";   /* The part after the facing */
493         char    replace[MAX_VGROUP_NAME] = "";   /* The replacement string */
494         char    number[MAX_VGROUP_NAME]  = "";   /* The number extension string */
495         char    *index = NULL;
496
497         /* always copy the name, since this can be called with an uninitialized string */
498         BLI_strncpy(name, from_name, MAX_VGROUP_NAME);
499
500         len = BLI_strnlen(from_name, MAX_VGROUP_NAME);
501         if (len < 3) {
502                 /* we don't do names like .R or .L */
503                 return;
504         }
505
506         /* We first check the case with a .### extension, let's find the last period */
507         if (isdigit(name[len - 1])) {
508                 index = strrchr(name, '.'); // last occurrence
509                 if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever!
510                         if (strip_number == 0) {
511                                 BLI_strncpy(number, index, sizeof(number));
512                         }
513                         *index = 0;
514                         len = BLI_strnlen(name, MAX_VGROUP_NAME);
515                 }
516         }
517
518         BLI_strncpy(prefix, name, sizeof(prefix));
519
520         /* first case; separator . - _ with extensions r R l L  */
521         if (is_char_sep(name[len - 2])) {
522                 switch (name[len - 1]) {
523                         case 'l':
524                                 prefix[len - 1] = 0;
525                                 strcpy(replace, "r");
526                                 break;
527                         case 'r':
528                                 prefix[len - 1] = 0;
529                                 strcpy(replace, "l");
530                                 break;
531                         case 'L':
532                                 prefix[len - 1] = 0;
533                                 strcpy(replace, "R");
534                                 break;
535                         case 'R':
536                                 prefix[len - 1] = 0;
537                                 strcpy(replace, "L");
538                                 break;
539                 }
540         }
541         /* case; beginning with r R l L , with separator after it */
542         else if (is_char_sep(name[1])) {
543                 switch (name[0]) {
544                         case 'l':
545                                 strcpy(replace, "r");
546                                 BLI_strncpy(suffix, name + 1, sizeof(suffix));
547                                 prefix[0] = 0;
548                                 break;
549                         case 'r':
550                                 strcpy(replace, "l");
551                                 BLI_strncpy(suffix, name + 1, sizeof(suffix));
552                                 prefix[0] = 0;
553                                 break;
554                         case 'L':
555                                 strcpy(replace, "R");
556                                 BLI_strncpy(suffix, name + 1, sizeof(suffix));
557                                 prefix[0] = 0;
558                                 break;
559                         case 'R':
560                                 strcpy(replace, "L");
561                                 BLI_strncpy(suffix, name + 1, sizeof(suffix));
562                                 prefix[0] = 0;
563                                 break;
564                 }
565         }
566         else if (len > 5) {
567                 /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
568                 index = BLI_strcasestr(prefix, "right");
569                 if (index == prefix || index == prefix + len - 5) {
570                         if (index[0] == 'r')
571                                 strcpy(replace, "left");
572                         else {
573                                 if (index[1] == 'I')
574                                         strcpy(replace, "LEFT");
575                                 else
576                                         strcpy(replace, "Left");
577                         }
578                         *index = 0;
579                         BLI_strncpy(suffix, index + 5, sizeof(suffix));
580                 }
581                 else {
582                         index = BLI_strcasestr(prefix, "left");
583                         if (index == prefix || index == prefix + len - 4) {
584                                 if (index[0] == 'l')
585                                         strcpy(replace, "right");
586                                 else {
587                                         if (index[1] == 'E')
588                                                 strcpy(replace, "RIGHT");
589                                         else
590                                                 strcpy(replace, "Right");
591                                 }
592                                 *index = 0;
593                                 BLI_strncpy(suffix, index + 4, sizeof(suffix));
594                         }
595                 }
596         }
597
598         BLI_snprintf (name, MAX_VGROUP_NAME, "%s%s%s%s", prefix, replace, suffix, number);
599 }
600
601 float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup)
602 {
603         MDeformWeight *dw = defvert_find_index(dvert, defgroup);
604         return dw ? dw->weight : 0.0f;
605 }
606
607 /* take care with this the rationale is:
608  * - if the object has no vertex group. act like vertex group isn't set and return 1.0,
609  * - if the vertex group exists but the 'defgroup' isn't found on this vertex, _still_ return 0.0
610  *
611  * This is a bit confusing, just saves some checks from the caller.
612  */
613 float defvert_array_find_weight_safe(const struct MDeformVert *dvert, const int index, const int defgroup)
614 {
615         if (defgroup == -1 || dvert == NULL)
616                 return 1.0f;
617
618         return defvert_find_weight(dvert + index, defgroup);
619 }
620
621
622 MDeformWeight *defvert_find_index(const MDeformVert *dvert, const int defgroup)
623 {
624         if (dvert && defgroup >= 0) {
625                 MDeformWeight *dw = dvert->dw;
626                 unsigned int i;
627
628                 for (i = dvert->totweight; i != 0; i--, dw++) {
629                         if (dw->def_nr == defgroup) {
630                                 return dw;
631                         }
632                 }
633         }
634
635         return NULL;
636 }
637
638 /* Ensures that mv has a deform weight entry for the specified defweight group */
639 /* Note this function is mirrored in editmesh_tools.c, for use for editvertices */
640 MDeformWeight *defvert_verify_index(MDeformVert *dvert, const int defgroup)
641 {
642         MDeformWeight *dw_new;
643
644         /* do this check always, this function is used to check for it */
645         if (!dvert || defgroup < 0)
646                 return NULL;
647
648         dw_new = defvert_find_index(dvert, defgroup);
649         if (dw_new)
650                 return dw_new;
651
652         dw_new = MEM_callocN(sizeof(MDeformWeight) * (dvert->totweight + 1), "deformWeight");
653         if (dvert->dw) {
654                 memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
655                 MEM_freeN(dvert->dw);
656         }
657         dvert->dw = dw_new;
658         dw_new += dvert->totweight;
659         dw_new->weight = 0.0f;
660         dw_new->def_nr = defgroup;
661         /* Group index */
662
663         dvert->totweight++;
664
665         return dw_new;
666 }
667
668 /* TODO. merge with code above! */
669
670 /* Adds the given vertex to the specified vertex group, with given weight.
671  * warning, this does NOT check for existing, assume caller already knows its not there */
672 void defvert_add_index_notest(MDeformVert *dvert, int defgroup, const float weight)
673 {
674         MDeformWeight *dw_new;
675
676         /* do this check always, this function is used to check for it */
677         if (!dvert || defgroup < 0)
678                 return;
679
680         dw_new = MEM_callocN(sizeof(MDeformWeight) * (dvert->totweight + 1), "defvert_add_to group, new deformWeight");
681         if (dvert->dw) {
682                 memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
683                 MEM_freeN(dvert->dw);
684         }
685         dvert->dw = dw_new;
686         dw_new += dvert->totweight;
687         dw_new->weight = weight;
688         dw_new->def_nr = defgroup;
689         dvert->totweight++;
690 }
691
692
693 /* Removes the given vertex from the vertex group.
694  * WARNING: This function frees the given MDeformWeight, do not use it afterward! */
695 void defvert_remove_group(MDeformVert *dvert, MDeformWeight *dw)
696 {
697         if (dvert && dw) {
698                 MDeformWeight *dw_new;
699                 int i = dw - dvert->dw;
700
701                 /* Security check! */
702                 if (i < 0 || i >= dvert->totweight) {
703                         return;
704                 }
705
706                 dvert->totweight--;
707                 /* If there are still other deform weights attached to this vert then remove
708                  * this deform weight, and reshuffle the others.
709                  */
710                 if (dvert->totweight) {
711                         dw_new = MEM_mallocN(sizeof(MDeformWeight) * (dvert->totweight), __func__);
712                         if (dvert->dw) {
713 #if 1                   /* since we don't care about order, swap this with the last, save a memcpy */
714                                 if (i != dvert->totweight) {
715                                         dvert->dw[i] = dvert->dw[dvert->totweight];
716                                 }
717                                 memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * dvert->totweight);
718 #else
719                                 memcpy(dw_new, dvert->dw, sizeof(MDeformWeight) * i);
720                                 memcpy(dw_new + i, dvert->dw + i + 1, sizeof(MDeformWeight) * (dvert->totweight - i));
721 #endif
722                                 MEM_freeN(dvert->dw);
723                         }
724                         dvert->dw = dw_new;
725                 }
726                 else {
727                         /* If there are no other deform weights left then just remove this one. */
728                         MEM_freeN(dvert->dw);
729                         dvert->dw = NULL;
730                 }
731         }
732 }
733
734 void defvert_clear(MDeformVert *dvert)
735 {
736         if (dvert->dw) {
737                 MEM_freeN(dvert->dw);
738                 dvert->dw = NULL;
739         }
740
741         dvert->totweight = 0;
742 }