2009-12-17 19:48:30 +00:00
# ##### 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,
2010-02-12 13:34:04 +00:00
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2009-12-17 19:48:30 +00:00
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
import bpy
2010-09-09 06:29:44 +00:00
from bpy . props import *
2009-12-17 19:48:30 +00:00
2010-09-09 06:29:44 +00:00
class PoseTemplate ( bpy . types . IDPropertyGroup ) :
2010-09-10 04:04:48 +00:00
name = StringProperty ( name = " Name of the slave " , description = " " , maxlen = 64 , default = " " )
2009-12-17 19:48:30 +00:00
2010-09-09 06:29:44 +00:00
class PoseTemplateSettings ( bpy . types . IDPropertyGroup ) :
templates = CollectionProperty ( type = PoseTemplate , name = " Templates " , description = " " )
2010-09-10 16:07:18 +00:00
active_template_index = IntProperty ( name = " Index of the active slave " , description = " " , default = - 1 , min = - 1 , max = 65535 )
use_generate_deform_rig = BoolProperty ( name = " Create Deform Rig " , description = " Create a copy of the metarig, constrainted by the generated rig " , default = False )
2009-12-17 19:48:30 +00:00
def metarig_templates ( ) :
import rigify
return rigify . get_submodule_types ( )
class DATA_PT_template ( bpy . types . Panel ) :
bl_label = " Meta-Rig Templates "
bl_space_type = ' PROPERTIES '
bl_region_type = ' WINDOW '
bl_context = " data "
2010-08-26 01:05:37 +00:00
bl_options = { ' DEFAULT_CLOSED ' }
2009-12-17 19:48:30 +00:00
templates = [ ]
2010-08-09 01:37:09 +00:00
@classmethod
def poll ( cls , context ) :
2009-12-20 23:34:05 +00:00
if not context . armature :
return False
2009-12-17 19:48:30 +00:00
obj = context . object
if obj :
return ( obj . mode in ( ' POSE ' , ' OBJECT ' ) )
return False
def draw ( self , context ) :
layout = self . layout
try :
active_type = context . active_pose_bone [ " type " ]
except :
active_type = None
scene = context . scene
pose_templates = scene . pose_templates
if pose_templates . active_template_index == - 1 :
pose_templates . active_template_index = 0
if not self . templates :
self . templates [ : ] = metarig_templates ( )
while ( len ( pose_templates . templates ) < len ( self . templates ) ) :
pose_templates . templates . add ( )
while ( len ( pose_templates . templates ) > len ( self . templates ) ) :
pose_templates . templates . remove ( 0 )
for i , template_name in enumerate ( self . templates ) :
template = pose_templates . templates [ i ]
if active_type == template_name :
template . name = " < %s > " % template_name . replace ( " _ " , " " )
else :
template . name = " %s " % template_name . replace ( " _ " , " " )
row = layout . row ( )
row . operator ( " pose.metarig_generate " , text = " Generate " )
row . operator ( " pose.metarig_validate " , text = " Check " )
row . operator ( " pose.metarig_graph " , text = " Graph " )
row = layout . row ( )
2010-08-20 06:09:58 +00:00
row . prop ( pose_templates , " use_generate_deform_rig " )
2009-12-17 19:48:30 +00:00
row = layout . row ( )
col = row . column ( )
col . template_list ( pose_templates , " templates " , pose_templates , " active_template_index " , rows = 1 )
subrow = col . split ( percentage = 0.5 , align = True )
subsubrow = subrow . row ( align = True )
subsubrow . operator ( " pose.metarig_assign " , text = " Assign " )
subsubrow . operator ( " pose.metarig_clear " , text = " Clear " )
2010-08-10 18:21:33 +00:00
if self . templates :
subsubrow = subrow . split ( percentage = 0.8 )
subsubrow . operator ( " pose.metarig_sample_add " , text = " Sample " ) . metarig_type = self . templates [ pose_templates . active_template_index ]
2010-09-07 15:17:42 +00:00
subsubrow . operator ( " pose.metarig_sample_add " , text = " All " ) . metarig_type = " " # self.templates[pose_templates.active_template_index]
2009-12-17 19:48:30 +00:00
2010-08-10 18:21:33 +00:00
sub = row . column ( align = True )
sub . operator ( " pose.metarig_reload " , icon = " FILE_REFRESH " , text = " " )
2009-12-17 19:48:30 +00:00
class Reload ( bpy . types . Operator ) :
''' Re-Scan the metarig package directory for scripts '''
bl_idname = " pose.metarig_reload "
bl_label = " Re-Scan the list of metarig types "
def execute ( self , context ) :
DATA_PT_template . templates [ : ] = metarig_templates ( )
2009-12-24 19:50:43 +00:00
return { ' FINISHED ' }
2009-12-17 19:48:30 +00:00
def rigify_report_exception ( operator , exception ) :
import traceback
import sys
import os
# find the module name where the error happened
# hint, this is the metarig type!
exceptionType , exceptionValue , exceptionTraceback = sys . exc_info ( )
fn = traceback . extract_tb ( exceptionTraceback ) [ - 1 ] [ 0 ]
fn = os . path . basename ( fn )
fn = os . path . splitext ( fn ) [ 0 ]
message = [ ]
if fn . startswith ( " __ " ) :
message . append ( " Incorrect armature... " )
else :
message . append ( " Incorrect armature for type ' %s ' " % fn )
message . append ( exception . message )
2010-09-07 15:17:42 +00:00
message . reverse ( ) # XXX - stupid! menu's are upside down!
2009-12-17 19:48:30 +00:00
operator . report ( set ( [ ' INFO ' ] ) , ' \n ' . join ( message ) )
class Generate ( bpy . types . Operator ) :
''' Generates a metarig from the active armature '''
bl_idname = " pose.metarig_generate "
bl_label = " Generate Metarig "
def execute ( self , context ) :
import rigify
reload ( rigify )
2010-08-20 06:09:58 +00:00
meta_def = context . scene . pose_templates . use_generate_deform_rig
2009-12-17 19:48:30 +00:00
try :
rigify . generate_rig ( context , context . object , META_DEF = meta_def )
except rigify . RigifyError as rig_exception :
rigify_report_exception ( self , rig_exception )
2009-12-24 19:50:43 +00:00
return { ' FINISHED ' }
2009-12-17 19:48:30 +00:00
class Validate ( bpy . types . Operator ) :
''' Validate a metarig from the active armature '''
bl_idname = " pose.metarig_validate "
bl_label = " Validate Metarig "
def execute ( self , context ) :
import rigify
reload ( rigify )
try :
rigify . validate_rig ( context , context . object )
except rigify . RigifyError as rig_exception :
rigify_report_exception ( self , rig_exception )
2009-12-24 19:50:43 +00:00
return { ' FINISHED ' }
2009-12-17 19:48:30 +00:00
class Sample ( bpy . types . Operator ) :
''' Create a sample metarig to be modified before generating the final rig. '''
bl_idname = " pose.metarig_sample_add "
bl_label = " Re-Scan Metarig Scripts "
metarig_type = StringProperty ( name = " Type " , description = " Name of the rig type to generate a sample of, a blank string for all " , maxlen = 128 , default = " " )
def execute ( self , context ) :
import rigify
reload ( rigify )
2010-09-10 23:39:43 +00:00
final = ( self . metarig_type == " " )
objects = rigify . generate_test ( context , metarig_type = self . metarig_type , GENERATE_FINAL = final )
2009-12-17 19:48:30 +00:00
if len ( objects ) > 1 :
for i , ( obj_meta , obj_gen ) in enumerate ( objects ) :
obj_meta . location . x = i * 1.0
if obj_gen :
obj_gen . location . x = i * 1.0
2009-12-24 19:50:43 +00:00
return { ' FINISHED ' }
2009-12-17 19:48:30 +00:00
class Graph ( bpy . types . Operator ) :
''' Create a graph from the active armature through graphviz '''
bl_idname = " pose.metarig_graph "
bl_label = " Pose Graph "
def execute ( self , context ) :
import os
import graphviz_export
import bpy
reload ( graphviz_export )
obj = bpy . context . object
2010-08-06 01:40:54 +00:00
path = os . path . splitext ( bpy . data . filepath ) [ 0 ] + " - " + bpy . path . clean_name ( obj . name )
2009-12-17 19:48:30 +00:00
path_dot = path + " .dot "
path_png = path + " .png "
saved = graphviz_export . graph_armature ( bpy . context . object , path_dot , CONSTRAINTS = False , DRIVERS = False )
if saved :
# if we seriously want this working everywhere we'll need some new approach
2009-12-17 21:53:33 +00:00
os . system ( " dot -Tpng %s > %s ; gnome-open %s & " % ( path_dot , path_png , path_png ) )
#os.system("python /b/xdot.py '%s' &" % path_dot)
2009-12-17 19:48:30 +00:00
2009-12-24 19:50:43 +00:00
return { ' FINISHED ' }
2009-12-17 19:48:30 +00:00
class AsScript ( bpy . types . Operator ) :
''' Write the edit armature out as a python script '''
bl_idname = " pose.metarig_to_script "
bl_label = " Write Metarig to Script "
2010-03-01 00:03:51 +00:00
bl_options = { ' REGISTER ' , ' UNDO ' }
2009-12-17 19:48:30 +00:00
2010-06-14 03:52:10 +00:00
filepath = StringProperty ( name = " File Path " , description = " File path used for exporting the Armature file " , maxlen = 1024 , default = " " )
2009-12-17 19:48:30 +00:00
def execute ( self , context ) :
import rigify_utils
reload ( rigify_utils )
obj = context . object
code = rigify_utils . write_meta_rig ( obj )
2010-09-10 23:39:43 +00:00
path = self . filepath
2009-12-17 19:48:30 +00:00
file = open ( path , " w " )
file . write ( code )
file . close ( )
2009-12-24 19:50:43 +00:00
return { ' FINISHED ' }
2009-12-17 19:48:30 +00:00
def invoke ( self , context , event ) :
import os
obj = context . object
2010-09-10 23:39:43 +00:00
self . filepath = os . path . splitext ( bpy . data . filepath ) [ 0 ] + " - " + bpy . path . clean_name ( obj . name ) + " .py "
2010-09-02 04:53:05 +00:00
wm = context . window_manager
2009-12-17 19:48:30 +00:00
wm . add_fileselect ( self )
2009-12-24 21:17:14 +00:00
return { ' RUNNING_MODAL ' }
2009-12-17 19:48:30 +00:00
# operators that use the GUI
class ActiveAssign ( bpy . types . Operator ) :
''' Assign to the active posebone '''
bl_idname = " pose.metarig_assign "
bl_label = " Assign to the active posebone "
2010-08-09 01:37:09 +00:00
@classmethod
def poll ( cls , context ) :
2009-12-17 19:48:30 +00:00
bone = context . active_pose_bone
return bool ( bone and bone . id_data . mode == ' POSE ' )
def execute ( self , context ) :
scene = context . scene
pose_templates = scene . pose_templates
template_name = DATA_PT_template . templates [ pose_templates . active_template_index ]
context . active_pose_bone [ " type " ] = template_name
2009-12-24 19:50:43 +00:00
return { ' FINISHED ' }
2009-12-17 19:48:30 +00:00
class ActiveClear ( bpy . types . Operator ) :
''' Clear type from the active posebone '''
bl_idname = " pose.metarig_clear "
bl_label = " Metarig Clear Type "
2010-08-09 01:37:09 +00:00
@classmethod
def poll ( cls , context ) :
2009-12-17 19:48:30 +00:00
bone = context . active_pose_bone
return bool ( bone and bone . id_data . mode == ' POSE ' )
def execute ( self , context ) :
scene = context . scene
2010-02-15 13:30:26 +00:00
try :
del context . active_pose_bone [ " type " ]
except :
return { ' CANCELLED ' }
2009-12-24 19:50:43 +00:00
return { ' FINISHED ' }
2009-12-17 19:48:30 +00:00
2009-12-25 22:16:19 +00:00
class INFO_MT_armature_metarig_add ( bpy . types . Menu ) :
2009-12-17 19:48:30 +00:00
bl_idname = " INFO_MT_armature_metarig_add "
bl_label = " Meta-Rig "
def draw ( self , context ) :
import rigify
layout = self . layout
layout . operator_context = ' INVOKE_REGION_WIN '
for submodule_type in rigify . get_submodule_types ( ) :
2010-08-06 01:40:54 +00:00
text = bpy . path . display_name ( submodule_type )
2009-12-17 19:48:30 +00:00
layout . operator ( " pose.metarig_sample_add " , text = text , icon = ' OUTLINER_OB_ARMATURE ' ) . metarig_type = submodule_type
menu_func = ( lambda self , context : self . layout . menu ( " INFO_MT_armature_metarig_add " , icon = ' OUTLINER_OB_ARMATURE ' ) )
2010-09-07 15:17:42 +00:00
import space_info # ensure the menu is loaded first
2010-02-14 11:21:21 +00:00
2010-02-22 23:32:58 +00:00
2010-02-14 11:21:21 +00:00
def register ( ) :
2010-09-09 06:29:44 +00:00
bpy . types . Scene . pose_templates = PointerProperty ( type = PoseTemplateSettings , name = " Pose Templates " , description = " Pose Template Settings " )
2010-02-14 11:21:21 +00:00
space_info . INFO_MT_armature_add . append ( menu_func )
2010-02-22 23:32:58 +00:00
2010-02-14 11:21:21 +00:00
def unregister ( ) :
2010-09-09 17:41:36 +00:00
del bpy . types . Scene . pose_templates
2010-07-31 18:06:55 +00:00
space_info . INFO_MT_armature_add . remove ( menu_func )
2010-02-16 09:55:07 +00:00
if __name__ == " __main__ " :
register ( )