diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp index 5e349535610..c50de1ef72e 100644 --- a/source/blender/collada/ArmatureExporter.cpp +++ b/source/blender/collada/ArmatureExporter.cpp @@ -62,10 +62,11 @@ ArmatureExporter::ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSett } // write bone nodes -void ArmatureExporter::add_armature_bones(Depsgraph *depsgraph, Object *ob_arm, +void ArmatureExporter::add_armature_bones(bContext *C, Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se, std::list& child_objects) { + Main *bmain = CTX_data_main(C); // write bone nodes bArmature * armature = (bArmature *)ob_arm->data; @@ -77,11 +78,11 @@ void ArmatureExporter::add_armature_bones(Depsgraph *depsgraph, Object *ob_arm, for (Bone *bone = (Bone *)armature->bonebase.first; bone; bone = bone->next) { // start from root bones if (!bone->parent) - add_bone_node(depsgraph, bone, ob_arm, sce, se, child_objects); + add_bone_node(C, depsgraph, bone, ob_arm, sce, se, child_objects); } if (!is_edited) { - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); } } @@ -157,7 +158,7 @@ void ArmatureExporter::find_objects_using_armature(Object *ob_arm, std::vector& child_objects) { @@ -231,7 +232,7 @@ void ArmatureExporter::add_bone_node(Depsgraph *depsgraph, Bone *bone, Object *o mul_m4_m4m4((*i)->parentinv, temp, (*i)->parentinv); } - se->writeNodes(depsgraph, *i, sce); + se->writeNodes(C, depsgraph, *i, sce); copy_m4_m4((*i)->parentinv, backup_parinv); child_objects.erase(i++); @@ -240,13 +241,13 @@ void ArmatureExporter::add_bone_node(Depsgraph *depsgraph, Bone *bone, Object *o } for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { - add_bone_node(depsgraph, child, ob_arm, sce, se, child_objects); + add_bone_node(C, depsgraph, child, ob_arm, sce, se, child_objects); } node.end(); } else { for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { - add_bone_node(depsgraph, child, ob_arm, sce, se, child_objects); + add_bone_node(C, depsgraph, child, ob_arm, sce, se, child_objects); } } } diff --git a/source/blender/collada/ArmatureExporter.h b/source/blender/collada/ArmatureExporter.h index 17c02d637e8..7efa8b70e43 100644 --- a/source/blender/collada/ArmatureExporter.h +++ b/source/blender/collada/ArmatureExporter.h @@ -60,7 +60,7 @@ public: ArmatureExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings); // write bone nodes - void add_armature_bones(struct Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se, + void add_armature_bones(bContext *C, struct Depsgraph *depsgraph, Object *ob_arm, Scene *sce, SceneExporter *se, std::list& child_objects); bool add_instance_controller(Object *ob); @@ -85,7 +85,7 @@ private: // Scene, SceneExporter and the list of child_objects // are required for writing bone parented objects - void add_bone_node(struct Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se, + void add_bone_node(bContext *C, struct Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce, SceneExporter *se, std::list& child_objects); void add_bone_transform(Object *ob_arm, Bone *bone, COLLADASW::Node& node); diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index f24688479af..6bf6087c054 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -448,7 +448,7 @@ ArmatureJoints& ArmatureImporter::get_armature_joints(Object *ob_arm) return armature_joints.back(); } #endif -void ArmatureImporter::create_armature_bones(std::vector &ob_arms) +void ArmatureImporter::create_armature_bones(Main *bmain, std::vector &ob_arms) { std::vector::iterator ri; std::vector layer_labels; @@ -481,7 +481,7 @@ void ArmatureImporter::create_armature_bones(std::vector &ob_arms) } /* exit armature edit mode to populate the Armature object */ - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); ED_armature_to_edit(armature); @@ -489,7 +489,7 @@ void ArmatureImporter::create_armature_bones(std::vector &ob_arms) fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation); unskinned_armature_map[(*ri)->getUniqueId()] = ob_arm; - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); int index = std::find(ob_arms.begin(), ob_arms.end(), ob_arm) - ob_arms.begin(); @@ -501,7 +501,7 @@ void ArmatureImporter::create_armature_bones(std::vector &ob_arms) } } -Object *ArmatureImporter::create_armature_bones(SkinInfo& skin) +Object *ArmatureImporter::create_armature_bones(Main *bmain, SkinInfo& skin) { // just do like so: // - get armature @@ -619,7 +619,7 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin) } /* exit armature edit mode to populate the Armature object */ - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); ED_armature_to_edit(armature); @@ -627,7 +627,7 @@ Object *ArmatureImporter::create_armature_bones(SkinInfo& skin) connect_bone_chains(armature, (Bone *)armature->bonebase.first, UNLIMITED_CHAIN_MAX); } fix_leaf_bone_hierarchy(armature, (Bone *)armature->bonebase.first, this->import_settings->fix_orientation); - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); DEG_id_tag_update(&ob_arm->id, OB_RECALC_OB | OB_RECALC_DATA); @@ -709,6 +709,7 @@ void ArmatureImporter::add_root_joint(COLLADAFW::Node *node) // here we add bones to armatures, having armatures previously created in write_controller void ArmatureImporter::make_armatures(bContext *C, std::vector &objects_to_scale) { + Main *bmain = CTX_data_main(C); std::vector ob_arms; std::map::iterator it; @@ -718,7 +719,7 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector &object SkinInfo& skin = it->second; - Object *ob_arm = create_armature_bones(skin); + Object *ob_arm = create_armature_bones(bmain, skin); // link armature with a mesh object const COLLADAFW::UniqueId &uid = skin.get_controller_uid(); @@ -759,7 +760,7 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector &object } //for bones without skins - create_armature_bones(ob_arms); + create_armature_bones(bmain, ob_arms); // Fix bone relations std::vector::iterator ob_arm_it; @@ -773,7 +774,7 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector &object fix_parent_connect(armature, (Bone *)armature->bonebase.first); - ED_armature_from_edit(armature); + ED_armature_from_edit(bmain, armature); ED_armature_edit_free(armature); } } diff --git a/source/blender/collada/ArmatureImporter.h b/source/blender/collada/ArmatureImporter.h index f260bb2307c..9f8961a41a2 100644 --- a/source/blender/collada/ArmatureImporter.h +++ b/source/blender/collada/ArmatureImporter.h @@ -130,8 +130,8 @@ private: ArmatureJoints& get_armature_joints(Object *ob_arm); #endif - Object *create_armature_bones(SkinInfo& skin); - void create_armature_bones(std::vector &arm_objs); + Object *create_armature_bones(Main *bmain, SkinInfo& skin); + void create_armature_bones(Main *bmain, std::vector &arm_objs); /** TagsMap typedef for uid_tags_map. */ typedef std::map TagsMap; diff --git a/source/blender/collada/DocumentExporter.cpp b/source/blender/collada/DocumentExporter.cpp index a66c4db7b4d..c685df84d02 100644 --- a/source/blender/collada/DocumentExporter.cpp +++ b/source/blender/collada/DocumentExporter.cpp @@ -181,7 +181,7 @@ static COLLADABU::NativeString make_temp_filepath(const char *name, const char * // For this to work, we need to know objects that use a certain action. -int DocumentExporter::exportCurrentScene(Scene *sce) +int DocumentExporter::exportCurrentScene(bContext *C, Scene *sce) { PointerRNA sceneptr, unit_settings; PropertyRNA *system; /* unused , *scale; */ @@ -307,7 +307,7 @@ int DocumentExporter::exportCurrentScene(Scene *sce) AnimationExporter ae(depsgraph, writer, this->export_settings); ae.exportAnimations(sce); } - se.exportScene(depsgraph, sce); + se.exportScene(C, depsgraph, sce); // std::string scene_name(translate_id(id_name(sce))); diff --git a/source/blender/collada/DocumentExporter.h b/source/blender/collada/DocumentExporter.h index c98f82e68b4..8a48ca29090 100644 --- a/source/blender/collada/DocumentExporter.h +++ b/source/blender/collada/DocumentExporter.h @@ -40,7 +40,7 @@ class DocumentExporter { public: DocumentExporter(Depsgraph *depsgraph, const ExportSettings *export_settings); - int exportCurrentScene(Scene *sce); + int exportCurrentScene(bContext *C, Scene *sce); void exportScenes(const char *filename); private: diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp index 5d1df800746..62ab4af5d1a 100644 --- a/source/blender/collada/SceneExporter.cpp +++ b/source/blender/collada/SceneExporter.cpp @@ -39,17 +39,17 @@ SceneExporter::SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, { } -void SceneExporter::exportScene(Depsgraph *depsgraph, Scene *sce) +void SceneExporter::exportScene(bContext *C, Depsgraph *depsgraph, Scene *sce) { // std::string id_naming = id_name(sce); openVisualScene(translate_id(id_naming), id_naming); - exportHierarchy(depsgraph, sce); + exportHierarchy(C, depsgraph, sce); closeVisualScene(); closeLibrary(); } -void SceneExporter::exportHierarchy(Depsgraph *depsgraph, Scene *sce) +void SceneExporter::exportHierarchy(bContext *C, Depsgraph *depsgraph, Scene *sce) { LinkNode *node; std::vector base_objects; @@ -81,13 +81,13 @@ void SceneExporter::exportHierarchy(Depsgraph *depsgraph, Scene *sce) Object *ob = base_objects[index]; if (bc_is_marked(ob)) { bc_remove_mark(ob); - writeNodes(depsgraph, ob, sce); + writeNodes(C, depsgraph, ob, sce); } } } -void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce) +void SceneExporter::writeNodes(bContext *C, Depsgraph *depsgraph, Object *ob, Scene *sce) { // Add associated armature first if available bool armature_exported = false; @@ -96,7 +96,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce) armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm); if (armature_exported && bc_is_marked(ob_arm)) { bc_remove_mark(ob_arm); - writeNodes(depsgraph, ob_arm, sce); + writeNodes(C, depsgraph, ob_arm, sce); armature_exported = true; } } @@ -155,7 +155,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce) // else if (ob->type == OB_ARMATURE) { - arm_exporter->add_armature_bones(depsgraph, ob, sce, this, child_objects); + arm_exporter->add_armature_bones(C, depsgraph, ob, sce, this, child_objects); } // @@ -234,7 +234,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce) for (std::list::iterator i = child_objects.begin(); i != child_objects.end(); ++i) { if (bc_is_marked(*i)) { bc_remove_mark(*i); - writeNodes(depsgraph, *i, sce); + writeNodes(C, depsgraph, *i, sce); } } diff --git a/source/blender/collada/SceneExporter.h b/source/blender/collada/SceneExporter.h index c330aa81e91..24a2dcf08c8 100644 --- a/source/blender/collada/SceneExporter.h +++ b/source/blender/collada/SceneExporter.h @@ -96,12 +96,12 @@ class SceneExporter: COLLADASW::LibraryVisualScenes, protected TransformWriter, { public: SceneExporter(COLLADASW::StreamWriter *sw, ArmatureExporter *arm, const ExportSettings *export_settings); - void exportScene(Depsgraph *depsgraph, Scene *sce); + void exportScene(bContext *C, Depsgraph *depsgraph, Scene *sce); private: friend class ArmatureExporter; - void exportHierarchy(struct Depsgraph *depsgraph, Scene *sce); - void writeNodes(struct Depsgraph *depsgraph, Object *ob, Scene *sce); + void exportHierarchy(bContext *C, struct Depsgraph *depsgraph, Scene *sce); + void writeNodes(bContext *C, struct Depsgraph *depsgraph, Object *ob, Scene *sce); ArmatureExporter *arm_exporter; const ExportSettings *export_settings; diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp index 5def6638df6..bf310cb24d8 100644 --- a/source/blender/collada/collada.cpp +++ b/source/blender/collada/collada.cpp @@ -51,7 +51,8 @@ int collada_import(bContext *C, ImportSettings *import_settings) return (imp.import())? 1:0; } -int collada_export(Depsgraph *depsgraph, +int collada_export(bContext *C, + Depsgraph *depsgraph, Scene *sce, ExportSettings *export_settings) { @@ -80,7 +81,7 @@ int collada_export(Depsgraph *depsgraph, } DocumentExporter exporter(depsgraph, export_settings); - int status = exporter.exportCurrentScene(sce); + int status = exporter.exportCurrentScene(C, sce); BLI_linklist_free(export_settings->export_set, NULL); diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index 5cf526af1f2..822e12f34e0 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -52,7 +52,8 @@ int collada_import(struct bContext *C, ImportSettings *import_settings); -int collada_export(struct Depsgraph *depsgraph, +int collada_export(struct bContext *C, + struct Depsgraph *depsgraph, struct Scene *sce, ExportSettings *export_settings); diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index 9fcf6ad4826..ccc1eefd9dc 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -50,6 +50,7 @@ #include "BKE_context.h" #include "BKE_layer.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_report.h" #include "BKE_object.h" @@ -68,7 +69,7 @@ /* ************************** Object Tools Exports ******************************* */ /* NOTE: these functions are exported to the Object module to be called from the tools there */ -void ED_armature_transform_apply(Object *ob, float mat[4][4], const bool do_props) +void ED_armature_transform_apply(Main *bmain, Object *ob, float mat[4][4], const bool do_props) { bArmature *arm = ob->data; @@ -79,7 +80,7 @@ void ED_armature_transform_apply(Object *ob, float mat[4][4], const bool do_prop ED_armature_transform_bones(arm, mat, do_props); /* Turn the list into an armature */ - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); } @@ -120,7 +121,7 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const b } } -void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props) +void ED_armature_transform(Main *bmain, bArmature *arm, float mat[4][4], const bool do_props) { if (arm->edbo) { ED_armature_transform_bones(arm, mat, do_props); @@ -133,14 +134,14 @@ void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do ED_armature_transform_bones(arm, mat, do_props); /* Go back to object mode*/ - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); } } /* exported for use in editors/object/ */ /* 0 == do center, 1 == center new, 2 == center cursor */ -void ED_armature_origin_set(Object *ob, float cursor[3], int centermode, int around) +void ED_armature_origin_set(Main *bmain, Object *ob, float cursor[3], int centermode, int around) { const bool is_editmode = BKE_object_is_in_editmode(ob); EditBone *ebone; @@ -190,7 +191,7 @@ void ED_armature_origin_set(Object *ob, float cursor[3], int centermode, int aro /* Turn the list into an armature */ if (is_editmode == false) { - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 5d6c383b24b..ee20c38cf69 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -400,7 +400,7 @@ int join_armature_exec(bContext *C, wmOperator *op) DEG_relations_tag_update(bmain); /* because we removed object(s) */ - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); @@ -516,7 +516,7 @@ static void separated_armature_fix_links(Object *origArm, Object *newArm) * sel: remove selected bones from the armature, otherwise the unselected bones are removed * (ob is not in editmode) */ -static void separate_armature_bones(Object *ob, short sel) +static void separate_armature_bones(Main *bmain, Object *ob, short sel) { bArmature *arm = (bArmature *)ob->data; bPoseChannel *pchan, *pchann; @@ -563,7 +563,7 @@ static void separate_armature_bones(Object *ob, short sel) } /* exit editmode (recalculates pchans too) */ - ED_armature_from_edit(ob->data); + ED_armature_from_edit(bmain, ob->data); ED_armature_edit_free(ob->data); } @@ -611,7 +611,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op) oldob->mode &= ~OB_MODE_POSE; //oldbase->flag &= ~OB_POSEMODE; - ED_armature_from_edit(obedit->data); + ED_armature_from_edit(bmain, obedit->data); ED_armature_edit_free(obedit->data); /* 2) duplicate base */ @@ -623,8 +623,8 @@ static int separate_armature_exec(bContext *C, wmOperator *op) /* 3) remove bones that shouldn't still be around on both armatures */ - separate_armature_bones(oldob, 1); - separate_armature_bones(newob, 0); + separate_armature_bones(bmain, oldob, 1); + separate_armature_bones(bmain, newob, 0); /* 4) fix links before depsgraph flushes */ // err... or after? diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index a8116ce26cf..02d45a4e041 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -585,7 +585,7 @@ static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelis } /* put EditMode back in Object */ -void ED_armature_from_edit(bArmature *arm) +void ED_armature_from_edit(Main *bmain, bArmature *arm) { EditBone *eBone, *neBone; Bone *newBone; @@ -679,7 +679,7 @@ void ED_armature_from_edit(bArmature *arm) armature_finalize_restpose(&arm->bonebase, arm->edbo); /* so all users of this armature should get rebuilt */ - for (obt = G.main->object.first; obt; obt = obt->id.next) { + for (obt = bmain->object.first; obt; obt = obt->id.next) { if (obt->data == arm) { BKE_pose_rebuild(obt, arm); } diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c new file mode 100644 index 00000000000..b74b515b37f --- /dev/null +++ b/source/blender/editors/armature/editarmature_retarget.c @@ -0,0 +1,2644 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Martin Poirier + * + * ***** END GPL LICENSE BLOCK ***** + * autoarmature.c: Interface for automagically manipulating armature (retarget, created, ...) + */ + +/** \file blender/editors/armature/editarmature_retarget.c + * \ingroup edarmature + */ + +#include "MEM_guardedalloc.h" + +#include "PIL_time.h" + +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" + +#include "BKE_constraint.h" +#include "BKE_armature.h" +#include "BKE_context.h" +#include "BKE_main.h" + +#include "ED_armature.h" +#include "ED_undo.h" + +#include "BIF_retarget.h" + +#include "armature_intern.h" + +/************ RIG RETARGET DATA STRUCTURES ***************/ + +typedef struct MemoNode { + float weight; + int next; +} MemoNode; + +typedef struct RetargetParam { + RigGraph *rigg; + RigArc *iarc; + RigNode *inode_start; + bContext *context; +} RetargetParam; + +typedef enum { + RETARGET_LENGTH, + RETARGET_AGGRESSIVE +} RetargetMode; + +typedef enum { + METHOD_BRUTE_FORCE = 0, + METHOD_MEMOIZE = 1 +} RetargetMethod; + +typedef enum { + ARC_FREE = 0, + ARC_TAKEN = 1, + ARC_USED = 2 +} ArcUsageFlags; + +static RigGraph *GLOBAL_RIGG = NULL; + +/*******************************************************************************************************/ + +void exec_retargetArctoArc(TaskPool * __restrict pool, void *taskdata, int threadid); + +static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second); +float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]); + +/* two levels */ +#define SHAPE_LEVELS (SHAPE_RADIX * SHAPE_RADIX) + +/*********************************** EDITBONE UTILS ****************************************************/ + +static int countEditBoneChildren(ListBase *list, EditBone *parent) +{ + EditBone *ebone; + int count = 0; + + for (ebone = list->first; ebone; ebone = ebone->next) { + if (ebone->parent == parent) { + count++; + } + } + + return count; +} + +static EditBone *nextEditBoneChild(ListBase *list, EditBone *parent, int n) +{ + EditBone *ebone; + + for (ebone = list->first; ebone; ebone = ebone->next) { + if (ebone->parent == parent) { + if (n == 0) { + return ebone; + } + n--; + } + } + + return NULL; +} + +static void getEditBoneRollUpAxis(EditBone *bone, float roll, float up_axis[3]) +{ + float mat[3][3], nor[3]; + + sub_v3_v3v3(nor, bone->tail, bone->head); + + vec_roll_to_mat3(nor, roll, mat); + copy_v3_v3(up_axis, mat[2]); +} + +static float rollBoneByQuatAligned(EditBone *bone, float old_up_axis[3], float qrot[4], float qroll[4], float aligned_axis[3]) +{ + float nor[3], new_up_axis[3], x_axis[3], z_axis[3]; + + copy_v3_v3(new_up_axis, old_up_axis); + mul_qt_v3(qrot, new_up_axis); + + sub_v3_v3v3(nor, bone->tail, bone->head); + + cross_v3_v3v3(x_axis, nor, aligned_axis); + cross_v3_v3v3(z_axis, x_axis, nor); + + normalize_v3(new_up_axis); + normalize_v3(x_axis); + normalize_v3(z_axis); + + if (dot_v3v3(new_up_axis, x_axis) < 0) { + negate_v3(x_axis); + } + + if (dot_v3v3(new_up_axis, z_axis) < 0) { + negate_v3(z_axis); + } + + if (angle_normalized_v3v3(x_axis, new_up_axis) < angle_normalized_v3v3(z_axis, new_up_axis)) { + rotation_between_vecs_to_quat(qroll, new_up_axis, x_axis); /* set roll rotation quat */ + return ED_armature_ebone_roll_to_vector(bone, x_axis, false); + } + else { + rotation_between_vecs_to_quat(qroll, new_up_axis, z_axis); /* set roll rotation quat */ + return ED_armature_ebone_roll_to_vector(bone, z_axis, false); + } +} + +static float rollBoneByQuatJoint(RigEdge *edge, RigEdge *previous, float qrot[4], float qroll[4], float up_axis[3]) +{ + if (previous == NULL) { + /* default to up_axis if no previous */ + return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis); + } + else { + float new_up_axis[3]; + float vec_first[3], vec_second[3], normal[3]; + + if (previous->bone) { + sub_v3_v3v3(vec_first, previous->bone->tail, previous->bone->head); + } + else if (previous->prev->bone) { + sub_v3_v3v3(vec_first, edge->bone->head, previous->prev->bone->tail); + } + else { + /* default to up_axis if first bone in the chain is an offset */ + return rollBoneByQuatAligned(edge->bone, edge->up_axis, qrot, qroll, up_axis); + } + + sub_v3_v3v3(vec_second, edge->bone->tail, edge->bone->head); + + normalize_v3(vec_first); + normalize_v3(vec_second); + + cross_v3_v3v3(normal, vec_first, vec_second); + normalize_v3(normal); + + axis_angle_to_quat(qroll, vec_second, edge->up_angle); + + mul_qt_v3(qroll, normal); + + copy_v3_v3(new_up_axis, edge->up_axis); + mul_qt_v3(qrot, new_up_axis); + + normalize_v3(new_up_axis); + + /* real qroll between normal and up_axis */ + rotation_between_vecs_to_quat(qroll, new_up_axis, normal); + + return ED_armature_ebone_roll_to_vector(edge->bone, normal, false); + } +} + +float rollBoneByQuat(EditBone *bone, float old_up_axis[3], float qrot[4]) +{ + float new_up_axis[3]; + + copy_v3_v3(new_up_axis, old_up_axis); + mul_qt_v3(qrot, new_up_axis); + + return ED_armature_ebone_roll_to_vector(bone, new_up_axis, false); +} + +/************************************ DESTRUCTORS ******************************************************/ + +static void RIG_freeRigArc(BArc *arc) +{ + BLI_freelistN(&((RigArc *)arc)->edges); +} + +void RIG_freeRigGraph(BGraph *rg) +{ + RigGraph *rigg = (RigGraph *)rg; + BNode *node; + BArc *arc; + + BLI_task_pool_free(rigg->task_pool); + BLI_task_scheduler_free(rigg->task_scheduler); + + if (rigg->link_mesh) { + REEB_freeGraph(rigg->link_mesh); + } + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RIG_freeRigArc(arc); + } + BLI_freelistN(&rg->arcs); + + for (node = rg->nodes.first; node; node = node->next) { + BLI_freeNode(rg, (BNode *)node); + } + BLI_freelistN(&rg->nodes); + + BLI_freelistN(&rigg->controls); + + BLI_ghash_free(rigg->bones_map, NULL, NULL); + BLI_ghash_free(rigg->controls_map, NULL, NULL); + + if (rigg->flag & RIG_FREE_BONELIST) { + BLI_freelistN(rigg->editbones); + MEM_freeN(rigg->editbones); + } + + MEM_freeN(rg); +} + +/************************************* ALLOCATORS ******************************************************/ + +static RigGraph *newRigGraph(void) +{ + RigGraph *rg; + int totthread; + + rg = MEM_callocN(sizeof(RigGraph), "rig graph"); + + rg->head = NULL; + + rg->bones_map = BLI_ghash_str_new("newRigGraph bones gh"); + rg->controls_map = BLI_ghash_str_new("newRigGraph cont gh"); + + rg->free_arc = RIG_freeRigArc; + rg->free_node = NULL; + +#ifdef USE_THREADS + totthread = TASK_SCHEDULER_AUTO_THREADS; +#else + totthread = TASK_SCHEDULER_SINGLE_THREAD; +#endif + + rg->task_scheduler = BLI_task_scheduler_create(totthread); + rg->task_pool = BLI_task_pool_create(rg->task_scheduler, NULL); + + return rg; +} + +static RigArc *newRigArc(RigGraph *rg) +{ + RigArc *arc; + + arc = MEM_callocN(sizeof(RigArc), "rig arc"); + arc->count = 0; + BLI_addtail(&rg->arcs, arc); + + return arc; +} + +static RigControl *newRigControl(RigGraph *rg) +{ + RigControl *ctrl; + + ctrl = MEM_callocN(sizeof(RigControl), "rig control"); + + BLI_addtail(&rg->controls, ctrl); + + return ctrl; +} + +static RigNode *newRigNodeHead(RigGraph *rg, RigArc *arc, float p[3]) +{ + RigNode *node; + node = MEM_callocN(sizeof(RigNode), "rig node"); + BLI_addtail(&rg->nodes, node); + + copy_v3_v3(node->p, p); + node->degree = 1; + node->arcs = NULL; + + arc->head = node; + + return node; +} + +static void addRigNodeHead(RigGraph *UNUSED(rg), RigArc *arc, RigNode *node) +{ + node->degree++; + + arc->head = node; +} + +static RigNode *newRigNode(RigGraph *rg, float p[3]) +{ + RigNode *node; + node = MEM_callocN(sizeof(RigNode), "rig node"); + BLI_addtail(&rg->nodes, node); + + copy_v3_v3(node->p, p); + node->degree = 0; + node->arcs = NULL; + + return node; +} + +static RigNode *newRigNodeTail(RigGraph *rg, RigArc *arc, float p[3]) +{ + RigNode *node = newRigNode(rg, p); + + node->degree = 1; + arc->tail = node; + + return node; +} + +static void RIG_appendEdgeToArc(RigArc *arc, RigEdge *edge) +{ + BLI_addtail(&arc->edges, edge); + + if (edge->prev == NULL) { + copy_v3_v3(edge->head, arc->head->p); + } + else { + RigEdge *last_edge = edge->prev; + copy_v3_v3(edge->head, last_edge->tail); + RIG_calculateEdgeAngles(last_edge, edge); + } + + edge->length = len_v3v3(edge->head, edge->tail); + + arc->length += edge->length; + + arc->count += 1; +} + +static void RIG_addEdgeToArc(RigArc *arc, float tail[3], EditBone *bone) +{ + RigEdge *edge; + + edge = MEM_callocN(sizeof(RigEdge), "rig edge"); + + copy_v3_v3(edge->tail, tail); + edge->bone = bone; + + if (bone) { + getEditBoneRollUpAxis(bone, bone->roll, edge->up_axis); + } + + RIG_appendEdgeToArc(arc, edge); +} +/************************************** CLONING TEMPLATES **********************************************/ + +static void renameTemplateBone(char *name, char *template_name, ListBase *editbones, char *side_string, char *num_string) +{ + int i, j; + + for (i = 0, j = 0; i < (MAXBONENAME - 1) && j < (MAXBONENAME - 1) && template_name[i] != '\0'; i++) { + if (template_name[i] == '&') { + if (template_name[i + 1] == 'S' || template_name[i + 1] == 's') { + j += BLI_strncpy_rlen(name + j, side_string, MAXBONENAME); + i++; + } + else if (template_name[i + 1] == 'N' || template_name[i + 1] == 'n') { + j += BLI_strncpy_rlen(name + j, num_string, MAXBONENAME); + i++; + } + else { + name[j] = template_name[i]; + j++; + } + } + else { + name[j] = template_name[i]; + j++; + } + } + + name[j] = '\0'; + + ED_armature_ebone_unique_name(editbones, name, NULL); +} + +static RigControl *cloneControl(RigGraph *rg, RigGraph *src_rg, RigControl *src_ctrl, GHash *ptr_hash, char *side_string, char *num_string) +{ + RigControl *ctrl; + char name[MAXBONENAME]; + + ctrl = newRigControl(rg); + + copy_v3_v3(ctrl->head, src_ctrl->head); + copy_v3_v3(ctrl->tail, src_ctrl->tail); + copy_v3_v3(ctrl->up_axis, src_ctrl->up_axis); + copy_v3_v3(ctrl->offset, src_ctrl->offset); + + ctrl->tail_mode = src_ctrl->tail_mode; + ctrl->flag = src_ctrl->flag; + + renameTemplateBone(name, src_ctrl->bone->name, rg->editbones, side_string, num_string); + ctrl->bone = duplicateEditBoneObjects(src_ctrl->bone, name, rg->editbones, src_rg->ob, rg->ob); + ctrl->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + BLI_ghash_insert(ptr_hash, src_ctrl->bone, ctrl->bone); + + ctrl->link = src_ctrl->link; + ctrl->link_tail = src_ctrl->link_tail; + + return ctrl; +} + +static RigArc *cloneArc(RigGraph *rg, RigGraph *src_rg, RigArc *src_arc, GHash *ptr_hash, char *side_string, char *num_string) +{ + RigEdge *src_edge; + RigArc *arc; + + arc = newRigArc(rg); + + arc->head = BLI_ghash_lookup(ptr_hash, src_arc->head); + arc->tail = BLI_ghash_lookup(ptr_hash, src_arc->tail); + + arc->head->degree++; + arc->tail->degree++; + + arc->length = src_arc->length; + + arc->count = src_arc->count; + + for (src_edge = src_arc->edges.first; src_edge; src_edge = src_edge->next) { + RigEdge *edge; + + edge = MEM_callocN(sizeof(RigEdge), "rig edge"); + + copy_v3_v3(edge->head, src_edge->head); + copy_v3_v3(edge->tail, src_edge->tail); + copy_v3_v3(edge->up_axis, src_edge->up_axis); + + edge->length = src_edge->length; + edge->angle = src_edge->angle; + edge->up_angle = src_edge->up_angle; + + if (src_edge->bone != NULL) { + char name[MAXBONENAME]; + renameTemplateBone(name, src_edge->bone->name, rg->editbones, side_string, num_string); + edge->bone = duplicateEditBoneObjects(src_edge->bone, name, rg->editbones, src_rg->ob, rg->ob); + edge->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + BLI_ghash_insert(ptr_hash, src_edge->bone, edge->bone); + } + + BLI_addtail(&arc->edges, edge); + } + + return arc; +} + +static RigGraph *cloneRigGraph(RigGraph *src, ListBase *editbones, Object *ob, char *side_string, char *num_string) +{ + GHash *ptr_hash; + RigNode *node; + RigArc *arc; + RigControl *ctrl; + RigGraph *rg; + + ptr_hash = BLI_ghash_ptr_new("cloneRigGraph gh"); + + rg = newRigGraph(); + + rg->ob = ob; + rg->editbones = editbones; + + preEditBoneDuplicate(rg->editbones); /* prime bones for duplication */ + preEditBoneDuplicate(src->editbones); /* prime bones for duplication */ + + /* Clone nodes */ + for (node = src->nodes.first; node; node = node->next) { + RigNode *cloned_node = newRigNode(rg, node->p); + BLI_ghash_insert(ptr_hash, node, cloned_node); + } + + rg->head = BLI_ghash_lookup(ptr_hash, src->head); + + /* Clone arcs */ + for (arc = src->arcs.first; arc; arc = arc->next) { + cloneArc(rg, src, arc, ptr_hash, side_string, num_string); + } + + /* Clone controls */ + for (ctrl = src->controls.first; ctrl; ctrl = ctrl->next) { + cloneControl(rg, src, ctrl, ptr_hash, side_string, num_string); + } + + /* Relink bones properly */ + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *edge; + + for (edge = arc->edges.first; edge; edge = edge->next) { + if (edge->bone != NULL) { + EditBone *bone; + + updateDuplicateSubtargetObjects(edge->bone, src->editbones, src->ob, rg->ob); + + if (edge->bone->parent) { + bone = BLI_ghash_lookup(ptr_hash, edge->bone->parent); + + if (bone != NULL) { + edge->bone->parent = bone; + } + else { + /* disconnect since parent isn't cloned + * this will only happen when cloning from selected bones + * */ + edge->bone->flag &= ~BONE_CONNECTED; + } + } + } + } + } + + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + EditBone *bone; + + updateDuplicateSubtargetObjects(ctrl->bone, src->editbones, src->ob, rg->ob); + + if (ctrl->bone->parent) { + bone = BLI_ghash_lookup(ptr_hash, ctrl->bone->parent); + + if (bone != NULL) { + ctrl->bone->parent = bone; + } + else { + /* disconnect since parent isn't cloned + * this will only happen when cloning from selected bones + * */ + ctrl->bone->flag &= ~BONE_CONNECTED; + } + } + + ctrl->link = BLI_ghash_lookup(ptr_hash, ctrl->link); + ctrl->link_tail = BLI_ghash_lookup(ptr_hash, ctrl->link_tail); + } + + BLI_ghash_free(ptr_hash, NULL, NULL); + + return rg; +} + + +/*******************************************************************************************************/ + +static void RIG_calculateEdgeAngles(RigEdge *edge_first, RigEdge *edge_second) +{ + float vec_first[3], vec_second[3]; + + sub_v3_v3v3(vec_first, edge_first->tail, edge_first->head); + sub_v3_v3v3(vec_second, edge_second->tail, edge_second->head); + + normalize_v3(vec_first); + normalize_v3(vec_second); + + edge_first->angle = angle_normalized_v3v3(vec_first, vec_second); + + if (edge_second->bone != NULL) { + float normal[3]; + + cross_v3_v3v3(normal, vec_first, vec_second); + normalize_v3(normal); + + edge_second->up_angle = angle_normalized_v3v3(normal, edge_second->up_axis); + } +} + +/************************************ CONTROL BONES ****************************************************/ + +static void RIG_addControlBone(RigGraph *rg, EditBone *bone) +{ + RigControl *ctrl = newRigControl(rg); + ctrl->bone = bone; + copy_v3_v3(ctrl->head, bone->head); + copy_v3_v3(ctrl->tail, bone->tail); + getEditBoneRollUpAxis(bone, bone->roll, ctrl->up_axis); + ctrl->tail_mode = TL_NONE; + + BLI_ghash_insert(rg->controls_map, bone->name, ctrl); +} + +static int RIG_parentControl(RigControl *ctrl, EditBone *link) +{ + if (link) { + float offset[3]; + int flag = 0; + + sub_v3_v3v3(offset, ctrl->bone->head, link->head); + + /* if root matches, check for direction too */ + if (dot_v3v3(offset, offset) < 0.0001f) { + float vbone[3], vparent[3]; + + flag |= RIG_CTRL_FIT_ROOT; + + sub_v3_v3v3(vbone, ctrl->bone->tail, ctrl->bone->head); + sub_v3_v3v3(vparent, link->tail, link->head); + + /* test for opposite direction */ + if (dot_v3v3(vbone, vparent) > 0) { + float nor[3]; + float len; + + cross_v3_v3v3(nor, vbone, vparent); + + len = dot_v3v3(nor, nor); + if (len < 0.0001f) { + flag |= RIG_CTRL_FIT_BONE; + } + } + } + + /* Bail out if old one is automatically better */ + if (flag < ctrl->flag) { + return 0; + } + + /* if there's already a link + * overwrite only if new link is higher in the chain */ + if (ctrl->link && flag == ctrl->flag) { + EditBone *bone = NULL; + + for (bone = ctrl->link; bone; bone = bone->parent) { + /* if link is in the chain, break and use that one */ + if (bone == link) { + break; + } + } + + /* not in chain, don't update link */ + if (bone == NULL) { + return 0; + } + } + + + ctrl->link = link; + ctrl->flag = flag; + + copy_v3_v3(ctrl->offset, offset); + + return 1; + } + + return 0; +} + +static void RIG_reconnectControlBones(RigGraph *rg) +{ + RigControl *ctrl; + bool changed = true; + + /* first pass, link to deform bones */ + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + bPoseChannel *pchan; + bConstraint *con; + int found = 0; + + /* DO SOME MAGIC HERE */ + for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { + for (con = pchan->constraints.first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + /* constraint targets */ + if (cti && cti->get_constraint_targets) { + int target_index; + + cti->get_constraint_targets(con, &targets); + + for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) { + if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { + /* SET bone link to bone corresponding to pchan */ + EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name); + + /* Making sure bone is in this armature */ + if (link != NULL) { + /* for pole targets, link to parent bone instead, if possible */ + if (con->type == CONSTRAINT_TYPE_KINEMATIC && target_index == 1) { + if (link->parent && BLI_ghash_haskey(rg->bones_map, link->parent->name)) { + link = link->parent; + } + } + + found = RIG_parentControl(ctrl, link); + } + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } + + /* if not found yet, check parent */ + if (found == 0) { + if (ctrl->bone->parent) { + /* make sure parent is a deforming bone + * NULL if not + * */ + EditBone *link = BLI_ghash_lookup(rg->bones_map, ctrl->bone->parent->name); + + found = RIG_parentControl(ctrl, link); + } + + /* check if bone is not superposed on another one */ + { + RigArc *arc; + RigArc *best_arc = NULL; + EditBone *link = NULL; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *edge; + for (edge = arc->edges.first; edge; edge = edge->next) { + if (edge->bone) { + int fit = 0; + + fit = len_v3v3(ctrl->bone->head, edge->bone->head) < 0.0001f; + fit = fit || len_v3v3(ctrl->bone->tail, edge->bone->tail) < 0.0001f; + + if (fit) { + /* pick the bone on the arc with the lowest symmetry level + * means you connect control to the trunk of the skeleton */ + if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) { + best_arc = arc; + link = edge->bone; + } + } + } + } + } + + found = RIG_parentControl(ctrl, link); + } + } + + /* if not found yet, check child */ + if (found == 0) { + RigArc *arc; + RigArc *best_arc = NULL; + EditBone *link = NULL; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *edge; + for (edge = arc->edges.first; edge; edge = edge->next) { + if (edge->bone && edge->bone->parent == ctrl->bone) { + /* pick the bone on the arc with the lowest symmetry level + * means you connect control to the trunk of the skeleton */ + if (best_arc == NULL || arc->symmetry_level < best_arc->symmetry_level) { + best_arc = arc; + link = edge->bone; + } + } + } + } + + found = RIG_parentControl(ctrl, link); + } + + } + + + /* second pass, make chains in control bones */ + while (changed) { + changed = false; + + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + /* if control is not linked yet */ + if (ctrl->link == NULL) { + bPoseChannel *pchan; + bConstraint *con; + RigControl *ctrl_parent = NULL; + RigControl *ctrl_child; + int found = 0; + + if (ctrl->bone->parent) { + ctrl_parent = BLI_ghash_lookup(rg->controls_map, ctrl->bone->parent->name); + } + + /* check constraints first */ + + /* DO SOME MAGIC HERE */ + for (pchan = rg->ob->pose->chanbase.first; pchan; pchan = pchan->next) { + for (con = pchan->constraints.first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + ListBase targets = {NULL, NULL}; + bConstraintTarget *ct; + + /* constraint targets */ + if (cti && cti->get_constraint_targets) { + cti->get_constraint_targets(con, &targets); + + for (ct = targets.first; ct; ct = ct->next) { + if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) { + /* SET bone link to ctrl corresponding to pchan */ + RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name); + + /* if owner is a control bone, link with it */ + if (link && link->link) { + RIG_parentControl(ctrl, link->bone); + found = 1; + break; + } + } + } + + if (cti->flush_constraint_targets) + cti->flush_constraint_targets(con, &targets, 0); + } + } + } + + if (found == 0) { + /* check if parent is already linked */ + if (ctrl_parent && ctrl_parent->link) { + RIG_parentControl(ctrl, ctrl_parent->bone); + changed = true; + } + else { + /* check childs */ + for (ctrl_child = rg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) { + /* if a child is linked, link to that one */ + if (ctrl_child->link && ctrl_child->bone->parent == ctrl->bone) { + RIG_parentControl(ctrl, ctrl_child->bone); + changed = true; + break; + } + } + } + } + } + } + } + + /* third pass, link control tails */ + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + /* fit bone already means full match, so skip those */ + if ((ctrl->flag & RIG_CTRL_FIT_BONE) == 0) { + GHashIterator ghi; + + /* look on deform bones first */ + BLI_ghashIterator_init(&ghi, rg->bones_map); + + for (; !BLI_ghashIterator_done(&ghi); BLI_ghashIterator_step(&ghi)) { + EditBone *bone = (EditBone *)BLI_ghashIterator_getValue(&ghi); + + /* don't link with parent */ + if (bone->parent != ctrl->bone) { + if (len_v3v3(ctrl->bone->tail, bone->head) < 0.01f) { + ctrl->tail_mode = TL_HEAD; + ctrl->link_tail = bone; + break; + } + else if (len_v3v3(ctrl->bone->tail, bone->tail) < 0.01f) { + ctrl->tail_mode = TL_TAIL; + ctrl->link_tail = bone; + break; + } + } + } + + /* if we haven't found one yet, look in control bones */ + if (ctrl->tail_mode == TL_NONE) { + /* pass */ + } + } + } + +} + +/*******************************************************************************************************/ + +static void RIG_joinArcs(RigGraph *rg, RigNode *node, RigArc *joined_arc1, RigArc *joined_arc2) +{ + RigEdge *edge, *next_edge; + + /* ignore cases where joint is at start or end */ + if (joined_arc1->head == joined_arc2->head || joined_arc1->tail == joined_arc2->tail) { + return; + } + + /* swap arcs to make sure arc1 is before arc2 */ + if (joined_arc1->head == joined_arc2->tail) { + RigArc *tmp = joined_arc1; + joined_arc1 = joined_arc2; + joined_arc2 = tmp; + } + + for (edge = joined_arc2->edges.first; edge; edge = next_edge) { + next_edge = edge->next; + + RIG_appendEdgeToArc(joined_arc1, edge); + } + + joined_arc1->tail = joined_arc2->tail; + + BLI_listbase_clear(&joined_arc2->edges); + + BLI_removeArc((BGraph *)rg, (BArc *)joined_arc2); + + BLI_removeNode((BGraph *)rg, (BNode *)node); +} + +static void RIG_removeNormalNodes(RigGraph *rg) +{ + RigNode *node, *next_node; + + for (node = rg->nodes.first; node; node = next_node) { + next_node = node->next; + + if (node->degree == 2) { + RigArc *arc, *joined_arc1 = NULL, *joined_arc2 = NULL; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + if (arc->head == node || arc->tail == node) { + if (joined_arc1 == NULL) { + joined_arc1 = arc; + } + else { + joined_arc2 = arc; + break; + } + } + } + + RIG_joinArcs(rg, node, joined_arc1, joined_arc2); + } + } +} + +static void RIG_removeUneededOffsets(RigGraph *rg) +{ + RigArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *first_edge, *last_edge; + + first_edge = arc->edges.first; + last_edge = arc->edges.last; + + if (first_edge->bone == NULL) { + if (first_edge->bone == NULL && len_v3v3(first_edge->tail, arc->head->p) <= 0.001f) { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + } + else if (arc->head->degree == 1) { + RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001f); + + if (new_node) { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head); + } + else { + RigEdge *next_edge = first_edge->next; + + if (next_edge) { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + + copy_v3_v3(arc->head->p, next_edge->head); + } + } + } + else { + /* check if all arc connected start with a null edge */ + RigArc *other_arc; + for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) { + if (other_arc != arc) { + RigEdge *test_edge; + if (other_arc->head == arc->head) { + test_edge = other_arc->edges.first; + + if (test_edge->bone != NULL) { + break; + } + } + else if (other_arc->tail == arc->head) { + test_edge = other_arc->edges.last; + + if (test_edge->bone != NULL) { + break; + } + } + } + } + + if (other_arc == NULL) { + RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, first_edge->tail, 0.001); + + if (new_node) { + /* remove null edge in other arcs too */ + for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) { + if (other_arc != arc) { + RigEdge *test_edge; + if (other_arc->head == arc->head) { + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->head); + test_edge = other_arc->edges.first; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + else if (other_arc->tail == arc->head) { + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)other_arc, (BNode *)new_node, (BNode *)other_arc->tail); + test_edge = other_arc->edges.last; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + } + } + + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->head); + } + else { + RigEdge *next_edge = first_edge->next; + + if (next_edge) { + BLI_remlink(&arc->edges, first_edge); + MEM_freeN(first_edge); + + copy_v3_v3(arc->head->p, next_edge->head); + + /* remove null edge in other arcs too */ + for (other_arc = rg->arcs.first; other_arc; other_arc = other_arc->next) { + if (other_arc != arc) { + RigEdge *test_edge; + if (other_arc->head == arc->head) { + test_edge = other_arc->edges.first; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + else if (other_arc->tail == arc->head) { + test_edge = other_arc->edges.last; + BLI_remlink(&other_arc->edges, test_edge); + MEM_freeN(test_edge); + } + } + } + } + } + } + } + } + + if (last_edge->bone == NULL) { + if (len_v3v3(last_edge->head, arc->tail->p) <= 0.001f) { + BLI_remlink(&arc->edges, last_edge); + MEM_freeN(last_edge); + } + else if (arc->tail->degree == 1) { + RigNode *new_node = (RigNode *)BLI_FindNodeByPosition((BGraph *)rg, last_edge->head, 0.001f); + + if (new_node) { + RigEdge *previous_edge = last_edge->prev; + + BLI_remlink(&arc->edges, last_edge); + MEM_freeN(last_edge); + BLI_replaceNodeInArc((BGraph *)rg, (BArc *)arc, (BNode *)new_node, (BNode *)arc->tail); + + /* set previous angle to 0, since there's no following edges */ + if (previous_edge) { + previous_edge->angle = 0; + } + } + else { + RigEdge *previous_edge = last_edge->prev; + + if (previous_edge) { + BLI_remlink(&arc->edges, last_edge); + MEM_freeN(last_edge); + + copy_v3_v3(arc->tail->p, previous_edge->tail); + previous_edge->angle = 0; + } + } + } + } + } +} + +static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bone, RigNode *starting_node, bool selected) +{ + EditBone *bone, *last_bone = root_bone; + RigArc *arc = NULL; + int contain_head = 0; + + for (bone = root_bone; bone; bone = nextEditBoneChild(list, bone, 0)) { + int nb_children; + + if (selected == 0 || (bone->flag & BONE_SELECTED)) { + if ((bone->flag & BONE_NO_DEFORM) == 0) { + BLI_ghash_insert(rg->bones_map, bone->name, bone); + + if (arc == NULL) { + arc = newRigArc(rg); + + if (starting_node == NULL) { + starting_node = newRigNodeHead(rg, arc, root_bone->head); + } + else { + addRigNodeHead(rg, arc, starting_node); + } + } + + if (bone->parent && (bone->flag & BONE_CONNECTED) == 0) { + RIG_addEdgeToArc(arc, bone->head, NULL); + } + + RIG_addEdgeToArc(arc, bone->tail, bone); + + last_bone = bone; + + if (STREQ(bone->name, "head")) { + contain_head = 1; + } + } + else if ((bone->flag & BONE_EDITMODE_LOCKED) == 0) { /* ignore locked bones */ + RIG_addControlBone(rg, bone); + } + } + + nb_children = countEditBoneChildren(list, bone); + if (nb_children > 1) { + RigNode *end_node = NULL; + int i; + + if (arc != NULL) { + end_node = newRigNodeTail(rg, arc, bone->tail); + } + else { + end_node = newRigNode(rg, bone->tail); + } + + for (i = 0; i < nb_children; i++) { + root_bone = nextEditBoneChild(list, bone, i); + RIG_arcFromBoneChain(rg, list, root_bone, end_node, selected); + } + + /* arc ends here, break */ + break; + } + } + + /* If the loop exited without forking */ + if (arc != NULL && bone == NULL) { + newRigNodeTail(rg, arc, last_bone->tail); + } + + if (contain_head) { + rg->head = arc->tail; + } +} + +/*******************************************************************************************************/ +static void RIG_findHead(RigGraph *rg) +{ + if (rg->head == NULL) { + if (BLI_listbase_is_single(&rg->arcs)) { + RigArc *arc = rg->arcs.first; + + rg->head = (RigNode *)arc->head; + } + else { + RigArc *arc; + + for (arc = rg->arcs.first; arc; arc = arc->next) { + RigEdge *edge = arc->edges.last; + + if (edge->bone->flag & (BONE_TIPSEL | BONE_SELECTED)) { + rg->head = arc->tail; + break; + } + } + } + + if (rg->head == NULL) { + rg->head = rg->nodes.first; + } + } +} + +/*******************************************************************************************************/ + +static void RIG_printNode(RigNode *node, const char name[]) +{ + printf("%s %p %i <%0.3f, %0.3f, %0.3f>\n", name, (void *)node, node->degree, node->p[0], node->p[1], node->p[2]); + + if (node->symmetry_flag & SYM_TOPOLOGICAL) { + if (node->symmetry_flag & SYM_AXIAL) + printf("Symmetry AXIAL\n"); + else if (node->symmetry_flag & SYM_RADIAL) + printf("Symmetry RADIAL\n"); + + print_v3("symmetry axis", node->symmetry_axis); + } +} + +void RIG_printArcBones(RigArc *arc) +{ + RigEdge *edge; + + for (edge = arc->edges.first; edge; edge = edge->next) { + if (edge->bone) + printf("%s ", edge->bone->name); + else + printf("---- "); + } + printf("\n"); +} + +static void RIG_printCtrl(RigControl *ctrl, char *indent) +{ + char text[128]; + + printf("%sBone: %s\n", indent, ctrl->bone->name); + printf("%sLink: %s\n", indent, ctrl->link ? ctrl->link->name : "!NONE!"); + + BLI_snprintf(text, sizeof(text), "%soffset", indent); + print_v3(text, ctrl->offset); + + printf("%sFlag: %i\n", indent, ctrl->flag); +} + +static void RIG_printLinkedCtrl(RigGraph *rg, EditBone *bone, int tabs) +{ + RigControl *ctrl; + char indent[64]; + char *s = indent; + int i; + + for (i = 0; i < tabs; i++) { + s[0] = '\t'; + s++; + } + s[0] = 0; + + for (ctrl = rg->controls.first; ctrl; ctrl = ctrl->next) { + if (ctrl->link == bone) { + RIG_printCtrl(ctrl, indent); + RIG_printLinkedCtrl(rg, ctrl->bone, tabs + 1); + } + } +} + +void RIG_printArc(RigGraph *rg, RigArc *arc) +{ + RigEdge *edge; + + RIG_printNode((RigNode *)arc->head, "head"); + + for (edge = arc->edges.first; edge; edge = edge->next) { + printf("\tinner joints %0.3f %0.3f %0.3f\n", edge->tail[0], edge->tail[1], edge->tail[2]); + printf("\t\tlength %f\n", edge->length); + printf("\t\tangle %f\n", edge->angle * (float)(180 / M_PI)); + if (edge->bone) { + printf("\t\t%s\n", edge->bone->name); + RIG_printLinkedCtrl(rg, edge->bone, 3); + } + } + printf("symmetry level: %i flag: %i group %i\n", arc->symmetry_level, arc->symmetry_flag, arc->symmetry_group); + + RIG_printNode((RigNode *)arc->tail, "tail"); +} + +void RIG_printGraph(RigGraph *rg) +{ + RigArc *arc; + + printf("---- ARCS ----\n"); + for (arc = rg->arcs.first; arc; arc = arc->next) { + RIG_printArc(rg, arc); + printf("\n"); + } + + if (rg->head) { + RIG_printNode(rg->head, "HEAD NODE:"); + } + else { + printf("HEAD NODE: NONE\n"); + } +} + +/*******************************************************************************************************/ + +RigGraph *RIG_graphFromArmature(const bContext *C, Object *ob, bArmature *arm) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + EditBone *ebone; + RigGraph *rg; + + rg = newRigGraph(); + + if (obedit == ob) { + rg->editbones = ((bArmature *)obedit->data)->edbo; + } + else { + rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones"); + make_boneList(rg->editbones, &arm->bonebase, NULL, NULL); + rg->flag |= RIG_FREE_BONELIST; + } + + rg->ob = ob; + + /* Do the rotations */ + for (ebone = rg->editbones->first; ebone; ebone = ebone->next) { + if (ebone->parent == NULL) { + RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 0); + } + } + + BLI_removeDoubleNodes((BGraph *)rg, 0.001); + + RIG_removeNormalNodes(rg); + + RIG_removeUneededOffsets(rg); + + BLI_buildAdjacencyList((BGraph *)rg); + + RIG_findHead(rg); + + BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit); + + RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */ + + if (BLI_isGraphCyclic((BGraph *)rg)) { + printf("armature cyclic\n"); + } + + return rg; +} + +static RigGraph *armatureSelectedToGraph(bContext *C, Object *ob, bArmature *arm) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + EditBone *ebone; + RigGraph *rg; + + rg = newRigGraph(); + + if (obedit == ob) { + rg->editbones = arm->edbo; + } + else { + rg->editbones = MEM_callocN(sizeof(ListBase), "EditBones"); + make_boneList(rg->editbones, &arm->bonebase, NULL, NULL); + rg->flag |= RIG_FREE_BONELIST; + } + + rg->ob = ob; + + /* Do the rotations */ + for (ebone = rg->editbones->first; ebone; ebone = ebone->next) { + if (ebone->parent == NULL) { + RIG_arcFromBoneChain(rg, rg->editbones, ebone, NULL, 1); + } + } + + BLI_removeDoubleNodes((BGraph *)rg, 0.001); + + RIG_removeNormalNodes(rg); + + RIG_removeUneededOffsets(rg); + + BLI_buildAdjacencyList((BGraph *)rg); + + RIG_findHead(rg); + + BLI_markdownSymmetry((BGraph *)rg, (BNode *)rg->head, scene->toolsettings->skgen_symmetry_limit); + + RIG_reconnectControlBones(rg); /* after symmetry, because we use levels to find best match */ + + if (BLI_isGraphCyclic((BGraph *)rg)) { + printf("armature cyclic\n"); + } + + return rg; +} +/************************************ GENERATING *****************************************************/ + +#if 0 +static EditBone *add_editbonetolist(char *name, ListBase *list) +{ + EditBone *bone = MEM_callocN(sizeof(EditBone), "eBone"); + + BLI_strncpy(bone->name, name, sizeof(bone->name)); + ED_armature_ebone_unique_name(list, bone->name, NULL); + + BLI_addtail(list, bone); + + bone->flag |= BONE_TIPSEL; + bone->weight = 1.0F; + bone->dist = 0.25F; + bone->xwidth = 0.1; + bone->zwidth = 0.1; + bone->rad_head = 0.10; + bone->rad_tail = 0.05; + bone->segments = 1; + bone->layer = 1; //arm->layer; + + /* Bendy-Bone parameters */ + bone->roll1 = 0.0f; + bone->roll2 = 0.0f; + bone->curveInX = 0.0f; + bone->curveInY = 0.0f; + bone->curveOutX = 0.0f; + bone->curveOutY = 0.0f; + bone->ease1 = 1.0f; + bone->ease2 = 1.0f; + bone->scaleIn = 1.0f; + bone->scaleOut = 1.0f; + + return bone; +} +#endif + +#if 0 /* UNUSED */ +static void generateMissingArcsFromNode(RigGraph *rigg, ReebNode *node, int multi_level_limit) +{ + while (node->multi_level > multi_level_limit && node->link_up) + { + node = node->link_up; + } + + while (node->multi_level < multi_level_limit && node->link_down) + { + node = node->link_down; + } + + if (node->multi_level == multi_level_limit) + { + int i; + + for (i = 0; i < node->degree; i++) + { + ReebArc *earc = node->arcs[i]; + + if (earc->flag == ARC_FREE && earc->head == node) + { + ReebNode *other = BIF_otherNodeFromIndex(earc, node); + + earc->flag = ARC_USED; + + //generateBonesForArc(rigg, earc, node, other); + generateMissingArcsFromNode(rigg, other, multi_level_limit); + } + } + } +} + +static void generateMissingArcs(RigGraph *rigg) +{ + ReebGraph *reebg; + int multi_level_limit = 5; + + for (reebg = rigg->link_mesh; reebg; reebg = reebg->link_up) + { + ReebArc *earc; + + for (earc = reebg->arcs.first; earc; earc = earc->next) + { + if (earc->flag == ARC_USED) + { + generateMissingArcsFromNode(rigg, earc->head, multi_level_limit); + generateMissingArcsFromNode(rigg, earc->tail, multi_level_limit); + } + } + } +} +#endif + +/************************************ RETARGETTING *****************************************************/ + +static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float tail[3], float qrot[4], float resize); + +static void repositionTailControl(RigGraph *rigg, RigControl *ctrl); + +static void finalizeControl(RigGraph *rigg, RigControl *ctrl, float resize) +{ + if ((ctrl->flag & RIG_CTRL_DONE) == RIG_CTRL_DONE) { + RigControl *ctrl_child; + +#if 0 + printf("CTRL: %s LINK: %s", ctrl->bone->name, ctrl->link->name); + + if (ctrl->link_tail) + { + printf(" TAIL: %s", ctrl->link_tail->name); + } + + printf("\n"); +#endif + + /* if there was a tail link: apply link, recalc resize factor and qrot */ + if (ctrl->tail_mode != TL_NONE) { + float *tail_vec = NULL; + float v1[3], v2[3], qtail[4]; + + if (ctrl->tail_mode == TL_TAIL) { + tail_vec = ctrl->link_tail->tail; + } + else if (ctrl->tail_mode == TL_HEAD) { + tail_vec = ctrl->link_tail->head; + } + + sub_v3_v3v3(v1, ctrl->bone->tail, ctrl->bone->head); + sub_v3_v3v3(v2, tail_vec, ctrl->bone->head); + + copy_v3_v3(ctrl->bone->tail, tail_vec); + + rotation_between_vecs_to_quat(qtail, v1, v2); + mul_qt_qtqt(ctrl->qrot, qtail, ctrl->qrot); + + resize = len_v3(v2) / len_v3v3(ctrl->head, ctrl->tail); + } + + ctrl->bone->roll = rollBoneByQuat(ctrl->bone, ctrl->up_axis, ctrl->qrot); + + /* Cascade to connected control bones */ + for (ctrl_child = rigg->controls.first; ctrl_child; ctrl_child = ctrl_child->next) { + if (ctrl_child->link == ctrl->bone) { + repositionControl(rigg, ctrl_child, ctrl->bone->head, ctrl->bone->tail, ctrl->qrot, resize); + } + if (ctrl_child->link_tail == ctrl->bone) { + repositionTailControl(rigg, ctrl_child); + } + } + } +} + +static void repositionTailControl(RigGraph *rigg, RigControl *ctrl) +{ + ctrl->flag |= RIG_CTRL_TAIL_DONE; + + finalizeControl(rigg, ctrl, 1); /* resize will be recalculated anyway so we don't need it */ +} + +static void repositionControl(RigGraph *rigg, RigControl *ctrl, float head[3], float UNUSED(tail[3]), float qrot[4], float resize) +{ + float parent_offset[3], tail_offset[3]; + + copy_v3_v3(parent_offset, ctrl->offset); + mul_v3_fl(parent_offset, resize); + mul_qt_v3(qrot, parent_offset); + + add_v3_v3v3(ctrl->bone->head, head, parent_offset); + + ctrl->flag |= RIG_CTRL_HEAD_DONE; + + copy_qt_qt(ctrl->qrot, qrot); + + if (ctrl->tail_mode == TL_NONE) { + sub_v3_v3v3(tail_offset, ctrl->tail, ctrl->head); + mul_v3_fl(tail_offset, resize); + mul_qt_v3(qrot, tail_offset); + + add_v3_v3v3(ctrl->bone->tail, ctrl->bone->head, tail_offset); + + ctrl->flag |= RIG_CTRL_TAIL_DONE; + } + + finalizeControl(rigg, ctrl, resize); +} + +static void repositionBone(bContext *C, RigGraph *rigg, RigEdge *edge, float vec0[3], float vec1[3], float up_axis[3]) +{ + Scene *scene = CTX_data_scene(C); + EditBone *bone; + RigControl *ctrl; + float qrot[4], resize; + float v1[3], v2[3]; + float l1, l2; + + bone = edge->bone; + + sub_v3_v3v3(v1, edge->tail, edge->head); + sub_v3_v3v3(v2, vec1, vec0); + + l1 = normalize_v3(v1); + l2 = normalize_v3(v2); + + resize = l2 / l1; + + rotation_between_vecs_to_quat(qrot, v1, v2); + + copy_v3_v3(bone->head, vec0); + copy_v3_v3(bone->tail, vec1); + + if (!is_zero_v3(up_axis)) { + float qroll[4]; + + if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_VIEW) { + bone->roll = rollBoneByQuatAligned(bone, edge->up_axis, qrot, qroll, up_axis); + } + else if (scene->toolsettings->skgen_retarget_roll == SK_RETARGET_ROLL_JOINT) { + bone->roll = rollBoneByQuatJoint(edge, edge->prev, qrot, qroll, up_axis); + } + else { + unit_qt(qroll); + } + + mul_qt_qtqt(qrot, qroll, qrot); + } + else { + bone->roll = rollBoneByQuat(bone, edge->up_axis, qrot); + } + + for (ctrl = rigg->controls.first; ctrl; ctrl = ctrl->next) { + if (ctrl->link == bone) { + repositionControl(rigg, ctrl, vec0, vec1, qrot, resize); + } + if (ctrl->link_tail == bone) { + repositionTailControl(rigg, ctrl); + } + } +} + +static RetargetMode detectArcRetargetMode(RigArc *arc); +static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start); + + +static RetargetMode detectArcRetargetMode(RigArc *iarc) +{ + RetargetMode mode = RETARGET_AGGRESSIVE; + ReebArc *earc = iarc->link_mesh; + RigEdge *edge; + int large_angle = 0; + float avg_angle = 0; + /* float avg_length = 0; */ /* UNUSED */ + int nb_edges = 0; + + + for (edge = iarc->edges.first; edge; edge = edge->next) { + avg_angle += edge->angle; + nb_edges++; + } + + avg_angle /= nb_edges - 1; /* -1 because last edge doesn't have an angle */ + + /* avg_length = iarc->length / nb_edges; */ /* UNUSED */ + + + if (nb_edges > 2) { + for (edge = iarc->edges.first; edge; edge = edge->next) { + if (fabsf(edge->angle - avg_angle) > (float)(M_PI / 6)) { + large_angle = 1; + } + } + } + else if (nb_edges == 2 && avg_angle > 0) { + large_angle = 1; + } + + + if (large_angle == 0) { + mode = RETARGET_LENGTH; + } + + if (earc->bcount <= (iarc->count - 1)) { + mode = RETARGET_LENGTH; + } + + return mode; +} + +#ifndef USE_THREADS +static void printMovesNeeded(int *positions, int nb_positions) +{ + int moves = 0; + int i; + + for (i = 0; i < nb_positions; i++) { + moves += positions[i] - (i + 1); + } + + printf("%i moves needed\n", moves); +} + +static void printPositions(int *positions, int nb_positions) +{ + int i; + + for (i = 0; i < nb_positions; i++) { + printf("%i ", positions[i]); + } + printf("\n"); +} +#endif + +#define MAX_COST FLT_MAX /* FIX ME */ + +static float costDistance(BArcIterator *iter, float *vec0, float *vec1, int i0, int i1, float distance_weight) +{ + EmbedBucket *bucket = NULL; + float max_dist = 0; + float v1[3], v2[3], c[3]; + float v1_inpf; + + if (distance_weight > 0) { + sub_v3_v3v3(v1, vec0, vec1); + + v1_inpf = dot_v3v3(v1, v1); + + if (v1_inpf > 0) { + int j; + for (j = i0 + 1; j < i1 - 1; j++) { + float dist; + + bucket = IT_peek(iter, j); + + sub_v3_v3v3(v2, bucket->p, vec1); + + cross_v3_v3v3(c, v1, v2); + + dist = dot_v3v3(c, c) / v1_inpf; + + max_dist = dist > max_dist ? dist : max_dist; + } + + return distance_weight * max_dist; + } + else { + return MAX_COST; + } + } + else { + return 0; + } +} + +static float costAngle(float original_angle, float vec_first[3], float vec_second[3], float angle_weight) +{ + if (angle_weight > 0) { + float current_angle; + + if (!is_zero_v3(vec_first) && !is_zero_v3(vec_second)) { + current_angle = saacos(dot_v3v3(vec_first, vec_second)); + + return angle_weight * fabsf(current_angle - original_angle); + } + else { + return angle_weight * (float)M_PI; + } + } + else { + return 0; + } +} + +static float costLength(float original_length, float current_length, float length_weight) +{ + if (current_length == 0) { + return MAX_COST; + } + else { + float length_ratio = fabsf((current_length - original_length) / original_length); + return length_weight * length_ratio * length_ratio; + } +} + +#if 0 +static float calcCostLengthDistance(BArcIterator *iter, float **vec_cache, RigEdge *edge, float *vec1, float *vec2, int i1, int i2) +{ + float vec[3]; + float length; + + sub_v3_v3v3(vec, vec2, vec1); + length = normalize_v3(vec); + + return costLength(edge->length, length) + costDistance(iter, vec1, vec2, i1, i2); +} +#endif + +static float calcCostAngleLengthDistance(BArcIterator *iter, float **UNUSED(vec_cache), RigEdge *edge, + float *vec0, float *vec1, float *vec2, int i1, int i2, + float angle_weight, float length_weight, float distance_weight) +{ + float vec_second[3], vec_first[3]; + float length2; + float new_cost = 0; + + sub_v3_v3v3(vec_second, vec2, vec1); + length2 = normalize_v3(vec_second); + + + /* Angle cost */ + if (edge->prev) { + sub_v3_v3v3(vec_first, vec1, vec0); + normalize_v3(vec_first); + + new_cost += costAngle(edge->prev->angle, vec_first, vec_second, angle_weight); + } + + /* Length cost */ + new_cost += costLength(edge->length, length2, length_weight); + + /* Distance cost */ + new_cost += costDistance(iter, vec1, vec2, i1, i2, distance_weight); + + return new_cost; +} + +static int indexMemoNode(int nb_positions, int previous, int current, int joints_left) +{ + return joints_left * nb_positions * nb_positions + current * nb_positions + previous; +} + +static void copyMemoPositions(int *positions, MemoNode *table, int nb_positions, int joints_left) +{ + int previous = 0, current = 0; + int i = 0; + + for (i = 0; joints_left > 0; joints_left--, i++) { + MemoNode *node; + node = table + indexMemoNode(nb_positions, previous, current, joints_left); + + positions[i] = node->next; + + previous = current; + current = node->next; + } +} + +static MemoNode *solveJoints(MemoNode *table, BArcIterator *iter, float **vec_cache, + int nb_joints, int nb_positions, int previous, int current, RigEdge *edge, + int joints_left, float angle_weight, float length_weight, float distance_weight) +{ + MemoNode *node; + int index = indexMemoNode(nb_positions, previous, current, joints_left); + + node = table + index; + + if (node->weight != 0) { + return node; + } + else if (joints_left == 0) { + float *vec0 = vec_cache[previous]; + float *vec1 = vec_cache[current]; + float *vec2 = vec_cache[nb_positions + 1]; + + node->weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, iter->length, angle_weight, length_weight, distance_weight); + + return node; + } + else { + MemoNode *min_node = NULL; + float *vec0 = vec_cache[previous]; + float *vec1 = vec_cache[current]; + float min_weight = 0.0f; + int min_next = 0; + int next; + + for (next = current + 1; next <= nb_positions - (joints_left - 1); next++) { + MemoNode *next_node; + float *vec2 = vec_cache[next]; + float weight = 0.0f; + + /* ADD WEIGHT OF PREVIOUS - CURRENT - NEXT triple */ + weight = calcCostAngleLengthDistance(iter, vec_cache, edge, vec0, vec1, vec2, current, next, angle_weight, length_weight, distance_weight); + + if (weight >= MAX_COST) { + continue; + } + + /* add node weight */ + next_node = solveJoints(table, iter, vec_cache, nb_joints, nb_positions, current, next, edge->next, joints_left - 1, angle_weight, length_weight, distance_weight); + weight += next_node->weight; + + if (min_node == NULL || weight < min_weight) { + min_weight = weight; + min_node = next_node; + min_next = next; + } + } + + if (min_node) { + node->weight = min_weight; + node->next = min_next; + return node; + } + else { + node->weight = MAX_COST; + return node; + } + } + +} + +static int testFlipArc(RigArc *iarc, RigNode *inode_start) +{ + ReebArc *earc = iarc->link_mesh; + ReebNode *enode_start = BIF_NodeFromIndex(earc, inode_start->link_mesh); + + /* no flip needed if both nodes are the same */ + if ((enode_start == earc->head && inode_start == iarc->head) || + (enode_start == earc->tail && inode_start == iarc->tail)) + { + return 0; + } + else { + return 1; + } +} + +static void retargetArctoArcAggresive(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) +{ + ReebArcIterator arc_iter; + BArcIterator *iter = (BArcIterator *)&arc_iter; + RigEdge *edge; + ReebNode *node_start, *node_end; + ReebArc *earc = iarc->link_mesh; + float angle_weight = 1.0; // GET FROM CONTEXT + float length_weight = 1.0; + float distance_weight = 1.0; +#ifndef USE_THREADS + float min_cost = FLT_MAX; +#endif + float *vec0, *vec1; + int *best_positions; + int nb_edges = BLI_listbase_count(&iarc->edges); + int nb_joints = nb_edges - 1; + RetargetMethod method = METHOD_MEMOIZE; + int i; + + if (nb_joints > earc->bcount) { + printf("NOT ENOUGH BUCKETS!\n"); + return; + } + + best_positions = MEM_callocN(sizeof(int) * nb_joints, "Best positions"); + + if (testFlipArc(iarc, inode_start)) { + node_start = earc->tail; + node_end = earc->head; + } + else { + node_start = earc->head; + node_end = earc->tail; + } + + /* equal number of joints and potential position, just fill them in */ + if (nb_joints == earc->bcount) { + /* init with first values */ + for (i = 0; i < nb_joints; i++) { + best_positions[i] = i + 1; + } + } + if (method == METHOD_MEMOIZE) { + int nb_positions = earc->bcount; + int nb_memo_nodes = nb_positions * nb_positions * (nb_joints + 1); + MemoNode *table = MEM_callocN(nb_memo_nodes * sizeof(MemoNode), "memoization table"); +#ifndef USE_THREADS + MemoNode *result; +#endif + float **positions_cache = MEM_callocN(sizeof(float *) * (nb_positions + 2), "positions cache"); + + positions_cache[0] = node_start->p; + positions_cache[nb_positions + 1] = node_end->p; + + initArcIterator(iter, earc, node_start); + + for (i = 1; i <= nb_positions; i++) { + EmbedBucket *bucket = IT_peek(iter, i); + positions_cache[i] = bucket->p; + } + +#ifndef USE_THREADS + result = solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight); + min_cost = result->weight; +#else + solveJoints(table, iter, positions_cache, nb_joints, earc->bcount, 0, 0, iarc->edges.first, nb_joints, angle_weight, length_weight, distance_weight); +#endif + + copyMemoPositions(best_positions, table, earc->bcount, nb_joints); + + MEM_freeN(table); + MEM_freeN(positions_cache); + } + + vec0 = node_start->p; + initArcIterator(iter, earc, node_start); + +#ifndef USE_THREADS + printPositions(best_positions, nb_joints); + printMovesNeeded(best_positions, nb_joints); + printf("min_cost %f\n", min_cost); + printf("buckets: %i\n", earc->bcount); +#endif + + /* set joints to best position */ + for (edge = iarc->edges.first, i = 0; + edge; + edge = edge->next, i++) + { + float *no = NULL; + if (i < nb_joints) { + EmbedBucket *bucket = IT_peek(iter, best_positions[i]); + vec1 = bucket->p; + no = bucket->no; + } + else { + vec1 = node_end->p; + no = node_end->no; + } + + if (edge->bone) { + repositionBone(C, rigg, edge, vec0, vec1, no); + } + + vec0 = vec1; + } + + MEM_freeN(best_positions); +} + +static void retargetArctoArcLength(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) +{ + ReebArcIterator arc_iter; + BArcIterator *iter = (BArcIterator *)&arc_iter; + ReebArc *earc = iarc->link_mesh; + ReebNode *node_start, *node_end; + RigEdge *edge; + EmbedBucket *bucket = NULL; + float embedding_length = 0; + float *vec0 = NULL; + float *vec1 = NULL; + float *previous_vec = NULL; + + + if (testFlipArc(iarc, inode_start)) { + node_start = (ReebNode *)earc->tail; + node_end = (ReebNode *)earc->head; + } + else { + node_start = (ReebNode *)earc->head; + node_end = (ReebNode *)earc->tail; + } + + initArcIterator(iter, earc, node_start); + + bucket = IT_next(iter); + + vec0 = node_start->p; + + while (bucket != NULL) { + vec1 = bucket->p; + + embedding_length += len_v3v3(vec0, vec1); + + vec0 = vec1; + bucket = IT_next(iter); + } + + embedding_length += len_v3v3(node_end->p, vec1); + + /* fit bones */ + initArcIterator(iter, earc, node_start); + + bucket = IT_next(iter); + + vec0 = node_start->p; + previous_vec = vec0; + vec1 = bucket->p; + + for (edge = iarc->edges.first; edge; edge = edge->next) { + float new_bone_length = edge->length / iarc->length * embedding_length; + float *no = NULL; + float length = 0; + + while (bucket && new_bone_length > length) { + length += len_v3v3(previous_vec, vec1); + bucket = IT_next(iter); + previous_vec = vec1; + vec1 = bucket->p; + no = bucket->no; + } + + if (bucket == NULL) { + vec1 = node_end->p; + no = node_end->no; + } + + /* no need to move virtual edges (space between unconnected bones) */ + if (edge->bone) { + repositionBone(C, rigg, edge, vec0, vec1, no); + } + + vec0 = vec1; + previous_vec = vec1; + } +} + +static void retargetArctoArc(bContext *C, RigGraph *rigg, RigArc *iarc, RigNode *inode_start) +{ + RetargetParam *p = MEM_callocN(sizeof(RetargetParam), "RetargetParam"); + + p->rigg = rigg; + p->iarc = iarc; + p->inode_start = inode_start; + p->context = C; + + BLI_task_pool_push(rigg->task_pool, exec_retargetArctoArc, p, true, TASK_PRIORITY_HIGH); +} + +void exec_retargetArctoArc(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) +{ + RetargetParam *p = (RetargetParam *)taskdata; + RigGraph *rigg = p->rigg; + RigArc *iarc = p->iarc; + bContext *C = p->context; + RigNode *inode_start = p->inode_start; + ReebArc *earc = iarc->link_mesh; + + if (BLI_listbase_is_single(&iarc->edges)) { + RigEdge *edge = iarc->edges.first; + + if (testFlipArc(iarc, inode_start)) { + repositionBone(C, rigg, edge, earc->tail->p, earc->head->p, earc->head->no); + } + else { + repositionBone(C, rigg, edge, earc->head->p, earc->tail->p, earc->tail->no); + } + } + else { + RetargetMode mode = detectArcRetargetMode(iarc); + + if (mode == RETARGET_AGGRESSIVE) { + retargetArctoArcAggresive(C, rigg, iarc, inode_start); + } + else { + retargetArctoArcLength(C, rigg, iarc, inode_start); + } + } +} + +static void matchMultiResolutionNode(RigGraph *rigg, RigNode *inode, ReebNode *top_node) +{ + ReebNode *enode = top_node; + ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); + int ishape, eshape; + + ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS; + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; + + inode->link_mesh = enode; + + while (ishape == eshape && enode->link_down) { + inode->link_mesh = enode; + + enode = enode->link_down; + reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); /* replace with call to link_down once that exists */ + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; + } +} + +static void markMultiResolutionChildArc(ReebNode *end_enode, ReebNode *enode) +{ + int i; + + for (i = 0; i < enode->degree; i++) { + ReebArc *earc = (ReebArc *)enode->arcs[i]; + + if (earc->flag == ARC_FREE) { + earc->flag = ARC_TAKEN; + + if (earc->tail->degree > 1 && earc->tail != end_enode) { + markMultiResolutionChildArc(end_enode, earc->tail); + } + break; + } + } +} + +static void markMultiResolutionArc(ReebArc *start_earc) +{ + if (start_earc->link_up) { + ReebArc *earc; + for (earc = start_earc->link_up; earc; earc = earc->link_up) { + earc->flag = ARC_TAKEN; + + if (earc->tail->index != start_earc->tail->index) { + markMultiResolutionChildArc(earc->tail, earc->tail); + } + } + } +} + +static void matchMultiResolutionArc(RigGraph *rigg, RigNode *start_node, RigArc *next_iarc, ReebArc *next_earc) +{ + ReebNode *enode = next_earc->head; + ReebGraph *reebg = BIF_graphForMultiNode(rigg->link_mesh, enode); + int ishape, eshape; + + ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)start_node, (BArc *)next_iarc, 1) % SHAPE_LEVELS; + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS; + + while (ishape != eshape && next_earc->link_up) { + next_earc->flag = ARC_TAKEN; // mark previous as taken, to prevent backtrack on lower levels + + next_earc = next_earc->link_up; + reebg = reebg->link_up; + enode = next_earc->head; + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, (BArc *)next_earc, 1) % SHAPE_LEVELS; + } + + next_earc->flag = ARC_USED; + next_iarc->link_mesh = next_earc; + + /* mark all higher levels as taken too */ + markMultiResolutionArc(next_earc); +// while (next_earc->link_up) +// { +// next_earc = next_earc->link_up; +// next_earc->flag = ARC_TAKEN; +// } +} + +static void matchMultiResolutionStartingNode(RigGraph *rigg, ReebGraph *reebg, RigNode *inode) +{ + ReebNode *enode; + int ishape, eshape; + + enode = reebg->nodes.first; + + ishape = BLI_subtreeShape((BGraph *)rigg, (BNode *)inode, NULL, 0) % SHAPE_LEVELS; + eshape = BLI_subtreeShape((BGraph *)rigg->link_mesh, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; + + while (ishape != eshape && reebg->link_up) { + reebg = reebg->link_up; + + enode = reebg->nodes.first; + + eshape = BLI_subtreeShape((BGraph *)reebg, (BNode *)enode, NULL, 0) % SHAPE_LEVELS; + } + + inode->link_mesh = enode; +} + +static void findCorrespondingArc(RigGraph *rigg, RigArc *start_arc, RigNode *start_node, RigArc *next_iarc, int root) +{ + ReebNode *enode = start_node->link_mesh; + ReebArc *next_earc; + int symmetry_level = next_iarc->symmetry_level; + int symmetry_group = next_iarc->symmetry_group; + int symmetry_flag = next_iarc->symmetry_flag; + int i; + + next_iarc->link_mesh = NULL; + +// if (root) +// { +// printf("-----------------------\n"); +// printf("MATCHING LIMB\n"); +// RIG_printArcBones(next_iarc); +// } + + for (i = 0; i < enode->degree; i++) { + next_earc = (ReebArc *)enode->arcs[i]; + +// if (next_earc->flag == ARC_FREE) +// { +// printf("candidate (level %i ?= %i) (flag %i ?= %i) (group %i ?= %i)\n", +// symmetry_level, next_earc->symmetry_level, +// symmetry_flag, next_earc->symmetry_flag, +// symmetry_group, next_earc->symmetry_flag); +// } + + if (next_earc->flag == ARC_FREE && + next_earc->symmetry_flag == symmetry_flag && + next_earc->symmetry_group == symmetry_group && + next_earc->symmetry_level == symmetry_level) + { +// printf("CORRESPONDING ARC FOUND\n"); +// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); + + matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); + break; + } + } + + /* not found, try at higher nodes (lower node might have filtered internal arcs, messing shape of tree */ + if (next_iarc->link_mesh == NULL) { +// printf("NO CORRESPONDING ARC FOUND - GOING TO HIGHER LEVELS\n"); + + if (enode->link_up) { + start_node->link_mesh = enode->link_up; + findCorrespondingArc(rigg, start_arc, start_node, next_iarc, 0); + } + } + + /* still not found, print debug info */ + if (root && next_iarc->link_mesh == NULL) { + start_node->link_mesh = enode; /* linking back with root node */ + +// printf("NO CORRESPONDING ARC FOUND\n"); +// RIG_printArcBones(next_iarc); +// +// printf("ON NODE %i, multilevel %i\n", enode->index, enode->multi_level); +// +// printf("LOOKING FOR\n"); +// printf("flag %i -- level %i -- flag %i -- group %i\n", ARC_FREE, symmetry_level, symmetry_flag, symmetry_group); +// +// printf("CANDIDATES\n"); +// for (i = 0; i < enode->degree; i++) +// { +// next_earc = (ReebArc *)enode->arcs[i]; +// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); +// } + + /* Emergency matching */ + for (i = 0; i < enode->degree; i++) { + next_earc = (ReebArc *)enode->arcs[i]; + + if (next_earc->flag == ARC_FREE && next_earc->symmetry_level == symmetry_level) { +// printf("USING:\n"); +// printf("flag %i -- level %i -- flag %i -- group %i\n", next_earc->flag, next_earc->symmetry_level, next_earc->symmetry_flag, next_earc->symmetry_group); + matchMultiResolutionArc(rigg, start_node, next_iarc, next_earc); + break; + } + } + } + +} + +static void retargetSubgraph(bContext *C, RigGraph *rigg, RigArc *start_arc, RigNode *start_node) +{ + RigNode *inode = start_node; + int i; + + /* no start arc on first node */ + if (start_arc) { + ReebNode *enode = start_node->link_mesh; + ReebArc *earc = start_arc->link_mesh; + + retargetArctoArc(C, rigg, start_arc, start_node); + + enode = BIF_otherNodeFromIndex(earc, enode); + inode = (RigNode *)BLI_otherNode((BArc *)start_arc, (BNode *)inode); + + /* match with lowest node with correct shape */ + matchMultiResolutionNode(rigg, inode, enode); + } + + for (i = 0; i < inode->degree; i++) { + RigArc *next_iarc = (RigArc *)inode->arcs[i]; + + /* no back tracking */ + if (next_iarc != start_arc) { + findCorrespondingArc(rigg, start_arc, inode, next_iarc, 1); + if (next_iarc->link_mesh) { + retargetSubgraph(C, rigg, next_iarc, inode); + } + } + } +} + +static void finishRetarget(RigGraph *rigg) +{ + BLI_task_pool_work_and_wait(rigg->task_pool); +} + +static void adjustGraphs(bContext *C, RigGraph *rigg) +{ + Main *bmain = CTX_data_main(C); + bArmature *arm = rigg->ob->data; + RigArc *arc; + + for (arc = rigg->arcs.first; arc; arc = arc->next) { + if (arc->link_mesh) { + retargetArctoArc(C, rigg, arc, arc->head); + } + } + + finishRetarget(rigg); + + /* Turn the list into an armature */ + arm->edbo = rigg->editbones; + ED_armature_from_edit(bmain, arm); + + ED_undo_push(C, "Retarget Skeleton"); +} + +static void retargetGraphs(bContext *C, RigGraph *rigg) +{ + Main *bmain = CTX_data_main(C); + bArmature *arm = rigg->ob->data; + ReebGraph *reebg = rigg->link_mesh; + RigNode *inode; + + /* flag all ReebArcs as free */ + BIF_flagMultiArcs(reebg, ARC_FREE); + + /* return to first level */ + inode = rigg->head; + + matchMultiResolutionStartingNode(rigg, reebg, inode); + + retargetSubgraph(C, rigg, NULL, inode); + + //generateMissingArcs(rigg); + + finishRetarget(rigg); + + /* Turn the list into an armature */ + arm->edbo = rigg->editbones; + ED_armature_from_edit(bmain, arm); +} + +const char *RIG_nameBone(RigGraph *rg, int arc_index, int bone_index) +{ + RigArc *arc = BLI_findlink(&rg->arcs, arc_index); + RigEdge *iedge; + + if (arc == NULL) { + return "None"; + } + + if (bone_index == BLI_listbase_count(&arc->edges)) { + return "Last joint"; + } + + iedge = BLI_findlink(&arc->edges, bone_index); + + if (iedge == NULL) { + return "Done"; + } + + if (iedge->bone == NULL) { + return "Bone offset"; + } + + return iedge->bone->name; +} + +int RIG_nbJoints(RigGraph *rg) +{ + RigArc *arc; + int total = 0; + + total += BLI_listbase_count(&rg->nodes); + + for (arc = rg->arcs.first; arc; arc = arc->next) { + total += BLI_listbase_count(&arc->edges) - 1; /* -1 because end nodes are already counted */ + } + + return total; +} + +static void BIF_freeRetarget(void) +{ + if (GLOBAL_RIGG) { + RIG_freeRigGraph((BGraph *)GLOBAL_RIGG); + GLOBAL_RIGG = NULL; + } +} + +void BIF_retargetArmature(bContext *C) +{ + ReebGraph *reebg; + double start_time, end_time; + double gstart_time, gend_time; + double reeb_time, rig_time = 0.0, retarget_time = 0.0, total_time; + + gstart_time = start_time = PIL_check_seconds_timer(); + + reebg = BIF_ReebGraphMultiFromEditMesh(C); + + end_time = PIL_check_seconds_timer(); + reeb_time = end_time - start_time; + + printf("Reeb Graph created\n"); + + CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases) + { + Object *ob = base->object; + + if (ob->type == OB_ARMATURE) { + RigGraph *rigg; + bArmature *arm; + + arm = ob->data; + + /* Put the armature into editmode */ + + + start_time = PIL_check_seconds_timer(); + + rigg = RIG_graphFromArmature(C, ob, arm); + + end_time = PIL_check_seconds_timer(); + rig_time = end_time - start_time; + + printf("Armature graph created\n"); + + //RIG_printGraph(rigg); + + rigg->link_mesh = reebg; + + printf("retargetting %s\n", ob->id.name); + + start_time = PIL_check_seconds_timer(); + + retargetGraphs(C, rigg); + + end_time = PIL_check_seconds_timer(); + retarget_time = end_time - start_time; + + BIF_freeRetarget(); + + GLOBAL_RIGG = rigg; + + break; /* only one armature at a time */ + } + } + CTX_DATA_END; + + + gend_time = PIL_check_seconds_timer(); + + total_time = gend_time - gstart_time; + + printf("-----------\n"); + printf("runtime: \t%.3f\n", total_time); + printf("reeb: \t\t%.3f (%.1f%%)\n", reeb_time, reeb_time / total_time * 100); + printf("rig: \t\t%.3f (%.1f%%)\n", rig_time, rig_time / total_time * 100); + printf("retarget: \t%.3f (%.1f%%)\n", retarget_time, retarget_time / total_time * 100); + printf("-----------\n"); + + ED_undo_push(C, "Retarget Skeleton"); + + // XXX +// allqueue(REDRAWVIEW3D, 0); +} + +void BIF_retargetArc(bContext *C, ReebArc *earc, RigGraph *template_rigg) +{ + Object *obedit = CTX_data_edit_object(C); + Scene *scene = CTX_data_scene(C); + bArmature *armedit = obedit->data; + Object *ob; + RigGraph *rigg; + RigArc *iarc; + char *side_string = scene->toolsettings->skgen_side_string; + char *num_string = scene->toolsettings->skgen_num_string; + int free_template = 0; + + if (template_rigg) { + ob = template_rigg->ob; + } + else { + free_template = 1; + ob = obedit; + template_rigg = armatureSelectedToGraph(C, ob, ob->data); + } + + if (BLI_listbase_is_empty(&template_rigg->arcs)) { +// XXX +// error("No Template and no deforming bones selected"); + return; + } + + rigg = cloneRigGraph(template_rigg, armedit->edbo, obedit, side_string, num_string); + + iarc = rigg->arcs.first; + + iarc->link_mesh = earc; + iarc->head->link_mesh = earc->head; + iarc->tail->link_mesh = earc->tail; + + retargetArctoArc(C, rigg, iarc, iarc->head); + + finishRetarget(rigg); + + /* free template if it comes from the edit armature */ + if (free_template) { + RIG_freeRigGraph((BGraph *)template_rigg); + } + RIG_freeRigGraph((BGraph *)rigg); + + ED_armature_edit_validate_active(armedit); + +// XXX +// allqueue(REDRAWVIEW3D, 0); +} + +void BIF_adjustRetarget(bContext *C) +{ + if (GLOBAL_RIGG) { + adjustGraphs(C, GLOBAL_RIGG); + } +} diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index de0612d840d..22c710dcda5 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -97,6 +97,7 @@ static void applyarmature_fix_boneparents(const bContext *C, Scene *scene, Objec /* set the current pose as the restpose */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Depsgraph *depsgraph = CTX_data_depsgraph(C); Scene *scene = CTX_data_scene(C); Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object @@ -195,7 +196,7 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) } /* convert editbones back to bones, and then free the edit-data */ - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); /* flush positions of posebones */ diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index ab6586d2ab6..b6007ca5e18 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1105,7 +1105,7 @@ static int *initialize_index_map(Object *obedit, int *r_old_totvert) return old_to_new_map; } -static void remap_hooks_and_vertex_parents(Object *obedit) +static void remap_hooks_and_vertex_parents(Main *bmain, Object *obedit) { Object *object; Curve *curve = (Curve *) obedit->data; @@ -1121,7 +1121,7 @@ static void remap_hooks_and_vertex_parents(Object *obedit) return; } - for (object = G.main->object.first; object; object = object->id.next) { + for (object = bmain->object.first; object; object = object->id.next) { ModifierData *md; int index; if ((object->parent) && @@ -1184,7 +1184,7 @@ static void remap_hooks_and_vertex_parents(Object *obedit) } /* load editNurb in object */ -void ED_curve_editnurb_load(Object *obedit) +void ED_curve_editnurb_load(Main *bmain, Object *obedit) { ListBase *editnurb = object_editcurve_get(obedit); @@ -1195,7 +1195,7 @@ void ED_curve_editnurb_load(Object *obedit) Nurb *nu, *newnu; ListBase newnurb = {NULL, NULL}, oldnurb = cu->nurb; - remap_hooks_and_vertex_parents(obedit); + remap_hooks_and_vertex_parents(bmain, obedit); for (nu = editnurb->first; nu; nu = nu->next) { newnu = BKE_nurb_duplicate(nu); @@ -1325,7 +1325,7 @@ static int separate_exec(bContext *C, wmOperator *op) BLI_movelisttolist(&newedit->nurbs, &newnurb); /* 4. put old object out of editmode and delete separated geometry */ - ED_curve_editnurb_load(newob); + ED_curve_editnurb_load(bmain, newob); ED_curve_editnurb_free(newob); curve_delete_segments(oldob, true); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 60374f87955..c075c89dbb2 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -42,6 +42,7 @@ struct bPoseChannel; struct Depsgraph; struct IDProperty; struct ListBase; +struct Main; struct MeshDeformModifierData; struct Mesh; struct Object; @@ -135,7 +136,7 @@ void ED_operatormacros_armature(void); void ED_keymap_armature(struct wmKeyConfig *keyconf); /* editarmature.c */ -void ED_armature_from_edit(struct bArmature *arm); +void ED_armature_from_edit(struct Main *bmain, struct bArmature *arm); void ED_armature_to_edit(struct bArmature *arm); void ED_armature_edit_free(struct bArmature *arm); @@ -181,11 +182,11 @@ void ED_armature_ebone_from_mat3(EditBone *ebone, float mat[3][3]); void ED_armature_ebone_from_mat4(EditBone *ebone, float mat[4][4]); void ED_armature_edit_transform_mirror_update(struct Object *obedit); -void ED_armature_origin_set(struct Object *ob, float cursor[3], int centermode, int around); +void ED_armature_origin_set(struct Main *bmain, struct Object *ob, float cursor[3], int centermode, int around); void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4], const bool do_props); -void ED_armature_transform_apply(struct Object *ob, float mat[4][4], const bool do_props); -void ED_armature_transform(struct bArmature *arm, float mat[4][4], const bool do_props); +void ED_armature_transform_apply(struct Main *bmain, struct Object *ob, float mat[4][4], const bool do_props); +void ED_armature_transform(struct Main *bmain, struct bArmature *arm, float mat[4][4], const bool do_props); #define ARM_GROUPS_NAME 1 #define ARM_GROUPS_ENVELOPE 2 diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 74c8334322f..8fcfb4743d5 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -32,15 +32,16 @@ #define __ED_CURVE_H__ struct bContext; +struct BezTriple; +struct BPoint; +struct Curve; +struct EditNurb; +struct Main; struct Nurb; struct Object; struct Text; struct wmOperator; struct wmKeyConfig; -struct Curve; -struct EditNurb; -struct BezTriple; -struct BPoint; struct UndoType; /* curve_ops.c */ @@ -51,7 +52,7 @@ void ED_keymap_curve(struct wmKeyConfig *keyconf); /* editcurve.c */ struct ListBase *object_editcurve_get(struct Object *ob); -void ED_curve_editnurb_load(struct Object *obedit); +void ED_curve_editnurb_load(struct Main *bmain, struct Object *obedit); void ED_curve_editnurb_make(struct Object *obedit); void ED_curve_editnurb_free(struct Object *obedit); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index c793c0aad2b..3ffab756319 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -126,7 +126,7 @@ enum { EM_NO_CONTEXT = (1 << 4), }; bool ED_object_editmode_exit_ex( - struct Scene *scene, struct Object *obedit, int flag); + struct Main *bmain, struct Scene *scene, struct Object *obedit, int flag); bool ED_object_editmode_exit(struct bContext *C, int flag); bool ED_object_editmode_enter_ex(struct Main *bmain, struct Scene *scene, struct Object *ob, int flag); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 63485800a9b..f10e1039cd4 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -160,7 +160,7 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area); vert_name = (vert_name == (win)->global_areas.vertbase.last) ? (screen)->vertbase.first : vert_name->next) /* screens */ -void ED_screens_initialize(struct wmWindowManager *wm); +void ED_screens_initialize(struct Main *bmain, struct wmWindowManager *wm); void ED_screen_draw_edges(struct wmWindow *win); void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2); void ED_screen_draw_split_preview(struct ScrArea *sa, const int dir, const float fac); diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index c847974fc71..aca380c3123 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -205,9 +205,11 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op) if (export_settings.include_armatures) includeFilter |= OB_REL_MOD_ARMATURE; if (export_settings.include_children) includeFilter |= OB_REL_CHILDREN_RECURSIVE; - export_count = collada_export(CTX_data_depsgraph(C), - scene, - &export_settings + export_count = collada_export( + C, + CTX_data_depsgraph(C), + scene, + &export_settings ); if (export_count == 0) { diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 121a30c754a..3f43f3c0407 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -152,7 +152,7 @@ bConstraint *get_active_constraint(Object *ob) /* ------------- PyConstraints ------------------ */ /* this callback sets the text-file to be used for selected menu item */ -static void validate_pyconstraint_cb(void *arg1, void *arg2) +static void validate_pyconstraint_cb(Main *bmain, void *arg1, void *arg2) { bPythonConstraint *data = arg1; Text *text = NULL; @@ -162,13 +162,13 @@ static void validate_pyconstraint_cb(void *arg1, void *arg2) /* exception for no script */ if (index) { /* innovative use of a for...loop to search */ - for (text = G.main->text.first, i = 1; text && index != i; i++, text = text->id.next) ; + for (text = bmain->text.first, i = 1; text && index != i; i++, text = text->id.next) ; } data->text = text; } /* this returns a string for the list of usable pyconstraint script names */ -static char *buildmenu_pyconstraints(Text *con_text, int *pyconindex) +static char *buildmenu_pyconstraints(Main *bmain, Text *con_text, int *pyconindex) { DynStr *pupds = BLI_dynstr_new(); Text *text; @@ -185,7 +185,7 @@ static char *buildmenu_pyconstraints(Text *con_text, int *pyconindex) *pyconindex = 0; /* loop through markers, adding them */ - for (text = G.main->text.first, i = 1; text; i++, text = text->id.next) { + for (text = bmain->text.first, i = 1; text; i++, text = text->id.next) { /* this is important to ensure that right script is shown as active */ if (text == con_text) *pyconindex = i; @@ -1798,14 +1798,14 @@ static int constraint_add_exec(bContext *C, wmOperator *op, Object *ob, ListBase char *menustr; int scriptint = 0; /* popup a list of usable scripts */ - menustr = buildmenu_pyconstraints(NULL, &scriptint); + menustr = buildmenu_pyconstraints(bmain, NULL, &scriptint); /* XXX scriptint = pupmenu(menustr); */ MEM_freeN(menustr); /* only add constraint if a script was chosen */ if (scriptint) { /* add constraint */ - validate_pyconstraint_cb(con->data, &scriptint); + validate_pyconstraint_cb(bmain, con->data, &scriptint); /* make sure target allowance is set correctly */ BPY_pyconstraint_update(ob, con); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 9bc01892ef0..d47a2576a8a 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -209,7 +209,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f if (arm->edbo == NULL) { return false; } - ED_armature_from_edit(obedit->data); + ED_armature_from_edit(bmain, obedit->data); if (freedata) { ED_armature_edit_free(obedit->data); } @@ -224,7 +224,7 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f if (cu->editnurb == NULL) { return false; } - ED_curve_editnurb_load(obedit); + ED_curve_editnurb_load(bmain, obedit); if (freedata) { ED_curve_editnurb_free(obedit); } @@ -272,13 +272,13 @@ bool ED_object_editmode_load(Main *bmain, Object *obedit) * \param flag: * - If #EM_FREEDATA isn't in the flag, use ED_object_editmode_load directly. */ -bool ED_object_editmode_exit_ex(Scene *scene, Object *obedit, int flag) +bool ED_object_editmode_exit_ex(Main *bmain, Scene *scene, Object *obedit, int flag) { const bool freedata = (flag & EM_FREEDATA) != 0; if (flag & EM_WAITCURSOR) waitcursor(1); - if (ED_object_editmode_load_ex(G.main, obedit, freedata) == false) { + if (ED_object_editmode_load_ex(bmain, obedit, freedata) == false) { /* in rare cases (background mode) its possible active object * is flagged for editmode, without 'obedit' being set [#35489] */ if (UNLIKELY(obedit && obedit->mode & OB_MODE_EDIT)) { @@ -318,9 +318,10 @@ bool ED_object_editmode_exit_ex(Scene *scene, Object *obedit, int flag) bool ED_object_editmode_exit(bContext *C, int flag) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); - return ED_object_editmode_exit_ex(scene, obedit, flag); + return ED_object_editmode_exit_ex(bmain, scene, obedit, flag); } bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag) @@ -465,7 +466,7 @@ static int editmode_toggle_exec(bContext *C, wmOperator *op) FOREACH_OBJECT_BEGIN(view_layer, ob) { if ((ob != obact) && (ob->type == obact->type)) { - ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA | EM_WAITCURSOR); + ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA | EM_WAITCURSOR); } } FOREACH_OBJECT_END; diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 7687bd476b9..31e8685e323 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -304,7 +304,7 @@ static int return_editcurve_indexar( return totvert; } -static bool object_hook_index_array(Scene *scene, Object *obedit, +static bool object_hook_index_array(Main *bmain, Scene *scene, Object *obedit, int *r_tot, int **r_indexar, char *r_name, float r_cent[3]) { *r_indexar = NULL; @@ -336,7 +336,7 @@ static bool object_hook_index_array(Scene *scene, Object *obedit, } case OB_CURVE: case OB_SURF: - ED_curve_editnurb_load(obedit); + ED_curve_editnurb_load(bmain, obedit); ED_curve_editnurb_make(obedit); return return_editcurve_indexar(obedit, r_tot, r_indexar, r_cent); case OB_LATTICE: @@ -476,7 +476,7 @@ static int add_hook_object(const bContext *C, Main *bmain, Scene *scene, ViewLay int tot, ok, *indexar; char name[MAX_NAME]; - ok = object_hook_index_array(scene, obedit, &tot, &indexar, name, cent); + ok = object_hook_index_array(bmain, scene, obedit, &tot, &indexar, name, cent); if (!ok) { BKE_report(reports, RPT_ERROR, "Requires selected vertices or active vertex group"); @@ -814,6 +814,7 @@ void OBJECT_OT_hook_recenter(wmOperatorType *ot) static int object_hook_assign_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); int num = RNA_enum_get(op->ptr, "modifier"); @@ -831,7 +832,7 @@ static int object_hook_assign_exec(bContext *C, wmOperator *op) /* assign functionality */ - if (!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) { + if (!object_hook_index_array(bmain, scene, ob, &tot, &indexar, name, cent)) { BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c index 66c2ad5fa9b..e9bd6fbce8f 100644 --- a/source/blender/editors/object/object_modes.c +++ b/source/blender/editors/object/object_modes.c @@ -209,7 +209,7 @@ static bool ed_object_mode_generic_exit_ex( if (only_test) { return true; } - ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA); + ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); } } else if (ob->mode & OB_MODE_VERTEX_PAINT) { diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index dbe2d21a487..1b9af3725ca 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -1782,7 +1782,7 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, MEM_freeN(emap); MEM_freeN(emap_mem); - ED_armature_from_edit(arm); + ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); return arm_ob; diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index cb609b2567b..721d248ae4c 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -553,7 +553,7 @@ static int apply_objects_internal( BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { - ED_armature_transform_apply(ob, mat, do_props); + ED_armature_transform_apply(bmain, ob, mat, do_props); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; @@ -1006,7 +1006,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) /* Function to recenter armatures in editarmature.c * Bone + object locations are handled there. */ - ED_armature_origin_set(ob, cursor, centermode, around); + ED_armature_origin_set(bmain, ob, cursor, centermode, around); tot_change++; arm->id.tag |= LIB_TAG_DOIT; diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 06735eb8689..2aa48a15291 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -340,12 +340,12 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) /** * Empty screen, with 1 dummy area without spacedata. Uses window size. */ -bScreen *screen_add(const char *name, const rcti *rect) +bScreen *screen_add(Main *bmain, const char *name, const rcti *rect) { bScreen *sc; ScrVert *sv1, *sv2, *sv3, *sv4; - sc = BKE_libblock_alloc(G.main, ID_SCR, name, 0); + sc = BKE_libblock_alloc(bmain, ID_SCR, name, 0); sc->do_refresh = true; sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN; @@ -832,7 +832,7 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win) } /* file read, set all screens, ... */ -void ED_screens_initialize(wmWindowManager *wm) +void ED_screens_initialize(Main *UNUSED(bmain), wmWindowManager *wm) { wmWindow *win; diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index adfd7b185ab..b02198764e0 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -48,7 +48,7 @@ void screen_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade); /* screen_edit.c */ -bScreen *screen_add(const char *name, const rcti *rect); +bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect); void screen_data_copy(bScreen *to, bScreen *from); void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new); void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc); diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c index 6285f031836..4cb88b7f9a0 100644 --- a/source/blender/editors/screen/workspace_layout_edit.c +++ b/source/blender/editors/screen/workspace_layout_edit.c @@ -54,7 +54,7 @@ WorkSpaceLayout *ED_workspace_layout_add( rcti screen_rect; WM_window_screen_rect_calc(win, &screen_rect); - screen = screen_add(name, &screen_rect); + screen = screen_add(G.main, name, &screen_rect); return BKE_workspace_layout_add(workspace, screen, name); } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 0dd0aca48c6..8123bed541c 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2313,7 +2313,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const #if 0 /* Kept for reference here, in case we want to add back that feature later. We do not need it currently. */ /* Code ***NOT*** updated for job stuff! */ -static void filelist_readjob_main_rec(struct FileList *filelist) +static void filelist_readjob_main_rec(Main *bmain, FileList *filelist) { ID *id; FileDirEntry *files, *firstlib = NULL; @@ -2375,7 +2375,7 @@ static void filelist_readjob_main_rec(struct FileList *filelist) /* make files */ idcode = groupname_to_code(filelist->filelist.root); - lb = which_libbase(G.main, idcode); + lb = which_libbase(bmain, idcode); if (lb == NULL) return; filelist->filelist.nbr_entries = 0; diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 441765528d1..af1b11b28d2 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -47,6 +47,7 @@ #include "BKE_collection.h" #include "BKE_context.h" #include "BKE_layer.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_scene.h" #include "BKE_sequencer.h" @@ -74,6 +75,7 @@ static void do_outliner_activate_obdata(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base) { + Main *bmain = CTX_data_main(C); Object *obact = OBACT(view_layer); bool use_all = false; @@ -95,7 +97,7 @@ static void do_outliner_activate_obdata(bContext *C, Scene *scene, ViewLayer *vi if (ob->type == obact->type) { bool ok; if (BKE_object_is_in_editmode(ob)) { - ok = ED_object_editmode_exit_ex(scene, ob, EM_FREEDATA | EM_WAITCURSOR); + ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA | EM_WAITCURSOR); } else { ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_WAITCURSOR | EM_NO_CONTEXT); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 30c643388af..27e88dc1ee0 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -504,9 +504,9 @@ static int rna_Armature_is_editmode_get(PointerRNA *ptr) return (arm->edbo != NULL); } -static void rna_Armature_transform(struct bArmature *arm, float *mat) +static void rna_Armature_transform(struct bArmature *arm, Main *bmain, float *mat) { - ED_armature_transform(arm, (float (*)[4])mat, true); + ED_armature_transform(bmain, arm, (float (*)[4])mat, true); } #else @@ -1034,6 +1034,7 @@ static void rna_def_armature(BlenderRNA *brna) RNA_def_struct_sdna(srna, "bArmature"); func = RNA_def_function(srna, "transform", "rna_Armature_transform"); + RNA_def_function_flag(func, FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Transform armature bones by a matrix"); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index a6653c680e0..9214f8530b8 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -300,7 +300,7 @@ static void rna_Object_active_shape_update(bContext *C, PointerRNA *ptr) break; case OB_CURVE: case OB_SURF: - ED_curve_editnurb_load(ob); + ED_curve_editnurb_load(bmain, ob); ED_curve_editnurb_make(ob); break; case OB_LATTICE: diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index b6a12acd57d..9100e47d820 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -394,6 +394,7 @@ void WM_keymap_init(bContext *C) void WM_check(bContext *C) { + Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); /* wm context */ @@ -424,7 +425,7 @@ void WM_check(bContext *C) /* case: fileread */ /* note: this runs in bg mode to set the screen context cb */ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) { - ED_screens_initialize(wm); + ED_screens_initialize(bmain, wm); wm->initialized |= WM_WINDOW_IS_INITIALIZED; } } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 088aca05268..315a3d715ea 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -572,7 +572,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* we didn't succeed, now try to read Blender file */ if (retval == BKE_READ_EXOTIC_OK_BLEND) { - Main *bmain = CTX_data_main(C); int G_f = G.f; ListBase wmbase; @@ -583,6 +582,10 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* confusing this global... */ G.relbase_valid = 1; retval = BKE_blendfile_read(C, filepath, reports, 0); + + /* BKE_file_read sets new Main into context. */ + Main *bmain = CTX_data_main(C); + /* when loading startup.blend's, we can be left with a blank path */ if (BKE_main_blendfile_path(bmain)) { G.save_over = 1; @@ -600,12 +603,12 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } /* match the read WM with current WM */ - wm_window_match_do(C, &wmbase, &G.main->wm, &G.main->wm); + wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); WM_check(C); /* opens window(s), checks keymaps */ if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) { /* in case a userdef is read from regular .blend */ - wm_init_userdef(G.main, false); + wm_init_userdef(bmain, false); } if (retval != BKE_BLENDFILE_READ_FAIL) {