drivers.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. from .utilities import (prRed, prGreen, prPurple, prWhite,
  2. prOrange,
  3. wrapRed, wrapGreen, wrapPurple, wrapWhite,
  4. wrapOrange,)
  5. ##########################################################################
  6. # Drivers!
  7. ##########################################################################
  8. # SO: the idea is that the driver's input is a Python dictionary
  9. # with all of the requisite information to build the driver
  10. # I need a generic function to create the driver
  11. # EXAMPLE INPUT:
  12. # example = {"owner":None,
  13. # "prop":None,
  14. # "ind":-1,
  15. # "type":"AVERAGE",
  16. # "vars":[{"id":None,
  17. # "name":"a",
  18. # "type":"TRANSFORMS",
  19. # "space":'LOCAL_SPACE',
  20. # "channel":'LOC_Z',},],
  21. # "keys":[{"co":(0,0.5),
  22. # "interpolation": "BEZIER",
  23. # "handle_left_type": "AUTO_CLAMPED", #if AUTO then handle_left will be ignored
  24. # "handle_right_type": "AUTO_CLAMPED",
  25. # "type":"KEYFRAME",}, #display type
  26. # {"co":(-1,0),
  27. # "interpolation": "BEZIER",
  28. # "handle_left_type": "AUTO_CLAMPED",
  29. # "handle_right_type": "AUTO_CLAMPED",
  30. # "type":"KEYFRAME",},
  31. # {"co":(1,1),
  32. # "interpolation": "BEZIER",
  33. # "handle_left_type": "ALIGNED",
  34. # "handle_right_type": "ALIGNED",
  35. # "handle_left": (-0.4,0), #these are treated as offsets
  36. # "handle_right": ( 0.04,0), #only valid if interp. == BEZIER
  37. # "type":"KEYFRAME",},],
  38. # }
  39. class MantisDriver(dict):
  40. pass
  41. def CreateDrivers(drivers):
  42. from bpy.app import version
  43. def brackets(s):
  44. return "[\""+s+"\"]"
  45. from bpy.types import Object, Key
  46. for driver in drivers:
  47. if (isinstance(driver["owner"], Object)):
  48. ob = driver["owner"]
  49. else: # Pose Bone:
  50. ob = driver["owner"].id_data
  51. if isinstance(driver["owner"], Key):
  52. fc = ob.driver_add(driver["prop"])
  53. else:
  54. fc = ob.driver_add(driver["owner"].path_from_id(driver["prop"]), driver["ind"])
  55. drv = fc.driver
  56. try: # annoyingly, this initializes with a modifier
  57. fc.modifiers.remove(fc.modifiers[0])
  58. except IndexError: #haven't seen this happen, but should handle
  59. pass # perhaps this has been fixed for 3.0?
  60. if version >= (5,0,0): # and now it initializes with keys. p
  61. fc.keyframe_points.clear()
  62. drv.type = driver["type"]
  63. if (expr := driver.get("expression")) and isinstance(expr, str):
  64. drv.expression = expr
  65. fc.extrapolation = "CONSTANT"
  66. if (extrapolation_mode := driver.get("extrapolation")) in ("CONSTANT", "LINEAR"):
  67. fc.extrapolation = extrapolation_mode
  68. else:
  69. prRed(f"Extrapolation Mode in driver has incorrect data: {extrapolation_mode}")
  70. # logic for handling type can go here
  71. # start by clearing
  72. while (len(drv.variables) > 0):
  73. v = drv.variables[0]
  74. dVar = drv.variables.remove(v)
  75. for v in driver["vars"]:
  76. pose_bone = False
  77. bone = ''; target2bone = ''
  78. vob, target2ob = None, None
  79. if (isinstance(v["owner"], Object)):
  80. vob = v["owner"]
  81. else:
  82. pose_bone = True
  83. vob = v["owner"].id_data
  84. bone = v["owner"].name
  85. #
  86. if "xForm 2" in v.keys() and v["xForm 2"]:
  87. if (isinstance(v["xForm 2"], Object)):
  88. target2ob = v["xForm 2"]
  89. else:
  90. target2ob = v["xForm 2"].id_data
  91. target2bone = v["xForm 2"].name
  92. dVar = drv.variables.new()
  93. dVar.name = v["name"]
  94. dVar.type = v["type"]
  95. #for now, assume this is always true:
  96. #dVar.targets[0].id_type = "OBJECT"
  97. #it's possible to use other datablocks, but this is not commonly done
  98. #actually, it looks like Blender figures this out for me.
  99. dVar.targets[0].id = vob
  100. dVar.targets[0].bone_target = bone
  101. if len(dVar.targets) > 1:
  102. dVar.targets[1].id = target2ob
  103. dVar.targets[1].bone_target = target2bone
  104. if (dVar.type == "TRANSFORMS"):
  105. dVar.targets[0].transform_space = v["space"]
  106. dVar.targets[0].transform_type = v["channel"]
  107. if (dVar.type == 'SINGLE_PROP'):
  108. if pose_bone:
  109. stub = "pose.bones[\""+v["owner"].name+"\"]"
  110. dVar.targets[0].data_path = stub + brackets(v["prop"])
  111. if (hasattr( v["owner"], v["prop"] )):
  112. dVar.targets[0].data_path = stub + "."+ (v["prop"])
  113. # else: # the property may be added later.
  114. # TODO BUG I want a guarantee that this property is already there.
  115. else:
  116. if (hasattr( v["owner"], v["prop"] )):
  117. dVar.targets[0].data_path = (v["prop"])
  118. else:
  119. dVar.targets[0].data_path = brackets(v["prop"])
  120. # setup keyframe points
  121. kp = fc.keyframe_points
  122. for key in driver["keys"]:
  123. k = kp.insert(frame=key["co"][0], value = key["co"][1],)
  124. k.interpolation = key["interpolation"]
  125. if (key["interpolation"] == 'BEZIER'):
  126. k.handle_left_type = key["handle_left_type" ]
  127. k.handle_right_type = key["handle_right_type"]
  128. if (k.handle_left_type in ("ALIGNED", "VECTOR", "FREE")):
  129. k.handle_left = (k.co[0] + key["handle_left"][0], k.co[1] + key["handle_left"][1])
  130. if (k.handle_right_type in ("ALIGNED", "VECTOR", "FREE")):
  131. k.handle_right = (k.co[0] + key["handle_right"][0], k.co[1] + key["handle_right"][1])
  132. k.type = key["type"]