From ace8d45c1c7cdd754771f9e4aceae80de2154653 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 15 Jan 2010 17:28:00 +0000 Subject: - particle drawing was using invalid memory with weights. - particle set weight operator (Shift + K) and from the menu. - mirror vertex groups operator can also flip weight group names. a number of utility functions for weight groups added int *get_defgroup_flip_map(struct Object *ob); void flip_vertexgroup_name (char *name_r, const char *name, int strip_number); // moved from modifier.c void copy_defvert (struct MDeformVert *dvert_r, const struct MDeformVert *dvert); void flip_defvert (struct MDeformVert *dvert, int *flip_map); --- source/blender/blenkernel/BKE_deform.h | 5 + source/blender/blenkernel/intern/deform.c | 176 ++++++++++++++++++++++++ source/blender/blenkernel/intern/modifier.c | 116 +--------------- source/blender/blenkernel/intern/particle.c | 19 +-- source/blender/editors/mesh/editmesh_mods.c | 2 +- source/blender/editors/object/object_intern.h | 1 + source/blender/editors/object/object_ops.c | 1 + source/blender/editors/object/object_vgroup.c | 100 +++++++++++++- source/blender/editors/physics/particle_edit.c | 46 +++++++ source/blender/editors/physics/physics_intern.h | 1 + source/blender/editors/physics/physics_ops.c | 3 + 11 files changed, 343 insertions(+), 127 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index 8a34b286881..d9cf6bc8feb 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -44,11 +44,16 @@ void copy_defgroups (struct ListBase *lb1, struct ListBase *lb2); struct bDeformGroup *copy_defgroup (struct bDeformGroup *ingroup); struct bDeformGroup *get_named_vertexgroup (Object *ob, char *name); int get_defgroup_num (struct Object *ob, struct bDeformGroup *dg); +int *get_defgroup_flip_map(struct Object *ob); int get_named_vertexgroup_num (Object *ob, const char *name); void unique_vertexgroup_name (struct bDeformGroup *dg, struct Object *ob); +void flip_vertexgroup_name (char *name_r, const char *name, int strip_number); float deformvert_get_weight(const struct MDeformVert *dvert, int group_num); float vertexgroup_get_vertex_weight(const struct MDeformVert *dvert, int index, int group_num); +void copy_defvert (struct MDeformVert *dvert_r, const struct MDeformVert *dvert); +void flip_defvert (struct MDeformVert *dvert, int *flip_map); + #endif diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index c1e45243bb5..620e114bad2 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -34,6 +34,7 @@ #include #include +#include "ctype.h" #include "MEM_guardedalloc.h" @@ -95,6 +96,36 @@ bDeformGroup *copy_defgroup (bDeformGroup *ingroup) return outgroup; } +void copy_defvert (MDeformVert *dvert_r, const MDeformVert *dvert) +{ + if(dvert_r->totweight == dvert->totweight) { + if(dvert->totweight) + memcpy(dvert_r->dw, dvert->dw, dvert->totweight * sizeof(MDeformWeight)); + } + else { + if(dvert_r->dw) + MEM_freeN(dvert_r->dw); + + if(dvert->totweight) + dvert_r->dw= MEM_dupallocN(dvert->dw); + else + dvert_r->dw= NULL; + + dvert_r->totweight = dvert->totweight; + } +} + +void flip_defvert (MDeformVert *dvert, int *flip_map) +{ + MDeformWeight *dw; + int i; + + for(dw= dvert->dw, i=0; itotweight; dw++, i++) + if(flip_map[dw->def_nr] >= 0) + dw->def_nr= flip_map[dw->def_nr]; +} + + bDeformGroup *get_named_vertexgroup (Object *ob, char *name) { /* return a pointer to the deform group with this name @@ -167,6 +198,36 @@ int get_defgroup_num (Object *ob, bDeformGroup *dg) } +/* note, must be freed */ +int *get_defgroup_flip_map(Object *ob) +{ + bDeformGroup *dg; + int totdg= BLI_countlist(&ob->defbase); + + if(totdg==0) { + return NULL; + } + else { + char name[sizeof(dg->name)]; + int i, flip_num, *map= MEM_mallocN(totdg * sizeof(int), "get_defgroup_flip_map"); + memset(map, -1, totdg * sizeof(int)); + + for (dg=ob->defbase.first, i=0; dg; dg=dg->next, i++) { + if(map[i] == -1) { /* may be calculated previously */ + flip_vertexgroup_name(name, dg->name, 0); + if(strcmp(name, dg->name)) { + flip_num= get_named_vertexgroup_num(ob, name); + if(flip_num > -1) { + map[i]= flip_num; + map[flip_num]= i; /* save an extra lookup */ + } + } + } + } + return map; + } +} + void unique_vertexgroup_name (bDeformGroup *dg, Object *ob) { bDeformGroup *curdef; @@ -221,6 +282,121 @@ void unique_vertexgroup_name (bDeformGroup *dg, Object *ob) } } + +/* finds the best possible flipped name. For renaming; check for unique names afterwards */ +/* if strip_number: removes number extensions */ +void flip_vertexgroup_name (char *name_r, const char *name, int strip_number) +{ + int len; + char prefix[sizeof((bDeformGroup *)NULL)->name]={""}; /* The part before the facing */ + char suffix[sizeof((bDeformGroup *)NULL)->name]={""}; /* The part after the facing */ + char replace[sizeof((bDeformGroup *)NULL)->name]={""}; /* The replacement string */ + char number[sizeof((bDeformGroup *)NULL)->name]={""}; /* The number extension string */ + char *index=NULL; + + len= strlen(name); + if(len<3) return; // we don't do names like .R or .L + + /* We first check the case with a .### extension, let's find the last period */ + if(isdigit(name[len-1])) { + index= strrchr(name, '.'); // last occurrence + if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever! + if(strip_number==0) + strcpy(number, index); + *index= 0; + len= strlen(name); + } + } + + strcpy (prefix, name); + +#define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_') + + /* first case; separator . - _ with extensions r R l L */ + if( IS_SEPARATOR(name[len-2]) ) { + switch(name[len-1]) { + case 'l': + prefix[len-1]= 0; + strcpy(replace, "r"); + break; + case 'r': + prefix[len-1]= 0; + strcpy(replace, "l"); + break; + case 'L': + prefix[len-1]= 0; + strcpy(replace, "R"); + break; + case 'R': + prefix[len-1]= 0; + strcpy(replace, "L"); + break; + } + } + /* case; beginning with r R l L , with separator after it */ + else if( IS_SEPARATOR(name[1]) ) { + switch(name[0]) { + case 'l': + strcpy(replace, "r"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'r': + strcpy(replace, "l"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'L': + strcpy(replace, "R"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + case 'R': + strcpy(replace, "L"); + strcpy(suffix, name+1); + prefix[0]= 0; + break; + } + } + else if(len > 5) { + /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */ + index = BLI_strcasestr(prefix, "right"); + if (index==prefix || index==prefix+len-5) { + if(index[0]=='r') + strcpy (replace, "left"); + else { + if(index[1]=='I') + strcpy (replace, "LEFT"); + else + strcpy (replace, "Left"); + } + *index= 0; + strcpy (suffix, index+5); + } + else { + index = BLI_strcasestr(prefix, "left"); + if (index==prefix || index==prefix+len-4) { + if(index[0]=='l') + strcpy (replace, "right"); + else { + if(index[1]=='E') + strcpy (replace, "RIGHT"); + else + strcpy (replace, "Right"); + } + *index= 0; + strcpy (suffix, index+4); + } + } + } + +#undef IS_SEPARATOR + + sprintf (name_r, "%s%s%s%s", prefix, replace, suffix, number); +} + + + float deformvert_get_weight(const struct MDeformVert *dvert, int group_num) { if(dvert) diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 7e211f60cd5..3c925e5ff25 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -39,7 +39,6 @@ #include "stdarg.h" #include "math.h" #include "float.h" -#include "ctype.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -1801,118 +1800,6 @@ static void mirrorModifier_updateDepgraph(ModifierData *md, DagForest *forest, S } } -/* finds the best possible flipped name. For renaming; check for unique names afterwards */ -/* if strip_number: removes number extensions */ -static void vertgroup_flip_name (char *name, int strip_number) -{ - int len; - char prefix[128]={""}; /* The part before the facing */ - char suffix[128]={""}; /* The part after the facing */ - char replace[128]={""}; /* The replacement string */ - char number[128]={""}; /* The number extension string */ - char *index=NULL; - - len= strlen(name); - if(len<3) return; // we don't do names like .R or .L - - /* We first check the case with a .### extension, let's find the last period */ - if(isdigit(name[len-1])) { - index= strrchr(name, '.'); // last occurrence - if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever! - if(strip_number==0) - strcpy(number, index); - *index= 0; - len= strlen(name); - } - } - - strcpy (prefix, name); - -#define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_') - - /* first case; separator . - _ with extensions r R l L */ - if( IS_SEPARATOR(name[len-2]) ) { - switch(name[len-1]) { - case 'l': - prefix[len-1]= 0; - strcpy(replace, "r"); - break; - case 'r': - prefix[len-1]= 0; - strcpy(replace, "l"); - break; - case 'L': - prefix[len-1]= 0; - strcpy(replace, "R"); - break; - case 'R': - prefix[len-1]= 0; - strcpy(replace, "L"); - break; - } - } - /* case; beginning with r R l L , with separator after it */ - else if( IS_SEPARATOR(name[1]) ) { - switch(name[0]) { - case 'l': - strcpy(replace, "r"); - strcpy(suffix, name+1); - prefix[0]= 0; - break; - case 'r': - strcpy(replace, "l"); - strcpy(suffix, name+1); - prefix[0]= 0; - break; - case 'L': - strcpy(replace, "R"); - strcpy(suffix, name+1); - prefix[0]= 0; - break; - case 'R': - strcpy(replace, "L"); - strcpy(suffix, name+1); - prefix[0]= 0; - break; - } - } - else if(len > 5) { - /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */ - index = BLI_strcasestr(prefix, "right"); - if (index==prefix || index==prefix+len-5) { - if(index[0]=='r') - strcpy (replace, "left"); - else { - if(index[1]=='I') - strcpy (replace, "LEFT"); - else - strcpy (replace, "Left"); - } - *index= 0; - strcpy (suffix, index+5); - } - else { - index = BLI_strcasestr(prefix, "left"); - if (index==prefix || index==prefix+len-4) { - if(index[0]=='l') - strcpy (replace, "right"); - else { - if(index[1]=='E') - strcpy (replace, "RIGHT"); - else - strcpy (replace, "Right"); - } - *index= 0; - strcpy (suffix, index+4); - } - } - } - -#undef IS_SEPARATOR - - sprintf (name, "%s%s%s%s", prefix, replace, suffix, number); -} - static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, Object *ob, DerivedMesh *dm, @@ -2022,8 +1909,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd, continue; def = vector_def[dvert->dw[j].def_nr]; - strcpy(tmpname, def->name); - vertgroup_flip_name(tmpname,0); + flip_vertexgroup_name(tmpname, def->name, 0); for(b = 0, defb = ob->defbase.first; defb; defb = defb->next, b++) diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 63d681cce0b..006e05370b1 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -2999,8 +2999,8 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf /* should init_particle_interpolation set this ? */ if(pset->brushtype==PE_BRUSH_WEIGHT){ - pind.hkey[0] = pa->hair; - pind.hkey[1] = pa->hair + 1; + pind.hkey[0] = NULL; + pind.hkey[1] = pa->hair; } @@ -3036,12 +3036,6 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result); - /* should init_particle_interpolation set this ? */ - if(pset->brushtype==PE_BRUSH_WEIGHT){ - pind.hkey[0] = pind.hkey[1]; - pind.hkey[1]++; - } - /* non-hair points are already in global space */ if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { mul_m4_v3(hairmat, result.co); @@ -3099,10 +3093,17 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf /* selection coloring in edit mode */ if(pset->brushtype==PE_BRUSH_WEIGHT){ - if(k==steps) + if(k==0) + weight_to_rgb(pind.hkey[1]->weight, ca->col, ca->col+1, ca->col+2); + else if(k >= steps - 1) weight_to_rgb(pind.hkey[0]->weight, ca->col, ca->col+1, ca->col+2); else weight_to_rgb((1.0f - keytime) * pind.hkey[0]->weight + keytime * pind.hkey[1]->weight, ca->col, ca->col+1, ca->col+2); + + /* at the moment this is only used for weight painting. + * will need to move out of this check if its used elsewhere. */ + pind.hkey[0] = pind.hkey[1]; + pind.hkey[1]++; } else { if((ekey + (pind.ekey[0] - point->keys))->flag & PEK_SELECT){ diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index ab558afe897..412a733dee0 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -120,7 +120,7 @@ void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em) } } -void EM_select_mirrored(Object *obedit, EditMesh *em, int extend) +static void EM_select_mirrored(Object *obedit, EditMesh *em, int extend) { EditVert *eve; diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 861b2cc0a6e..cfb4cda2460 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -187,6 +187,7 @@ void OBJECT_OT_vertex_group_levels(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_invert(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_blend(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_clean(struct wmOperatorType *ot); +void OBJECT_OT_vertex_group_mirror(struct wmOperatorType *ot); void OBJECT_OT_vertex_group_set_active(struct wmOperatorType *ot); void OBJECT_OT_game_property_new(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 0837051ae0c..8b29e2ca2ae 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -173,6 +173,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_vertex_group_levels); WM_operatortype_append(OBJECT_OT_vertex_group_blend); WM_operatortype_append(OBJECT_OT_vertex_group_clean); + WM_operatortype_append(OBJECT_OT_vertex_group_mirror); WM_operatortype_append(OBJECT_OT_vertex_group_set_active); WM_operatortype_append(OBJECT_OT_game_property_new); diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 43fabff6793..84b70e0a690 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -903,6 +903,68 @@ static void vgroup_clean_all(Object *ob, float eul, int keep_single) } } +static void vgroup_mirror(Object *ob, int mirror_weights, int flip_vgroups) +{ + EditVert *eve, *eve_mirr; + MDeformVert *dvert, *dvert_mirr; + int *flip_map; + + if(mirror_weights==0 && flip_vgroups==0) + return; + + /* only the active group */ + if(ob->type == OB_MESH) { + Mesh *me= ob->data; + EditMesh *em = BKE_mesh_get_editmesh(me); + + EM_cache_x_mirror_vert(ob, em); + + if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) + return; + + flip_map= get_defgroup_flip_map(ob); + + /* Go through the list of editverts and assign them */ + for(eve=em->verts.first; eve; eve=eve->next){ + if((eve_mirr=eve->tmp.v)) { + if(eve_mirr->f & SELECT || eve->f & SELECT) { + dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + dvert_mirr= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT); + if(dvert && dvert_mirr) { + if(eve_mirr->f & SELECT && eve->f & SELECT) { + /* swap */ + if(mirror_weights) + SWAP(MDeformVert, *dvert, *dvert_mirr); + if(flip_vgroups) { + flip_defvert(dvert, flip_map); + flip_defvert(dvert_mirr, flip_map); + } + } + else { + /* dvert should always be the target */ + if(eve_mirr->f & SELECT) { + SWAP(MDeformVert *, dvert, dvert_mirr); + } + + if(mirror_weights) + copy_defvert(dvert, dvert_mirr); + if(flip_vgroups) { + flip_defvert(dvert, flip_map); + } + } + } + } + + eve->tmp.v= eve_mirr->tmp.v= NULL; + } + } + + MEM_freeN(flip_map); + + BKE_mesh_end_editmesh(me, em); + } +} + static void vgroup_delete_update_users(Object *ob, int id) { ExplodeModifierData *emd; @@ -1026,7 +1088,7 @@ static void vgroup_active_remove_verts(Object *ob, int allverts) for(eve=em->verts.first; eve; eve=eve->next){ dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); - if(dvert && dvert->dw && ((eve->f & 1) || allverts)){ + if(dvert && dvert->dw && ((eve->f & SELECT) || allverts)){ for(i=0; itotweight; i++){ /* Find group */ eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr); @@ -1208,7 +1270,7 @@ static void vgroup_assign_verts(Object *ob, float weight) for(eve=em->verts.first; eve; eve=eve->next){ dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); - if(dvert && (eve->f & 1)){ + if(dvert && (eve->f & SELECT)){ done=0; /* See if this vert already has a reference to this group */ /* If so: Change its weight */ @@ -1684,6 +1746,40 @@ void OBJECT_OT_vertex_group_clean(wmOperatorType *ot) } +static int vertex_group_mirror_exec(bContext *C, wmOperator *op) +{ + Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; + + vgroup_mirror(ob, RNA_boolean_get(op->ptr,"mirror_weights"), RNA_boolean_get(op->ptr,"flip_group_names")); + + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_vertex_group_mirror(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mirror Vertex Group"; + ot->idname= "OBJECT_OT_vertex_group_mirror"; + ot->description= "Mirror weights, and flip vertex group names, copying when only one side is selected."; + + /* api callbacks */ + ot->poll= vertex_group_poll_edit; + ot->exec= vertex_group_mirror_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "mirror_weights", TRUE, "Mirror Weights", "Mirror weights."); + RNA_def_boolean(ot->srna, "flip_group_names", TRUE, "Flip Groups", "Flip vertex group names while mirroring."); + +} + + static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index fe38d71dc92..f0870ca9764 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -2366,6 +2366,52 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot) RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f); } + +static int weight_set_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + ParticleEditSettings *pset= PE_settings(scene); + Object *ob= CTX_data_active_object(C); + PTCacheEdit *edit= PE_get_current(scene, ob); + ParticleSystem *psys = edit->psys; + POINT_P; + KEY_K; + HairKey *hkey; + float weight; + ParticleBrushData *brush= &pset->brush[pset->brushtype]; + edit= psys->edit; + + weight= (float)(brush->strength / 100.0f); + + LOOP_SELECTED_POINTS { + ParticleData *pa= psys->particles + p; + + LOOP_SELECTED_KEYS { + hkey= pa->hair + k; + hkey->weight= weight; + } + } + + DAG_id_flush_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob); + + return OPERATOR_FINISHED; +} + +void PARTICLE_OT_weight_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Weight Set"; + ot->idname= "PARTICLE_OT_weight_set"; + + /* api callbacks */ + ot->exec= weight_set_exec; + ot->poll= PE_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /************************ cursor drawing *******************************/ static void brush_drawcursor(bContext *C, int x, int y, void *customdata) diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h index cc0a288f8be..3de5c256df7 100644 --- a/source/blender/editors/physics/physics_intern.h +++ b/source/blender/editors/physics/physics_intern.h @@ -50,6 +50,7 @@ void PARTICLE_OT_reveal(struct wmOperatorType *ot); void PARTICLE_OT_rekey(struct wmOperatorType *ot); void PARTICLE_OT_subdivide(struct wmOperatorType *ot); void PARTICLE_OT_remove_doubles(struct wmOperatorType *ot); +void PARTICLE_OT_weight_set(struct wmOperatorType *ot); void PARTICLE_OT_delete(struct wmOperatorType *ot); void PARTICLE_OT_mirror(struct wmOperatorType *ot); diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index 5cb8230e463..2728f64a777 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -57,6 +57,7 @@ static void operatortypes_particle(void) WM_operatortype_append(PARTICLE_OT_rekey); WM_operatortype_append(PARTICLE_OT_subdivide); WM_operatortype_append(PARTICLE_OT_remove_doubles); + WM_operatortype_append(PARTICLE_OT_weight_set); WM_operatortype_append(PARTICLE_OT_delete); WM_operatortype_append(PARTICLE_OT_mirror); @@ -111,6 +112,8 @@ static void keymap_particle(wmKeyConfig *keyconf) RNA_enum_set(WM_keymap_add_item(keymap, "PARTICLE_OT_brush_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH); WM_keymap_add_menu(keymap, "VIEW3D_MT_particle_specials", WKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "PARTICLE_OT_weight_set", KKEY, KM_PRESS, KM_SHIFT, 0); ED_object_generic_keymap(keyconf, keymap, 1); } -- cgit v1.2.3