Remove workaround for uuid, resolved with the Python3.4x and MSVC2013 move.
[blender-addons.git] / io_scene_ms3d / ms3d_export.py
blob127c2496965189fd199778135e949ed9c2dc3372
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
19 # <pep8 compliant>
21 ###############################################################################
22 #234567890123456789012345678901234567890123456789012345678901234567890123456789
23 #--------1---------2---------3---------4---------5---------6---------7---------
26 # ##### BEGIN COPYRIGHT BLOCK #####
28 # initial script copyright (c)2011-2013 Alexander Nussbaumer
30 # ##### END COPYRIGHT BLOCK #####
33 #import python stuff
34 import io
35 from math import (
36 pi,
38 from mathutils import (
39 Matrix,
41 from os import (
42 path,
44 from sys import (
45 exc_info,
47 from time import (
48 time,
52 # import io_scene_ms3d stuff
53 from io_scene_ms3d.ms3d_strings import (
54 ms3d_str,
56 from io_scene_ms3d.ms3d_spec import (
57 Ms3dSpec,
58 Ms3dModel,
59 Ms3dVertex,
60 Ms3dTriangle,
61 Ms3dGroup,
62 Ms3dMaterial,
63 Ms3dJoint,
64 Ms3dRotationKeyframe,
65 Ms3dTranslationKeyframe,
66 Ms3dCommentEx,
67 Ms3dComment,
69 from io_scene_ms3d.ms3d_utils import (
70 select_all,
71 enable_edit_mode,
72 pre_setup_environment,
73 post_setup_environment,
74 matrix_difference,
76 from io_scene_ms3d.ms3d_ui import (
77 Ms3dUi,
78 Ms3dMaterialProperties,
79 Ms3dMaterialHelper,
83 #import blender stuff
84 from bpy import (
85 ops,
87 import bmesh
90 ###############################################################################
91 class Ms3dExporter():
92 """
93 Load a MilkShape3D MS3D File
94 """
95 def __init__(self,
96 report,
97 verbose='NONE',
98 use_blender_names=True,
99 use_blender_materials=False,
100 apply_transform=True,
101 apply_modifiers=True,
102 apply_modifiers_mode='PREVIEW',
103 use_animation=True,
104 normalize_weights=True,
105 shrink_to_keys=False,
106 bake_each_frame=True,
108 self.report = report
109 self.options_verbose = verbose
110 self.options_use_blender_names = use_blender_names
111 self.options_use_blender_materials = use_blender_materials
112 self.options_apply_transform = apply_transform
113 self.options_apply_modifiers = apply_modifiers
114 self.options_apply_modifiers_mode = apply_modifiers_mode
115 self.options_use_animation = use_animation
116 self.options_normalize_weights = normalize_weights
117 self.options_shrink_to_keys = shrink_to_keys
118 self.options_bake_each_frame = bake_each_frame
119 pass
121 # create a empty ms3d ms3d_model
122 # fill ms3d_model with blender content
123 # writer ms3d file
124 def write(self, blender_context, filepath):
125 """convert bender content to ms3d content and write it to file"""
127 t1 = time()
128 t2 = None
130 try:
131 # setup environment
132 pre_setup_environment(self, blender_context)
134 # create an empty ms3d template
135 ms3d_model = Ms3dModel()
137 # inject blender data to ms3d file
138 self.from_blender(blender_context, ms3d_model)
140 t2 = time()
142 try:
143 # write ms3d file to disk
144 with io.FileIO(filepath, "wb") as raw_io:
145 debug_out = ms3d_model.write(raw_io)
146 raw_io.flush()
147 raw_io.close()
149 if self.options_verbose in Ms3dUi.VERBOSE_MAXIMAL:
150 print(debug_out)
151 finally:
152 pass
154 # if option is set, this time will enlargs the io time
155 if self.options_verbose in Ms3dUi.VERBOSE_MAXIMAL:
156 ms3d_model.print_internal()
158 post_setup_environment(self, blender_context)
159 # restore active object
160 blender_context.scene.objects.active = self.active_object
162 if ((not blender_context.scene.objects.active)
163 and (blender_context.selected_objects)):
164 blender_context.scene.objects.active \
165 = blender_context.selected_objects[0]
167 # restore pre operator undo state
168 blender_context.user_preferences.edit.use_global_undo = self.undo
170 is_valid, statistics = ms3d_model.is_valid()
171 if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
172 print()
173 print("##########################################################")
174 print("Export from Blender to MS3D")
175 print(statistics)
176 print("##########################################################")
178 except Exception:
179 type, value, traceback = exc_info()
180 if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
181 print("write - exception in try block\n type: '{0}'\n"
182 " value: '{1}'".format(type, value, traceback))
183 if self.report:
184 self.report({'WARNING', 'ERROR', }, "write - exception.")
186 if t2 is None:
187 t2 = time()
189 return False
191 else:
192 pass
194 t3 = time()
195 if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
196 print(ms3d_str['SUMMARY_EXPORT'].format(
197 (t3 - t1), (t2 - t1), (t3 - t2)))
199 return True
202 ###########################################################################
203 def from_blender(self, blender_context, ms3d_model):
204 blender_mesh_objects = []
206 source = (blender_context.active_object, )
208 for blender_object in source:
209 if blender_object and blender_object.type == 'MESH' \
210 and blender_object.is_visible(blender_context.scene):
211 blender_mesh_objects.append(blender_object)
213 blender_to_ms3d_bones = {}
215 self.create_animation(blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones)
216 self.create_geometry(blender_context, ms3d_model, blender_mesh_objects,
217 blender_to_ms3d_bones)
220 ###########################################################################
221 def create_geometry(self, blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones):
222 blender_scene = blender_context.scene
224 blender_to_ms3d_vertices = {}
225 blender_to_ms3d_triangles = {}
226 blender_to_ms3d_groups = {}
227 blender_to_ms3d_materials = {}
229 for blender_mesh_object in blender_mesh_objects:
230 blender_mesh = blender_mesh_object.data
232 ms3d_model._model_ex_object.joint_size = \
233 blender_mesh.ms3d.joint_size
234 ms3d_model._model_ex_object.alpha_ref = blender_mesh.ms3d.alpha_ref
235 ms3d_model._model_ex_object.transparency_mode = \
236 Ms3dUi.transparency_mode_to_ms3d(
237 blender_mesh.ms3d.transparency_mode)
239 if blender_mesh.ms3d.comment:
240 ms3d_model._comment_object = Ms3dComment(blender_mesh.ms3d.comment)
242 ##########################
243 # prepare ms3d groups if available
244 # works only for exporting active object
245 ##EXPORT_ACTIVE_ONLY:
246 for ms3d_local_group_index, blender_ms3d_group in enumerate(
247 blender_mesh.ms3d.groups):
248 ms3d_group = Ms3dGroup()
249 ms3d_group.__index = len(ms3d_model._groups)
250 ms3d_group.name = blender_ms3d_group.name
251 ms3d_group.flags = Ms3dUi.flags_to_ms3d(blender_ms3d_group.flags)
252 if blender_ms3d_group.comment:
253 ms3d_group._comment_object = Ms3dCommentEx()
254 ms3d_group._comment_object.comment = \
255 blender_ms3d_group.comment
256 ms3d_group._comment_object.index = len(ms3d_model._groups)
257 ms3d_group.material_index = None # to mark as not setted
258 ms3d_model._groups.append(ms3d_group)
259 blender_to_ms3d_groups[blender_ms3d_group.id] = ms3d_group
261 ##########################
262 # i have to use BMesh, because there are several custom data stored.
263 # BMesh doesn't support quads_convert_to_tris()
264 # so, i use that very ugly way:
265 # create a complete copy of mesh and bend object data
266 # to be able to apply operations to it.
268 # temporary, create a full heavy copy of the model
269 # (object, mesh, modifiers)
270 blender_mesh_temp = blender_mesh_object.data.copy()
271 blender_mesh_object_temp = blender_mesh_object.copy()
272 blender_mesh_object_temp.data = blender_mesh_temp
273 blender_scene.objects.link(blender_mesh_object_temp)
274 blender_scene.objects.active = blender_mesh_object_temp
276 # apply transform
277 if self.options_apply_transform:
278 matrix_transform = blender_mesh_object_temp.matrix_basis
279 else:
280 matrix_transform = 1
282 # apply modifiers
283 for modifier in blender_mesh_object_temp.modifiers:
284 if self.options_apply_modifiers:
285 # disable only armature modifiers and only,
286 # when use_animation is enabled
287 if self.options_use_animation \
288 and modifier.type in {'ARMATURE', }:
289 modifier.show_viewport = False
290 modifier.show_render = False
291 else:
292 # disable all modifiers,
293 # to be able to add and apply triangulate modifier later
294 modifier.show_viewport = False
295 modifier.show_render = False
297 # convert to tris by using the triangulate modifier
298 blender_mesh_object_temp.modifiers.new("temp", 'TRIANGULATE')
299 blender_mesh_temp = blender_mesh_object_temp.to_mesh(
300 blender_scene,
301 True,
302 self.options_apply_modifiers_mode)
304 enable_edit_mode(True, blender_context)
305 bm = bmesh.new()
306 bm.from_mesh(blender_mesh_temp)
308 layer_texture = bm.faces.layers.tex.get(
309 ms3d_str['OBJECT_LAYER_TEXTURE'])
310 if layer_texture is None:
311 layer_texture = bm.faces.layers.tex.new(
312 ms3d_str['OBJECT_LAYER_TEXTURE'])
314 layer_smoothing_group = bm.faces.layers.int.get(
315 ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
316 if layer_smoothing_group is None:
317 layer_smoothing_group = bm.faces.layers.int.new(
318 ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
320 layer_group = bm.faces.layers.int.get(
321 ms3d_str['OBJECT_LAYER_GROUP'])
322 if layer_group is None:
323 layer_group = bm.faces.layers.int.new(
324 ms3d_str['OBJECT_LAYER_GROUP'])
326 layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV'])
327 if layer_uv is None:
328 if bm.loops.layers.uv:
329 layer_uv = bm.loops.layers.uv[0]
330 else:
331 layer_uv = bm.loops.layers.uv.new(
332 ms3d_str['OBJECT_LAYER_UV'])
334 layer_deform = bm.verts.layers.deform.active
336 layer_extra = bm.verts.layers.int.get(ms3d_str['OBJECT_LAYER_EXTRA'])
337 if layer_extra is None:
338 layer_extra = bm.verts.layers.int.new(
339 ms3d_str['OBJECT_LAYER_EXTRA'])
342 ##########################
343 # handle vertices
344 for bmv in bm.verts:
345 item = blender_to_ms3d_vertices.get(bmv)
346 if item is None:
347 index = len(ms3d_model._vertices)
348 ms3d_vertex = Ms3dVertex()
349 ms3d_vertex.__index = index
351 ms3d_vertex._vertex = self.geometry_correction(
352 matrix_transform * bmv.co)
354 if self.options_use_animation and layer_deform:
355 blender_vertex_group_ids = bmv[layer_deform]
356 if blender_vertex_group_ids:
357 bone_weights = {}
358 for blender_index, blender_weight \
359 in blender_vertex_group_ids.items():
360 ms3d_joint = blender_to_ms3d_bones.get(
361 blender_mesh_object_temp.vertex_groups[\
362 blender_index].name)
363 if ms3d_joint:
364 weight = bone_weights.get(ms3d_joint.__index)
365 if not weight:
366 weight = 0
367 bone_weights[ms3d_joint.__index] = weight + blender_weight
369 # sort (bone_id: weight) according its weights
370 # to skip only less important weights in the next pass
371 bone_weights_sorted = sorted(bone_weights.items(), key=lambda item: item[1], reverse=True)
373 count = 0
374 bone_ids = []
375 weights = []
376 for ms3d_index, blender_weight \
377 in bone_weights_sorted:
379 if count == 0:
380 ms3d_vertex.bone_id = ms3d_index
381 weights.append(blender_weight)
382 elif count == 1:
383 bone_ids.append(ms3d_index)
384 weights.append(blender_weight)
385 elif count == 2:
386 bone_ids.append(ms3d_index)
387 weights.append(blender_weight)
388 elif count == 3:
389 bone_ids.append(ms3d_index)
390 if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
391 self.report(
392 {'WARNING', 'INFO'},
393 ms3d_str['WARNING_EXPORT_SKIP_WEIGHT'])
394 else:
395 # only first three weights will be supported / four bones
396 if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
397 self.report(
398 {'WARNING', 'INFO'},
399 ms3d_str['WARNING_EXPORT_SKIP_WEIGHT_EX'])
400 break
401 count += 1
403 # normalize weights to 100%
404 if self.options_normalize_weights:
405 weight_sum = 0.0
406 for weight in weights:
407 weight_sum += weight
409 if weight_sum > 0.0:
410 weight_normalize = 1.0 / weight_sum
411 else:
412 weight_normalize = 1.0
414 weight_sum = 100
415 for index, weight in enumerate(weights):
416 if index >= count-1 or index >= 2:
417 # take the full rest instead of calculate,
418 # that should fill up to exactly 100%
419 # (in some cases it is only 99% bacaus of roulding errors)
420 weights[index] = int(weight_sum)
421 break
422 normalized_weight = int(weight * weight_normalize * 100)
423 weights[index] = normalized_weight
424 weight_sum -= normalized_weight
426 # fill up missing values
427 while len(bone_ids) < 3:
428 bone_ids.append(Ms3dSpec.DEFAULT_VERTEX_BONE_ID)
429 while len(weights) < 3:
430 weights.append(0)
432 ms3d_vertex._vertex_ex_object._bone_ids = \
433 tuple(bone_ids)
434 ms3d_vertex._vertex_ex_object._weights = \
435 tuple(weights)
437 if layer_extra:
438 #ms3d_vertex._vertex_ex_object.extra = bmv[layer_extra]
439 # bm.verts.layers.int does only support signed int32
440 # convert signed int32 to unsigned int32 (little-endian)
441 signed_int32 = bmv[layer_extra]
442 bytes_int32 = signed_int32.to_bytes(
443 4, byteorder='little', signed=True)
444 unsigned_int32 = int.from_bytes(
445 bytes_int32, byteorder='little', signed=False)
446 ms3d_vertex._vertex_ex_object.extra = unsigned_int32
448 ms3d_model._vertices.append(ms3d_vertex)
449 blender_to_ms3d_vertices[bmv] = ms3d_vertex
451 ##########################
452 # handle faces / tris
453 for bmf in bm.faces:
454 item = blender_to_ms3d_triangles.get(bmf)
455 if item is None:
456 index = len(ms3d_model._triangles)
457 ms3d_triangle = Ms3dTriangle()
458 ms3d_triangle.__index = index
459 bmv0 = bmf.verts[0]
460 bmv1 = bmf.verts[1]
461 bmv2 = bmf.verts[2]
462 ms3d_vertex0 = blender_to_ms3d_vertices[bmv0]
463 ms3d_vertex1 = blender_to_ms3d_vertices[bmv1]
464 ms3d_vertex2 = blender_to_ms3d_vertices[bmv2]
465 ms3d_vertex0.reference_count += 1
466 ms3d_vertex1.reference_count += 1
467 ms3d_vertex2.reference_count += 1
468 ms3d_triangle._vertex_indices = (
469 ms3d_vertex0.__index,
470 ms3d_vertex1.__index,
471 ms3d_vertex2.__index,
473 ms3d_triangle._vertex_normals = (
474 self.geometry_correction(bmv0.normal),
475 self.geometry_correction(bmv1.normal),
476 self.geometry_correction(bmv2.normal),
478 ms3d_triangle._s = (
479 bmf.loops[0][layer_uv].uv.x,
480 bmf.loops[1][layer_uv].uv.x,
481 bmf.loops[2][layer_uv].uv.x,
483 ms3d_triangle._t = (
484 1.0 - bmf.loops[0][layer_uv].uv.y,
485 1.0 - bmf.loops[1][layer_uv].uv.y,
486 1.0 - bmf.loops[2][layer_uv].uv.y,
489 ms3d_triangle.smoothing_group = bmf[layer_smoothing_group]
490 ms3d_model._triangles.append(ms3d_triangle)
492 ms3d_material = self.get_ms3d_material_add_if(
493 blender_mesh, ms3d_model,
494 blender_to_ms3d_materials, bmf.material_index)
495 ms3d_group = blender_to_ms3d_groups.get(bmf[layer_group])
497 ##EXPORT_ACTIVE_ONLY:
498 if ms3d_group is not None:
499 if ms3d_material is None:
500 ms3d_group.material_index = \
501 Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX
502 else:
503 if ms3d_group.material_index is None:
504 ms3d_group.material_index = \
505 ms3d_material.__index
506 else:
507 if ms3d_group.material_index != \
508 ms3d_material.__index:
509 ms3d_group = \
510 self.get_ms3d_group_by_material_add_if(
511 ms3d_model, ms3d_material)
512 else:
513 if ms3d_material is not None:
514 ms3d_group = self.get_ms3d_group_by_material_add_if(
515 ms3d_model, ms3d_material)
516 else:
517 ms3d_group = self.get_ms3d_group_default_material_add_if(
518 ms3d_model)
520 if ms3d_group is not None:
521 ms3d_group._triangle_indices.append(
522 ms3d_triangle.__index)
523 ms3d_triangle.group_index = ms3d_group.__index
525 blender_to_ms3d_triangles[bmf] = ms3d_triangle
527 if bm is not None:
528 bm.free()
530 enable_edit_mode(False, blender_context)
532 ##########################
533 # remove the temporary data
534 blender_scene.objects.unlink(blender_mesh_object_temp)
535 if blender_mesh_temp is not None:
536 blender_mesh_temp.user_clear()
537 blender_context.blend_data.meshes.remove(blender_mesh_temp)
538 blender_mesh_temp = None
539 if blender_mesh_object_temp is not None:
540 blender_mesh_temp = blender_mesh_object_temp.data.user_clear()
541 blender_mesh_object_temp.user_clear()
542 blender_context.blend_data.objects.remove(
543 blender_mesh_object_temp)
544 if blender_mesh_temp is not None:
545 blender_mesh_temp.user_clear()
546 blender_context.blend_data.meshes.remove(blender_mesh_temp)
549 ###########################################################################
550 def create_animation(self, blender_context, ms3d_model,
551 blender_mesh_objects, blender_to_ms3d_bones):
552 ##########################
553 # setup scene
554 blender_scene = blender_context.scene
556 if not self.options_use_animation:
557 ms3d_model.animation_fps = 24
558 ms3d_model.number_total_frames = 1
559 ms3d_model.current_time = 0
560 return
562 frame_start = blender_scene.frame_start
563 frame_end = blender_scene.frame_end
564 frame_total = (frame_end - frame_start) + 1
565 frame_step = blender_scene.frame_step
566 frame_offset = 0
568 fps = blender_scene.render.fps * blender_scene.render.fps_base
569 time_base = 1.0 / fps
571 base_bone_correction = Matrix.Rotation(pi / 2, 4, 'Z')
573 for blender_mesh_object in blender_mesh_objects:
574 blender_bones = None
575 blender_action = None
576 blender_nla_tracks = None
578 # note: only one armature modifier/parent will be handled.
579 # if the parent is an armature, it will be handled irrespective
580 # of existence of any armature modifier
582 # question: maybe it is better to handle
583 # all existing armature sources (parent / modifier)
584 # as a merged animation...
585 # what is best practice in case of multiple animation sources?
587 # take parent to account if it is an armature
588 if blender_mesh_object.parent and \
589 blender_mesh_object.parent_type == 'ARMATURE' and \
590 blender_mesh_object.parent.pose:
591 blender_bones = blender_mesh_object.parent.data.bones
592 blender_pose_bones = blender_mesh_object.parent.pose.bones
593 if blender_mesh_object.parent.animation_data:
594 blender_action = \
595 blender_mesh_object.parent.animation_data.action
596 blender_nla_tracks = \
597 blender_mesh_object.parent.animation_data.nla_tracks
599 # apply transform
600 if self.options_apply_transform:
601 matrix_transform = blender_mesh_object.parent.matrix_basis
602 else:
603 matrix_transform = 1
605 # search for animation modifier
606 else:
607 for blender_modifier in blender_mesh_object.modifiers:
608 if blender_modifier.type == 'ARMATURE' \
609 and blender_modifier.object.pose:
610 blender_bones = blender_modifier.object.data.bones
611 blender_pose_bones = blender_modifier.object.pose.bones
612 if blender_modifier.object.animation_data:
613 blender_action = \
614 blender_modifier.object.animation_data.action
615 blender_nla_tracks = \
616 blender_modifier.object.animation_data.nla_tracks
618 # apply transform
619 if self.options_apply_transform:
620 matrix_transform = blender_modifier.object.matrix_basis
621 else:
622 matrix_transform = 1
624 break
626 # skip animation/bone handling, if no animation data is available
627 if blender_bones is None \
628 and (blender_action is None and blender_nla_tracks is None):
629 continue
631 ##########################
632 # bones
633 blender_bones_ordered = []
634 self.build_blender_bone_dependency_order(
635 blender_bones, blender_bones_ordered)
636 for blender_bone_name in blender_bones_ordered:
637 blender_bone_oject = blender_bones[blender_bone_name]
638 ms3d_joint = Ms3dJoint()
639 ms3d_joint.__index = len(ms3d_model._joints)
641 blender_bone_ms3d = blender_bone_oject.ms3d
642 blender_bone = blender_bone_oject
644 ms3d_joint.flags = Ms3dUi.flags_to_ms3d(blender_bone_ms3d.flags)
645 if blender_bone_ms3d.comment:
646 ms3d_joint._comment_object = Ms3dCommentEx()
647 ms3d_joint._comment_object.comment = \
648 blender_bone_ms3d.comment
649 ms3d_joint._comment_object.index = ms3d_joint.__index
651 ms3d_joint.joint_ex_object._color = blender_bone_ms3d.color[:]
653 ms3d_joint.name = blender_bone.name
655 if blender_bone.parent:
656 ms3d_joint.parent_name = blender_bone.parent.name
657 ms3d_joint.__matrix = matrix_difference(
658 matrix_transform * blender_bone.matrix_local,
659 matrix_transform * blender_bone.parent.matrix_local)
660 else:
661 ms3d_joint.__matrix = base_bone_correction \
662 * matrix_transform * blender_bone.matrix_local
664 mat = ms3d_joint.__matrix
665 loc = mat.to_translation()
666 rot = mat.to_euler('XZY')
667 ms3d_joint._position = self.joint_correction(loc)
668 ms3d_joint._rotation = self.joint_correction(rot)
670 ms3d_model._joints.append(ms3d_joint)
671 blender_to_ms3d_bones[blender_bone.name] = ms3d_joint
673 ##########################
674 # animation
675 frames = None
676 frames_location = set()
677 frames_rotation = set()
678 frames_scale = set()
680 if blender_action:
681 self.fill_keyframe_sets(
682 blender_action.fcurves,
683 frames_location, frames_rotation, frames_scale,
686 if blender_nla_tracks:
687 for nla_track in blender_nla_tracks:
688 if nla_track.mute:
689 continue
690 for strip in nla_track.strips:
691 if strip.mute:
692 continue
693 frame_correction = strip.frame_start \
694 - strip.action_frame_start
695 self.fill_keyframe_sets(
696 strip.action.fcurves,
697 frames_location, frames_rotation, frames_scale,
698 frame_correction)
700 frames = set(frames_location)
701 frames = frames.union(frames_rotation)
702 frames = frames.union(frames_scale)
704 if not self.options_shrink_to_keys:
705 frames = frames.intersection(range(
706 blender_scene.frame_start, blender_scene.frame_end + 1))
708 frames_sorted = list(frames)
709 frames_sorted.sort()
711 if self.options_shrink_to_keys and len(frames_sorted) >= 2:
712 frame_start = frames_sorted[0]
713 frame_end = frames_sorted[len(frames_sorted)-1]
714 frame_total = (frame_end - frame_start) + 1
715 frame_offset = frame_start - 1
717 if self.options_bake_each_frame:
718 frames_sorted = range(int(frame_start), int(frame_end + 1),
719 int(frame_step))
721 frame_temp = blender_scene.frame_current
723 for current_frame in frames_sorted:
724 blender_scene.frame_set(current_frame)
726 current_time = (current_frame - frame_offset) * time_base
727 for blender_bone_name in blender_bones_ordered:
728 blender_bone = blender_bones[blender_bone_name]
729 blender_pose_bone = blender_pose_bones[blender_bone_name]
730 ms3d_joint = blender_to_ms3d_bones[blender_bone_name]
732 m1 = blender_bone.matrix_local.inverted()
733 if blender_pose_bone.parent:
734 m2 = blender_pose_bone.parent.matrix_channel.inverted()
735 else:
736 m2 = 1
737 m3 = blender_pose_bone.matrix.copy()
738 m = ((m1 * m2) * m3)
739 loc = m.to_translation()
740 rot = m.to_euler('XZY')
742 ms3d_joint.translation_key_frames.append(
743 Ms3dTranslationKeyframe(
744 current_time, self.joint_correction(loc)
747 ms3d_joint.rotation_key_frames.append(
748 Ms3dRotationKeyframe(
749 current_time, self.joint_correction(rot)
753 blender_scene.frame_set(frame_temp)
755 ms3d_model.animation_fps = fps
756 if ms3d_model.number_joints > 0:
757 ms3d_model.number_total_frames = int(frame_total)
758 ms3d_model.current_time = ((blender_scene.frame_current \
759 - blender_scene.frame_start) + 1) * time_base
760 else:
761 ms3d_model.number_total_frames = 1
762 ms3d_model.current_time = 0
765 ###########################################################################
766 def get_ms3d_group_default_material_add_if(self, ms3d_model):
767 markerName = "MaterialGroupDefault"
768 markerComment = "group without material"
770 for ms3d_group in ms3d_model._groups:
771 if ms3d_group.material_index == \
772 Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX \
773 and ms3d_group.name == markerName \
774 and ms3d_group._comment_object \
775 and ms3d_group._comment_object.comment == markerComment:
776 return ms3d_group
778 ms3d_group = Ms3dGroup()
779 ms3d_group.__index = len(ms3d_model._groups)
780 ms3d_group.name = markerName
781 ms3d_group._comment_object = Ms3dCommentEx()
782 ms3d_group._comment_object.comment = markerComment
783 ms3d_group._comment_object.index = len(ms3d_model._groups)
784 ms3d_group.material_index = Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX
786 ms3d_model._groups.append(ms3d_group)
788 return ms3d_group
791 ###########################################################################
792 def get_ms3d_group_by_material_add_if(self, ms3d_model, ms3d_material):
793 if ms3d_material.__index < 0 \
794 or ms3d_material.__index >= len(ms3d_model.materials):
795 return None
797 markerName = "MaterialGroup.{}".format(ms3d_material.__index)
798 markerComment = "MaterialGroup({})".format(ms3d_material.name)
800 for ms3d_group in ms3d_model._groups:
801 if ms3d_group.name == markerName \
802 and ms3d_group._comment_object \
803 and ms3d_group._comment_object.comment == markerComment:
804 return ms3d_group
806 ms3d_group = Ms3dGroup()
807 ms3d_group.__index = len(ms3d_model._groups)
808 ms3d_group.name = markerName
809 ms3d_group._comment_object = Ms3dCommentEx()
810 ms3d_group._comment_object.comment = markerComment
811 ms3d_group._comment_object.index = len(ms3d_model._groups)
812 ms3d_group.material_index = ms3d_material.__index
814 ms3d_model._groups.append(ms3d_group)
816 return ms3d_group
819 ###########################################################################
820 def get_ms3d_material_add_if(self, blender_mesh, ms3d_model,
821 blender_to_ms3d_materials, blender_index):
822 if blender_index < 0 or blender_index >= len(blender_mesh.materials):
823 return None
825 blender_material = blender_mesh.materials[blender_index]
826 ms3d_material = blender_to_ms3d_materials.get(blender_material)
827 if ms3d_material is None:
828 ms3d_material = Ms3dMaterial()
829 ms3d_material.__index = len(ms3d_model.materials)
831 blender_ms3d_material = blender_material.ms3d
833 if not self.options_use_blender_names \
834 and not self.options_use_blender_materials \
835 and blender_ms3d_material.name:
836 ms3d_material.name = blender_ms3d_material.name
837 else:
838 ms3d_material.name = blender_material.name
840 temp_material = None
841 if self.options_use_blender_materials:
842 temp_material = Ms3dMaterial()
843 Ms3dMaterialHelper.copy_from_blender(
844 None, None, temp_material, blender_material)
845 else:
846 temp_material = blender_ms3d_material
848 ms3d_material._ambient = temp_material.ambient[:]
849 ms3d_material._diffuse = temp_material.diffuse[:]
850 ms3d_material._specular = temp_material.specular[:]
851 ms3d_material._emissive = temp_material.emissive[:]
852 ms3d_material.shininess = temp_material.shininess
853 ms3d_material.transparency = temp_material.transparency
854 ms3d_material.texture = temp_material.texture
855 ms3d_material.alphamap = temp_material.alphamap
857 ms3d_material.mode = Ms3dUi.texture_mode_to_ms3d(
858 blender_ms3d_material.mode)
859 if blender_ms3d_material.comment:
860 ms3d_material._comment_object = Ms3dCommentEx()
861 ms3d_material._comment_object.comment = \
862 blender_ms3d_material.comment
863 ms3d_material._comment_object.index = ms3d_material.__index
865 ms3d_model.materials.append(ms3d_material)
867 blender_to_ms3d_materials[blender_material] = ms3d_material
869 return ms3d_material
872 ###########################################################################
873 def geometry_correction(self, value):
874 return (value[1], value[2], value[0])
877 ###########################################################################
878 def joint_correction(self, value):
879 return (-value[0], value[2], value[1])
882 ###########################################################################
883 def build_blender_bone_dependency_order(self, blender_bones,
884 blender_bones_ordered):
885 if not blender_bones:
886 return blender_bones_ordered
888 blender_bones_children = {None: []}
889 for blender_bone in blender_bones:
890 if blender_bone.parent:
891 blender_bone_children = blender_bones_children.get(
892 blender_bone.parent.name)
893 if blender_bone_children is None:
894 blender_bone_children = blender_bones_children[
895 blender_bone.parent.name] = []
896 else:
897 blender_bone_children = blender_bones_children[None]
899 blender_bone_children.append(blender_bone.name)
901 self.traverse_dependencies(
902 blender_bones_ordered,
903 blender_bones_children,
904 None)
906 return blender_bones_ordered
909 ###########################################################################
910 def traverse_dependencies(self, blender_bones_ordered,
911 blender_bones_children, key):
912 blender_bone_children = blender_bones_children.get(key)
913 if blender_bone_children:
914 for blender_bone_name in blender_bone_children:
915 blender_bones_ordered.append(blender_bone_name)
916 self.traverse_dependencies(
917 blender_bones_ordered,
918 blender_bones_children,
919 blender_bone_name)
921 ###########################################################################
922 def fill_keyframe_sets(self,
923 fcurves,
924 frames_location, frames_rotation, frames_scale,
925 frame_correction):
926 for fcurve in fcurves:
927 if fcurve.data_path.endswith(".location"):
928 frames = frames_location
929 elif fcurve.data_path.endswith(".rotation_euler"):
930 frames = frames_rotation
931 elif fcurve.data_path.endswith(".rotation_quaternion"):
932 frames = frames_rotation
933 elif fcurve.data_path.endswith(".scale"):
934 frames = frames_scale
935 else:
936 pass
938 for keyframe_point in fcurve.keyframe_points:
939 frames.add(int(keyframe_point.co[0] + frame_correction))
942 ###############################################################################
943 #234567890123456789012345678901234567890123456789012345678901234567890123456789
944 #--------1---------2---------3---------4---------5---------6---------7---------
945 # ##### END OF FILE #####