diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-09-11 09:52:53 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-09-11 09:52:53 +0300 |
commit | 7d7741d25fb7d248b557c6f5270510d7c0dbe923 (patch) | |
tree | cfb288dc6297f35be54f73470b9f465238f88281 /release | |
parent | 49ba9d02d8dc5e1aef3cc0f0b3453866125af64c (diff) | |
parent | f56fea3d6b481b70e5ca518e41dab8c00bc26251 (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'release')
-rw-r--r-- | release/scripts/modules/bpy_extras/anim_utils.py | 165 | ||||
-rw-r--r-- | release/scripts/modules/nodeitems_utils.py | 12 | ||||
-rw-r--r-- | release/scripts/startup/bl_operators/anim.py | 46 |
3 files changed, 148 insertions, 75 deletions
diff --git a/release/scripts/modules/bpy_extras/anim_utils.py b/release/scripts/modules/bpy_extras/anim_utils.py index 5e21260e5e4..f2df1bc16b3 100644 --- a/release/scripts/modules/bpy_extras/anim_utils.py +++ b/release/scripts/modules/bpy_extras/anim_utils.py @@ -20,35 +20,118 @@ __all__ = ( "bake_action", - ) + "bake_action_objects", + + "bake_action_iter", + "bake_action_objects_iter", +) import bpy -# XXX visual keying is actually always considered as True in this code... -def bake_action(frame_start, - frame_end, - frame_step=1, - only_selected=False, - do_pose=True, - do_object=True, - do_visual_keying=True, - do_constraint_clear=False, - do_parents_clear=False, - do_clean=False, - action=None, - ): +def bake_action( + obj, + *, + action, frames, + **kwargs, +): + """ + :arg obj: Object to bake. + :type obj: :class:`bpy.types.Object` + :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 + :arg frames: Frames to bake. + :type frames: iterable of int + :return: an action or None + :rtype: :class:`bpy.types.Action` """ - 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 + if not (do_pose or do_object): + return None + + action, = bake_action_objects( + [(obj, action)], + frames, + **kwargs, + ) + return action + + +def bake_action_objects( + object_action_pairs, + *, + frames, + **kwargs, +): + """ + A version of :func:`bake_action_objects_iter` that takes frames and returns the output. + + :arg frames: Frames to bake. + :type frames: iterable of int + + :return: A sequence of Action or None types (aligned with `object_action_pairs`) + :rtype: sequence of :class:`bpy.types.Action` + """ + iter = bake_action_objects_iter(object_action_pairs, **kwargs) + iter.send(None) + for frame in frames: + iter.send(frame) + return iter.send(None) + + +def bake_action_objects_iter( + object_action_pairs, + **kwargs, +): + """ + An coroutine that bakes actions for multiple objects. + + :arg object_action_pairs: Sequence of object action tuples, + action is the destination for the baked data. When None a new action will be created. + :type object_action_pairs: Sequence of (:class:`bpy.types.Object`, :class:`bpy.types.Action`) + """ + scene = bpy.context.scene + frame_back = scene.frame_current + iter_all = tuple( + bake_action_iter(obj, action=action, **kwargs) + for (obj, action) in object_action_pairs + ) + for iter in iter_all: + iter.send(None) + while True: + frame = yield None + if frame is None: + break + scene.frame_set(frame) + scene.update() + for iter in iter_all: + iter.send(frame) + scene.frame_set(frame_back) + yield tuple(iter.send(None) for iter in iter_all) + + +# XXX visual keying is actually always considered as True in this code... +def bake_action_iter( + obj, + *, + action, + only_selected=False, + do_pose=True, + do_object=True, + do_visual_keying=True, + do_constraint_clear=False, + do_parents_clear=False, + do_clean=False, +): + """ + An coroutine that bakes action for a single object. + + :arg obj: Object to bake. + :type obj: :class:`bpy.types.Object` + :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 :arg only_selected: Only bake selected bones. :type only_selected: bool :arg do_pose: Bake pose channels. @@ -63,14 +146,10 @@ def bake_action(frame_start, :type do_parents_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 and vars @@ -112,34 +191,32 @@ def bake_action(frame_start, # ------------------------------------------------------------------------- # Setup the Context - # TODO, pass data rather then grabbing from the context! - scene = bpy.context.scene - obj = bpy.context.object - frame_back = scene.frame_current - if obj.pose is None: do_pose = False if not (do_pose or do_object): - return None + raise Exception("Pose and object baking is disabled, no action needed") pose_info = [] obj_info = [] options = {'INSERTKEY_NEEDED'} - frame_range = range(frame_start, frame_end + 1, frame_step) - # ------------------------------------------------------------------------- # Collect transformations - for f in frame_range: - scene.frame_set(f) - scene.update() + while True: + # Caller is responsible for setting the frame and updating the scene. + frame = yield None + + # Signal we're done! + if frame is None: + break + if do_pose: - pose_info.append(pose_frame_info(obj)) + pose_info.append((frame, pose_frame_info(obj))) if do_object: - obj_info.append(obj_frame_info(obj)) + obj_info.append((frame, obj_frame_info(obj))) # ------------------------------------------------------------------------- # Clean (store initial data) @@ -178,7 +255,7 @@ def bake_action(frame_start, # create compatible eulers euler_prev = None - for (f, matrix) in zip(frame_range, pose_info): + for (f, matrix) in pose_info: pbone.matrix_basis = matrix[name].copy() pbone.keyframe_insert("location", -1, f, name, options) @@ -210,7 +287,7 @@ def bake_action(frame_start, # create compatible eulers euler_prev = None - for (f, matrix) in zip(frame_range, obj_info): + for (f, matrix) in obj_info: name = "Action Bake" # XXX: placeholder obj.matrix_basis = matrix @@ -261,6 +338,4 @@ def bake_action(frame_start, else: i += 1 - scene.frame_set(frame_back) - - return action + yield action diff --git a/release/scripts/modules/nodeitems_utils.py b/release/scripts/modules/nodeitems_utils.py index 7dc456f6c98..117e35dd028 100644 --- a/release/scripts/modules/nodeitems_utils.py +++ b/release/scripts/modules/nodeitems_utils.py @@ -59,9 +59,9 @@ class NodeItem: return self._label else: # if no custom label is defined, fall back to the node type UI name - cls = bpy.types.Node.bl_rna_get_subclass(self.nodetype) - if cls is not None: - return cls.bl_rna.name + bl_rna = bpy.types.Node.bl_rna_get_subclass(self.nodetype) + if bl_rna is not None: + return bl_rna.name else: return "Unknown" @@ -71,9 +71,9 @@ class NodeItem: return bpy.app.translations.contexts.default else: # if no custom label is defined, fall back to the node type UI name - cls = bpy.types.Node.bl_rna_get_subclass(self.nodetype) - if cls is not None: - return cls.bl_rna.translation_context + bl_rna = bpy.types.Node.bl_rna_get_subclass(self.nodetype) + if bl_rna is not None: + return bl_rna.translation_context else: return bpy.app.translations.contexts.default diff --git a/release/scripts/startup/bl_operators/anim.py b/release/scripts/startup/bl_operators/anim.py index a843c17217a..0632f9bc3ca 100644 --- a/release/scripts/startup/bl_operators/anim.py +++ b/release/scripts/startup/bl_operators/anim.py @@ -198,7 +198,7 @@ class ANIM_OT_keying_set_export(Operator): class BakeAction(Operator): - """Bake object/pose loc/scale/rotation animation to a new action""" + """Bake all selected objects loc/scale/rotation animation to an action""" bl_idname = "nla.bake" bl_label = "Bake Action" bl_options = {'REGISTER', 'UNDO'} @@ -222,7 +222,7 @@ class BakeAction(Operator): default=1, ) only_selected = BoolProperty( - name="Only Selected", + name="Only Selected Bones", description="Only key selected bones (Pose baking only)", default=True, ) @@ -258,29 +258,27 @@ class BakeAction(Operator): ) def execute(self, context): - from bpy_extras import anim_utils - - action = None - if self.use_current_action: - obj = context.object - if obj.animation_data: - action = obj.animation_data.action - - action = anim_utils.bake_action(self.frame_start, - self.frame_end, - frame_step=self.step, - only_selected=self.only_selected, - do_pose='POSE' in self.bake_types, - do_object='OBJECT' in self.bake_types, - do_visual_keying=self.visual_keying, - do_constraint_clear=self.clear_constraints, - do_parents_clear=self.clear_parents, - do_clean=True, - action=action, - ) - - if action is None: + objects = context.selected_editable_objects + object_action_pairs = ( + [(obj, getattr(obj.animation_data, "action", None)) for obj in objects] + if self.use_current_action else + [(obj, None) for obj in objects] + ) + + actions = anim_utils.bake_action_objects( + object_action_pairs, + frames=range(self.frame_start, self.frame_end + 1, self.step), + only_selected=self.only_selected, + do_pose='POSE' in self.bake_types, + do_object='OBJECT' in self.bake_types, + do_visual_keying=self.visual_keying, + do_constraint_clear=self.clear_constraints, + do_parents_clear=self.clear_parents, + do_clean=True, + ) + + if not any(actions): self.report({'INFO'}, "Nothing to bake") return {'CANCELLED'} |