| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  | # ##### 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, | 
					
						
							| 
									
										
										
										
											2010-02-12 13:34:04 +00:00
										 |  |  | #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # ##### END GPL LICENSE BLOCK ##### | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | # <pep8 compliant> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-02 10:32:39 +00:00
										 |  |  | import bpy | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  | header = '''
 | 
					
						
							|  |  |  | digraph ancestors           { | 
					
						
							|  |  |  | graph [fontsize=30 labelloc="t" label="" splines=false overlap=true, rankdir=BT]; | 
					
						
							|  |  |  | ratio = "auto" ; | 
					
						
							|  |  |  | '''
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | footer = '''
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | '''
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-02 02:56:22 +00:00
										 |  |  | def compat_str(text, line_length=0): | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if line_length: | 
					
						
							|  |  |  |         text_ls = [] | 
					
						
							|  |  |  |         while len(text) > line_length: | 
					
						
							|  |  |  |             text_ls.append(text[:line_length]) | 
					
						
							|  |  |  |             text = text[line_length:] | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |         if text: | 
					
						
							|  |  |  |             text_ls.append(text) | 
					
						
							|  |  |  |         text = '\n  '.join(text_ls) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |     #text = text.replace('.', '.\n') | 
					
						
							|  |  |  |     #text = text.replace(']', ']\n') | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |     text = text.replace("\n", "\\n") | 
					
						
							|  |  |  |     text = text.replace('"', '\\"') | 
					
						
							| 
									
										
										
										
											2009-12-10 11:56:31 +00:00
										 |  |  |     return text | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-14 03:52:10 +00:00
										 |  |  | def graph_armature(obj, filepath, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True, XTRA_INFO=True): | 
					
						
							| 
									
										
										
										
											2009-12-05 20:45:51 +00:00
										 |  |  |     CONSTRAINTS = DRIVERS = True | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-14 03:52:10 +00:00
										 |  |  |     fileobject = open(filepath, "w") | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  |     fw = fileobject.write | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |     fw(header) | 
					
						
							| 
									
										
										
										
											2010-06-02 17:58:28 +00:00
										 |  |  |     fw('label = "%s::%s" ;' % (bpy.data.filepath.split("/")[-1].split("\\")[-1], obj.name)) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |     arm = obj.data | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |     bones = [bone.name for bone in arm.bones] | 
					
						
							|  |  |  |     bones.sort() | 
					
						
							|  |  |  |     print("") | 
					
						
							|  |  |  |     for bone in bones: | 
					
						
							|  |  |  |         b = arm.bones[bone] | 
					
						
							| 
									
										
										
										
											2010-08-18 07:45:32 +00:00
										 |  |  |         print(">>", bone, ["*>", "->"][b.use_connect], getattr(getattr(b, "parent", ""), "name", "")) | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |         label = [bone] | 
					
						
							|  |  |  |         bone = arm.bones[bone] | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |         for key, value in obj.pose.bones[bone.name].items(): | 
					
						
							|  |  |  |             if key.startswith("_"): | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |             if type(value) == float: | 
					
						
							|  |  |  |                 value = "%.3f" % value | 
					
						
							|  |  |  |             elif type(value) == str: | 
					
						
							|  |  |  |                 value = compat_str(value) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |             label.append("%s = %s" % (key, value)) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-05 20:45:51 +00:00
										 |  |  |         opts = ["shape=box", "regular=1", "style=filled", "fixedsize=false", 'label="%s"' % compat_str('\n'.join(label))] | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |         if bone.name.startswith('ORG'): | 
					
						
							|  |  |  |             opts.append("fillcolor=yellow") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             opts.append("fillcolor=white") | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |         fw('"%s" [%s];\n' % (bone.name, ','.join(opts))) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-02 10:32:39 +00:00
										 |  |  |     fw('\n\n# Hierarchy:\n') | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:25:59 +00:00
										 |  |  |     # Root node. | 
					
						
							|  |  |  |     if FAKE_PARENT: | 
					
						
							|  |  |  |         fw('"Object::%s" [];\n' % obj.name) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-02 02:56:22 +00:00
										 |  |  |     for bone in bones: | 
					
						
							|  |  |  |         bone = arm.bones[bone] | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |         parent = bone.parent | 
					
						
							|  |  |  |         if parent: | 
					
						
							| 
									
										
										
										
											2009-12-01 12:25:59 +00:00
										 |  |  |             parent_name = parent.name | 
					
						
							| 
									
										
										
										
											2010-08-18 07:45:32 +00:00
										 |  |  |             connected = bone.use_connect | 
					
						
							| 
									
										
										
										
											2009-12-01 12:25:59 +00:00
										 |  |  |         elif FAKE_PARENT: | 
					
						
							|  |  |  |             parent_name = 'Object::%s' % obj.name | 
					
						
							|  |  |  |             connected = False | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:25:59 +00:00
										 |  |  |         opts = ["dir=forward", "weight=2", "arrowhead=normal"] | 
					
						
							|  |  |  |         if not connected: | 
					
						
							|  |  |  |             opts.append("style=dotted") | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:25:59 +00:00
										 |  |  |         fw('"%s" -> "%s" [%s] ;\n' % (bone.name, parent_name, ','.join(opts))) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  |     del bone | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |     # constraints | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |     if CONSTRAINTS: | 
					
						
							| 
									
										
										
										
											2009-12-02 10:32:39 +00:00
										 |  |  |         fw('\n\n# Constraints:\n') | 
					
						
							|  |  |  |         for bone in bones: | 
					
						
							|  |  |  |             pbone = obj.pose.bones[bone] | 
					
						
							|  |  |  |             # must be ordered | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |             for constraint in pbone.constraints: | 
					
						
							| 
									
										
										
										
											2009-12-03 14:20:35 +00:00
										 |  |  |                 subtarget = getattr(constraint, "subtarget", "") | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |                 if subtarget: | 
					
						
							|  |  |  |                     # TODO, not internal links | 
					
						
							|  |  |  |                     opts = ['dir=forward', "weight=1", "arrowhead=normal", "arrowtail=none", "constraint=false", 'color="red"', 'labelfontsize=4'] | 
					
						
							| 
									
										
										
										
											2009-12-05 20:45:51 +00:00
										 |  |  |                     if XTRA_INFO: | 
					
						
							|  |  |  |                         label = "%s\n%s" % (constraint.type, constraint.name) | 
					
						
							|  |  |  |                         opts.append('label="%s"' % compat_str(label)) | 
					
						
							| 
									
										
										
										
											2009-12-08 17:00:53 +00:00
										 |  |  |                     fw('"%s" -> "%s" [%s] ;\n' % (pbone.name, subtarget, ','.join(opts))) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |     # Drivers | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |     if DRIVERS: | 
					
						
							| 
									
										
										
										
											2009-12-02 10:32:39 +00:00
										 |  |  |         fw('\n\n# Drivers:\n') | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |         def rna_path_as_pbone(rna_path): | 
					
						
							|  |  |  |             if not rna_path.startswith("pose.bones["): | 
					
						
							|  |  |  |                 return None | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |             #rna_path_bone = rna_path[:rna_path.index("]") + 1] | 
					
						
							| 
									
										
										
										
											2018-07-03 06:27:53 +02:00
										 |  |  |             # return obj.path_resolve(rna_path_bone) | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |             bone_name = rna_path.split("[")[1].split("]")[0] | 
					
						
							|  |  |  |             return obj.pose.bones[bone_name[1:-1]] | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |         animation_data = obj.animation_data | 
					
						
							|  |  |  |         if animation_data: | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-02 02:56:22 +00:00
										 |  |  |             fcurve_drivers = [fcurve_driver for fcurve_driver in animation_data.drivers] | 
					
						
							| 
									
										
										
										
											2009-12-10 22:23:09 +00:00
										 |  |  |             fcurve_drivers.sort(key=lambda fcurve_driver: fcurve_driver.data_path) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-02 02:56:22 +00:00
										 |  |  |             for fcurve_driver in fcurve_drivers: | 
					
						
							| 
									
										
										
										
											2009-12-10 22:23:09 +00:00
										 |  |  |                 rna_path = fcurve_driver.data_path | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |                 pbone = rna_path_as_pbone(rna_path) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 22:45:56 +00:00
										 |  |  |                 if pbone: | 
					
						
							| 
									
										
										
										
											2010-04-30 05:45:02 +00:00
										 |  |  |                     for var in fcurve_driver.driver.variables: | 
					
						
							|  |  |  |                         for target in var.targets: | 
					
						
							|  |  |  |                             pbone_target = rna_path_as_pbone(target.data_path) | 
					
						
							|  |  |  |                             rna_path_target = target.data_path | 
					
						
							|  |  |  |                             if pbone_target: | 
					
						
							| 
									
										
										
										
											2010-09-07 15:17:42 +00:00
										 |  |  |                                 opts = ['dir=forward', "weight=1", "arrowhead=normal", "arrowtail=none", "constraint=false", 'color="blue"', "labelfontsize=4"] | 
					
						
							| 
									
										
										
										
											2010-04-30 05:45:02 +00:00
										 |  |  |                                 display_source = rna_path.replace("pose.bones", "") | 
					
						
							|  |  |  |                                 display_target = rna_path_target.replace("pose.bones", "") | 
					
						
							|  |  |  |                                 if XTRA_INFO: | 
					
						
							|  |  |  |                                     label = "%s\\n%s" % (display_source, display_target) | 
					
						
							|  |  |  |                                     opts.append('label="%s"' % compat_str(label)) | 
					
						
							|  |  |  |                                 fw('"%s" -> "%s" [%s] ;\n' % (pbone_target.name, pbone.name, ','.join(opts))) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |     fw(footer) | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  |     fileobject.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-02 10:32:39 +00:00
										 |  |  |     '''
 | 
					
						
							| 
									
										
										
										
											2012-06-19 22:17:19 +00:00
										 |  |  |     print(".", end="") | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  |     import sys | 
					
						
							|  |  |  |     sys.stdout.flush() | 
					
						
							| 
									
										
										
										
											2009-12-02 10:32:39 +00:00
										 |  |  |     '''
 | 
					
						
							| 
									
										
										
										
											2010-06-14 03:52:10 +00:00
										 |  |  |     print("\nSaved:", filepath) | 
					
						
							| 
									
										
										
										
											2009-12-02 10:32:39 +00:00
										 |  |  |     return True | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 06:27:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-12-01 12:02:23 +00:00
										 |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     import os | 
					
						
							| 
									
										
										
										
											2009-12-05 22:03:07 +00:00
										 |  |  |     tmppath = "/tmp/test.dot" | 
					
						
							|  |  |  |     graph_armature(bpy.context.object, tmppath, CONSTRAINTS=True, DRIVERS=True) | 
					
						
							|  |  |  |     os.system("dot -Tpng %s > %s; eog %s &" % (tmppath, tmppath + '.png', tmppath + '.png')) |