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>2017-09-11 09:52:53 +0300
committerCampbell Barton <ideasman42@gmail.com>2017-09-11 09:52:53 +0300
commit7d7741d25fb7d248b557c6f5270510d7c0dbe923 (patch)
treecfb288dc6297f35be54f73470b9f465238f88281 /release
parent49ba9d02d8dc5e1aef3cc0f0b3453866125af64c (diff)
parentf56fea3d6b481b70e5ca518e41dab8c00bc26251 (diff)
Merge branch 'master' into blender2.8
Diffstat (limited to 'release')
-rw-r--r--release/scripts/modules/bpy_extras/anim_utils.py165
-rw-r--r--release/scripts/modules/nodeitems_utils.py12
-rw-r--r--release/scripts/startup/bl_operators/anim.py46
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'}