Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2018-06-06 17:25:28 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2018-06-06 17:25:28 +0300
commitbb7202495a289370fe39a9aaeebf8d21fa7d357c (patch)
treea7fd7b43a423ee3bc5fd106bba9a98a52de76262
parent19d651ca9a694f556c76a09c2822b81ae1dc18a5 (diff)
parent48e871ab1d57ef2e95047b2be5718cee5d3cefe6 (diff)
Merge branch 'master' into blender2.8
Conflicts: source/blender/collada/ArmatureExporter.cpp source/blender/collada/ArmatureExporter.h source/blender/collada/DocumentExporter.cpp source/blender/collada/DocumentExporter.h source/blender/collada/SceneExporter.cpp source/blender/collada/SceneExporter.h source/blender/collada/collada.cpp source/blender/collada/collada.h source/blender/editors/armature/armature_edit.c source/blender/editors/armature/editarmature_retarget.c source/blender/editors/armature/pose_transform.c source/blender/editors/include/ED_armature.h source/blender/editors/include/ED_object.h source/blender/editors/include/ED_screen.h source/blender/editors/io/io_collada.c source/blender/editors/object/object_transform.c source/blender/editors/screen/screen_edit.c source/blender/editors/screen/screen_ops.c source/blender/windowmanager/intern/wm.c source/blender/windowmanager/intern/wm_files.c source/blender/windowmanager/intern/wm_window.c source/blenderplayer/bad_level_call_stubs/stubs.c
-rw-r--r--source/blender/collada/ArmatureExporter.cpp15
-rw-r--r--source/blender/collada/ArmatureExporter.h4
-rw-r--r--source/blender/collada/ArmatureImporter.cpp19
-rw-r--r--source/blender/collada/ArmatureImporter.h4
-rw-r--r--source/blender/collada/DocumentExporter.cpp4
-rw-r--r--source/blender/collada/DocumentExporter.h2
-rw-r--r--source/blender/collada/SceneExporter.cpp16
-rw-r--r--source/blender/collada/SceneExporter.h6
-rw-r--r--source/blender/collada/collada.cpp5
-rw-r--r--source/blender/collada/collada.h3
-rw-r--r--source/blender/editors/armature/armature_edit.c13
-rw-r--r--source/blender/editors/armature/armature_relations.c12
-rw-r--r--source/blender/editors/armature/armature_utils.c4
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c2644
-rw-r--r--source/blender/editors/armature/pose_transform.c3
-rw-r--r--source/blender/editors/curve/editcurve.c10
-rw-r--r--source/blender/editors/include/ED_armature.h9
-rw-r--r--source/blender/editors/include/ED_curve.h11
-rw-r--r--source/blender/editors/include/ED_object.h2
-rw-r--r--source/blender/editors/include/ED_screen.h2
-rw-r--r--source/blender/editors/io/io_collada.c8
-rw-r--r--source/blender/editors/object/object_constraint.c12
-rw-r--r--source/blender/editors/object/object_edit.c13
-rw-r--r--source/blender/editors/object/object_hook.c9
-rw-r--r--source/blender/editors/object/object_modes.c2
-rw-r--r--source/blender/editors/object/object_modifier.c2
-rw-r--r--source/blender/editors/object/object_transform.c4
-rw-r--r--source/blender/editors/screen/screen_edit.c6
-rw-r--r--source/blender/editors/screen/screen_intern.h2
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c2
-rw-r--r--source/blender/editors/space_file/filelist.c4
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c4
-rw-r--r--source/blender/makesrna/intern/rna_armature.c5
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/windowmanager/intern/wm.c3
-rw-r--r--source/blender/windowmanager/intern/wm_files.c9
36 files changed, 2769 insertions, 106 deletions
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<Object *>& 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<O
#endif
// parent_mat is armature-space
-void ArmatureExporter::add_bone_node(Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce,
+void ArmatureExporter::add_bone_node(bContext *C, Depsgraph *depsgraph, Bone *bone, Object *ob_arm, Scene *sce,
SceneExporter *se,
std::list<Object *>& 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<Object *>& 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<Object *>& 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<Object *> &ob_arms)
+void ArmatureImporter::create_armature_bones(Main *bmain, std::vector<Object *> &ob_arms)
{
std::vector<COLLADAFW::Node *>::iterator ri;
std::vector<std::string> layer_labels;
@@ -481,7 +481,7 @@ void ArmatureImporter::create_armature_bones(std::vector<Object *> &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<Object *> &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<Object *> &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<Object *> &objects_to_scale)
{
+ Main *bmain = CTX_data_main(C);
std::vector<Object *> ob_arms;
std::map<COLLADAFW::UniqueId, SkinInfo>::iterator it;
@@ -718,7 +719,7 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &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 *> &object
}
//for bones without skins
- create_armature_bones(ob_arms);
+ create_armature_bones(bmain, ob_arms);
// Fix bone relations
std::vector<Object *>::iterator ob_arm_it;
@@ -773,7 +774,7 @@ void ArmatureImporter::make_armatures(bContext *C, std::vector<Object *> &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<Object *> &arm_objs);
+ Object *create_armature_bones(Main *bmain, SkinInfo& skin);
+ void create_armature_bones(Main *bmain, std::vector<Object *> &arm_objs);
/** TagsMap typedef for uid_tags_map. */
typedef std::map<std::string, ExtraTags*> 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);
// <scene>
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)
{
// <library_visual_scenes> <visual_scene>
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<Object *> 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)
// <instance_controller>
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);
}
// <instance_camera>
@@ -234,7 +234,7 @@ void SceneExporter::writeNodes(Depsgraph *depsgraph, Object *ob, Scene *sce)
for (std::list<Object *>::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) {