From 5d6bdd7c2ea0413b707dd08d3b3b67154ccd9a55 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 27 May 2010 11:56:31 +0000 Subject: [PATCH] Various constraint code cleanups: 1) Fixed some weird formatting introduced during math-lib cleanups, and some other inconsistencies 2) Optimised the Maintain Volume constraint by taking the value calculations out Copy All Constraints Operators: * Added one for bones too * These are now included in the menus * Removed some weird/extra code copying/changing/bleh the actcol/totcol stuff... --- release/scripts/ui/space_view3d.py | 2 + source/blender/blenkernel/intern/constraint.c | 106 ++++++------ .../editors/object/object_constraint.c | 152 ++++++++++++------ source/blender/editors/object/object_intern.h | 4 +- source/blender/editors/object/object_ops.c | 3 +- .../blender/makesdna/DNA_constraint_types.h | 2 +- 6 files changed, 160 insertions(+), 109 deletions(-) diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py index 8f44d00581f..4a3818eae73 100644 --- a/release/scripts/ui/space_view3d.py +++ b/release/scripts/ui/space_view3d.py @@ -797,6 +797,7 @@ class VIEW3D_MT_object_constraints(bpy.types.Menu): layout = self.layout layout.operator("object.constraint_add_with_targets") + layout.operator("object.constraints_copy") layout.operator("object.constraints_clear") @@ -1160,6 +1161,7 @@ class VIEW3D_MT_pose_constraints(bpy.types.Menu): layout = self.layout layout.operator("pose.constraint_add_with_targets", text="Add (With Targets)...") + layout.operator("pose.constraints_copy") layout.operator("pose.constraints_clear") diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 1a8d665a91d..171276d118e 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -820,12 +820,12 @@ static void childof_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *ta /* extract components of both matrices */ VECCOPY(loc, ct->matrix[3]); - mat4_to_eulO( eul, ct->rotOrder,ct->matrix); - mat4_to_size( size,ct->matrix); + mat4_to_eulO(eul, ct->rotOrder, ct->matrix); + mat4_to_size(size, ct->matrix); VECCOPY(loco, invmat[3]); - mat4_to_eulO( eulo, cob->rotOrder,invmat); - mat4_to_size( sizo,invmat); + mat4_to_eulO(eulo, cob->rotOrder, invmat); + mat4_to_size(sizo, invmat); /* disable channels not enabled */ if (!(data->flag & CHILDOF_LOCX)) loc[0]= loco[0]= 0.0f; @@ -1017,7 +1017,7 @@ static void trackto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *ta float tmat[4][4]; /* Get size property, since ob->size is only the object's own relative size, not its global one */ - mat4_to_size( size,cob->matrix); + mat4_to_size(size, cob->matrix); /* Clear the object's rotation */ cob->matrix[0][0]=size[0]; @@ -1385,9 +1385,9 @@ static void rotlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *t float size[3]; VECCOPY(loc, cob->matrix[3]); - mat4_to_size( size,cob->matrix); + mat4_to_size(size, cob->matrix); - mat4_to_eulO( eul, cob->rotOrder,cob->matrix); + mat4_to_eulO(eul, cob->rotOrder, cob->matrix); /* constraint data uses radians internally */ @@ -1638,11 +1638,11 @@ static void rotlike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *ta float size[3]; VECCOPY(loc, cob->matrix[3]); - mat4_to_size( size,cob->matrix); + mat4_to_size(size, cob->matrix); /* to allow compatible rotations, must get both rotations in the order of the owner... */ - mat4_to_eulO( eul, cob->rotOrder,ct->matrix); - mat4_to_eulO( obeul, cob->rotOrder,cob->matrix); + mat4_to_eulO(eul, cob->rotOrder, ct->matrix); + mat4_to_eulO(obeul, cob->rotOrder, cob->matrix); if ((data->flag & ROTLIKE_X)==0) eul[0] = obeul[0]; @@ -1868,29 +1868,29 @@ static void samevolume_evaluate (bConstraint *con, bConstraintOb *cob, ListBase { bSameVolumeConstraint *data= con->data; + float volume = data->volume; + float fac = 1.0f; float obsize[3]; - float volume=data->volume; mat4_to_size(obsize, cob->matrix); - + + /* calculate normalising scale factor for non-essential values */ + if (obsize[data->flag] != 0) + fac = sqrt(volume / obsize[data->flag]) / obsize[data->flag]; + + /* apply scaling factor to the channels not being kept */ switch (data->flag) { case SAMEVOL_X: - if (obsize[0]!=0) { - mul_v3_fl(cob->matrix[1], sqrt(volume/obsize[0])/obsize[0]); - mul_v3_fl(cob->matrix[2], sqrt(volume/obsize[0])/obsize[0]); - } + mul_v3_fl(cob->matrix[1], fac); + mul_v3_fl(cob->matrix[2], fac); break; case SAMEVOL_Y: - if (obsize[1]!=0) { - mul_v3_fl(cob->matrix[0], sqrt(volume/obsize[1])/obsize[1]); - mul_v3_fl(cob->matrix[2], sqrt(volume/obsize[1])/obsize[1]); - } + mul_v3_fl(cob->matrix[0], fac); + mul_v3_fl(cob->matrix[2], fac); break; case SAMEVOL_Z: - if (obsize[2]!=0) { - mul_v3_fl(cob->matrix[0], sqrt(volume/obsize[2])/obsize[2]); - mul_v3_fl(cob->matrix[1], sqrt(volume/obsize[2])/obsize[2]); - } + mul_v3_fl(cob->matrix[0], fac); + mul_v3_fl(cob->matrix[1], fac); break; } } @@ -2770,7 +2770,7 @@ static void stretchto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * float dist; /* store scaling before destroying obmat */ - mat4_to_size( size,cob->matrix); + mat4_to_size(size, cob->matrix); /* store X orientation before destroying obmat */ xx[0] = cob->matrix[0][0]; @@ -3353,7 +3353,7 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * mat4_to_size( dvec,ct->matrix); break; case 1: /* rotation (convert to degrees first) */ - mat4_to_eulO( dvec, cob->rotOrder,ct->matrix); + mat4_to_eulO(dvec, cob->rotOrder, ct->matrix); for (i=0; i<3; i++) dvec[i] = (float)(dvec[i] / M_PI * 180); break; @@ -3364,8 +3364,8 @@ static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * /* extract components of owner's matrix */ VECCOPY(loc, cob->matrix[3]); - mat4_to_eulO( eul, cob->rotOrder,cob->matrix); - mat4_to_size( size,cob->matrix); + mat4_to_eulO(eul, cob->rotOrder, cob->matrix); + mat4_to_size(size, cob->matrix); /* determine where in range current transforms lie */ if (data->expo) { @@ -3485,73 +3485,73 @@ static void shrinkwrap_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr float co[3] = {0.0f, 0.0f, 0.0f}; float no[3] = {0.0f, 0.0f, 0.0f}; float dist; - + SpaceTransform transform; DerivedMesh *target = object_get_derived_final(cob->scene, ct->tar, CD_MASK_BAREMESH); BVHTreeRayHit hit; BVHTreeNearest nearest; - + BVHTreeFromMesh treeData; - memset( &treeData, 0, sizeof(treeData) ); - + memset(&treeData, 0, sizeof(treeData)); + nearest.index = -1; nearest.dist = FLT_MAX; - + hit.index = -1; hit.dist = 100000.0f; //TODO should use FLT_MAX.. but normal projection doenst yet supports it - + unit_m4(ct->matrix); - + if(target != NULL) { space_transform_from_matrixs(&transform, cob->matrix, ct->tar->obmat); - + switch(scon->shrinkType) { case MOD_SHRINKWRAP_NEAREST_SURFACE: case MOD_SHRINKWRAP_NEAREST_VERTEX: - + if(scon->shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) bvhtree_from_mesh_verts(&treeData, target, 0.0, 2, 6); else bvhtree_from_mesh_faces(&treeData, target, 0.0, 2, 6); - + if(treeData.tree == NULL) { fail = TRUE; break; } - + space_transform_apply(&transform, co); - + BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData); dist = len_v3v3(co, nearest.co); interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist)/dist); /* linear interpolation */ space_transform_invert(&transform, co); break; - + case MOD_SHRINKWRAP_PROJECT: if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) no[0] = 1.0f; if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) no[1] = 1.0f; if(scon->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) no[2] = 1.0f; - + if(INPR(no,no) < FLT_EPSILON) { fail = TRUE; break; } - + normalize_v3(no); - - + + bvhtree_from_mesh_faces(&treeData, target, scon->dist, 4, 6); if(treeData.tree == NULL) { fail = TRUE; break; } - + if(normal_projection_project_vertex(0, co, no, &transform, treeData.tree, &hit, treeData.raycast_callback, &treeData) == FALSE) { fail = TRUE; @@ -3560,17 +3560,17 @@ static void shrinkwrap_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr VECCOPY(co, hit.co); break; } - + free_bvhtree_from_mesh(&treeData); - + target->release(target); - + if(fail == TRUE) { /* Don't move the point */ co[0] = co[1] = co[2] = 0.0f; } - + /* co is in local object coordinates, change it to global and update target position */ mul_m4_v3(cob->matrix, co); VECCOPY(ct->matrix[3], co); @@ -3704,7 +3704,7 @@ static void damptrack_evaluate (bConstraint *con, bConstraintOb *cob, ListBase * /* construct rotation matrix from the axis-angle rotation found above * - this call takes care to make sure that the axis provided is a unit vector first */ - axis_angle_to_mat3( rmat,raxis, rangle); + axis_angle_to_mat3(rmat, raxis, rangle); /* rotate the owner in the way defined by this rotation matrix, then reapply the location since * we may have destroyed that in the process of multiplying the matrix @@ -4262,9 +4262,9 @@ void copy_constraints (ListBase *dst, const ListBase *src, int do_extern) /* perform custom copying operations if needed */ if (cti->copy_data) cti->copy_data(con, srccon); - + /* for proxies we dont want to make extern */ - if(do_extern) { + if (do_extern) { /* go over used ID-links for this constraint to ensure that they are valid for proxies */ if (cti->id_looper) cti->id_looper(con, con_extern_cb, NULL); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index eaabcd866cd..034de3fb703 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -133,6 +133,7 @@ bConstraint *get_active_constraint (Object *ob) { return constraints_get_active(get_active_constraints(ob)); } + /* -------------- Constraint Management (Add New, Remove, Rename) -------------------- */ /* ------------- PyConstraints ------------------ */ @@ -435,15 +436,16 @@ static void test_constraints (Object *owner, bPoseChannel *pchan) void object_test_constraints (Object *owner) { - if(owner->constraints.first) + if (owner->constraints.first) test_constraints(owner, NULL); - + if (owner->type==OB_ARMATURE && owner->pose) { bPoseChannel *pchan; - - for (pchan= owner->pose->chanbase.first; pchan; pchan= pchan->next) - if(pchan->constraints.first) + + for (pchan= owner->pose->chanbase.first; pchan; pchan= pchan->next) { + if (pchan->constraints.first) test_constraints(owner, pchan); + } } } @@ -454,9 +456,9 @@ void object_test_constraints (Object *owner) #define EDIT_CONSTRAINT_OWNER_BONE 1 static EnumPropertyItem constraint_owner_items[] = { -{EDIT_CONSTRAINT_OWNER_OBJECT, "OBJECT", 0, "Object", "Edit a constraint on the active object"}, -{EDIT_CONSTRAINT_OWNER_BONE, "BONE", 0, "Bone", "Edit a constraint on the active bone"}, -{0, NULL, 0, NULL, NULL}}; + {EDIT_CONSTRAINT_OWNER_OBJECT, "OBJECT", 0, "Object", "Edit a constraint on the active object"}, + {EDIT_CONSTRAINT_OWNER_BONE, "BONE", 0, "Bone", "Edit a constraint on the active bone"}, + {0, NULL, 0, NULL, NULL}}; static int edit_constraint_poll_generic(bContext *C, StructRNA *rna_type) @@ -519,7 +521,8 @@ static bConstraint *edit_constraint_property_get(bContext *C, wmOperator *op, Ob if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { list = &ob->constraints; - } else if (owner == EDIT_CONSTRAINT_OWNER_BONE) { + } + else if (owner == EDIT_CONSTRAINT_OWNER_BONE) { bPoseChannel *pchan= get_active_posechannel(ob); if (pchan) list = &pchan->constraints; @@ -529,7 +532,7 @@ static bConstraint *edit_constraint_property_get(bContext *C, wmOperator *op, Ob con = constraints_findByName(list, constraint_name); - if (con && type != 0 && con->type != type) + if (con && (type != 0) && (con->type != type)) con = NULL; return con; @@ -964,19 +967,21 @@ void POSE_OT_constraints_clear(wmOperatorType *ot) static int object_constraints_clear_exec(bContext *C, wmOperator *op) { - Object *ob= ED_object_active_context(C); Scene *scene= CTX_data_scene(C); /* do freeing */ - // TODO: we should free constraints for all selected objects instead (to be more consistent with bones) - free_constraints(&ob->constraints); + CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) + { + free_constraints(&ob->constraints); + DAG_id_flush_update(&ob->id, OB_RECALC_OB); + } + CTX_DATA_END; /* force depsgraph to get recalculated since relationships removed */ DAG_scene_sort(scene); /* sort order of objects */ /* do updates */ - DAG_id_flush_update(&ob->id, OB_RECALC_OB); - WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, ob); + WM_event_add_notifier(C, NC_OBJECT|ND_CONSTRAINT, NULL); return OPERATOR_FINISHED; } @@ -993,6 +998,84 @@ void OBJECT_OT_constraints_clear(wmOperatorType *ot) ot->poll= ED_operator_object_active_editable; } +/************************ copy all constraints operators *********************/ + +static int pose_constraint_copy_exec(bContext *C, wmOperator *op) +{ + bPoseChannel *pchan = CTX_data_active_pose_bone(C); + Scene *scene = CTX_data_scene(C); + + /* don't do anything if bone doesn't exist or doesn't have any constraints */ + if (ELEM(NULL, pchan, pchan->constraints.first)) { + BKE_report(op->reports, RPT_ERROR, "No active bone with constraints for copying"); + return OPERATOR_CANCELLED; + } + + /* copy all constraints from active posebone to all selected posebones */ + CTX_DATA_BEGIN(C, bPoseChannel*, chan, selected_pose_bones) + { + /* if we're not handling the object we're copying from, copy all constraints over */ + if (pchan != chan) + copy_constraints(&chan->constraints, &pchan->constraints, TRUE); + } + CTX_DATA_END; + + /* force depsgraph to get recalculated since new relationships added */ + DAG_scene_sort(scene); /* sort order of objects/bones */ + + return OPERATOR_FINISHED; +} + +void POSE_OT_constraints_copy(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Copy Constraints to Selected"; + ot->idname= "POSE_OT_constraints_copy"; + ot->description = "Copy constraints to other selected bones."; + + /* api callbacks */ + ot->exec= pose_constraint_copy_exec; + ot->poll= ED_operator_posemode; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int object_constraint_copy_exec(bContext *C, wmOperator *op) +{ + Object *obact = ED_object_active_context(C); + Scene *scene = CTX_data_scene(C); + + /* copy all constraints from active object to all selected objects */ + CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) + { + /* if we're not handling the object we're copying from, copy all constraints over */ + if (obact != ob) + copy_constraints(&ob->constraints, &obact->constraints, TRUE); + } + CTX_DATA_END; + + /* force depsgraph to get recalculated since new relationships added */ + DAG_scene_sort(scene); /* sort order of objects */ + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_constraints_copy(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Copy Constraints to Selected"; + ot->idname= "OBJECT_OT_constraints_copy"; + ot->description = "Copy constraints to other selected objects."; + + /* api callbacks */ + ot->exec= object_constraint_copy_exec; + ot->poll= ED_operator_object_active_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /************************ add constraint operators *********************/ /* get the Object and/or PoseChannel to use as target */ @@ -1163,7 +1246,7 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase } /* create a new constraint of the type requried, and add it to the active/given constraints list */ - if(pchan) + if (pchan) con = add_pose_constraint(ob, pchan, NULL, type); else con = add_ob_constraint(ob, NULL, type); @@ -1271,28 +1354,6 @@ static int object_constraint_add_exec(bContext *C, wmOperator *op) return constraint_add_exec(C, op, ob, &ob->constraints, type, with_targets); } -/* dummy operator callback */ -static int object_constraint_copy_exec(bContext *C, wmOperator *op) -{ - Object *ob=ED_object_active_context(C); - - CTX_DATA_BEGIN(C, Object*, ob_iter, selected_editable_objects) { - if(ob != ob_iter) { - if (ob->data != ob_iter->data){ - copy_constraints(&ob_iter->constraints, &ob->constraints, TRUE); - } - - if(ob_iter->totcol==ob->totcol) { - ob_iter->actcol= ob->actcol; - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob_iter); - } - } - } - CTX_DATA_END; - - return OPERATOR_FINISHED; -} - /* dummy operator callback */ static int pose_constraint_add_exec(bContext *C, wmOperator *op) { @@ -1354,21 +1415,6 @@ void OBJECT_OT_constraint_add_with_targets(wmOperatorType *ot) ot->prop= RNA_def_enum(ot->srna, "type", constraint_type_items, 0, "Type", ""); } -void OBJECT_OT_constraint_copy(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Copy Constraints to Selected"; - ot->description = "Copy constraints to other selected objects."; - ot->idname= "OBJECT_OT_constraint_copy"; - - /* api callbacks */ - ot->exec= object_constraint_copy_exec; - ot->poll= ED_operator_object_active_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - void POSE_OT_constraint_add(wmOperatorType *ot) { /* identifiers */ diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 5d44baae3f4..5b446b3a828 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -164,10 +164,12 @@ void OBJECT_OT_explode_refresh(struct wmOperatorType *ot); /* object_constraint.c */ void OBJECT_OT_constraint_add(struct wmOperatorType *ot); void OBJECT_OT_constraint_add_with_targets(struct wmOperatorType *ot); -void OBJECT_OT_constraint_copy(struct wmOperatorType *ot); void POSE_OT_constraint_add(struct wmOperatorType *ot); void POSE_OT_constraint_add_with_targets(struct wmOperatorType *ot); +void OBJECT_OT_constraints_copy(struct wmOperatorType *ot); +void POSE_OT_constraints_copy(struct wmOperatorType *ot); + void OBJECT_OT_constraints_clear(struct wmOperatorType *ot); void POSE_OT_constraints_clear(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index b09de8a1628..602b94034bd 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -145,9 +145,10 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_constraint_add); WM_operatortype_append(OBJECT_OT_constraint_add_with_targets); - WM_operatortype_append(OBJECT_OT_constraint_copy); WM_operatortype_append(POSE_OT_constraint_add); WM_operatortype_append(POSE_OT_constraint_add_with_targets); + WM_operatortype_append(OBJECT_OT_constraints_copy); + WM_operatortype_append(POSE_OT_constraints_copy); WM_operatortype_append(OBJECT_OT_constraints_clear); WM_operatortype_append(POSE_OT_constraints_clear); WM_operatortype_append(POSE_OT_ik_add); diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 00694a7ea1f..f310e5e55e0 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -211,7 +211,7 @@ typedef struct bSizeLikeConstraint { /* Maintain Volume Constraint */ typedef struct bSameVolumeConstraint { - int flag; + int flag; float volume; } bSameVolumeConstraint;