[Bf-blender-cvs] [ffb0ed3] multi_previews_id: Applied my work from temp-sybren-poselib branch.
Sybren A. Stüvel
noreply at git.blender.org
Tue Nov 1 15:14:21 CET 2016
Commit: ffb0ed305d87d236787163abbe33a921d3eaecf6
Author: Sybren A. Stüvel
Date: Tue Nov 1 15:14:15 2016 +0100
Branches: multi_previews_id
https://developer.blender.org/rBffb0ed305d87d236787163abbe33a921d3eaecf6
Applied my work from temp-sybren-poselib branch.
Still a bit rough. For example, the viewport used for OpenGL rendering is
more or less randomly chosen from the current screen.
===================================================================
M release/scripts/startup/bl_operators/__init__.py
A release/scripts/startup/bl_operators/poselib.py
M release/scripts/startup/bl_ui/__init__.py
M release/scripts/startup/bl_ui/properties_data_armature.py
M source/blender/blenkernel/intern/anim_sys.c
M source/blender/editors/armature/pose_lib.c
M source/blender/editors/armature/pose_transform.c
M source/blender/makesrna/intern/rna_timeline.c
===================================================================
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index a696410..01c954d 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -39,6 +39,7 @@ _modules = [
"object",
"object_randomize_transform",
"object_quick_effects",
+ "poselib",
"presets",
"rigidbody",
"screen_play_rendered_anim",
diff --git a/release/scripts/startup/bl_operators/poselib.py b/release/scripts/startup/bl_operators/poselib.py
new file mode 100644
index 0000000..0579470
--- /dev/null
+++ b/release/scripts/startup/bl_operators/poselib.py
@@ -0,0 +1,129 @@
+# ##### 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 #####
+
+if "bpy" in locals():
+ from importlib import reload
+ if "anim_utils" in locals():
+ reload(anim_utils)
+ del reload
+
+
+import bpy
+from bpy.types import Operator
+from bpy.props import (
+ IntProperty,
+ BoolProperty,
+ EnumProperty,
+ StringProperty,
+ )
+
+
+class POSELIB_OT_render_previews(Operator):
+ """Renders a preview image for each pose in the pose library.
+
+ TODO: the viewport used for OpenGL rendering is more or less random.
+ """
+
+ import logging as __logging
+
+ bl_idname = "poselib.render_previews"
+ bl_label = "Render pose previews"
+ bl_description = "Renders a preview image for each pose in the pose library"
+
+ log = __logging.getLogger('bpy.ops.%s' % bl_idname)
+
+ render_method = EnumProperty(
+ items=[
+ ('OPENGL', 'OpenGL render', 'Use the OpenGL viewport render'),
+ ('FULL', 'Full render', 'Use the same render engine as the scene'),
+ ],
+ default='OPENGL'
+ )
+
+ plib_index = 0
+
+ @classmethod
+ def poll(cls, context):
+ """Running only makes sense if there are any poses in the library."""
+ plib = context.object and context.object.pose_library
+ return bool(plib and plib.pose_markers)
+
+ def execute(self, context):
+ return {'PASS_THROUGH'}
+
+ def modal(self, context, event):
+ if event.type == 'ESC':
+ self._finish(context)
+ self.report({'INFO'}, 'Canceled rendering pose library previews')
+ return {'CANCELLED'}
+
+ if event.type != 'TIMER':
+ return {'PASS_THROUGH'}
+
+ plib = context.object.pose_library
+
+ pose_count = len(plib.pose_markers)
+ if self.plib_index >= pose_count:
+ self._finish(context)
+ self.report({'INFO'}, 'Done rendering pose library previews')
+ return {'FINISHED'}
+
+ self.render_pose(context, plib, self.plib_index)
+ self.plib_index += 1
+
+ return {'RUNNING_MODAL'}
+
+ def render_pose(self, context, plib, plib_index):
+ import os.path
+
+ marker = plib.pose_markers[plib_index]
+ self.log.info('Rendering pose %s at frame %i', marker.name, marker.frame)
+
+ context.scene.frame_set(marker.frame)
+ switch_to = None
+ if marker.camera:
+ switch_to = marker.camera
+ else:
+ cams = [m.camera for m in context.scene.timeline_markers
+ if m.frame == marker.frame and m.camera]
+ if cams:
+ switch_to = cams[0]
+ if switch_to is not None:
+ self.log.info('Switching camera to %s', switch_to)
+ context.scene.camera = switch_to
+
+ bpy.ops.poselib.apply_pose(pose_index=plib_index)
+
+ fname = '%s.png' % marker.name
+ context.scene.render.filepath = os.path.join(plib.pose_previews_dir, fname)
+ bpy.ops.render.opengl(write_still=True)
+
+ def invoke(self, context, event):
+ wm = context.window_manager
+ wm.modal_handler_add(self)
+
+ self.wm = context.window_manager
+ self.timer = self.wm.event_timer_add(0.01, context.window)
+ self.plib_index = 0
+ self.orig_filepath = context.scene.render.filepath
+
+ return {'RUNNING_MODAL'}
+
+ def _finish(self, context):
+ self.wm.event_timer_remove(self.timer)
+ context.scene.render.filepath = self.orig_filepath
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 2389be6..56d3ece 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -139,12 +139,32 @@ def register():
default={'OFFICIAL', 'COMMUNITY'},
options={'ENUM_FLAG'},
)
+
+ # properties_data_armature.py
+ from . import properties_data_armature
+ bpy.types.Action.pose_previews = EnumProperty(
+ items=properties_data_armature.pose_preview_items,
+ update=properties_data_armature.update_pose)
+ bpy.types.Action.pose_previews_dir = StringProperty(
+ name='Thumbnail Path',
+ subtype='DIR_PATH',
+ default='',
+ # update=filepath_update
+ )
+
+
# done...
def unregister():
bpy.utils.unregister_module(__name__)
+ from . import properties_data_armature
+
+ del bpy.types.Object.pose_previews
+ if properties_data_armature.previews:
+ bpy.utils.previews.remove(properties_data_armature.previews)
+
# Define a default UIList, when a list does not need any custom drawing...
# Keep in sync with its #defined name in UI_interface.h
diff --git a/release/scripts/startup/bl_ui/properties_data_armature.py b/release/scripts/startup/bl_ui/properties_data_armature.py
index 8261f0c..b98eaf8 100644
--- a/release/scripts/startup/bl_ui/properties_data_armature.py
+++ b/release/scripts/startup/bl_ui/properties_data_armature.py
@@ -161,6 +161,56 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
sub.operator("pose.group_deselect", text="Deselect")
+previews = None
+
+
+def pose_preview_items(poselib, context):
+ global previews
+ import os.path
+
+ if context is None or not poselib.pose_previews_dir:
+ return []
+
+ directory = bpy.path.abspath(poselib.pose_previews_dir)
+ if not os.path.isdir(directory):
+ return []
+
+ if previews is not None and directory == previews.get('pose_previews_dir', None):
+ return previews.pose_previews
+
+ if previews is None:
+ previews = bpy.utils.previews.new()
+ else:
+ previews.clear()
+
+ no_thumbnail = os.path.join(os.path.dirname(__file__),
+ 'thumbnails',
+ 'no_thumbnail.png')
+ no_thumb_thumb = previews.load('NO THUMBNAIL', no_thumbnail, 'IMAGE')
+
+ enum_items = []
+ for pose_idx, pose_marker in enumerate(poselib.pose_markers):
+ filepath = os.path.join(directory, '%s.png' % pose_marker.name)
+ if os.path.exists(filepath):
+ thumb = previews.load(pose_marker.name, filepath, 'IMAGE')
+ else:
+ print('Warning: "%s" does not exist' % filepath)
+ thumb = no_thumb_thumb
+
+ enum_items.append((pose_marker.name, pose_marker.name, pose_marker.name,
+ thumb.icon_id, pose_idx))
+
+ previews.pose_previews = enum_items
+ previews['pose_previews_dir'] = directory
+ return previews.pose_previews
+
+
+def update_pose(poselib_action, context):
+ pose_name = poselib_action.pose_previews
+ poselib_action.pose_markers.active = poselib_action.pose_markers[pose_name]
+ bpy.ops.poselib.apply_pose(pose_index=poselib_action.pose_markers.active_index)
+
+
class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
bl_label = "Pose Library"
bl_options = {'DEFAULT_CLOSED'}
@@ -177,33 +227,50 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
layout.template_ID(ob, "pose_library", new="poselib.new", unlink="poselib.unlink")
- if poselib:
- # list of poses in pose library
- row = layout.row()
- row.template_list("UI_UL_list", "pose_markers", poselib, "pose_markers",
- poselib.pose_markers, "active_index", rows=5)
+ if not poselib:
+ return
+
+ # layout.template_icon_view(
+ # poselib, 'pose_markers',
+ # show_labels=True,
+ # )
+ # list of poses in pose library
+ row = layout.row()
+ row.template_list("UI_UL_list", "pose_markers", poselib, "pose_markers",
+ poselib.pose_markers, "active_index",
+ rows=5)
+ # column of operators for active pose
+ # - goes beside list
+ col = row.column(align=True)
+
+ # invoke should still be used for 'add', as it is needed to allow
+ # add/replace options to be used properly
+ col.operator("poselib.pose_add", icon='ZOOMIN', text="")
+ pose_marker_active = poselib.pose_markers.active
- # column of operators for active pose
- # - goes beside list
- col = row.column(align=True)
+ # The following operators just need to be executed, not invoked;
+ # otherwise they show a menu which we don't want.
+ col.operator_context = 'EXEC_DEFAULT'
- # invoke should still be used for 'add', as it is needed to allow
- # add/replace options to be used properly
- col.operator("poselib.pose_add", icon='ZOOMIN', text="")
+ if pose_marker_active:
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list