-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathsavefile.py
133 lines (105 loc) · 3.13 KB
/
savefile.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import bpy
import json
from bpy_extras.io_utils import ExportHelper, ImportHelper
from .util import matrix_to_list
def draw_panel(ctx, layout):
layout.enabled = not ctx.ui_editing_mappings and not ctx.ui_editing_alignment
row = layout.row()
row.operator(SavefileLoadOperator.bl_idname, icon='FILEBROWSER')
row.operator(SavefileSaveOperator.bl_idname, icon='FILE_TICK')
class SavefileLoadOperator(bpy.types.Operator, ImportHelper):
bl_idname = 'savefile.load'
bl_label = 'Load Config'
bl_description = 'Load bone mappings, alignments and other settings from a file. Can be applied to any armature with identical bone names'
filter_glob: bpy.props.StringProperty(
default='*.blend*',
options={'HIDDEN'},
maxlen=255
)
def execute(self, context):
with open(self.filepath, 'r') as f:
load_serialized_state(context.object.retargeting_context, json.load(f))
return {'FINISHED'}
class SavefileSaveOperator(bpy.types.Operator, ExportHelper):
bl_idname = 'savefile.save'
bl_label = 'Save Config'
filename_ext = '.blend-retarget'
bl_description = 'Save bone mappings, alignments and other settings from a file. Can be applied to any armature with identical bone names'
filter_glob: bpy.props.StringProperty(
default='*.blend-retarget',
options={'HIDDEN'},
maxlen=255
)
def execute(self, context):
with open(self.filepath, 'w') as f:
f.write(
json.dumps(
serialize_state(context.object.retargeting_context),
indent=4
)
)
return {'FINISHED'}
def serialize_state(ctx):
return {
'armatures': {
'source': serialize_armature(ctx.source),
'target': serialize_armature(ctx.target)
},
'mappings': [
{
'source': m.source,
'target': m.target,
'rest': list(m.rest),
'offset': list(m.offset)
}
for m in ctx.mappings
],
'ik_limbs': [
{
'name': l.name,
'enabled': l.enabled,
'target_bone': l.target_bone,
'origin_bone': l.origin_bone,
'control_transform': list(l.control_transform)
}
for l in ctx.ik_limbs
],
'setting_correct_feet': ctx.setting_correct_feet,
'setting_correct_hands': ctx.setting_correct_hands
}
def serialize_armature(armature):
return {
'matrix_world': matrix_to_list(armature.matrix_world),
'bones': {
bone.name: {
'parent': bone.parent.name if bone.parent else None,
'matrix': matrix_to_list(bone.matrix),
'matrix_local': matrix_to_list(bone.matrix_local)
}
for bone in armature.data.bones
}
}
def load_serialized_state(ctx, data):
ctx.is_importing = True
ctx.reset()
for m in data['mappings']:
mapping = ctx.mappings.add()
mapping.source = m['source']
mapping.target = m['target']
mapping.rest = m['rest']
mapping.offset = m['offset']
for l in data['ik_limbs']:
limb = ctx.ik_limbs.add()
limb.name = l['name']
limb.enabled = l['enabled']
limb.target_bone = l['target_bone']
limb.origin_bone = l['origin_bone']
limb.control_transform = l['control_transform']
ctx.setting_correct_feet = data['setting_correct_feet']
ctx.setting_correct_hands = data['setting_correct_hands']
ctx.is_importing = False
ctx.update_drivers()
classes = (
SavefileLoadOperator,
SavefileSaveOperator
)