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:
authorCampbell Barton <ideasman42@gmail.com>2011-09-23 02:51:54 +0400
committerCampbell Barton <ideasman42@gmail.com>2011-09-23 02:51:54 +0400
commit458b920abb8deafa99e420b8edc0adbaee144cda (patch)
tree103cea8ed8a0cae1e8c5a08ec247645b015bd3ce /release
parentea32492dd58522ecbddc28158067642cbb5f0808 (diff)
remove bl_operators/nla.py, move bake_action function into bpy_extras.anim_utils and bake operator into bl_operators/anim.py
Diffstat (limited to 'release')
-rw-r--r--release/scripts/modules/bpy_extras/__init__.py1
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py247
-rw-r--r--release/scripts/startup/bl_operators/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/anim.py108
-rw-r--r--release/scripts/startup/bl_operators/nla.py306
5 files changed, 356 insertions, 307 deletions
diff --git a/release/scripts/modules/bpy_extras/__init__.py b/release/scripts/modules/bpy_extras/__init__.py
index d853d5fda10..fd653a4129c 100644
--- a/release/scripts/modules/bpy_extras/__init__.py
+++ b/release/scripts/modules/bpy_extras/__init__.py
@@ -23,6 +23,7 @@ Utility modules assosiated with the bpy module.
"""
__all__ = (
+ "anim_utils",
"object_utils",
"io_utils",
"image_utils",
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py
new file mode 100644
index 00000000000..9482dc3e1c9
--- /dev/null
+++ b/release/scripts/modules/bpy_extras/anim_utils.py
@@ -0,0 +1,247 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8-80 compliant>
+
+__all__ = (
+ "bake_action",
+ )
+
+import bpy
+
+
+def bake_action(frame_start,
+ frame_end,
+ frame_step=1,
+ only_selected=False,
+ do_pose=True,
+ do_object=True,
+ do_constraint_clear=False,
+ do_clean=False,
+ action=None,
+ ):
+
+ """
+ Return an image from the file path with options to search multiple paths
+ and return a placeholder if its not found.
+
+ :arg frame_start: First frame to bake.
+ :type frame_start: int
+ :arg frame_end: Last frame to bake.
+ :type frame_end: int
+ :arg frame_step: Frame step.
+ :type frame_step: int
+ :arg only_selected: Only bake selected data.
+ :type only_selected: bool
+ :arg do_pose: Bake pose channels.
+ :type do_pose: bool
+ :arg do_object: Bake objects.
+ :type do_object: bool
+ :arg do_constraint_clear: Remove constraints.
+ :type do_constraint_clear: bool
+ :arg do_clean: Remove redundant keyframes after baking.
+ :type do_clean: bool
+ :arg action: An action to bake the data into, or None for a new action
+ to be created.
+ :type action: :class:`bpy.types.Action` or None
+
+ :return: an action or None
+ :rtype: :class:`bpy.types.Action`
+ """
+
+ # -------------------------------------------------------------------------
+ # Helper Functions
+
+ def pose_frame_info(obj):
+ from mathutils import Matrix
+
+ info = {}
+
+ pose = obj.pose
+
+ pose_items = pose.bones.items()
+
+ for name, pbone in pose_items:
+ binfo = {}
+ bone = pbone.bone
+
+ binfo["parent"] = getattr(bone.parent, "name", None)
+ binfo["bone"] = bone
+ binfo["pbone"] = pbone
+ binfo["matrix_local"] = bone.matrix_local.copy()
+ try:
+ binfo["matrix_local_inv"] = binfo["matrix_local"].inverted()
+ except:
+ binfo["matrix_local_inv"] = Matrix()
+
+ binfo["matrix"] = bone.matrix.copy()
+ binfo["matrix_pose"] = pbone.matrix.copy()
+ try:
+ binfo["matrix_pose_inv"] = binfo["matrix_pose"].inverted()
+ except:
+ binfo["matrix_pose_inv"] = Matrix()
+
+ info[name] = binfo
+
+ for name, pbone in pose_items:
+ binfo = info[name]
+ binfo_parent = binfo.get("parent", None)
+ if binfo_parent:
+ binfo_parent = info[binfo_parent]
+
+ matrix = binfo["matrix_pose"]
+ rest_matrix = binfo["matrix_local"]
+
+ if binfo_parent:
+ matrix = binfo_parent["matrix_pose_inv"] * matrix
+ rest_matrix = binfo_parent["matrix_local_inv"] * rest_matrix
+
+ binfo["matrix_key"] = rest_matrix.inverted() * matrix
+
+ return info
+
+
+ def obj_frame_info(obj):
+ info = {}
+ # parent = obj.parent
+ info["matrix_key"] = obj.matrix_local.copy()
+ return info
+
+ # -------------------------------------------------------------------------
+ # Setup the Context
+
+ # TODO, pass data rather then grabbing from the context!
+ scene = bpy.context.scene
+ obj = bpy.context.object
+ pose = obj.pose
+ frame_back = scene.frame_current
+
+ if pose is None:
+ do_pose = False
+
+ if do_pose is None and do_object is None:
+ return None
+
+ pose_info = []
+ obj_info = []
+
+ frame_range = range(frame_start, frame_end + 1, frame_step)
+
+ # -------------------------------------------------------------------------
+ # Collect transformations
+
+ # could speed this up by applying steps here too...
+ for f in frame_range:
+ scene.frame_set(f)
+
+ if do_pose:
+ pose_info.append(pose_frame_info(obj))
+ if do_object:
+ obj_info.append(obj_frame_info(obj))
+
+ f += 1
+
+ # -------------------------------------------------------------------------
+ # Create action
+
+ # incase animation data hassnt been created
+ atd = obj.animation_data_create()
+ if action is None:
+ action = bpy.data.actions.new("Action")
+ atd.action = action
+
+ if do_pose:
+ pose_items = pose.bones.items()
+ else:
+ pose_items = [] # skip
+
+ # -------------------------------------------------------------------------
+ # Apply transformations to action
+
+ # pose
+ for name, pbone in (pose_items if do_pose else ()):
+ if only_selected and not pbone.bone.select:
+ continue
+
+ if do_constraint_clear:
+ while pbone.constraints:
+ pbone.constraints.remove(pbone.constraints[0])
+
+ for f in frame_range:
+ matrix = pose_info[(f - frame_start) // frame_step][name]["matrix_key"]
+
+ # pbone.location = matrix.to_translation()
+ # pbone.rotation_quaternion = matrix.to_quaternion()
+ pbone.matrix_basis = matrix
+
+ pbone.keyframe_insert("location", -1, f, name)
+
+ rotation_mode = pbone.rotation_mode
+
+ if rotation_mode == 'QUATERNION':
+ pbone.keyframe_insert("rotation_quaternion", -1, f, name)
+ elif rotation_mode == 'AXIS_ANGLE':
+ pbone.keyframe_insert("rotation_axis_angle", -1, f, name)
+ else: # euler, XYZ, ZXY etc
+ pbone.keyframe_insert("rotation_euler", -1, f, name)
+
+ pbone.keyframe_insert("scale", -1, f, name)
+
+ # object. TODO. multiple objects
+ if do_object:
+ if do_constraint_clear:
+ while obj.constraints:
+ obj.constraints.remove(obj.constraints[0])
+
+ for f in frame_range:
+ matrix = obj_info[(f - frame_start) // frame_step]["matrix_key"]
+ obj.matrix_local = matrix
+
+ obj.keyframe_insert("location", -1, f)
+
+ rotation_mode = obj.rotation_mode
+
+ if rotation_mode == 'QUATERNION':
+ obj.keyframe_insert("rotation_quaternion", -1, f)
+ elif rotation_mode == 'AXIS_ANGLE':
+ obj.keyframe_insert("rotation_axis_angle", -1, f)
+ else: # euler, XYZ, ZXY etc
+ obj.keyframe_insert("rotation_euler", -1, f)
+
+ obj.keyframe_insert("scale", -1, f)
+
+ scene.frame_set(frame_back)
+
+ # -------------------------------------------------------------------------
+ # Clean
+
+ if do_clean:
+ for fcu in action.fcurves:
+ keyframe_points = fcu.keyframe_points
+ i = 1
+ while i < len(fcu.keyframe_points) - 1:
+ val_prev = keyframe_points[i - 1].co[1]
+ val_next = keyframe_points[i + 1].co[1]
+ val = keyframe_points[i].co[1]
+
+ if abs(val - val_prev) + abs(val - val_next) < 0.0001:
+ keyframe_points.remove(keyframe_points[i])
+ else:
+ i += 1
+
+ return action
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index 918e9153b73..f5f8b992356 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -29,7 +29,6 @@ _modules = (
"console",
"image",
"mesh",
- "nla",
"object_align",
"object",
"object_randomize_transform",
diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py
index f33d5614629..660194abf8c 100644
--- a/release/scripts/startup/bl_operators/anim.py
+++ b/release/scripts/startup/bl_operators/anim.py
@@ -18,8 +18,14 @@
# <pep8-80 compliant>
+if "bpy" in locals():
+ import imp
+ if "anim_utils" in locals():
+ imp.reload(anim_utils)
+
import bpy
from bpy.types import Operator
+from bpy.props import IntProperty, BoolProperty, EnumProperty
class ANIM_OT_keying_set_export(Operator):
@@ -125,3 +131,105 @@ class ANIM_OT_keying_set_export(Operator):
wm = context.window_manager
wm.fileselect_add(self)
return {'RUNNING_MODAL'}
+
+
+class BakeAction(Operator):
+ '''Bake animation to an Action'''
+ bl_idname = "nla.bake"
+ bl_label = "Bake Action"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ frame_start = IntProperty(
+ name="Start Frame",
+ description="Start frame for baking",
+ min=0, max=300000,
+ default=1,
+ )
+ frame_end = IntProperty(
+ name="End Frame",
+ description="End frame for baking",
+ min=1, max=300000,
+ default=250,
+ )
+ step = IntProperty(
+ name="Frame Step",
+ description="Frame Step",
+ min=1, max=120,
+ default=1,
+ )
+ only_selected = BoolProperty(
+ name="Only Selected",
+ default=True,
+ )
+ clear_consraints = BoolProperty(
+ name="Clear Constraints",
+ default=False,
+ )
+ bake_types = EnumProperty(
+ name="Bake Data",
+ options={'ENUM_FLAG'},
+ items=(('POSE', "Pose", ""),
+ ('OBJECT', "Object", ""),
+ ),
+ default={'POSE'},
+ )
+
+ def execute(self, context):
+
+ from bpy_extras import anim_utils
+
+ action = anim_utils.bake_action(self.frame_start,
+ self.frame_end,
+ self.step,
+ self.only_selected,
+ 'POSE' in self.bake_types,
+ 'OBJECT' in self.bake_types,
+ self.clear_consraints,
+ True,
+ )
+
+ if action is None:
+ self.report({'INFO'}, "Nothing to bake")
+ return {'CANCELLED'}
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ wm = context.window_manager
+ return wm.invoke_props_dialog(self)
+
+
+class ClearUselessActions(Operator):
+ '''Mark actions with no F-Curves for deletion after save+reload of ''' \
+ '''file preserving "action libraries"'''
+ bl_idname = "anim.clear_useless_actions"
+ bl_label = "Clear Useless Actions"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ only_unused = BoolProperty(name="Only Unused",
+ description="Only unused (Fake User only) actions get considered",
+ default=True)
+
+ @classmethod
+ def poll(cls, context):
+ return len(bpy.data.actions) != 0
+
+ def execute(self, context):
+ removed = 0
+
+ for action in bpy.data.actions:
+ # if only user is "fake" user...
+ if ((self.only_unused is False) or
+ (action.use_fake_user and action.users == 1)):
+
+ # if it has F-Curves, then it's a "action library"
+ # (i.e. walk, wave, jump, etc.)
+ # and should be left alone as that's what fake users are for!
+ if not action.fcurves:
+ # mark action for deletion
+ action.user_clear()
+ removed += 1
+
+ self.report({'INFO'}, "Removed %d empty and/or fake-user only Actions"
+ % removed)
+ return {'FINISHED'}
diff --git a/release/scripts/startup/bl_operators/nla.py b/release/scripts/startup/bl_operators/nla.py
deleted file mode 100644
index feb0016b1c7..00000000000
--- a/release/scripts/startup/bl_operators/nla.py
+++ /dev/null
@@ -1,306 +0,0 @@
-# ##### 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.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8-80 compliant>
-
-import bpy
-from bpy.types import Operator
-
-
-def pose_frame_info(obj):
- from mathutils import Matrix
-
- info = {}
-
- pose = obj.pose
-
- pose_items = pose.bones.items()
-
- for name, pbone in pose_items:
- binfo = {}
- bone = pbone.bone
-
- binfo["parent"] = getattr(bone.parent, "name", None)
- binfo["bone"] = bone
- binfo["pbone"] = pbone
- binfo["matrix_local"] = bone.matrix_local.copy()
- try:
- binfo["matrix_local_inv"] = binfo["matrix_local"].inverted()
- except:
- binfo["matrix_local_inv"] = Matrix()
-
- binfo["matrix"] = bone.matrix.copy()
- binfo["matrix_pose"] = pbone.matrix.copy()
- try:
- binfo["matrix_pose_inv"] = binfo["matrix_pose"].inverted()
- except:
- binfo["matrix_pose_inv"] = Matrix()
-
- info[name] = binfo
-
- for name, pbone in pose_items:
- binfo = info[name]
- binfo_parent = binfo.get("parent", None)
- if binfo_parent:
- binfo_parent = info[binfo_parent]
-
- matrix = binfo["matrix_pose"]
- rest_matrix = binfo["matrix_local"]
-
- if binfo_parent:
- matrix = binfo_parent["matrix_pose_inv"] * matrix
- rest_matrix = binfo_parent["matrix_local_inv"] * rest_matrix
-
- binfo["matrix_key"] = rest_matrix.inverted() * matrix
-
- return info
-
-
-def obj_frame_info(obj):
- info = {}
- # parent = obj.parent
- info["matrix_key"] = obj.matrix_local.copy()
- return info
-
-
-def bake(frame_start,
- frame_end, step=1,
- only_selected=False,
- do_pose=True,
- do_object=True,
- do_constraint_clear=False,
- action=None):
-
- scene = bpy.context.scene
- obj = bpy.context.object
- pose = obj.pose
- frame_back = scene.frame_current
-
- if pose is None:
- do_pose = False
-
- if do_pose is None and do_object is None:
- return None
-
- pose_info = []
- obj_info = []
-
- frame_range = range(frame_start, frame_end + 1, step)
-
- # -------------------------------------------------------------------------
- # Collect transformations
-
- # could speed this up by applying steps here too...
- for f in frame_range:
- scene.frame_set(f)
-
- if do_pose:
- pose_info.append(pose_frame_info(obj))
- if do_object:
- obj_info.append(obj_frame_info(obj))
-
- f += 1
-
- # -------------------------------------------------------------------------
- # Create action
-
- # incase animation data hassnt been created
- atd = obj.animation_data_create()
- if action is None:
- action = bpy.data.actions.new("Action")
- atd.action = action
-
- if do_pose:
- pose_items = pose.bones.items()
- else:
- pose_items = [] # skip
-
- # -------------------------------------------------------------------------
- # Apply transformations to action
-
- # pose
- for name, pbone in (pose_items if do_pose else ()):
- if only_selected and not pbone.bone.select:
- continue
-
- if do_constraint_clear:
- while pbone.constraints:
- pbone.constraints.remove(pbone.constraints[0])
-
- for f in frame_range:
- matrix = pose_info[(f - frame_start) // step][name]["matrix_key"]
-
- # pbone.location = matrix.to_translation()
- # pbone.rotation_quaternion = matrix.to_quaternion()
- pbone.matrix_basis = matrix
-
- pbone.keyframe_insert("location", -1, f, name)
-
- rotation_mode = pbone.rotation_mode
-
- if rotation_mode == 'QUATERNION':
- pbone.keyframe_insert("rotation_quaternion", -1, f, name)
- elif rotation_mode == 'AXIS_ANGLE':
- pbone.keyframe_insert("rotation_axis_angle", -1, f, name)
- else: # euler, XYZ, ZXY etc
- pbone.keyframe_insert("rotation_euler", -1, f, name)
-
- pbone.keyframe_insert("scale", -1, f, name)
-
- # object. TODO. multiple objects
- if do_object:
- if do_constraint_clear:
- while obj.constraints:
- obj.constraints.remove(obj.constraints[0])
-
- for f in frame_range:
- matrix = obj_info[(f - frame_start) // step]["matrix_key"]
- obj.matrix_local = matrix
-
- obj.keyframe_insert("location", -1, f)
-
- rotation_mode = obj.rotation_mode
-
- if rotation_mode == 'QUATERNION':
- obj.keyframe_insert("rotation_quaternion", -1, f)
- elif rotation_mode == 'AXIS_ANGLE':
- obj.keyframe_insert("rotation_axis_angle", -1, f)
- else: # euler, XYZ, ZXY etc
- obj.keyframe_insert("rotation_euler", -1, f)
-
- obj.keyframe_insert("scale", -1, f)
-
- scene.frame_set(frame_back)
-
- return action
-
-
-from bpy.props import IntProperty, BoolProperty, EnumProperty
-
-
-class BakeAction(Operator):
- '''Bake animation to an Action'''
- bl_idname = "nla.bake"
- bl_label = "Bake Action"
- bl_options = {'REGISTER', 'UNDO'}
-
- frame_start = IntProperty(
- name="Start Frame",
- description="Start frame for baking",
- min=0, max=300000,
- default=1,
- )
- frame_end = IntProperty(
- name="End Frame",
- description="End frame for baking",
- min=1, max=300000,
- default=250,
- )
- step = IntProperty(
- name="Frame Step",
- description="Frame Step",
- min=1, max=120,
- default=1,
- )
- only_selected = BoolProperty(
- name="Only Selected",
- default=True,
- )
- clear_consraints = BoolProperty(
- name="Clear Constraints",
- default=False,
- )
- bake_types = EnumProperty(
- name="Bake Data",
- options={'ENUM_FLAG'},
- items=(('POSE', "Pose", ""),
- ('OBJECT', "Object", ""),
- ),
- default={'POSE'},
- )
-
- def execute(self, context):
-
- action = bake(self.frame_start,
- self.frame_end,
- self.step,
- self.only_selected,
- 'POSE' in self.bake_types,
- 'OBJECT' in self.bake_types,
- self.clear_consraints,
- )
-
- if action is None:
- self.report({'INFO'}, "Nothing to bake")
- return {'CANCELLED'}
-
- # basic cleanup, could move elsewhere
- for fcu in action.fcurves:
- keyframe_points = fcu.keyframe_points
- i = 1
- while i < len(fcu.keyframe_points) - 1:
- val_prev = keyframe_points[i - 1].co[1]
- val_next = keyframe_points[i + 1].co[1]
- val = keyframe_points[i].co[1]
-
- if abs(val - val_prev) + abs(val - val_next) < 0.0001:
- keyframe_points.remove(keyframe_points[i])
- else:
- i += 1
-
- return {'FINISHED'}
-
- def invoke(self, context, event):
- wm = context.window_manager
- return wm.invoke_props_dialog(self)
-
-
-class ClearUselessActions(Operator):
- '''Mark actions with no F-Curves for deletion after save+reload of ''' \
- '''file preserving "action libraries"'''
- bl_idname = "anim.clear_useless_actions"
- bl_label = "Clear Useless Actions"
- bl_options = {'REGISTER', 'UNDO'}
-
- only_unused = BoolProperty(name="Only Unused",
- description="Only unused (Fake User only) actions get considered",
- default=True)
-
- @classmethod
- def poll(cls, context):
- return len(bpy.data.actions) != 0
-
- def execute(self, context):
- removed = 0
-
- for action in bpy.data.actions:
- # if only user is "fake" user...
- if ((self.only_unused is False) or
- (action.use_fake_user and action.users == 1)):
-
- # if it has F-Curves, then it's a "action library"
- # (i.e. walk, wave, jump, etc.)
- # and should be left alone as that's what fake users are for!
- if not action.fcurves:
- # mark action for deletion
- action.user_clear()
- removed += 1
-
- self.report({'INFO'}, "Removed %d empty and/or fake-user only Actions"
- % removed)
- return {'FINISHED'}