Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <string.h> 00034 #include <stddef.h> 00035 #include <math.h> 00036 #include <assert.h> 00037 00038 #include "MEM_guardedalloc.h" 00039 00040 #include "DNA_cloth_types.h" 00041 #include "DNA_curve_types.h" 00042 #include "DNA_lattice_types.h" 00043 #include "DNA_meshdata_types.h" 00044 #include "DNA_modifier_types.h" 00045 #include "DNA_object_types.h" 00046 #include "DNA_object_force.h" 00047 #include "DNA_scene_types.h" 00048 #include "DNA_particle_types.h" 00049 00050 #include "BLI_math.h" 00051 #include "BLI_blenlib.h" 00052 #include "BLI_editVert.h" 00053 #include "BLI_utildefines.h" 00054 00055 #include "BKE_context.h" 00056 #include "BKE_customdata.h" 00057 #include "BKE_deform.h" 00058 #include "BKE_depsgraph.h" 00059 #include "BKE_global.h" 00060 #include "BKE_mesh.h" 00061 #include "BKE_report.h" 00062 #include "BKE_DerivedMesh.h" 00063 00064 #include "RNA_access.h" 00065 #include "RNA_define.h" 00066 00067 #include "WM_api.h" 00068 #include "WM_types.h" 00069 00070 #include "ED_object.h" 00071 #include "ED_mesh.h" 00072 00073 #include "UI_resources.h" 00074 00075 #include "object_intern.h" 00076 00077 /************************ Exported Functions **********************/ 00078 static void vgroup_remap_update_users(Object *ob, int *map); 00079 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *defgroup); 00080 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg); 00081 static void vgroup_delete_all(Object *ob); 00082 00083 static Lattice *vgroup_edit_lattice(Object *ob) 00084 { 00085 Lattice *lt= ob->data; 00086 BLI_assert(ob->type==OB_LATTICE); 00087 return (lt->editlatt)? lt->editlatt->latt: lt; 00088 } 00089 00090 int ED_vgroup_object_is_edit_mode(Object *ob) 00091 { 00092 if(ob->type == OB_MESH) 00093 return (((Mesh*)ob->data)->edit_mesh != NULL); 00094 else if(ob->type == OB_LATTICE) 00095 return (((Lattice*)ob->data)->editlatt != NULL); 00096 00097 return 0; 00098 } 00099 00100 bDeformGroup *ED_vgroup_add_name(Object *ob, const char *name) 00101 { 00102 bDeformGroup *defgroup; 00103 00104 if(!ob || !OB_TYPE_SUPPORT_VGROUP(ob->type)) 00105 return NULL; 00106 00107 defgroup = MEM_callocN(sizeof(bDeformGroup), "add deformGroup"); 00108 00109 BLI_strncpy(defgroup->name, name, sizeof(defgroup->name)); 00110 00111 BLI_addtail(&ob->defbase, defgroup); 00112 defgroup_unique_name(defgroup, ob); 00113 00114 ob->actdef = BLI_countlist(&ob->defbase); 00115 00116 return defgroup; 00117 } 00118 00119 bDeformGroup *ED_vgroup_add(Object *ob) 00120 { 00121 return ED_vgroup_add_name(ob, "Group"); 00122 } 00123 00124 void ED_vgroup_delete(Object *ob, bDeformGroup *defgroup) 00125 { 00126 bDeformGroup *dg = (bDeformGroup *)ob->defbase.first; 00127 00128 while (dg) { 00129 if (dg == defgroup) 00130 break; 00131 dg = dg->next; 00132 } 00133 00134 if (dg == NULL) 00135 return; 00136 00137 if(ED_vgroup_object_is_edit_mode(ob)) 00138 vgroup_delete_edit_mode(ob, dg); 00139 else 00140 vgroup_delete_object_mode(ob, dg); 00141 } 00142 00143 void ED_vgroup_clear(Object *ob) 00144 { 00145 bDeformGroup *dg= (bDeformGroup *)ob->defbase.first; 00146 int edit_mode= ED_vgroup_object_is_edit_mode(ob); 00147 00148 while (dg) { 00149 bDeformGroup *next_dg= dg->next; 00150 00151 if(edit_mode) 00152 vgroup_delete_edit_mode(ob, dg); 00153 else 00154 vgroup_delete_object_mode(ob, dg); 00155 00156 dg= next_dg; 00157 } 00158 } 00159 00160 int ED_vgroup_data_create(ID *id) 00161 { 00162 /* create deform verts */ 00163 00164 if(GS(id->name)==ID_ME) { 00165 Mesh *me= (Mesh *)id; 00166 me->dvert= CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert); 00167 return TRUE; 00168 } 00169 else if(GS(id->name)==ID_LT) { 00170 Lattice *lt= (Lattice *)id; 00171 lt->dvert= MEM_callocN(sizeof(MDeformVert)*lt->pntsu*lt->pntsv*lt->pntsw, "lattice deformVert"); 00172 return TRUE; 00173 } 00174 else { 00175 return FALSE; 00176 } 00177 } 00178 00179 static int ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_tot, const short use_vert_sel) 00180 { 00181 *dvert_tot = 0; 00182 *dvert_arr = NULL; 00183 00184 if(id) { 00185 switch(GS(id->name)) { 00186 case ID_ME: 00187 { 00188 Mesh *me = (Mesh *)id; 00189 00190 if(me->edit_mesh) { 00191 EditMesh *em = me->edit_mesh; 00192 EditVert *eve; 00193 int i; 00194 00195 if (!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) { 00196 return 0; 00197 } 00198 00199 i= BLI_countlist(&em->verts); 00200 00201 *dvert_arr= MEM_mallocN(sizeof(void*)*i, "vgroup parray from me"); 00202 *dvert_tot = i; 00203 00204 i = 0; 00205 00206 if (use_vert_sel) { 00207 for (eve=em->verts.first; eve; eve=eve->next, i++) { 00208 (*dvert_arr)[i] = (eve->f & SELECT) ? 00209 CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT) : NULL; 00210 } 00211 } 00212 else { 00213 for (eve=em->verts.first; eve; eve=eve->next, i++) { 00214 (*dvert_arr)[i] = CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); 00215 } 00216 } 00217 00218 return 1; 00219 } 00220 else if(me->dvert) { 00221 MVert *mvert= me->mvert; 00222 MDeformVert *dvert= me->dvert; 00223 int i; 00224 00225 *dvert_tot= me->totvert; 00226 *dvert_arr= MEM_mallocN(sizeof(void*)*me->totvert, "vgroup parray from me"); 00227 00228 if (use_vert_sel) { 00229 for (i=0; i<me->totvert; i++) { 00230 (*dvert_arr)[i] = (mvert[i].flag & SELECT) ? 00231 &dvert[i] : NULL; 00232 } 00233 } 00234 else { 00235 for (i=0; i<me->totvert; i++) { 00236 (*dvert_arr)[i] = me->dvert + i; 00237 } 00238 } 00239 00240 return 1; 00241 } 00242 else { 00243 return 0; 00244 } 00245 } 00246 case ID_LT: 00247 { 00248 int i=0; 00249 00250 Lattice *lt= (Lattice *)id; 00251 lt= (lt->editlatt)? lt->editlatt->latt: lt; 00252 00253 if(lt->dvert) { 00254 BPoint *def= lt->def; 00255 *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw; 00256 *dvert_arr= MEM_mallocN(sizeof(void*)*(*dvert_tot), "vgroup parray from me"); 00257 00258 if (use_vert_sel) { 00259 for (i=0; i<*dvert_tot; i++) { 00260 (*dvert_arr)[i] = (def->f1 & SELECT) ? 00261 <->dvert[i] : NULL; 00262 } 00263 } 00264 else { 00265 for (i=0; i<*dvert_tot; i++) { 00266 (*dvert_arr)[i] = lt->dvert + i; 00267 } 00268 } 00269 00270 return 1; 00271 } 00272 else { 00273 return 0; 00274 } 00275 } 00276 } 00277 } 00278 00279 return 0; 00280 } 00281 00282 /* returns true if the id type supports weights */ 00283 int ED_vgroup_give_array(ID *id, MDeformVert **dvert_arr, int *dvert_tot) 00284 { 00285 if(id) { 00286 switch(GS(id->name)) { 00287 case ID_ME: 00288 { 00289 Mesh *me = (Mesh *)id; 00290 *dvert_arr= me->dvert; 00291 *dvert_tot= me->totvert; 00292 return TRUE; 00293 } 00294 case ID_LT: 00295 { 00296 Lattice *lt= (Lattice *)id; 00297 lt= (lt->editlatt)? lt->editlatt->latt: lt; 00298 *dvert_arr= lt->dvert; 00299 *dvert_tot= lt->pntsu*lt->pntsv*lt->pntsw; 00300 return TRUE; 00301 } 00302 } 00303 } 00304 00305 *dvert_arr= NULL; 00306 *dvert_tot= 0; 00307 return FALSE; 00308 } 00309 00310 /* matching index only */ 00311 int ED_vgroup_copy_array(Object *ob, Object *ob_from) 00312 { 00313 MDeformVert **dvert_array_from, **dvf; 00314 MDeformVert **dvert_array, **dv; 00315 int dvert_tot_from; 00316 int dvert_tot; 00317 int i; 00318 int defbase_tot_from= BLI_countlist(&ob_from->defbase); 00319 int defbase_tot= BLI_countlist(&ob->defbase); 00320 short new_vgroup= FALSE; 00321 00322 ED_vgroup_give_parray(ob_from->data, &dvert_array_from, &dvert_tot_from, FALSE); 00323 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, FALSE); 00324 00325 if((dvert_array == NULL) && (dvert_array_from != NULL) && ED_vgroup_data_create(ob->data)) { 00326 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, FALSE); 00327 new_vgroup= TRUE; 00328 } 00329 00330 if(ob==ob_from || dvert_tot==0 || (dvert_tot != dvert_tot_from) || dvert_array_from==NULL || dvert_array==NULL) { 00331 if (dvert_array) MEM_freeN(dvert_array); 00332 if (dvert_array_from) MEM_freeN(dvert_array_from); 00333 00334 if(new_vgroup == TRUE) { 00335 /* free the newly added vgroup since it wasn't compatible */ 00336 vgroup_delete_all(ob); 00337 } 00338 return 0; 00339 } 00340 00341 /* do the copy */ 00342 BLI_freelistN(&ob->defbase); 00343 BLI_duplicatelist(&ob->defbase, &ob_from->defbase); 00344 ob->actdef= ob_from->actdef; 00345 00346 if(defbase_tot_from < defbase_tot) { 00347 /* correct vgroup indices because the number of vgroups is being reduced. */ 00348 int *remap= MEM_mallocN(sizeof(int) * (defbase_tot + 1), __func__); 00349 for(i=0; i<=defbase_tot_from; i++) remap[i]= i; 00350 for(; i<=defbase_tot; i++) remap[i]= 0; /* can't use these, so disable */ 00351 00352 vgroup_remap_update_users(ob, remap); 00353 MEM_freeN(remap); 00354 } 00355 00356 dvf= dvert_array_from; 00357 dv= dvert_array; 00358 00359 for(i=0; i<dvert_tot; i++, dvf++, dv++) { 00360 if((*dv)->dw) 00361 MEM_freeN((*dv)->dw); 00362 00363 *(*dv)= *(*dvf); 00364 00365 if((*dv)->dw) 00366 (*dv)->dw= MEM_dupallocN((*dv)->dw); 00367 } 00368 00369 MEM_freeN(dvert_array); 00370 MEM_freeN(dvert_array_from); 00371 00372 return 1; 00373 } 00374 00375 00376 /* for Mesh in Object mode */ 00377 /* allows editmode for Lattice */ 00378 static void ED_vgroup_nr_vert_add(Object *ob, 00379 const int def_nr, const int vertnum, 00380 const float weight, const int assignmode) 00381 { 00382 /* add the vert to the deform group with the 00383 * specified number 00384 */ 00385 MDeformVert *dvert= NULL; 00386 int tot; 00387 00388 /* get the vert */ 00389 ED_vgroup_give_array(ob->data, &dvert, &tot); 00390 00391 if(dvert==NULL) 00392 return; 00393 00394 /* check that vertnum is valid before trying to get the relevant dvert */ 00395 if ((vertnum < 0) || (vertnum >= tot)) 00396 return; 00397 00398 00399 if (dvert) { 00400 MDeformVert *dv= &dvert[vertnum]; 00401 MDeformWeight *dw; 00402 00403 /* Lets first check to see if this vert is 00404 * already in the weight group -- if so 00405 * lets update it 00406 */ 00407 00408 dw= defvert_find_index(dv, def_nr); 00409 00410 if (dw) { 00411 switch(assignmode) { 00412 case WEIGHT_REPLACE: 00413 dw->weight = weight; 00414 break; 00415 case WEIGHT_ADD: 00416 dw->weight += weight; 00417 if(dw->weight >= 1.0f) 00418 dw->weight = 1.0f; 00419 break; 00420 case WEIGHT_SUBTRACT: 00421 dw->weight -= weight; 00422 /* if the weight is zero or less then 00423 * remove the vert from the deform group 00424 */ 00425 if(dw->weight <= 0.0f) { 00426 defvert_remove_group(dv, dw); 00427 } 00428 break; 00429 } 00430 } 00431 else { 00432 /* if the vert wasn't in the deform group then 00433 * we must take a different form of action ... 00434 */ 00435 00436 switch(assignmode) { 00437 case WEIGHT_SUBTRACT: 00438 /* if we are subtracting then we don't 00439 * need to do anything 00440 */ 00441 return; 00442 00443 case WEIGHT_REPLACE: 00444 case WEIGHT_ADD: 00445 /* if we are doing an additive assignment, then 00446 * we need to create the deform weight 00447 */ 00448 00449 /* we checked if the vertex was added before so no need to test again, simply add */ 00450 defvert_add_index_notest(dv, def_nr, weight); 00451 } 00452 } 00453 } 00454 } 00455 00456 /* called while not in editmode */ 00457 void ED_vgroup_vert_add(Object *ob, bDeformGroup *dg, int vertnum, float weight, int assignmode) 00458 { 00459 /* add the vert to the deform group with the 00460 * specified assign mode 00461 */ 00462 const int def_nr= BLI_findindex(&ob->defbase, dg); 00463 00464 MDeformVert *dv= NULL; 00465 int tot; 00466 00467 /* get the deform group number, exit if 00468 * it can't be found 00469 */ 00470 if(def_nr < 0) return; 00471 00472 /* if there's no deform verts then create some, 00473 */ 00474 if(ED_vgroup_give_array(ob->data, &dv, &tot) && dv==NULL) 00475 ED_vgroup_data_create(ob->data); 00476 00477 /* call another function to do the work 00478 */ 00479 ED_vgroup_nr_vert_add(ob, def_nr, vertnum, weight, assignmode); 00480 } 00481 00482 /* mesh object mode, lattice can be in editmode */ 00483 void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum) 00484 { 00485 /* This routine removes the vertex from the specified 00486 * deform group. 00487 */ 00488 00489 /* TODO, this is slow in a loop, better pass def_nr directly, but leave for later... - campbell */ 00490 const int def_nr= BLI_findindex(&ob->defbase, dg); 00491 00492 if(def_nr != -1) { 00493 MDeformVert *dvert= NULL; 00494 int tot; 00495 00496 /* get the deform vertices corresponding to the 00497 * vertnum 00498 */ 00499 ED_vgroup_give_array(ob->data, &dvert, &tot); 00500 00501 if(dvert) { 00502 MDeformVert *dv= &dvert[vertnum]; 00503 MDeformWeight *dw; 00504 00505 dw= defvert_find_index(dv, def_nr); 00506 defvert_remove_group(dv, dw); /* dw can be NULL */ 00507 } 00508 } 00509 } 00510 00511 static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum) 00512 { 00513 MDeformVert *dv= NULL; 00514 EditVert *eve; 00515 Mesh *me; 00516 00517 /* get the deform vertices corresponding to the vertnum */ 00518 if(ob->type==OB_MESH) { 00519 me= ob->data; 00520 00521 if(me->edit_mesh) { 00522 eve= BLI_findlink(&me->edit_mesh->verts, vertnum); 00523 if(!eve) { 00524 return 0.0f; 00525 } 00526 dv= CustomData_em_get(&me->edit_mesh->vdata, eve->data, CD_MDEFORMVERT); 00527 } 00528 else { 00529 if(vertnum >= me->totvert) { 00530 return 0.0f; 00531 } 00532 dv = &me->dvert[vertnum]; 00533 } 00534 } 00535 else if(ob->type==OB_LATTICE) { 00536 Lattice *lt= vgroup_edit_lattice(ob); 00537 00538 if(lt->dvert) { 00539 if(vertnum >= lt->pntsu*lt->pntsv*lt->pntsw) { 00540 return 0.0f; 00541 } 00542 dv = <->dvert[vertnum]; 00543 } 00544 } 00545 00546 if (dv) { 00547 MDeformWeight *dw= defvert_find_index(dv, def_nr); 00548 if (dw) { 00549 return dw->weight; 00550 } 00551 } 00552 00553 return -1; 00554 } 00555 00556 float ED_vgroup_vert_weight(Object *ob, bDeformGroup *dg, int vertnum) 00557 { 00558 const int def_nr= BLI_findindex(&ob->defbase, dg); 00559 00560 if(def_nr == -1) { 00561 return -1; 00562 } 00563 00564 return get_vert_def_nr(ob, def_nr, vertnum); 00565 } 00566 00567 void ED_vgroup_select_by_name(Object *ob, const char *name) 00568 { /* note: ob->actdef==0 signals on painting to create a new one, if a bone in posemode is selected */ 00569 ob->actdef= defgroup_name_index(ob, name) + 1; 00570 } 00571 00572 /********************** Operator Implementations *********************/ 00573 00574 /* only in editmode */ 00575 static void vgroup_select_verts(Object *ob, int select) 00576 { 00577 const int def_nr= ob->actdef-1; 00578 MDeformVert *dv; 00579 00580 if (!BLI_findlink(&ob->defbase, def_nr)) { 00581 return; 00582 } 00583 00584 if(ob->type == OB_MESH) { 00585 Mesh *me= ob->data; 00586 00587 if (me->edit_mesh) { 00588 EditMesh *em = BKE_mesh_get_editmesh(me); 00589 EditVert *eve; 00590 00591 for (eve=em->verts.first; eve; eve=eve->next) { 00592 if (!eve->h) { 00593 dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); 00594 if (defvert_find_index(dv, def_nr)) { 00595 if (select) eve->f |= SELECT; 00596 else eve->f &= ~SELECT; 00597 } 00598 } 00599 } 00600 /* this has to be called, because this function operates on vertices only */ 00601 if(select) EM_select_flush(em); // vertices to edges/faces 00602 else EM_deselect_flush(em); 00603 00604 BKE_mesh_end_editmesh(me, em); 00605 } 00606 else { 00607 if (me->dvert) { 00608 MVert *mv; 00609 MDeformVert *dv; 00610 int i; 00611 00612 mv = me->mvert; 00613 dv = me->dvert; 00614 00615 for (i=0; i<me->totvert; i++, mv++, dv++) { 00616 if (!(mv->flag & ME_HIDE)) { 00617 if (defvert_find_index(dv, def_nr)) { 00618 if (select) mv->flag |= SELECT; 00619 else mv->flag &= ~SELECT; 00620 } 00621 } 00622 } 00623 00624 paintvert_flush_flags(ob); 00625 } 00626 } 00627 } 00628 else if(ob->type == OB_LATTICE) { 00629 Lattice *lt= vgroup_edit_lattice(ob); 00630 00631 if(lt->dvert) { 00632 BPoint *bp; 00633 int a, tot; 00634 00635 dv= lt->dvert; 00636 00637 tot= lt->pntsu*lt->pntsv*lt->pntsw; 00638 for(a=0, bp= lt->def; a<tot; a++, bp++, dv++) { 00639 if (defvert_find_index(dv, def_nr)) { 00640 if (select) bp->f1 |= SELECT; 00641 else bp->f1 &= ~SELECT; 00642 } 00643 } 00644 } 00645 } 00646 } 00647 00648 static void vgroup_duplicate(Object *ob) 00649 { 00650 bDeformGroup *dg, *cdg; 00651 char name[sizeof(dg->name)]; 00652 MDeformWeight *dw_org, *dw_cpy; 00653 MDeformVert **dvert_array=NULL; 00654 int i, idg, icdg, dvert_tot=0; 00655 00656 dg = BLI_findlink(&ob->defbase, (ob->actdef-1)); 00657 if(!dg) 00658 return; 00659 00660 if(!strstr(dg->name, "_copy")) { 00661 BLI_snprintf(name, sizeof(name), "%s_copy", dg->name); 00662 } 00663 else { 00664 BLI_snprintf(name, sizeof(name), "%s", dg->name); 00665 } 00666 00667 cdg = defgroup_duplicate(dg); 00668 BLI_strncpy(cdg->name, name, sizeof(cdg->name)); 00669 defgroup_unique_name(cdg, ob); 00670 00671 BLI_addtail(&ob->defbase, cdg); 00672 00673 idg = (ob->actdef-1); 00674 ob->actdef = BLI_countlist(&ob->defbase); 00675 icdg = (ob->actdef-1); 00676 00677 /* TODO, we might want to allow only copy selected verts here? - campbell */ 00678 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, FALSE); 00679 00680 if (dvert_array) { 00681 for(i = 0; i < dvert_tot; i++) { 00682 MDeformVert *dv= dvert_array[i]; 00683 dw_org = defvert_find_index(dv, idg); 00684 if(dw_org) { 00685 /* defvert_verify_index re-allocs org so need to store the weight first */ 00686 dw_cpy = defvert_verify_index(dv, icdg); 00687 dw_cpy->weight = dw_org->weight; 00688 } 00689 } 00690 00691 MEM_freeN(dvert_array); 00692 } 00693 } 00694 00695 static void vgroup_normalize(Object *ob) 00696 { 00697 MDeformWeight *dw; 00698 MDeformVert *dv, **dvert_array=NULL; 00699 int i, dvert_tot=0; 00700 const int def_nr= ob->actdef-1; 00701 00702 Mesh *me = ob->data; 00703 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0; 00704 00705 if (!BLI_findlink(&ob->defbase, def_nr)) { 00706 return; 00707 } 00708 00709 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); 00710 00711 if (dvert_array) { 00712 float weight_max = 0.0f; 00713 00714 for(i = 0; i < dvert_tot; i++) { 00715 00716 /* incase its not selected */ 00717 if (!(dv = dvert_array[i])) { 00718 continue; 00719 } 00720 00721 dw = defvert_find_index(dv, def_nr); 00722 if(dw) { 00723 weight_max = MAX2(dw->weight, weight_max); 00724 } 00725 } 00726 00727 if(weight_max > 0.0f) { 00728 for(i = 0; i < dvert_tot; i++) { 00729 00730 /* incase its not selected */ 00731 if (!(dv = dvert_array[i])) { 00732 continue; 00733 } 00734 00735 dw = defvert_find_index(dv, def_nr); 00736 if(dw) { 00737 dw->weight /= weight_max; 00738 00739 /* incase of division errors with very low weights */ 00740 CLAMP(dw->weight, 0.0f, 1.0f); 00741 } 00742 } 00743 } 00744 00745 MEM_freeN(dvert_array); 00746 } 00747 } 00748 00749 /* This adds the indices of vertices to a list if they are not already present 00750 It returns the number that it added (0-2) 00751 It relies on verts having -1 for unassigned indices 00752 */ 00753 static int tryToAddVerts(int *verts, int length, int a, int b) 00754 { 00755 char containsA = FALSE; 00756 char containsB = FALSE; 00757 int added = 0; 00758 int i; 00759 for(i = 0; i < length && (!containsA || !containsB); i++) { 00760 if(verts[i] == a) { 00761 containsA = TRUE; 00762 } else if(verts[i] == b) { 00763 containsB = TRUE; 00764 } else if(verts[i] == -1) { 00765 if(!containsA) { 00766 verts[i] = a; 00767 containsA = TRUE; 00768 added++; 00769 } else if(!containsB){ 00770 verts[i] = b; 00771 containsB = TRUE; 00772 added++; 00773 } 00774 } 00775 } 00776 return added; 00777 } 00778 00779 /* This finds all of the vertices connected to vert by an edge 00780 and returns an array of indices of size count 00781 00782 count is an int passed by reference so it can be assigned the value of the length here. 00783 */ 00784 static int* getSurroundingVerts(Mesh *me, int vert, int *count) 00785 { 00786 int length = 0; 00787 int *tverts; 00788 int *verts = NULL; 00789 MFace *mf = me->mface; 00790 int totface = me->totface; 00791 int found = 0; 00792 int i; 00793 for(i = 0; i < totface; i++, mf++) { 00794 if(vert == mf->v1 || vert == mf->v2 || vert == mf->v3 || (mf->v4 &&vert == mf->v4)) { 00795 length+=2; 00796 } 00797 } 00798 if(!length) { 00799 return NULL; 00800 } 00801 tverts = MEM_mallocN(sizeof(int)*length, "tempSurroundingVerts"); 00802 mf = me->mface; 00803 for(i = 0; i < length; i++) { 00804 tverts[i] = -1; 00805 } 00806 for(i = 0; i < totface; i++, mf++) { 00807 int a=-1, b=-1; 00808 if(mf->v1 == vert) { 00809 a = mf->v2; 00810 if(mf->v4) { 00811 b = mf->v4; 00812 } else { 00813 b = mf->v3; 00814 } 00815 } else if(mf->v2 == vert) { 00816 a = mf->v1; 00817 b = mf->v3; 00818 } else if(mf->v3 == vert) { 00819 a = mf->v2; 00820 if(mf->v4) { 00821 b = mf->v4; 00822 } else { 00823 b = mf->v1; 00824 } 00825 } else if (mf->v4 && mf->v4 == vert){ 00826 a = mf->v1; 00827 b = mf->v3; 00828 } else { 00829 continue; 00830 } 00831 found += tryToAddVerts(tverts, length, a, b); 00832 } 00833 if(found) { 00834 verts = MEM_mallocN(sizeof(int)* found, "surroundingVerts"); 00835 for(i = 0; i < found; i++) { 00836 verts[i] = tverts[i]; 00837 } 00838 *count = found; 00839 } 00840 MEM_freeN(tverts); 00841 return verts; 00842 } 00843 00844 /* get a single point in space by averaging a point cloud (vectors of size 3) 00845 coord is the place the average is stored, points is the point cloud, count is the number of points in the cloud 00846 */ 00847 static void getSingleCoordinate(MVert *points, int count, float coord[3]) 00848 { 00849 int i; 00850 zero_v3(coord); 00851 for(i = 0; i < count; i++) { 00852 add_v3_v3(coord, points[i].co); 00853 } 00854 mul_v3_fl(coord, 1.0f/count); 00855 } 00856 00857 /* given a plane and a start and end position, 00858 compute the amount of vertical distance relative to the plane and store it in dists, 00859 then get the horizontal and vertical change and store them in changes 00860 */ 00861 static void getVerticalAndHorizontalChange(const float norm[3], float d, const float coord[3], 00862 const float start[3], float distToStart, 00863 float *end, float (*changes)[2], float *dists, int index) 00864 { 00865 // A=Q-((Q-P).N)N 00866 // D = (a*x0 + b*y0 +c*z0 +d) 00867 float projA[3], projB[3]; 00868 00869 closest_to_plane_v3(projA, coord, norm, start); 00870 closest_to_plane_v3(projB, coord, norm, end); 00871 // (vertical and horizontal refer to the plane's y and xz respectively) 00872 // vertical distance 00873 dists[index] = norm[0]*end[0] + norm[1]*end[1] + norm[2]*end[2] + d; 00874 // vertical change 00875 changes[index][0] = dists[index] - distToStart; 00876 //printf("vc %f %f\n", distance(end, projB, 3)-distance(start, projA, 3), changes[index][0]); 00877 // horizontal change 00878 changes[index][1] = len_v3v3(projA, projB); 00879 } 00880 00881 // I need the derived mesh to be forgotten so the positions are recalculated with weight changes (see dm_deform_recalc) 00882 static void dm_deform_clear(DerivedMesh *dm, Object *ob) 00883 { 00884 if(ob->derivedDeform && (ob->derivedDeform)==dm) { 00885 ob->derivedDeform->needsFree = 1; 00886 ob->derivedDeform->release(ob->derivedDeform); 00887 ob->derivedDeform = NULL; 00888 } 00889 else if(dm) { 00890 dm->needsFree = 1; 00891 dm->release(dm); 00892 } 00893 } 00894 00895 // recalculate the deformation 00896 static DerivedMesh* dm_deform_recalc(Scene *scene, Object *ob) 00897 { 00898 return mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); 00899 } 00900 00901 /* by changing nonzero weights, try to move a vertex in me->mverts with index 'index' to 00902 distToBe distance away from the provided plane strength can change distToBe so that it moves 00903 towards distToBe by that percentage cp changes how much the weights are adjusted 00904 to check the distance 00905 00906 index is the index of the vertex being moved 00907 norm and d are the plane's properties for the equation: ax + by + cz + d = 0 00908 coord is a point on the plane 00909 */ 00910 static void moveCloserToDistanceFromPlane(Scene *scene, Object *ob, Mesh *me, int index, float norm[3], 00911 float coord[3], float d, float distToBe, float strength, float cp) 00912 { 00913 DerivedMesh *dm; 00914 MDeformWeight *dw; 00915 MVert m; 00916 MDeformVert *dvert = me->dvert+index; 00917 int totweight = dvert->totweight; 00918 float oldw = 0; 00919 float oldPos[3] = {0}; 00920 float vc, hc, dist = 0.0f; 00921 int i, k; 00922 float (*changes)[2] = MEM_mallocN(sizeof(float *)*totweight*2, "vertHorzChange"); 00923 float *dists = MEM_mallocN(sizeof(float)*totweight, "distance"); 00924 00925 /* track if up or down moved it closer for each bone */ 00926 int *upDown = MEM_callocN(sizeof(int)*totweight, "upDownTracker"); 00927 00928 int *dwIndices = MEM_callocN(sizeof(int)*totweight, "dwIndexTracker"); 00929 float distToStart; 00930 int bestIndex = 0; 00931 char wasChange; 00932 char wasUp; 00933 int lastIndex = -1; 00934 float originalDistToBe = distToBe; 00935 do { 00936 wasChange = FALSE; 00937 dm = dm_deform_recalc(scene, ob); 00938 dm->getVert(dm, index, &m); 00939 copy_v3_v3(oldPos, m.co); 00940 distToStart = dot_v3v3(norm, oldPos) + d; 00941 00942 if(distToBe == originalDistToBe) { 00943 distToBe += distToStart - distToStart*strength; 00944 } 00945 for(i = 0; i < totweight; i++) { 00946 dwIndices[i] = i; 00947 dw = (dvert->dw+i); 00948 vc = hc = 0; 00949 if(!dw->weight) { 00950 changes[i][0] = 0; 00951 changes[i][1] = 0; 00952 dists[i] = distToStart; 00953 continue; 00954 } 00955 for(k = 0; k < 2; k++) { 00956 if(dm) { 00957 dm_deform_clear(dm, ob); dm = NULL; 00958 } 00959 oldw = dw->weight; 00960 if(k) { 00961 dw->weight *= 1+cp; 00962 } else { 00963 dw->weight /= 1+cp; 00964 } 00965 if(dw->weight == oldw) { 00966 changes[i][0] = 0; 00967 changes[i][1] = 0; 00968 dists[i] = distToStart; 00969 break; 00970 } 00971 if(dw->weight > 1) { 00972 dw->weight = 1; 00973 } 00974 dm = dm_deform_recalc(scene, ob); 00975 dm->getVert(dm, index, &m); 00976 getVerticalAndHorizontalChange(norm, d, coord, oldPos, distToStart, m.co, changes, dists, i); 00977 dw->weight = oldw; 00978 if(!k) { 00979 vc = changes[i][0]; 00980 hc = changes[i][1]; 00981 dist = dists[i]; 00982 } else { 00983 if(fabs(dist - distToBe) < fabs(dists[i] - distToBe)) { 00984 upDown[i] = 0; 00985 changes[i][0] = vc; 00986 changes[i][1] = hc; 00987 dists[i] = dist; 00988 } else { 00989 upDown[i] = 1; 00990 } 00991 if(fabs(dists[i] - distToBe) > fabs(distToStart - distToBe)) { 00992 changes[i][0] = 0; 00993 changes[i][1] = 0; 00994 dists[i] = distToStart; 00995 } 00996 } 00997 } 00998 } 00999 // sort the changes by the vertical change 01000 for(k = 0; k < totweight; k++) { 01001 float tf; 01002 int ti; 01003 bestIndex = k; 01004 for(i = k+1; i < totweight; i++) { 01005 dist = dists[i]; 01006 01007 if(fabs(dist) > fabs(dists[i])) { 01008 bestIndex = i; 01009 } 01010 } 01011 // switch with k 01012 if(bestIndex != k) { 01013 ti = upDown[k]; 01014 upDown[k] = upDown[bestIndex]; 01015 upDown[bestIndex] = ti; 01016 01017 ti = dwIndices[k]; 01018 dwIndices[k] = dwIndices[bestIndex]; 01019 dwIndices[bestIndex] = ti; 01020 01021 tf = changes[k][0]; 01022 changes[k][0] = changes[bestIndex][0]; 01023 changes[bestIndex][0] = tf; 01024 01025 tf = changes[k][1]; 01026 changes[k][1] = changes[bestIndex][1]; 01027 changes[bestIndex][1] = tf; 01028 01029 tf = dists[k]; 01030 dists[k] = dists[bestIndex]; 01031 dists[bestIndex] = tf; 01032 } 01033 } 01034 bestIndex = -1; 01035 // find the best change with an acceptable horizontal change 01036 for(i = 0; i < totweight; i++) { 01037 if(fabs(changes[i][0]) > fabs(changes[i][1]*2.0f)) { 01038 bestIndex = i; 01039 break; 01040 } 01041 } 01042 if(bestIndex != -1) { 01043 wasChange = TRUE; 01044 // it is a good place to stop if it tries to move the opposite direction 01045 // (relative to the plane) of last time 01046 if(lastIndex != -1) { 01047 if(wasUp != upDown[bestIndex]) { 01048 wasChange = FALSE; 01049 } 01050 } 01051 lastIndex = bestIndex; 01052 wasUp = upDown[bestIndex]; 01053 dw = (dvert->dw+dwIndices[bestIndex]); 01054 oldw = dw->weight; 01055 if(upDown[bestIndex]) { 01056 dw->weight *= 1+cp; 01057 } else { 01058 dw->weight /= 1+cp; 01059 } 01060 if(dw->weight > 1) { 01061 dw->weight = 1; 01062 } 01063 if(oldw == dw->weight) { 01064 wasChange = FALSE; 01065 } 01066 if(dm) { 01067 dm_deform_clear(dm, ob); dm = NULL; 01068 } 01069 } 01070 } while(wasChange && (distToStart-distToBe)/fabsf(distToStart-distToBe) == 01071 (dists[bestIndex]-distToBe)/fabsf(dists[bestIndex]-distToBe)); 01072 MEM_freeN(upDown); 01073 MEM_freeN(changes); 01074 MEM_freeN(dists); 01075 MEM_freeN(dwIndices); 01076 } 01077 01078 /* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex 01079 but it could be used to raise or lower an existing 'bump.' */ 01080 static void vgroup_fix(Scene *scene, Object *ob, float distToBe, float strength, float cp) 01081 { 01082 int i; 01083 01084 Mesh *me = ob->data; 01085 MVert *mvert = me->mvert; 01086 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0; 01087 int *verts = NULL; 01088 for(i = 0; i < me->totvert && mvert; i++, mvert++) { 01089 01090 if(use_vert_sel && (mvert->flag & SELECT)) { 01091 01092 int count=0; 01093 if((verts = getSurroundingVerts(me, i, &count))) { 01094 MVert m; 01095 MVert *p = MEM_callocN(sizeof(MVert)*(count), "deformedPoints"); 01096 int k; 01097 01098 DerivedMesh *dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); 01099 for(k = 0; k < count; k++) { 01100 dm->getVert(dm, verts[k], &m); 01101 p[k] = m; 01102 } 01103 01104 if(count >= 3) { 01105 float d /*, dist */ /* UNUSED */, mag; 01106 float coord[3]; 01107 float norm[3]; 01108 getSingleCoordinate(p, count, coord); 01109 dm->getVert(dm, i, &m); 01110 sub_v3_v3v3(norm, m.co, coord); 01111 mag= normalize_v3(norm); 01112 if(mag) { /* zeros fix */ 01113 d = -dot_v3v3(norm, coord); 01114 /* dist = (norm[0]*m.co[0] + norm[1]*m.co[1] + norm[2]*m.co[2] + d); */ /* UNUSED */ 01115 moveCloserToDistanceFromPlane(scene, ob, me, i, norm, coord, d, distToBe, strength, cp); 01116 } 01117 } 01118 01119 MEM_freeN(verts); 01120 MEM_freeN(p); 01121 } 01122 } 01123 } 01124 } 01125 01126 static void vgroup_levels(Object *ob, float offset, float gain) 01127 { 01128 MDeformWeight *dw; 01129 MDeformVert *dv, **dvert_array=NULL; 01130 int i, dvert_tot=0; 01131 const int def_nr= ob->actdef-1; 01132 01133 Mesh *me = ob->data; 01134 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0; 01135 01136 if (!BLI_findlink(&ob->defbase, def_nr)) { 01137 return; 01138 } 01139 01140 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); 01141 01142 if (dvert_array) { 01143 for(i = 0; i < dvert_tot; i++) { 01144 01145 /* incase its not selected */ 01146 if (!(dv = dvert_array[i])) { 01147 continue; 01148 } 01149 01150 dw = defvert_find_index(dv, def_nr); 01151 if(dw) { 01152 dw->weight = gain * (dw->weight + offset); 01153 01154 CLAMP(dw->weight, 0.0f, 1.0f); 01155 } 01156 } 01157 01158 MEM_freeN(dvert_array); 01159 } 01160 } 01161 01162 /* TODO - select between groups */ 01163 static void vgroup_normalize_all(Object *ob, int lock_active) 01164 { 01165 MDeformVert *dv, **dvert_array=NULL; 01166 int i, dvert_tot=0; 01167 const int def_nr= ob->actdef-1; 01168 01169 Mesh *me = ob->data; 01170 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0; 01171 01172 if (lock_active && !BLI_findlink(&ob->defbase, def_nr)) { 01173 return; 01174 } 01175 01176 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); 01177 01178 if (dvert_array) { 01179 if(lock_active) { 01180 01181 for(i = 0; i < dvert_tot; i++) { 01182 /* incase its not selected */ 01183 if (!(dv = dvert_array[i])) { 01184 continue; 01185 } 01186 01187 defvert_normalize_lock(dv, def_nr); 01188 } 01189 } 01190 else { 01191 for(i = 0; i < dvert_tot; i++) { 01192 01193 /* incase its not selected */ 01194 if (!(dv = dvert_array[i])) { 01195 continue; 01196 } 01197 01198 defvert_normalize(dv); 01199 } 01200 } 01201 01202 MEM_freeN(dvert_array); 01203 } 01204 } 01205 01206 01207 static void vgroup_lock_all(Object *ob, int action) 01208 { 01209 bDeformGroup *dg; 01210 01211 if(action == SEL_TOGGLE) { 01212 action= SEL_SELECT; 01213 for(dg= ob->defbase.first; dg; dg= dg->next) { 01214 if(dg->flag & DG_LOCK_WEIGHT) { 01215 action= SEL_DESELECT; 01216 break; 01217 } 01218 } 01219 } 01220 01221 for(dg= ob->defbase.first; dg; dg= dg->next) { 01222 switch(action) { 01223 case SEL_SELECT: 01224 dg->flag |= DG_LOCK_WEIGHT; 01225 break; 01226 case SEL_DESELECT: 01227 dg->flag &= ~DG_LOCK_WEIGHT; 01228 break; 01229 case SEL_INVERT: 01230 dg->flag ^= DG_LOCK_WEIGHT; 01231 break; 01232 } 01233 } 01234 } 01235 01236 static void vgroup_invert(Object *ob, const short auto_assign, const short auto_remove) 01237 { 01238 MDeformWeight *dw; 01239 MDeformVert *dv, **dvert_array=NULL; 01240 int i, dvert_tot=0; 01241 const int def_nr= ob->actdef-1; 01242 01243 Mesh *me = ob->data; 01244 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0; 01245 01246 if (!BLI_findlink(&ob->defbase, def_nr)) { 01247 return; 01248 } 01249 01250 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); 01251 01252 if (dvert_array) { 01253 for(i = 0; i < dvert_tot; i++) { 01254 01255 /* incase its not selected */ 01256 if (!(dv = dvert_array[i])) { 01257 continue; 01258 } 01259 01260 if (auto_assign) { 01261 dw= defvert_verify_index(dv, def_nr); 01262 } 01263 else { 01264 dw= defvert_find_index(dv, def_nr); 01265 } 01266 01267 if(dw) { 01268 dw->weight = 1.0f - dw->weight; 01269 01270 if(auto_remove && dw->weight <= 0.0f) { 01271 defvert_remove_group(dv, dw); 01272 } 01273 } 01274 } 01275 01276 MEM_freeN(dvert_array); 01277 } 01278 } 01279 01280 static void vgroup_blend(Object *ob) 01281 { 01282 MDeformWeight *dw; 01283 MDeformVert *dvert_array=NULL, *dvert; 01284 int i, dvert_tot=0; 01285 const int def_nr= ob->actdef-1; 01286 01287 EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data)); 01288 // ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot); 01289 01290 if (em==NULL) 01291 return; 01292 01293 if (BLI_findlink(&ob->defbase, def_nr)) { 01294 int sel1, sel2; 01295 int i1, i2; 01296 01297 EditEdge *eed; 01298 EditVert *eve; 01299 float *vg_weights; 01300 float *vg_users; 01301 01302 i= 0; 01303 for(eve= em->verts.first; eve; eve= eve->next) 01304 eve->tmp.l= i++; 01305 01306 dvert_tot= i; 01307 01308 vg_weights= MEM_callocN(sizeof(float)*dvert_tot, "vgroup_blend_f"); 01309 vg_users= MEM_callocN(sizeof(int)*dvert_tot, "vgroup_blend_i"); 01310 01311 for(eed= em->edges.first; eed; eed= eed->next) { 01312 sel1= eed->v1->f & SELECT; 01313 sel2= eed->v2->f & SELECT; 01314 01315 if(sel1 != sel2) { 01316 /* i1 is always the selected one */ 01317 if(sel1==TRUE && sel2==FALSE) { 01318 i1= eed->v1->tmp.l; 01319 i2= eed->v2->tmp.l; 01320 eve= eed->v2; 01321 } 01322 else { 01323 i2= eed->v1->tmp.l; 01324 i1= eed->v2->tmp.l; 01325 eve= eed->v1; 01326 } 01327 01328 vg_users[i1]++; 01329 01330 /* TODO, we may want object mode blending */ 01331 if(em) dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); 01332 else dvert= dvert_array+i2; 01333 01334 dw= defvert_find_index(dvert, def_nr); 01335 01336 if(dw) { 01337 vg_weights[i1] += dw->weight; 01338 } 01339 } 01340 } 01341 01342 i= 0; 01343 for(eve= em->verts.first; eve; eve= eve->next) { 01344 if(eve->f & SELECT && vg_users[i] > 0) { 01345 /* TODO, we may want object mode blending */ 01346 if(em) dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); 01347 else dvert= dvert_array+i; 01348 01349 dw= defvert_verify_index(dvert, def_nr); 01350 dw->weight= vg_weights[i] / (float)vg_users[i]; 01351 01352 /* incase of division errors */ 01353 CLAMP(dw->weight, 0.0f, 1.0f); 01354 } 01355 01356 i++; 01357 } 01358 MEM_freeN(vg_weights); 01359 MEM_freeN(vg_users); 01360 } 01361 } 01362 01363 static void vgroup_clean(Object *ob, const float epsilon, int keep_single) 01364 { 01365 MDeformWeight *dw; 01366 MDeformVert *dv, **dvert_array=NULL; 01367 int i, dvert_tot=0; 01368 const int def_nr= ob->actdef-1; 01369 01370 Mesh *me = ob->data; 01371 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0; 01372 01373 if (!BLI_findlink(&ob->defbase, def_nr)) { 01374 return; 01375 } 01376 01377 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); 01378 01379 if (dvert_array) { 01380 /* only the active group */ 01381 for(i = 0; i < dvert_tot; i++) { 01382 01383 /* incase its not selected */ 01384 if (!(dv = dvert_array[i])) { 01385 continue; 01386 } 01387 01388 dw= defvert_find_index(dv, def_nr); 01389 01390 if (dw) { 01391 if (dw->weight <= epsilon) { 01392 if(keep_single==FALSE || dv->totweight > 1) { 01393 defvert_remove_group(dv, dw); /* dw can be NULL */ 01394 } 01395 } 01396 } 01397 } 01398 01399 MEM_freeN(dvert_array); 01400 } 01401 } 01402 01403 static void vgroup_clean_all(Object *ob, const float epsilon, const int keep_single) 01404 { 01405 MDeformVert **dvert_array=NULL; 01406 int i, dvert_tot=0; 01407 01408 Mesh *me = ob->data; 01409 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0; 01410 01411 ED_vgroup_give_parray(ob->data, &dvert_array, &dvert_tot, use_vert_sel); 01412 01413 if (dvert_array) { 01414 MDeformVert *dv; 01415 MDeformWeight *dw; 01416 01417 for(i = 0; i < dvert_tot; i++) { 01418 int j; 01419 01420 /* incase its not selected */ 01421 if (!(dv = dvert_array[i])) { 01422 continue; 01423 } 01424 01425 j= dv->totweight; 01426 01427 while(j--) { 01428 01429 if(keep_single && dv->totweight == 1) 01430 break; 01431 01432 dw= dv->dw + j; 01433 01434 if(dw->weight <= epsilon) { 01435 defvert_remove_group(dv, dw); 01436 } 01437 } 01438 } 01439 01440 MEM_freeN(dvert_array); 01441 } 01442 } 01443 01444 01445 static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr, 01446 const char sel, const char sel_mirr, 01447 const int *flip_map, const int flip_map_len, 01448 const short mirror_weights, const short flip_vgroups, 01449 const short all_vgroups, const int act_vgroup) 01450 { 01451 BLI_assert(sel || sel_mirr); 01452 01453 if(sel_mirr && sel) { 01454 /* swap */ 01455 if(mirror_weights) { 01456 if (all_vgroups) { 01457 SWAP(MDeformVert, *dvert, *dvert_mirr); 01458 } 01459 else { 01460 MDeformWeight *dw= defvert_find_index(dvert, act_vgroup); 01461 MDeformWeight *dw_mirr= defvert_find_index(dvert_mirr, act_vgroup); 01462 01463 if (dw || dw_mirr) { 01464 if (dw_mirr == NULL) 01465 dw_mirr= defvert_verify_index(dvert_mirr, act_vgroup); 01466 if (dw == NULL) 01467 dw= defvert_verify_index(dvert, act_vgroup); 01468 01469 SWAP(float, dw->weight, dw_mirr->weight); 01470 } 01471 } 01472 } 01473 01474 if(flip_vgroups) { 01475 defvert_flip(dvert, flip_map, flip_map_len); 01476 defvert_flip(dvert_mirr, flip_map, flip_map_len); 01477 } 01478 } 01479 else { 01480 /* dvert should always be the target, only swaps pointer */ 01481 if(sel_mirr) { 01482 SWAP(MDeformVert *, dvert, dvert_mirr); 01483 } 01484 01485 if(mirror_weights) { 01486 if (all_vgroups) { 01487 defvert_copy(dvert, dvert_mirr); 01488 } 01489 else { 01490 defvert_copy_index(dvert, dvert_mirr, act_vgroup); 01491 } 01492 } 01493 01494 /* flip map already modified for 'all_vgroups' */ 01495 if(flip_vgroups) { 01496 defvert_flip(dvert, flip_map, flip_map_len); 01497 } 01498 } 01499 } 01500 01501 /* TODO, vgroup locking */ 01502 /* TODO, face masking */ 01503 void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_vgroups, const short all_vgroups) 01504 { 01505 01506 #define VGROUP_MIRR_OP \ 01507 dvert_mirror_op(dvert, dvert_mirr, \ 01508 sel, sel_mirr, \ 01509 flip_map, flip_map_len, \ 01510 mirror_weights, flip_vgroups, \ 01511 all_vgroups, def_nr \ 01512 ) 01513 01514 EditVert *eve, *eve_mirr; 01515 MDeformVert *dvert, *dvert_mirr; 01516 short sel, sel_mirr; 01517 int *flip_map, flip_map_len; 01518 const int def_nr= ob->actdef-1; 01519 01520 if ( (mirror_weights==0 && flip_vgroups==0) || 01521 (BLI_findlink(&ob->defbase, def_nr) == NULL) ) 01522 { 01523 return; 01524 } 01525 01526 if (flip_vgroups) { 01527 flip_map= all_vgroups ? 01528 defgroup_flip_map(ob, &flip_map_len, FALSE) : 01529 defgroup_flip_map_single(ob, &flip_map_len, FALSE, def_nr); 01530 01531 BLI_assert(flip_map != NULL); 01532 01533 if (flip_map == NULL) { 01534 /* something went wrong!, possibly no groups */ 01535 return; 01536 } 01537 } 01538 else { 01539 flip_map= NULL; 01540 flip_map_len= 0; 01541 } 01542 01543 /* only the active group */ 01544 if(ob->type == OB_MESH) { 01545 Mesh *me= ob->data; 01546 EditMesh *em = BKE_mesh_get_editmesh(me); 01547 01548 if (em) { 01549 if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) { 01550 goto cleanup; 01551 } 01552 01553 EM_cache_x_mirror_vert(ob, em); 01554 01555 /* Go through the list of editverts and assign them */ 01556 for(eve=em->verts.first; eve; eve=eve->next){ 01557 if((eve_mirr=eve->tmp.v)) { 01558 sel= eve->f & SELECT; 01559 sel_mirr= eve_mirr->f & SELECT; 01560 01561 if((sel || sel_mirr) && (eve != eve_mirr)) { 01562 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); 01563 dvert_mirr= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT); 01564 if(dvert && dvert_mirr) { 01565 VGROUP_MIRR_OP; 01566 } 01567 } 01568 01569 eve->tmp.v= eve_mirr->tmp.v= NULL; 01570 } 01571 } 01572 BKE_mesh_end_editmesh(me, em); 01573 } 01574 else { 01575 /* object mode / weight paint */ 01576 MVert *mv, *mv_mirr; 01577 int vidx, vidx_mirr; 01578 const int use_vert_sel= (me->editflag & ME_EDIT_VERT_SEL) != 0; 01579 01580 if (me->dvert == NULL) { 01581 goto cleanup; 01582 } 01583 01584 if (!use_vert_sel) { 01585 sel= sel_mirr= TRUE; 01586 } 01587 01588 /* tag verts we have used */ 01589 for(vidx= 0, mv= me->mvert; vidx < me->totvert; vidx++, mv++) { 01590 mv->flag &= ~ME_VERT_TMP_TAG; 01591 } 01592 01593 for(vidx= 0, mv= me->mvert; vidx < me->totvert; vidx++, mv++) { 01594 if ( ((mv->flag & ME_VERT_TMP_TAG) == 0) && 01595 ((vidx_mirr= mesh_get_x_mirror_vert(ob, vidx)) != -1) && 01596 (vidx != vidx_mirr) && 01597 ((((mv_mirr= me->mvert + vidx_mirr)->flag) & ME_VERT_TMP_TAG) == 0)) 01598 { 01599 01600 if (use_vert_sel) { 01601 sel= mv->flag & SELECT; 01602 sel_mirr= mv_mirr->flag & SELECT; 01603 } 01604 01605 if (sel || sel_mirr) { 01606 dvert= &me->dvert[vidx]; 01607 dvert_mirr= &me->dvert[vidx_mirr]; 01608 01609 VGROUP_MIRR_OP; 01610 } 01611 01612 mv->flag |= ME_VERT_TMP_TAG; 01613 mv_mirr->flag |= ME_VERT_TMP_TAG; 01614 } 01615 } 01616 } 01617 } 01618 else if (ob->type == OB_LATTICE) { 01619 Lattice *lt= vgroup_edit_lattice(ob); 01620 int i1, i2; 01621 int u, v, w; 01622 int pntsu_half; 01623 /* half but found up odd value */ 01624 01625 if(lt->pntsu == 1 || lt->dvert == NULL) { 01626 goto cleanup; 01627 } 01628 01629 /* unlike editmesh we know that by only looping over the first hald of 01630 * the 'u' indicies it will cover all points except the middle which is 01631 * ok in this case */ 01632 pntsu_half= lt->pntsu / 2; 01633 01634 for(w=0; w<lt->pntsw; w++) { 01635 for(v=0; v<lt->pntsv; v++) { 01636 for(u=0; u<pntsu_half; u++) { 01637 int u_inv= (lt->pntsu - 1) - u; 01638 if(u != u_inv) { 01639 BPoint *bp, *bp_mirr; 01640 01641 i1= LT_INDEX(lt, u, v, w); 01642 i2= LT_INDEX(lt, u_inv, v, w); 01643 01644 bp= <->def[i1]; 01645 bp_mirr= <->def[i2]; 01646 01647 sel= bp->f1 & SELECT; 01648 sel_mirr= bp_mirr->f1 & SELECT; 01649 01650 if(sel || sel_mirr) { 01651 dvert= <->dvert[i1]; 01652 dvert_mirr= <->dvert[i2]; 01653 01654 VGROUP_MIRR_OP; 01655 } 01656 } 01657 } 01658 } 01659 } 01660 } 01661 01662 cleanup: 01663 if (flip_map) MEM_freeN(flip_map); 01664 01665 #undef VGROUP_MIRR_OP 01666 01667 } 01668 01669 static void vgroup_remap_update_users(Object *ob, int *map) 01670 { 01671 ExplodeModifierData *emd; 01672 ModifierData *md; 01673 ParticleSystem *psys; 01674 ClothModifierData *clmd; 01675 ClothSimSettings *clsim; 01676 int a; 01677 01678 /* these cases don't use names to refer to vertex groups, so when 01679 * they get deleted the numbers get out of sync, this corrects that */ 01680 01681 if(ob->soft) 01682 ob->soft->vertgroup= map[ob->soft->vertgroup]; 01683 01684 for(md=ob->modifiers.first; md; md=md->next) { 01685 if(md->type == eModifierType_Explode) { 01686 emd= (ExplodeModifierData*)md; 01687 emd->vgroup= map[emd->vgroup]; 01688 } 01689 else if(md->type == eModifierType_Cloth) { 01690 clmd= (ClothModifierData*)md; 01691 clsim= clmd->sim_parms; 01692 01693 if(clsim) { 01694 clsim->vgroup_mass= map[clsim->vgroup_mass]; 01695 clsim->vgroup_bend= map[clsim->vgroup_bend]; 01696 clsim->vgroup_struct= map[clsim->vgroup_struct]; 01697 } 01698 } 01699 } 01700 01701 for(psys=ob->particlesystem.first; psys; psys=psys->next) { 01702 for(a=0; a<PSYS_TOT_VG; a++) 01703 psys->vgroup[a]= map[psys->vgroup[a]]; 01704 } 01705 } 01706 01707 01708 static void vgroup_delete_update_users(Object *ob, int id) 01709 { 01710 int i, defbase_tot= BLI_countlist(&ob->defbase) + 1; 01711 int *map= MEM_mallocN(sizeof(int) * defbase_tot, "vgroup del"); 01712 01713 map[id]= map[0]= 0; 01714 for(i=1; i<id; i++) map[i]=i; 01715 for(i=id+1; i<defbase_tot; i++) map[i]=i-1; 01716 01717 vgroup_remap_update_users(ob, map); 01718 MEM_freeN(map); 01719 } 01720 01721 01722 static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg) 01723 { 01724 MDeformVert *dvert_array=NULL; 01725 int dvert_tot=0; 01726 const int def_nr= BLI_findindex(&ob->defbase, dg); 01727 01728 assert(def_nr > -1); 01729 01730 ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot); 01731 01732 if(dvert_array) { 01733 int i, j; 01734 MDeformVert *dv; 01735 for(i= 0, dv= dvert_array; i < dvert_tot; i++, dv++) { 01736 MDeformWeight *dw; 01737 01738 dw= defvert_find_index(dv, def_nr); 01739 defvert_remove_group(dv, dw); /* dw can be NULL */ 01740 01741 /* inline, make into a function if anything else needs to do this */ 01742 for(j = 0; j < dv->totweight; j++) { 01743 if(dv->dw[j].def_nr > def_nr) { 01744 dv->dw[j].def_nr--; 01745 } 01746 } 01747 /* done */ 01748 } 01749 } 01750 01751 vgroup_delete_update_users(ob, def_nr + 1); 01752 01753 /* Remove the group */ 01754 BLI_freelinkN(&ob->defbase, dg); 01755 01756 /* Update the active deform index if necessary */ 01757 if(ob->actdef > def_nr) 01758 ob->actdef--; 01759 if(ob->actdef < 1 && ob->defbase.first) 01760 ob->actdef= 1; 01761 01762 } 01763 01764 /* only in editmode */ 01765 /* removes from active defgroup, if allverts==0 only selected vertices */ 01766 static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGroup *dg) 01767 { 01768 MDeformVert *dv; 01769 const int def_nr= BLI_findindex(&ob->defbase, dg); 01770 01771 if(ob->type == OB_MESH) { 01772 Mesh *me= ob->data; 01773 01774 if (me->edit_mesh) { 01775 EditVert *eve; 01776 EditMesh *em = BKE_mesh_get_editmesh(me); 01777 01778 for (eve=em->verts.first; eve; eve=eve->next) { 01779 dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); 01780 01781 if (dv && dv->dw && (allverts || (eve->f & SELECT))) { 01782 MDeformWeight *dw = defvert_find_index(dv, def_nr); 01783 defvert_remove_group(dv, dw); /* dw can be NULL */ 01784 } 01785 } 01786 BKE_mesh_end_editmesh(me, em); 01787 } 01788 else { 01789 MVert *mv; 01790 MDeformVert *dv; 01791 int i; 01792 01793 if (!me->dvert) { 01794 ED_vgroup_data_create(&me->id); 01795 } 01796 01797 mv = me->mvert; 01798 dv = me->dvert; 01799 01800 for (i=0; i<me->totvert; i++, mv++, dv++) { 01801 if (mv->flag & SELECT) { 01802 if (dv->dw && (allverts || (mv->flag & SELECT))) { 01803 MDeformWeight *dw = defvert_find_index(dv, def_nr); 01804 defvert_remove_group(dv, dw); /* dw can be NULL */ 01805 } 01806 } 01807 } 01808 } 01809 } 01810 else if(ob->type == OB_LATTICE) { 01811 Lattice *lt= vgroup_edit_lattice(ob); 01812 01813 if(lt->dvert) { 01814 BPoint *bp; 01815 int i, tot= lt->pntsu*lt->pntsv*lt->pntsw; 01816 01817 for(i=0, bp= lt->def; i<tot; i++, bp++) { 01818 if(allverts || (bp->f1 & SELECT)) { 01819 MDeformWeight *dw; 01820 01821 dv= <->dvert[i]; 01822 01823 dw = defvert_find_index(dv, def_nr); 01824 defvert_remove_group(dv, dw); /* dw can be NULL */ 01825 } 01826 } 01827 } 01828 } 01829 } 01830 01831 static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg) 01832 { 01833 int i; 01834 const int dg_index= BLI_findindex(&ob->defbase, dg); 01835 01836 assert(dg_index > -1); 01837 01838 /* Make sure that no verts are using this group */ 01839 vgroup_active_remove_verts(ob, TRUE, dg); 01840 01841 /* Make sure that any verts with higher indices are adjusted accordingly */ 01842 if(ob->type==OB_MESH) { 01843 Mesh *me= ob->data; 01844 EditMesh *em = BKE_mesh_get_editmesh(me); 01845 EditVert *eve; 01846 MDeformVert *dvert; 01847 01848 for(eve=em->verts.first; eve; eve=eve->next){ 01849 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); 01850 01851 if(dvert) 01852 for(i=0; i<dvert->totweight; i++) 01853 if(dvert->dw[i].def_nr > dg_index) 01854 dvert->dw[i].def_nr--; 01855 } 01856 BKE_mesh_end_editmesh(me, em); 01857 } 01858 else if(ob->type==OB_LATTICE) { 01859 Lattice *lt= vgroup_edit_lattice(ob); 01860 BPoint *bp; 01861 MDeformVert *dvert= lt->dvert; 01862 int a, tot; 01863 01864 if(dvert) { 01865 tot= lt->pntsu*lt->pntsv*lt->pntsw; 01866 for(a=0, bp= lt->def; a<tot; a++, bp++, dvert++) { 01867 for(i=0; i<dvert->totweight; i++){ 01868 if(dvert->dw[i].def_nr > dg_index) 01869 dvert->dw[i].def_nr--; 01870 } 01871 } 01872 } 01873 } 01874 01875 vgroup_delete_update_users(ob, dg_index + 1); 01876 01877 /* Remove the group */ 01878 BLI_freelinkN (&ob->defbase, dg); 01879 01880 /* Update the active deform index if necessary */ 01881 if(ob->actdef > dg_index) 01882 ob->actdef--; 01883 if(ob->actdef < 1 && ob->defbase.first) 01884 ob->actdef= 1; 01885 01886 /* remove all dverts */ 01887 if(ob->defbase.first == NULL) { 01888 if(ob->type==OB_MESH) { 01889 Mesh *me= ob->data; 01890 CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); 01891 me->dvert= NULL; 01892 } 01893 else if(ob->type==OB_LATTICE) { 01894 Lattice *lt= vgroup_edit_lattice(ob); 01895 if(lt->dvert) { 01896 MEM_freeN(lt->dvert); 01897 lt->dvert= NULL; 01898 } 01899 } 01900 } 01901 } 01902 01903 static int vgroup_object_in_edit_mode(Object *ob) 01904 { 01905 if(ob->type == OB_MESH) 01906 return (((Mesh*)ob->data)->edit_mesh != NULL); 01907 else if(ob->type == OB_LATTICE) 01908 return (((Lattice*)ob->data)->editlatt != NULL); 01909 01910 return 0; 01911 } 01912 01913 static int vgroup_object_in_wpaint_vert_select(Object *ob) 01914 { 01915 if (ob->type == OB_MESH) { 01916 Mesh *me = ob->data; 01917 return ( (ob->mode & OB_MODE_WEIGHT_PAINT) && 01918 (me->edit_mesh == NULL) && 01919 (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX) ); 01920 } 01921 01922 return 0; 01923 } 01924 01925 static void vgroup_delete(Object *ob) 01926 { 01927 bDeformGroup *dg = BLI_findlink(&ob->defbase, ob->actdef-1); 01928 if(!dg) 01929 return; 01930 01931 if(vgroup_object_in_edit_mode(ob)) 01932 vgroup_delete_edit_mode(ob, dg); 01933 else 01934 vgroup_delete_object_mode(ob, dg); 01935 } 01936 01937 static void vgroup_delete_all(Object *ob) 01938 { 01939 /* Remove all DVerts */ 01940 if(ob->type==OB_MESH) { 01941 Mesh *me= ob->data; 01942 CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert); 01943 me->dvert= NULL; 01944 } 01945 else if(ob->type==OB_LATTICE) { 01946 Lattice *lt= vgroup_edit_lattice(ob); 01947 if(lt->dvert) { 01948 MEM_freeN(lt->dvert); 01949 lt->dvert= NULL; 01950 } 01951 } 01952 01953 /* Remove all DefGroups */ 01954 BLI_freelistN(&ob->defbase); 01955 01956 /* Fix counters/indices */ 01957 ob->actdef= 0; 01958 } 01959 01960 /* only in editmode */ 01961 static void vgroup_assign_verts(Object *ob, const float weight) 01962 { 01963 MDeformVert *dv; 01964 const int def_nr= ob->actdef-1; 01965 01966 if(!BLI_findlink(&ob->defbase, def_nr)) 01967 return; 01968 01969 if(ob->type == OB_MESH) { 01970 Mesh *me= ob->data; 01971 if (me->edit_mesh) { 01972 EditMesh *em = BKE_mesh_get_editmesh(me); 01973 EditVert *eve; 01974 01975 if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) 01976 EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL); 01977 01978 /* Go through the list of editverts and assign them */ 01979 for (eve=em->verts.first; eve; eve=eve->next) { 01980 if (eve->f & SELECT) { 01981 MDeformWeight *dw; 01982 dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); /* can be NULL */ 01983 dw= defvert_verify_index(dv, def_nr); 01984 if (dw) { 01985 dw->weight= weight; 01986 } 01987 } 01988 } 01989 BKE_mesh_end_editmesh(me, em); 01990 } 01991 else { 01992 MVert *mv; 01993 MDeformVert *dv; 01994 int i; 01995 01996 if (!me->dvert) { 01997 ED_vgroup_data_create(&me->id); 01998 } 01999 02000 mv = me->mvert; 02001 dv = me->dvert; 02002 02003 for (i=0; i<me->totvert; i++, mv++, dv++) { 02004 if (mv->flag & SELECT) { 02005 MDeformWeight *dw; 02006 dw= defvert_verify_index(dv, def_nr); 02007 if (dw) { 02008 dw->weight= weight; 02009 } 02010 } 02011 } 02012 } 02013 } 02014 else if(ob->type == OB_LATTICE) { 02015 Lattice *lt= vgroup_edit_lattice(ob); 02016 BPoint *bp; 02017 int a, tot; 02018 02019 if(lt->dvert==NULL) 02020 ED_vgroup_data_create(<->id); 02021 02022 dv= lt->dvert; 02023 02024 tot= lt->pntsu*lt->pntsv*lt->pntsw; 02025 for(a=0, bp= lt->def; a<tot; a++, bp++, dv++) { 02026 if(bp->f1 & SELECT) { 02027 MDeformWeight *dw; 02028 02029 dw= defvert_verify_index(dv, def_nr); 02030 if (dw) { 02031 dw->weight= weight; 02032 } 02033 } 02034 } 02035 } 02036 } 02037 02038 /* only in editmode */ 02039 /* removes from all defgroup, if allverts==0 only selected vertices */ 02040 static void vgroup_remove_verts(Object *ob, int allverts) 02041 { 02042 /* To prevent code redundancy, we just use vgroup_active_remove_verts, but that 02043 * only operates on the active vgroup. So we iterate through all groups, by changing 02044 * active group index 02045 */ 02046 bDeformGroup *dg; 02047 for(dg= ob->defbase.first; dg; dg= dg->next) { 02048 vgroup_active_remove_verts(ob, allverts, dg); 02049 } 02050 } 02051 02052 /********************** vertex group operators *********************/ 02053 02054 static int vertex_group_poll(bContext *C) 02055 { 02056 Object *ob= ED_object_context(C); 02057 ID *data= (ob)? ob->data: NULL; 02058 return (ob && !ob->id.lib && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && !data->lib); 02059 } 02060 02061 static int UNUSED_FUNCTION(vertex_group_poll_edit)(bContext *C) 02062 { 02063 Object *ob= ED_object_context(C); 02064 ID *data= (ob)? ob->data: NULL; 02065 02066 if(!(ob && !ob->id.lib && data && !data->lib)) 02067 return 0; 02068 02069 return vgroup_object_in_edit_mode(ob); 02070 } 02071 02072 /* editmode _or_ weight paint vertex sel */ 02073 static int vertex_group_poll_edit_or_wpaint_vert_select(bContext *C) 02074 { 02075 Object *ob= ED_object_context(C); 02076 ID *data= (ob)? ob->data: NULL; 02077 02078 if(!(ob && !ob->id.lib && data && !data->lib)) 02079 return 0; 02080 02081 return ( vgroup_object_in_edit_mode(ob) || 02082 vgroup_object_in_wpaint_vert_select(ob) ); 02083 } 02084 02085 static int vertex_group_add_exec(bContext *C, wmOperator *UNUSED(op)) 02086 { 02087 Object *ob= ED_object_context(C); 02088 02089 ED_vgroup_add(ob); 02090 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02091 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02092 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02093 02094 return OPERATOR_FINISHED; 02095 } 02096 02097 void OBJECT_OT_vertex_group_add(wmOperatorType *ot) 02098 { 02099 /* identifiers */ 02100 ot->name= "Add Vertex Group"; 02101 ot->idname= "OBJECT_OT_vertex_group_add"; 02102 02103 /* api callbacks */ 02104 ot->poll= vertex_group_poll; 02105 ot->exec= vertex_group_add_exec; 02106 02107 /* flags */ 02108 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02109 } 02110 02111 static int vertex_group_remove_exec(bContext *C, wmOperator *op) 02112 { 02113 Object *ob= ED_object_context(C); 02114 02115 if(RNA_boolean_get(op->ptr, "all")) 02116 vgroup_delete_all(ob); 02117 else 02118 vgroup_delete(ob); 02119 02120 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02121 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02122 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02123 02124 return OPERATOR_FINISHED; 02125 } 02126 02127 void OBJECT_OT_vertex_group_remove(wmOperatorType *ot) 02128 { 02129 /* identifiers */ 02130 ot->name= "Remove Vertex Group"; 02131 ot->idname= "OBJECT_OT_vertex_group_remove"; 02132 02133 /* api callbacks */ 02134 ot->poll= vertex_group_poll; 02135 ot->exec= vertex_group_remove_exec; 02136 02137 /* flags */ 02138 /* redo operator will fail in this case because vertex groups aren't stored 02139 in local edit mode stack and toggling "all" property will lead to 02140 all groups deleted without way to restore them (see [#29527], sergey) */ 02141 ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO; 02142 02143 /* properties */ 02144 RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups"); 02145 } 02146 02147 static int vertex_group_assign_exec(bContext *C, wmOperator *op) 02148 { 02149 ToolSettings *ts= CTX_data_tool_settings(C); 02150 Object *ob= ED_object_context(C); 02151 02152 if(RNA_boolean_get(op->ptr, "new")) 02153 ED_vgroup_add(ob); 02154 02155 vgroup_assign_verts(ob, ts->vgroup_weight); 02156 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02157 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02158 02159 return OPERATOR_FINISHED; 02160 } 02161 02162 void OBJECT_OT_vertex_group_assign(wmOperatorType *ot) 02163 { 02164 /* identifiers */ 02165 ot->name= "Assign Vertex Group"; 02166 ot->idname= "OBJECT_OT_vertex_group_assign"; 02167 02168 /* api callbacks */ 02169 ot->poll= vertex_group_poll_edit_or_wpaint_vert_select; 02170 ot->exec= vertex_group_assign_exec; 02171 02172 /* flags */ 02173 /* redo operator will fail in this case because vertex group assignment 02174 isn't stored in local edit mode stack and toggling "new" property will 02175 lead to creating plenty of new veretx groups (see [#29527], sergey) */ 02176 ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO; 02177 02178 /* properties */ 02179 RNA_def_boolean(ot->srna, "new", 0, "New", "Assign vertex to new vertex group"); 02180 } 02181 02182 static int vertex_group_remove_from_exec(bContext *C, wmOperator *op) 02183 { 02184 Object *ob= ED_object_context(C); 02185 02186 if(RNA_boolean_get(op->ptr, "all")) 02187 vgroup_remove_verts(ob, 0); 02188 else { 02189 bDeformGroup *dg= BLI_findlink(&ob->defbase, ob->actdef - 1); 02190 02191 if(dg == NULL) { 02192 return OPERATOR_CANCELLED; 02193 } 02194 02195 vgroup_active_remove_verts(ob, FALSE, dg); 02196 } 02197 02198 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02199 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02200 02201 return OPERATOR_FINISHED; 02202 } 02203 02204 void OBJECT_OT_vertex_group_remove_from(wmOperatorType *ot) 02205 { 02206 /* identifiers */ 02207 ot->name= "Remove from Vertex Group"; 02208 ot->idname= "OBJECT_OT_vertex_group_remove_from"; 02209 02210 /* api callbacks */ 02211 ot->poll= vertex_group_poll_edit_or_wpaint_vert_select; 02212 ot->exec= vertex_group_remove_from_exec; 02213 02214 /* flags */ 02215 /* redo operator will fail in this case because vertex groups ssignment 02216 isn't stored in local edit mode stack and toggling "all" property will lead to 02217 removing vertices from all groups (see [#29527], sergey) */ 02218 ot->flag= /*OPTYPE_REGISTER|*/OPTYPE_UNDO; 02219 02220 /* properties */ 02221 RNA_def_boolean(ot->srna, "all", 0, "All", "Remove from all vertex groups"); 02222 } 02223 02224 static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op)) 02225 { 02226 Object *ob= ED_object_context(C); 02227 02228 if(!ob || ob->id.lib) 02229 return OPERATOR_CANCELLED; 02230 02231 vgroup_select_verts(ob, 1); 02232 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data); 02233 02234 return OPERATOR_FINISHED; 02235 } 02236 02237 void OBJECT_OT_vertex_group_select(wmOperatorType *ot) 02238 { 02239 /* identifiers */ 02240 ot->name= "Select Vertex Group"; 02241 ot->idname= "OBJECT_OT_vertex_group_select"; 02242 02243 /* api callbacks */ 02244 ot->poll= vertex_group_poll_edit_or_wpaint_vert_select; 02245 ot->exec= vertex_group_select_exec; 02246 02247 /* flags */ 02248 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02249 } 02250 02251 static int vertex_group_deselect_exec(bContext *C, wmOperator *UNUSED(op)) 02252 { 02253 Object *ob= ED_object_context(C); 02254 02255 vgroup_select_verts(ob, 0); 02256 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data); 02257 02258 return OPERATOR_FINISHED; 02259 } 02260 02261 void OBJECT_OT_vertex_group_deselect(wmOperatorType *ot) 02262 { 02263 /* identifiers */ 02264 ot->name= "Deselect Vertex Group"; 02265 ot->idname= "OBJECT_OT_vertex_group_deselect"; 02266 02267 /* api callbacks */ 02268 ot->poll= vertex_group_poll_edit_or_wpaint_vert_select; 02269 ot->exec= vertex_group_deselect_exec; 02270 02271 /* flags */ 02272 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02273 } 02274 02275 static int vertex_group_copy_exec(bContext *C, wmOperator *UNUSED(op)) 02276 { 02277 Object *ob= ED_object_context(C); 02278 02279 vgroup_duplicate(ob); 02280 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02281 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02282 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02283 02284 return OPERATOR_FINISHED; 02285 } 02286 02287 void OBJECT_OT_vertex_group_copy(wmOperatorType *ot) 02288 { 02289 /* identifiers */ 02290 ot->name= "Copy Vertex Group"; 02291 ot->idname= "OBJECT_OT_vertex_group_copy"; 02292 02293 /* api callbacks */ 02294 ot->poll= vertex_group_poll; 02295 ot->exec= vertex_group_copy_exec; 02296 02297 /* flags */ 02298 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02299 } 02300 02301 static int vertex_group_levels_exec(bContext *C, wmOperator *op) 02302 { 02303 Object *ob= ED_object_context(C); 02304 02305 float offset= RNA_float_get(op->ptr,"offset"); 02306 float gain= RNA_float_get(op->ptr,"gain"); 02307 02308 vgroup_levels(ob, offset, gain); 02309 02310 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02311 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02312 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02313 02314 return OPERATOR_FINISHED; 02315 } 02316 02317 void OBJECT_OT_vertex_group_levels(wmOperatorType *ot) 02318 { 02319 /* identifiers */ 02320 ot->name= "Vertex Group Levels"; 02321 ot->idname= "OBJECT_OT_vertex_group_levels"; 02322 02323 /* api callbacks */ 02324 ot->poll= vertex_group_poll; 02325 ot->exec= vertex_group_levels_exec; 02326 02327 /* flags */ 02328 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02329 02330 RNA_def_float(ot->srna, "offset", 0.f, -1.0, 1.0, "Offset", "Value to add to weights", -1.0f, 1.f); 02331 RNA_def_float(ot->srna, "gain", 1.f, 0.f, FLT_MAX, "Gain", "Value to multiply weights by", 0.0f, 10.f); 02332 } 02333 02334 static int vertex_group_normalize_exec(bContext *C, wmOperator *UNUSED(op)) 02335 { 02336 Object *ob= ED_object_context(C); 02337 02338 vgroup_normalize(ob); 02339 02340 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02341 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02342 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02343 02344 return OPERATOR_FINISHED; 02345 } 02346 02347 void OBJECT_OT_vertex_group_normalize(wmOperatorType *ot) 02348 { 02349 /* identifiers */ 02350 ot->name= "Normalize Vertex Group"; 02351 ot->idname= "OBJECT_OT_vertex_group_normalize"; 02352 02353 /* api callbacks */ 02354 ot->poll= vertex_group_poll; 02355 ot->exec= vertex_group_normalize_exec; 02356 02357 /* flags */ 02358 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02359 } 02360 02361 static int vertex_group_normalize_all_exec(bContext *C, wmOperator *op) 02362 { 02363 Object *ob= ED_object_context(C); 02364 int lock_active= RNA_boolean_get(op->ptr,"lock_active"); 02365 02366 vgroup_normalize_all(ob, lock_active); 02367 02368 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02369 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02370 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02371 02372 return OPERATOR_FINISHED; 02373 } 02374 02375 void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot) 02376 { 02377 /* identifiers */ 02378 ot->name= "Normalize All Vertex Groups"; 02379 ot->idname= "OBJECT_OT_vertex_group_normalize_all"; 02380 02381 /* api callbacks */ 02382 ot->poll= vertex_group_poll; 02383 ot->exec= vertex_group_normalize_all_exec; 02384 02385 /* flags */ 02386 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02387 02388 RNA_def_boolean(ot->srna, "lock_active", TRUE, "Lock Active", 02389 "Keep the values of the active group while normalizing others"); 02390 } 02391 02392 static int vertex_group_fix_exec(bContext *C, wmOperator *op) 02393 { 02394 Object *ob= CTX_data_active_object(C); 02395 Scene *scene= CTX_data_scene(C); 02396 02397 float distToBe= RNA_float_get(op->ptr, "dist"); 02398 float strength= RNA_float_get(op->ptr, "strength"); 02399 float cp= RNA_float_get(op->ptr, "accuracy"); 02400 ModifierData *md= ob->modifiers.first; 02401 02402 while(md) { 02403 if(md->type == eModifierType_Mirror && (md->mode&eModifierMode_Realtime)) { 02404 break; 02405 } 02406 md = md->next; 02407 } 02408 02409 if(md && md->type == eModifierType_Mirror) { 02410 BKE_report(op->reports, RPT_ERROR_INVALID_CONTEXT, "This operator does not support an active mirror modifier"); 02411 return OPERATOR_CANCELLED; 02412 } 02413 vgroup_fix(scene, ob, distToBe, strength, cp); 02414 02415 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02416 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02417 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02418 02419 return OPERATOR_FINISHED; 02420 } 02421 02422 void OBJECT_OT_vertex_group_fix(wmOperatorType *ot) 02423 { 02424 /* identifiers */ 02425 ot->name= "Fix Vertex Group Deform"; 02426 ot->idname= "OBJECT_OT_vertex_group_fix"; 02427 ot->description= "Modify the position of selected vertices by changing only their respective " 02428 "groups' weights (this tool may be slow for many vertices)"; 02429 02430 /* api callbacks */ 02431 ot->poll= vertex_group_poll; 02432 ot->exec= vertex_group_fix_exec; 02433 02434 /* flags */ 02435 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02436 RNA_def_float(ot->srna, "dist", 0.0f, -FLT_MAX, FLT_MAX, "Distance", "The distance to move to", -10.0f, 10.0f); 02437 RNA_def_float(ot->srna, "strength", 1.f, -2.0f, FLT_MAX, "Strength", 02438 "The distance moved can be changed by this multiplier", -2.0f, 2.0f); 02439 RNA_def_float(ot->srna, "accuracy", 1.0f, 0.05f, FLT_MAX, "Change Sensitivity", 02440 "Change the amount weights are altered with each iteration: lower values are slower", 0.05f, 1.f); 02441 } 02442 02443 02444 static int vertex_group_lock_exec(bContext *C, wmOperator *op) 02445 { 02446 Object *ob= CTX_data_active_object(C); 02447 02448 int action = RNA_enum_get(op->ptr, "action"); 02449 02450 vgroup_lock_all(ob, action); 02451 02452 return OPERATOR_FINISHED; 02453 } 02454 02455 void OBJECT_OT_vertex_group_lock(wmOperatorType *ot) 02456 { 02457 /* identifiers */ 02458 ot->name= "Change the Lock On Vertex Groups"; 02459 ot->idname= "OBJECT_OT_vertex_group_lock"; 02460 02461 /* api callbacks */ 02462 ot->poll= vertex_group_poll; 02463 ot->exec= vertex_group_lock_exec; 02464 02465 /* flags */ 02466 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02467 02468 WM_operator_properties_select_all(ot); 02469 } 02470 02471 static int vertex_group_invert_exec(bContext *C, wmOperator *op) 02472 { 02473 Object *ob= ED_object_context(C); 02474 int auto_assign= RNA_boolean_get(op->ptr,"auto_assign"); 02475 int auto_remove= RNA_boolean_get(op->ptr,"auto_remove"); 02476 02477 vgroup_invert(ob, auto_assign, auto_remove); 02478 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02479 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02480 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02481 02482 return OPERATOR_FINISHED; 02483 } 02484 02485 void OBJECT_OT_vertex_group_invert(wmOperatorType *ot) 02486 { 02487 /* identifiers */ 02488 ot->name= "Invert Vertex Group"; 02489 ot->idname= "OBJECT_OT_vertex_group_invert"; 02490 02491 /* api callbacks */ 02492 ot->poll= vertex_group_poll; 02493 ot->exec= vertex_group_invert_exec; 02494 02495 /* flags */ 02496 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02497 02498 RNA_def_boolean(ot->srna, "auto_assign", TRUE, "Add Weights", 02499 "Add verts from groups that have zero weight before inverting"); 02500 RNA_def_boolean(ot->srna, "auto_remove", TRUE, "Remove Weights", 02501 "Remove verts from groups that have zero weight after inverting"); 02502 } 02503 02504 02505 static int vertex_group_blend_exec(bContext *C, wmOperator *UNUSED(op)) 02506 { 02507 Object *ob= ED_object_context(C); 02508 02509 vgroup_blend(ob); 02510 02511 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02512 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02513 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02514 02515 return OPERATOR_FINISHED; 02516 } 02517 02518 void OBJECT_OT_vertex_group_blend(wmOperatorType *ot) 02519 { 02520 /* identifiers */ 02521 ot->name= "Blend Vertex Group"; 02522 ot->idname= "OBJECT_OT_vertex_group_blend"; 02523 ot->description= ""; 02524 02525 /* api callbacks */ 02526 ot->poll= vertex_group_poll; 02527 ot->exec= vertex_group_blend_exec; 02528 02529 /* flags */ 02530 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02531 } 02532 02533 02534 static int vertex_group_clean_exec(bContext *C, wmOperator *op) 02535 { 02536 Object *ob= ED_object_context(C); 02537 02538 float limit= RNA_float_get(op->ptr,"limit"); 02539 int all_groups= RNA_boolean_get(op->ptr,"all_groups"); 02540 int keep_single= RNA_boolean_get(op->ptr,"keep_single"); 02541 02542 if(all_groups) vgroup_clean_all(ob, limit, keep_single); 02543 else vgroup_clean(ob, limit, keep_single); 02544 02545 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02546 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02547 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02548 02549 return OPERATOR_FINISHED; 02550 } 02551 02552 void OBJECT_OT_vertex_group_clean(wmOperatorType *ot) 02553 { 02554 /* identifiers */ 02555 ot->name= "Clean Vertex Group"; 02556 ot->idname= "OBJECT_OT_vertex_group_clean"; 02557 ot->description= "Remove Vertex Group assignments which aren't required"; 02558 02559 /* api callbacks */ 02560 ot->poll= vertex_group_poll; 02561 ot->exec= vertex_group_clean_exec; 02562 02563 /* flags */ 02564 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02565 02566 RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, 1.0, "Limit", "Remove weights under this limit", 0.001f, 0.99f); 02567 RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Clean all vertex groups"); 02568 RNA_def_boolean(ot->srna, "keep_single", FALSE, "Keep Single", 02569 "Keep verts assigned to at least one group when cleaning"); 02570 } 02571 02572 02573 static int vertex_group_mirror_exec(bContext *C, wmOperator *op) 02574 { 02575 Object *ob= ED_object_context(C); 02576 02577 ED_vgroup_mirror(ob, 02578 RNA_boolean_get(op->ptr,"mirror_weights"), 02579 RNA_boolean_get(op->ptr,"flip_group_names"), 02580 RNA_boolean_get(op->ptr,"all_groups")); 02581 02582 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02583 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); 02584 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); 02585 02586 return OPERATOR_FINISHED; 02587 } 02588 02589 void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot) 02590 { 02591 /* identifiers */ 02592 ot->name= "Mirror Vertex Group"; 02593 ot->idname= "OBJECT_OT_vertex_group_mirror"; 02594 ot->description= "Mirror all vertex groups, flip weights and/or names, editing only selected vertices, " 02595 "flipping when both sides are selected otherwise copy from unselected"; 02596 02597 /* api callbacks */ 02598 ot->poll= vertex_group_poll; 02599 ot->exec= vertex_group_mirror_exec; 02600 02601 /* flags */ 02602 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02603 02604 /* properties */ 02605 RNA_def_boolean(ot->srna, "mirror_weights", TRUE, "Mirror Weights", "Mirror weights"); 02606 RNA_def_boolean(ot->srna, "flip_group_names", TRUE, "Flip Groups", "Flip vertex group names"); 02607 RNA_def_boolean(ot->srna, "all_groups", FALSE, "All Groups", "Mirror all vertex groups weights"); 02608 02609 } 02610 02611 static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *UNUSED(op)) 02612 { 02613 Scene *scene= CTX_data_scene(C); 02614 Object *ob= ED_object_context(C); 02615 Base *base; 02616 int retval= OPERATOR_CANCELLED; 02617 02618 for(base=scene->base.first; base; base= base->next) { 02619 if(base->object->type==ob->type) { 02620 if(base->object!=ob && base->object->data==ob->data) { 02621 BLI_freelistN(&base->object->defbase); 02622 BLI_duplicatelist(&base->object->defbase, &ob->defbase); 02623 base->object->actdef= ob->actdef; 02624 02625 DAG_id_tag_update(&base->object->id, OB_RECALC_DATA); 02626 WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object); 02627 WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data); 02628 02629 retval = OPERATOR_FINISHED; 02630 } 02631 } 02632 } 02633 02634 return retval; 02635 } 02636 02637 void OBJECT_OT_vertex_group_copy_to_linked(wmOperatorType *ot) 02638 { 02639 /* identifiers */ 02640 ot->name= "Copy Vertex Groups to Linked"; 02641 ot->idname= "OBJECT_OT_vertex_group_copy_to_linked"; 02642 ot->description= "Copy Vertex Groups to all users of the same Geometry data"; 02643 02644 /* api callbacks */ 02645 ot->poll= vertex_group_poll; 02646 ot->exec= vertex_group_copy_to_linked_exec; 02647 02648 /* flags */ 02649 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02650 } 02651 02652 static int vertex_group_copy_to_selected_exec(bContext *C, wmOperator *op) 02653 { 02654 Object *obact= ED_object_context(C); 02655 int change= 0; 02656 int fail= 0; 02657 02658 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) 02659 { 02660 if(obact != ob) { 02661 if(ED_vgroup_copy_array(ob, obact)) change++; 02662 else fail++; 02663 } 02664 } 02665 CTX_DATA_END; 02666 02667 if((change == 0 && fail == 0) || fail) { 02668 BKE_reportf(op->reports, RPT_ERROR, 02669 "Copy to VGroups to Selected warning done %d, failed %d, object data must have matching indicies", 02670 change, fail); 02671 } 02672 02673 return OPERATOR_FINISHED; 02674 } 02675 02676 02677 void OBJECT_OT_vertex_group_copy_to_selected(wmOperatorType *ot) 02678 { 02679 /* identifiers */ 02680 ot->name= "Copy Vertex Group to Selected"; 02681 ot->idname= "OBJECT_OT_vertex_group_copy_to_selected"; 02682 ot->description= "Copy Vertex Groups to other selected objects with matching indices"; 02683 02684 /* api callbacks */ 02685 ot->poll= vertex_group_poll; 02686 ot->exec= vertex_group_copy_to_selected_exec; 02687 02688 /* flags */ 02689 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02690 } 02691 02692 static EnumPropertyItem vgroup_items[]= { 02693 {0, NULL, 0, NULL, NULL}}; 02694 02695 static int set_active_group_exec(bContext *C, wmOperator *op) 02696 { 02697 Object *ob= ED_object_context(C); 02698 int nr= RNA_enum_get(op->ptr, "group"); 02699 02700 BLI_assert(nr+1 >= 0); 02701 ob->actdef= nr+1; 02702 02703 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02704 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob); 02705 02706 return OPERATOR_FINISHED; 02707 } 02708 02709 static EnumPropertyItem *vgroup_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) 02710 { 02711 Object *ob= ED_object_context(C); 02712 EnumPropertyItem tmp = {0, "", 0, "", ""}; 02713 EnumPropertyItem *item= NULL; 02714 bDeformGroup *def; 02715 int a, totitem= 0; 02716 02717 if(!ob) 02718 return vgroup_items; 02719 02720 for(a=0, def=ob->defbase.first; def; def=def->next, a++) { 02721 tmp.value= a; 02722 tmp.icon= ICON_GROUP_VERTEX; 02723 tmp.identifier= def->name; 02724 tmp.name= def->name; 02725 RNA_enum_item_add(&item, &totitem, &tmp); 02726 } 02727 02728 RNA_enum_item_end(&item, &totitem); 02729 *free= 1; 02730 02731 return item; 02732 } 02733 02734 void OBJECT_OT_vertex_group_set_active(wmOperatorType *ot) 02735 { 02736 PropertyRNA *prop; 02737 02738 /* identifiers */ 02739 ot->name= "Set Active Vertex Group"; 02740 ot->idname= "OBJECT_OT_vertex_group_set_active"; 02741 ot->description= "Set the active vertex group"; 02742 02743 /* api callbacks */ 02744 ot->poll= vertex_group_poll; 02745 ot->exec= set_active_group_exec; 02746 ot->invoke= WM_menu_invoke; 02747 02748 /* flags */ 02749 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02750 02751 /* properties */ 02752 prop= RNA_def_enum(ot->srna, "group", vgroup_items, 0, "Group", "Vertex group to set as active"); 02753 RNA_def_enum_funcs(prop, vgroup_itemf); 02754 ot->prop= prop; 02755 } 02756 02757 /*creates the name_array parameter for vgroup_do_remap, call this before fiddling 02758 with the order of vgroups then call vgroup_do_remap after*/ 02759 static char *vgroup_init_remap(Object *ob) 02760 { 02761 bDeformGroup *def; 02762 int defbase_tot = BLI_countlist(&ob->defbase); 02763 char *name_array= MEM_mallocN(MAX_VGROUP_NAME * sizeof(char) * defbase_tot, "sort vgroups"); 02764 char *name; 02765 02766 name= name_array; 02767 for(def = ob->defbase.first; def; def=def->next) { 02768 BLI_strncpy(name, def->name, MAX_VGROUP_NAME); 02769 name += MAX_VGROUP_NAME; 02770 } 02771 02772 return name_array; 02773 } 02774 02775 static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op) 02776 { 02777 MDeformVert *dvert= NULL; 02778 bDeformGroup *def; 02779 int defbase_tot = BLI_countlist(&ob->defbase); 02780 02781 /* needs a dummy index at the start*/ 02782 int *sort_map_update= MEM_mallocN(sizeof(int) * (defbase_tot + 1), "sort vgroups"); 02783 int *sort_map= sort_map_update + 1; 02784 02785 char *name; 02786 int i; 02787 02788 name= name_array; 02789 for(def= ob->defbase.first, i=0; def; def=def->next, i++){ 02790 sort_map[i]= BLI_findstringindex(&ob->defbase, name, offsetof(bDeformGroup, name)); 02791 name += MAX_VGROUP_NAME; 02792 02793 BLI_assert(sort_map[i] != -1); 02794 } 02795 02796 if(ob->mode == OB_MODE_EDIT) { 02797 if(ob->type==OB_MESH) { 02798 EditMesh *em = BKE_mesh_get_editmesh(ob->data); 02799 EditVert *eve; 02800 02801 for(eve=em->verts.first; eve; eve=eve->next){ 02802 dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); 02803 if(dvert && dvert->totweight){ 02804 defvert_remap(dvert, sort_map, defbase_tot); 02805 } 02806 } 02807 } 02808 else { 02809 BKE_report(op->reports, RPT_ERROR, "Editmode lattice isnt supported yet"); 02810 MEM_freeN(sort_map_update); 02811 return OPERATOR_CANCELLED; 02812 } 02813 } 02814 else { 02815 int dvert_tot=0; 02816 02817 ED_vgroup_give_array(ob->data, &dvert, &dvert_tot); 02818 02819 /*create as necassary*/ 02820 while(dvert && dvert_tot--) { 02821 if(dvert->totweight) 02822 defvert_remap(dvert, sort_map, defbase_tot); 02823 dvert++; 02824 } 02825 } 02826 02827 /* update users */ 02828 for(i=0; i<defbase_tot; i++) 02829 sort_map[i]++; 02830 02831 sort_map_update[0]= 0; 02832 vgroup_remap_update_users(ob, sort_map_update); 02833 02834 BLI_assert(sort_map_update[ob->actdef] >= 0); 02835 ob->actdef= sort_map_update[ob->actdef]; 02836 02837 MEM_freeN(sort_map_update); 02838 02839 return OPERATOR_FINISHED; 02840 } 02841 02842 static int vgroup_sort(void *def_a_ptr, void *def_b_ptr) 02843 { 02844 bDeformGroup *def_a= (bDeformGroup *)def_a_ptr; 02845 bDeformGroup *def_b= (bDeformGroup *)def_b_ptr; 02846 02847 return BLI_natstrcmp(def_a->name, def_b->name); 02848 } 02849 02850 static int vertex_group_sort_exec(bContext *C, wmOperator *op) 02851 { 02852 Object *ob= ED_object_context(C); 02853 char *name_array; 02854 int ret; 02855 02856 /*init remapping*/ 02857 name_array = vgroup_init_remap(ob); 02858 02859 /*sort vgroup names*/ 02860 BLI_sortlist(&ob->defbase, vgroup_sort); 02861 02862 /*remap vgroup data to map to correct names*/ 02863 ret = vgroup_do_remap(ob, name_array, op); 02864 02865 if (ret != OPERATOR_CANCELLED) { 02866 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02867 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob); 02868 } 02869 02870 if (name_array) MEM_freeN(name_array); 02871 02872 return ret; 02873 } 02874 02875 void OBJECT_OT_vertex_group_sort(wmOperatorType *ot) 02876 { 02877 ot->name= "Sort Vertex Groups"; 02878 ot->idname= "OBJECT_OT_vertex_group_sort"; 02879 ot->description= "Sorts vertex groups alphabetically"; 02880 02881 /* api callbacks */ 02882 ot->poll= vertex_group_poll; 02883 ot->exec= vertex_group_sort_exec; 02884 02885 /* flags */ 02886 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02887 } 02888 02889 static int vgroup_move_exec(bContext *C, wmOperator *op) 02890 { 02891 Object *ob= ED_object_context(C); 02892 bDeformGroup *def; 02893 char *name_array; 02894 int dir= RNA_enum_get(op->ptr, "direction"), ret; 02895 02896 def = BLI_findlink(&ob->defbase, ob->actdef - 1); 02897 if (!def) { 02898 return OPERATOR_CANCELLED; 02899 } 02900 02901 name_array = vgroup_init_remap(ob); 02902 02903 if (dir == 1) { /*up*/ 02904 void *prev = def->prev; 02905 02906 BLI_remlink(&ob->defbase, def); 02907 BLI_insertlinkbefore(&ob->defbase, prev, def); 02908 } else { /*down*/ 02909 void *next = def->next; 02910 02911 BLI_remlink(&ob->defbase, def); 02912 BLI_insertlinkafter(&ob->defbase, next, def); 02913 } 02914 02915 ret = vgroup_do_remap(ob, name_array, op); 02916 02917 if (name_array) MEM_freeN(name_array); 02918 02919 if (ret != OPERATOR_CANCELLED) { 02920 DAG_id_tag_update(&ob->id, OB_RECALC_DATA); 02921 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob); 02922 } 02923 02924 return ret; 02925 } 02926 02927 void OBJECT_OT_vertex_group_move(wmOperatorType *ot) 02928 { 02929 static EnumPropertyItem vgroup_slot_move[] = { 02930 {1, "UP", 0, "Up", ""}, 02931 {-1, "DOWN", 0, "Down", ""}, 02932 {0, NULL, 0, NULL, NULL} 02933 }; 02934 02935 /* identifiers */ 02936 ot->name= "Move Vertex Group"; 02937 ot->idname= "OBJECT_OT_vertex_group_move"; 02938 02939 /* api callbacks */ 02940 ot->poll= vertex_group_poll; 02941 ot->exec= vgroup_move_exec; 02942 02943 /* flags */ 02944 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02945 02946 RNA_def_enum(ot->srna, "direction", vgroup_slot_move, 0, "Direction", "Direction to move, UP or DOWN"); 02947 }