File size: 9,301 Bytes
4d3af08
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# 「プロパティ」エリア → 「アーマチュアデータ」タブ
import os, re, sys, bpy, time, bmesh, mathutils
from . import common

# メニュー等に項目追加
def menu_func(self, context):
	import re
	ob = context.active_object
	if not ob: return
	if ob.type != 'ARMATURE': return
	
	arm = ob.data
	is_boxed = False
	
	bone_data_count = 0
	if 'BoneData:0' in arm and 'LocalBoneData:0' in arm:
		for key in arm.keys():
			if re.search(r'^(Local)?BoneData:\d+$', key):
				bone_data_count += 1
	enabled_clipboard = False
	clipboard = context.window_manager.clipboard
	if 'BoneData:' in clipboard and 'LocalBoneData:' in clipboard:
		enabled_clipboard = True
	if bone_data_count or enabled_clipboard:
		if not is_boxed:
			box = self.layout.box()
			box.label(text="For CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
			is_boxed = True
		
		col = box.column(align=True)
		row = col.row(align=True)
		row.label(text="Bone Data", icon='CONSTRAINT_BONE')
		sub_row = row.row()
		sub_row.alignment = 'RIGHT'
		if bone_data_count:
			sub_row.label(text=str(bone_data_count), icon='CHECKBOX_HLT')
		else:
			sub_row.label(text="0", icon='CHECKBOX_DEHLT')
		row = col.row(align=True)
		row.operator('object.copy_armature_bone_data_property', icon='COPYDOWN', text="Copy")
		row.operator('object.paste_armature_bone_data_property', icon='PASTEDOWN', text="Paste")
		row.operator('object.remove_armature_bone_data_property', icon='X', text="")
	
	flag = False
	for bone in arm.bones:
		if not flag and re.search(r'[_ ]([rRlL])[_ ]', bone.name):
			flag = True
		if not flag and bone.name.count('*') == 1:
			if re.search(r'\.([rRlL])$', bone.name):
				flag = True
		if flag:
			if not is_boxed:
				box = self.layout.box()
				box.label(text="For CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
				is_boxed = True
			
			col = box.column(align=True)
			col.label(text="Convert Bone Names", icon='SORTALPHA')
			row = col.row(align=True)
			row.operator('armature.decode_cm3d2_bone_names', text="CM3D2 → Blender", icon='BLENDER')
			row.operator('armature.encode_cm3d2_bone_names', text="Blender → CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
			break
	
	if 'is T Stance' in arm:
		if not is_boxed:
			box = self.layout.box()
			box.label(text="For CM3D2", icon_value=common.preview_collections['main']['KISS'].icon_id)
			is_boxed = True
		
		col = box.column(align=True)
		col.label(text="Pause", icon='POSE_HLT')
		row = col.row(align=True)
		
		sub_row = row.row(align=True)
		op = sub_row.operator('wm.context_set_int', icon='ARMATURE_DATA', text="Original")
		op.data_path, op.value = 'scene.frame_current', 1
		if context.scene.frame_current % 2:
			sub_row.enabled = False
		
		sub_row = row.row(align=True)
		op = sub_row.operator('wm.context_set_int', icon='POSE_DATA', text="Pose data")
		op.data_path, op.value = 'scene.frame_current', 0
		if not context.scene.frame_current % 2:
			sub_row.enabled = False

class decode_cm3d2_bone_names(bpy.types.Operator):
	bl_idname = 'armature.decode_cm3d2_bone_names'
	bl_label = " Decode CM3D2 bone names→Blender bones names"
	bl_description = "Bone names are converted to Blender bone names for mirror functions."
	bl_options = {'REGISTER', 'UNDO'}
	
	@classmethod
	def poll(cls, context):
		import re
		ob = context.active_object
		if ob:
			if ob.type == 'ARMATURE':
				arm = ob.data
				for bone in arm.bones:
					if re.search(r'[_ ]([rRlL])[_ ]', bone.name):
						return True
		return False
	
	def execute(self, context):
		ob = context.active_object
		arm = ob.data
		convert_count = 0
		for bone in arm.bones:
			bone_name = common.decode_bone_name(bone.name)
			if bone_name != bone.name:
				bone.name = bone_name
				convert_count += 1
		if convert_count == 0:
			self.report(type={'WARNING'}, message="No convertible names were found. Aborting.")
		else:
			self.report(type={'INFO'}, message="Bones names were converted for Blender. Mission Accomplished.")
		return {'FINISHED'}

class encode_cm3d2_bone_names(bpy.types.Operator):
	bl_idname = 'armature.encode_cm3d2_bone_names'
	bl_label = "Blender bone names→CM3D2 bone names"
	bl_description = "blender bone names are reverted back to CM3D2 bone names."
	bl_options = {'REGISTER', 'UNDO'}
	
	@classmethod
	def poll(cls, context):
		import re
		ob = context.active_object
		if ob:
			if ob.type == 'ARMATURE':
				arm = ob.data
				for bone in arm.bones:
					if bone.name.count('*') == 1 and re.search(r'\.([rRlL])$', bone.name):
						return True
		return False
	
	def execute(self, context):
		ob = context.active_object
		arm = ob.data
		convert_count = 0
		for bone in arm.bones:
			bone_name = common.encode_bone_name(bone.name)
			if bone_name != bone.name:
				bone.name = bone_name
				convert_count += 1
		if convert_count == 0:
			self.report(type={'WARNING'}, message="A name that cannot be converted was found, Mission failed")
		else:
			self.report(type={'INFO'}, message="Bone names were converted back to CM3D2 Format. Mission Accomplished.")
		return {'FINISHED'}

class copy_armature_bone_data_property(bpy.types.Operator):
	bl_idname = 'object.copy_armature_bone_data_property'
	bl_label = "Copy the bone Data"
	bl_description = "Copy the bone Data in the armature custom properties to the clipboard."
	bl_options = {'REGISTER', 'UNDO'}
	
	@classmethod
	def poll(cls, context):
		ob = context.active_object
		if ob:
			if ob.type == 'ARMATURE':
				arm = ob.data
				if 'BoneData:0' in arm and 'LocalBoneData:0' in arm:
					return True
		return False
	
	def execute(self, context):
		output_text = ""
		ob = context.active_object.data
		pass_count = 0
		if 'BaseBone' in ob:
			output_text += "BaseBone:" + ob['BaseBone'] + "\n"
		for i in range(99999):
			name = "BoneData:" + str(i)
			if name in ob:
				output_text += "BoneData:" + ob[name] + "\n"
			else:
				pass_count += 1
			if 10 < pass_count:
				break
		pass_count = 0
		for i in range(99999):
			name = "LocalBoneData:" + str(i)
			if name in ob:
				output_text += "LocalBoneData:" + ob[name] + "\n"
			else:
				pass_count += 1
			if 10 < pass_count:
				break
		context.window_manager.clipboard = output_text
		self.report(type={'INFO'}, message="Bone Data was copied, mission accomplished.")
		return {'FINISHED'}

class paste_armature_bone_data_property(bpy.types.Operator):
	bl_idname = 'object.paste_armature_bone_data_property'
	bl_label = "Paste Bone Data"
	bl_description = "Bone Data is pasted into the Armature custom properties. NOTE: this wil replace any Data in the custom properties."
	bl_options = {'REGISTER', 'UNDO'}
	
	@classmethod
	def poll(cls, context):
		ob = context.active_object
		if ob:
			if ob.type == 'ARMATURE':
				clipboard = context.window_manager.clipboard
				if 'BoneData:' in clipboard and 'LocalBoneData:' in clipboard:
					return True
		return False
	
	def execute(self, context):
		import re
		ob = context.active_object.data
		pass_count = 0
		for i in range(99999):
			name = "BoneData:" + str(i)
			if name in ob:
				del ob[name]
			else:
				pass_count += 1
			if 10 < pass_count:
				break
		pass_count = 0
		for i in range(99999):
			name = "LocalBoneData:" + str(i)
			if name in ob:
				del ob[name]
			else:
				pass_count += 1
			if 10 < pass_count:
				break
		bone_data_count = 0
		local_bone_data_count = 0
		for line in context.window_manager.clipboard.split("\n"):
			r = re.search('^BaseBone:(.+)$', line)
			if r:
				ob['BaseBone'] = r.groups()[0]
			r = re.search('^BoneData:(.+)$', line)
			if r:
				if line.count(',') == 4:
					info = r.groups()[0]
					name = "BoneData:" + str(bone_data_count)
					ob[name] = info
					bone_data_count += 1
			r = re.search('^LocalBoneData:(.+)$', line)
			if r:
				if line.count(',') == 1:
					info = r.groups()[0]
					name = "LocalBoneData:" + str(local_bone_data_count)
					ob[name] = info
					local_bone_data_count += 1
		self.report(type={'INFO'}, message="Bone Data was pasted, mission accomplished")
		return {'FINISHED'}

class remove_armature_bone_data_property(bpy.types.Operator):
	bl_idname = 'object.remove_armature_bone_data_property'
	bl_label = "Remove Bone Data"
	bl_description = "Removes all Bone Data from the armature's custom properties."
	bl_options = {'REGISTER', 'UNDO'}
	
	@classmethod
	def poll(cls, context):
		ob = context.active_object
		if ob:
			if ob.type == 'ARMATURE':
				arm = ob.data
				if 'BoneData:0' in arm and 'LocalBoneData:0' in arm:
					return True
		return False
	
	def invoke(self, context, event):
		return context.window_manager.invoke_props_dialog(self)
	
	def draw(self, context):
		self.layout.label(text="Removes all bone Data from the armature's custom properties.", icon='CANCEL')
	
	def execute(self, context):
		ob = context.active_object.data
		pass_count = 0
		if 'BaseBone' in ob:
			del ob['BaseBone']
		for i in range(99999):
			name = "BoneData:" + str(i)
			if name in ob:
				del ob[name]
			else:
				pass_count += 1
			if 10 < pass_count:
				break
		pass_count = 0
		for i in range(99999):
			name = "LocalBoneData:" + str(i)
			if name in ob:
				del ob[name]
			else:
				pass_count += 1
			if 10 < pass_count:
				break
		self.report(type={'INFO'}, message="Bone data was removed, mission accomplished")
		return {'FINISHED'}