Index: source/blender/blenkernel/BKE_object.h =================================================================== --- source/blender/blenkernel/BKE_object.h (revision 37882) +++ source/blender/blenkernel/BKE_object.h (working copy) @@ -39,6 +39,7 @@ #endif struct Base; +struct bContext; struct Scene; struct Object; struct Camera; @@ -50,6 +51,7 @@ struct bAction; struct RenderData; struct rctf; +struct wmOperator; void clear_workob(struct Object *workob); void what_does_parent(struct Scene *scene, struct Object *ob, struct Object *workob); @@ -106,6 +108,8 @@ void object_to_mat3(struct Object *ob, float mat[][3]); void object_to_mat4(struct Object *ob, float mat[][4]); void object_apply_mat4(struct Object *ob, float mat[][4], const short use_compat, const short use_parent); +int test_parent_loop(struct Object *par, struct Object *ob); +int do_parent_set(struct bContext *C, struct wmOperator *op, struct Object *par, int partype); void set_no_parent_ipo(int val); Index: source/blender/blenkernel/intern/object.c =================================================================== --- source/blender/blenkernel/intern/object.c (revision 37882) +++ source/blender/blenkernel/intern/object.c (working copy) @@ -71,7 +71,9 @@ #include "BKE_action.h" #include "BKE_bullet.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_deform.h" +#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_animsys.h" #include "BKE_anim.h" @@ -93,12 +95,20 @@ #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_property.h" +#include "BKE_report.h" #include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_sequencer.h" #include "BKE_softbody.h" #include "BKE_material.h" +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_armature.h" +#include "ED_keyframing.h" +#include "ED_object.h" + #include "LBM_fluidsim.h" #ifdef WITH_PYTHON @@ -1803,6 +1813,192 @@ add_v3_v3v3(mat[3], ob->loc, ob->dloc); } +/* ******* parent types ******* */ +#define PAR_OBJECT 0 +#define PAR_ARMATURE 1 +#define PAR_ARMATURE_NAME 2 +#define PAR_ARMATURE_ENVELOPE 3 +#define PAR_ARMATURE_AUTO 4 +#define PAR_BONE 5 +#define PAR_CURVE 6 +#define PAR_FOLLOW 7 +#define PAR_PATH_CONST 8 +#define PAR_LATTICE 9 +#define PAR_VERTEX 10 +#define PAR_TRIA 11 + +int test_parent_loop(Object *par, Object *ob) +{ + /* test if 'ob' is a parent somewhere in par's parents */ + + if(par == NULL) return 0; + if(ob == par) return 1; + + return test_parent_loop(par->parent, ob); +} + +int do_parent_set(bContext *C, wmOperator *op, Object *par, int partype) +{ + Main *bmain= CTX_data_main(C); + Scene *scene= CTX_data_scene(C); + bPoseChannel *pchan= NULL; + int pararm= ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); + + par->recalc |= OB_RECALC_OB; + + /* preconditions */ + if(partype==PAR_FOLLOW || partype==PAR_PATH_CONST) { + if(par->type!=OB_CURVE) + return 0; + else { + Curve *cu= par->data; + + if((cu->flag & CU_PATH)==0) { + cu->flag |= CU_PATH|CU_FOLLOW; + makeDispListCurveTypes(scene, par, 0); /* force creation of path data */ + } + else cu->flag |= CU_FOLLOW; + + /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */ + if(partype == PAR_FOLLOW) { + /* get or create F-Curve */ + bAction *act = verify_adt_action(&cu->id, 1); + FCurve *fcu = verify_fcurve(act, NULL, "eval_time", 0, 1); + + /* setup dummy 'generator' modifier here to get 1-1 correspondance still working */ + if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) + add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); + } + + /* fall back on regular parenting now (for follow only) */ + if(partype == PAR_FOLLOW) + partype= PAR_OBJECT; + } + } + else if(partype==PAR_BONE) { + pchan= get_active_posechannel(par); + + if(pchan==NULL) { + BKE_report(op->reports, RPT_ERROR, "No active Bone"); + return 0; + } + } + + /* context iterator */ + CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) { + + if(ob!=par) { + + if( test_parent_loop(par, ob) ) { + BKE_report(op->reports, RPT_ERROR, "Loop in parents"); + } + else { + Object workob; + + /* apply transformation of previous parenting */ + /* object_apply_mat4(ob, ob->obmat); */ /* removed because of bug [#23577] */ + + /* set the parent (except for follow-path constraint option) */ + if(partype != PAR_PATH_CONST) + ob->parent= par; + + /* handle types */ + if (pchan) + strcpy(ob->parsubstr, pchan->name); + else + ob->parsubstr[0]= 0; + + if(partype == PAR_PATH_CONST) + ; /* don't do anything here, since this is not technically "parenting" */ + else if( ELEM(partype, PAR_CURVE, PAR_LATTICE) || pararm ) + { + /* partype is now set to PAROBJECT so that invisible 'virtual' modifiers don't need to be created + * NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, creating the virtual modifiers + */ + ob->partype= PAROBJECT; /* note, dna define, not operator property */ + //ob->partype= PARSKEL; /* note, dna define, not operator property */ + + /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses */ + // XXX currently this should only happen for meshes, curves, surfaces, and lattices - this stuff isn't available for metas yet + if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) + { + ModifierData *md; + + switch (partype) { + case PAR_CURVE: /* curve deform */ + md= ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, eModifierType_Curve); + ((CurveModifierData *)md)->object= par; + break; + case PAR_LATTICE: /* lattice deform */ + md= ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, eModifierType_Lattice); + ((LatticeModifierData *)md)->object= par; + break; + default: /* armature deform */ + md= ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, eModifierType_Armature); + ((ArmatureModifierData *)md)->object= par; + break; + } + } + } + else if (partype == PAR_BONE) + ob->partype= PARBONE; /* note, dna define, not operator property */ + else + ob->partype= PAROBJECT; /* note, dna define, not operator property */ + + /* constraint */ + if(partype == PAR_PATH_CONST) { + bConstraint *con; + bFollowPathConstraint *data; + float cmat[4][4], vec[3]; + + con = add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); + + data = con->data; + data->tar = par; + + get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra - give_timeoffset(ob)); + sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); + + ob->loc[0] = vec[0]; + ob->loc[1] = vec[1]; + ob->loc[2] = vec[2]; + } + else if(pararm && ob->type==OB_MESH && par->type == OB_ARMATURE) { + if(partype == PAR_ARMATURE_NAME) + create_vgroups_from_armature(op->reports, scene, ob, par, ARM_GROUPS_NAME, 0); + else if(partype == PAR_ARMATURE_ENVELOPE) + create_vgroups_from_armature(op->reports, scene, ob, par, ARM_GROUPS_ENVELOPE, 0); + else if(partype == PAR_ARMATURE_AUTO) { + WM_cursor_wait(1); + create_vgroups_from_armature(op->reports, scene, ob, par, ARM_GROUPS_AUTO, 0); + WM_cursor_wait(0); + } + /* get corrected inverse */ + ob->partype= PAROBJECT; + what_does_parent(scene, ob, &workob); + + invert_m4_m4(ob->parentinv, workob.obmat); + } + else { + /* calculate inverse parent matrix */ + what_does_parent(scene, ob, &workob); + invert_m4_m4(ob->parentinv, workob.obmat); + } + + ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA; + } + } + } + CTX_DATA_END; + + DAG_scene_sort(bmain, scene); + DAG_ids_flush_update(bmain, 0); + WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT|ND_PARENT, NULL); + + return 1; +} + /* extern */ int enable_cu_speed= 1; Index: source/blender/editors/space_outliner/outliner.c =================================================================== --- source/blender/editors/space_outliner/outliner.c (revision 37882) +++ source/blender/editors/space_outliner/outliner.c (working copy) @@ -79,6 +79,7 @@ #include "BKE_library.h" #include "BKE_main.h" #include "BKE_modifier.h" +#include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_sequencer.h" @@ -137,6 +138,9 @@ static int group_select_flag(Group *gr); +static int outliner_get_item_hover(bContext *C, wmEvent *event, wmOperator *op, TreeElement *te, TreeStoreElem *tselem, float *fmval); +static int parent_drop_invoke(bContext *C, wmOperator *op, wmEvent *event); + /* ******************** PERSISTANT DATA ***************** */ static void outliner_storage_cleanup(SpaceOops *soops) @@ -4290,6 +4294,229 @@ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; } +/* ******************** Parent Drop Operator *********************** */ +#define PAR_OBJECT 0 +#define PAR_ARMATURE 1 +#define PAR_ARMATURE_NAME 2 +#define PAR_ARMATURE_ENVELOPE 3 +#define PAR_ARMATURE_AUTO 4 +#define PAR_BONE 5 +#define PAR_CURVE 6 +#define PAR_FOLLOW 7 +#define PAR_PATH_CONST 8 +#define PAR_LATTICE 9 +#define PAR_VERTEX 10 +#define PAR_TRIA 11 + +EnumPropertyItem prop_make_parent_types[] = { + {PAR_OBJECT, "OBJECT", 0, "Object", ""}, + {PAR_ARMATURE, "ARMATURE", 0, "Armature Deform", ""}, + {PAR_ARMATURE_NAME, "ARMATURE_NAME", 0, " With Empty Groups", ""}, + {PAR_ARMATURE_AUTO, "ARMATURE_AUTO", 0, " With Automatic Weights", ""}, + {PAR_ARMATURE_ENVELOPE, "ARMATURE_ENVELOPE", 0, " With Envelope Weights", ""}, + {PAR_BONE, "BONE", 0, "Bone", ""}, + {PAR_CURVE, "CURVE", 0, "Curve Deform", ""}, + {PAR_FOLLOW, "FOLLOW", 0, "Follow Path", ""}, + {PAR_PATH_CONST, "PATH_CONST", 0, "Path Constraint", ""}, + {PAR_LATTICE, "LATTICE", 0, "Lattice Deform", ""}, + {PAR_VERTEX, "VERTEX", 0, "Vertex", ""}, + {PAR_TRIA, "TRIA", 0, "Triangle", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static int parent_drop_exec(bContext *C, wmOperator *op) +{ + Object *par = NULL; + int partype = -1; + char parname[32]; + + partype= RNA_enum_get(op->ptr, "type"); + RNA_string_get(op->ptr, "parent", parname); + par= (Object *)find_id("OB", parname); + + do_parent_set(C, op, par, partype); + + return OPERATOR_FINISHED; +} + +/* Used for drag and drop parenting */ +static int outliner_get_item_hover(bContext *C, wmEvent *event, wmOperator *op, TreeElement *te, TreeStoreElem *tselem, float *fmval) +{ + SpaceOops *soops= CTX_wm_space_outliner(C); + + if((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) { + /* name and first icon */ + if((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend)) { + /* always makes active object */ + if(te->idcode == ID_OB) { + RNA_string_set(op->ptr, "parent", te->name); + return 1; + } + else + return 0; + } + } + + // Not it. Let's look at its children. + if((tselem->flag != 1) && (te->subtree.first)) { + for(te = te->subtree.first; te; te = te->next) { + tselem = TREESTORE(te); + if(outliner_get_item_hover(C, event, op, te, tselem, fmval)) return 1; + } + } + return 0; +} + +static int parent_drop_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + Object *par= NULL; + Object *ob= NULL; + SpaceOops *soops= CTX_wm_space_outliner(C); + ARegion *ar= CTX_wm_region(C); + Scene *scene= CTX_data_scene(C); + TreeElement *te= NULL; + TreeStoreElem *tselem= NULL; + char childname[32]; + char parname[32]; + int partype= 0; + float fmval[2]; + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + /* Find object hovered over */ + for(te= soops->tree.first; te; te= te->next) { + tselem= TREESTORE(te); + if(outliner_get_item_hover(C, event, op, te, tselem, fmval)) break; + } + + if(te){ + /* Identify parent and child */ + RNA_string_get(op->ptr, "child", childname); + ob= (Object *)find_id("OB", childname); + RNA_string_get(op->ptr, "parent", parname); + par= (Object *)find_id("OB", parname); + + if(ob==NULL || par==NULL) { + if(par==NULL) printf("par==NULL\n"); + return OPERATOR_CANCELLED; + } + if(ob == par) { + return OPERATOR_CANCELLED; + } + + /* check dragged object (child) is active */ + if(ob != CTX_data_active_object(C)) + ED_base_object_select(object_in_scene(ob, scene), BA_SELECT); + + if( (par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) + do_parent_set(C, op, par, partype); + else { + /* Menu creation */ + uiPopupMenu *pup= uiPupMenuBegin(C, "Set Parent To", ICON_NONE); + uiLayout *layout= uiPupMenuLayout(pup); + + PointerRNA ptr; + + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_OBJECT); + /* Cannot use uiItemEnumO()... have multiple properties to set. */ + uiItemFullO(layout, "OUTLINER_OT_parent_drop", "Object", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + + /* par becomes parent, make the associated menus */ + if(par->type==OB_ARMATURE) { + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE); + uiItemFullO(layout, "OUTLINER_OT_parent_drop", "Armature Deform", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME); + uiItemFullO(layout, "OUTLINER_OT_parent_drop", " With Empty Groups", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE); + uiItemFullO(layout, "OUTLINER_OT_parent_drop", " With Envelope Weights", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO); + uiItemFullO(layout, "OUTLINER_OT_parent_drop", " With Automatic Weights", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_BONE); + uiItemFullO(layout, "OUTLINER_OT_parent_drop", "Bone", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + } + else if(par->type==OB_CURVE) { + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_CURVE); + uiItemFullO(layout, "OUTLINER_OT_parent_drop", "Curve Deform", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_FOLLOW); + uiItemFullO(layout, "OUTLINER_OT_parent_drop", "Follow Path", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_PATH_CONST); + uiItemFullO(layout, "OUTLINER_OT_parent_drop", "Path Constraint", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + } + else if(par->type == OB_LATTICE) { + WM_operator_properties_create(&ptr, "OUTLINER_OT_parent_drop"); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_LATTICE); + uiItemFullO(layout, "OUTLINER_OT_parent_drop", "Lattice Deform", 0, ptr.data, WM_OP_EXEC_DEFAULT, 0); + } + + uiPupMenuEnd(C, pup); + + return OPERATOR_CANCELLED; + } + } + else { + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_parent_drop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Drop to Set Parent"; + ot->description = "Drag to parent in outliner"; + ot->idname= "OUTLINER_OT_parent_drop"; + + /* api callbacks */ + ot->invoke= parent_drop_invoke; + ot->exec= parent_drop_exec; + + ot->poll= ED_operator_outliner_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_string(ot->srna, "child", "Object", 24, "Child", "Child Object"); + RNA_def_string(ot->srna, "parent", "Object", 24, "Parent", "Parent Object"); + RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); +} + /* ***************** DRAW *************** */ /* make function calls a bit compacter */ Index: source/blender/editors/space_outliner/outliner_ops.c =================================================================== --- source/blender/editors/space_outliner/outliner_ops.c (revision 37882) +++ source/blender/editors/space_outliner/outliner_ops.c (working copy) @@ -75,6 +75,8 @@ WM_operatortype_append(OUTLINER_OT_drivers_add_selected); WM_operatortype_append(OUTLINER_OT_drivers_delete_selected); + + WM_operatortype_append(OUTLINER_OT_parent_drop); } void outliner_keymap(wmKeyConfig *keyconf) Index: source/blender/editors/space_outliner/outliner_intern.h =================================================================== --- source/blender/editors/space_outliner/outliner_intern.h (revision 37882) +++ source/blender/editors/space_outliner/outliner_intern.h (working copy) @@ -148,5 +148,7 @@ void OUTLINER_OT_drivers_add_selected(struct wmOperatorType *ot); void OUTLINER_OT_drivers_delete_selected(struct wmOperatorType *ot); +void OUTLINER_OT_parent_drop(struct wmOperatorType *ot); + #endif /* ED_OUTLINER_INTERN_H */ Index: source/blender/editors/space_outliner/space_outliner.c =================================================================== --- source/blender/editors/space_outliner/space_outliner.c (revision 37882) +++ source/blender/editors/space_outliner/space_outliner.c (working copy) @@ -52,6 +52,8 @@ #include "BIF_gl.h" +#include "RNA_access.h" + #include "UI_resources.h" #include "UI_view2d.h" @@ -60,6 +62,7 @@ static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar) { + ListBase *lb; wmKeyMap *keymap; UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); @@ -68,8 +71,38 @@ keymap= WM_keymap_find(wm->defaultconf, "Outliner", SPACE_OUTLINER, 0); /* don't pass on view2d mask, it's always set with scrollbar space, hide fails */ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, NULL, &ar->winrct); + + /* Add dropboxes */ + lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW); + WM_event_add_dropbox_handler(&ar->handlers, lb); + } +static int outliner_parent_drop_poll(bContext *UNUSED(C), wmDrag *drag, wmEvent *UNUSED(event)) +{ + if(drag->type == WM_DRAG_ID) { + ID *id = (ID *)drag->poin; + if( GS(id->name) == ID_OB ) + return 1; + } + return 0; +} + +static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop) +{ + ID *id = (ID *)drag->poin; + + RNA_string_set(drop->ptr, "child", id->name+2); +} + +/* region dropbox definition */ +static void outliner_dropboxes(void) +{ + ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW); + + WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", outliner_parent_drop_poll, outliner_parent_drop_copy); +} + static void outliner_main_area_draw(const bContext *C, ARegion *ar) { View2D *v2d= &ar->v2d; @@ -293,6 +326,7 @@ st->duplicate= outliner_duplicate; st->operatortypes= outliner_operatortypes; st->keymap= outliner_keymap; + st->dropboxes= outliner_dropboxes; /* regions: main window */ art= MEM_callocN(sizeof(ARegionType), "spacetype time region"); Index: source/blender/editors/object/object_relations.c =================================================================== --- source/blender/editors/object/object_relations.c (revision 37882) +++ source/blender/editors/object/object_relations.c (working copy) @@ -500,16 +500,6 @@ {0, NULL, 0, NULL, NULL} }; -static int test_parent_loop(Object *par, Object *ob) -{ - /* test if 'ob' is a parent somewhere in par's parents */ - - if(par == NULL) return 0; - if(ob == par) return 1; - - return test_parent_loop(par->parent, ob); -} - void ED_object_parent(Object *ob, Object *par, int type, const char *substr) { if(!par || test_parent_loop(par, ob)) { @@ -529,166 +519,13 @@ static int parent_set_exec(bContext *C, wmOperator *op) { - Main *bmain= CTX_data_main(C); - Scene *scene= CTX_data_scene(C); Object *par= ED_object_active_context(C); - bPoseChannel *pchan= NULL; int partype= RNA_enum_get(op->ptr, "type"); - int pararm= ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO); - - par->recalc |= OB_RECALC_OB; - - /* preconditions */ - if(partype==PAR_FOLLOW || partype==PAR_PATH_CONST) { - if(par->type!=OB_CURVE) - return OPERATOR_CANCELLED; - else { - Curve *cu= par->data; - - if((cu->flag & CU_PATH)==0) { - cu->flag |= CU_PATH|CU_FOLLOW; - makeDispListCurveTypes(scene, par, 0); /* force creation of path data */ - } - else cu->flag |= CU_FOLLOW; - - /* if follow, add F-Curve for ctime (i.e. "eval_time") so that path-follow works */ - if(partype == PAR_FOLLOW) { - /* get or create F-Curve */ - bAction *act = verify_adt_action(&cu->id, 1); - FCurve *fcu = verify_fcurve(act, NULL, "eval_time", 0, 1); - - /* setup dummy 'generator' modifier here to get 1-1 correspondance still working */ - if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) - add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR); - } - - /* fall back on regular parenting now (for follow only) */ - if(partype == PAR_FOLLOW) - partype= PAR_OBJECT; - } - } - else if(partype==PAR_BONE) { - pchan= get_active_posechannel(par); - - if(pchan==NULL) { - BKE_report(op->reports, RPT_ERROR, "No active Bone"); - return OPERATOR_CANCELLED; - } - } - - /* context iterator */ - CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) { - - if(ob!=par) { - - if( test_parent_loop(par, ob) ) { - BKE_report(op->reports, RPT_ERROR, "Loop in parents"); - } - else { - Object workob; - - /* apply transformation of previous parenting */ - /* object_apply_mat4(ob, ob->obmat); */ /* removed because of bug [#23577] */ - /* set the parent (except for follow-path constraint option) */ - if(partype != PAR_PATH_CONST) - ob->parent= par; - - /* handle types */ - if (pchan) - strcpy(ob->parsubstr, pchan->name); - else - ob->parsubstr[0]= 0; - - if(partype == PAR_PATH_CONST) - ; /* don't do anything here, since this is not technically "parenting" */ - else if( ELEM(partype, PAR_CURVE, PAR_LATTICE) || pararm ) - { - /* partype is now set to PAROBJECT so that invisible 'virtual' modifiers don't need to be created - * NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, creating the virtual modifiers - */ - ob->partype= PAROBJECT; /* note, dna define, not operator property */ - //ob->partype= PARSKEL; /* note, dna define, not operator property */ - - /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses */ - // XXX currently this should only happen for meshes, curves, surfaces, and lattices - this stuff isn't available for metas yet - if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) - { - ModifierData *md; - - switch (partype) { - case PAR_CURVE: /* curve deform */ - md= ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, eModifierType_Curve); - ((CurveModifierData *)md)->object= par; - break; - case PAR_LATTICE: /* lattice deform */ - md= ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, eModifierType_Lattice); - ((LatticeModifierData *)md)->object= par; - break; - default: /* armature deform */ - md= ED_object_modifier_add(op->reports, bmain, scene, ob, NULL, eModifierType_Armature); - ((ArmatureModifierData *)md)->object= par; - break; - } - } - } - else if (partype == PAR_BONE) - ob->partype= PARBONE; /* note, dna define, not operator property */ - else - ob->partype= PAROBJECT; /* note, dna define, not operator property */ - - /* constraint */ - if(partype == PAR_PATH_CONST) { - bConstraint *con; - bFollowPathConstraint *data; - float cmat[4][4], vec[3]; - - con = add_ob_constraint(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH); - - data = con->data; - data->tar = par; - - get_constraint_target_matrix(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra - give_timeoffset(ob)); - sub_v3_v3v3(vec, ob->obmat[3], cmat[3]); - - ob->loc[0] = vec[0]; - ob->loc[1] = vec[1]; - ob->loc[2] = vec[2]; - } - else if(pararm && ob->type==OB_MESH && par->type == OB_ARMATURE) { - if(partype == PAR_ARMATURE_NAME) - create_vgroups_from_armature(op->reports, scene, ob, par, ARM_GROUPS_NAME, 0); - else if(partype == PAR_ARMATURE_ENVELOPE) - create_vgroups_from_armature(op->reports, scene, ob, par, ARM_GROUPS_ENVELOPE, 0); - else if(partype == PAR_ARMATURE_AUTO) { - WM_cursor_wait(1); - create_vgroups_from_armature(op->reports, scene, ob, par, ARM_GROUPS_AUTO, 0); - WM_cursor_wait(0); - } - /* get corrected inverse */ - ob->partype= PAROBJECT; - what_does_parent(scene, ob, &workob); - - invert_m4_m4(ob->parentinv, workob.obmat); - } - else { - /* calculate inverse parent matrix */ - what_does_parent(scene, ob, &workob); - invert_m4_m4(ob->parentinv, workob.obmat); - } - - ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA; - } - } - } - CTX_DATA_END; - - DAG_scene_sort(bmain, scene); - DAG_ids_flush_update(bmain, 0); - WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT|ND_PARENT, NULL); - - return OPERATOR_FINISHED; + if(do_parent_set(C, op, par, partype)) + return OPERATOR_FINISHED; + else + return OPERATOR_CANCELLED; } static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))