Page Menu
Home
Search
Configure Global Search
Log In
Files
F7996
PoseLib16.py
Public
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Authored By
Brendon Murphy (meta-androcto)
Nov 13 2013, 1:50 PM
Size
233 KB
Subscribers
None
PoseLib16.py
View Options
#!BPY
""" Registration info for Blender menus:
Name: '_Blender Pose Handler'
Blender: 242
Group: 'Animation'
Tooltip: 'Specialized saving and loading of Blender Library-style poses'
"""
__author__
=
[
"Basil_Fawlty/Cage_drei (Andrew Cruse)"
]
__url__
=
(
"http://wiki.blender.org/index.php/Extensions:Py/Scripts/Manual/Animation/PoseLib16"
,
"http://www.kuroyumes-developmentzone.com/~Cage/PoseLib16.zip"
)
__version__
=
"1.0 (Sept 22,2006)"
__email__
=
"Cagedrei@aol.com"
__bpydoc__
=
"""\
This script provides several tools for pose and armature handling. It uses Blender Library type poses
and provides animation support using batch import and export of those poses. It also provides various
tools for pose tweaking and development and can import and export Poser poses.
This script processes bone quaternion rotations four different ways to produce four varieties of poses.
1) Blender Library type. This method seems to embed bone roll data in the pose, making it difficult
to use the pose with armatures other than the source armature.
Save:
quat without processing
Load:
quat without processing
Note: No conversion processing is required for default poses.
2) Restmatrix type (exported in bvh data, also from PoserPython). Essentially lacks embedded bone roll
data in the pose, so the pose can be loaded onto armatures with different bone roll setups.
Save:
quat = (rest_matrix_invert * quat_as_matrix * rest_matrix).toQuat()
Load:
quat = (rest_matrix * quat_as_matrix * rest_matrix_invert).toQuat()
Note: Load restmatrix type poses using the 'Restmatrix pose ('No Roll')' option.
3) Posematrix type. This type uses the poseMatrix to export IK and constraints. This type also embeds
bone roll data.
Save:
quat = (posematrix * parent_posematrix).toQuat()
Load:
quat = (quat_as_matrix * (rest_matrix * parent_rest_matrix_invert).invert()).toQuat()
Note: Load posematrix type poses using the 'Posematrix pose ('IK')' option.
4) Combination posematrix and restmatrix type. Combined correctly, types 2) and 3) can render a pose which
both contains IK and constraint data, but lacks embedded bone roll. This is not simply a matter of encoding
the data both ways on export and import. That works - in the order 3)-2) for export and 2)-3) for import - but
the bone roll information remains embedded. To export the benefits of both, they are processed as they would be
if type 3) were saved, then loaded, then saved again as type 2).
Save:
quat = ((posematrix * parent_posematrix) * (rest_matrix * parent_restmatrix_invert).invert()).toQuat()
This is a combination of the save and load for type three. Then it is passed to the save process for type two.
quat = (rest_matrix_invert * quat_as_matrix * rest_matrix).toQuat()
Load:
quat = (rest_matrix * quat_as_matrix * rest_matrix_invert).toQuat()
Note: Load combination type poses using the 'Restmatrix pose ('No Roll')' option.
That's kind of a shorthand version of the handling in this script. Type 2 poses are based on the work of Campbell Barton.
Type three poses are based on scripts by der_ton and others.
- Save fxn, load fxn, and pose formatting are adapted from Blender Library<br>
- PoseMatrix pose handling adapted from der_ton's md5 I/O scripts<br>
- "No roll"/restmatrix pose handling adapted from Campbell Barton's bvh_import.py for 2.42<br>
- Radians conversion borrowed from xsi export, by "Elira"<br>
- GUI colorbox from discombobulator.py<br>
This script is designed to work with my poser2blender.py for PoserPython
Some elements of this script are still in development:<br>
- Bone layer handling will be added once it is added to the BPy API.<br>
- align_chains and boneroll_correction both need tweaking.<br>
- Poses exported with save_poser are occasionally incorrect. Blender's quaternion to euler conversions don't
seem to return the correct results for this purpose, and no wholly correct conversion method has yet been found.
"""
# --------------------------------------------------------------------------
# Blender Pose Handler V1.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
import
Blender
from
Blender
import
*
from
Blender.Mathutils
import
*
from
Blender.Registry
import
*
from
Blender.Draw
import
*
from
Blender.BGL
import
*
import
math
,
os
,
re
##-------Save Functions----------------------------------------------------
"""
object = Blender.Scene.GetCurrent().getActiveObject()
if not object or object.getType() != 'Mesh':
"""
def
goSave
(
save_name
):
global
EmpPose
,
PoserSave
#print save_name
if
save_name
!=
""
:
poseText
=
""
if
EmpPose
==
1
:
poseText
=
Export_Empties
()
#Export a pose from bvh import empties
elif
EmpPose
==
0
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
pose
=
ob
.
getPose
()
if
PoserSave
==
0
:
#save a Blender Library type pose
for
bone
in
pose
.
bones
.
values
():
savePart
=
save_part
(
bone
)
#check screening with partial groups and bones list
if
savePart
==
1
:
quat
=
bone
.
quat
quat
=
save_convert
(
ob
,
pose
,
bone
,
quat
,
0
)
#posematrix and restmatrix type conversions
poseText
+=
"
%s
,"
%
(
bone
.
name
)
if
No_Trans
==
1
:
poseText
+=
"0.0,0.0,0.0,"
#Don't save translations
elif
No_Trans
==
0
:
poseText
+=
"
%f
,
%f
,
%f
,"
%
(
bone
.
loc
[
0
],
bone
.
loc
[
1
],
bone
.
loc
[
2
])
#Save trans
poseText
+=
"
%f
,
%f
,
%f
,
%f
,"
%
(
quat
[
0
],
quat
[
1
],
quat
[
2
],
quat
[
3
])
if
No_Scale
==
1
:
poseText
+=
"1.0,1.0,1.0
\n
"
#Don't save scaling
elif
No_Scale
==
0
:
poseText
+=
"
%f
,
%f
,
%f
\n
"
%
(
bone
.
size
[
0
],
bone
.
size
[
1
],
bone
.
size
[
2
])
#Save scaling
elif
PoserSave
==
1
:
poseText
=
save_poser
(
ob
,
pose
)
#save a Poser pose
if
poseText
!=
""
:
#Don't proceed if there's nothing to write
if
PoserSave
==
0
:
if
os
.
path
.
splitext
(
save_name
)[
1
]
==
""
:
save_name
+=
".blend"
if
os
.
path
.
splitext
(
save_name
)[
1
]
!=
".blend"
and
os
.
path
.
splitext
(
save_name
)
!=
".bPose"
:
save_name
=
sys
.
makename
(
save_name
,
ext
=
".blend"
,
strip
=
0
)
elif
PoserSave
==
1
:
compress
=
PupMenu
(
"Use file compression? %t|Yes
%x
1|No
%x
2"
)
if
compress
==
2
:
save_name
=
os
.
path
.
splitext
(
save_name
)[
0
]
+
".pz2"
else
:
save_name
=
os
.
path
.
splitext
(
save_name
)[
0
]
+
".p2z"
warning
=
0
if
sys
.
exists
(
save_name
)
==
1
:
warning
=
PupMenu
(
"Overwrite file
%s
?
%%
t|Yes
%%
x1|No
%%
x2"
%
(
sys
.
basename
(
save_name
)))
#Don't overwrite
if
sys
.
exists
(
save_name
)
!=
1
or
warning
!=
2
:
if
compress
==
2
:
text
=
open
(
save_name
,
'w'
)
elif
compress
==
1
:
#save compressed Poser pose
import
gzip
text
=
gzip
.
GzipFile
(
save_name
,
'wb'
)
text
.
write
(
poseText
)
text
.
close
()
Blender
.
Redraw
()
#------check for save part screening (partial groups and bones list)--------------
def
save_part
(
bone
):
global
partVar
,
sideVar
savePart
=
0
if
bonesSave
==
1
and
bone
.
name
in
boxBones
:
savePart
=
1
#Save only bones listbox selections
if
bonesSave
==
2
and
bone
.
name
not
in
boxBones
:
savePart
=
1
#Exclude bones listbox selections from save
if
partVar
==
""
and
sideVar
==
""
and
bonesSave
==
0
:
savePart
=
1
#Partial pose saving
if
partVar
!=
""
:
if
sideVar
!=
""
:
#Symmetrical save
partVar2
=
partVar
.
split
(
"@
%#%
@"
)
for
group
in
range
(
0
,
len
(
partVar2
)):
if
bone
.
name
in
groupsDict
:
if
groupsDict
[
bone
.
name
][:
-
1
]
==
partVar2
[
group
]:
savePart
=
0
if
(
sideVar
==
"right"
or
sideVar
==
"both"
)
and
(
pref
==
1
and
bone
.
name
[:
lenR
]
==
right
)
or
\
(
suff
==
1
and
bone
.
name
[
-
lenR
:]
==
right
):
savePart
=
1
if
(
sideVar
==
"left"
or
sideVar
==
"both"
)
and
(
pref
==
1
and
bone
.
name
[:
lenL
]
==
left
)
or
\
(
suff
==
1
and
bone
.
name
[
-
lenL
:]
==
left
):
savePart
=
1
partVar2
=
partVar
.
split
(
"@
%#%
@"
)
#This allows multiple group handling
for
group
in
range
(
0
,
len
(
partVar2
)):
if
bone
.
name
in
groupsDict
:
if
groupsDict
[
bone
.
name
][:
-
1
]
==
partVar2
[
group
]:
savePart
=
1
return
savePart
#--------run pose type conversions (restmatrix/posematrix)--------------------------------
def
save_convert
(
ob
,
pose
,
bone
,
quat
):
global
IKPose
,
NoRollPose
if
IKPose
==
1
:
quat
=
IK_save
(
bone
,
ob
,
pose
)
#Save pose from bone.poseMatrix()
if
IKPose
==
1
and
NoRollPose
==
1
:
#This enables posematrix poses to have benefits of
bone1
=
pose
.
bones
[
bone
.
name
]
#restmatrix poses (bone roll becomes irrelevant)
quat
=
IK_load
(
bone1
,
quat
,
ob
,
pose
)
if
NoRollPose
==
1
:
quat
=
roll_correction
(
bone
,
quat
)
#Save pose relative to armature rest matrix
return
quat
#-------General save options---------------------------
def
export_options
():
global
EmpPose
,
IKPose
,
NoRollPose
,
OptPose
,
saveBatch
,
LibSave
,
LibPath
,
LibTog
,
LibVar
,
partVar
,
sideVar
,
\
NoRollTog
,
IKTog
expo
=
PupMenu
(
"Save pose options: %t|Save pose from .bvh empties - Load with 'No Roll' option.
%x
1\
|
Save
pose
with
IK
/
constraints
(
poseMatrix
)
-
Load
with
'IK'
option
.
%
x2
\
|
Save
pose
without
embedded
bone
roll
(
restmatrix
)
-
Load
with
'No Roll'
%
x3
\
|
Save
combination
IK
and
'no roll'
-
Load
with
'No Roll'
option
%
x4
\
|
Save
animation
as
batch
of
pose
files
%
x5
\
|
Save
poses
to
current
load
list
folder
(
load
menu
browser
)
%
x6
\
|
Deactivate
all
options
%
x7
|
Cancel
(
Keep
current
options
)
%
x8
")
if
expo
==
1
:
#save pose from empties
EmpPose
=
1
-
EmpPose
IKPose
=
0
NoRollPose
=
0
elif
expo
==
2
:
#save posematrix
IKPose
=
1
-
IKPose
NoRollPose
=
0
EmpPose
=
0
elif
expo
==
3
:
#save restmatrix
NoRollPose
=
1
-
NoRollPose
IKPose
=
0
EmpPose
=
0
elif
expo
==
4
:
#save combination posematrix and restmatrix
NoRollPose
=
IKPose
=
1
-
NoRollPose
EmpPose
=
0
elif
expo
==
5
:
#batch export for animation
saveBatch
=
1
-
saveBatch
elif
expo
==
6
:
#save to menu browse folder
if
LibPath
!=
""
:
LibSave
=
1
-
LibSave
if
LibPath
==
""
:
if
LibTog
==
0
:
sub
=
PupMenu
(
"List load browsing not enabled %t|Enable list browsing
%x
1|Cancel
%x
2"
)
if
LibTog
==
1
:
sub
=
PupMenu
(
"List load folder not specified %t|Select list load folder
%x
1|Cancel
%x
2"
)
if
sub
==
1
:
LibVar
=
LibTog
=
LibSave
=
OptPose
=
1
Window
.
FileSelector
(
list_browser
,
'Select pose folder:'
)
if
LibSave
==
EmpPose
==
IKPose
==
NoRollPose
==
saveBatch
==
0
:
OptPose
=
0
elif
expo
==
7
:
EmpPose
=
IKPose
=
NoRollPose
=
saveBatch
=
OptPose
=
0
#deactivate all
if
EmpPose
==
IKPose
==
NoRollPose
==
saveBatch
==
LibSave
==
0
:
#cancel
OptPose
=
0
NoRollTog
=
NoRollPose
##set the toggle display
IKTog
=
IKPose
#-----save posematrix (IK) conversion----------------------------
#Based (primarily) on der_ton's blender2md5export.py
def
IK_save
(
bone
,
armature
,
pose
):
#Saves a poseMatrix pose - enabling saving of IK and constraints
MATRIX_IDENTITY_4x4
=
Matrix
([
1
,
0
,
0
,
0
],[
0
,
1
,
0
,
0
],[
0
,
0
,
1
,
0
],[
0
,
0
,
0
,
1
])
AData
=
armature
.
getData
()
rest_bone
=
AData
.
bones
[
bone
.
name
]
pose_bone_mat
=
Matrix
(
bone
.
poseMatrix
)
if
rest_bone
.
parent
:
parentposemat
=
Matrix
(
pose
.
bones
[
rest_bone
.
parent
.
name
]
.
poseMatrix
)
else
:
parentposemat
=
MATRIX_IDENTITY_4x4
parentposemat
.
invert
()
finalMatrix
=
pose_bone_mat
*
parentposemat
return
finalMatrix
.
toQuat
()
#-------save restmatrix (no roll) conversion-------------------------------
#Based on Campbell Barton's bvh_import.py for Blender 2.42
def
roll_correction
(
bone
,
quat
):
#This is the inverse of the Poser Convert function, adapted for save
#rx,ry,rz = quat.toEuler().unique() #Saves a pose which will load on another armature, without bone roll problems.
bone_rotation_matrix
=
quat
.
toMatrix
()
#go directly to matrix, skipping euler conversion....
arm
=
Object
.
GetSelected
()[
0
]
AData
=
arm
.
getData
()
bone1
=
AData
.
bones
[
bone
.
name
]
bone_rest_matrix
=
bone1
.
matrix
[
'ARMATURESPACE'
]
.
rotationPart
()
bone_rest_matrix_inv
=
Matrix
(
bone_rest_matrix
)
bone_rest_matrix_inv
.
invert
()
#bone_rotation_matrix= Euler(rx,ry,rz).toMatrix()
finalMatrix
=
bone_rest_matrix_inv
*
bone_rotation_matrix
*
bone_rest_matrix
#Switch the order of multiplication
return
finalMatrix
.
toQuat
()
#--------export empties---------------------------------
def
Export_Empties
():
#Export a pose from .bvh import empties
poseText
=
""
if
EmpPose
==
1
:
objs
=
Blender
.
Scene
.
GetCurrent
()
.
getChildren
()
for
ob
in
objs
:
if
ob
.
getType
()
==
"Empty"
:
if
ob
.
name
[
0
]
==
"_"
:
ob
.
name
=
ob
.
name
[
1
:
len
(
ob
.
name
)]
if
ob
.
name
[
-
4
:]
!=
"_end"
and
ob
.
name
[
0
]
!=
"_"
and
ob
.
name
[
-
4
:]
!=
".001"
:
#omit junk empties
poseText
+=
ob
.
name
+
","
poseText
+=
"0.0,0.0,0.0,"
#translation is ignored
oQuat
=
Euler
(
r2d
(
ob
.
rot
[
0
]),
r2d
(
ob
.
rot
[
1
]),
r2d
(
ob
.
rot
[
2
]))
.
unique
()
.
toQuat
()
#radians to degrees
poseText
+=
"
%f
,
%f
,
%f
,
%f
,"
%
(
oQuat
[
0
],
oQuat
[
1
],
oQuat
[
2
],
oQuat
[
3
])
poseText
+=
"1.0,1.0,1.0
\n
"
#Ignore scaling, too.
return
poseText
# ---------------------------------------------------------------------------
# r2d - radians to degrees (from .xsi export, by "Elira")
# ---------------------------------------------------------------------------
def
r2d
(
r
):
return
round
(
r
*
180.0
/
math
.
pi
,
4
)
#Approx. 57.295828 before rounding
#----save partial groups menu-------------------------------------
def
partSave
():
#Combination toggle/popup for partial save specification.
global
partVar
,
sideVar
,
TrimPose
,
maxVal
,
minVal
,
bonesSave
,
boxBones
groupcount
=
[]
#Dict for list of parts visible to user
groupsides
=
[]
#Dict for internal version of parts (includes symmetry flag)
puplist
=
""
#The menu list
partvar
=
""
sideVar
=
""
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
if
groupsDict
==
{}:
groups
()
#Find body part groups for partial save
if
flipDict
==
{}:
flip
()
for
group
in
groupsDict
.
values
():
#Fill the menu list from the groupsDict
if
groupsides
.
count
(
group
)
<
1
:
groupsides
.
append
(
group
)
groupcount
.
append
(
group
[:
-
1
])
#Make the cleaned-up version visible
groupcount
.
sort
()
groupsides
.
sort
()
noGroups
=
"No groups found. Try changing selection parameters."
if
groupcount
==
[]:
groupcount
.
append
(
noGroups
)
for
i
in
range
(
0
,
len
(
groupcount
)):
puplist
+=
"
%s
%%
x
%i
|"
%
(
groupcount
[
i
],
i
+
1
)
if
i
==
len
(
groupcount
)
-
1
:
puplist
+=
"Alter automatic group selection parameters
%%
x
%i
|"
%
(
i
+
2
)
puplist
+=
"Save only bones listbox selections in pose
%%
x
%i
|"
%
(
i
+
3
)
puplist
+=
"Exclude bones listbox selections from saved pose
%%
x
%i
|"
%
(
i
+
4
)
puplist
+=
"Deactivate all groups
%%
x
%i
|"
%
(
i
+
5
)
puplist
+=
"Cancel (Keep current options)
%%
x
%i
"
%
(
i
+
6
)
partList
=
PupMenu
(
"Select partial pose group or bones list screening: %t|"
+
puplist
)
for
part
in
range
(
1
,
len
(
groupcount
)
+
1
):
if
partList
==
part
and
groupcount
[
0
]
!=
noGroups
:
partVar
+=
groupcount
[
part
-
1
]
partVar
+=
"@
%#%
@"
#Pick an unlikely sequence of symbols to split multiple entries for multiple group selections
if
groupsides
[
part
-
1
][
-
1
:]
==
"!"
:
#Check notation to see if it's centered
sideVar
=
symmetrical_save
()
#Symmetry handling
if
sideVar
==
""
:
partVar
=
""
#Cancelled during symmetry selection
#break
if
partList
==
len
(
groupcount
)
+
1
:
#Change automatic group selection parameters
maxVal
=
PupIntInput
(
"Max group size:"
,
totalBones
/
2
,
1
,
totalBones
-
1
)
if
maxVal
==
0
or
maxVal
==
None
:
maxVal
=
1
#Avoid division by zero errors
maxVal
=
int
(
totalBones
/
maxVal
)
#Convert target size to divisor value
if
maxVal
==
0
or
maxVal
==
None
:
maxVal
=
1
minVal
=
PupIntInput
(
"Min group size:"
,
3
,
0
,
totalBones
-
1
)
if
minVal
==
None
:
minVal
=
2
partVar
=
sideVar
=
""
groups
()
if
partVar
==
""
and
sideVar
==
""
:
TrimPose
=
0
elif
partList
==
len
(
groupcount
)
+
2
or
partList
==
len
(
groupcount
)
+
3
:
if
partVar
!=
""
:
ask
=
PupMenu
(
"Options %t|Combine listbox selection with partial save group(s)
%x
1\
|
Deactivate
partial
save
group
(
s
)
%
x2
|
Cancel
%
x3
")
if
ask
==
2
:
partVar
=
""
sideVar
=
""
if
ask
==
3
:
return
if
partList
==
len
(
groupcount
)
+
2
:
#bones list save inclusive
if
boxBones
==
[]:
error
=
PupMenu
(
"No current bone listbox selection. %t|Please make a bone listbox selection."
)
else
:
if
bonesSave
==
1
:
bonesSave
=
0
elif
bonesSave
==
0
or
bonesSave
==
2
:
bonesSave
=
1
#1 is inclusive
elif
partList
==
len
(
groupcount
)
+
3
:
#bones list save exclusive
if
boxBones
==
[]:
error
=
PupMenu
(
"No current bone listbox selection. %t|Please make a bone listbox selection."
)
else
:
if
bonesSave
==
2
:
bonesSave
=
0
elif
bonesSave
==
0
or
bonesSave
==
1
:
bonesSave
=
2
#2 is exclusive
elif
partList
==
len
(
groupcount
)
+
4
or
\
(
partList
==
1
and
groupcount
[
0
]
==
noGroups
):
#Deactivate all
TrimPose
=
0
partVar
=
""
sideVar
=
""
bonesSave
=
0
if
partVar
==
sideVar
==
""
and
bonesSave
==
0
:
TrimPose
=
0
#Cancel
else
:
TrimPose
=
0
#No armature selection
error
=
PupMenu
(
"Error.%t|Please select an Armature"
)
def
symmetrical_save
():
#Select the side if a group is symmetrized
sideList
=
PupMenu
(
"Select side(s) to save in pose: %t|Right
%x
1|Left
%x
2|Both
%x
3|Cancel
%x
4"
)
if
sideList
==
1
:
sideVar
=
"right"
elif
sideList
==
2
:
sideVar
=
"left"
elif
sideList
==
3
:
sideVar
=
"both"
else
:
sideVar
=
""
return
sideVar
##-------Load Functions (and "real time" application)-------------------------------------------------
def
load_pose
(
file_name
):
global
bodyscale
,
PoserConvert
,
flipbone
,
realTime
,
right
,
left
,
lenR
,
lenL
ext
=
os
.
path
.
splitext
(
file_name
)[
1
]
if
ext
==
".pz2"
or
ext
==
".p2z"
or
ext
==
".hd2"
or
ext
==
".hdz"
:
#Poser pose loading
load_poser_pose
(
file_name
)
return
if
file_name
!=
""
or
realTime
==
1
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
if
groupsDict
==
{}:
groups
()
#partial groups and root part definition
pose
=
ob
.
getPose
()
if
realTime
==
0
:
#realTime is a toggle variable which enables us to multitask this loop.
txt
=
open
(
file_name
,
"r"
)
#With realTime == 0, we load a pose from a textfile.
lines
=
txt
.
readlines
()
#With realTime == 1, we apply selected changes (from gui buttons) to
if
realTime
==
1
:
#the current armature pose, without loading a file.
lines
=
pose
.
bones
.
values
()
for
line
in
lines
:
if
realTime
==
0
:
data
=
line
.
rstrip
(
"
\n
"
)
.
split
(
","
)
bone
=
pose
.
bones
[
data
[
0
]]
if
realTime
==
1
:
#collect the bone's data in the form passed by a saved pose
bone
=
line
loc
=
bone
.
loc
quat
=
bone
.
quat
size
=
bone
.
size
data
=
(
bone
.
name
,
loc
[
0
],
loc
[
1
],
loc
[
2
],
quat
[
0
],
quat
[
1
],
quat
[
2
],
quat
[
3
],
size
[
0
],
size
[
1
],
size
[
2
])
if
bone
:
if
flipDict
==
{}:
flip
()
#Opposite side bones
flipbone
=
""
screening
=
0
#Flag variable to exclude a bone from handling in this loop
if
ExcludePart
==
1
:
screening
=
Part_Load
(
bone
,
0
)
#Exclude selected partial save group when loading
if
IncludePart
==
1
:
screening
=
Part_Load
(
bone
,
1
)
#Use only selected partial save group when loading
if
bonesLoad
==
1
and
bone
.
name
not
in
boxBones
:
screening
=
1
#Load only bones listbox selections
if
bonesLoad
==
2
and
bone
.
name
in
boxBones
:
screening
=
1
#Exclude bones listbox selections when loading
if
(
ScreenPose
==
1
or
DupPose
==
1
)
and
screening
==
0
:
screening
=
Screen_Pose
(
bone
.
name
,
pose
)
#Screen out right or left side when loading
#------HipPose and bodyscale are still formatted for cr2-derived armatures
#------The HipPose functions should still find the root in an armature, however.
#root and rootchild are inherited from the groups() fxn.
if
bone
.
name
==
"BODY"
and
root
.
name
==
bone
.
name
and
bodyscale
==
0
:
#On/off for BODY (root)
screening
=
1
#Poser-specific
#print bone.name, bone.loc, root.name, screening, rootchild
noRot
=
0
noTrans
=
0
if
HipPose
==
1
:
#On/off for root OR for hip (child of root) if root is BODY (as w/ Poser cr2)
if
(
bone
.
name
==
"hip"
and
rootchild
!=
None
and
bone
.
name
==
rootchild
.
name
)
or
\
(
bone
.
name
==
root
.
name
and
bone
.
name
!=
"BODY"
):
#print "root: ", root, "rootchild: ", rootchild, HipPose, hipR, hipT
if
hipR
==
1
:
noRot
=
1
if
hipT
==
1
:
noTrans
=
1
#Need to clean this up. Five variables?
#---------------------------------------
if
screening
==
0
:
if
noTrans
==
1
:
loc
=
bone
.
loc
#loc = Vector(0,0,0)
if
noTrans
==
0
:
#We start applying the values (from Blender Library).
loc
=
Vector
(
data
[
1
],
data
[
2
],
data
[
3
])
if
noRot
==
1
:
quat
=
bone
.
quat
#quat = Quaternion(1,0,0,0)
if
noRot
==
0
:
quat
=
Quaternion
(
data
[
4
],
data
[
5
],
data
[
6
],
data
[
7
])
if
bodyscale
==
1
and
addscale
==
1
and
bone
.
name
==
root
.
name
:
quat
=
MixPose
(
quat
,
bone
,
0
,
0
)
#Additive rotation for BODY - cr2 armature-specific
#------------------pose type conversions
if
PoserConvert
==
1
:
quat
=
Poser_Conversion
(
bone
,
quat
,
noRot
)
#Convert Poser export/"empty" pose/restmatrix "no roll" pose
if
PoseMat
==
1
:
quat
=
IK_load
(
bone
,
quat
,
ob
,
pose
)
#Convert poseMatrix "IK" pose
#------------------------------combinatory modifiers
if
noRot
==
0
:
if
partPose
!=
1.0
:
quat
=
Partial_Pose
(
quat
,
0
,
0
)
#Apply pose partially, from slider value
loc
=
Partial_Pose
(
0
,
loc
,
1
)
#translation
if
MixPose
==
1
:
quat
=
Mix_Pose
(
quat
,
bone
,
0
,
0
)
#Mix pose with current armature rotation
loc
=
Mix_Pose
(
0
,
bone
,
loc
,
1
)
#translation
bone
.
loc
=
loc
bone
.
quat
=
quat
size
=
Vector
(
data
[
8
],
data
[
9
],
data
[
10
])
#Finish applying base values (Blender Library)
bone
.
size
=
size
#--------Symmetry stuff----------------------------------------
if
DupPose
==
1
:
#Duplicate sides (Symmetry Right/Left button)
if
bone
.
name
in
flipDict
:
flipbone
=
flipDict
[
bone
.
name
]
flipbone
=
pose
.
bones
[
flipbone
]
loc
=
Flip_Pose2
(
0
,
loc
,
2
)
flipbone
.
loc
=
loc
quat
=
Flip_Pose2
(
quat
,
0
,
1
)
flipbone
.
quat
=
quat
else
:
#Zero the torso chain or other un-mirrored parts
#This checks the flipDict. Would it be better to check for centered parts, as w/ groups?
if
torsoZero
==
0
:
bone
.
loc
=
Flip_Zero
(
0
,
loc
,
2
)
bone
.
quat
=
Flip_Zero
(
quat
,
0
,
1
)
if
MirrorPose
==
1
or
MirrorBone
==
1
:
#Mirror pose (Flip Pose button)
if
bone
.
name
not
in
flipDict
or
MirrorBone
==
1
:
#1 - parts not mirrored
quat
=
Flip_Pose2
(
bone
.
quat
,
0
,
1
)
loc
=
Flip_Pose2
(
0
,
bone
.
loc
,
2
)
bone
.
quat
=
quat
bone
.
loc
=
loc
#-------End symmetry stuff. End main loop-----------------------------------------
else
:
#If body part in pose doesn't match any bones, just overlook it
pass
#-----------Last part of flip (outside loop)------------------------------------------------
#Symmetrical parts are mirrored in a separate loop. All data for both sides needs to
#be available from the outset, which isn't true when reading a pose - so the function
#is run outside the main loop.
if
MirrorPose
==
1
and
MirrorBone
==
0
:
#These are mutually exclusive, so this is redundant
for
bone
in
pose
.
bones
.
values
():
if
bone
.
name
in
flipDict
:
#2 - mirrored parts
screening
=
0
#repeat the partial groups screening from the main loop....
if
ExcludePart
==
1
:
screening
=
Part_Load
(
bone
,
0
)
if
IncludePart
==
1
:
screening
=
Part_Load
(
bone
,
1
)
if
bonesLoad
==
1
and
bone
.
name
not
in
boxBones
:
screening
=
1
if
bonesLoad
==
2
and
bone
.
name
in
boxBones
:
screening
=
1
if
screening
==
0
:
flipbone
=
pose
.
bones
[
flipDict
[
bone
.
name
]]
quat
=
Flip_Pose2
(
flipbone
.
quat
,
0
,
1
)
loc
=
Flip_Pose2
(
0
,
flipbone
.
loc
,
2
)
flipquat
=
Flip_Pose2
(
bone
.
quat
,
0
,
1
)
fliploc
=
Flip_Pose2
(
0
,
bone
.
loc
,
2
)
bone
.
quat
=
quat
bone
.
loc
=
loc
flipbone
.
quat
=
flipquat
flipbone
.
loc
=
fliploc
del
flipDict
[
bone
.
name
]
del
flipDict
[
flipbone
.
name
]
#-----------------------------------------------------------------------------------------------
if
askKey
!=
2
:
if
askKey
==
0
:
#Ipo curve handling replaces Blender Library keyframing, which was slow.
c
=
PupMenu
(
"Insert pose keys for this frame?%t|Yes
%x
1|No
%x
2"
)
if
askKey
==
1
:
c
=
1
if
c
==
1
:
for
bone
in
pose
.
bones
.
values
():
add_curves
(
ob
,
pose
,
bone
.
name
,
bone
.
quat
,
bone
.
loc
,
bone
.
size
,
Blender
.
Get
(
'curframe'
))
if
realTime
==
0
:
txt
.
close
()
if
realTime
==
1
:
realTime
=
1
-
realTime
if
askKey
!=
2
:
#openBatch sets askKey to 2. This doesn't need to run w/ batch load (not sure why...?).
pose
.
update
()
ob
.
makeDisplayList
()
if
openBatch
==
1
:
#Ipo curve keyframing
for
bone
in
pose
.
bones
.
values
():
add_curves
(
ob
,
pose
,
bone
.
name
,
bone
.
quat
,
bone
.
loc
,
bone
.
size
,
Blender
.
Get
(
'curframe'
))
elif
ob
.
getType
()
!=
"Armature"
:
error
=
PupMenu
(
"Error.%t|Please select an Armature"
)
Blender
.
Redraw
()
flipBone
=
""
flipDict
.
clear
()
#---------------------------------------------------------
def
Mix_Pose
(
quat
,
bone
,
loc
,
switch
):
#Load pose additive to current pose
if
switch
==
0
:
#rotation
x1
,
y1
,
z1
=
quat
.
toEuler
()
.
unique
()
xa
,
ya
,
za
=
bone
.
quat
.
toEuler
()
.
unique
()
qEu
=
Euler
(
x1
+
xa
,
y1
+
ya
,
z1
+
za
)
.
unique
()
return
qEu
.
toQuat
()
if
switch
==
1
:
#translation
x1
,
y1
,
z1
=
loc
xa
,
ya
,
za
=
bone
.
loc
loc
=
Vector
(
x1
+
xa
,
y1
+
ya
,
z1
+
za
)
return
loc
#---------------------------------------------------------
def
Partial_Pose
(
quat
,
loc
,
switch
):
#Apply pose by slider percentage
if
switch
==
0
:
#rotation
xp
,
yp
,
zp
=
quat
.
toEuler
()
.
unique
()
quat
=
Euler
(
xp
*
partPose
,
yp
*
partPose
,
zp
*
partPose
)
.
unique
()
return
quat
.
toQuat
()
if
switch
==
1
:
#translation
xp
,
yp
,
zp
=
loc
loc
=
Vector
(
xp
*
partPose
,
yp
*
partPose
,
zp
*
partPose
)
return
loc
#-----"Screen" sides (exclusion)---------------------------------
#Screen one side, based on symmetry notation, with check to be sure no bone is screened
#which lacks a symmetrical counterpart.
def
Screen_Pose
(
bone_name
,
pose
):
screening
=
0
if
bone_name
in
flipDict
.
keys
():
flipbone
=
flipDict
[
bone_name
]
if
screenL
==
1
:
if
(
pref
==
1
and
flipbone
[:
lenL
]
==
left
)
or
(
suff
==
1
and
flipbone
[
-
lenL
:]
==
left
)
or
\
(
pref
==
1
and
flipbone
[:
len
(
left_alt
)]
==
left_alt
):
screening
=
1
elif
screenR
==
1
:
if
(
pref
==
1
and
flipbone
[:
lenR
]
==
right
)
or
(
suff
==
1
and
flipbone
[
-
lenR
:]
==
right
)
or
\
(
pref
==
1
and
flipbone
[:
len
(
right_alt
)]
==
right_alt
):
screening
=
1
return
screening
#-----Flip pose (mirror)--------------------------------------
#This handles both the "Flip" and "Symmetry" buttons
#With DupPose - not MirrorPose - this inherits its symmetry screening from a ScreenPose call
def
Flip_Pose2
(
quat
,
loc
,
switch
):
if
switch
==
1
:
quat
=
Quaternion
(
quat
[
0
],
quat
[
1
],
-
quat
[
2
],
-
quat
[
3
])
#Use quaternion flipping
#xf,yf,zf = quat.toEuler().unique() #paste_posebuf in poseobject.c simply flips euler signs....
#quat = Euler(xf,-yf,-zf).unique().toQuat()
return
quat
if
switch
==
2
:
loc
=
Vector
(
-
loc
[
0
],
loc
[
1
],
loc
[
2
])
return
loc
#----zeroes un-mirrored bones------------------------
def
Flip_Zero
(
quat
,
loc
,
switch
):
if
switch
==
1
:
quat
=
Quaternion
(
quat
[
0
],
quat
[
1
],
0.0
,
0.0
)
#Quaternion version
#quat = Quaternion(1,0,0,0) #Zero all rotational axes
#xq,yq,zq = quat.toEuler().unique() #Euler version
#quat = Euler(xq,0,0).toQuat() #Just zero y and z
return
quat
if
switch
==
2
:
loc
=
Vector
(
0
,
loc
[
1
],
loc
[
2
])
#Just zero the x
#loc = Vector(0,0,0) #Zero all translation
return
loc
#-----Poser conversion (restmatrix/no roll) import--------------------------------
def
Poser_Conversion
(
bone
,
quat
,
noRot
):
#Based on Campbell Barton's bvh_import.py (for 2.42)
if
noRot
==
0
:
#rx,ry,rz = quat.toEuler().unique() #Work with eulers mainly to reduce changes to Cambo source
bone_rotation_matrix
=
quat
.
toMatrix
()
#go straight to matrix
arm
=
Object
.
GetSelected
()[
0
]
AData
=
arm
.
getData
()
bone1
=
AData
.
bones
[
bone
.
name
]
bone_rest_matrix
=
bone1
.
matrix
[
'ARMATURESPACE'
]
.
rotationPart
()
bone_rest_matrix_inv
=
Matrix
(
bone_rest_matrix
)
bone_rest_matrix_inv
.
invert
()
#bone_rotation_matrix= Euler(rx,ry,rz).toMatrix()
finalMatrix
=
bone_rest_matrix
*
bone_rotation_matrix
*
bone_rest_matrix_inv
return
finalMatrix
.
toQuat
()
#----PoseMatrix/constraints pose import----------------------------------------
# Based (primarily) on der_ton's blender2md5import.py
def
IK_load
(
bone
,
quat
,
armature
,
pose
):
MATRIX_IDENTITY_4x4
=
Matrix
([
1
,
0
,
0
,
0
],[
0
,
1
,
0
,
0
],[
0
,
0
,
1
,
0
],[
0
,
0
,
0
,
1
])
AData
=
armature
.
getData
()
bone1
=
AData
.
bones
[
bone
.
name
]
pose_bone_mat
=
quat
.
toMatrix
()
.
resize4x4
()
bone_rest_matrix
=
bone1
.
matrix
[
'ARMATURESPACE'
]
if
bone1
.
parent
:
parent_restMat
=
bone1
.
parent
.
matrix
[
'ARMATURESPACE'
]
else
:
parent_restMat
=
MATRIX_IDENTITY_4x4
parent_restMat_inv
=
Matrix
(
parent_restMat
)
#make a copy so the actual matrix isn't inverted inadvertantly
parent_restMat_inv
.
invert
()
localMat
=
pose_bone_mat
*
(
bone_rest_matrix
*
parent_restMat_inv
)
.
invert
()
return
localMat
.
toQuat
()
#-------Partial pose group loading------------------------------------------------
def
Part_Load
(
bone
,
switch
):
#Same basic code is seen in the goSave function
#This is used by load_pose and by bonebox_menu
global
partVar
,
sideVar
screening
=
0
if
partVar
==
""
and
sideVar
==
""
:
return
screening
#This is redundant
if
partVar
!=
""
:
if
sideVar
!=
""
:
#With symmetry selection
partVar2
=
partVar
.
split
(
"@
%#%
@"
)
for
group
in
range
(
0
,
len
(
partVar2
)):
if
bone
.
name
in
groupsDict
:
if
groupsDict
[
bone
.
name
][:
-
1
]
==
partVar2
[
group
]:
screening
=
0
if
(
sideVar
==
"right"
or
sideVar
==
"both"
)
and
(
pref
==
1
and
bone
.
name
[:
lenR
]
==
right
)
or
\
(
suff
==
1
and
bone
.
name
[
-
lenR
:]
==
right
):
screening
=
1
if
(
sideVar
==
"left"
or
sideVar
==
"both"
)
and
(
pref
==
1
and
bone
.
name
[:
lenL
]
==
left
)
or
\
(
suff
==
1
and
bone
.
name
[
-
lenL
:]
==
left
):
screening
=
1
partVar2
=
partVar
.
split
(
"@
%#%
@"
)
for
group
in
range
(
0
,
len
(
partVar2
)):
if
bone
.
name
in
groupsDict
:
if
groupsDict
[
bone
.
name
][:
-
1
]
==
partVar2
[
group
]:
screening
=
1
if
switch
==
0
:
return
screening
#Exclude
if
switch
==
1
:
return
1
-
screening
#Include
#--------Loading options menu------------------------------------------------
def
Load_Menu
():
global
bodyscale
,
addscale
,
HipPose
,
hipR
,
hipT
,
LibVar
,
openBatch
,
LibTog
,
\
TrimPose
,
LibPath
,
loadlist
,
poseList
,
askKey
,
torsoZero
,
poseLimit
menu
=
PupMenu
(
"Apply pose options: %t|Toggle menu browser and file browser
%x
1|Exclude root rotation
%x
2\
|
Exclude
root
translation
%
x3
|
Exclude
both
root
rotation
and
translation
%
x4
\
|
Don
't zero un-mirrored parts with '
Symmetry
' button
%x
5\
|
Poser
CR2
'BODY'
handling
%
x6
|
Import
animation
as
batch
of
pose
files
%
x7
\
|
Configure
keyframing
%
x8
|
Configure
menu
browsing
%
x9
|
Deactivate
all
options
%
x10
\
|
Cancel
(
Keep
current
options
)
%
x11
")
if
menu
==
1
:
#toggle menu browser
LibVar
=
1
-
LibVar
#1 = menu, 0 = file selector
if
ListTabTog
==
0
:
LibPath
=
""
#Only clear the path if the listbox browser is closed
loadlist
=
"Pose list browser %t|Browse for a new folder."
poseList
=
[]
elif
menu
==
2
:
#exclude root rot
HipPose
=
hipR
=
1
-
hipR
hipT
=
0
elif
menu
==
3
:
#exclude root trans
HipPose
=
hipT
=
1
-
hipT
hipR
=
0
elif
menu
==
4
:
#exclude both rot and trans for root
HipPose
=
hipR
=
hipT
=
1
elif
menu
==
5
:
torsoZero
=
1
-
torsoZero
#Zero torso chain w/ mirror
elif
menu
==
6
:
#Poser CR2-derived armature special handling
submenu
=
PupMenu
(
"CR2 'BODY' options: %t|Use rotation
%x
1|Use additive rotation
%x
2| Cancel
%x
3"
)
if
submenu
==
1
:
bodyscale
=
1
-
bodyscale
addscale
=
0
elif
submenu
==
2
:
bodyscale
=
addscale
=
1
-
addscale
elif
submenu
==
3
:
bodyscale
=
addscale
=
LibTog
=
0
elif
menu
==
7
:
#Animation load
openBatch
=
1
-
openBatch
elif
menu
==
8
:
#configure keyframing
submenu
=
PupMenu
(
"Keyframing options: %t|Ask every time
%x
1|Add keyframe without asking
%x
2\
|
Don
't add keyframes
%x
3|Remove all keyframes
%x
4|Cancel
%x
5")
if
submenu
==
1
:
askKey
=
0
elif
submenu
==
2
:
askKey
=
1
elif
submenu
==
3
:
askKey
=
2
elif
submenu
==
4
:
remove_keys
()
elif
menu
==
9
:
#Configure menu browser columns
poseLimit
=
PupIntInput
(
"Max list items:"
,
54
,
1
,
100
)
elif
menu
==
10
:
#Deactivate
HipPose
=
hipR
=
hipT
=
bodyscale
=
addscale
=
openBatch
\
=
LibTog
=
askKey
=
LibVar
=
0
#if menu == 11 or menu == 0 or menu == -1 or menu == 11: #Cancel
if
LibVar
==
HipPose
==
hipR
==
hipT
==
bodyscale
==
addscale
\
==
openBatch
==
askKey
==
torsoZero
==
0
:
LibTog
=
0
#-----Load menu for partial group handling--------------------------------
def
GroupLoad_Menu
():
global
IncludePart
,
ExcludePart
,
TrimPose
,
bonesLoad
,
boxBones
,
GroupTog
menu
=
PupMenu
(
"Apply screening options: %t|Load only selected partial save group(s)
%x
1\
|
Exclude
partial
save
group
(
s
)
when
loading
%
x2
|
Load
only
bone
listbox
selections
%
x3
\
|
Exclude
bone
listbox
selections
when
loading
%
x4
|
Deactivate
all
groups
%
x5
\
|
Cancel
(
Keep
current
options
)
%
x6
")
if
menu
==
1
:
#partial inclusive
if
partVar
==
sideVar
==
""
:
error
=
PupMenu
(
"Please select a partial save group."
)
partSave
()
if
partVar
==
sideVar
==
""
:
GroupTog
=
0
if
partVar
!=
""
or
sideVar
!=
""
:
IncludePart
=
1
ExcludePart
=
0
TrimPose
=
1
elif
menu
==
2
:
#partial exclusive
if
partVar
==
sideVar
==
""
:
error
=
PupMenu
(
"Please select a partial save group."
)
partSave
()
if
partVar
==
sideVar
==
""
:
GroupTog
=
0
if
partVar
!=
""
or
sideVar
!=
""
:
IncludePart
=
0
ExcludePart
=
1
TrimPose
=
1
elif
menu
==
3
:
#bones list inclusive
if
boxBones
==
[]:
error
=
PupMenu
(
"No current bone listbox selection. %t|Please make a bone listbox selection."
)
else
:
if
bonesLoad
==
1
:
bonesLoad
=
0
elif
bonesLoad
==
0
or
bonesLoad
==
2
:
bonesLoad
=
1
#1 is inclusive
elif
menu
==
4
:
#bones list exclusive
if
boxBones
==
[]:
error
=
PupMenu
(
"No current bone listbox selection. %t|Please make a bone listbox selection."
)
else
:
if
bonesLoad
==
2
:
bonesLoad
=
0
elif
bonesLoad
==
0
or
bonesLoad
==
1
:
bonesLoad
=
2
#2 is exclusive
elif
menu
==
5
:
#Deactivate
IncludePart
=
ExcludePart
=
bonesLoad
=
GroupTog
=
0
if
IncludePart
==
ExcludePart
==
bonesLoad
==
0
:
#Cancel
GroupTog
=
0
##-----Zero pose fxn-------------------------------------------------------------
#Set pose to zero values (rest position values)
def
Zero_Pose
():
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
pose
=
ob
.
getPose
()
for
bone
in
pose
.
bones
.
values
():
bone
.
loc
=
Vector
(
0.00
,
0.00
,
0.00
)
bone
.
quat
=
Quaternion
(
1.00
,
0.00
,
0.00
,
0.00
)
bone
.
size
=
Vector
(
1.00
,
1.00
,
1.00
)
if
askKey
!=
2
:
if
askKey
==
0
:
c
=
PupMenu
(
"Insert pose keys for this frame?%t|Yes
%x
1|No
%x
2"
)
if
askKey
==
1
:
c
=
1
if
c
==
1
:
for
bone
in
pose
.
bones
.
values
():
add_curves
(
ob
,
pose
,
bone
.
name
,
bone
.
quat
,
bone
.
loc
,
bone
.
size
,
Blender
.
Get
(
'curframe'
))
pose
.
update
()
ob
.
makeDisplayList
()
Blender
.
Redraw
()
##-----Symmetry notation handling----------------------------------------------------------
#Change right and left values to alter default suffix of prefix
#Swap suff and pref values to change default from prefix to suffix
def
Symmetry_Notation
():
global
right
,
left
right
=
PupStrInput
(
"Enter right (-x):"
,
right
,
25
)
left
=
PupStrInput
(
"Enter left (+x):"
,
left
,
25
)
if
right
==
None
:
right
=
"r"
if
left
==
None
:
left
=
"l"
right
=
right
.
replace
(
"."
,
""
)
#Strip the dots (".") because len comparisons don't include them
left
=
left
.
replace
(
"."
,
""
)
lenR
=
len
(
right
)
lenL
=
len
(
left
)
#-----Define the opposite side--------------------------------------
def
flip
():
global
right
,
left
,
suff
,
pref
,
flipbone
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
AData
=
ob
.
getData
()
if
ob
.
getType
()
==
"Armature"
:
AData
=
ob
.
getData
()
flipnames
=
AData
.
bones
.
keys
()
for
name
in
flipnames
:
flipbone
=
"None"
if
suff
==
1
:
if
name
[
-
lenR
:]
==
right
:
flipbone
=
name
[:
-
lenR
]
+
left
elif
name
[
-
lenL
:]
==
left
:
flipbone
=
name
[:
-
lenL
]
+
right
if
pref
==
1
:
if
name
[:
lenR
]
==
right
:
flipbone
=
left
+
name
[
lenR
:]
elif
name
[:
lenL
]
==
left
:
flipbone
=
right
+
name
[
lenL
:]
elif
name
[:
len
(
right_alt
)]
==
right_alt
:
flipbone
=
left_alt
+
name
[
len
(
right_alt
):]
#custom extras
elif
name
[:
len
(
left_alt
)]
==
left_alt
:
flipbone
=
right_alt
+
name
[
len
(
left_alt
):]
if
flipbone
in
flipnames
:
#Don't enter the name if the bone doesn't exist...
flipDict
[
name
]
=
flipbone
#(e.g. - "lowerfoot" might become "rowerfoot" and create a bad entry)
#------Automatically locate partial save groups----------------
def
groups
():
#Fill groups for use with partial pose saves.
global
root
,
rootchild
,
maxVal
,
minVal
,
totalBones
if
flipDict
==
{}:
flip
()
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
AData
=
ob
.
getData
()
groupnames
=
AData
.
bones
.
values
()
groupsDict
.
clear
()
for
group1
in
groupnames
:
if
not
group1
.
hasParent
():
#We assume the root is the bone which has children, but no parent....
if
group1
.
hasChildren
():
root
=
group1
totalBones
=
len
(
group1
.
getAllChildren
())
if
len
(
root
.
children
)
==
1
:
rootchild
=
root
.
children
[
0
]
break
for
group1
in
groupnames
:
if
group1
.
hasChildren
():
if
len
(
group1
.
children
)
>
1
:
for
i
in
group1
.
getAllChildren
():
if
len
(
group1
.
getAllChildren
())
<
totalBones
/
maxVal
and
len
(
group1
.
getAllChildren
())
>=
minVal
:
#Screening parameters are configurable, in the partSave function.
if
round
(
AData
.
bones
[
group1
.
name
]
.
head
[
'ARMATURESPACE'
][
0
],
4
)
==
0.0000
:
add
=
"="
elif
round
(
AData
.
bones
[
group1
.
name
]
.
head
[
'ARMATURESPACE'
][
0
],
4
)
!=
0.0000
:
add
=
"!"
#Determine whether the ultimate parent of group is centered on x.
#(Note: using the flipDict for this proved inadequate....)
if
pref
==
1
and
group1
.
name
[:
lenR
]
==
right
and
group1
.
name
in
flipDict
:
group_name
=
group1
.
name
[
lenR
:]
+
"_parts"
+
add
elif
suff
==
1
and
group1
.
name
[
-
lenR
:]
==
right
and
group1
.
name
in
flipDict
:
group_name
=
group1
.
name
[:
-
lenR
]
+
"_parts"
+
add
elif
pref
==
1
and
group1
.
name
[:
lenL
]
==
left
and
group1
.
name
in
flipDict
:
group_name
=
group1
.
name
[
lenL
:]
+
"_parts"
+
add
elif
suff
==
1
and
group1
.
name
[
-
lenL
:]
==
left
and
group1
.
name
in
flipDict
:
group_name
=
group1
.
name
[:
-
lenL
]
+
"_parts"
+
add
else
:
group_name
=
str
(
group1
.
name
)
+
"_parts"
+
add
group_name
=
group_name
.
lower
()
groupsDict
[
i
.
name
]
=
group_name
##----------Armature and Bone roll functions---------------------------------------------------
#makeEditable() reportedly has a bug. Each implementation seems to require that the function be called
#in a different location, relative to a loop using the Armature.bones dict. Placing it within the loop
#seems to cause a memory error in which Blender system variable names (or memory locations?) are substituted
#for dict keys or values.
#-------Menu for bone functions-----------------------------------------
def
Bone_Menu
():
menu
=
PupMenu
(
"Armature settings options: %t|Save armature settings to .txt
%x
1|Load armature settings from .txt
%x
2\
|
Zero
bone
roll
%
x3
|
Restore
bone
roll
(
in
-
session
only
)
%
x4
|
Correct
bone
roll
angles
for
all
bones
%
x5
\
|
Correct
bone
roll
for
bones
list
bones
%
x6
|
Create
armature
from
.txt
or
.cr2
/.
crz
%
x7
|
Cancel
%
x8
")
if
menu
==
1
:
Window
.
FileSelector
(
boneSave
,
'Save as .txt file.'
)
elif
menu
==
2
:
Window
.
FileSelector
(
boneLoad
,
'Browse for .txt file.'
)
elif
menu
==
3
:
Bone_Roll_Z
()
elif
menu
==
4
:
Bone_Roll_R
()
elif
menu
==
5
:
boneroll_correct
(
0
)
elif
menu
==
6
:
boneroll_correct
(
1
)
elif
menu
==
7
:
Window
.
FileSelector
(
create_armature
,
'Browse for .txt file.'
)
#--------Save armature settings to .txt file-----------------------------
def
boneSave
(
save_name
):
#Saves roll, head, tail, parent, IK target bone, IK chainlen
if
save_name
!=
""
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
temptext
=
""
AData
=
ob
.
getData
()
pose
=
ob
.
getPose
()
option
=
PupMenu
(
"Bones to save? %t|Save all bones in armature
%x
1|Save only bones list selections
%x
2"
)
if
option
==
1
:
templist
=
AData
.
bones
.
values
()
elif
option
==
2
:
templist
=
list
(
AData
.
bones
[
bone
]
for
bone
in
boxBones
)
if
AData
:
for
bone1
in
templist
:
head
=
bone1
.
head
[
'ARMATURESPACE'
]
tail
=
bone1
.
tail
[
'ARMATURESPACE'
]
parent
=
bone1
.
parent
if
parent
==
None
:
parent
=
"None"
else
:
parent
=
parent
.
name
IK
=
"None"
chainlen
=
0
bone
=
pose
.
bones
[
bone1
.
name
]
for
const
in
bone
.
constraints
:
if
const
.
type
==
Constraint
.
Type
.
IKSOLVER
:
IK
=
const
[
Constraint
.
Settings
.
BONE
]
chainlen
=
const
[
Constraint
.
Settings
.
CHAINLEN
]
temptext
+=
"
%s
,
%f
,"
%
(
bone1
.
name
,
bone1
.
roll
[
'ARMATURESPACE'
])
temptext
+=
"
%f
,
%f
,
%f
,"
%
(
head
[
0
],
head
[
1
],
head
[
2
])
temptext
+=
"
%f
,
%f
,
%f
,"
%
(
tail
[
0
],
tail
[
1
],
tail
[
2
])
temptext
+=
"
%s
,
%s
,
%i
\n
"
%
(
parent
,
IK
,
chainlen
)
save_name
=
os
.
path
.
splitext
(
save_name
)[
0
]
+
".txt"
if
sys
.
exists
(
save_name
)
==
1
:
warning
=
PupMenu
(
"Overwrite file
%s
?
%%
t|Yes
%%
x1|No
%%
x2"
%
(
sys
.
basename
(
save_name
)))
#Don't overwrite
if
sys
.
exists
(
save_name
)
!=
1
or
warning
!=
2
:
rollsave
=
open
(
save_name
,
"w"
)
rollsave
.
write
(
temptext
)
rollsave
.
close
()
#--------Load bone roll settings from .txt file---------------------------
def
boneLoad
(
file_name
):
#Loads roll, head, tail, parent, IK target bone, IK chainlen; optionally adds missing bones
warning
=
PupMenu
(
"Warning: This will alter your armature. %t|Load bone roll settings
%x
1\
|
Load
head
and
tail
settings
%
x2
|
Load
parenting
%
x3
|
Load
IK
%
x4
|
Load
IK
with
parenting
%
x5
\
|
Load
all
%
x6
|
Cancel
%
x7
")
if
warning
!=
7
:
if
file_name
!=
""
:
temptext
=
""
addlist
=
[]
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
AData
=
ob
.
getData
()
pose
=
ob
.
getPose
()
if
AData
:
option
=
PupMenu
(
"Bones to load: %t|Load all bones in armature
%x
1|Load only bones list selections
%x
2"
)
if
option
==
1
:
templist
=
AData
.
bones
.
keys
()
elif
option
==
2
:
templist
=
boxBones
AData
.
makeEditable
()
temptext
=
open
(
file_name
,
"r"
)
lines
=
temptext
.
readlines
()
for
line
in
lines
:
data
=
line
.
rstrip
(
"
\n
"
)
.
split
(
","
)
if
data
[
0
]
not
in
AData
.
bones
.
keys
():
#optionally add missing bones (all or none)
addbone
=
PupMenu
(
"Bone not found:
%s
%%
t|Add missing bone(s) to armature
%%
x1\
|
Don
't add missing bone(s)
%%
x2" %(data[0]))
if
addbone
==
1
:
#Add all missing bones in a subloop, to avoid parenting problems
scale
=
PupFloatInput
(
"Scaling:"
,
1.0
,
0.001
,
1000.0
,
10
,
2
)
if
scale
==
None
:
scale
=
1.0
#pup inputs can return None
for
line
in
lines
:
data2
=
line
.
rstrip
(
"
\n
"
)
.
split
(
","
)
if
data2
[
0
]
not
in
AData
.
bones
.
keys
():
head
=
(
float
(
data2
[
2
])
*
scale
,
float
(
data2
[
3
])
*
scale
,
float
(
data2
[
4
])
*
scale
)
head
=
Vector
(
head
)
tail
=
(
float
(
data2
[
5
])
*
scale
,
float
(
data2
[
6
])
*
scale
,
float
(
data2
[
7
])
*
scale
)
tail
=
Vector
(
tail
)
create_bone
(
AData
,
data2
[
0
],
head
,
tail
,
float
(
data2
[
1
]))
addlist
.
append
(
data2
[
0
])
#pass parenting info for new bones to parenting step
templist
.
append
(
data2
[
0
])
AData
.
update
()
#these update the armature data in case two armatures are being combined
AData
.
makeEditable
()
pose
=
ob
.
getPose
()
if
data
[
0
]
in
templist
:
##set the requested values for bones
bone1
=
AData
.
bones
[
data
[
0
]]
if
bone1
.
name
==
data
[
0
]:
if
(
warning
==
1
or
warning
==
6
)
and
data
[
0
]
not
in
addlist
:
#roll
bone1
.
roll
=
float
(
data
[
1
])
if
(
warning
==
2
or
warning
==
6
)
and
data
[
0
]
not
in
addlist
:
#head and tail
bone1
.
head
=
Vector
(
data
[
2
],
data
[
3
],
data
[
4
])
bone1
.
tail
=
Vector
(
data
[
5
],
data
[
6
],
data
[
7
])
if
warning
==
3
or
warning
==
5
or
warning
==
6
or
data
[
0
]
in
addlist
:
#parenting
if
data
[
8
]
in
AData
.
bones
.
keys
():
bone1
.
parent
=
AData
.
bones
[
data
[
8
]]
if
warning
==
4
or
warning
==
5
or
warning
==
6
:
#IK
if
data
[
9
]
in
AData
.
bones
.
keys
():
bone
=
pose
.
bones
[
bone1
.
name
]
bone
.
constraints
.
append
(
Constraint
.
Type
.
IKSOLVER
)
const
=
bone
.
constraints
[
len
(
bone
.
constraints
)
-
1
]
#last entry is our appended IKSOLVER
const
[
Constraint
.
Settings
.
TARGET
]
=
ob
#target object is the selected armature
const
[
Constraint
.
Settings
.
BONE
]
=
data
[
9
]
#active bones list selection is target bone
const
[
Constraint
.
Settings
.
CHAINLEN
]
=
int
(
data
[
10
])
else
:
print
"Bone not loaded:"
,
data
[
0
]
temptext
.
close
()
AData
.
update
()
pose
.
update
()
ob
.
makeDisplayList
()
Blender
.
Redraw
()
print
"Done loading armature settings."
#---------Create a bone----------------------------------------------------
def
create_bone
(
armature
,
name
,
head
,
tail
,
roll
):
bone
=
Armature
.
Editbone
()
bone
.
roll
=
roll
bone
.
head
=
head
bone
.
tail
=
tail
armature
.
bones
[
name
]
=
bone
print
"Added bone
%s
to armature."
%
(
name
)
#---------Create an armature from saved .txt settings------------------------------------------
def
create_armature
(
file_name
):
if
os
.
path
.
splitext
(
file_name
)[
1
]
==
".txt"
:
switch
=
1
elif
os
.
path
.
splitext
(
file_name
)[
1
]
==
".cr2"
or
os
.
path
.
splitext
(
file_name
)[
1
]
==
".crz"
:
switch
=
2
scale
=
PupFloatInput
(
"Scaling:"
,
1.0
,
0.001
,
1000.0
,
10
,
2
)
if
scale
==
None
:
scale
=
1.0
#pup inputs can return None
armname
=
PupStrInput
(
"Armature name:"
,
"ARM.NEWARM"
,
25
)
#get a name for the new armature
if
armname
==
None
:
armname
=
"ARM.NEWARM"
objs
=
Blender
.
Scene
.
GetCurrent
()
.
getChildren
()
objs
=
list
(
obj
.
name
for
obj
in
objs
)
if
armname
in
objs
:
addname
+=
"_"
+
str
(
len
(
objs
))
.
rjust
(
4
,
"0"
)
ob
=
Object
.
New
(
'Armature'
)
AData
=
Armature
.
Armature
(
armname
)
ob
.
link
(
AData
)
AData
.
makeEditable
()
if
switch
==
1
:
#custom armature backup
temptext
=
open
(
file_name
,
"r"
)
lines
=
temptext
.
readlines
()
elif
switch
==
2
:
#Poser cr2 import
lines
=
parse_poser_file
(
file_name
)
for
line
in
lines
:
#add the bones
data
=
line
.
rstrip
(
"
\n
"
)
.
split
(
","
)
bone
=
Armature
.
Editbone
()
bone
.
roll
=
float
(
data
[
1
])
bone
.
head
=
Vector
(
float
(
data
[
2
])
*
scale
,
float
(
data
[
3
])
*
scale
,
float
(
data
[
4
])
*
scale
)
bone
.
tail
=
Vector
(
float
(
data
[
5
])
*
scale
,
float
(
data
[
6
])
*
scale
,
float
(
data
[
7
])
*
scale
)
AData
.
bones
[
data
[
0
]]
=
bone
for
line
in
lines
:
#assign parenting after all bones are present
data
=
line
.
rstrip
(
"
\n
"
)
.
split
(
","
)
if
data
[
0
]
in
AData
.
bones
.
keys
():
bone
=
AData
.
bones
[
data
[
0
]]
if
data
[
8
]
in
AData
.
bones
.
keys
():
bone
.
parent
=
AData
.
bones
[
data
[
8
]]
AData
.
update
()
scn
=
Blender
.
Scene
.
GetCurrent
()
scn
.
link
(
ob
)
scn
.
update
()
pose
=
ob
.
getPose
()
try
:
for
line
in
lines
:
#A third loop for IK (posebone-level) addition, after armature is updated and scene-linked
data
=
line
.
rstrip
(
"
\n
"
)
.
split
(
","
)
if
data
[
9
]
in
pose
.
bones
.
keys
():
bone1
=
pose
.
bones
[
data
[
0
]]
bone1
.
constraints
.
append
(
Constraint
.
Type
.
IKSOLVER
)
const
=
bone1
.
constraints
[
len
(
bone1
.
constraints
)
-
1
]
#last entry is our appended IKSOLVER
const
[
Constraint
.
Settings
.
TARGET
]
=
ob
#target object is the new armature
const
[
Constraint
.
Settings
.
BONE
]
=
data
[
9
]
#target bone
const
[
Constraint
.
Settings
.
CHAINLEN
]
=
int
(
data
[
10
])
const
.
influence
=
1.0
except
:
pass
#IK scripting not available before 242
pose
.
update
()
ob
.
select
(
1
)
if
switch
==
1
:
temptext
.
close
()
ob
.
makeDisplayList
()
#to refresh the bones display
#---------Restore bone roll settings (in-session only) -----------------------------------------
def
Bone_Roll_R
():
#Restore boneroll from original values in oldRolls dict
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
AData
=
ob
.
getData
()
if
AData
:
AData
.
makeEditable
()
bones
=
AData
.
bones
.
values
()
for
bone1
in
bones
:
if
oldRolls
.
has_key
(
bone1
.
name
):
bRoll2
=
oldRolls
[
bone1
.
name
]
bone1
.
roll
=
bRoll2
AData
.
update
()
#--------------Zero bone roll settings----------------------------------------------------------
def
Bone_Roll_Z
():
#Zero bone roll angles; save to oldRolls dict w/ option to save .txt backup
if
Object
.
GetSelected
()
!=
[]:
c
=
PupMenu
(
"Save old bone roll settings to .txt file? %t|Yes
%x
1|No
%x
2|Cancel
%x
3"
)
if
c
==
1
:
Window
.
FileSelector
(
boneSave
,
'File to save as?'
)
if
c
!=
3
:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
AData
=
ob
.
getData
()
if
AData
:
if
oldRolls
==
{}:
for
bone1
in
AData
.
bones
.
values
():
#Don't replace backup values if they've already been set.
oldRolls
[
bone1
.
name
]
=
int
(
bone1
.
roll
[
'ARMATURESPACE'
])
AData
.
makeEditable
()
bones
=
AData
.
bones
.
values
()
for
bone1
in
bones
:
bone1
.
roll
=
0.0
AData
.
update
()
#-------"Correct" the roll angles to conform with Blender standards.------------------------------------
#Roll angles need to be zeroed before running this.
#This is probably a ridiculous kludge approach. Some z-pointing bones aren't quite correct....
#points bone z-axis in "correct" direction. Up for horizontal bones, forward for vertical.
def
boneroll_correct
(
switch
):
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
c
=
PupMenu
(
"Save old bone roll settings to .txt file? %t|Yes
%x
1|No
%x
2|Cancel
%x
3"
)
if
c
==
1
:
Window
.
FileSelector
(
boneSave
,
'File to save as?'
)
if
c
!=
3
:
ob
=
Object
.
GetSelected
()[
0
]
AData
=
ob
.
getData
()
if
AData
:
if
oldRolls
==
{}:
for
bone1
in
AData
.
bones
.
values
():
#Don't replace backup values if they've already been set.
oldRolls
[
bone1
.
name
]
=
int
(
bone1
.
roll
[
'ARMATURESPACE'
])
pose
=
ob
.
getPose
()
rollDict
=
{}
y_dir
=
Vector
(
0
,
1
,
0
)
#Directions x,y,z as vectors
z_dir
=
Vector
(
0
,
0
,
1
)
x_dir
=
Vector
(
1
,
0
,
0
)
if
switch
==
0
:
templist
=
pose
.
bones
.
keys
()
elif
switch
==
1
:
templist
=
boxBones
#if AData.drawAxes == False: AData.drawAxes = True
for
bone
in
templist
:
#y_dir2 = y_dir * pose.bones[bone].poseMatrix.rotationPart() # poseMatrix is worldspace
#z_dir2 = z_dir * pose.bones[bone].poseMatrix.rotationPart()
#x_dir2 = x_dir * pose.bones[bone].poseMatrix.rotationPart()
y_dir2
=
y_dir
*
AData
.
bones
[
bone
]
.
matrix
[
'ARMATURESPACE'
]
.
rotationPart
()
z_dir2
=
z_dir
*
AData
.
bones
[
bone
]
.
matrix
[
'ARMATURESPACE'
]
.
rotationPart
()
#x_dir2 = x_dir * AData.bones[bone].matrix['ARMATURESPACE'].rotationPart()
dx
,
dy
,
dz
=
y_dir2
dirtup
=
(
abs
(
dx
),
abs
(
dy
),
abs
(
dz
))
dirtup
=
list
(
dirtup
)
dirmax
=
max
(
dirtup
)
#Find the dominant axis
axis
=
z_dir2
#The bone axis to be "pointed"
#Define "direx" as the direction in which to point "axis"
#Proof that this is a hack: I don't really know why the round(dirtup) stuff helps, but it seems to....
if
dirtup
.
index
(
dirmax
)
==
0
:
#x-pointing
if
round
(
dirtup
[
2
],
1
)
>
0.3
:
#if there is z-pointing angling
direx
=
x_dir
else
:
direx
=
y_dir
#point up
elif
dirtup
.
index
(
dirmax
)
==
1
:
#y-pointing
if
round
(
dirtup
[
2
],
1
)
>
0.3
:
#if there is z-pointing angling
print
bone
if
dy
>=
0
:
direx
=
y_dir
-
z_dir
elif
dy
<
0
:
if
dz
>=
0
:
direx
=
y_dir
+
z_dir
else
:
direx
=
y_dir
-
z_dir
direx
=
-
direx
else
:
direx
=
z_dir
#point forward
elif
dirtup
.
index
(
dirmax
)
==
2
:
#z-pointing
if
round
(
dirtup
[
1
],
1
)
>
0.3
:
#if there is x-pointing angling
if
dy
>=
0
:
direx
=
y_dir
-
z_dir
elif
dy
<
0
:
direx
=
y_dir
+
z_dir
else
:
direx
=
y_dir
#point up
roll_ang
=
AngleBetweenVecs
(
direx
,
axis
)
#roll value is angle between direx and axis
if
dx
>
0
:
roll_ang
=
-
roll_ang
#if bone points in +x direction, flip the roll value
rollDict
[
bone
]
=
roll_ang
#can't query values after makeEditable, so pass between loops using dict
AData
.
makeEditable
()
for
bone
in
templist
:
roll_ang
=
rollDict
[
bone
]
AData
.
bones
[
bone
]
.
roll
=
roll_ang
AData
.
update
()
##----------------Animation-----------------------------------------
#------------Keyframe handling--------------------------------------
def
anim_menu
():
menu
=
PupMenu
(
"Frames options: %t|Select all keyframes
%x
1|De-select all
%x
2|Invert keyframe selection
%x
3\
|
Delete
all
keyframes
%
x4
|
Delete
selected
keyframes
for
all
bones
%
x5
\
|
Delete
selected
keyframes
for
bones
list
selections
%
x6
\
|
Delete
selected
keyframes
for
active
bones
list
bone
%
x7
|
Change
frame
count
%
x8
|
Cancel
%
x9
")
if
menu
==
1
:
select_keys
()
elif
menu
==
2
:
deselect_keys
()
elif
menu
==
3
:
invert_keys
()
elif
menu
==
4
:
remove_keys
()
elif
menu
==
5
:
remove_selected
(
2
)
elif
menu
==
6
:
remove_selected
(
0
)
elif
menu
==
7
:
remove_selected
(
1
)
elif
menu
==
8
:
change_frames
()
def
change_frames
():
#This changes the length of the frames list display. Python apparently can't set the endframe.
global
animlen
animlen
=
PupIntInput
(
"Frame count:"
,
animlen
,
1
,
animlen
+
1000
)
def
remove_keys
():
#Delete all keyframes.
global
boxFrames
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
if
ob
.
getAction
():
pose
=
ob
.
getPose
()
act
=
ob
.
getAction
()
#get the current action
all
=
act
.
getAllChannelIpos
()
#all channel curves for action
if
len
(
all
)
>
0
:
#if there are keyframes
for
bone
in
pose
.
bones
.
keys
():
#loop through all bones
if
bone
in
all
:
#if bone is keyframed
act
.
removeChannel
(
bone
)
#remove all channels for bone
boxFrames
=
[]
#clear the display list selections
else
:
oops
=
PupMenu
(
"No keyframes to delete!"
)
ob
.
makeDisplayList
()
#to refresh the bones display
def
select_keys
():
#select current keyframes
global
boxFrames
try
:
boxFrames
=
[]
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
if
ob
.
getAction
():
act
=
ob
.
getAction
()
c
=
act
.
getFrameNumbers
()
#Not available before 242
boxFrames
=
list
(
str
(
k
)
for
k
in
c
)
if
c
==
[]:
oops
=
PupMenu
(
"No keyframes to select!"
)
except
:
error
=
PupMenu
(
"This feature is only available in versions later than 2.41"
)
def
deselect_keys
():
#deselect everything in anim listbox
global
boxFrames
boxFrames
=
[]
def
invert_keys
():
#invert keyframe selection in bones listbox
global
boxFrames
try
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
if
ob
.
getAction
():
act
=
ob
.
getAction
()
a
=
set
(
int
(
i
)
for
i
in
boxFrames
)
b
=
set
(
act
.
getFrameNumbers
())
c
=
list
(
b
-
a
)
boxFrames
=
list
(
str
(
k
)
for
k
in
c
)
except
:
error
=
PupMenu
(
"This feature is only available in versions later than 2.41"
)
def
remove_selected
(
switch
):
#Delete selected keyframes
global
boxFrames
try
:
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
and
ob
.
getAction
():
#if there is an armature selection
startTime
=
sys
.
time
()
#keep track of speed
templist
=
[]
if
switch
==
0
and
boxBones
!=
[]:
templist
=
boxBones
#use only bones list selections
if
switch
==
1
and
lastBone
!=
""
:
#use only active bones list selection
templist
=
[]
templist
.
append
(
lastBone
)
if
switch
==
2
:
#use all bones in armature
pose
=
ob
.
getPose
()
templist
=
pose
.
bones
.
keys
()
act
=
ob
.
getAction
()
#get the action
if
len
(
act
.
getAllChannelIpos
())
>
0
:
#if there are keyframes
a
=
set
(
templist
)
b
=
set
(
act
.
getAllChannelIpos
())
templist
=
list
(
a
&
b
)
#the list of bones which have Ipo curves
a
=
set
(
int
(
i
)
for
i
in
boxFrames
)
b
=
set
(
act
.
getFrameNumbers
())
c
=
sorted
(
list
(
b
-
a
))
#the list of keyframes which aren't selected
d
=
list
(
a
&
b
)
#the list of keyframes which are selected (for tracking)
if
templist
!=
[]:
if
c
==
[]:
#if all keyframed frames are selected
for
bone
in
templist
:
act
.
removeChannel
(
bone
)
#delete all channels for selected bones
if
c
!=
[]:
#not all keyframed frames selected
framesDict
=
{}
for
indx
,
frame
in
enumerate
(
c
):
data
=
""
Blender
.
Set
(
'curframe'
,
frame
)
for
bone
in
templist
:
#for selected bones
bone
=
pose
.
bones
[
bone
]
#collect the animation data
lx
,
ly
,
lz
=
bone
.
loc
qw
,
qx
,
qy
,
qz
=
bone
.
quat
sx
,
sy
,
sz
=
bone
.
size
data
+=
"
%s
,
%f
,
%f
,
%f
,
%f
,
%f
,
%f
,
%f
,
%f
,
%f
,
%f
\n
"
%
(
bone
.
name
,
lx
,
ly
,
lz
,
qw
,
qx
,
qy
,
qz
,
sx
,
sy
,
sz
)
if
indx
==
len
(
c
)
-
1
:
#if this is the last frame in the sequence
act
.
removeChannel
(
bone
.
name
)
#remove all the bone's ipo channels
framesDict
[
frame
]
=
data
#add the data to the dict
Blender
.
Set
(
'curframe'
,
c
[
0
])
#restore first frame not to be deleted
for
frame
,
data
in
framesDict
.
iteritems
():
#use the dict to add frames back into animation
lines
=
data
.
split
(
"
\n
"
)
for
line1
in
lines
:
line
=
line1
.
split
(
","
)
if
line
!=
[
''
]:
#don't try to run last line, which is blank
bone
=
pose
.
bones
[
line
[
0
]]
bone
.
loc
=
Vector
(
line
[
1
],
line
[
2
],
line
[
3
])
#rebuild the data
bone
.
quat
=
Quaternion
(
line
[
4
],
line
[
5
],
line
[
6
],
line
[
7
])
bone
.
size
=
Vector
(
line
[
8
],
line
[
9
],
line
[
10
])
add_curves
(
ob
,
pose
,
bone
.
name
,
bone
.
quat
,
bone
.
loc
,
bone
.
size
,
frame
)
#restore the undeleted frames
framesDict
.
clear
()
a
=
set
(
boxFrames
)
b
=
set
(
str
(
k
)
for
k
in
act
.
getFrameNumbers
())
boxFrames
=
list
(
a
&
b
)
#refresh boxFrames as the set of keyframes which weren't deleted
ob
.
makeDisplayList
()
#to refresh the bones display
finTime
=
sys
.
time
()
-
startTime
print
"Done deleting
%i
keyframes from
%i
bones in
%f
seconds"
%
(
len
(
d
),
len
(
templist
),
finTime
)
else
:
oops
=
PupMenu
(
"No keyframes to delete!"
)
except
:
error
=
PupMenu
(
"This feature is only available in versions later than 2.41"
)
def
add_curves
(
ob
,
pose
,
bone
,
quat
,
loc
,
size
,
time
):
#This is kind of a compressed and simplified version of Cambo's Ipo keyframing from bvh_import.py for 242.
#This is used by open_batch and remove_selected...
#Also by load_pose, Zero_Pose, numerical_entry, and load_poser_pose for keyframe insertion
if
not
ob
.
getAction
():
act
=
Armature
.
NLA
.
NewAction
(
"Action"
)
act
.
setActive
(
ob
)
else
:
act
=
ob
.
getAction
()
act_ipo
=
act
.
getAllChannelIpos
()
if
bone
in
act_ipo
:
ipo
=
act_ipo
[
bone
]
ipo
[
Ipo
.
PO_LOCX
]
.
append
((
time
,
loc
[
0
]))
ipo
[
Ipo
.
PO_LOCY
]
.
append
((
time
,
loc
[
1
]))
ipo
[
Ipo
.
PO_LOCZ
]
.
append
((
time
,
loc
[
2
]))
ipo
[
Ipo
.
PO_SCALEX
]
.
append
((
time
,
size
[
0
]))
ipo
[
Ipo
.
PO_SCALEY
]
.
append
((
time
,
size
[
1
]))
ipo
[
Ipo
.
PO_SCALEZ
]
.
append
((
time
,
size
[
2
]))
ipo
[
Ipo
.
PO_QUATW
]
.
append
((
time
,
quat
[
0
]))
ipo
[
Ipo
.
PO_QUATX
]
.
append
((
time
,
quat
[
1
]))
ipo
[
Ipo
.
PO_QUATY
]
.
append
((
time
,
quat
[
2
]))
ipo
[
Ipo
.
PO_QUATZ
]
.
append
((
time
,
quat
[
3
]))
elif
not
bone
in
act_ipo
:
# a keyframe needs to be added to create the bone ipo if it doesn't already exist
bone1
=
pose
.
bones
[
bone
]
bone1
.
insertKey
(
ob
,
time
,
Object
.
Pose
.
LOC
)
bone1
.
insertKey
(
ob
,
time
,
Object
.
Pose
.
ROT
)
bone1
.
insertKey
(
ob
,
time
,
Object
.
Pose
.
SIZE
)
#-----------Animation load and save (batch handling)------------------------------------------------
def
frames_sort
():
global
boxFrames
if
batchFrames
==
1
:
#sort boxFrames numerically
templist
=
sorted
(
int
(
i
)
for
i
in
boxFrames
)
boxFrames
=
list
(
str
(
i
)
for
i
in
templist
)
#-------------------------------------------------------------------------
def
open_batch
(
filename
):
#load a batch of poses, option to specify destination keys using frames listbox
#This cannot change the endframe of an animation, but it will increase the range of the frames listbox
global
askKey
,
batchFrames
,
animlen
if
len
(
boxFrames
)
<
1
:
batchFrames
=
0
startTime
=
sys
.
time
()
curframe
=
Blender
.
Get
(
'curframe'
)
if
batchLoad
==
0
:
#default if not using pose listbox - load numbered batch, as saved
frames
=
PupIntInput
(
"animation length:"
,
1
,
Blender
.
Get
(
'staframe'
),
Blender
.
Get
(
'endframe'
))
if
frames
!=
None
:
if
batchFrames
==
0
:
frame
=
curframe
#Blender.Get('curframe') #load starts from current frame
elif
batchFrames
==
1
:
#frames listbox screening
frames_sort
()
#sort the selected list frames numerically
frame
=
int
(
boxFrames
[
0
])
Blender
.
Set
(
'curframe'
,
frame
)
path
=
sys
.
dirname
(
filename
)
filename
=
sys
.
basename
(
filename
)
file_ext
=
os
.
path
.
splitext
(
filename
)[
1
]
filebase
=
os
.
path
.
splitext
(
filename
)[
0
][:
-
4
]
temp
=
askKey
askKey
=
2
for
filenum
in
range
(
1
,
frames
+
1
):
fileload
=
sys
.
join
(
path
,
filebase
+
str
(
filenum
)
.
rjust
(
4
,
"0"
)
+
file_ext
)
if
sys
.
exists
(
fileload
)
==
1
:
load_pose
(
fileload
)
if
batchFrames
==
0
:
Blender
.
Set
(
'curframe'
,
frame
+
filenum
)
curframe
=
frame
+
filenum
elif
batchFrames
==
1
:
#frames listbox screening
if
filenum
<
len
(
boxFrames
):
Blender
.
Set
(
'curframe'
,
int
(
boxFrames
[
filenum
]))
curframe
=
int
(
boxFrames
[
filenum
])
else
:
Blender
.
Set
(
'curframe'
,
int
(
boxFrames
[
len
(
boxFrames
)
-
1
])
+
(
filenum
-
len
(
boxFrames
))
+
1
)
curframe
=
int
(
boxFrames
[
len
(
boxFrames
)
-
1
])
+
(
filenum
-
len
(
boxFrames
))
+
1
if
curframe
>
animlen
:
animlen
+=
curframe
-
animlen
askKey
=
temp
#Reset keyframe screening
Blender
.
Set
(
'curframe'
,
frame
)
#Go back to start frame
#--------------------------------------------------------------------------------------
elif
batchLoad
==
1
:
#loading via pose listbox - load custom listbox selections
if
len
(
boxPoses
)
>
0
:
frames
=
len
(
boxPoses
)
if
batchFrames
==
0
:
frame
=
curframe
#Blender.Get('curframe') #load starts from current frame
elif
batchFrames
==
1
:
#frames listbox screening
frames_sort
()
#sort the selected list frames numerically
frame
=
int
(
boxFrames
[
0
])
Blender
.
Set
(
'curframe'
,
frame
)
temp
=
askKey
askKey
=
2
for
filenum
in
range
(
1
,
frames
+
1
):
fileload
=
sys
.
join
(
LibPath
,
boxPoses
[
filenum
-
1
])
if
sys
.
exists
(
fileload
)
==
1
:
load_pose
(
fileload
)
if
batchFrames
==
0
:
Blender
.
Set
(
'curframe'
,
frame
+
filenum
)
curframe
=
frame
+
filenum
elif
batchFrames
==
1
:
#frames listbox screening
if
filenum
<
len
(
boxFrames
):
Blender
.
Set
(
'curframe'
,
int
(
boxFrames
[
filenum
]))
curframe
=
int
(
boxFrames
[
filenum
])
else
:
Blender
.
Set
(
'curframe'
,
int
(
boxFrames
[
len
(
boxFrames
)
-
1
])
+
(
filenum
-
len
(
boxFrames
))
+
1
)
curframe
=
int
(
boxFrames
[
len
(
boxFrames
)
-
1
])
+
(
filenum
-
len
(
boxFrames
))
+
1
if
curframe
>
animlen
:
animlen
+=
curframe
-
animlen
askKey
=
temp
#Reset keyframe screening
Blender
.
Set
(
'curframe'
,
frame
)
#Go back to start frame
finTime
=
sys
.
time
()
-
startTime
if
frames
!=
None
:
print
"Done loading
%i
poses in
%f
seconds"
%
(
frames
,
finTime
)
#PupIntInput can return None.
#--------------------------------------------------------------------------------------------
def
save_batch
(
filename
):
#Save animation as a batch of numbered poses, optional selection via frames list
if
PoserSave
==
0
:
if
batchFrames
==
0
:
frames
=
PupIntInput
(
"animation length:"
,
1
,
Blender
.
Get
(
'staframe'
),
Blender
.
Get
(
'endframe'
))
frame
=
Blender
.
Get
(
'curframe'
)
#default save starts from current frame
elif
batchFrames
==
1
:
if
len
(
boxFrames
)
>
0
:
frames_sort
()
frames
=
len
(
boxFrames
)
frame
=
int
(
boxFrames
[
0
])
Blender
.
Set
(
'curframe'
,
frame
)
path
=
sys
.
dirname
(
filename
)
filename
=
sys
.
basename
(
filename
)
filebase
=
os
.
path
.
splitext
(
filename
)[
0
]
if
PoserSave
==
0
:
#Poser pose export is all written to one file; don't run batch
for
filenum
in
range
(
1
,
frames
+
1
):
filesave
=
sys
.
join
(
path
,
filebase
+
"_"
+
str
(
filenum
)
.
rjust
(
4
,
"0"
))
##file extension will be appended by goSave
goSave
(
filesave
)
#print filesave, filenum, boxFrames[filenum-1]
if
batchFrames
==
0
:
Blender
.
Set
(
'curframe'
,
frame
+
filenum
)
elif
batchFrames
==
1
:
if
filenum
<
len
(
boxFrames
):
Blender
.
Set
(
'curframe'
,
int
(
boxFrames
[
filenum
]))
Blender
.
Set
(
'curframe'
,
frame
)
#Go back to start frame
elif
PoserSave
==
1
:
filesave
=
sys
.
join
(
path
,
filebase
)
goSave
(
filesave
)
##--------------IK handling--------------------------------------------
def
IK_menu
():
menu
=
PupMenu
(
"IK options: %t|Select all bones with IK
%x
1|De-select all
%x
2|Set IK influence for all IK chains
%x
3\
|
Set
IK
influence
for
list
selections
%
x4
|
Set
IK
influence
for
active
selection
%
x5
|
Cancel
%
x6
")
if
menu
==
1
:
select_IK
()
elif
menu
==
2
:
deselect_IK
()
elif
menu
==
3
:
IK_toggle
(
2
)
elif
menu
==
4
:
IK_toggle
(
0
)
elif
menu
==
5
:
IK_toggle
(
1
)
def
IK_toggle
(
switch
):
try
:
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
pose
=
ob
.
getPose
()
togval
=
PupFloatInput
(
"value:"
,
1.0
,
0.0
,
1.0
,
10
,
2
)
#get the setting
if
togval
==
None
:
togval
=
1.0
templist
=
[]
if
switch
==
0
and
boxBones
!=
[]:
templist
=
boxBones
#use only bones list selections
if
switch
==
1
and
lastBone
!=
""
:
#use only active bones list selection
templist
=
[]
templist
.
append
(
lastBone
)
if
switch
==
2
:
#use all bones in armature
templist
=
pose
.
bones
.
keys
()
for
bonename
in
templist
:
bone
=
pose
.
bones
[
bonename
]
for
const
in
bone
.
constraints
:
if
const
.
type
==
Constraint
.
Type
.
IKSOLVER
:
const
.
influence
=
togval
ob
.
makeDisplayList
()
#to refresh the bones display
except
:
error
=
PupMenu
(
"This feature is only available in versions later than 2.41"
)
def
deselect_IK
():
#deselect everything in anim listbox
global
boxBones
boxBones
=
[]
def
select_IK
():
global
boxBones
,
lastBone
try
:
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
pose
=
ob
.
getPose
()
for
bone
in
pose
.
bones
.
values
():
for
const
in
bone
.
constraints
:
if
const
.
type
==
Constraint
.
Type
.
IKSOLVER
:
boxBones
.
append
(
bone
.
name
)
if
len
(
boxBones
)
>
0
:
#Set active selection as first displayed item in list
boxBones
.
sort
()
boxBones
.
reverse
()
lastBone
=
boxBones
[
len
(
boxBones
)
-
1
]
except
:
error
=
PupMenu
(
"This feature is only available in versions later than 2.41"
)
#-------Bones list toolset for IK custom construction-------------------------
#some tools to assist in building or removing IK solver constraints
def
tools_menu
():
menu
=
PupMenu
(
"Bones toolset options: %t|De-select all
%x
1|Re-parent selected bones
%x
2\
|
Change
IK
target
bone
for
selections
%
x3
|
Add
IK
to
selection
(
s
)
%
x4
\
|
Remove
IK
from
all
selections
%
x5
|
Add
a
bone
to
current
armature
%
x6
\
|
Add
IK
goal
bone
to
armature
%
x7
|
Add
IK
bend
target
bone
to
armature
%
x8
\
|
Delete
all
selected
bones
%
x9
|
%
x18
|
Scale
selected
bones
%
x10
\
|
Translate
selected
bones
%
x11
|
Swap
head
and
tail
of
selected
bones
%
x12
\
|
Flip
selected
bones
along
an
axis
%
x13
|
Connect
selected
bones
with
active
selection
%
x14
\
|
Connect
selected
bones
with
their
parents
%
x15
|
Straighten
selected
bones
%
x16
\
|
Straighten
and
align
chains
%
x17
|
Cancel
%
x18
")
if
menu
==
1
:
deselect_IK
()
elif
menu
==
2
:
reparent
()
elif
menu
==
3
:
retarget
()
elif
menu
==
4
:
add_IK
()
elif
menu
==
5
:
remove_IK
()
elif
menu
==
6
:
add_bone
(
0
)
elif
menu
==
7
:
add_bone
(
1
)
elif
menu
==
8
:
add_bone
(
2
)
elif
menu
==
9
:
delete_bones
()
elif
menu
==
10
:
scale_bones
()
elif
menu
==
11
:
move_bones
()
elif
menu
==
12
:
swap_bones
()
elif
menu
==
13
:
flip_bone_axis
()
elif
menu
==
14
:
connect_bones
(
0
)
elif
menu
==
15
:
connect_bones
(
1
)
elif
menu
==
16
:
align_bones
()
elif
menu
==
17
:
align_chains
()
def
reparent
():
#make active (last) bones list selection new parent of all previous selections
global
root
,
boxBones
,
lastBone
,
boxList
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
lastBone
!=
""
:
if
len
(
boxBones
)
>
1
:
AData
=
ob
.
getData
()
templist
=
boxBones
#keep bone from being parented to one of its offspring
boxBones
=
[]
for
bone
in
templist
:
if
bone
!=
lastBone
and
AData
.
bones
[
bone
]
.
hasChildren
():
offspring
=
list
(
child
.
name
for
child
in
AData
.
bones
[
bone
]
.
getAllChildren
())
if
not
lastBone
in
offspring
:
#check the family tree
print
"Reparented
%s
to
%s
."
%
(
bone
,
lastBone
)
boxBones
.
append
(
bone
)
else
:
print
"Cannot reparent
%s
to
%s
:
%s
is a descendant of
%s
."
%
(
bone
,
lastBone
,
lastBone
,
bone
)
else
:
boxBones
.
append
(
bone
)
#bones without children and active bone are restored to list
AData
.
makeEditable
()
boneparent
=
AData
.
bones
[
lastBone
]
for
selected
in
range
(
0
,
len
(
boxBones
)
-
1
):
bone
=
AData
.
bones
[
boxBones
[
selected
]]
bone
.
parent
=
boneparent
AData
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
if
boneSort
==
1
:
boxList
=
sort_hierarchy
(
boxList
)
#re-sort for hierarchical display
def
retarget
():
#change target bone to active list bone for all inactive selections
try
:
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
lastBone
!=
""
:
if
len
(
boxBones
)
>
1
:
pose
=
ob
.
getPose
()
for
selected
in
range
(
0
,
len
(
boxBones
)
-
1
):
bone
=
pose
.
bones
[
boxBones
[
selected
]]
for
const
in
bone
.
constraints
:
if
const
.
type
==
Constraint
.
Type
.
IKSOLVER
:
const
[
Constraint
.
Settings
.
BONE
]
=
lastBone
##set the target bone
pose
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
except
:
error
=
PupMenu
(
"This feature is only available in versions later than 2.41"
)
#This can crash Blender if no pose bone has been selected
def
remove_IK
():
#remove IK solver constraints from bones list selections
global
boxBones
try
:
if
Object
.
GetSelected
()
!=
[]
and
boxBones
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
pose
=
ob
.
getPose
()
if
ob
.
getType
()
==
"Armature"
:
try
:
pose
.
bones
[
boxBones
[
0
]]
.
sel
=
True
#try to select a bone (only available in 242 CVS)
except
:
print
"Could not auto-select a pose bone. Method not available in this build of Blender."
AData
=
ob
.
getData
()
#Verify that a bone has been selected
selected
=
0
for
selbone
in
AData
.
bones
.
values
():
if
Armature
.
BONE_SELECTED
in
selbone
.
options
:
selected
=
1
break
if
selected
==
1
:
#crash-prevention: only proceed if there is a user-selected bone
for
bone
in
boxBones
:
bone
=
pose
.
bones
[
bone
]
for
const
in
bone
.
constraints
:
if
const
.
type
==
Constraint
.
Type
.
IKSOLVER
:
bone
.
constraints
.
remove
(
const
)
boxBones
=
[]
#entries have been deleted, so clear the list.
pose
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
else
:
error
=
PupMenu
(
"A bone must be selected in the 3D view before IK can be removed."
)
except
:
error
=
PupMenu
(
"This feature is only available in versions later than 2.41"
)
def
add_IK
():
#add IK solver constraints to bones list selections
try
:
#This has gotten kind of messy... needs some reorganization....
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
len
(
boxBones
)
>
0
:
pose
=
ob
.
getPose
()
AData
=
ob
.
getData
()
chaintype
=
1
chain_len
=
1
if
len
(
boxBones
)
>
1
:
#Chain will be added in order selected w/ chaintype = 2
chaintype
=
PupMenu
(
"Options: %t|Add IK to last inactive list bone only
%x
1\
|
Add
IK
as
chain
to
all
inactive
selections
%
x2
|
Cancel
%
x3
")
if
chaintype
==
1
:
chain_len
=
PupIntInput
(
"Chainlen:"
,
1
,
1
,
len
(
pose
.
bones
))
option
=
2
if
chaintype
==
1
or
chaintype
==
2
:
if
chaintype
==
2
:
inkyname
=
PupStrInput
(
"Name for new bone:"
,
"inkychain"
,
25
)
#get a name
if
inkyname
==
None
:
inkyname
=
"inkychain"
if
inkyname
in
AData
.
bones
.
keys
():
inkyname
+=
"_"
+
str
(
len
(
AData
.
bones
.
keys
()))
.
rjust
(
4
,
"0"
)
option
=
PupMenu
(
"Include active selection in chain? %t|Yes
%x
1|No
%x
2"
)
root
=
sort_hierarchy
(
pose
.
bones
.
keys
())[
0
]
rootlen
=
AData
.
bones
[
root
]
.
length
AData
.
makeEditable
()
for
i
in
range
(
len
(
boxBones
)
-
1
,
-
1
,
-
1
):
bone
=
boxBones
[
i
]
bone1
=
pose
.
bones
[
bone
]
const
=
None
if
(
option
==
2
and
boxBones
.
index
(
bone
)
<
len
(
boxBones
)
-
1
)
or
\
(
option
==
1
and
boxBones
.
index
(
bone
)
<
len
(
boxBones
)):
bone1
.
constraints
.
append
(
Constraint
.
Type
.
IKSOLVER
)
const
=
bone1
.
constraints
[
len
(
bone1
.
constraints
)
-
1
]
#last entry is our appended IKSOLVER
const
[
Constraint
.
Settings
.
TARGET
]
=
ob
#target object is the selected armature
const
[
Constraint
.
Settings
.
CHAINLEN
]
=
i
+
1
#boxBones.index(bone) + 1 #add chainlen value
const
.
influence
=
1.0
if
chaintype
==
1
:
#single bone
if
const
!=
None
:
const
[
Constraint
.
Settings
.
BONE
]
=
lastBone
#active bones list selection is target bone
const
[
Constraint
.
Settings
.
CHAINLEN
]
=
chain_len
#user-specified chainlen value
elif
chaintype
==
2
:
bone1
=
AData
.
bones
[
bone
]
h
=
ob
.
getData
()
.
bones
[
bone
]
.
head
[
'ARMATURESPACE'
]
t
=
ob
.
getData
()
.
bones
[
bone
]
.
tail
[
'ARMATURESPACE'
]
dirextup
=
(
abs
(
t
[
0
]
-
h
[
0
]),
abs
(
t
[
1
]
-
h
[
1
]),
abs
(
t
[
2
]
-
h
[
2
]))
direx
=
max
(
dirextup
)
#find direction in which bone y axis points
if
boxBones
.
index
(
bone
)
==
len
(
boxBones
)
-
1
:
#create goal bone and parent Poser goal actor to it
if
option
==
2
:
_t
=
ob
.
getData
()
.
bones
[
boxBones
[
len
(
boxBones
)
-
2
]]
.
tail
[
'ARMATURESPACE'
]
_h
=
ob
.
getData
()
.
bones
[
boxBones
[
len
(
boxBones
)
-
2
]]
.
head
[
'ARMATURESPACE'
]
else
:
_t
=
t
_h
=
h
dirextup2
=
(
abs
(
_t
[
0
]
-
_h
[
0
]),
abs
(
_t
[
1
]
-
_h
[
1
]),
abs
(
_t
[
2
]
-
_h
[
2
]))
direx2
=
max
(
dirextup2
)
#find direction in which bone y axis points
if
direx2
==
dirextup2
[
0
]:
length
=
max
(
abs
(
abs
(
_t
[
0
])
-
abs
(
_h
[
0
]))
/
2
,
rootlen
/
3
)
elif
direx2
==
dirextup2
[
1
]:
length
=
max
(
abs
(
abs
(
_t
[
1
])
-
abs
(
_h
[
1
]))
/
2
,
rootlen
/
3
)
elif
direx2
==
dirextup2
[
2
]:
length
=
max
(
abs
(
abs
(
_t
[
2
])
-
abs
(
_h
[
2
]))
/
2
,
rootlen
/
3
)
_taillen
=
_t
[
1
]
-
length
if
_t
[
2
]
<
-
0.003
:
_taillen
=
-
(
_taillen
/
option
)
#needs work
_tail
=
Vector
(
_t
[
0
],
_taillen
,
_t
[
2
])
if
direx
==
dirextup
[
1
]:
_tail
=
Vector
(
_t
[
0
],
_t
[
1
],
_taillen
)
create_bone
(
AData
,
inkyname
,
Vector
(
_t
[
0
],
_t
[
1
],
_t
[
2
]),
_tail
,
0.0
)
AData
.
bones
[
inkyname
]
.
parent
=
AData
.
bones
[
root
]
if
option
==
2
:
bone1
.
parent
=
AData
.
bones
[
inkyname
]
if
(
option
==
2
and
boxBones
.
index
(
bone
)
==
len
(
boxBones
)
-
2
)
or
\
(
option
==
1
and
boxBones
.
index
(
bone
)
==
len
(
boxBones
)
-
1
):
#point last link in Blender chain at goal bone
const
[
Constraint
.
Settings
.
BONE
]
=
inkyname
if
(
option
==
2
and
boxBones
.
index
(
bone
)
<
len
(
boxBones
)
-
2
)
or
\
(
option
==
1
and
boxBones
.
index
(
bone
)
<
len
(
boxBones
)
-
1
):
#create bend target bones
if
direx
==
dirextup
[
0
]:
#bone points on x
bend
=
max
(
abs
(
abs
(
t
[
2
])
-
(
abs
(
t
[
0
])
-
abs
(
h
[
0
]))
/
2
),
rootlen
/
3
)
bend
=
-
bend
bend2
=
t
[
1
]
elif
direx
==
dirextup
[
1
]:
#bone points on y
if
t
[
2
]
<
-
0.003
:
bend
=
-
max
(
abs
(
abs
(
t
[
2
])
-
(
abs
(
t
[
1
])
-
abs
(
h
[
1
]))
/
2
),
rootlen
/
3
)
else
:
bend
=
max
(
abs
(
abs
(
t
[
2
])
+
(
abs
(
t
[
1
])
-
abs
(
h
[
1
]))
/
2
),
rootlen
/
3
)
bend2
=
t
[
1
]
elif
direx
==
dirextup
[
2
]:
#bone points on z
bend2
=
max
(
abs
(
abs
(
t
[
1
])
+
(
abs
(
t
[
2
])
-
abs
(
h
[
2
]))
/
2
),
rootlen
/
3
)
bend
=
t
[
2
]
create_bone
(
AData
,
bone
+
"_bend"
,
Vector
(
t
[
0
],
bend2
,
bend
),
Vector
(
t
[
0
],
t
[
1
],
bend
*
2
),
0.0
)
AData
.
bones
[
bone
+
"_bend"
]
.
parent
=
AData
.
bones
[
root
]
const
[
Constraint
.
Settings
.
BONE
]
=
bone
+
"_bend"
if
chaintype
==
2
:
AData
.
update
()
pose
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
except
:
error
=
PupMenu
(
"This feature is only available in versions later than 2.41"
)
def
add_bone
(
switch
):
global
root
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
lastBone
!=
""
:
if
switch
==
2
:
#are more options needed here? Up-down? Right-left?
side
=
PupMenu
(
"Place bone in front of or behind active list bone? %t\
|
Front
(
joint
bends
forward
)
%
x1
|
Behind
(
joint
bends
backward
)
%
x2
")
offset
=
PupFloatInput
(
"Offset:"
,
0.0
,
0.0
,
100.0
,
10
,
2
)
if
side
==
-
1
:
side
=
1
if
offset
==
None
:
offset
=
0.0
AData
=
ob
.
getData
()
pose
=
ob
.
getPose
()
addname
=
PupStrInput
(
"Name for new bone:"
,
"new_bone"
,
25
)
#get a name for the new bone
if
addname
==
None
:
addname
=
"new_bone"
if
addname
in
AData
.
bones
.
keys
():
addname
+=
"_"
+
str
(
len
(
AData
.
bones
.
keys
()))
.
rjust
(
4
,
"0"
)
for
bone
in
AData
.
bones
.
values
():
#find the root bone
if
not
bone
.
hasParent
():
if
bone
.
hasChildren
():
root
=
bone
break
#most of the following specifies positioning relative to active bones list selection
y_dir
=
Vector
(
0
,
1
,
0
)
#Cambo method to find direction in which bone axis points
y_dir
=
y_dir
*
pose
.
bones
[
lastBone
]
.
poseMatrix
.
rotationPart
()
# poseMatrix is worldspace
#y_dir = y_dir * AData.bones[bone].matrix['ARMATURESPACE'].rotationPart()
dx
,
dy
,
dz
=
y_dir
dirtup
=
(
abs
(
dx
),
abs
(
dy
),
abs
(
dz
))
dirtup
=
list
(
dirtup
)
dirmax
=
max
(
dirtup
)
#Find the dominant axis
bone1
=
AData
.
bones
[
lastBone
]
tail_x
=
bone1
.
tail
[
'ARMATURESPACE'
][
0
]
tail_y
=
bone1
.
tail
[
'ARMATURESPACE'
][
1
]
tail_z
=
bone1
.
tail
[
'ARMATURESPACE'
][
2
]
_len
=
max
(
bone1
.
length
/
2
,
root
.
length
/
5
)
#This is arbitrary - set length relative to selection or root
if
switch
<
2
:
_head
=
Vector
(
tail_x
,
tail_y
,
tail_z
)
elif
switch
==
2
:
if
side
==
2
:
offset
=
-
offset
if
dirtup
.
index
(
dirmax
)
<
2
:
tail_z
+=
root
.
length
*
offset
elif
dirtup
.
index
(
dirmax
)
==
2
:
tail_y
+=
root
.
length
*
offset
if
side
==
1
:
if
dirtup
.
index
(
dirmax
)
<
2
:
_head
=
Vector
(
tail_x
,
tail_y
,
tail_z
+
(
_len
/
2
))
elif
dirtup
.
index
(
dirmax
)
==
2
:
_head
=
Vector
(
tail_x
,
tail_y
+
(
_len
/
2
),
tail_z
)
_len
=
-
_len
elif
side
==
2
:
if
dirtup
.
index
(
dirmax
)
<
2
:
_head
=
Vector
(
tail_x
,
tail_y
,
tail_z
-
(
_len
/
2
))
elif
dirtup
.
index
(
dirmax
)
==
2
:
_head
=
Vector
(
tail_x
,
tail_y
-
(
_len
/
2
),
tail_z
)
if
dirtup
.
index
(
dirmax
)
==
0
:
_tail
=
Vector
(
tail_x
,
tail_y
,
tail_z
-
_len
)
elif
dirtup
.
index
(
dirmax
)
==
1
:
_tail
=
Vector
(
tail_x
,
tail_y
,
tail_z
-
_len
)
elif
dirtup
.
index
(
dirmax
)
==
2
:
_tail
=
Vector
(
tail_x
,
tail_y
-
_len
,
tail_z
)
#now add the bone (adapted from epydocs example)
AData
.
makeEditable
()
bone
=
Armature
.
Editbone
()
if
switch
==
0
:
bone
.
parent
=
AData
.
bones
[
lastBone
]
#add mere bone
elif
switch
>
0
:
bone
.
parent
=
AData
.
bones
[
root
.
name
]
#add IK handling bones
bone
.
roll
=
0.0
bone
.
head
=
_head
bone
.
tail
=
_tail
AData
.
bones
[
addname
]
=
bone
AData
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
def
delete_bones
():
#delete selected bones and re-parent their children
global
boxBones
,
lastBone
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
len
(
boxBones
)
>
0
:
warning
=
PupMenu
(
"This will delete all selected bones. Proceed? %t|Yes
%x
1|No
%x
2"
)
if
warning
==
1
:
remove_selected
(
0
)
#Clear any Ipo curves associated with the bones before deleting
AData2
=
ob
.
getData
()
parents
=
{}
#stores a list of all parents of bone
children
=
{}
#stores a list containing immediate children of bone
for
bone
in
boxBones
:
#gather parent and child data before calling makeEditable
if
AData2
.
bones
[
bone
]
.
hasParent
():
parentlist
=
[]
bone1
=
bone
while
AData2
.
bones
[
bone1
]
.
parent
!=
None
:
#Fill the list with the parenting hierarchy
parentlist
.
append
(
AData2
.
bones
[
bone1
]
.
parent
.
name
)
bone1
=
AData2
.
bones
[
bone1
]
.
parent
.
name
parents
[
bone
]
=
parentlist
else
:
parents
[
bone
]
=
None
if
AData2
.
bones
[
bone
]
.
hasChildren
():
childlist
=
list
(
child
.
name
for
child
in
AData2
.
bones
[
bone
]
.
children
)
children
[
bone
]
=
childlist
else
:
children
[
bone
]
=
"None"
AData
=
AData2
#It's silly, but sometimes makeEditable seems to need this....
AData
.
makeEditable
()
for
bone
in
boxBones
:
if
children
[
bone
]
!=
"None"
:
for
child
in
children
[
bone
]:
if
not
child
in
boxBones
:
#Don't try to reparent what will be deleted
if
parents
[
bone
]
!=
None
:
for
bone1
in
parents
[
bone
]:
#Move up the hierarchical chain, find first ancestor not to be deleted
if
not
bone1
in
boxBones
:
AData
.
bones
[
child
]
.
parent
=
AData
.
bones
[
bone1
]
break
else
:
AData
.
bones
[
child
]
.
clearParent
()
#Set parent to None if root has been deleted
del
AData
.
bones
[
bone
]
AData
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
lastBone
=
""
#clear listbox info (can cause problems with number tab)
boxBones
=
[]
def
scale_bones
():
#Re-scale selected bones by specified value
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
boxBones
!=
[]:
scale
=
PupFloatInput
(
"Scaling:"
,
1.0
,
0.001
,
1000.0
,
10
,
2
)
if
scale
==
None
:
scale
=
1.0
#pup inputs can return None
AData
=
ob
.
getData
()
AData
.
makeEditable
()
for
bone
in
boxBones
:
bone
=
AData
.
bones
[
bone
]
_head
=
bone
.
head
_tail
=
bone
.
tail
bone
.
head
=
Vector
(
_head
[
0
]
*
scale
,
_head
[
1
]
*
scale
,
_head
[
2
]
*
scale
)
bone
.
tail
=
Vector
(
_tail
[
0
]
*
scale
,
_tail
[
1
]
*
scale
,
_tail
[
2
]
*
scale
)
AData
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
else
:
error
=
PupMenu
(
"No bones list selection."
)
def
move_bones
():
#translates bones list selections as a group
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
boxBones
!=
[]:
xval
=
Create
(
0.0
)
yval
=
Create
(
0.0
)
zval
=
Create
(
0.0
)
block
=
[]
block
.
append
((
"X translation:"
,
xval
,
-
100.000
,
100.000
,
"Warning: this will alter your armature!"
))
block
.
append
((
"Y translation:"
,
yval
,
-
100.000
,
100.000
,
"Warning: this will alter your armature!"
))
block
.
append
((
"Z translation:"
,
zval
,
-
100.000
,
100.000
,
"Warning: this will alter your armature!"
))
moveVal
=
PupBlock
(
"Translate selected bones"
,
block
)
if
moveVal
==
1
:
AData
=
ob
.
getData
()
AData
.
makeEditable
()
for
bone
in
boxBones
:
bone
=
AData
.
bones
[
bone
]
_head
=
bone
.
head
#editbones are armaturespace
_tail
=
bone
.
tail
bone
.
head
=
Vector
(
_head
[
0
]
+
xval
.
val
,
_head
[
1
]
+
yval
.
val
,
_head
[
2
]
+
zval
.
val
)
bone
.
tail
=
Vector
(
_tail
[
0
]
+
xval
.
val
,
_tail
[
1
]
+
yval
.
val
,
_tail
[
2
]
+
zval
.
val
)
AData
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
else
:
error
=
PupMenu
(
"No bones list selection."
)
def
swap_bones
():
#flips bones list selections over themselves (swaps head and tail)
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
boxBones
!=
[]:
AData
=
ob
.
getData
()
AData
.
makeEditable
()
for
bone
in
boxBones
:
bone
=
AData
.
bones
[
bone
]
hx
=
bone
.
head
[
0
]
#using same assignment method as move_bones leads to zero-sized deletion errors
hy
=
bone
.
head
[
1
]
hz
=
bone
.
head
[
2
]
tx
=
bone
.
tail
[
0
]
ty
=
bone
.
tail
[
1
]
tz
=
bone
.
tail
[
2
]
bone
.
head
=
Vector
(
tx
,
ty
,
tz
)
bone
.
tail
=
Vector
(
hx
,
hy
,
hz
)
AData
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
else
:
error
=
PupMenu
(
"No bones list selection."
)
def
flip_bone_axis
():
#flips bones list selections over selected axes, as a group
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
boxBones
!=
[]:
xval
=
Create
(
0
)
yval
=
Create
(
0
)
zval
=
Create
(
0
)
block
=
[]
block
.
append
((
"Flip X axis"
,
xval
,
"Warning: this will alter your armature!"
))
block
.
append
((
"Flip Y axis"
,
yval
,
"Warning: this will alter your armature!"
))
block
.
append
((
"Flip Z axis"
,
zval
,
"Warning: this will alter your armature!"
))
moveVal
=
PupBlock
(
"Axes to flip:"
,
block
)
if
moveVal
==
1
:
AData
=
ob
.
getData
()
AData
.
makeEditable
()
for
bone
in
boxBones
:
bone
=
AData
.
bones
[
bone
]
hx
=
bone
.
head
[
0
]
hy
=
bone
.
head
[
1
]
hz
=
bone
.
head
[
2
]
tx
=
bone
.
tail
[
0
]
ty
=
bone
.
tail
[
1
]
tz
=
bone
.
tail
[
2
]
if
xval
.
val
==
1
:
hx
=
-
hx
tx
=
-
tx
if
yval
.
val
==
1
:
hy
=
-
hy
ty
=
-
ty
if
zval
.
val
==
1
:
hz
=
-
hz
tz
=
-
tz
bone
.
head
=
Vector
(
hx
,
hy
,
hz
)
bone
.
tail
=
Vector
(
tx
,
ty
,
tz
)
AData
.
update
()
ob
.
makeDisplayList
()
#to refresh the bones display
else
:
error
=
PupMenu
(
"No bones list selection."
)
def
connect_bones
(
switch
):
#connect bone head with parent tail or active bones list selection tail
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
if
len
(
boxBones
)
>
1
:
AData
=
ob
.
getData
()
if
switch
==
0
:
_tail
=
AData
.
bones
[
lastBone
]
.
tail
[
'ARMATURESPACE'
]
elif
switch
==
1
:
parents
=
[]
for
bone
in
boxBones
:
if
AData
.
bones
[
bone
]
.
hasParent
():
par_tail
=
AData
.
bones
[
bone
]
.
parent
.
tail
[
'ARMATURESPACE'
]
parents
.
append
(
par_tail
)
else
:
parents
.
append
(
AData
.
bones
[
bone
]
.
head
[
'ARMATURESPACE'
])
AData
.
makeEditable
()
for
count
,
bone
in
enumerate
(
boxBones
):
if
bone
!=
lastBone
:
if
switch
==
0
:
AData
.
bones
[
bone
]
.
head
=
_tail
elif
switch
==
1
:
AData
.
bones
[
bone
]
.
head
=
parents
[
count
]
AData
.
update
()
ob
.
makeDisplayList
()
def
align_bones
():
#align bones list selections with the axis along which they predominantly point
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
if
len
(
boxBones
)
!=
0
:
AData
=
ob
.
getData
()
AData
.
makeEditable
()
for
bone
in
boxBones
:
y_dir
=
Vector
(
0
,
1
,
0
)
#Cambo method to find direction in which bone axis points
bone
=
AData
.
bones
[
bone
]
hx
=
bone
.
head
[
0
]
hy
=
bone
.
head
[
1
]
hz
=
bone
.
head
[
2
]
tx
=
bone
.
tail
[
0
]
ty
=
bone
.
tail
[
1
]
tz
=
bone
.
tail
[
2
]
y_dir
=
y_dir
*
bone
.
matrix
.
rotationPart
()
xd
,
yd
,
zd
=
y_dir
y_dir
=
[
abs
(
xd
),
abs
(
yd
),
abs
(
zd
)]
dirmax
=
max
(
y_dir
)
#this may get funny with 45 degree angles....
if
y_dir
.
index
(
dirmax
)
==
0
:
bone
.
tail
=
Vector
(
tx
,
hy
,
hz
)
elif
y_dir
.
index
(
dirmax
)
==
1
:
bone
.
tail
=
Vector
(
hx
,
ty
,
hz
)
elif
y_dir
.
index
(
dirmax
)
==
2
:
bone
.
tail
=
Vector
(
hx
,
hy
,
tz
)
AData
.
update
()
ob
.
makeDisplayList
()
def
align_chains
():
#align bones with parents, straightening chains
global
boxBones
,
boxList
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
if
len
(
boxBones
)
!=
0
:
hval
=
Create
(
0
)
tval
=
Create
(
0
)
block
=
[]
block
.
append
((
"head to parent tail"
,
hval
,
"Warning: this will alter your armature!"
))
block
.
append
((
"tail to parent tail"
,
tval
,
"Warning: this will alter your armature!"
))
moveVal
=
PupBlock
(
"Align bones:"
,
block
)
if
moveVal
==
1
:
if
flipDict
==
{}:
flip
()
AData
=
ob
.
getData
()
parents
=
[]
boxBones
=
sort_hierarchy
(
boxBones
)
for
bone
in
boxBones
:
if
AData
.
bones
[
bone
]
.
hasChildren
():
numchild
=
len
(
AData
.
bones
[
bone
]
.
children
)
else
:
numchild
=
0
if
AData
.
bones
[
bone
]
.
hasParent
():
par_tail
=
(
AData
.
bones
[
bone
]
.
parent
.
name
,
AData
.
bones
[
bone
]
.
parent
.
tail
[
'ARMATURESPACE'
],
numchild
)
else
:
par_tail
=
(
"None"
,
AData
.
bones
[
bone
]
.
head
[
'ARMATURESPACE'
],
numchild
)
parents
.
append
(
par_tail
)
AData
.
makeEditable
()
for
count
,
bone
in
enumerate
(
boxBones
):
y_dir
=
Vector
(
0
,
1
,
0
)
bone
=
AData
.
bones
[
bone
]
_tail
=
parents
[
count
][
1
]
hx
=
bone
.
head
[
0
]
hy
=
bone
.
head
[
1
]
hz
=
bone
.
head
[
2
]
tpx
=
_tail
[
0
]
tpy
=
_tail
[
1
]
tpz
=
_tail
[
2
]
y_dir
=
y_dir
*
bone
.
matrix
.
rotationPart
()
xd
,
yd
,
zd
=
y_dir
y_dir
=
[
abs
(
xd
),
abs
(
yd
),
abs
(
zd
)]
dirmax
=
max
(
y_dir
)
if
y_dir
.
index
(
dirmax
)
==
0
:
if
parents
[
count
][
2
]
==
1
:
if
hval
.
val
==
1
:
bone
.
head
=
Vector
(
hx
,
tpy
,
tpz
)
if
tval
.
val
==
1
:
bone
.
tail
=
Vector
(
bone
.
tail
[
0
],
tpy
,
tpz
)
elif
y_dir
.
index
(
dirmax
)
==
1
:
if
(
parents
[
count
][
0
]
in
flipDict
and
bone
.
name
in
flipDict
)
or
\
(
parents
[
count
][
0
]
not
in
flipDict
and
bone
.
name
not
in
flipDict
):
if
hval
.
val
==
1
:
bone
.
head
=
Vector
(
tpx
,
hy
,
tpz
)
if
tval
.
val
==
1
:
bone
.
tail
=
Vector
(
tpx
,
bone
.
tail
[
1
],
tpz
)
elif
y_dir
.
index
(
dirmax
)
==
2
:
if
parents
[
count
][
2
]
==
1
:
if
hval
.
val
==
1
:
bone
.
head
=
Vector
(
tpx
,
tpy
,
hz
)
if
tval
.
val
==
1
:
bone
.
tail
=
Vector
(
tpx
,
tpy
,
bone
.
tail
[
2
])
AData
.
update
()
ob
.
makeDisplayList
()
boxList
=
sort_hierarchy
(
boxList
)
#------Other bone functions------------------------------------------------------------------
def
sort_hierarchy
(
bonelist
):
#produces a hierarchically sorted bone list
global
listTree
if
len
(
bonelist
)
!=
0
:
#if the submitted list isn't blank
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
AData
=
ob
.
getData
()
templist
=
[]
levellist
=
[]
listTree
=
[]
level
=
0
for
bone
in
AData
.
bones
.
keys
():
#a separate loop to force these to be first in list
if
not
AData
.
bones
[
bone
]
.
hasParent
():
templist
.
append
(
bone
)
levellist
.
append
(
level
)
templist
.
sort
()
for
bone
in
templist
:
if
AData
.
bones
[
bone
]
.
hasChildren
():
children
=
sorted
(
child
.
name
for
child
in
AData
.
bones
[
bone
]
.
children
)
children
.
reverse
()
for
child
in
children
:
level
=
levellist
[
templist
.
index
(
AData
.
bones
[
child
]
.
parent
.
name
)]
+
1
if
not
child
in
templist
:
if
not
AData
.
bones
[
child
]
.
parent
.
name
in
templist
:
templist
.
append
(
child
)
levellist
.
append
(
level
)
else
:
templist
.
insert
(
templist
.
index
(
AData
.
bones
[
child
]
.
parent
.
name
)
+
1
,
child
)
levellist
.
insert
(
templist
.
index
(
AData
.
bones
[
child
]
.
parent
.
name
)
+
1
,
level
)
templist2
=
[]
for
bone
in
templist
:
#templist contains all bones. Now screen against submitted list
if
bone
in
bonelist
:
templist2
.
append
(
bone
)
if
AData
.
bones
[
bone
]
.
parent
:
level
=
levellist
[
templist
.
index
(
bone
)]
#listTree.append((AData.bones[bone].parent.name,level))
listTree
.
append
(
level
)
#else: listTree.append(("None",0))
else
:
listTree
.
append
(
0
)
#print zip(templist2,listTree)
return
templist2
else
:
return
[]
#Need to return a blank list if one was submitted as an argument
def
bone_search
():
global
boxBones
,
lastBone
name
=
PupStrInput
(
"Name of bone:"
,
""
,
50
)
#get a name for the new bone
if
name
!=
None
and
name
!=
""
:
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
try
:
pose
=
ob
.
getPose
()
if
name
[
-
1
:]
==
"*"
:
prog
=
re
.
compile
(
name
[:
-
1
],
re
.
I
)
#wildcards
else
:
prog
=
re
.
compile
(
name
)
#case sensitive
for
bone
in
pose
.
bones
.
keys
():
result
=
prog
.
search
(
bone
)
if
name
==
bone
or
result
!=
None
:
pose
.
bones
[
bone
]
.
sel
=
TRUE
if
bone
not
in
boxBones
:
boxBones
.
append
(
bone
)
lastBone
=
bone
pose
.
update
()
except
:
pass
#pose bone .sel is not available in current (Sept 06) formal release of 242, only CVS
def
bone_grab
():
if
Object
.
GetSelected
()
!=
[]:
#if there is a current selection in 3d view
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
#if there is an armature selection
try
:
pose
=
ob
.
getPose
()
if
len
(
boxBones
)
!=
0
:
for
bone
in
boxBones
:
pose
.
bones
[
bone
]
.
sel
=
1
-
pose
.
bones
[
bone
]
.
sel
#toggle selection
elif
len
(
boxBones
)
==
0
:
#clear selections if box is empty
for
bone
in
pose
.
bones
.
values
():
bone
.
sel
=
FALSE
pose
.
update
()
ob
.
makeDisplayList
()
Blender
.
Redraw
()
except
:
pass
#pose bone .sel is not available in current (Sept 06) formal release of 242, only CVS
##----------------Poser-specific functions----------------------------------
#-------Poser pose (.pz2 or .p2z) export functions-------------------------------------------------
def
save_poser
(
ob
,
pose
):
global
NoRollPose
,
PoserConvert
,
curFrame
poseText
=
""
temp
=
NoRollPose
NoRollPose
=
1
#Poser poses are restMatrix type
frames
=
[]
#the list of frames to export
runAnim
=
0
#armature can have an action with no keyframes, so we need a control variable
curframe
=
Blender
.
Get
(
'curframe'
)
#local - used to advance frames for posematrix use
curFrame
=
Blender
.
Get
(
'curframe'
)
#global - used to reset start frame at end of run
#thighLen = ""
if
ob
.
getAction
():
act
=
ob
.
getAction
()
if
len
(
act
.
getAllChannelIpos
())
>
0
:
#if there are keyframes
runAnim
=
1
if
saveBatch
==
1
and
runAnim
==
1
:
#animation
if
batchFrames
==
0
:
#not using frames list screening
framelen
=
PupIntInput
(
"animation length:"
,
1
,
Blender
.
Get
(
'staframe'
),
Blender
.
Get
(
'endframe'
))
if
framelen
==
None
:
framelen
=
1
frames
=
list
(
i
+
curframe
for
i
in
range
(
framelen
))
elif
batchFrames
==
1
:
#with frames list screening
if
len
(
boxFrames
)
>
0
:
frames_sort
()
frames
=
list
(
int
(
i
)
for
i
in
boxFrames
)
elif
saveBatch
==
0
or
runAnim
==
0
:
#single frame; only current
frames
.
append
(
curframe
)
poseText
+=
"{
\n
version
\n\t
{
\n\t
number
\n\t
}
\n\n
"
#version header
if
saveBatch
==
1
and
runAnim
==
1
:
poseText
+=
"clearFigureKeys
%i
\n\n
"
%
(
frames
[
len
(
frames
)
-
1
])
#clears the keyframes in Poser
bonelist
=
pose
.
bones
.
keys
()
#bonelist.sort() #alphabetical sort
bonelist
=
sort_hierarchy
(
bonelist
)
#get the hierarchical setup
AData
=
ob
.
getData
()
for
bone
in
AData
.
bones
.
keys
():
#Poser pose format omits root part - not necessary
if
not
AData
.
bones
[
bone
]
.
hasParent
():
if
AData
.
bones
[
bone
]
.
hasChildren
():
bonelist
.
remove
(
bone
)
#if AData.bones[bone].name == "rThigh": #only mess with thighLength if this is a Poser-derived armature
# thighLen = "thighLength %f\n\n" %(AData.bones[bone].length)
# poseText += thighLen
for
bone
in
bonelist
:
if
JPdict
==
{}
or
len
(
JPdict
.
keys
())
!=
len
(
AData
.
bones
.
keys
()):
axis_direction
(
AData
,
0
)
#get generic rotation orders for bones without defined joint orders
order
=
JPdict
[
bone
]
#define joint rotation order
rxlist
=
[]
#we only need to worry about six parameters
rylist
=
[]
#these are lists for those parameters
rzlist
=
[]
txlist
=
[]
tylist
=
[]
tzlist
=
[]
curvelist
=
[]
#stores the Ipo curves
savePart
=
save_part
(
bone
)
#screening check
if
savePart
==
1
:
if
saveBatch
==
1
and
runAnim
==
1
:
#act is defined when runAnim is set, above
if
bone
in
act
.
getAllChannelIpos
():
#if the bone is keyframed
ipo
=
act
.
getChannelIpo
(
bone
)
#gather together all the key data for the bone
icu_locx
=
ipo
[
Ipo
.
PO_LOCX
]
#1
icu_locy
=
ipo
[
Ipo
.
PO_LOCY
]
#2
icu_locz
=
ipo
[
Ipo
.
PO_LOCZ
]
#3
icu_quatw
=
ipo
[
Ipo
.
PO_QUATW
]
#25
icu_quatx
=
ipo
[
Ipo
.
PO_QUATX
]
#26
icu_quaty
=
ipo
[
Ipo
.
PO_QUATY
]
#27
icu_quatz
=
ipo
[
Ipo
.
PO_QUATZ
]
#28
curvelist
=
[
icu_locx
,
icu_locy
,
icu_locz
,
icu_quatw
,
icu_quatx
,
icu_quaty
,
icu_quatz
]
for
framenum
in
frames
:
#loop through the frames to reorganize all the frame data
lx
=
0
ly
=
0
lz
=
0
qw
=
0
qx
=
0
qy
=
0
qz
=
0
if
saveBatch
==
1
and
runAnim
==
1
:
#get the data for each frame if we're handling multiple frames
for
count
,
icu
in
enumerate
(
curvelist
):
if
icu
!=
None
and
len
(
icu
.
bezierPoints
)
>
0
:
#We might get errors is some parameters lack curves....
if
count
==
0
:
lx
=
icu
[
framenum
]
elif
count
==
1
:
ly
=
icu
[
framenum
]
elif
count
==
2
:
lz
=
icu
[
framenum
]
elif
count
==
3
:
qw
=
icu
[
framenum
]
elif
count
==
4
:
qx
=
icu
[
framenum
]
elif
count
==
5
:
qy
=
icu
[
framenum
]
elif
count
==
6
:
qz
=
icu
[
framenum
]
quat
=
Quaternion
(
qw
,
qx
,
qy
,
qz
)
##compile the quaternion rotations
elif
saveBatch
==
0
or
runAnim
==
0
:
quat
=
pose
.
bones
[
bone
]
.
quat
#if we're only doing current frame, get the current pose values
lx
,
ly
,
lz
=
pose
.
bones
[
bone
]
.
loc
if
IKPose
==
1
:
#posematrix needs to get data from current frame - this is very bloody slow!!!!
Blender
.
Set
(
'curframe'
,
framenum
)
quat
=
save_convert
(
ob
,
pose
,
pose
.
bones
[
bone
],
quat
)
#Do the restmatrix/posematrix conversions
#qx,qy,qz = quat.toEuler()#.unique() #convert the quaternion to euler for Poser (unique doesn't help)
qx
,
qy
,
qz
=
quat_to_euler2
(
quat
)
#alternate conversion returns better results - but still not quite right....
rxlist
.
append
(
qx
)
#append the gathered animation data to the proper list for each parameter
rylist
.
append
(
qy
)
rzlist
.
append
(
qz
)
txlist
.
append
(
lx
)
tylist
.
append
(
lz
)
#flip y and z... not really sure if this helps anything, or not....
tzlist
.
append
(
ly
)
params1
=
[]
#a list to store Poser parameter names
params2
=
[]
#a list to store the corresponding list of animation data (created above)
for
axis
in
order
:
#order is a list containing the joint rotation order
if
axis
==
0
:
#fill the parameters lists - this is where we specify joint rotation order
params1
.
append
(
"rotateX xrot"
)
params2
.
append
(
rxlist
)
elif
axis
==
1
:
params1
.
append
(
"rotateY yrot"
)
params2
.
append
(
rylist
)
elif
axis
==
2
:
params1
.
append
(
"rotateZ zrot"
)
params2
.
append
(
rzlist
)
params1
.
append
(
"translateX xtran"
)
params1
.
append
(
"translateY ytran"
)
params1
.
append
(
"translateZ ztran"
)
params2
.
append
(
txlist
)
params2
.
append
(
tylist
)
params2
.
append
(
tzlist
)
poseText
+=
"actor
%s
:1
\n\t
{
\n\t
channels
\n\t\t
{
\n
"
%
(
bone
)
#actor line
for
channel
,
param
in
zip
(
params1
,
params2
):
#correlate the two parameters lists
poseText
+=
"
\t\t
%s
\n\t\t\t
{
\n\t\t\t
keys
\n\t\t\t\t
{
\n
"
%
(
channel
)
#channel line and keys
for
value
in
param
:
#identify parameters with all zero keys - only export the first key for these
if
round
(
value
,
6
)
<>
0.000000
:
allZero
=
0
break
else
:
allZero
=
1
for
key
,
value
in
enumerate
(
param
):
if
allZero
==
0
:
if
saveBatch
==
1
and
runAnim
==
1
:
frame
=
frames
[
key
]
-
1
#multi-frame saves to frame index
elif
saveBatch
==
0
or
runAnim
==
0
:
frame
=
key
#single frame should save to zero
elif
allZero
==
1
and
key
==
0
:
frame
=
key
poseText
+=
"
\t\t\t\t
k
%i
%f
\n
"
%
(
frame
,
value
)
#add each keyframe, value pair - double spaces between!
#if allZero == 0:
# poseText += "\t\t\t\tsl 1\n\t\t\t\tspl\n\t\t\t\tsm\n" #spline interpolation listings
#elif allZero == 1: break
if
allZero
==
1
:
break
poseText
+=
"
\t\t\t\t
}
\n
"
#close all the brackets
poseText
+=
"
\t\t\t
}
\n
"
poseText
+=
"
\t\t
}
\n\t
}
\n\n
"
#(That's a lotta brackets....)
poseText
+=
"figure
\n\t
{
\n\t
}
\n
"
#figure section at end of pose
poseText
+=
"
\n
version
\n\t
{
\n\t
number
\n\t
}
\n\n
"
#IK section repeats header,clearfigure, and figure blocks
if
saveBatch
==
1
and
runAnim
==
1
:
poseText
+=
"clearFigureKeys
%i
\n\n
"
%
(
frames
[
len
(
frames
)
-
1
])
#if thighLen != "": poseText += thighLen
poseText
+=
"figure
\n\t
{
\n\t
}
\n
}"
NoRollPose
=
temp
#reset restMatrix save value
if
IKPose
==
1
:
Blender
.
Set
(
'curframe'
,
curFrame
)
#restore the start frame if posematrix has had us walk the frames
return
poseText
JPdict
=
{}
def
axis_direction
(
AData
,
switch
):
#find generic joint rotation orders for Poser export
#Generic orders are based on a sampling of applied rotation orders in Poser figures. When building a Poser figure,
#'bend' apparently s/b the axis least likely to receive 90 degrees rotation - but that standard rarely seems to have
#been followed with existing figs. Here, bend is the common bend axis in most figures I examined.
for
bone
in
AData
.
bones
.
keys
():
if
switch
==
1
or
bone
not
in
JPdict
:
bonemat
=
AData
.
bones
[
bone
]
.
matrix
[
'ARMATURESPACE'
]
.
rotationPart
()
direx
=
[
"X"
,
"Y"
,
"Z"
]
y_dir
=
[
bonemat
[
1
][
0
],
bonemat
[
1
][
1
],
bonemat
[
1
][
2
]]
y_dir2
=
list
(
abs
(
i
)
for
i
in
y_dir
)
y_dir3
=
max
(
y_dir2
)
#direction in which bone y axis points
direx
[
0
]
=
y_dir2
.
index
(
y_dir3
)
if
direx
[
0
]
==
0
:
#x-pointing bone
direx
[
1
]
=
1
#assume most humanoid rigs will have y-bend for x-twist bones
elif
direx
[
0
]
==
1
:
#y-pointing
direx
[
1
]
=
0
#assume most humanoid rigs will have x-bend for y-twist bones
elif
direx
[
0
]
==
2
:
#z-pointing
direx
[
1
]
=
1
#assume most humanoid rigs will have y-bend for z-twist bones
for
i
in
range
(
3
):
#fill direx[2] with whichever axis is left unaccounted for
if
not
i
in
direx
:
direx
[
2
]
=
i
break
JPdict
[
bone
]
=
direx
#------quaternion conversion---------------------------------------------------------
def
quat_to_euler2
(
q1
):
#adapted from Maths - Conversion Quaternion to Euler - Martin Baker
#http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm
sqw
=
q1
.
w
*
q1
.
w
sqx
=
q1
.
x
*
q1
.
x
sqy
=
q1
.
y
*
q1
.
y
sqz
=
q1
.
z
*
q1
.
z
unit
=
sqx
+
sqy
+
sqz
+
sqw
# if normalised is one, otherwise is correction factor
test
=
(
q1
.
x
*
q1
.
y
)
+
(
q1
.
z
*
q1
.
w
)
#test = (q1.x*q1.z) - (q1.y*q1.w)
if
test
>
0.499
*
unit
:
# and test < 0.501*unit: # singularity at north pole
#print "north", test, unit, 0.498*unit, 0.501*unit
bank
=
2
*
math
.
atan2
(
q1
.
x
,
q1
.
w
)
attitude
=
math
.
pi
/
2
heading
=
0
elif
test
<
-
0.499
*
unit
:
# and test > -0.501*unit: # singularity at south pole
#print "south", test, unit, -0.498*unit, -0.501*unit
bank
=
-
2
*
math
.
atan2
(
q1
.
x
,
q1
.
w
)
attitude
=
-
math
.
pi
/
2
heading
=
0
else
:
heading
=
math
.
atan2
(
2
*
q1
.
y
*
q1
.
w
-
2
*
q1
.
x
*
q1
.
z
,
sqx
-
sqy
-
sqz
+
sqw
)
attitude
=
math
.
asin
(
2
*
test
/
unit
)
bank
=
math
.
atan2
(
2
*
q1
.
x
*
q1
.
w
-
2
*
q1
.
y
*
q1
.
z
,
-
sqx
+
sqy
-
sqz
+
sqw
)
return
r2d
(
bank
),
r2d
(
heading
),
r2d
(
attitude
)
#return r2d(heading),r2d(attitude),r2d(bank)
#-----joint order functions----------------------------------------------
def
change_JP_order
():
if
len
(
boxBones
)
>
0
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
if
JPdict
==
{}:
axis_direction
(
ob
.
getData
(),
1
)
if
JPdict
!=
{}:
menu
=
PupMenu
(
"New joint rotation order for bones list selections: %t|XYZ
%x
1|XZY
%x
2|YXZ
%x
3\
|
YZX
%
x4
|
ZXY
%
x5
|
ZYX
%
x6
|
Cancel
%
x7
")
if
menu
!=
7
:
if
menu
==
1
:
order
=
[
0
,
1
,
2
]
elif
menu
==
2
:
order
=
[
0
,
2
,
1
]
elif
menu
==
3
:
order
=
[
1
,
0
,
2
]
elif
menu
==
4
:
order
=
[
1
,
2
,
0
]
elif
menu
==
5
:
order
=
[
2
,
0
,
1
]
elif
menu
==
6
:
order
=
[
2
,
1
,
0
]
for
bone
in
boxBones
:
JPdict
[
bone
]
=
order
else
:
error
=
PupMenu
(
"You must make an armature selection to use this function."
)
else
:
error
=
PupMenu
(
"You must make one or more bones listbox selections to use this function."
)
def
export_JP_order
(
save_name
):
#
if
save_name
!=
""
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
temptext
=
""
pose
=
ob
.
getPose
()
if
JPdict
==
{}:
axis_direction
(
ob
.
getData
(),
1
)
for
bone
in
pose
.
bones
.
keys
():
rotOrder
=
""
order
=
JPdict
[
bone
]
for
i
in
order
:
if
i
==
0
:
rotOrder
+=
"X"
elif
i
==
1
:
rotOrder
+=
"Y"
elif
i
==
2
:
rotOrder
+=
"Z"
temptext
+=
"
%s
,
%s
,
%s
,
%s
\n
"
%
(
bone
,
rotOrder
[
0
],
rotOrder
[
1
],
rotOrder
[
2
])
save_name
=
os
.
path
.
splitext
(
save_name
)[
0
]
+
".txt"
if
sys
.
exists
(
save_name
)
==
1
:
warning
=
PupMenu
(
"Overwrite file
%s
?
%%
t|Yes
%%
x1|No
%%
x2"
%
(
sys
.
basename
(
save_name
)))
#Don't overwrite
if
sys
.
exists
(
save_name
)
!=
1
or
warning
!=
2
:
jpsave
=
open
(
save_name
,
"w"
)
jpsave
.
write
(
temptext
)
jpsave
.
close
()
def
save_JP_order
(
save_name
):
#saves a rotation order text file straight from JP dict
if
save_name
!=
""
:
if
JPdict
!=
{}:
temptext
=
""
for
key
,
value
in
JPdict
.
iteritems
():
rotOrder
=
""
for
i
in
value
:
if
i
==
0
:
rotOrder
+=
"X"
elif
i
==
1
:
rotOrder
+=
"Y"
elif
i
==
2
:
rotOrder
+=
"Z"
temptext
+=
"
%s
,
%s
,
%s
,
%s
\n
"
%
(
key
,
rotOrder
[
0
],
rotOrder
[
1
],
rotOrder
[
2
])
save_name
=
os
.
path
.
splitext
(
save_name
)[
0
]
+
".txt"
if
sys
.
exists
(
save_name
)
==
1
:
warning
=
PupMenu
(
"Overwrite file
%s
?
%%
t|Yes
%%
x1|No
%%
x2"
%
(
sys
.
basename
(
save_name
)))
#Don't overwrite
if
sys
.
exists
(
save_name
)
!=
1
or
warning
!=
2
:
jpsave
=
open
(
save_name
,
"w"
)
jpsave
.
write
(
temptext
)
jpsave
.
close
()
def
import_JP_order
(
file_name
):
#imports a rotation order text file saved by this script
if
file_name
!=
""
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
pose
=
ob
.
getPose
()
temptext
=
open
(
file_name
,
"r"
)
lines
=
temptext
.
readlines
()
for
line
in
lines
:
data
=
line
.
rstrip
(
"
\n
"
)
.
split
(
","
)
if
data
[
0
]
in
pose
.
bones
.
keys
():
#Keep dict from being badly updated; would create errors later
rotOrder
=
[]
for
i
in
range
(
1
,
4
):
if
data
[
i
]
==
"X"
:
rotOrder
.
append
(
0
)
elif
data
[
i
]
==
"Y"
:
rotOrder
.
append
(
1
)
elif
data
[
i
]
==
"Z"
:
rotOrder
.
append
(
2
)
JPdict
[
data
[
0
]]
=
rotOrder
temptext
.
close
()
def
parse_JP_order
(
file_name
):
#parses rotation orders out of a Poser .pz2 or .cr2 file
if
file_name
!=
""
:
ext
=
os
.
path
.
splitext
(
file_name
)[
1
]
if
ext
==
".cr2"
or
ext
==
".pz2"
or
ext
==
".crz"
or
ext
==
".p2z"
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
pose
=
ob
.
getPose
()
if
ext
[
3
]
==
"2"
:
temptext
=
open
(
file_name
,
"r"
)
if
ext
[
3
]
==
"z"
:
try
:
import
gzip
temptext
=
gzip
.
GzipFile
(
file_name
)
except
:
error
=
Blender
.
Draw
.
PupMenu
(
"Could not read .pzz file. Try decompressing and reading as .pz2"
)
return
lines
=
temptext
.
readlines
()
name
=
""
rotOrder
=
[]
if
len
(
lines
)
==
1
:
lines
=
lines
[
0
]
.
replace
(
"
\r
"
,
"
\n
"
)
.
split
(
"
\n
"
)
#if it's all been read as one line
for
line
in
lines
:
line
=
line
.
replace
(
"
\n
"
,
""
)
.
replace
(
"
\t
"
,
""
)
.
replace
(
"
\r
"
,
""
)
.
replace
(
" "
,
" "
)
if
line
.
find
(
"actor"
)
!=
-
1
:
name
=
line
.
split
(
":"
)[
0
]
.
replace
(
"actor "
,
""
)
if
name
!=
""
:
if
line
.
find
(
"xrot"
)
!=
-
1
:
rotOrder
.
append
(
0
)
if
line
.
find
(
"yrot"
)
!=
-
1
:
rotOrder
.
append
(
1
)
if
line
.
find
(
"zrot"
)
!=
-
1
:
rotOrder
.
append
(
2
)
if
name
!=
""
and
len
(
rotOrder
)
==
3
:
if
name
in
pose
.
bones
.
keys
():
JPdict
[
name
]
=
rotOrder
name
=
""
rotOrder
=
[]
temptext
.
flush
()
temptext
.
close
()
if
JPdict
!=
{}:
menu
=
PupMenu
(
"Save rotation data as text file? %t|Yes
%x
1|No
%x
2"
)
if
menu
==
1
:
Window
.
FileSelector
(
save_JP_order
,
'Browse for save location.'
)
#---------Poser file reading--------------------------------------------------------
#This is called by create_armature(); this merely collects data - create armature makes the rig
def
parse_poser_file
(
file_name
):
#Build an armature from a .cr2 file, optionally including IK and rotation order save
if
file_name
!=
""
:
ext
=
os
.
path
.
splitext
(
file_name
)[
1
]
if
ext
==
".cr2"
or
ext
==
".crz"
:
IKask
=
PupMenu
(
"Add IK to armature? %t|Yes
%x
1|No
%x
2|Yes, but omit 'Collar' parts
%x
3"
)
startTime
=
sys
.
time
()
#keep track of speed
if
ext
[
3
]
==
"2"
:
temptext
=
open
(
file_name
,
"r"
)
if
ext
[
3
]
==
"z"
:
try
:
import
gzip
temptext
=
gzip
.
GzipFile
(
file_name
)
except
:
error
=
Blender
.
Draw
.
PupMenu
(
"Could not read .pzz file. Try decompressing and reading as .pz2"
)
return
lines
=
temptext
.
readlines
()
flag
=
0
data
=
[]
rotOrder
=
[]
IKlist
=
[]
temp
=
[
"name"
,
"h0"
,
"h1"
,
"h2"
,
"t0"
,
"t1"
,
"t2"
,
"None"
]
if
len
(
lines
)
==
1
:
lines
=
lines
[
0
]
.
replace
(
"
\r
"
,
"
\n
"
)
.
split
(
"
\n
"
)
#Macs save \r and .crz reading fails to split at \r
for
indx
,
line
in
enumerate
(
lines
):
line
=
line
.
replace
(
"
\n
"
,
""
)
.
replace
(
"
\t
"
,
""
)
.
replace
(
"
\r
"
,
""
)
.
replace
(
" "
,
" "
)
if
line
.
find
(
"actor"
)
!=
-
1
and
lines
[
indx
+
2
]
.
find
(
"name"
)
!=
-
1
:
#get the bone name
name
=
line
.
split
(
":"
)[
0
]
.
replace
(
"actor "
,
""
)
.
replace
(
"
\t
"
,
""
)
.
replace
(
"
\n
"
,
""
)
.
replace
(
"
\r
"
,
""
)
temp
[
0
]
=
name
if
line
.
find
(
"parent"
)
!=
-
1
:
#get the parent name
if
lines
[
indx
+
2
]
.
find
(
"nonInkyParent"
)
!=
-
1
:
#if cr2 was saved with IK on
read
=
lines
[
indx
+
2
]
.
split
(
":"
)[
0
]
.
replace
(
"
\n
"
,
""
)
.
replace
(
"
\t
"
,
""
)
.
replace
(
"
\r
"
,
""
)
.
split
(
" "
)
else
:
read
=
line
.
split
(
":"
)[
0
]
.
split
(
" "
)
if
read
[
1
]
!=
"UNIVERSE"
:
temp
[
7
]
=
read
[
1
]
else
:
root
=
name
if
len
(
rotOrder
)
<
3
:
#get the joint rotation order for the actor
if
line
.
find
(
"xrot"
)
!=
-
1
:
rotOrder
.
append
(
0
)
if
line
.
find
(
"yrot"
)
!=
-
1
:
rotOrder
.
append
(
1
)
if
line
.
find
(
"zrot"
)
!=
-
1
:
rotOrder
.
append
(
2
)
if
line
.
find
(
"endPoint"
)
!=
-
1
:
#get the endPoint data (tail)
read
=
line
.
split
(
" "
)
for
i
in
range
(
1
,
4
):
temp
[
i
+
3
]
=
read
[
i
]
if
line
.
find
(
"origin"
)
!=
-
1
:
#get the origin data (head)
read
=
line
.
split
(
" "
)
for
i
in
range
(
1
,
4
):
temp
[
i
]
=
read
[
i
]
flag
=
1
#build the IK structure-------------------------------------------------------------
if
IKask
==
1
or
IKask
==
3
:
if
line
.
find
(
"inkyChain"
)
!=
-
1
:
inkyname
=
line
.
replace
(
"inkyChain "
,
""
)
.
strip
()
IKlist
=
[]
num
=
indx
+
4
while
lines
[
num
]
.
find
(
"linkWeight"
)
==
-
1
:
#fill a list with the IK chain data
if
not
(
IKask
==
3
and
lines
[
num
]
.
find
(
'Collar'
)
!=
-
1
):
#omit collars, which don't handle well w/ Blender IK
IKlist
.
append
(
lines
[
num
]
.
split
(
" "
)[
1
]
.
replace
(
"
\t
"
,
""
)
.
replace
(
"
\n
"
,
""
)
.
replace
(
"
\r
"
,
""
)
.
split
(
":"
)[
0
])
num
+=
1
for
chainlen
,
bone
in
enumerate
(
IKlist
):
for
items
in
data
:
item
=
items
.
split
(
","
)
if
item
[
0
]
==
bone
:
item
[
10
]
=
str
(
chainlen
+
1
)
#add chainlen value
if
chainlen
<
len
(
IKlist
)
-
2
:
#create bend target bones
dirextup
=
(
abs
(
float
(
item
[
5
])
-
float
(
item
[
2
])),
abs
(
float
(
item
[
6
])
-
float
(
item
[
3
])),
abs
(
float
(
item
[
7
])
-
float
(
item
[
4
])))
direx
=
max
(
dirextup
)
#find direction in which bone y axis points
if
direx
==
dirextup
[
0
]:
#bone points on x
bend
=
max
(
abs
(
abs
(
float
(
item
[
7
]))
-
(
abs
(
float
(
item
[
5
]))
-
abs
(
float
(
item
[
2
])))
/
2
),
rootlen
/
3
)
bend
=
-
bend
bend2
=
float
(
item
[
6
])
elif
direx
==
dirextup
[
1
]:
#bone points on y
bend
=
max
(
abs
(
abs
(
float
(
item
[
7
]))
+
(
abs
(
float
(
item
[
6
]))
-
abs
(
float
(
item
[
3
])))
/
2
),
rootlen
/
3
)
bend2
=
float
(
item
[
6
])
elif
direx
==
dirextup
[
2
]:
#bone points on z
bend2
=
max
(
abs
(
abs
(
float
(
item
[
6
]))
+
(
abs
(
float
(
item
[
7
]))
-
abs
(
float
(
item
[
4
])))
/
2
),
rootlen
/
3
)
bend
=
float
(
item
[
7
])
dataline
=
"
%s
,0.0,
%s
,
%f
,
%f
,
%s
,
%s
,
%f
,
%s
,None,0
\n
"
%
(
bone
+
"_bend"
,
item
[
5
],
bend2
,
bend
,
item
[
5
],
item
[
6
],
bend
*
2
,
root
)
data
.
append
(
dataline
)
item
[
9
]
=
bone
+
"_bend"
elif
chainlen
==
len
(
IKlist
)
-
2
:
#point last link in Blender chain at goal bone
item
[
9
]
=
inkyname
elif
chainlen
==
len
(
IKlist
)
-
1
:
#create goal bone and parent Poser goal actor to it
item
[
8
]
=
inkyname
_tail
=
data
[
data
.
index
(
items
)
-
1
]
.
split
(
","
)
if
direx
==
dirextup
[
0
]:
length
=
max
(
abs
(
abs
(
float
(
_tail
[
5
]))
-
abs
(
float
(
_tail
[
2
])))
/
2
,
rootlen
/
3
)
elif
direx
==
dirextup
[
1
]:
length
=
max
(
abs
(
abs
(
float
(
_tail
[
6
]))
-
abs
(
float
(
_tail
[
3
])))
/
2
,
rootlen
/
3
)
elif
direx
==
dirextup
[
2
]:
length
=
max
(
abs
(
abs
(
float
(
_tail
[
7
]))
-
abs
(
float
(
_tail
[
4
])))
/
2
,
rootlen
/
3
)
_taillen
=
float
(
_tail
[
6
])
-
length
dataline
=
"
%s
,0.0,
%s
,
%s
,
%s
,
%s
,
%f
,
%s
,
%s
,None,0
\n
"
%
(
inkyname
,
_tail
[
5
],
_tail
[
6
],
_tail
[
7
],
_tail
[
5
],
_taillen
,
_tail
[
7
],
root
)
data
.
append
(
dataline
)
dataline
=
""
for
param
in
item
:
dataline
+=
str
(
param
)
+
","
dataline
+=
"
\n
"
#string will be split by commas, so \n after the comma is no problem
data
[
data
.
index
(
items
)]
=
dataline
#end IK----------------------------------------------------
if
flag
==
1
:
if
name
==
root
:
#line up the root (BODY) with its child (hip - Poser will have only one rootchild)
rootlen
=
max
(
abs
(
float
(
temp
[
5
])
-
float
(
temp
[
3
]))
/
3
,
0.2
)
#0.2 is a value which is scaled for Poser sizes
if
temp
[
7
]
==
root
:
dataline
=
"
%s
,0.0,
%s
,
%s
,
%s
,
%s
,
%s
,
%f
,None,None,0
\n
"
%
(
root
,
temp
[
1
],
temp
[
2
],
temp
[
3
],
temp
[
1
],
temp
[
2
],
-
rootlen
)
data
[
0
]
=
dataline
dataline
=
"
%s
,0.0,
%s
,
%s
,
%s
,
%s
,
%s
,
%s
,
%s
,None,0
\n
"
%
(
temp
[
0
],
temp
[
1
],
temp
[
2
],
temp
[
3
],
temp
[
4
],
temp
[
5
],
temp
[
6
],
temp
[
7
])
data
.
append
(
dataline
)
JPdict
[
name
]
=
rotOrder
#enter rotation orders in our Poser export dict
flag
=
0
name
=
""
rotOrder
=
[]
temptext
.
flush
()
temptext
.
close
()
finTime
=
sys
.
time
()
-
startTime
print
"Done reading armature from
%s
in
%f
seconds"
%
(
sys
.
basename
(
file_name
),
finTime
)
option
=
PupMenu
(
"Save joint rotation orders for Poser pose export? %t|Yes
%x
1|No
%x
2"
)
if
option
==
1
:
Window
.
FileSelector
(
save_JP_order
,
'Browse for save location.'
)
return
data
#passes armature data back to create_armature()
def
load_poser_pose
(
file_name
):
global
PoserConvert
,
PoseMat
,
realTime
,
askKey
,
flipbone
if
file_name
!=
""
:
ext
=
os
.
path
.
splitext
(
file_name
)[
1
]
if
ext
==
".pz2"
or
ext
==
".p2z"
or
ext
==
".hd2"
or
ext
==
".hdz"
:
#support pose and hand files
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
startTime
=
sys
.
time
()
#keep track of speed
hand
=
0
if
ext
==
".hd2"
or
ext
==
".hdz"
:
hand
=
PupMenu
(
"Load for which hand? %t|Right
%x
1|Left
%x
2"
)
tempval
=
PoserConvert
PoserConvert
=
1
pose
=
ob
.
getPose
()
if
ext
[
3
]
==
"2"
:
temptext
=
open
(
file_name
,
"r"
)
if
ext
[
3
]
==
"z"
:
try
:
import
gzip
temptext
=
gzip
.
GzipFile
(
file_name
)
except
:
error
=
Blender
.
Draw
.
PupMenu
(
"Could not read .p2z file. Try decompressing and reading as .pz2"
)
return
lines
=
temptext
.
readlines
()
name
=
""
flag
=
0
multi
=
1
numActors
=
0
if
len
(
lines
)
==
1
:
lines
=
lines
[
0
]
.
replace
(
"
\r
"
,
"
\n
"
)
.
split
(
"
\n
"
)
#Macs save \r and .p2z reading fails to split at \r
for
indx
,
line
in
enumerate
(
lines
):
line
=
line
.
replace
(
"
\n
"
,
""
)
.
replace
(
"
\t
"
,
""
)
.
replace
(
"
\r
"
,
""
)
.
replace
(
" "
,
" "
)
if
line
.
find
(
"clearFigureKeys"
)
!=
-
1
:
multi
=
int
(
line
.
split
(
" "
)[
1
])
#number of frames, if animated
if
line
.
find
(
"actor"
)
!=
-
1
:
name
=
line
.
split
(
":"
)[
0
]
.
replace
(
"actor "
,
""
)
#bone name is Poser internal name minus figure number
xrot
=
[]
yrot
=
[]
zrot
=
[]
xtran
=
[]
ytran
=
[]
ztran
=
[]
if
name
!=
""
:
if
line
.
find
(
"xrot"
)
!=
-
1
:
xrot
,
flag
=
read_keys
(
lines
,
line
,
indx
,
xrot
,
flag
)
if
line
.
find
(
"yrot"
)
!=
-
1
:
yrot
,
flag
=
read_keys
(
lines
,
line
,
indx
,
yrot
,
flag
)
if
line
.
find
(
"zrot"
)
!=
-
1
:
zrot
,
flag
=
read_keys
(
lines
,
line
,
indx
,
zrot
,
flag
)
if
line
.
find
(
"xtran"
)
!=
-
1
:
xtran
,
flag
=
read_keys
(
lines
,
line
,
indx
,
xtran
,
flag
)
if
line
.
find
(
"ytran"
)
!=
-
1
:
ytran
,
flag
=
read_keys
(
lines
,
line
,
indx
,
ytran
,
flag
)
if
line
.
find
(
"ztran"
)
!=
-
1
:
ztran
,
flag
=
read_keys
(
lines
,
line
,
indx
,
ztran
,
flag
)
if
name
!=
""
and
flag
==
6
:
if
name
in
pose
.
bones
.
keys
():
numActors
+=
1
#pose screening (from load_pose())----------------
if
flipDict
==
{}:
flip
()
flipbone
=
""
screening
=
0
noRot
=
0
noTrans
=
0
if
ExcludePart
==
1
:
screening
=
Part_Load
(
pose
.
bones
[
name
],
0
)
if
IncludePart
==
1
:
screening
=
Part_Load
(
pose
.
bones
[
name
],
1
)
if
bonesLoad
==
1
and
name
not
in
boxBones
:
screening
=
1
if
bonesLoad
==
2
and
name
in
boxBones
:
screening
=
1
if
(
ScreenPose
==
1
or
DupPose
==
1
)
and
screening
==
0
:
screening
=
Screen_Pose
(
name
,
pose
)
#if (name == "BODY" or numActors == 1) and bodyscale == 0: screening = 1
if
HipPose
==
1
:
if
name
==
"hip"
or
numActors
==
1
:
if
hipR
==
1
:
noRot
=
1
if
hipT
==
1
:
noTrans
=
1
#if numActors <= 2: print name, numActors, noRot, noTrans, HipPose, bodyscale, screening
if
numActors
>
1
:
noTrans
=
1
#exclude IK goal translation in poses
#end pose screening---------------------
if
screening
==
0
:
size
=
Vector
(
1
,
1
,
1
)
xr
=
0.0
yr
=
0.0
zr
=
0.0
xt
=
0.0
yt
=
0.0
zt
=
0.0
for
i
in
range
(
0
,
multi
):
#loop through frames, sort out the keys
if
noRot
==
0
:
if
len
(
xrot
)
>
i
and
xrot
[
i
][
0
]
==
i
:
xr
=
xrot
[
i
][
1
]
if
len
(
yrot
)
>
i
and
yrot
[
i
][
0
]
==
i
:
yr
=
yrot
[
i
][
1
]
if
len
(
zrot
)
>
i
and
zrot
[
i
][
0
]
==
i
:
zr
=
zrot
[
i
][
1
]
if
noTrans
==
0
:
if
len
(
xtran
)
>
i
and
xtran
[
i
][
0
]
==
i
:
xt
=
xtran
[
i
][
1
]
if
len
(
ytran
)
>
i
and
ytran
[
i
][
0
]
==
i
:
yt
=
ytran
[
i
][
1
]
if
len
(
ztran
)
>
i
and
ztran
[
i
][
0
]
==
i
:
zt
=
ztran
[
i
][
1
]
quat
=
Euler
(
xr
,
yr
,
zr
)
quat
=
quat
.
toQuat
()
quat
=
Poser_Conversion
(
pose
.
bones
[
name
],
quat
,
0
)
#convert Poser eulers to restmatrix type quat
if
hand
!=
0
:
#selected hand for .hd2 hand poses
if
(
hand
==
1
and
(
pref
==
1
and
name
[:
lenR
]
==
left
)
or
(
suff
==
1
and
name
[
-
lenR
:]
==
left
))
or
\
(
hand
==
2
and
(
pref
==
1
and
name
[:
lenR
]
==
right
)
or
(
suff
==
1
and
name
[
-
lenR
:]
==
right
)):
name
=
flipDict
[
name
]
quat
=
Flip_Pose2
(
quat
,
0
,
1
)
if
noTrans
==
0
:
loc
=
Vector
(
xt
,
zt
,
yt
)
#change axis order - only for tran
else
:
loc
=
Vector
(
0
,
0
,
0
)
#combinatory modifiers (from load_pose())---------------------
if
noRot
==
0
:
if
partPose
!=
1.0
:
quat
=
Partial_Pose
(
quat
,
0
,
0
)
loc
=
Partial_Pose
(
0
,
loc
,
1
)
if
MixPose
==
1
:
quat
=
Mix_Pose
(
quat
,
pose
.
bones
[
name
],
0
,
0
)
loc
=
Mix_Pose
(
0
,
pose
.
bones
[
name
],
loc
,
1
)
#end combo modifiers------------------------------------------
if
batchFrames
==
0
:
time
=
i
+
curFrame
# - 1 #load relative to current frame
elif
batchFrames
==
1
:
if
i
<
len
(
boxFrames
):
time
=
int
(
boxFrames
[
i
])
# - 1
if
i
==
0
and
curFrame
!=
time
:
Blender
.
Set
(
'curframe'
,
time
)
#for add_curves() in frame 1
else
:
time
=
int
(
boxFrames
[
len
(
boxFrames
)
-
1
])
+
(
i
-
(
len
(
boxFrames
))
+
1
)
if
i
==
0
:
#multi == 0: #single frame or first keyframe
bone
=
pose
.
bones
[
name
]
bone
.
loc
=
loc
bone
.
quat
=
quat
bone
.
size
=
size
if
multi
!=
1
:
add_curves
(
ob
,
pose
,
name
,
quat
,
loc
,
size
,
time
)
#multiple frames
flag
=
0
name
=
""
if
DupPose
==
1
or
MirrorPose
==
1
or
MirrorBone
==
1
:
#pose symmetry modifiers
tempval2
=
PoseMat
tempval3
=
askKey
askKey
=
2
PoseMat
=
0
PoserConvert
=
0
realTime
=
1
load_pose
(
""
)
PoseMat
=
tempval2
askKey
=
tempval3
if
multi
==
1
and
askKey
!=
2
:
#keyframe single pose
if
askKey
==
0
:
c
=
PupMenu
(
"Insert pose keys for this frame?%t|Yes
%x
1|No
%x
2"
)
if
askKey
==
1
:
c
=
1
if
c
==
1
:
for
bone
in
pose
.
bones
.
values
():
add_curves
(
ob
,
pose
,
bone
.
name
,
bone
.
quat
,
bone
.
loc
,
bone
.
size
,
Blender
.
Get
(
'curframe'
))
PoserConvert
=
tempval
pose
.
update
()
ob
.
makeDisplayList
()
Blender
.
Redraw
()
temptext
.
flush
()
temptext
.
close
()
Blender
.
Set
(
'curframe'
,
curFrame
)
#reset current frame
finTime
=
sys
.
time
()
-
startTime
#xrot = yrot = zrot = xtran = ytran = ztran = xr = yr = zr = xt = yt = zt = 0.0
print
"Done loading
%i
frames for
%i
bones in
%f
seconds"
%
(
multi
,
numActors
,
finTime
)
def
read_keys
(
lines
,
line
,
indx
,
paramlist
,
flag
):
#reads keyframe ('k') lines in a Poser pose
num
=
indx
+
4
while
lines
[
num
]
.
find
(
"}"
)
==
-
1
:
if
lines
[
num
]
.
find
(
"k "
)
!=
-
1
:
read
=
lines
[
num
]
.
replace
(
"
\n
"
,
""
)
.
replace
(
"
\r
"
,
""
)
.
replace
(
"
\t
"
,
""
)
.
replace
(
" "
,
" "
)
.
split
(
" "
)
param
=
(
int
(
read
[
1
]),
float
(
read
[
2
]))
paramlist
.
append
(
param
)
num
+=
1
flag
+=
1
return
(
paramlist
,
flag
)
##---------------Numerical entry-----------------------------------------
#Results of rounding a float are not as controlled as one would like. The decimal module might be a better
#tool for handling controlled rounding, but it is not part of the standard BPy package....
def
entry_values
():
#Sets the dial values for the numerical tab
global
_tran_x
,
_tran_y
,
_tran_z
,
_rot_x
,
_rot_y
,
_rot_z
,
_size_x
,
_size_y
,
_size_z
,
\
_boneroll_num
,
_head_x
,
_head_y
,
_head_z
,
_tail_x
,
tail_y
,
_tail_z
,
lastBone
,
lastLen
,
\
boxBones
if
lastBone
!=
""
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
AData
=
ob
.
getData
()
pose
=
ob
.
getPose
()
bone1
=
AData
.
bones
[
lastBone
]
lastLen
=
bone1
.
length
#Bone length is used to configure loc dial sensitivity
bone
=
pose
.
bones
[
lastBone
]
if
uniqueRot
==
1
:
rot
=
bone
.
quat
.
toEuler
()
.
unique
()
#option to use unique to avoid gimbal lock
elif
uniqueRot
==
0
:
rot
=
bone
.
quat
.
toEuler
()
_tran_x
.
val
=
round
(
bone
.
loc
[
0
],
6
)
#control value inputs with rounding
_tran_y
.
val
=
round
(
bone
.
loc
[
1
],
6
)
_tran_z
.
val
=
round
(
bone
.
loc
[
2
],
6
)
_rot_x
.
val
=
round
(
rot
[
0
],
6
)
_rot_y
.
val
=
round
(
rot
[
1
],
6
)
_rot_z
.
val
=
round
(
rot
[
2
],
6
)
_size_x
.
val
=
round
(
bone
.
size
[
0
],
6
)
_size_y
.
val
=
round
(
bone
.
size
[
1
],
6
)
_size_z
.
val
=
round
(
bone
.
size
[
2
],
6
)
_boneroll_num
.
val
=
round
(
bone1
.
roll
[
'ARMATURESPACE'
],
6
)
_head_x
.
val
=
round
(
bone1
.
head
[
'ARMATURESPACE'
][
0
],
6
)
_head_y
.
val
=
round
(
bone1
.
head
[
'ARMATURESPACE'
][
1
],
6
)
_head_z
.
val
=
round
(
bone1
.
head
[
'ARMATURESPACE'
][
2
],
6
)
_tail_x
.
val
=
round
(
bone1
.
tail
[
'ARMATURESPACE'
][
0
],
6
)
_tail_y
.
val
=
round
(
bone1
.
tail
[
'ARMATURESPACE'
][
1
],
6
)
_tail_z
.
val
=
round
(
bone1
.
tail
[
'ARMATURESPACE'
][
2
],
6
)
if
BonesTabTog
==
1
:
boxBones
=
[]
boxBones
.
append
(
lastBone
)
#Restrict bones list selections to one when in numerical mode
def
numerical_entry
():
global
_tran_x
,
_tran_y
,
_tran_z
,
_rot_x
,
_rot_y
,
_rot_z
,
_size_x
,
_size_y
,
_size_z
#, myKeys, keyType, boxBones
#Applies pose mode dial entries returned by the numerical tab
if
lastBone
!=
""
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
pose
=
ob
.
getPose
()
bone
=
pose
.
bones
[
lastBone
]
if
uniqueRot
==
1
:
rot
=
bone
.
quat
.
toEuler
()
.
unique
()
elif
uniqueRot
==
0
:
rot
=
bone
.
quat
.
toEuler
()
if
round
(
_tran_x
.
val
,
6
)
!=
round
(
bone
.
loc
[
0
],
6
):
#locX
loc
=
round
(
_tran_x
.
val
,
6
),
bone
.
loc
[
1
],
bone
.
loc
[
2
]
bone
.
loc
=
Vector
(
loc
)
elif
round
(
_tran_y
.
val
,
6
)
!=
round
(
bone
.
loc
[
1
],
6
):
#locY
loc
=
bone
.
loc
[
0
],
round
(
_tran_y
.
val
,
6
),
bone
.
loc
[
2
]
bone
.
loc
=
Vector
(
loc
)
elif
round
(
_tran_z
.
val
,
6
)
!=
round
(
bone
.
loc
[
2
],
6
):
#locZ
loc
=
bone
.
loc
[
0
],
bone
.
loc
[
1
],
round
(
_tran_z
.
val
,
6
)
bone
.
loc
=
Vector
(
loc
)
elif
round
(
_rot_x
.
val
,
6
)
!=
round
(
rot
[
0
],
6
):
#rotX
quat
=
round
(
_rot_x
.
val
,
6
),
rot
[
1
],
rot
[
2
]
if
uniqueRot
==
1
:
bone
.
quat
=
Euler
(
quat
)
.
unique
()
.
toQuat
()
if
uniqueRot
==
0
:
bone
.
quat
=
Euler
(
quat
)
.
toQuat
()
elif
round
(
_rot_y
.
val
,
6
)
!=
round
(
rot
[
1
],
6
):
#rotY
quat
=
rot
[
0
],
round
(
_rot_y
.
val
,
6
),
rot
[
2
]
if
uniqueRot
==
1
:
bone
.
quat
=
Euler
(
quat
)
.
unique
()
.
toQuat
()
if
uniqueRot
==
0
:
bone
.
quat
=
Euler
(
quat
)
.
toQuat
()
elif
round
(
_rot_z
.
val
,
6
)
!=
round
(
rot
[
2
],
6
):
#rotZ
quat
=
rot
[
0
],
rot
[
1
],
round
(
_rot_z
.
val
,
6
)
if
uniqueRot
==
1
:
bone
.
quat
=
Euler
(
quat
)
.
unique
()
.
toQuat
()
if
uniqueRot
==
0
:
bone
.
quat
=
Euler
(
quat
)
.
toQuat
()
elif
round
(
_size_x
.
val
,
6
)
!=
round
(
bone
.
size
[
0
],
6
):
#scaleX
size
=
round
(
_size_x
.
val
,
6
),
bone
.
size
[
1
],
bone
.
size
[
2
]
bone
.
size
=
Vector
(
size
)
elif
round
(
_size_y
.
val
,
6
)
!=
round
(
bone
.
size
[
1
],
6
):
#scaleY
size
=
bone
.
size
[
0
],
round
(
_size_y
.
val
,
6
),
bone
.
size
[
2
]
bone
.
size
=
Vector
(
size
)
elif
round
(
_size_z
.
val
,
6
)
!=
round
(
bone
.
size
[
2
],
6
):
#scaleZ
size
=
bone
.
size
[
0
],
bone
.
size
[
1
],
round
(
_size_z
.
val
,
6
)
bone
.
size
=
Vector
(
size
)
if
myKeys
==
1
:
#Add keyframe
bonelist
=
[]
#Note: 2 and 3 will be the same if bones list is open in dual mode.
if
keyType
==
1
:
bonelist
=
pose
.
bones
.
values
()
elif
keyType
==
2
:
bonelist
=
list
(
pose
.
bones
[
bone
]
for
bone
in
boxBones
)
elif
keyType
==
3
:
bonelist
.
append
(
pose
.
bones
[
lastBone
])
for
bone
in
bonelist
:
add_curves
(
ob
,
pose
,
bone
.
name
,
bone
.
quat
,
bone
.
loc
,
bone
.
size
,
Blender
.
Get
(
'curframe'
))
pose
.
update
()
ob
.
makeDisplayList
()
entry_values
()
#refresh the listings
Blender
.
Redraw
()
def
numerical_edit
():
global
_boneroll_num
,
_head_x
,
_head_y
,
_head_z
,
_tail_x
,
tail_y
,
_tail_z
,
lastBone
#Applies edit mode dial entries from numerical tab
if
lastBone
!=
""
:
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
AData
=
ob
.
getData
()
bone1
=
AData
.
bones
[
lastBone
]
roll1
=
bone1
.
roll
[
'ARMATURESPACE'
]
head1
=
bone1
.
head
[
'ARMATURESPACE'
]
tail1
=
bone1
.
tail
[
'ARMATURESPACE'
]
AData2
=
AData
#makeEditable seems to require this odd step sometimes....
AData2
.
makeEditable
()
bone1
=
AData2
.
bones
[
lastBone
]
#makeEditable() has a real #$%@*!! problem....
if
round
(
_boneroll_num
.
val
,
6
)
!=
round
(
roll1
,
6
):
#roll
bone1
.
roll
=
round
(
_boneroll_num
.
val
,
6
)
elif
round
(
_head_x
.
val
,
6
)
!=
round
(
head1
[
0
],
6
):
#head x
head
=
round
(
_head_x
.
val
,
6
),
head1
[
1
],
head1
[
2
]
bone1
.
head
=
Vector
(
head
)
elif
round
(
_head_y
.
val
,
6
)
!=
round
(
head1
[
1
],
6
):
#head y
head
=
head1
[
0
],
round
(
_head_y
.
val
,
6
),
head1
[
2
]
bone1
.
head
=
Vector
(
head
)
elif
round
(
_head_z
.
val
,
6
)
!=
round
(
head1
[
2
],
6
):
#head z
head
=
head1
[
0
],
head1
[
1
],
round
(
_head_z
.
val
,
6
)
bone1
.
head
=
Vector
(
head
)
elif
round
(
_tail_x
.
val
,
6
)
!=
round
(
tail1
[
0
],
6
):
#tail x
tail
=
round
(
_tail_x
.
val
,
6
),
tail1
[
1
],
tail1
[
2
]
bone1
.
tail
=
Vector
(
tail
)
elif
round
(
_tail_y
.
val
,
6
)
!=
round
(
tail1
[
1
],
6
):
#tail y
tail
=
tail1
[
0
],
round
(
_tail_y
.
val
,
6
),
tail1
[
2
]
bone1
.
tail
=
Vector
(
tail
)
elif
round
(
_tail_z
.
val
,
6
)
!=
round
(
tail1
[
2
],
6
):
#tail z
tail
=
tail1
[
0
],
tail1
[
1
],
round
(
_tail_z
.
val
,
6
)
bone1
.
tail
=
Vector
(
tail
)
AData
.
update
()
ob
.
makeDisplayList
()
entry_values
()
#refresh the listings
Blender
.
Redraw
()
def
zero_entries
():
#Zero the buttons
global
_tran_x
,
_tran_y
,
_tran_z
,
_rot_x
,
_rot_y
,
_rot_z
,
_size_x
,
_size_y
,
_size_z
,
\
_boneroll_num
,
_head_x
,
_head_y
,
_head_z
,
_tail_x
,
tail_y
,
_tail_z
_tran_x
.
val
=
0.0000
_tran_y
.
val
=
0.0000
_tran_z
.
val
=
0.0000
_rot_x
.
val
=
0.0000
_rot_y
.
val
=
0.0000
_rot_z
.
val
=
0.0000
_size_x
.
val
=
0.0000
_size_y
.
val
=
0.0000
_size_z
.
val
=
0.0000
_head_x
.
val
=
0.0000
_head_y
.
val
=
0.0000
_head_z
.
val
=
0.0000
_tail_x
.
val
=
0.0000
_tail_y
.
val
=
0.0000
_tail_z
.
val
=
0.0000
_boneroll_num
.
val
=
0.0
##---------------File browsing (Menu and listbox)------------------------------------------------
#----Fills the poseList for menu and listbox browsing, fills loadlist for menu-------
def
list_browser
(
path
):
global
LibPath
,
loadlist
,
poseList
,
poseStart
,
posePages
,
poseLimit
,
foldTog
,
boxList
poseList
=
[]
puplist
=
""
if
LibPath
==
""
:
# or ListTabTog == 1:
poseStart
=
0
posePages
=
0
if
os
.
path
.
exists
(
sys
.
dirname
(
path
)):
path
=
sys
.
dirname
(
path
)
else
:
path
=
sys
.
expandpath
(
'//'
)
LibPath
=
path
for
posefile
in
os
.
listdir
(
LibPath
):
ext
=
os
.
path
.
splitext
(
posefile
)[
1
]
if
ext
==
".blend"
or
ext
==
".bPose"
or
\
ext
==
".pz2"
or
ext
==
".p2z"
or
ext
==
".hd2"
or
ext
==
".hdz"
:
poseList
.
append
(
sys
.
basename
(
posefile
))
if
poseList
==
[]:
if
ListTabTog
==
0
:
nothing
=
PupMenu
(
"No files found %t|Please browse to select a different folder."
)
LibPath
=
""
if
ListTabTog
==
1
:
poseList
.
append
(
"No poses found."
)
poseList
.
append
(
"Select a new folder."
)
if
ListTabTog
==
1
:
boxList
=
poseList
#Fill the listbox to pass to gui
if
poseList
!=
[]:
poseList
.
sort
()
poseTotal
=
len
(
poseList
)
#Total number of poses in folder
poseSplit
=
int
(
math
.
ceil
(
poseTotal
/
poseLimit
))
#Number of split listings
path
=
os
.
path
.
split
(
path
)[
1
]
if
poseTotal
>
poseLimit
:
path
+=
"(
%i
)"
%
(
posePages
+
1
)
puplist
+=
"Poses in:
%s
%%
t|Browse for a new folder
%%
x1|"
%
(
path
)
for
i
in
range
(
poseStart
,
min
(
poseStart
+
poseLimit
,
poseTotal
)):
puplist
+=
"
%s
%%
x
%i
|"
%
(
sys
.
basename
(
poseList
[
i
]),
i
+
2
)
if
i
==
poseStart
+
poseLimit
-
1
or
i
==
poseTotal
-
1
:
if
poseTotal
>
poseLimit
:
if
poseStart
/
poseLimit
<
poseSplit
:
puplist
+=
"Forward (
%i
more poses)
%%
x
%i
"
%
(
poseTotal
-
(
poseStart
+
poseLimit
),
poseTotal
+
10
)
if
poseStart
==
0
:
puplist
+=
"|List part
%i
of
%i
%%
x
%i
"
%
(
posePages
+
1
,
poseSplit
+
1
,
poseTotal
+
11
)
if
poseStart
>
0
:
puplist
+=
"|Back (
%i
previous poses)
%%
x
%i
"
%
(
poseStart
,
poseTotal
+
11
)
if
posePages
==
poseSplit
:
puplist
+=
"List part
%i
of
%i
%%
x
%i
"
%
(
posePages
+
1
,
poseSplit
+
1
,
poseTotal
+
10
)
puplist
+=
"|Back (
%i
previous poses)
%%
x
%i
"
%
(
poseStart
,
poseTotal
+
11
)
loadlist
=
puplist
#-----Menu browser file loading--------------------
def
list_select
(
selected
):
global
poseStart
,
LibPath
,
loadlist
,
posePages
,
poseLimit
,
boxList
poseTotal
=
len
(
poseList
)
poseSplit
=
int
(
math
.
ceil
(
poseTotal
/
poseLimit
))
pageTotal
=
min
((
posePages
+
1
)
*
poseLimit
,
poseTotal
)
if
selected
==
1
:
#One is always 'browse for new folder'
loadlist
=
"Pose list browser %t|Browse for a new folder
%x
1"
LibPath
=
""
Window
.
FileSelector
(
list_browser
,
'Locate pose folder:'
)
if
selected
>
poseTotal
+
5
:
#Set arbitrarily high
if
selected
==
poseTotal
+
10
and
posePages
!=
poseSplit
:
#Total plus 10 is always forward
poseStart
+=
poseLimit
posePages
+=
1
if
selected
==
poseTotal
+
11
and
poseStart
!=
0
:
#Total plus 11 is always back
poseStart
-=
poseLimit
posePages
-=
1
LibPath
=
sys
.
join
(
LibPath
,
sys
.
basename
(
Blender
.
Get
(
'filename'
)))
list_browser
(
LibPath
)
if
selected
>
1
and
selected
<=
pageTotal
+
1
and
selected
<
poseTotal
+
2
:
filepath
=
sys
.
join
(
LibPath
,
poseList
[
selected
-
2
])
#load_pose(filepath)
if
sys
.
exists
(
filepath
)
==
1
:
ext
=
os
.
path
.
splitext
(
filepath
)[
1
]
if
ext
==
".pz2"
or
ext
==
".p2z"
or
ext
==
"hd2"
or
ext
==
".hdz"
:
load_poser_pose
(
filepath
)
else
:
if
openBatch
==
0
:
load_pose
(
filepath
)
#single pose
elif
openBatch
==
1
:
open_batch
(
filepath
)
#Animated batch support
print
"Menu browse file:"
,
filepath
else
:
error
=
PupMenu
(
"Error %t|Selected path is not valid."
)
#print selected
#-----Folder browsing with listbox-------------------------
def
folder_browse
(
path
):
global
LibPath
,
poseList
poseList
=
[]
if
path
==
""
:
path
=
sys
.
expandpath
(
'//'
)
#Start in current .blend folder
if
path
.
endswith
(
sys
.
sep
)
and
path
!=
os
.
path
.
splitdrive
(
path
)[
0
]
+
sys
.
sep
:
path
=
path
[:
-
1
]
#Strip trailing sep symbol
LibPath
=
path
for
folder
in
os
.
listdir
(
LibPath
):
if
sys
.
exists
(
sys
.
join
(
LibPath
,
folder
))
==
2
:
poseList
.
append
(
sys
.
basename
(
folder
))
if
poseList
!=
[]:
poseList
.
sort
()
poseList
.
insert
(
0
,
"Up a level"
)
#print "folder", LibPath, poseList
#---------search for poses in folder (pose tab search button)----------------------
def
pose_search
():
global
boxPoses
,
batchLoad
,
openBatch
,
LibTog
,
saveBatch
,
OptPose
name
=
PupStrInput
(
"Name of pose:"
,
""
,
50
)
#get a name for the new bone
if
name
!=
None
and
name
!=
""
:
if
LibPath
!=
""
and
poseList
!=
[]:
#if a folder is selected
boxPoses
=
[]
if
name
[
-
1
:]
==
"*"
:
prog
=
re
.
compile
(
name
[:
-
1
],
re
.
I
)
#wildcards
else
:
prog
=
re
.
compile
(
name
)
#case sensitive
for
pose
in
poseList
:
result
=
prog
.
search
(
pose
)
if
name
==
pose
or
result
!=
None
:
boxPoses
.
append
(
pose
)
if
len
(
boxPoses
)
>
1
:
batchLoad
=
1
openBatch
=
1
#batch loading toggle
LibTog
=
1
#load options menu toggle
saveBatch
=
1
#batch save toggle
OptPose
=
1
#save options menu toggle
##---------Listbox handling-------------------------------------------------
#-----------------Draws contents of listbox-----------------------
def
listbox
(
box_l
,
box_r
,
box_b
,
box_t
,
text_h
,
line_top
,
line_bot
,
multi
,
text_offset
,
armname
):
global
boxList
,
boxPoses
,
boxBones
,
in_box
,
lastBone
,
boxFrames
,
curFrame
if
ListTabTog
==
1
:
box_select
=
boxPoses
#Multi-tasking with multiple lists
elif
BonesTabTog
==
1
:
box_select
=
boxBones
elif
AnimTabTog
==
1
:
box_select
=
boxFrames
glColor3f
(
0.0
,
0.0
,
0.0
)
#Text color = black
for
line
in
range
(
line_top
,
min
(
line_bot
,
len
(
boxList
))):
text_l
=
(
box_t
-
text_h
-
(
line
*
text_h
))
+
line_top
*
text_h
#Line position
glRasterPos2i
(
box_l
+
8
,
text_l
)
#Draw position
#---Draw listbox contents--------
if
mouse_y
>
text_l
and
mouse_y
<
text_l
+
text_h
and
in_box
==
1
:
#Select current line
if
box_select
.
count
(
boxList
[
line
])
==
0
:
if
multi
==
0
and
len
(
box_select
)
==
0
:
box_select
.
append
(
boxList
[
line
])
elif
multi
==
1
:
box_select
.
append
(
boxList
[
line
])
lastBone
=
boxList
[
line
]
#Assign active user selection (always most recent) in multi-select mode
elif
multi
==
2
:
#multiple select w/out active assignment
box_select
.
append
(
boxList
[
line
])
elif
box_select
.
count
(
boxList
[
line
])
!=
0
:
#Remove w/ click during mutliple use
if
multi
!=
0
:
box_select
.
remove
(
boxList
[
line
])
if
multi
==
1
:
if
len
(
box_select
)
>=
1
:
lastBone
=
box_select
[
len
(
box_select
)
-
1
]
#Assign last item in list as active selection
if
len
(
box_select
)
==
0
:
lastBone
=
""
#Clear active selection if list is empty
if
multi
!=
0
:
in_box
=
0
#This needs to be reset to prevent looping and display errors w/ wheelmouse
elif
mouse_y
>
text_l
and
mouse_y
<
text_l
+
text_h
and
in_box
==
2
:
#right click
if
AnimTabTog
==
1
:
Blender
.
Set
(
"curframe"
,
int
(
boxList
[
line
]))
#Make 3d window current frame equal clicked frame number
curFrame
=
int
(
boxList
[
line
])
if
NumTabTog
==
1
:
entry_values
()
#refresh the numbers tab listings
in_box
=
0
if
box_select
.
count
(
boxList
[
line
])
!=
0
:
#selection boxes
glColor3f
(
1.00
,
1.00
,
0.00
)
#yellow
glRecti
(
box_l
+
1
,
text_l
-
text_h
/
5
,
box_r
-
1
,
text_l
+
4
*
text_h
/
5
)
#draw selection box
if
multi
==
1
:
#Special handling for active selection with multiple (also a draw event in box_click)
if
boxList
[
line
]
==
lastBone
:
glColor3f
(
1.00
,
0.60
,
0.60
)
#red for active selection
glRecti
(
box_l
+
1
,
text_l
-
text_h
/
5
,
box_r
-
1
,
text_l
+
4
*
text_h
/
5
)
#draw selection box
glColor3f
(
0.0
,
0.0
,
0.0
)
#restore text color
lineText
=
boxList
[
line
]
if
BonesTabTog
==
1
and
boneSort
==
1
:
#indentation with tree view
space
=
"."
#character used for display spacing
level
=
listTree
[
line
]
#[1] #number of spaces (depth of bone in hierarchy tree)
#lineText = str(level) + " " + (space*level) + lineText
lineText
=
"
%s%s
"
%
((
space
*
level
),
lineText
)
if
GetStringWidth
(
lineText
)
>
(
box_r
-
box_l
)
-
10
:
#trim lines which are too long
for
i
in
range
(
len
(
lineText
),
0
,
-
1
):
if
GetStringWidth
(
lineText
[:
i
])
<
(
box_r
-
box_l
)
-
10
:
Text
(
lineText
[:
i
])
break
else
:
Text
(
lineText
)
#Draw unaltered line
#----Line numbers and headers------------
if
numList
==
1
:
glRasterPos2i
(
box_l
-
15
,
text_l
)
#Draw line numbers
Text
(
str
(
line
+
1
),
"tiny"
)
#Start from one
glColor3f
(
0.0
,
0.0
,
0.0
)
#Draw headers
glRasterPos2i
(
box_l
,
box_t
+
(
text_offset
/
2
))
if
ListTabTog
==
1
:
if
foldTog
==
0
:
#Pose browse mode
Text
(
"Poses in:
%s
(
%i
)"
%
(
os
.
path
.
split
(
LibPath
)[
1
],
len
(
boxList
)),
"small"
)
if
foldTog
==
1
:
#Folder browse mode
path
=
LibPath
if
path
!=
os
.
path
.
splitdrive
(
path
)[
0
]
+
sys
.
sep
:
path
=
os
.
path
.
split
(
path
)[
1
]
Text
(
"Folders in:
%s
(
%i
)"
%
(
path
,
len
(
boxList
)),
"small"
)
boxPoses
=
box_select
elif
BonesTabTog
==
1
:
if
armname
!=
""
:
#If there's an armature selection
Text
(
"bones in
%s
:
%i
"
%
(
armname
,
len
(
boxList
)),
"small"
)
boxBones
=
box_select
elif
AnimTabTog
==
1
:
boxFrames
=
box_select
#-----------------Mouse click interaction with listbox-------------------
def
box_click
(
double
,
right
):
global
box_l
,
box_r
,
box_t
,
box_b
,
mouse_y
,
in_box
,
boxPoses
,
box_select
in_box
=
0
#Find out if we're in the box-------------------------
for
win
in
range
(
0
,
len
(
Window
.
GetScreenInfo
())):
#Find out if we're inside the box
win1
=
Window
.
GetScreenInfo
()[
win
]
#Blender screen arrangement
if
win1
[
'type'
]
==
14
:
#script window type is 14
l
=
win1
[
'vertices'
][
0
]
+
box_l
r
=
win1
[
'vertices'
][
0
]
+
box_r
t
=
win1
[
'vertices'
][
1
]
+
(
box_b
-
8
)
b
=
win1
[
'vertices'
][
1
]
+
(
box_t
+
3
)
#wx = win1['vertices'][0]
wy
=
win1
[
'vertices'
][
1
]
if
Window
.
GetMouseCoords
()[
0
]
>
l
and
Window
.
GetMouseCoords
()[
0
]
<
r
and
\
Window
.
GetMouseCoords
()[
1
]
>
t
and
Window
.
GetMouseCoords
()[
1
]
<
b
:
mouse_y
=
Window
.
GetMouseCoords
()[
1
]
-
wy
#We only need mouse y value to find the clicked line
if
multi
==
0
:
box_select
=
[]
#Limit list of selected items to 1
if
right
==
0
:
in_box
=
1
#Allows listbox fxn to respond
elif
right
==
1
:
in_box
=
2
#right-click handling
#print "INSIDE BOX!", Window.GetMouseCoords(), Window.GetMouseCoords()[0]-wx, Window.GetMouseCoords()[1]-wy
#Process information returned by the box-------------------------------
if
multi
==
0
:
#single mode
if
double
==
0
:
boxPoses
=
[]
if
double
==
1
:
box_run
()
#Run the activation function if double click
boxPoses
=
box_select
box_select
=
[]
Draw
()
#Display results of interaction with box
if
multi
==
1
:
if
NumTabTog
==
1
:
entry_values
()
#refresh numerical entry values
Draw
()
#Refresh to display active selection line correctly (multiple mode)
#---------Runs the click activation for listbox when multiple selections are disabled--------
def
box_run
():
global
boxPoses
,
LibPath
,
in_box
,
box_select
,
boxList
,
_partial_slider
,
partPose
if
in_box
==
1
and
len
(
boxPoses
)
==
1
:
#-----------Poses
if
foldTog
==
0
:
partPose
=
_partial_slider
.
val
#pass the partial pose value to load_pose
filepath
=
sys
.
join
(
LibPath
,
poseList
[
poseList
.
index
(
boxPoses
[
0
])])
#With single selection, index 0 is always selected
if
sys
.
exists
(
filepath
)
==
1
:
if
os
.
path
.
splitext
(
filepath
)[
1
]
==
".pz2"
or
os
.
path
.
splitext
(
filepath
)[
1
]
==
".p2z"
:
load_poser_pose
(
filepath
)
else
:
if
openBatch
==
0
:
load_pose
(
filepath
)
#single pose
elif
openBatch
==
1
:
open_batch
(
filepath
)
#Animated batch support
print
"listbox file:"
,
filepath
else
:
error
=
PupMenu
(
"Error %t|Selected path is not valid."
)
boxPoses
=
[]
if
NumTabTog
==
1
:
entry_values
()
#refresh numerical entry values
#----------Folders
if
foldTog
==
1
and
boxPoses
[
0
]
in
boxList
:
if
LibPath
.
endswith
(
sys
.
sep
):
LibPath
=
LibPath
[:
-
1
]
if
boxList
.
index
(
boxPoses
[
0
])
==
0
:
#if selection is "Up a level"
LibPath
=
LibPath
.
rsplit
(
sys
.
sep
,
1
)[
0
]
if
LibPath
==
os
.
path
.
splitdrive
(
LibPath
)[
0
]:
LibPath
+=
sys
.
sep
#Special handling for root (Windows-specific?)
if
boxList
.
index
(
boxPoses
[
0
])
>
0
:
LibPath
=
sys
.
join
(
LibPath
,
boxPoses
[
0
])
if
os
.
path
.
isdir
(
LibPath
):
folder_browse
(
LibPath
)
else
:
print
"Clicked selection is not a directory"
,
LibPath
boxList
=
poseList
#fill the display list
in_box
=
0
#re-set to prevent looping
Draw
()
#Folder browser changes list and display needs to be refreshed
#----------------Selection options for the bone listbox----------------
def
bonebox_menu
():
global
boxBones
,
boxList
,
TrimPose
,
lastBone
,
boneSort
menu
=
PupMenu
(
"Bone listbox selection options: %t|Select All
%x
1|Deselect All
%x
2|Invert current selection
%x
6\
|
Select
using
partial
save
group
%
x3
|
Remove
using
partial
save
group
%
x4
\
|
Change
Partial
group
selection
%
x5
|
Add
immediate
children
of
active
selection
%
x7
\
|
Add
all
children
of
active
selection
%
x8
|
Remove
immediate
children
of
active
selection
%
x9
\
|
Remove
all
children
of
active
selection
%
x10
|
Toggle
sorting
:
alphabtically
/
hierarchically
%
x11
\
|
Cancel
%
x11
")
if
menu
==
1
:
#Add all
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
pose
=
ob
.
getPose
()
for
bone
in
pose
.
bones
.
keys
():
boxBones
.
append
(
bone
)
if
boneSort
==
0
:
boxBones
.
sort
()
elif
boneSort
==
1
:
boxBones
=
sort_hierarchy
(
boxBones
)
boxBones
.
reverse
()
#To make new active selection the first sorted entry in new list
if
len
(
boxBones
)
>
0
:
lastBone
=
boxBones
[
len
(
boxBones
)
-
1
]
#Active is last item in list
elif
menu
==
2
:
#Remove all
boxBones
=
[]
lastBone
=
""
#Clear the active user selection
elif
menu
==
3
or
menu
==
4
:
#Add or remove using partial save group
if
partVar
==
""
and
sideVar
==
""
:
partSave
()
#Show the save groups selection pupmenu
if
partVar
!=
""
:
#Proceed if there is a selected group
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
pose
=
ob
.
getPose
()
for
bone
in
pose
.
bones
.
values
():
screening
=
Part_Load
(
bone
,
0
)
if
menu
==
3
:
#add
if
screening
==
1
:
boxBones
.
append
(
bone
.
name
)
elif
menu
==
4
:
#remove
if
screening
==
1
:
if
bone
.
name
in
boxBones
:
boxBones
.
remove
(
bone
.
name
)
if
bone
.
name
==
lastBone
and
lastBone
in
boxBones
:
boxBones
.
remove
(
lastBone
)
#This needs to be specified or lastBone is retained
lastBone
=
""
#Clear the active user selection if it is removed
if
lastBone
==
""
and
len
(
boxBones
)
>
0
:
if
boneSort
==
0
:
boxBones
.
sort
()
elif
boneSort
==
1
:
boxBones
=
sort_hierarchy
(
boxBones
)
boxBones
.
reverse
()
lastBone
=
boxBones
[
len
(
boxBones
)
-
1
]
if
menu
==
3
:
#sort the added listings
if
boneSort
==
0
:
boxBones
.
sort
()
elif
boneSort
==
1
:
boxBones
=
sort_hierarchy
(
boxBones
)
boxBones
.
reverse
()
if
lastBone
in
boxBones
:
boxBones
.
remove
(
lastBone
)
boxBones
.
append
(
lastBone
)
#Place active selection at end of list
else
:
if
len
(
boxBones
)
>
0
:
lastBone
=
boxBones
[
len
(
boxBones
)
-
1
]
#Active is last item in list
elif
menu
==
5
:
#Change partial save group selections
partSave
()
if
partVar
!=
""
:
TrimPose
=
1
#Set partial group save toggle
elif
menu
==
6
:
#Invert selection
boxList
=
boxBones
boxBones
=
[]
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
and
ob
.
getType
()
==
"Armature"
:
pose
=
ob
.
getPose
()
for
bone
in
pose
.
bones
.
keys
():
if
bone
not
in
boxList
:
boxBones
.
append
(
bone
)
if
boneSort
==
0
:
boxBones
.
sort
()
elif
boneSort
==
1
:
boxBones
=
sort_hierarchy
(
boxBones
)
#print boxBones
boxBones
.
reverse
()
#To make new active selection the first sorted entry in new list
if
len
(
boxBones
)
>
0
:
lastBone
=
boxBones
[
len
(
boxBones
)
-
1
]
#Active is last item in list
elif
menu
>
6
and
menu
<
11
:
#work with children
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
and
len
(
boxBones
)
>
0
:
#There must be a list selection
AData
=
ob
.
getData
()
bone1
=
AData
.
bones
[
lastBone
]
#Last bone selected
if
bone1
.
hasChildren
():
if
menu
%
2
!=
0
:
offspring
=
bone1
.
children
#7, 9 = odd
elif
menu
%
2
==
0
:
offspring
=
bone1
.
getAllChildren
()
#8, 10 = even
if
menu
<
9
:
#7 & 8 are additive
for
child
in
offspring
:
boxBones
.
append
(
child
.
name
)
if
boneSort
==
0
:
boxBones
.
sort
()
elif
boneSort
==
1
:
boxBones
=
sort_hierarchy
(
boxBones
)
boxBones
.
reverse
()
if
lastBone
in
boxBones
:
boxBones
.
remove
(
bone1
.
name
)
#update to keep last user selection last in list
boxBones
.
append
(
bone1
.
name
)
elif
menu
>
8
:
#9, 10 are subtractive
for
child
in
offspring
:
if
child
.
name
in
boxBones
:
boxBones
.
remove
(
child
.
name
)
if
child
.
name
==
lastBone
:
lastBone
=
""
#Clear the active user selection if it is removed
if
boneSort
==
0
:
boxBones
.
sort
()
elif
boneSort
==
1
:
boxBones
=
sort_hierarchy
(
boxBones
)
boxBones
.
reverse
()
elif
menu
==
11
:
boneSort
=
1
-
boneSort
if
boneSort
==
0
:
boxList
.
sort
()
#boxList needs to be sorted after sort/reverse for lastBone display (above).
elif
boneSort
==
1
:
boxList
=
sort_hierarchy
(
boxList
)
#boxList = boxBones
##---------------------GUI adapted from Blender Cal3D script----------------------
#----------------------Some additions adapted from discombobulator.py------------------
#pose application----------------------------------------------------
realTime
=
0
#Toggle variable for applying pose changes to current without loading a file
#load pose type conversion------------------------------------------
PoserConvert
=
0
#Poser conversion toggle
PoseMat
=
0
#Toggle for import conversion of a pose saved using the PoseMatrix option for IK
#save pose type conversion-------------------------------------------
NoRollTog
=
0
#Toggle button variable for restmatrix pose save
IKTog
=
0
#Toggle button variable for posematrix save
PoserSave
=
0
#Toggle button variable for Poser pose export
#pose modifiers------------------------------------------------------
MirrorPose
=
0
#Toggle for option to flip sides of a pose R/L
ScreenPose
=
0
#Screen pose toggle
screenR
=
1
#Load only side R with screening
screenL
=
0
#Load only side L with screening
DupPose
=
0
#Symmetrical pose toggle variable
dupR
=
1
#Symmetrical pose R to L
dupL
=
0
#Symmetrical pose L to R
torsoZero
=
0
#Option to zero centered parts with symmetrize button. 0 = zero them, 1 = don't.
partPose
=
1.0
#Partial load pose slider value
MixPose
=
0
#Combine new pose with current toggle variable
MirrorBone
=
0
#Toggle for option to flip a bone's own values
#root handling-------------------------------------------------------
bodyscale
=
0
#BODY screening toggle
HipPose
=
0
#hip screening toggle
hipR
=
0
#Screen hip rotation
hipT
=
0
#Screen hip translation
addscale
=
0
#Additive rotation loading for BODY - will probably remove this.
#partial pose loading------------------------------------------------
IncludePart
=
0
#Toggle var to load only partial save group(s) in pose
ExcludePart
=
0
#Toggle var to exclude partial save groups when loading a pose
#animation-----------------------------------------------------------
openBatch
=
0
#For batch file import to animate from a series of static poses
saveBatch
=
0
#For batch file save for animation support
askKey
=
0
#Variable for keyframe options. 0 = ask, 1 = yes, 2 = no
batchLoad
=
0
#Batch toggle for poses listbox. Allows multiple selections for loading of non-sequential frames
batchFrames
=
0
#Batch toggle for frames listbox. Screen load/save using selected frame numbers
animlen
=
Blender
.
Get
(
'endframe'
)
-
(
Blender
.
Get
(
'staframe'
)
-
1
)
#length of the current animation
curFrame
=
Blender
.
Get
(
"curframe"
)
#Blender.Get calls seem to cause memory jumps, so minimize the calls w/ a global
#save pose types------------------------------------------------------
EmpPose
=
0
#Save pose from empties toggle
IKPose
=
0
#Toggle to save a poseMatrix pose, including IK/constraints.
NoRollPose
=
0
#Toggle to save a "PoserConvert" compatible pose, which excludes embedded bone roll data
#symmetry notation-----------------------------------------------------
suff
=
0
#Symmetry notation using prefix
pref
=
1
#Symmetry notation using suffix
right
=
"r"
#"R" = right(-x) prefix/suffix
left
=
"l"
#"L" = left(+x) prefix/suffix
flipbone
=
""
#The bone which flips
lenR
=
len
(
right
)
#length of right prefix/suffix
lenL
=
len
(
left
)
#length of left prefix/suffix
right_alt
=
"capeR"
#Specify for non-standard part handling
left_alt
=
"capeL"
#alt types currently only work with prefixes
flipDict
=
{}
#Dict to store symmetrical bone pairs
#save modifiers----------------------------------------------------------
No_Trans
=
0
#Toggle variable to exclude translation w/ pose save
No_Scale
=
0
#Toggle variable to exclude scaling with pose save
#save and load option menus-----------------------------------------------
LibTog
=
0
#Variable for pose load options toggle
OptPose
=
0
#Toggle for export options on or off (toggle display)
#partial group handling---------------------------------------------------
TrimPose
=
0
#Partial pose menu toggle for save
GroupTog
=
0
#Partial pose menu toggle for load
partVar
=
""
#Stores partial group selection
sideVar
=
""
#Stores selected side with symmetrized groups
root
=
None
#root part
rootchild
=
None
#Single child of root if root has only one child (for special handling as w/ cr2 BODY and hip).
groupsDict
=
{}
#Store the groups
maxVal
=
2
#Value by which total number of bones will be divided when determining group selection maximum size
minVal
=
3
#Minimum number of children and subchildren a bone can have for group selection minimum size
totalBones
=
1
#Total count of bones in armature (minus the root itself)
#Bone roll----------------------------------------------------------------
oldRolls
=
{}
#Dictionary to cache old values for in-session restoration
#menu and listbox file browser handling-------------------------------------
LibVar
=
0
#Toggle var to select or deselect Pupmenu file loading. 1 is menu browsing, 0 is file selector browsing.
LibPath
=
""
#Path to pose folder
loadlist
=
"Pose list browser %t|Browse for a new folder
%x
1"
#Variable to store menu for list browsing
LibSave
=
0
#Option to save to selected list loading folder
poseList
=
[]
#List of poses in target folder
poseStart
=
0
#Starting number for each displayed sub-list
posePages
=
0
#Number of sub-lists into which list of poses is split
poseLimit
=
54
#Max number of poses per displayed list (user-configurable in load menu)
#page tabs-----------------------------------------------------------------
LoadTabTog
=
1
#Load tab
SaveTabTog
=
0
#Save tab
MiscTabTog
=
0
#Miscellaneous options tab
ListTabTog
=
0
#Listbox tab
BonesTabTog
=
0
#Bone list tab
NumTabTog
=
0
#Numerical entry tab
AnimTabTog
=
0
#Animation frames listbox tab
dualList
=
0
#Dual display toggle for page tabs
#listbox------------------------------------------------------------------
line_top
=
0
#listbox top line
line_bot
=
0
# listbox bottom line
box_h
=
0
#Listbox height (calculated later; global to pass limits to mouse wheel event)
box_select
=
[]
#Active list of selected listbox items
boxList
=
[]
#Active listbox multitasking list. Stores poseList, bones list, or folders list
boxPoses
=
[]
#Stored listbox pose selections to pass on or restore
boxBones
=
[]
#Stored listbox bone selections to pass on or restore
boxFrames
=
[]
#Stored listbox frames selection for animation i/o and keyframe use
mouse_y
=
0
#pass the mouse y coords between click event and listbox gui
in_box
=
0
#Screening for inside/outside of box. 0 = out, 1 = in/left click, 2 = in/right click
multi
=
0
#multiple selection support flag; 0 = single select, 1 = multiple w/ active, 2 = multiple w/out active
numList
=
1
#Toggle for listbox line numbers
wheelslider
=
1
#Toggle listbox scrolling between slider and wheelmouse modes. Slider = 0, wheelmouse = 1
listScroll
=
1
-
wheelslider
#Start value for pose/file list slider
listScrollB
=
1
-
wheelslider
#Start value for bones list slider
listScrollA
=
1
-
wheelslider
#Start value for animation list slider
foldTog
=
0
#Folder browser toggle in pose listbox mode
#Bone listbox selection handling------------------------------------------
bonesLoad
=
0
#Toggle option for load/apply screening: 1 = include, 2 = exclude
bonesSave
=
0
#Toggle option for save screening: 1 = include, 2 = exclude
lastBone
=
""
#Last user-selected bone name (the active bones list selection)
boneSort
=
1
#Type of sorting for bones list. 0 = alphabetical, 1 = hierarchical
listTree
=
[]
#List for treeview
#Numerical entry--------------------------------------------------------
myKeys
=
0
#Keyframe toggle button variable for number tab.
keyType
=
0
#Keyframe handling for myKeys toggle. 0 = no keyframes, 1 = keyframe all bones, 2 = keyframe bones list active
lastLen
=
0
#Length of lastBone (to configure translation sensitivity)
uniqueRot
=
0
#Toggle to use euler.unique() with rot dials (may return very unusual results....)
#General preferences----------------------------------------------------
setprefs
=
0
#flag to set preferences at next exit
#gui buttons-------------------------------------------------------------
_partial_slider
=
Create
(
1.0
)
#Slider handling from der_ton's .md5 exporter.
_load_menu
=
Create
(
1
)
#So we can pass the load menu .val parameter
_scroll_slider
=
Create
(
0.0
)
#Listbox slider
_dual_width
=
Create
(
240
)
#dual width number button - to alter button_width and display width
_tran_x
=
Create
(
0.0000
)
#These are numerical entry tab dials
_tran_y
=
Create
(
0.0000
)
_tran_z
=
Create
(
0.0000
)
_rot_x
=
Create
(
0.0000
)
_rot_y
=
Create
(
0.0000
)
_rot_z
=
Create
(
0.0000
)
_size_x
=
Create
(
0.0000
)
_size_y
=
Create
(
0.0000
)
_size_z
=
Create
(
0.0000
)
_head_x
=
Create
(
0.0000
)
_head_y
=
Create
(
0.0000
)
_head_z
=
Create
(
0.0000
)
_tail_x
=
Create
(
0.0000
)
_tail_y
=
Create
(
0.0000
)
_tail_z
=
Create
(
0.0000
)
_boneroll_num
=
Create
(
0.0
)
#These are all buttons which don't use .val as their linked values
_quit_button
=
Create
(
0
)
_loadtab_toggle
=
Create
(
0
)
_savetab_toggle
=
Create
(
0
)
_misctab_toggle
=
Create
(
0
)
_numtab_toggle
=
Create
(
0
)
_listtab_toggle
=
Create
(
0
)
_bonetab_toggle
=
Create
(
0
)
_animtab_toggle
=
Create
(
0
)
_savelist_button
=
Create
(
0
)
_folder_toggle
=
Create
(
0
)
_folder_button
=
Create
(
0
)
_menu_button
=
Create
(
0
)
_load_button
=
Create
(
0
)
_load_menu
=
Create
(
0
)
_apply_button
=
Create
(
0
)
_zero_button
=
Create
(
0
)
_lib_toggle
=
Create
(
0
)
_group_toggle
=
Create
(
0
)
_poserL_toggle
=
Create
(
0
)
_posematL_toggle
=
Create
(
0
)
_flip_toggle
=
Create
(
0
)
_flipbone_toggle
=
Create
(
0
)
_screen_toggle
=
Create
(
0
)
_screen_R
=
Create
(
0
)
_screen_L
=
Create
(
0
)
_dup_toggle
=
Create
(
0
)
_dup_R
=
Create
(
0
)
_dup_L
=
Create
(
0
)
_mix_toggle
=
Create
(
0
)
_save_button
=
Create
(
0
)
_part_toggle
=
Create
(
0
)
_noTrans_toggle
=
Create
(
0
)
_noScale_toggle
=
Create
(
0
)
_opt_toggle
=
Create
(
0
)
_poserS_toggle
=
Create
(
0
)
_posematS_toggle
=
Create
(
0
)
_suffBone_button
=
Create
(
0
)
_prefix_toggle
=
Create
(
0
)
_suffix_toggle
=
Create
(
0
)
_wheel_toggle
=
Create
(
0
)
_number_toggle
=
Create
(
0
)
_dual_toggle
=
Create
(
0
)
_menuA_button
=
Create
(
0
)
_batchload_toggle
=
Create
(
0
)
_batchload_button
=
Create
(
0
)
_batchframes_toggle
=
Create
(
0
)
_IK_button
=
Create
(
0
)
_tools_button
=
Create
(
0
)
_reg_button
=
Create
(
0
)
_poserSave_toggle
=
Create
(
0
)
_boneSearch_button
=
Create
(
0
)
_boneGrab_button
=
Create
(
0
)
_poseSearch_button
=
Create
(
0
)
#Button event constants---------------------------
EVENT_NOEVENT
=
0
EVENT_QUIT
=
1
EVENT_SAVE
=
2
EVENT_LOAD
=
3
EVENT_CONVERT
=
4
EVENT_FLIP
=
5
EVENT_SCREEN
=
6
EVENT_DUP
=
7
EVENT_SCR_R
=
8
EVENT_SCR_L
=
9
EVENT_DUP_R
=
10
EVENT_DUP_L
=
11
EVENT_PART
=
12
EVENT_MIX
=
13
EVENT_EMP
=
14
EVENT_ZERO
=
15
EVENT_SUFFPREF
=
16
EVENT_PREF
=
17
EVENT_SUFF
=
18
EVENT_APPLY
=
19
EVENT_NOTRANS
=
20
EVENT_NOSCALE
=
21
EVENT_POSEMAT
=
22
EVENT_BONE
=
23
EVENT_LIB
=
24
EVENT_TAB_L
=
25
EVENT_TAB_S
=
26
EVENT_TAB_M
=
27
EVENT_TAB_T
=
28
EVENT_TAB_B
=
29
EVENT_LISTSCROLL
=
30
EVENT_WHEEL
=
31
EVENT_NUMB
=
32
EVENT_FOLDER
=
33
EVENT_BONEMENU
=
34
EVENT_GROUP
=
35
EVENT_NOROLL
=
36
EVENT_IK
=
37
EVENT_DUAL
=
38
EVENT_TAB_N
=
39
EVENT_ENTRY
=
40
EVENT_KEYF
=
41
EVENT_EDIT
=
42
EVENT_UNIQUE
=
43
EVENT_LISTLOAD
=
44
EVENT_FLIPBONE
=
45
EVENT_TAB_A
=
46
EVENT_ANIMMENU
=
47
EVENT_BATCHTOG
=
48
EVENT_BATCHLOAD
=
49
EVENT_BATCHFRAMES
=
50
EVENT_IKTOG
=
51
EVENT_TOOLS
=
52
EVENT_REG
=
53
EVENT_POSERSAVE
=
54
EVENT_BONESEARCH
=
55
EVENT_BONEGRAB
=
56
EVENT_POSESEARCH
=
57
def
colorbox
(
x
,
y
,
xright
,
bottom
):
#from discombobulator.py
glColor3f
(
0.75
,
0.75
,
0.75
)
glRecti
(
x
+
1
,
y
+
1
,
xright
-
1
,
bottom
-
1
)
def
gui
():
global
_partial_slider
,
_load_menu
,
_scroll_slider
,
_dual_width
,
_tran_x
,
_tran_y
,
\
_tran_z
,
_rot_x
,
_rot_y
,
_rot_z
,
_size_x
,
_size_y
,
_size_z
,
_head_x
,
_head_y
,
\
_head_z
,
_tail_x
,
_tail_y
,
_tail_z
,
_boneroll_num
,
_quit_button
,
_loadtab_toggle
,
\
_savetab_toggle
,
_misctab_toggle
,
_numtab_toggle
,
_listtab_toggle
,
_bonetab_toggle
,
\
_savelist_button
,
_folder_toggle
,
_folder_button
,
_menu_button
,
_load_button
,
\
_load_menu
,
_apply_button
,
_zero_button
,
_lib_toggle
,
_group_toggle
,
_poserL_toggle
,
\
_posematL_toggle
,
_flip_toggle
,
_flipbone_toggle
,
_screen_toggle
,
_screen_R
,
_screen_L
,
\
_dup_toggle
,
_dup_R
,
_dup_L
,
_mix_toggle
,
_save_button
,
_part_toggle
,
_noTrans_toggle
,
\
_noScale_toggle
,
_opt_toggle
,
_poserS_toggle
,
_posematS_toggle
,
_suffBone_button
,
\
_prefix_toggle
,
_suffix_toggle
,
_wheel_toggle
,
_number_toggle
,
_dual_toggle
,
\
_animtab_toggle
,
_menuA_button
,
_batchload_toggle
,
_batchload_button
,
_batchframes_toggle
,
\
_IK_button
,
_tools_button
,
_reg_button
,
_poserSave_toggle
,
_boneSearch_button
,
_boneGrab_button
,
\
_poseSearch_button
global
line_top
,
line_bot
,
box_l
,
box_r
,
box_t
,
box_b
,
box_h
,
mouse_y
,
multi
,
\
box_select
,
boxList
,
listScroll
,
numList
,
text_h
,
boxPoses
,
boxBones
,
wheelslider
,
\
listScrollB
,
foldTog
,
lastBone
,
button_width
,
myKeys
,
lastLen
,
uniqueRot
,
\
boxFrames
,
listScrollA
,
animlen
,
boneSort
,
curFrame
button_left
=
20
#button_width = 240 #(default)
button_width
=
_dual_width
.
val
button_height
=
15
text_offset
=
5
button_space
=
button_height
+
button_height
/
4
#Various functions-------------------------------------------------------
colorbox
(
button_left
-
8
,
button_height
/
4
,
button_width
+
28
,
2
*
button_space
+
text_offset
)
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
+
(
button_width
/
2
-
GetStringWidth
(
"Blender Pose Handler V.1"
,
"small"
)
/
2
),
button_space
/
2
-
text_offset
/
2
)
Text
(
"Blender Pose Handler V.1"
,
"small"
)
_quit_button
=
Button
(
"Quit"
,
EVENT_QUIT
,
button_left
,
button_space
,
button_width
,
button_height
,
"Exit from script"
)
#Tab toggles------------------------------------------------------------
colorbox
(
button_left
-
8
,
23
*
button_space
-
text_offset
,
button_width
+
28
,
25
*
button_space
+
text_offset
)
_loadtab_toggle
=
Toggle
(
"Apply"
,
EVENT_TAB_L
,
button_left
,
24
*
button_space
,
button_width
/
4
,
button_height
,
LoadTabTog
,
"Select to view pose options for loading or real-time application."
)
_savetab_toggle
=
Toggle
(
"Save"
,
EVENT_TAB_S
,
button_left
+
button_width
/
4
,
24
*
button_space
,
button_width
/
4
,
button_height
,
SaveTabTog
,
"Select to view pose options for saving."
)
_misctab_toggle
=
Toggle
(
"Options"
,
EVENT_TAB_M
,
button_left
+
(
2
*
button_width
/
4
),
24
*
button_space
,
button_width
/
4
,
button_height
,
MiscTabTog
,
"Select to view options for bone roll, symmetry notation handling, and IK."
)
_numtab_toggle
=
Toggle
(
"Number"
,
EVENT_TAB_N
,
button_left
+
(
3
*
button_width
/
4
),
24
*
button_space
,
button_width
/
4
,
button_height
,
NumTabTog
,
"Numerical entry posing for bones list selection."
)
_listtab_toggle
=
Toggle
(
"Poses"
,
EVENT_TAB_T
,
button_left
,
23
*
button_space
,
button_width
/
3
,
button_height
,
ListTabTog
,
"Use listbox file browser."
)
_bonetab_toggle
=
Toggle
(
"Bones"
,
EVENT_TAB_B
,
button_left
+
(
button_width
/
3
),
23
*
button_space
,
button_width
/
3
,
button_height
,
BonesTabTog
,
"Work with list of bones in the selected armature."
)
_animtab_toggle
=
Toggle
(
"Frames"
,
EVENT_TAB_A
,
button_left
+
(
2
*
button_width
/
3
),
23
*
button_space
,
button_width
/
3
,
button_height
,
AnimTabTog
,
"Work with list of frames in current animation."
)
#----Listboxes----------------------------------------------------------
if
ListTabTog
==
1
or
BonesTabTog
==
1
or
AnimTabTog
==
1
:
#These are the GUI draw elements of the empty listbox. Listbox contents are in the listbox() fxn.
#Mouse interaction is in box_click().
#Change these to alter drawn position of listbox, slider, and listbox contents
num_offset
=
0
if
numList
==
1
:
num_offset
=
15
#GUI re-spacing w/ line numbers on/off
dual_offset
=
0
if
dualList
==
1
:
dual_offset
=
button_left
+
button_width
+
8
#Dual tab display spacing
text_h
=
12
#text height (10 plus spacing)
box_l
=
button_left
+
num_offset
+
dual_offset
#box left
box_r
=
4
*
(
button_width
/
5
)
+
num_offset
+
dual_offset
#box right
box_b
=
5
*
button_height
#box bottom
box_t
=
26
*
button_height
#box top
box_h
=
((
box_t
+
3
)
-
(
box_b
-
8
))
/
text_h
#box height
multi
=
0
#multiple selection toggle
armname
=
""
#Name of selected armature
colorbox
(
box_l
-
num_offset
-
8
,
3
*
button_space
-
10
,
dual_offset
+
button_width
+
28
,
box_t
+
button_height
)
#background
but_w
=
button_width
/
4
#re-spacing w/ list number toggle
but_l
=
(
3
*
but_w
)
+
dual_offset
if
numList
==
1
:
but_w
=
button_width
/
5
but_l
=
(
4
*
but_w
)
+
dual_offset
if
ListTabTog
==
1
:
#-----file---------------------------------------------
multi
=
0
if
batchLoad
==
1
:
multi
=
2
#multiple selection for animation import
armname
=
""
#For the pose listbox, the boxList is filled in:
#--EVENT_FOLDER for _folder_toggle (on and off)
#--list_browser() for _folder_button (and for list refresh with _save_button)
#--box_run() for folder click.
#--get_from_ini() for startup if ListTabTog == 1 and preferred settings are used
_savelist_button
=
Button
(
"Save"
,
EVENT_SAVE
,
button_left
+
but_l
,
8
*
button_height
,
but_w
,
button_height
,
"Save pose or batch of poses to current folder"
)
_folder_toggle
=
Toggle
(
"Folder"
,
EVENT_FOLDER
,
button_left
+
but_l
,
10
*
button_height
,
but_w
,
button_height
,
foldTog
,
"Use listbox to locate a new folder."
)
_folder_button
=
Button
(
"Browse"
,
EVENT_LISTLOAD
,
button_left
+
but_l
,
12
*
button_height
,
but_w
,
button_height
,
"Locate a new folder using the file browser"
)
_batchload_toggle
=
Toggle
(
"Batch"
,
EVENT_BATCHTOG
,
button_left
+
but_l
,
18
*
button_height
,
but_w
,
button_height
,
batchLoad
,
"Toggle multiple file selections, batch load, and batch save for animation."
)
_poseSearch_button
=
Button
(
"Search"
,
EVENT_POSESEARCH
,
button_left
+
but_l
,
14
*
button_height
,
but_w
,
button_height
,
"Search by name for pose files in current folder."
)
if
batchLoad
==
1
:
_batchload_button
=
Button
(
"load"
,
EVENT_BATCHLOAD
,
button_left
+
but_l
,
16
*
button_height
,
but_w
,
button_height
,
"Load multiple selections as animated batch."
)
else
:
_batchload_button
=
Create
(
0
)
if
wheelslider
==
0
:
_scroll_slider
=
Slider
(
"list top: "
,
EVENT_LISTSCROLL
,
box_l
,
(
3
*
button_space
)
-
8
,
box_r
-
box_l
,
button_height
,
listScroll
,
1
,
max
((
len
(
boxList
)
-
box_h
)
+
1
,
0
),
0
,
"Scroll the listbox with the slider bar."
)
elif
BonesTabTog
==
1
:
#---bones-------------------------------------------------
multi
=
1
#For the bones listbox, this is the only time the boxlist is filled
if
armname
==
""
:
#Get armature data only if boxList is empty
if
Object
.
GetSelected
()
!=
[]:
ob
=
Object
.
GetSelected
()[
0
]
if
ob
.
getType
()
==
"Armature"
:
armname
=
ob
.
name
pose
=
ob
.
getPose
()
if
len
(
boxList
)
!=
len
(
pose
.
bones
.
keys
())
or
(
len
(
boxList
)
==
0
and
armname
!=
""
):
#refill the list
boxList
=
pose
.
bones
.
keys
()
if
boneSort
==
0
:
boxList
.
sort
()
elif
boneSort
==
1
:
boxList
=
sort_hierarchy
(
boxList
)
else
:
boxList
=
[]
armname
=
""
if
NumTabTog
==
0
:
_menu_button
=
Button
(
"Select"
,
EVENT_BONEMENU
,
button_left
+
but_l
,
8
*
button_height
,
but_w
,
button_height
,
"Selection options for bones listbox"
)
_IK_button
=
Button
(
"IK"
,
EVENT_IKTOG
,
button_left
+
but_l
,
10
*
button_height
,
but_w
,
button_height
,
"IK handling options for bones listbox"
)
_tools_button
=
Button
(
"Tools"
,
EVENT_TOOLS
,
button_left
+
but_l
,
12
*
button_height
,
but_w
,
button_height
,
"Edit mode tools to aid IK construction - warning: these will alter your armature."
)
_boneSearch_button
=
Button
(
"Search"
,
EVENT_BONESEARCH
,
button_left
+
but_l
,
14
*
button_height
,
but_w
,
button_height
,
"Search by name for bones in bones list and 3d view."
)
_boneGrab_button
=
Button
(
"Grab"
,
EVENT_BONEGRAB
,
button_left
+
but_l
,
16
*
button_height
,
but_w
,
button_height
,
"Grab selected bones list bones in the 3D view."
)
if
wheelslider
==
0
:
_scroll_slider
=
Slider
(
"list top: "
,
EVENT_LISTSCROLL
,
box_l
,
(
3
*
button_space
)
-
8
,
box_r
-
box_l
,
button_height
,
listScrollB
,
1
,
max
((
len
(
boxList
)
-
box_h
)
+
1
,
0
),
0
,
"Scroll the listbox with the slider bar."
)
elif
AnimTabTog
==
1
:
#----frames--------------------------------------------------------
multi
=
2
armname
=
""
frame
=
curFrame
#Blender.Get("curframe")
if
frame
>
animlen
:
animlen
+=
frame
-
animlen
#extend the displayed list if user goes beyond the limit
#This is the only time boxList is filled for the frames list
if
len
(
boxList
)
!=
animlen
:
#Fill the frames list
boxList
=
[]
for
f
in
range
(
Blender
.
Get
(
'staframe'
),
animlen
+
1
):
boxList
.
append
(
str
(
f
))
_menuA_button
=
Button
(
"Select"
,
EVENT_ANIMMENU
,
button_left
+
but_l
,
8
*
button_height
,
but_w
,
button_height
,
"Selection options for frames listbox"
)
_batchframes_toggle
=
Toggle
(
"Batch"
,
EVENT_BATCHFRAMES
,
button_left
+
but_l
,
18
*
button_height
,
but_w
,
button_height
,
batchFrames
,
"Screen batch load/save using selected frames."
)
if
wheelslider
==
0
:
_scroll_slider
=
Slider
(
"list top: "
,
EVENT_LISTSCROLL
,
box_l
,
(
3
*
button_space
)
-
8
,
box_r
-
box_l
,
button_height
,
listScrollA
,
1
,
max
((
len
(
boxList
)
-
box_h
)
+
1
,
0
),
0
,
"Scroll the listbox with the slider bar."
)
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
box_l
-
10
,
box_t
+
(
text_offset
/
2
))
Text
(
"Frame count:
%i
Current frame:
%i
"
%
(
animlen
,
frame
),
"small"
)
#---------wheelmouse vs. slider---------------------------------------------------------
if
wheelslider
==
1
:
#Label if slider is not in use
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
box_l
,
3
*
button_space
-
text_offset
)
Text
(
"Use mouse wheel to scroll list"
)
elif
wheelslider
==
0
:
if
ListTabTog
==
1
:
line_top
=
int
(
listScroll
)
-
1
#Set top line for box display (slider value minus one to convert to list indices)
if
BonesTabTog
==
1
:
line_top
=
int
(
listScrollB
)
-
1
if
AnimTabTog
==
1
:
line_top
=
int
(
listScrollA
)
-
1
#--------default drawn elements---------------------------------------------
glColor3f
(
1.0
,
1.0
,
1.0
)
#listbox color = white
box
=
glRecti
(
box_l
,
box_b
-
text_h
,
box_r
,
box_t
)
#Draw the textbox
line_bot
=
min
(
line_top
+
box_h
,
len
(
boxList
))
#Define the bottom
if
ListTabTog
==
1
and
LibPath
==
""
:
boxList
=
[]
#If folder browse w/ file browser was cancelled.
if
boxList
!=
[]:
listbox
(
box_l
,
box_r
,
box_b
,
box_t
,
text_h
,
line_top
,
line_bot
,
multi
,
text_offset
,
armname
)
elif
boxList
==
[]:
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
box_l
,
box_t
+
(
text_offset
/
2
))
if
ListTabTog
==
1
:
Text
(
"No folder selected."
)
#Default header for pose list tab
if
BonesTabTog
==
1
:
if
armname
==
""
:
Text
(
"No armature selected."
)
#Default header for bones list tab
#Frames list will always be filled... unless a zero length animation is possible?
#------Pages-------------------------------------------------------
if
LoadTabTog
==
1
:
#Load tab
#Load functions------------------------------------------------------
colorbox
(
button_left
-
8
,
19
*
button_space
-
8
,
button_width
+
28
,
22
*
button_space
)
#options
colorbox
(
button_left
-
8
,
12
*
button_space
-
8
,
button_width
+
28
,
18
*
button_space
)
#modifier
colorbox
(
button_left
-
8
,
8
*
button_space
-
8
,
button_width
+
28
,
11
*
button_space
)
#conversion
colorbox
(
button_left
-
8
,
3
*
button_space
-
8
,
button_width
+
28
,
7
*
button_space
)
#loading
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
,
21
*
button_space
+
text_offset
)
Text
(
"Pose application options:"
)
glRasterPos2i
(
button_left
,
17
*
button_space
+
text_offset
)
Text
(
"Pose modifier settings:"
)
glRasterPos2i
(
button_left
,
6
*
button_space
+
text_offset
)
Text
(
"Loading and application:"
)
glRasterPos2i
(
button_left
,
10
*
button_space
+
text_offset
)
Text
(
"Pose type conversion:"
)
glRasterPos2i
(
button_left
,
16
*
button_space
+
text_offset
)
Text
(
"pose load settings:"
)
if
LibVar
==
0
:
_load_button
=
Button
(
"Load pose from file"
,
EVENT_LOAD
,
button_left
,
3
*
button_space
,
button_width
,
button_height
,
"Browse for Pose to Load"
)
elif
LibVar
==
1
:
#use if "if" rather than "elif" causes a python24dll error crash bug in 242 (w/ dual ListTabTog)
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
,
4
*
button_space
+
3
)
Text
(
"Menu browser:"
)
_load_menu
=
Menu
(
loadlist
,
EVENT_LOAD
,
button_left
+
(
button_width
/
3
),
3
*
button_space
,
2
*
button_width
/
3
,
button_height
,
_load_menu
.
val
,
"Browse for Pose to Load"
)
_apply_button
=
Button
(
"Apply modifiers to current pose"
,
EVENT_APPLY
,
button_left
,
4
*
button_space
,
button_width
,
button_height
,
"Apply pose modifier or type conversion settings to current pose."
)
_zero_button
=
Button
(
"Zero current pose"
,
EVENT_ZERO
,
button_left
,
5
*
button_space
,
button_width
,
button_height
,
"Restore all rotation, scaling, and translation settings to rest pose values"
)
_lib_toggle
=
Toggle
(
"General loading options"
,
EVENT_LIB
,
button_left
,
20
*
button_space
,
button_width
,
button_height
,
LibTog
,
"Set options for loading a pose."
)
_group_toggle
=
Toggle
(
"Partial group loading options"
,
EVENT_GROUP
,
button_left
,
19
*
button_space
,
button_width
,
button_height
,
GroupTog
,
"Set screening options to exclude some bones when loading a pose."
)
#Pose types
_poserL_toggle
=
Toggle
(
"Restmatrix pose ('No Roll')"
,
EVENT_CONVERT
,
button_left
,
9
*
button_space
,
button_width
,
button_height
,
PoserConvert
,
"Convert a restmatrix/no roll pose or a combo type pose."
)
_posematL_toggle
=
Toggle
(
"Posematrix pose ('IK')"
,
EVENT_POSEMAT
,
button_left
,
8
*
button_space
,
button_width
,
button_height
,
PoseMat
,
"Convert a pose saved with IK/constraints (poseMatrix) option."
)
#Symmetry handling
_flip_toggle
=
Toggle
(
"Flip Pose"
,
EVENT_FLIP
,
button_left
,
12
*
button_space
,
button_width
/
2
,
button_height
,
MirrorPose
,
"Mirror the pose (reverse left and right)."
)
_flipbone_toggle
=
Toggle
(
"Flip Bones"
,
EVENT_FLIPBONE
,
button_left
+
(
button_width
/
2
),
12
*
button_space
,
button_width
/
2
,
button_height
,
MirrorBone
,
"Flip each bone over itself."
)
_screen_toggle
=
Toggle
(
"Screen Right/Left"
,
EVENT_SCREEN
,
button_left
,
13
*
button_space
,
(
button_width
/
10
)
*
8
,
button_height
,
ScreenPose
,
"Apply only one side of pose."
)
_screen_R
=
Toggle
(
"R"
,
EVENT_SCR_R
,
button_left
+
(
button_width
/
10
)
*
8
,
13
*
button_space
,
button_width
/
10
,
button_height
,
screenR
,
"Use only right side of pose."
)
_screen_L
=
Toggle
(
"L"
,
EVENT_SCR_L
,
button_left
+
(
button_width
/
10
)
*
9
,
13
*
button_space
,
button_width
/
10
,
button_height
,
screenL
,
"Use only left side of pose."
)
_dup_toggle
=
Toggle
(
"Symmetry Right/Left"
,
EVENT_DUP
,
button_left
,
14
*
button_space
,
(
button_width
/
10
)
*
8
,
button_height
,
DupPose
,
"Load one side of pose and mirror it to second side."
)
_dup_R
=
Toggle
(
"R"
,
EVENT_DUP_R
,
button_left
+
(
button_width
/
10
)
*
8
,
14
*
button_space
,
button_width
/
10
,
button_height
,
dupR
,
"Copy right side to left side."
)
_dup_L
=
Toggle
(
"L"
,
EVENT_DUP_L
,
button_left
+
(
button_width
/
10
)
*
9
,
14
*
button_space
,
button_width
/
10
,
button_height
,
dupL
,
"Copy left side to right side."
)
#Combinatory options
if
dualList
==
0
:
sliderlabel
=
"Pose intensity:"
elif
dualList
==
1
:
sliderlabel
=
"Intensity:"
_partial_slider
=
Slider
(
sliderlabel
,
EVENT_NOEVENT
,
button_left
,
15
*
button_space
,
button_width
,
button_height
,
_partial_slider
.
val
,
0.01
,
2.0
,
0
,
"Adjust the amount of effect for the selected pose."
)
_mix_toggle
=
Toggle
(
"Combine with current pose"
,
EVENT_MIX
,
button_left
,
16
*
button_space
,
button_width
,
button_height
,
MixPose
,
"Add loaded pose data to current pose (mix)."
)
if
SaveTabTog
==
1
:
#Save tab
#Save functions-------------------------------------------------------
colorbox
(
button_left
-
8
,
19
*
button_space
-
8
,
button_width
+
28
,
22
*
button_space
)
#options
colorbox
(
button_left
-
8
,
16
*
button_space
-
8
,
button_width
+
28
,
18
*
button_space
)
#modifier
colorbox
(
button_left
-
8
,
11
*
button_space
-
8
,
button_width
+
28
,
15
*
button_space
)
#conversion
colorbox
(
button_left
-
8
,
8
*
button_space
-
8
,
button_width
+
28
,
10
*
button_space
)
#save
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
,
21
*
button_space
+
text_offset
)
Text
(
"Pose save options:"
)
glRasterPos2i
(
button_left
,
17
*
button_space
+
text_offset
)
Text
(
"Save modifier settings:"
)
glRasterPos2i
(
button_left
,
14
*
button_space
+
text_offset
)
Text
(
"Save type conversion:"
)
glRasterPos2i
(
button_left
,
9
*
button_space
+
text_offset
)
Text
(
"Save:"
)
_save_button
=
Button
(
"Save Pose"
,
EVENT_SAVE
,
button_left
,
8
*
button_space
,
button_width
,
button_height
,
"Browse for Pose Save Location"
)
_part_toggle
=
Toggle
(
"Partial group save options"
,
EVENT_PART
,
button_left
,
19
*
button_space
,
button_width
,
button_height
,
TrimPose
,
"Set screening options to exclude some bones from saved pose."
)
_noTrans_toggle
=
Toggle
(
"No translation"
,
EVENT_NOTRANS
,
button_left
,
16
*
button_space
,
button_width
/
2
,
button_height
,
No_Trans
,
"Select to exclude translation data from saved pose."
)
_noScale_toggle
=
Toggle
(
"No scaling"
,
EVENT_NOSCALE
,
button_left
+
(
button_width
/
2
),
16
*
button_space
,
button_width
/
2
,
button_height
,
No_Scale
,
"Select to exclude scaling data from saved pose."
)
_opt_toggle
=
Toggle
(
"General save options"
,
EVENT_EMP
,
button_left
,
20
*
button_space
,
button_width
,
button_height
,
OptPose
,
"Set options for saving poses."
)
#Save types
_poserS_toggle
=
Toggle
(
"Restmatrix pose ('No Roll')"
,
EVENT_NOROLL
,
button_left
,
13
*
button_space
,
button_width
,
button_height
,
NoRollTog
,
"Save a pose without 'embedded' bone roll."
)
_posematS_toggle
=
Toggle
(
"Posematrix pose ('IK')"
,
EVENT_IK
,
button_left
,
12
*
button_space
,
button_width
,
button_height
,
IKTog
,
"Save IK and constraints data in the pose."
)
_poserSave_toggle
=
Toggle
(
"Export Poser pose (.pz2)"
,
EVENT_POSERSAVE
,
button_left
,
11
*
button_space
,
button_width
,
button_height
,
PoserSave
,
"Save a Poser pose, instead of a Blender pose."
)
if
MiscTabTog
==
1
:
#Options tab
#Symmetry notation functions------------------------------------------
colorbox
(
button_left
-
8
,
19
*
button_space
-
8
,
button_width
+
28
,
22
*
button_space
)
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
,
21
*
button_space
+
text_offset
)
Text
(
"Symmetry Notation Handling:"
)
_suffBone_button
=
Button
(
"Enter symmetry prefix or suffix"
,
EVENT_SUFFPREF
,
button_left
,
19
*
button_space
,
(
button_width
),
button_height
,
"Press to enter right/left prefix or suffix"
)
_prefix_toggle
=
Toggle
(
"Use prefix"
,
EVENT_PREF
,
button_left
,
20
*
button_space
,
button_width
/
2
,
button_height
,
pref
,
"select if right/left handling uses a prefix"
)
_suffix_toggle
=
Toggle
(
"Use suffix"
,
EVENT_SUFF
,
button_left
+
(
button_width
/
2
),
20
*
button_space
,
button_width
/
2
,
button_height
,
suff
,
"select if right/left handling uses a suffix"
)
#Listbox settings options-----------------------------------------
colorbox
(
button_left
-
8
,
15
*
button_space
-
8
,
button_width
+
28
,
18
*
button_space
)
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
,
17
*
button_space
+
text_offset
)
Text
(
"Listbox display options:"
)
_wheel_toggle
=
Toggle
(
"Wheel mouse"
,
EVENT_WHEEL
,
button_left
,
16
*
button_space
,
button_width
/
2
,
button_height
,
wheelslider
,
"Select to use wheel mouse to scroll listboxes"
)
_number_toggle
=
Toggle
(
"Line numbers"
,
EVENT_NUMB
,
button_left
+
(
button_width
/
2
),
16
*
button_space
,
button_width
/
2
,
button_height
,
numList
,
"Select to use line numbers with listboxes"
)
_dual_toggle
=
Toggle
(
"Dual display"
,
EVENT_DUAL
,
button_left
,
15
*
button_space
,
button_width
/
2
,
button_height
,
dualList
,
"Select to use two tab pages side-by-side"
)
_dual_width
=
Number
(
"Width"
,
EVENT_NOEVENT
,
button_left
+
(
button_width
/
2
),
15
*
button_space
,
button_width
/
2
,
button_height
,
_dual_width
.
val
,
100
,
240
,
"Change width of displayed page (default value is 240)."
)
#Armature backup functions--------------------------------------------------
colorbox
(
button_left
-
8
,
12
*
button_space
-
8
,
button_width
+
28
,
14
*
button_space
)
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
,
13
*
button_space
+
text_offset
)
Text
(
"Armature options:"
)
_bone_button
=
Button
(
"Armature text backup options"
,
EVENT_BONE
,
button_left
,
12
*
button_space
,
button_width
,
button_height
,
"Save or load armature settings from a textfile backup."
)
#Numerical entry options----------------------------------------------
colorbox
(
button_left
-
8
,
9
*
button_space
-
8
,
button_width
+
28
,
11
*
button_space
)
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
,
10
*
button_space
+
text_offset
)
Text
(
"Numerical entry options:"
)
_unique_toggle
=
Toggle
(
"Use Euler Unique"
,
EVENT_UNIQUE
,
button_left
,
9
*
button_space
,
button_width
,
button_height
,
uniqueRot
,
"Select to use euler.unique() to avoid gimbal lock with rotation dials."
)
#Registry backup options-----------------------------------------------
colorbox
(
button_left
-
8
,
6
*
button_space
-
8
,
button_width
+
28
,
8
*
button_space
)
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
,
7
*
button_space
+
text_offset
)
Text
(
"General settings options:"
)
_reg_button
=
Button
(
"Gui preference options"
,
EVENT_REG
,
button_left
,
6
*
button_space
,
button_width
,
button_height
,
"Set or deactivate general preferences."
)
if
NumTabTog
==
1
:
#Numerical entry tab
#Pose mode entry----------------------------------------------------
#Number buttons handle differently in 241 and 242. This is optimized for 242 handling
maxval
=
1000.0000
minval
=
-
1000.0000
colorbox
(
button_left
-
8
,
3
*
button_space
-
8
,
button_width
+
28
,
22
*
button_space
+
text_offset
)
glColor3f
(
0.67
,
0.67
,
0.67
)
glRecti
(
button_left
-
8
,
21
*
button_space
,
button_width
+
28
,
23
*
button_space
-
text_offset
)
glRecti
(
button_left
-
8
,
15
*
button_space
,
button_width
+
28
,
18
*
button_space
)
glRecti
(
button_left
-
8
,
10
*
button_space
-
(
button_height
/
4
),
button_width
+
28
,
12
*
button_space
-
(
button_height
/
4
))
glRecti
(
button_left
-
8
,
4
*
button_space
-
(
button_height
/
4
),
button_width
+
28
,
7
*
button_space
-
(
button_height
/
4
))
glColor3f
(
0.0
,
0.0
,
0.0
)
glRasterPos2i
(
button_left
,
22
*
button_space
+
text_offset
)
if
lastBone
==
""
:
Text
(
"No active bones list selection"
,
"small"
)
if
lastBone
!=
""
:
Text
(
"Active bones list bone:
%s
"
%
(
lastBone
),
"small"
)
glRasterPos2i
(
button_left
,
21
*
button_space
+
text_offset
)
Text
(
"Pose mode:"
)
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
20
*
button_space
+
text_offset
)
Text
(
"locX:
%f
"
%
(
_tran_x
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
19
*
button_space
+
text_offset
)
Text
(
"LocY:
%f
"
%
(
_tran_y
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
18
*
button_space
+
text_offset
)
Text
(
"LocZ:
%f
"
%
(
_tran_z
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
17
*
button_space
+
text_offset
)
Text
(
"RotX:
%f
"
%
(
_rot_x
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
16
*
button_space
+
text_offset
)
Text
(
"RotY:
%f
"
%
(
_rot_y
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
15
*
button_space
+
text_offset
)
Text
(
"RotZ:
%f
"
%
(
_rot_z
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
14
*
button_space
+
text_offset
)
Text
(
"ScaleX:
%f
"
%
(
_size_x
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
13
*
button_space
+
text_offset
)
Text
(
"ScaleY:
%f
"
%
(
_size_y
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
12
*
button_space
+
text_offset
)
Text
(
"ScaleZ:
%f
"
%
(
_size_z
.
val
))
_tran_x
=
Number
(
""
,
EVENT_ENTRY
,
button_left
,
20
*
button_space
,
button_width
/
3
,
button_height
,
_tran_x
.
val
,
minval
*
(
lastLen
/
2
),
maxval
*
(
lastLen
/
2
),
"Set x translation of active bone list selection"
)
_tran_y
=
Number
(
""
,
EVENT_ENTRY
,
button_left
,
19
*
button_space
,
button_width
/
3
,
button_height
,
_tran_y
.
val
,
minval
*
(
lastLen
/
2
),
maxval
*
(
lastLen
/
2
),
"Set y translation of active bone list selection"
)
_tran_z
=
Number
(
""
,
EVENT_ENTRY
,
button_left
,
18
*
button_space
,
button_width
/
3
,
button_height
,
_tran_z
.
val
,
minval
*
(
lastLen
/
2
),
maxval
*
(
lastLen
/
2
),
"Set z translation of active bone list selection"
)
_rot_x
=
Number
(
""
,
EVENT_ENTRY
,
button_left
,
17
*
button_space
,
button_width
/
3
,
button_height
,
_rot_x
.
val
,
minval
*
10
,
maxval
*
10
,
"Set x rotation of active bone list selection"
)
_rot_y
=
Number
(
""
,
EVENT_ENTRY
,
button_left
,
16
*
button_space
,
button_width
/
3
,
button_height
,
_rot_y
.
val
,
minval
*
10
,
maxval
*
10
,
"Set y rotation of active bone list selection"
)
_rot_z
=
Number
(
""
,
EVENT_ENTRY
,
button_left
,
15
*
button_space
,
button_width
/
3
,
button_height
,
_rot_z
.
val
,
minval
*
10
,
maxval
*
10
,
"Set z rotation of active bone list selection"
)
_size_x
=
Number
(
""
,
EVENT_ENTRY
,
button_left
,
14
*
button_space
,
button_width
/
3
,
button_height
,
_size_x
.
val
,
minval
,
maxval
,
"Set x scaling for active bone list selection"
)
_size_y
=
Number
(
""
,
EVENT_ENTRY
,
button_left
,
13
*
button_space
,
button_width
/
3
,
button_height
,
_size_y
.
val
,
minval
,
maxval
,
"Set y scaling for active bone list selection"
)
_size_z
=
Number
(
""
,
EVENT_ENTRY
,
button_left
,
12
*
button_space
,
button_width
/
3
,
button_height
,
_size_z
.
val
,
minval
,
maxval
,
"Set z scaling for active bone list selection"
)
_keyframe_toggle
=
Toggle
(
"Add keyframes"
,
EVENT_KEYF
,
button_left
+
(
button_width
/
2
),
21
*
button_space
+
text_offset
,
button_width
/
2
,
button_height
,
myKeys
,
"Toggle on to add keyframing for each entry"
)
#Edit mode entry-----------------------------------------
glRasterPos2i
(
button_left
,
3
*
button_space
)
Text
(
"Caution: these will alter your armature."
,
"small"
)
glRasterPos2i
(
button_left
,
11
*
button_space
+
text_offset
)
Text
(
"Edit mode:"
)
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
11
*
button_space
+
text_offset
)
Text
(
"Length:
%f
"
%
(
lastLen
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
10
*
button_space
+
text_offset
)
Text
(
"Roll:
%f
"
%
(
_boneroll_num
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
9
*
button_space
+
text_offset
)
Text
(
"RootX:
%f
"
%
(
_head_x
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
8
*
button_space
+
text_offset
)
Text
(
"RootY:
%f
"
%
(
_head_y
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
7
*
button_space
+
text_offset
)
Text
(
"RootZ:
%f
"
%
(
_head_z
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
6
*
button_space
+
text_offset
)
Text
(
"TipX:
%f
"
%
(
_tail_x
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
5
*
button_space
+
text_offset
)
Text
(
"TipY:
%f
"
%
(
_tail_y
.
val
))
glRasterPos2i
(
button_left
+
(
button_width
/
3
)
+
8
,
4
*
button_space
+
text_offset
)
Text
(
"TipZ:
%f
"
%
(
_tail_z
.
val
))
_boneroll_num
=
Number
(
""
,
EVENT_EDIT
,
button_left
,
10
*
button_space
,
button_width
/
3
,
button_height
,
_boneroll_num
.
val
,
-
360
,
360
,
"Set bone roll for active bone list selection"
)
_head_x
=
Number
(
""
,
EVENT_EDIT
,
button_left
,
9
*
button_space
,
button_width
/
3
,
button_height
,
_head_x
.
val
,
minval
*
(
lastLen
/
2
),
maxval
*
(
lastLen
/
2
),
"Set head x translation for active bone list selection"
)
_head_y
=
Number
(
""
,
EVENT_EDIT
,
button_left
,
8
*
button_space
,
button_width
/
3
,
button_height
,
_head_y
.
val
,
minval
*
(
lastLen
/
2
),
maxval
*
(
lastLen
/
2
),
"Set head y translation for active bone list selection"
)
_head_z
=
Number
(
""
,
EVENT_EDIT
,
button_left
,
7
*
button_space
,
button_width
/
3
,
button_height
,
_head_z
.
val
,
minval
*
(
lastLen
/
2
),
maxval
*
(
lastLen
/
2
),
"Set head z translation for active bone list selection"
)
_tail_x
=
Number
(
""
,
EVENT_EDIT
,
button_left
,
6
*
button_space
,
button_width
/
3
,
button_height
,
_tail_x
.
val
,
minval
*
(
lastLen
/
2
),
maxval
*
(
lastLen
/
2
),
"Set tail x translation for active bone list selection"
)
_tail_y
=
Number
(
""
,
EVENT_EDIT
,
button_left
,
5
*
button_space
,
button_width
/
3
,
button_height
,
_tail_y
.
val
,
minval
*
(
lastLen
/
2
),
maxval
*
(
lastLen
/
2
),
"Set tail y translation for active bone list selection"
)
_tail_z
=
Number
(
""
,
EVENT_EDIT
,
button_left
,
4
*
button_space
,
button_width
/
3
,
button_height
,
_tail_z
.
val
,
minval
*
(
lastLen
/
2
),
maxval
*
(
lastLen
/
2
),
"Set tail z translation for active bone list selection"
)
#if NumTabTog == 0: zero_entries() #Clear the numerical tab buttons if the tab is not in use.
clicktime
=
sys
.
time
()
def
event
(
evt
,
val
):
global
line_top
,
box_h
,
clicktime
,
box_select
,
boxPoses
,
curFrame
if
AnimTabTog
==
1
:
curFrame
=
Blender
.
Get
(
'curframe'
)
if
not
val
:
if
AnimTabTog
==
1
:
curFrame
=
Blender
.
Get
(
'curframe'
)
if
(
evt
==
ESCKEY
):
if
setprefs
==
1
:
update_ini
()
Exit
()
return
elif
evt
==
LEFTMOUSE
:
#For the listbox
if
ListTabTog
==
1
or
BonesTabTog
==
1
or
AnimTabTog
==
1
:
double
=
0
if
round
(
sys
.
time
()
-
clicktime
,
1
)
<
0.5
:
double
=
1
#Alter to change double-click sensitivity
clicktime
=
sys
.
time
()
box_click
(
double
,
0
)
elif
evt
==
RIGHTMOUSE
:
#Right-click changes current frame in animation tab
if
AnimTabTog
==
1
:
box_click
(
0
,
1
)
elif
(
evt
==
WHEELDOWNMOUSE
or
evt
==
DOWNARROWKEY
)
and
len
(
boxList
)
>
box_h
:
#Avoid list index errors
if
(
ListTabTog
==
1
or
BonesTabTog
==
1
or
AnimTabTog
==
1
)
and
wheelslider
==
1
:
if
line_top
<
(
len
(
boxList
)
-
box_h
):
line_top
+=
3
if
line_top
>
(
len
(
boxList
)
-
box_h
):
line_top
=
len
(
boxList
)
-
box_h
Draw
()
elif
(
evt
==
WHEELUPMOUSE
or
evt
==
UPARROWKEY
)
and
len
(
boxList
)
>
box_h
:
if
(
ListTabTog
==
1
or
BonesTabTog
==
1
or
AnimTabTog
==
1
)
and
wheelslider
==
1
:
if
line_top
>
0
:
line_top
-=
3
if
line_top
<
0
:
line_top
=
0
Draw
()
def
bevent
(
evt
):
global
_partial_slider
,
_load_menu
,
_scroll_slider
,
\
bodyscale
,
PoserConvert
,
MirrorPose
,
ScreenPose
,
screenR
,
screenL
,
DupPose
,
dupR
,
dupL
,
\
HipPose
,
hipR
,
hipT
,
addscale
,
partPose
,
MixPose
,
EmpPose
,
suff
,
pref
,
TrimPose
,
\
openBatch
,
saveBatch
,
realTime
,
No_Trans
,
No_Scale
,
IKPose
,
NoRollPose
,
OptPose
,
PoseMat
,
\
LibVar
,
LibPath
,
LibSave
,
LibTog
,
IncludePart
,
ExcludePart
,
askKey
,
LoadTabTog
,
\
SaveTabTog
,
MiscTabTog
,
ListTabTog
,
BonesTabTog
,
line_top
,
multi
,
boxList
,
listScroll
,
numList
,
\
boxPoses
,
wheelslider
,
listScrollB
,
foldTog
,
in_box
,
GroupTog
,
NoRollTog
,
IKTog
,
lastBone
,
\
dualList
,
NumTabTog
,
myKeys
,
uniqueRot
,
MirrorBone
,
loadlist
,
AnimTabTog
,
boxFrames
,
listScrollA
,
\
batchLoad
,
batchFrames
,
keyType
,
setprefs
,
PoserSave
,
curFrame
if
AnimTabTog
==
1
:
curFrame
=
Blender
.
Get
(
'curframe'
)
if
evt
==
EVENT_LOAD
:
#load button and load pulldown menu
partPose
=
_partial_slider
.
val
if
LibVar
==
0
:
if
openBatch
==
0
:
Window
.
FileSelector
(
load_pose
,
'Pose to open?'
)
#File browse loading
elif
openBatch
==
1
:
Window
.
FileSelector
(
open_batch
,
'Pose to open?'
)
#Animated batch support
elif
LibVar
==
1
:
#Menu browse loading
if
LibPath
==
""
:
Window
.
FileSelector
(
list_browser
,
'Select pose folder:'
)
elif
LibPath
!=
""
:
list_select
(
_load_menu
.
val
)
elif
evt
==
EVENT_LISTLOAD
:
#Listbox folder loading
partPose
=
_partial_slider
.
val
if
ListTabTog
==
1
:
#Listbox use
foldTog
=
0
line_top
=
0
#Re-set top line of listbox to keep things in-bounds
listScroll
=
1
-
wheelslider
Window
.
FileSelector
(
list_browser
,
'Select pose folder:'
)
elif
evt
==
EVENT_SAVE
:
#Save button for both save tab and listbox tab
if
ListTabTog
==
1
:
temp
=
LibSave
LibSave
=
1
#Listbox use
if
LibSave
==
0
:
if
saveBatch
==
0
:
Window
.
FileSelector
(
goSave
,
'File to save as?'
)
#File browse saving
elif
saveBatch
==
1
:
Window
.
FileSelector
(
save_batch
,
'File to save as?'
)
#Animated batch support
if
LibSave
==
1
:
#Menu and listbox browse saving
savename
=
Create
(
"Pose"
)
saveblock
=
[(
"Enter save name:"
,
savename
,
0
,
30
,
"Enter name as which to save pose file."
)]
saveVal
=
PupBlock
(
"Save to list browse folder"
,
saveblock
)
if
saveVal
==
1
and
LibPath
!=
""
:
savename
=
sys
.
join
(
LibPath
,
savename
.
val
)
if
saveBatch
==
0
:
goSave
(
savename
)
elif
saveBatch
==
1
:
save_batch
(
savename
)
LibPath
=
sys
.
join
(
LibPath
,
sys
.
basename
(
Blender
.
Get
(
'filename'
)))
#pass a dummy filename to list_browser
list_browser
(
LibPath
)
#Refesh the menu to display new addition
if
ListTabTog
==
1
:
LibSave
=
temp
elif
evt
==
EVENT_QUIT
:
#"Quit" button
if
setprefs
==
1
:
update_ini
()
Exit
()
return
elif
evt
==
EVENT_CONVERT
:
#load tab restmatrix conversion toggle
PoserConvert
=
1
-
PoserConvert
if
PoserConvert
==
1
:
PoseMat
=
0
elif
evt
==
EVENT_FLIP
:
#load tab "Flip Pose" toggle
MirrorPose
=
1
-
MirrorPose
if
MirrorPose
==
1
:
MirrorBone
=
0
elif
evt
==
EVENT_SCREEN
:
#load tab screen pose toggle
ScreenPose
=
1
-
ScreenPose
if
DupPose
==
1
:
DupPose
=
0
elif
evt
==
EVENT_DUP
:
#load tab symmetrize pose toggle
DupPose
=
1
-
DupPose
if
ScreenPose
==
1
:
ScreenPose
=
0
elif
evt
==
EVENT_SCR_R
:
#load tab screen right toggle
screenL
=
screenR
screenR
=
1
-
screenR
dupR
=
screenR
dupL
=
screenL
elif
evt
==
EVENT_SCR_L
:
#load tab screen left toggle
screenR
=
screenL
screenL
=
1
-
screenL
dupR
=
screenR
dupL
=
screenL
elif
evt
==
EVENT_DUP_R
:
#load tab symmetrize right toggle
dupL
=
dupR
dupR
=
1
-
dupR
screenR
=
dupR
screenL
=
dupL
elif
evt
==
EVENT_DUP_L
:
#load tab symmetrize left toggle
dupR
=
dupL
dupL
=
1
-
dupL
screenR
=
dupR
screenL
=
dupL
elif
evt
==
EVENT_MIX
:
#load tab additive modifier toggle
MixPose
=
1
-
MixPose
elif
evt
==
EVENT_EMP
:
#Toggle adjusted to allow multiple menu selections
if
OptPose
==
0
:
#save tab general options toggle
OptPose
=
1
-
OptPose
if
OptPose
==
1
:
export_options
()
elif
evt
==
EVENT_POSEMAT
:
#load tab posematrix conversion toggle
PoseMat
=
1
-
PoseMat
if
PoseMat
==
1
:
PoserConvert
=
0
elif
evt
==
EVENT_ZERO
:
#load tab zero pose button
Zero_Pose
()
elif
evt
==
EVENT_SUFFPREF
:
#options tab symmetry button
Symmetry_Notation
()
elif
evt
==
EVENT_PREF
:
#options tab symmetry prefix toggle
pref
=
1
-
pref
suff
=
1
-
suff
elif
evt
==
EVENT_SUFF
:
#options tab symmetry suffix toggle
suff
=
1
-
suff
pref
=
1
-
pref
elif
evt
==
EVENT_PART
:
#Toggle adjusted to allow multiple menu selections
if
TrimPose
==
0
:
#save tab partial groups toggle
TrimPose
=
1
-
TrimPose
if
TrimPose
==
1
:
partSave
()
if
TrimPose
==
0
:
partVar
=
0
sideVar
=
0
elif
evt
==
EVENT_APPLY
:
#load tab realtime application button
realTime
=
1
-
realTime
partPose
=
_partial_slider
.
val
load_pose
(
''
)
elif
evt
==
EVENT_NOTRANS
:
#save tab no translation modifier toggle
No_Trans
=
1
-
No_Trans
elif
evt
==
EVENT_NOSCALE
:
#save tab no scaling modifier toggle
No_Scale
=
1
-
No_Scale
elif
evt
==
EVENT_BONE
:
#options tab boneroll button
Bone_Menu
()
elif
evt
==
EVENT_LIB
:
#Toggle adjusted to allow multiple menu selections
if
LibTog
==
0
:
#Load tab general options toggle
LibTog
=
1
-
LibTog
if
LibTog
==
1
:
Load_Menu
()
elif
evt
==
EVENT_TAB_L
:
#Load tab
if
NumTabTog
==
1
:
zero_entries
()
#Clear the numerical tab buttons if the tab is not in use.
LoadTabTog
=
1
SaveTabTog
=
0
MiscTabTog
=
0
NumTabTog
=
0
if
dualList
==
0
:
if
wheelslider
==
1
:
if
ListTabTog
==
1
:
listScroll
=
line_top
#store the current listbox top line
elif
BonesTabTog
==
1
:
listScrollB
=
line_top
elif
AnimTabTog
==
1
:
listScrollA
=
line_top
ListTabTog
=
0
BonesTabTog
=
0
AnimTabTog
=
0
boxList
=
[]
#clear the display list
elif
evt
==
EVENT_TAB_S
:
#Save tab
if
NumTabTog
==
1
:
zero_entries
()
#Clear the numerical tab buttons if the tab is not in use.
LoadTabTog
=
0
SaveTabTog
=
1
MiscTabTog
=
0
NumTabTog
=
0
if
dualList
==
0
:
if
wheelslider
==
1
:
if
ListTabTog
==
1
:
listScroll
=
line_top
elif
BonesTabTog
==
1
:
listScrollB
=
line_top
elif
AnimTabTog
==
1
:
listScrollA
=
line_top
ListTabTog
=
0
BonesTabTog
=
0
AnimTabTog
=
0
boxList
=
[]
elif
evt
==
EVENT_TAB_M
:
#options (Miscelllaneous) Tab
if
NumTabTog
==
1
:
zero_entries
()
#Clear the numerical tab buttons if the tab is not in use.
LoadTabTog
=
0
SaveTabTog
=
0
MiscTabTog
=
1
NumTabTog
=
0
if
dualList
==
0
:
if
wheelslider
==
1
:
if
ListTabTog
==
1
:
listScroll
=
line_top
elif
BonesTabTog
==
1
:
listScrollB
=
line_top
elif
AnimTabTog
==
1
:
listScrollA
=
line_top
ListTabTog
=
0
BonesTabTog
=
0
AnimTabTog
=
0
boxList
=
[]
elif
evt
==
EVENT_TAB_N
:
#Numerical entry tab
LoadTabTog
=
0
SaveTabTog
=
0
MiscTabTog
=
0
NumTabTog
=
1
if
dualList
==
0
:
if
wheelslider
==
1
:
if
ListTabTog
==
1
:
listScroll
=
line_top
elif
BonesTabTog
==
1
:
listScrollB
=
line_top
elif
AnimTabTog
==
1
:
listScrollA
=
line_top
ListTabTog
=
0
BonesTabTog
=
0
AnimTabTog
=
0
boxList
=
[]
lastBone
=
""
if
len
(
boxBones
)
>
0
:
lastBone
=
boxBones
[
len
(
boxBones
)
-
1
]
entry_values
()
#load the dial values
elif
evt
==
EVENT_TAB_T
:
#lisT tab
if
wheelslider
==
1
:
if
BonesTabTog
==
1
:
listScrollB
=
line_top
elif
AnimTabTog
==
1
:
listScrollA
=
line_top
line_top
=
listScroll
if
BonesTabTog
==
1
or
AnimTabTog
==
1
:
in_box
=
0
boxList
=
poseList
#Fill the pose list for display
ListTabTog
=
1
BonesTabTog
=
0
AnimTabTog
=
0
if
dualList
==
0
:
if
NumTabTog
==
1
:
zero_entries
()
#Clear the numerical tab buttons if the tab is not in use.
LoadTabTog
=
0
SaveTabTog
=
0
MiscTabTog
=
0
NumTabTog
=
0
elif
evt
==
EVENT_TAB_B
:
#Bones tab
if
wheelslider
==
1
:
if
ListTabTog
==
1
:
listScroll
=
line_top
elif
AnimTabTog
==
1
:
listScrollA
=
line_top
line_top
=
listScrollB
if
ListTabTog
==
1
or
AnimTabTog
==
1
:
in_box
=
0
#Re-set to keep multi-task list from bleeding over
boxList
=
[]
#clear the display list (re-filled in gui listbox draw event)
ListTabTog
=
0
BonesTabTog
=
1
AnimTabTog
=
0
if
dualList
==
0
:
if
NumTabTog
==
1
:
zero_entries
()
#Clear the numerical tab buttons if the tab is not in use.
LoadTabTog
=
0
SaveTabTog
=
0
MiscTabTog
=
0
NumTabTog
=
0
if
NumTabTog
==
1
:
entry_values
()
#Refresh both numbers tab and the boxBones display list
elif
evt
==
EVENT_TAB_A
:
#Animation frames tab
if
wheelslider
==
1
:
if
ListTabTog
==
1
:
listScroll
=
line_top
elif
BonesTabTog
==
1
:
line_top
=
listScrollB
line_top
=
listScrollA
if
ListTabTog
==
1
or
BonesTabTog
==
1
:
in_box
=
0
#Re-set to keep multi-task list from bleeding over
boxList
=
[]
#clear the display list (re-filled in gui listbox draw event)
ListTabTog
=
0
BonesTabTog
=
0
AnimTabTog
=
1
if
dualList
==
0
:
if
NumTabTog
==
1
:
zero_entries
()
#Clear the numerical tab buttons if the tab is not in use.
LoadTabTog
=
0
SaveTabTog
=
0
MiscTabTog
=
0
NumTabTog
=
0
curFrame
=
Blender
.
Get
(
'curframe'
)
elif
evt
==
EVENT_LISTSCROLL
:
#listbox slider handling
if
ListTabTog
==
1
:
#This handles three different listbox sliders
listScroll
=
int
(
_scroll_slider
.
val
)
if
listScroll
==
0
:
listScroll
+=
1
elif
BonesTabTog
==
1
:
listScrollB
=
int
(
_scroll_slider
.
val
)
if
listScrollB
==
0
:
listScrollB
+=
1
elif
AnimTabTog
==
1
:
listScrollA
=
int
(
_scroll_slider
.
val
)
if
listScrollA
==
0
:
listScrollA
+=
1
in_box
=
0
#Keep mouse event from mis-interpreting click release
elif
evt
==
EVENT_WHEEL
:
#options tab wheelmouse toggle
wheelslider
=
1
-
wheelslider
if
wheelslider
==
1
:
#Convert between displayed line number values and list index values
listScroll
-=
1
listScrollB
-=
1
listScrollA
-=
1
if
wheelslider
==
0
:
listScroll
+=
1
listScrollB
+=
1
listScrollA
+=
1
elif
evt
==
EVENT_NUMB
:
#options tab line numbers toggle
numList
=
1
-
numList
elif
evt
==
EVENT_FOLDER
:
#listbox folder browse toggle
foldTog
=
1
-
foldTog
box_select
=
[]
#clear the display list
if
foldTog
==
1
:
line_top
=
0
#Re-set top line of listbox to keep things in-bounds
listScroll
=
1
folder_browse
(
LibPath
)
if
foldTog
==
0
:
LibPath
=
sys
.
join
(
LibPath
,
sys
.
basename
(
Blender
.
Get
(
'filename'
)))
#list_browser needs a dummy filename
list_browser
(
LibPath
)
batchLoad
=
0
#turn off batch mode
batchSave
=
0
boxList
=
poseList
#fill the list
elif
evt
==
EVENT_BONEMENU
:
#Bones list options button
bonebox_menu
()
elif
evt
==
EVENT_GROUP
:
#Toggle adjusted to allow multiple menu selections
if
GroupTog
==
0
:
#Load tab partial groups toggle
GroupTog
=
1
-
GroupTog
if
GroupTog
==
1
:
GroupLoad_Menu
()
elif
evt
==
EVENT_NOROLL
:
#Save tab restmatrix conversion button
NoRollTog
=
1
-
NoRollTog
NoRollPose
=
NoRollTog
elif
evt
==
EVENT_IK
:
#Save tab posematrix conversion button
IKTog
=
1
-
IKTog
IKPose
=
IKTog
elif
evt
==
EVENT_DUAL
:
#Dual display option toggle (with width change)
dualList
=
1
-
dualList
if
dualList
==
1
:
if
_dual_width
.
val
==
240
:
_dual_width
.
val
=
180
#resets only if user hasn't altered defaults
ListTabTog
=
1
#Turn on the pose listbox
boxList
=
poseList
#Fill the pose list for display
if
dualList
==
0
:
if
_dual_width
.
val
==
180
:
_dual_width
.
val
=
240
if
ListTabTog
==
1
:
#Close lists
if
wheelslider
==
1
:
listScroll
=
line_top
ListTabTog
=
0
elif
BonesTabTog
==
1
:
if
wheelslider
==
1
:
listScrollB
=
line_top
BonesTabTog
=
0
elif
AnimTabTog
==
1
:
if
wheelslider
==
1
:
listScrollA
=
line_top
AnimTabTog
=
0
in_box
=
0
#prevent mouse-click errors with listbox re-positioning
elif
evt
==
EVENT_ENTRY
:
#numerical tab pose mode entries
numerical_entry
()
elif
evt
==
EVENT_KEYF
:
#numerical tab keyframes toggle
myKeys
=
1
-
myKeys
if
myKeys
==
1
:
options
=
PupMenu
(
"Select keyframing option: %t|Add keyframes for all bones
%x
1\
|
Add
Keyframes
only
for
bones
list
selections
%
x2
|
Add
keyframe
only
for
active
bones
list
bone
%
x3
\
|
Cancel
%
x5
")
if
options
==
1
:
keyType
=
1
elif
options
==
2
:
keyType
=
2
elif
options
==
3
:
keyType
=
3
else
:
if
keyType
==
0
:
myKeys
=
0
#cancel selected or -1 returned
elif
myKeys
==
0
:
keyType
=
0
elif
evt
==
EVENT_EDIT
:
#numerical tab edit mode entries
numerical_edit
()
elif
evt
==
EVENT_UNIQUE
:
#euler unique option in options tab
uniqueRot
=
1
-
uniqueRot
elif
evt
==
EVENT_FLIPBONE
:
#load tab "Flip Bones" button
MirrorBone
=
1
-
MirrorBone
if
MirrorBone
==
1
:
MirrorPose
=
0
elif
evt
==
EVENT_ANIMMENU
:
#Select button on frames tab
anim_menu
()
elif
evt
==
EVENT_BATCHLOAD
:
#Load button on poses tab (batch mode)
if
len
(
boxPoses
)
>
0
:
partPose
=
_partial_slider
.
val
open_batch
(
boxPoses
[
0
])
elif
evt
==
EVENT_BATCHTOG
:
#Batch toggle on poses tab.
if
foldTog
==
0
:
batchLoad
=
1
-
batchLoad
if
batchLoad
==
1
:
openBatch
=
1
#batch loading toggle
LibTog
=
1
#load options menu toggle
saveBatch
=
1
#batch save toggle
OptPose
=
1
#save options menu toggle
elif
batchLoad
==
0
:
#reset load/save menu toggles, if appropriate
openBatch
=
0
saveBatch
=
0
if
LibVar
==
HipPose
==
hipR
==
hipT
==
bodyscale
==
addscale
\
==
openBatch
==
askKey
==
torsoZero
==
0
:
LibTog
=
0
if
EmpPose
==
IKPose
==
NoRollPose
==
saveBatch
==
LibSave
==
0
:
OptPose
=
0
boxPoses
=
[]
elif
evt
==
EVENT_BATCHFRAMES
:
#Batch toggle on frames tab
batchFrames
=
1
-
batchFrames
elif
evt
==
EVENT_IKTOG
:
#IK button on frames tab
IK_menu
()
elif
evt
==
EVENT_TOOLS
:
#Tolls button on frames tab
tools_menu
()
elif
evt
==
EVENT_REG
:
regmenu
=
PupMenu
(
"Options: %t|Set GUI preferences with next script exit
%x
1\
|
Remove
preferred
settings
%
x2
|
Cancel
%
x3
")
if
regmenu
==
1
:
setprefs
=
1
-
setprefs
if
setprefs
==
1
:
notice
=
PupMenu
(
"Settings will be stored in registry when you exit the script."
)
elif
regmenu
==
2
:
saveloc
=
Blender
.
Get
(
'homedir'
)
if
sys
.
exists
(
sys
.
join
(
saveloc
,
"PoseHandlerSettings.txt"
))
==
1
:
os
.
remove
(
sys
.
join
(
saveloc
,
"PoseHandlerSettings.txt"
))
elif
evt
==
EVENT_POSERSAVE
:
global
JPdict
PoserSave
=
1
-
PoserSave
if
PoserSave
==
0
:
JPdict
.
clear
()
if
PoserSave
==
1
:
menu
=
PupMenu
(
"Poser export requires joint rotation order data %t|Parse joint order from a cr2/crz or pz2/p2z
%x
1\
|
Load
joint
order
from
a
saved
text
file
%
x2
|
Save
current
loaded
joint
orders
to
a
text
file
%
x3
\
|
Change
joint
order
for
bones
list
selections
%
x4
|
Use
automatic
(
generic
)
joint
rotation
order
%
x5
")
if
menu
==
1
:
JPdict
=
{}
Window
.
FileSelector
(
parse_JP_order
,
'Browse for .cr2 or .pz2.'
)
elif
menu
==
2
:
JPdict
=
{}
Window
.
FileSelector
(
import_JP_order
,
'Browse for .txt file.'
)
elif
menu
==
3
:
Window
.
FileSelector
(
export_JP_order
,
'Browse for save location.'
)
elif
menu
==
4
:
change_JP_order
()
elif
evt
==
EVENT_BONESEARCH
:
bone_search
()
elif
evt
==
EVENT_BONEGRAB
:
bone_grab
()
elif
evt
==
EVENT_POSESEARCH
:
if
foldTog
==
0
:
#disabled in folder browser mode
pose_search
()
elif
evt
==
EVENT_NOEVENT
:
#This prompts a gui re-draw
pass
else
:
return
# no need to redraw if nothing changed
Draw
()
def
update_ini
():
saveloc
=
Blender
.
Get
(
'homedir'
)
temptext
=
""
temptext
+=
"LoadTabTog<:>
%i
\n
"
%
(
LoadTabTog
)
temptext
+=
"SaveTabTog<:>
%i
\n
"
%
(
SaveTabTog
)
temptext
+=
"MiscTabTog<:>
%i
\n
"
%
(
MiscTabTog
)
temptext
+=
"ListTabTog<:>
%i
\n
"
%
(
ListTabTog
)
temptext
+=
"BonesTabTog<:>
%i
\n
"
%
(
BonesTabTog
)
temptext
+=
"NumTabTog<:>
%i
\n
"
%
(
NumTabTog
)
temptext
+=
"AnimTabTog<:>
%i
\n
"
%
(
AnimTabTog
)
temptext
+=
"numList<:>
%i
\n
"
%
(
numList
)
temptext
+=
"wheelslider<:>
%i
\n
"
%
(
wheelslider
)
temptext
+=
"dualList<:>
%i
\n
"
%
(
dualList
)
temptext
+=
"uniqueRot<:>
%i
\n
"
%
(
uniqueRot
)
temptext
+=
"loadlist<:>
%s
\n
"
%
(
loadlist
)
temptext
+=
"_dual_width<:>
%i
\n
"
%
(
_dual_width
.
val
)
temptext
+=
"bodyscale<:>
%i
\n
"
%
(
bodyscale
)
temptext
+=
"addscale<:>
%i
\n
"
%
(
addscale
)
temptext
+=
"HipPose<:>
%i
\n
"
%
(
HipPose
)
temptext
+=
"hipR<:>
%i
\n
"
%
(
hipR
)
temptext
+=
"hipT<:>
%i
\n
"
%
(
hipT
)
temptext
+=
"LibVar<:>
%i
\n
"
%
(
LibVar
)
temptext
+=
"LibTog<:>
%i
\n
"
%
(
LibTog
)
temptext
+=
"LibPath<:>
%s
\n
"
%
(
LibPath
)
temptext
+=
"poseList<:>
%s
\n
"
%
(
poseList
)
temptext
+=
"torsoZero<:>
%i
\n
"
%
(
torsoZero
)
temptext
+=
"poseStart<:>
%i
\n
"
%
(
poseStart
)
temptext
+=
"posePages<:>
%i
\n
"
%
(
posePages
)
temptext
+=
"poseLimit<:>
%i
\n
"
%
(
poseLimit
)
temptext
+=
"suff<:>
%i
\n
"
%
(
suff
)
temptext
+=
"pref<:>
%i
\n
"
%
(
pref
)
temptext
+=
"right<:>
%s
\n
"
%
(
right
)
temptext
+=
"left<:>
%s
\n
"
%
(
left
)
temptext
+=
"LibPath<:>
%s
\n
"
%
(
LibPath
)
temptext
+=
"right_alt<:>
%s
\n
"
%
(
right_alt
)
temptext
+=
"left_alt<:>
%s
\n
"
%
(
left_alt
)
temptext
+=
"minVal<:>
%i
\n
"
%
(
minVal
)
temptext
+=
"maxVal<:>
%i
\n
"
%
(
maxVal
)
temptext
+=
"boneSort<:>
%i
"
%
(
boneSort
)
settings
=
open
(
sys
.
join
(
saveloc
,
"PoseHandlerSettings.txt"
),
"w"
)
settings
.
write
(
temptext
)
settings
.
close
()
def
get_from_ini
():
global
LoadTabTog
,
SaveTabTog
,
MiscTabTog
,
ListTabTog
,
BonesTabTog
,
numList
,
wheelslider
,
dualList
,
\
NumTabTog
,
uniqueRot
,
loadlist
,
AnimTabTog
,
_dual_width
,
listScroll
,
listScrollA
,
listScrollB
global
bodyscale
,
addscale
,
HipPose
,
hipR
,
hipT
,
LibVar
,
openBatch
,
LibTog
,
\
TrimPose
,
LibPath
,
poseList
,
torsoZero
,
boneSort
global
poseStart
,
posePages
,
poseLimit
,
suff
,
pref
,
right
,
left
,
lenR
,
lenL
,
right_alt
,
\
left_alt
,
maxVal
,
minVal
saveloc
=
Blender
.
Get
(
'homedir'
)
if
sys
.
exists
(
sys
.
join
(
saveloc
,
"PoseHandlerSettings.txt"
))
==
1
:
settings
=
open
(
sys
.
join
(
saveloc
,
"PoseHandlerSettings.txt"
),
"r"
)
lines
=
settings
.
readlines
()
for
line
in
lines
:
data
=
line
.
rstrip
(
"
\n
"
)
.
split
(
"<:>"
)
if
data
[
0
]
==
"LoadTabTog"
:
LoadTabTog
=
int
(
data
[
1
])
elif
data
[
0
]
==
"SaveTabTog"
:
SaveTabTog
=
int
(
data
[
1
])
elif
data
[
0
]
==
"MiscTabTog"
:
MiscTabTog
=
int
(
data
[
1
])
elif
data
[
0
]
==
"ListTabTog"
:
ListTabTog
=
int
(
data
[
1
])
elif
data
[
0
]
==
"BonesTabTog"
:
BonesTabTog
=
int
(
data
[
1
])
elif
data
[
0
]
==
"NumTabTog"
:
NumTabTog
=
int
(
data
[
1
])
elif
data
[
0
]
==
"AnimTabTog"
:
AnimTabTog
=
int
(
data
[
1
])
elif
data
[
0
]
==
"numList"
:
numList
=
int
(
data
[
1
])
elif
data
[
0
]
==
"wheelslider"
:
wheelslider
=
int
(
data
[
1
])
elif
data
[
0
]
==
"dualList"
:
dualList
=
int
(
data
[
1
])
elif
data
[
0
]
==
"uniqueRot"
:
uniqueRot
=
int
(
data
[
1
])
elif
data
[
0
]
==
"loadlist"
:
loadlist
=
data
[
1
]
elif
data
[
0
]
==
"_dual_width"
:
_dual_width
.
val
=
int
(
data
[
1
])
elif
data
[
0
]
==
"bodyscale"
:
bodyscale
=
int
(
data
[
1
])
elif
data
[
0
]
==
"addscale"
:
addscale
=
int
(
data
[
1
])
elif
data
[
0
]
==
"HipPose"
:
HipPose
=
int
(
data
[
1
])
elif
data
[
0
]
==
"hipR"
:
hipR
=
int
(
data
[
1
])
elif
data
[
0
]
==
"hipT"
:
hipT
=
int
(
data
[
1
])
elif
data
[
0
]
==
"LibVar"
:
LibVar
=
int
(
data
[
1
])
elif
data
[
0
]
==
"LibTog"
:
LibTog
=
int
(
data
[
1
])
elif
data
[
0
]
==
"LibPath"
:
LibPath
=
data
[
1
]
elif
data
[
0
]
==
"poseList"
:
poseList
=
data
[
1
]
elif
data
[
0
]
==
"torsoZero"
:
torsoZero
=
int
(
data
[
1
])
elif
data
[
0
]
==
"poseStart"
:
poseStart
=
int
(
data
[
1
])
elif
data
[
0
]
==
"posePages"
:
posePages
=
int
(
data
[
1
])
elif
data
[
0
]
==
"poseLimit"
:
poseLimit
=
int
(
data
[
1
])
elif
data
[
0
]
==
"suff"
:
suff
=
int
(
data
[
1
])
elif
data
[
0
]
==
"pref"
:
pref
=
int
(
data
[
1
])
elif
data
[
0
]
==
"right"
:
right
=
data
[
1
]
elif
data
[
0
]
==
"left"
:
left
=
data
[
1
]
elif
data
[
0
]
==
"right_alt"
:
right_alt
=
data
[
1
]
elif
data
[
0
]
==
"left_alt"
:
left_alt
=
data
[
1
]
elif
data
[
0
]
==
"maxVal"
:
maxVal
=
int
(
data
[
1
])
elif
data
[
0
]
==
"minVal"
:
minVal
=
int
(
data
[
1
])
elif
data
[
0
]
==
"boneSort"
:
boneSort
=
int
(
data
[
1
])
settings
.
close
()
lenR
=
len
(
right
)
lenL
=
len
(
left
)
listScroll
=
1
-
wheelslider
listScrollB
=
1
-
wheelslider
listScrollA
=
1
-
wheelslider
if
sys
.
exists
(
LibPath
)
!=
2
:
LibPath
=
""
libVar
=
0
loadlist
=
[]
poseStart
=
0
posePages
=
0
else
:
LibPath
=
sys
.
join
(
LibPath
,
sys
.
basename
(
Blender
.
Get
(
'filename'
)))
#list_browser needs a dummy filename
list_browser
(
LibPath
)
if
ListTabTog
==
1
:
boxList
=
poseList
#fill the list
else
:
boxList
=
[]
#force a refresh for anim and bones tab
get_from_ini
()
Register
(
gui
,
event
,
bevent
)
if
Blender
.
Get
(
'version'
)
<
242
:
#notification for versions prior to 242
notice
=
PupMenu
(
"Some features will not function properly in versions before 2.42: %t\
|-
Numerical
entry
dials
on
'number'
tab
will
respond
incorrectly
%
x1
\
|-
Some
keyframe
options
on
'frames'
tab
will
not
work
%
x2
\
|-
All
IK
-
related
functions
on
'bones'
tab
will
be
disabled
%
x3
\
|
Some
features
will
not
work
without
a
CVS
build
of
242
:
%
x6
\
|-
The
'bones'
tab
'grab'
function
will
not
work
.
%
x4
\
|-
The
'bones'
tab
'search'
function
will
not
select
a
bone
in
3
d
view
.
%
x5
")
File Metadata
Details
Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ab/4c/c22e9c941d0d8ed7dcd994ae1b79
Event Timeline
Log In to Comment