Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander N <alpha-beta-release@gmx.net>2013-01-27 02:11:42 +0400
committerAlexander N <alpha-beta-release@gmx.net>2013-01-27 02:11:42 +0400
commitd2c18e87de18837fb10ed47ce0ec6737633ee0be (patch)
tree3c1ac84c22290414a3d9d15a0254712aab1cc974 /io_scene_ms3d
parent9707a87e34661d10a3c9126ddd026b8641d15d45 (diff)
moved MilkShape3D MS3D add-on from "addons_contrib" to "addons" (i got hopefully the permission by Campbell Barton)
Diffstat (limited to 'io_scene_ms3d')
-rw-r--r--io_scene_ms3d/__init__.py107
-rw-r--r--io_scene_ms3d/ms3d_export.py880
-rw-r--r--io_scene_ms3d/ms3d_import.py1005
-rw-r--r--io_scene_ms3d/ms3d_spec.py2069
-rw-r--r--io_scene_ms3d/ms3d_strings.py263
-rw-r--r--io_scene_ms3d/ms3d_ui.py1723
-rw-r--r--io_scene_ms3d/ms3d_utils.py222
7 files changed, 6269 insertions, 0 deletions
diff --git a/io_scene_ms3d/__init__.py b/io_scene_ms3d/__init__.py
new file mode 100644
index 00000000..2ae5199d
--- /dev/null
+++ b/io_scene_ms3d/__init__.py
@@ -0,0 +1,107 @@
+# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+bl_info = {
+ 'name': "MilkShape3D MS3D format (.ms3d)",
+ 'description': "Import / Export MilkShape3D MS3D files"\
+ " (conform with MilkShape3D v1.8.4)",
+ 'author': "Alexander Nussbaumer",
+ 'version': (0, 93, 1),
+ 'blender': (2, 65, 3),
+ 'location': "File > Import & File > Export",
+ 'warning': "",
+ 'wiki_url': "http://wiki.blender.org/index.php/Extensions:2.6/Py/"\
+ "Scripts/Import-Export/MilkShape3D_MS3D",
+ 'tracker_url': "http://projects.blender.org/tracker/index.php"\
+ "?func=detail&aid=29404",
+ 'category': "Import-Export",
+ }
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+
+
+# ##### BEGIN COPYRIGHT BLOCK #####
+#
+# initial script copyright (c)2011,2012 Alexander Nussbaumer
+#
+# ##### END COPYRIGHT BLOCK #####
+
+
+# To support reload properly, try to access a package var,
+# if it's there, reload everything
+if 'bpy' in locals():
+ import imp
+ if 'io_scene_ms3d.ms3d_ui' in locals():
+ imp.reload(io_scene_ms3d.ms3d_ui)
+else:
+ from io_scene_ms3d.ms3d_ui import (
+ Ms3dImportOperator,
+ Ms3dExportOperator,
+ )
+
+
+#import blender stuff
+from bpy.utils import (
+ register_module,
+ unregister_module,
+ )
+from bpy.types import (
+ INFO_MT_file_export,
+ INFO_MT_file_import,
+ )
+
+
+###############################################################################
+# registration
+def register():
+ ####################
+ # F8 - key
+ import imp
+ imp.reload(ms3d_ui)
+ # F8 - key
+ ####################
+
+ ms3d_ui.register()
+
+ register_module(__name__)
+ INFO_MT_file_export.append(Ms3dExportOperator.menu_func)
+ INFO_MT_file_import.append(Ms3dImportOperator.menu_func)
+
+
+def unregister():
+ ms3d_ui.unregister()
+
+ unregister_module(__name__)
+ INFO_MT_file_export.remove(Ms3dExportOperator.menu_func)
+ INFO_MT_file_import.remove(Ms3dImportOperator.menu_func)
+
+
+###############################################################################
+# global entry point
+if (__name__ == "__main__"):
+ register()
+
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+# ##### END OF FILE #####
diff --git a/io_scene_ms3d/ms3d_export.py b/io_scene_ms3d/ms3d_export.py
new file mode 100644
index 00000000..bc6425a1
--- /dev/null
+++ b/io_scene_ms3d/ms3d_export.py
@@ -0,0 +1,880 @@
+# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+
+
+# ##### BEGIN COPYRIGHT BLOCK #####
+#
+# initial script copyright (c)2011,2012 Alexander Nussbaumer
+#
+# ##### END COPYRIGHT BLOCK #####
+
+
+#import python stuff
+import io
+from math import (
+ pi,
+ )
+from mathutils import (
+ Matrix,
+ )
+from os import (
+ path,
+ )
+from sys import (
+ exc_info,
+ )
+from time import (
+ time,
+ )
+
+
+# import io_scene_ms3d stuff
+from io_scene_ms3d.ms3d_strings import (
+ ms3d_str,
+ )
+from io_scene_ms3d.ms3d_spec import (
+ Ms3dSpec,
+ Ms3dModel,
+ Ms3dVertex,
+ Ms3dTriangle,
+ Ms3dGroup,
+ Ms3dMaterial,
+ Ms3dJoint,
+ Ms3dRotationKeyframe,
+ Ms3dTranslationKeyframe,
+ Ms3dCommentEx,
+ )
+from io_scene_ms3d.ms3d_utils import (
+ select_all,
+ enable_edit_mode,
+ pre_setup_environment,
+ post_setup_environment,
+ matrix_difference,
+ )
+from io_scene_ms3d.ms3d_ui import (
+ Ms3dUi,
+ Ms3dMaterialProperties,
+ Ms3dMaterialHelper,
+ )
+
+
+#import blender stuff
+from bpy import (
+ ops,
+ )
+import bmesh
+
+
+###############################################################################
+class Ms3dExporter():
+ """
+ Load a MilkShape3D MS3D File
+ """
+ def __init__(self,
+ report,
+ verbose=False,
+ use_blender_names=True,
+ use_blender_materials=False,
+ apply_transform=True,
+ apply_modifiers=True,
+ apply_modifiers_mode='PREVIEW',
+ use_animation=True,
+ normalize_weights=True,
+ shrink_to_keys=False,
+ bake_each_frame=True,
+ ):
+ self.report = report
+ self.options_verbose = verbose
+ self.options_use_blender_names = use_blender_names
+ self.options_use_blender_materials = use_blender_materials
+ self.options_apply_transform = apply_transform
+ self.options_apply_modifiers = apply_modifiers
+ self.options_apply_modifiers_mode = apply_modifiers_mode
+ self.options_use_animation = use_animation
+ self.options_normalize_weights = normalize_weights
+ self.options_shrink_to_keys = shrink_to_keys
+ self.options_bake_each_frame = bake_each_frame
+ pass
+
+ # create a empty ms3d ms3d_model
+ # fill ms3d_model with blender content
+ # writer ms3d file
+ def write(self, blender_context, filepath):
+ """convert bender content to ms3d content and write it to file"""
+
+ t1 = time()
+ t2 = None
+
+ try:
+ # setup environment
+ pre_setup_environment(self, blender_context)
+
+ # create an empty ms3d template
+ ms3d_model = Ms3dModel()
+
+ # inject blender data to ms3d file
+ self.from_blender(blender_context, ms3d_model)
+
+ t2 = time()
+
+ try:
+ # write ms3d file to disk
+ with io.FileIO(filepath, "wb") as raw_io:
+ ms3d_model.write(raw_io)
+ raw_io.flush()
+ raw_io.close()
+ finally:
+ pass
+
+ # if option is set, this time will enlargs the io time
+ if self.options_verbose:
+ ms3d_model.print_internal()
+
+ post_setup_environment(self, blender_context)
+ # restore active object
+ blender_context.scene.objects.active = self.active_object
+
+ if ((not blender_context.scene.objects.active)
+ and (blender_context.selected_objects)):
+ blender_context.scene.objects.active \
+ = blender_context.selected_objects[0]
+
+ # restore pre operator undo state
+ blender_context.user_preferences.edit.use_global_undo = self.undo
+
+ is_valid, statistics = ms3d_model.is_valid()
+ print()
+ print("##########################################################")
+ print("Export from Blender to MS3D")
+ print(statistics)
+ print("##########################################################")
+
+ except Exception:
+ type, value, traceback = exc_info()
+ print("write - exception in try block\n type: '{0}'\n"
+ " value: '{1}'".format(type, value, traceback))
+
+ if t2 is None:
+ t2 = time()
+
+ raise
+
+ else:
+ pass
+
+ t3 = time()
+ print(ms3d_str['SUMMARY_EXPORT'].format(
+ (t3 - t1), (t2 - t1), (t3 - t2)))
+
+ return {"FINISHED"}
+
+
+ ###########################################################################
+ def from_blender(self, blender_context, ms3d_model):
+ blender_mesh_objects = []
+
+ source = (blender_context.active_object, )
+
+ for blender_object in source:
+ if blender_object and blender_object.type == 'MESH' \
+ and blender_object.is_visible(blender_context.scene):
+ blender_mesh_objects.append(blender_object)
+
+ blender_to_ms3d_bones = {}
+
+ self.create_animation(blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones)
+ self.create_geometry(blender_context, ms3d_model, blender_mesh_objects,
+ blender_to_ms3d_bones)
+
+
+ ###########################################################################
+ def create_geometry(self, blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones):
+ blender_scene = blender_context.scene
+
+ blender_to_ms3d_vertices = {}
+ blender_to_ms3d_triangles = {}
+ blender_to_ms3d_groups = {}
+ blender_to_ms3d_materials = {}
+
+ for blender_mesh_object in blender_mesh_objects:
+ blender_mesh = blender_mesh_object.data
+
+ ms3d_model._model_ex_object.joint_size = \
+ blender_mesh.ms3d.joint_size
+ ms3d_model._model_ex_object.alpha_ref = blender_mesh.ms3d.alpha_ref
+ ms3d_model._model_ex_object.transparency_mode = \
+ Ms3dUi.transparency_mode_to_ms3d(
+ blender_mesh.ms3d.transparency_mode)
+
+ ##########################
+ # prepare ms3d groups if available
+ # works only for exporting active object
+ ##EXPORT_ACTIVE_ONLY:
+ for ms3d_local_group_index, blender_ms3d_group in enumerate(
+ blender_mesh.ms3d.groups):
+ ms3d_group = Ms3dGroup()
+ ms3d_group.__index = len(ms3d_model._groups)
+ ms3d_group.name = blender_ms3d_group.name
+ ms3d_group.flags = Ms3dUi.flags_to_ms3d(blender_ms3d_group.flags)
+ if blender_ms3d_group.comment:
+ ms3d_group._comment_object = Ms3dCommentEx()
+ ms3d_group._comment_object.comment = \
+ blender_ms3d_group.comment
+ ms3d_group._comment_object.index = len(ms3d_model._groups)
+ ms3d_group.material_index = None # to mark as not setted
+ ms3d_model._groups.append(ms3d_group)
+ blender_to_ms3d_groups[blender_ms3d_group.id] = ms3d_group
+
+ ##########################
+ # i have to use BMesh, because there are several custom data stored.
+ # BMesh doesn't support quads_convert_to_tris()
+ # so, i use that very ugly way:
+ # create a complete copy of mesh and bend object data
+ # to be able to apply operations to it.
+
+ # temporary, create a full heavy copy of the model
+ # (object, mesh, modifiers)
+ blender_mesh_temp = blender_mesh_object.data.copy()
+ blender_mesh_object_temp = blender_mesh_object.copy()
+ blender_mesh_object_temp.data = blender_mesh_temp
+ blender_scene.objects.link(blender_mesh_object_temp)
+ blender_scene.objects.active = blender_mesh_object_temp
+
+ # apply transform
+ if self.options_apply_transform:
+ matrix_transform = blender_mesh_object_temp.matrix_local
+ else:
+ matrix_transform = Matrix()
+
+ # apply modifiers
+ for modifier in blender_mesh_object_temp.modifiers:
+ if self.options_apply_modifiers:
+ # disable only armature modifiers and only,
+ # when use_animation is enabled
+ if self.options_use_animation \
+ and modifier.type in {'ARMATURE', }:
+ modifier.show_viewport = False
+ modifier.show_render = False
+ else:
+ # disable all modifiers,
+ # to be able to add and apply triangulate modifier later
+ modifier.show_viewport = False
+ modifier.show_render = False
+
+ # convert to tris by using the triangulate modifier
+ blender_mesh_object_temp.modifiers.new("temp", 'TRIANGULATE')
+ blender_mesh_temp = blender_mesh_object_temp.to_mesh(
+ blender_scene,
+ True,
+ self.options_apply_modifiers_mode)
+
+ enable_edit_mode(True, blender_context)
+ bm = bmesh.new()
+ bm.from_mesh(blender_mesh_temp)
+
+ layer_texture = bm.faces.layers.tex.get(
+ ms3d_str['OBJECT_LAYER_TEXTURE'])
+ if layer_texture is None:
+ layer_texture = bm.faces.layers.tex.new(
+ ms3d_str['OBJECT_LAYER_TEXTURE'])
+
+ layer_smoothing_group = bm.faces.layers.int.get(
+ ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
+ if layer_smoothing_group is None:
+ layer_smoothing_group = bm.faces.layers.int.new(
+ ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
+
+ layer_group = bm.faces.layers.int.get(
+ ms3d_str['OBJECT_LAYER_GROUP'])
+ if layer_group is None:
+ layer_group = bm.faces.layers.int.new(
+ ms3d_str['OBJECT_LAYER_GROUP'])
+
+ layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV'])
+ if layer_uv is None:
+ if bm.loops.layers.uv:
+ layer_uv = bm.loops.layers.uv[0]
+ else:
+ layer_uv = bm.loops.layers.uv.new(
+ ms3d_str['OBJECT_LAYER_UV'])
+
+ layer_deform = bm.verts.layers.deform.active
+
+ layer_extra = bm.verts.layers.int.get(ms3d_str['OBJECT_LAYER_EXTRA'])
+ if layer_extra is None:
+ layer_extra = bm.verts.layers.int.new(
+ ms3d_str['OBJECT_LAYER_EXTRA'])
+
+
+ ##########################
+ # handle vertices
+ for bmv in bm.verts:
+ item = blender_to_ms3d_vertices.get(bmv)
+ if item is None:
+ index = len(ms3d_model._vertices)
+ ms3d_vertex = Ms3dVertex()
+ ms3d_vertex.__index = index
+
+ ms3d_vertex._vertex = self.geometry_correction(
+ matrix_transform * bmv.co)
+
+ if self.options_use_animation and layer_deform:
+ blender_vertex_group_ids = bmv[layer_deform]
+ if blender_vertex_group_ids:
+ count = 0
+ bone_ids = []
+ weights = []
+ for blender_index, blender_weight \
+ in blender_vertex_group_ids.items():
+ ms3d_joint = blender_to_ms3d_bones.get(
+ blender_mesh_object_temp.vertex_groups[\
+ blender_index].name)
+ if ms3d_joint:
+ if count == 0:
+ ms3d_vertex.bone_id = ms3d_joint.__index
+ weights.append(
+ int(blender_weight * 100.0))
+ elif count == 1:
+ bone_ids.append(ms3d_joint.__index)
+ weights.append(
+ int(blender_weight * 100.0))
+ elif count == 2:
+ bone_ids.append(ms3d_joint.__index)
+ weights.append(
+ int(blender_weight * 100.0))
+ elif count == 3:
+ bone_ids.append(ms3d_joint.__index)
+ self.report(
+ {'WARNING', 'INFO'},
+ ms3d_str['WARNING_EXPORT_SKIP_WEIGHT'])
+ else:
+ # only first three weights will be supported / four bones
+ self.report(
+ {'WARNING', 'INFO'},
+ ms3d_str['WARNING_EXPORT_SKIP_WEIGHT_EX'])
+ break
+ count+= 1
+
+ while len(bone_ids) < 3:
+ bone_ids.append(Ms3dSpec.DEFAULT_VERTEX_BONE_ID)
+ while len(weights) < 3:
+ weights.append(0)
+
+ # normalize weights to 100
+ if self.options_normalize_weights:
+ weight_sum = 0
+ for weight in weights:
+ weight_sum += weight
+
+ if weight_sum > 100:
+ weight_normalize = 100 / weight_sum
+ else:
+ weight_normalize = 1
+
+ weight_sum = 100
+ for index, weight in enumerate(weights):
+ if index >= count-1:
+ weights[index] = weight_sum
+ break
+ normalized_weight = int(
+ weight * weight_normalize)
+ weight_sum -= normalized_weight
+ weights[index] = normalized_weight
+
+ ms3d_vertex._vertex_ex_object._bone_ids = \
+ tuple(bone_ids)
+ ms3d_vertex._vertex_ex_object._weights = \
+ tuple(weights)
+
+ if layer_extra:
+ #ms3d_vertex._vertex_ex_object.extra = bmv[layer_extra]
+ # bm.verts.layers.int does only support signed int32
+ # convert signed int32 to unsigned int32 (little-endian)
+ signed_int32 = bmv[layer_extra]
+ bytes_int32 = signed_int32.to_bytes(
+ 4, byteorder='little', signed=True)
+ unsigned_int32 = int.from_bytes(
+ bytes_int32, byteorder='little', signed=False)
+ ms3d_vertex._vertex_ex_object.extra = unsigned_int32
+
+ ms3d_model._vertices.append(ms3d_vertex)
+ blender_to_ms3d_vertices[bmv] = ms3d_vertex
+
+ ##########################
+ # handle faces / tris
+ for bmf in bm.faces:
+ item = blender_to_ms3d_triangles.get(bmf)
+ if item is None:
+ index = len(ms3d_model._triangles)
+ ms3d_triangle = Ms3dTriangle()
+ ms3d_triangle.__index = index
+ bmv0 = bmf.verts[0]
+ bmv1 = bmf.verts[1]
+ bmv2 = bmf.verts[2]
+ ms3d_vertex0 = blender_to_ms3d_vertices[bmv0]
+ ms3d_vertex1 = blender_to_ms3d_vertices[bmv1]
+ ms3d_vertex2 = blender_to_ms3d_vertices[bmv2]
+ ms3d_vertex0.reference_count += 1
+ ms3d_vertex1.reference_count += 1
+ ms3d_vertex2.reference_count += 1
+ ms3d_triangle._vertex_indices = (
+ ms3d_vertex0.__index,
+ ms3d_vertex1.__index,
+ ms3d_vertex2.__index,
+ )
+ ms3d_triangle._vertex_normals = (
+ self.geometry_correction(bmv0.normal),
+ self.geometry_correction(bmv1.normal),
+ self.geometry_correction(bmv2.normal),
+ )
+ ms3d_triangle._s = (
+ bmf.loops[0][layer_uv].uv.x,
+ bmf.loops[1][layer_uv].uv.x,
+ bmf.loops[2][layer_uv].uv.x,
+ )
+ ms3d_triangle._t = (
+ 1.0 - bmf.loops[0][layer_uv].uv.y,
+ 1.0 - bmf.loops[1][layer_uv].uv.y,
+ 1.0 - bmf.loops[2][layer_uv].uv.y,
+ )
+
+ ms3d_triangle.smoothing_group = bmf[layer_smoothing_group]
+ ms3d_model._triangles.append(ms3d_triangle)
+
+ ms3d_material = self.get_ms3d_material_add_if(
+ blender_mesh, ms3d_model,
+ blender_to_ms3d_materials, bmf.material_index)
+ ms3d_group = blender_to_ms3d_groups.get(bmf[layer_group])
+
+ ##EXPORT_ACTIVE_ONLY:
+ if ms3d_group is not None:
+ if ms3d_material is None:
+ ms3d_group.material_index = \
+ Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX
+ else:
+ if ms3d_group.material_index is None:
+ ms3d_group.material_index = \
+ ms3d_material.__index
+ else:
+ if ms3d_group.material_index != \
+ ms3d_material.__index:
+ ms3d_group = \
+ self.get_ms3d_group_by_material_add_if(
+ ms3d_model, ms3d_material)
+ else:
+ if ms3d_material is not None:
+ ms3d_group = self.get_ms3d_group_by_material_add_if(
+ ms3d_model, ms3d_material)
+ else:
+ ms3d_group = self.get_ms3d_group_default_material_add_if(
+ ms3d_model)
+
+ if ms3d_group is not None:
+ ms3d_group._triangle_indices.append(
+ ms3d_triangle.__index)
+ ms3d_triangle.group_index = ms3d_group.__index
+
+ blender_to_ms3d_triangles[bmf] = ms3d_triangle
+
+ if bm is not None:
+ bm.free()
+
+ enable_edit_mode(False, blender_context)
+
+ ##########################
+ # remove the temporary data
+ blender_scene.objects.unlink(blender_mesh_object_temp)
+ if blender_mesh_temp is not None:
+ blender_mesh_temp.user_clear()
+ blender_context.blend_data.meshes.remove(blender_mesh_temp)
+ blender_mesh_temp = None
+ if blender_mesh_object_temp is not None:
+ blender_mesh_temp = blender_mesh_object_temp.data.user_clear()
+ blender_mesh_object_temp.user_clear()
+ blender_context.blend_data.objects.remove(
+ blender_mesh_object_temp)
+ if blender_mesh_temp is not None:
+ blender_mesh_temp.user_clear()
+ blender_context.blend_data.meshes.remove(blender_mesh_temp)
+
+
+ ###########################################################################
+ def create_animation(self, blender_context, ms3d_model,
+ blender_mesh_objects, blender_to_ms3d_bones):
+ ##########################
+ # setup scene
+ blender_scene = blender_context.scene
+
+ if not self.options_use_animation:
+ ms3d_model.animation_fps = 24
+ ms3d_model.number_total_frames = 1
+ ms3d_model.current_time = 0
+ return
+
+ frame_start = blender_scene.frame_start
+ frame_end = blender_scene.frame_end
+ frame_total = (frame_end - frame_start) + 1
+ frame_step = blender_scene.frame_step
+ frame_offset = 0
+
+ fps = blender_scene.render.fps * blender_scene.render.fps_base
+ time_base = 1.0 / fps
+
+ base_bone_correction = Matrix.Rotation(pi / 2, 4, 'Z')
+
+ for blender_mesh_object in blender_mesh_objects:
+ blender_bones = None
+ blender_action = None
+ blender_nla_tracks = None
+ for blender_modifier in blender_mesh_object.modifiers:
+ if blender_modifier.type == 'ARMATURE' \
+ and blender_modifier.object.pose:
+ blender_bones = blender_modifier.object.data.bones
+ blender_pose_bones = blender_modifier.object.pose.bones
+ if blender_modifier.object.animation_data:
+ blender_action = \
+ blender_modifier.object.animation_data.action
+ blender_nla_tracks = \
+ blender_modifier.object.animation_data.nla_tracks
+ break
+
+ if blender_bones is None \
+ and (blender_action is None and blender_nla_tracks is None):
+ continue
+
+ ##########################
+ # bones
+ blender_bones_ordered = []
+ self.build_blender_bone_dependency_order(
+ blender_bones, blender_bones_ordered)
+ for blender_bone_name in blender_bones_ordered:
+ blender_bone_oject = blender_bones[blender_bone_name]
+ ms3d_joint = Ms3dJoint()
+ ms3d_joint.__index = len(ms3d_model._joints)
+
+ blender_bone_ms3d = blender_bone_oject.ms3d
+ blender_bone = blender_bone_oject
+
+ ms3d_joint.flags = Ms3dUi.flags_to_ms3d(blender_bone_ms3d.flags)
+ if blender_bone_ms3d.comment:
+ ms3d_joint._comment_object = Ms3dCommentEx()
+ ms3d_joint._comment_object.comment = \
+ blender_bone_ms3d.comment
+ ms3d_joint._comment_object.index = ms3d_joint.__index
+
+ ms3d_joint.joint_ex_object._color = blender_bone_ms3d.color[:]
+
+ ms3d_joint.name = blender_bone.name
+
+ if blender_bone.parent:
+ ms3d_joint.parent_name = blender_bone.parent.name
+ ms3d_joint.__matrix = matrix_difference(
+ blender_bone.matrix_local,
+ blender_bone.parent.matrix_local)
+ else:
+ ms3d_joint.__matrix = base_bone_correction \
+ * blender_bone.matrix_local
+
+ mat = ms3d_joint.__matrix
+ loc = mat.to_translation()
+ rot = mat.to_euler('XZY')
+ ms3d_joint._position = self.joint_correction(loc)
+ ms3d_joint._rotation = self.joint_correction(rot)
+
+ ms3d_model._joints.append(ms3d_joint)
+ blender_to_ms3d_bones[blender_bone.name] = ms3d_joint
+
+ ##########################
+ # animation
+ frames = None
+ frames_location = set()
+ frames_rotation = set()
+ frames_scale = set()
+
+ if blender_action:
+ self.fill_keyframe_sets(
+ blender_action.fcurves,
+ frames_location, frames_rotation, frames_scale,
+ 0)
+
+ if blender_nla_tracks:
+ for nla_track in blender_nla_tracks:
+ if nla_track.mute:
+ continue
+ for strip in nla_track.strips:
+ if strip.mute:
+ continue
+ frame_correction = strip.frame_start \
+ - strip.action_frame_start
+ self.fill_keyframe_sets(
+ strip.action.fcurves,
+ frames_location, frames_rotation, frames_scale,
+ frame_correction)
+
+ frames = set(frames_location)
+ frames = frames.union(frames_rotation)
+ frames = frames.union(frames_scale)
+
+ if not self.options_shrink_to_keys:
+ frames = frames.intersection(range(
+ blender_scene.frame_start, blender_scene.frame_end + 1))
+
+ frames_sorted = list(frames)
+ frames_sorted.sort()
+
+ if self.options_shrink_to_keys and len(frames_sorted) >= 2:
+ frame_start = frames_sorted[0]
+ frame_end = frames_sorted[len(frames_sorted)-1]
+ frame_total = (frame_end - frame_start) + 1
+ frame_offset = frame_start - 1
+
+ if self.options_bake_each_frame:
+ frames_sorted = range(int(frame_start), int(frame_end + 1),
+ int(frame_step))
+
+ frame_temp = blender_scene.frame_current
+
+ for current_frame in frames_sorted:
+ blender_scene.frame_set(current_frame)
+
+ current_time = (current_frame - frame_offset) * time_base
+ for blender_bone_name in blender_bones_ordered:
+ blender_bone = blender_bones[blender_bone_name]
+ blender_pose_bone = blender_pose_bones[blender_bone_name]
+ ms3d_joint = blender_to_ms3d_bones[blender_bone_name]
+
+ m1 = blender_bone.matrix_local.inverted()
+ if blender_pose_bone.parent:
+ m2 = blender_pose_bone.parent.matrix_channel.inverted()
+ else:
+ m2 = Matrix()
+ m3 = blender_pose_bone.matrix.copy()
+ m = ((m1 * m2) * m3)
+ loc = m.to_translation()
+ rot = m.to_euler('XZY')
+
+ ms3d_joint.translation_key_frames.append(
+ Ms3dTranslationKeyframe(
+ current_time, self.joint_correction(loc)
+ )
+ )
+ ms3d_joint.rotation_key_frames.append(
+ Ms3dRotationKeyframe(
+ current_time, self.joint_correction(rot)
+ )
+ )
+
+ blender_scene.frame_set(frame_temp)
+
+ ms3d_model.animation_fps = fps
+ if ms3d_model.number_joints > 0:
+ ms3d_model.number_total_frames = int(frame_total)
+ ms3d_model.current_time = ((blender_scene.frame_current \
+ - blender_scene.frame_start) + 1) * time_base
+ else:
+ ms3d_model.number_total_frames = 1
+ ms3d_model.current_time = 0
+
+
+ ###########################################################################
+ def get_ms3d_group_default_material_add_if(self, ms3d_model):
+ markerName = "MaterialGroupDefault"
+ markerComment = "group without material"
+
+ for ms3d_group in ms3d_model._groups:
+ if ms3d_group.material_index == \
+ Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX \
+ and ms3d_group.name == markerName \
+ and ms3d_group._comment_object \
+ and ms3d_group._comment_object.comment == markerComment:
+ return ms3d_group
+
+ ms3d_group = Ms3dGroup()
+ ms3d_group.__index = len(ms3d_model._groups)
+ ms3d_group.name = markerName
+ ms3d_group._comment_object = Ms3dCommentEx()
+ ms3d_group._comment_object.comment = markerComment
+ ms3d_group._comment_object.index = len(ms3d_model._groups)
+ ms3d_group.material_index = Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX
+
+ ms3d_model._groups.append(ms3d_group)
+
+ return ms3d_group
+
+
+ ###########################################################################
+ def get_ms3d_group_by_material_add_if(self, ms3d_model, ms3d_material):
+ if ms3d_material.__index < 0 \
+ or ms3d_material.__index >= len(ms3d_model.materials):
+ return None
+
+ markerName = "MaterialGroup.{}".format(ms3d_material.__index)
+ markerComment = "MaterialGroup({})".format(ms3d_material.name)
+
+ for ms3d_group in ms3d_model._groups:
+ if ms3d_group.name == markerName \
+ and ms3d_group._comment_object \
+ and ms3d_group._comment_object.comment == markerComment:
+ return ms3d_group
+
+ ms3d_group = Ms3dGroup()
+ ms3d_group.__index = len(ms3d_model._groups)
+ ms3d_group.name = markerName
+ ms3d_group._comment_object = Ms3dCommentEx()
+ ms3d_group._comment_object.comment = markerComment
+ ms3d_group._comment_object.index = len(ms3d_model._groups)
+ ms3d_group.material_index = ms3d_material.__index
+
+ ms3d_model._groups.append(ms3d_group)
+
+ return ms3d_group
+
+
+ ###########################################################################
+ def get_ms3d_material_add_if(self, blender_mesh, ms3d_model,
+ blender_to_ms3d_materials, blender_index):
+ if blender_index < 0 or blender_index >= len(blender_mesh.materials):
+ return None
+
+ blender_material = blender_mesh.materials[blender_index]
+ ms3d_material = blender_to_ms3d_materials.get(blender_material)
+ if ms3d_material is None:
+ ms3d_material = Ms3dMaterial()
+ ms3d_material.__index = len(ms3d_model.materials)
+
+ blender_ms3d_material = blender_material.ms3d
+
+ if not self.options_use_blender_names \
+ and not self.options_use_blender_materials \
+ and blender_ms3d_material.name:
+ ms3d_material.name = blender_ms3d_material.name
+ else:
+ ms3d_material.name = blender_material.name
+
+ temp_material = None
+ if self.options_use_blender_materials:
+ temp_material = Ms3dMaterial()
+ Ms3dMaterialHelper.copy_from_blender(
+ None, None, temp_material, blender_material)
+ else:
+ temp_material = blender_ms3d_material
+
+ ms3d_material._ambient = temp_material.ambient[:]
+ ms3d_material._diffuse = temp_material.diffuse[:]
+ ms3d_material._specular = temp_material.specular[:]
+ ms3d_material._emissive = temp_material.emissive[:]
+ ms3d_material.shininess = temp_material.shininess
+ ms3d_material.transparency = temp_material.transparency
+ ms3d_material.texture = temp_material.texture
+ ms3d_material.alphamap = temp_material.alphamap
+
+ ms3d_material.mode = Ms3dUi.texture_mode_to_ms3d(
+ blender_ms3d_material.mode)
+ if blender_ms3d_material.comment:
+ ms3d_material._comment_object = Ms3dCommentEx()
+ ms3d_material._comment_object.comment = \
+ blender_ms3d_material.comment
+ ms3d_material._comment_object.index = ms3d_material.__index
+
+ ms3d_model.materials.append(ms3d_material)
+
+ blender_to_ms3d_materials[blender_material] = ms3d_material
+
+ return ms3d_material
+
+
+ ###########################################################################
+ def geometry_correction(self, value):
+ return (value[1], value[2], value[0])
+
+
+ ###########################################################################
+ def joint_correction(self, value):
+ return (-value[0], value[2], value[1])
+
+
+ ###########################################################################
+ def build_blender_bone_dependency_order(self, blender_bones,
+ blender_bones_ordered):
+ if not blender_bones:
+ return blender_bones_ordered
+
+ blender_bones_children = {None: []}
+ for blender_bone in blender_bones:
+ if blender_bone.parent:
+ blender_bone_children = blender_bones_children.get(
+ blender_bone.parent.name)
+ if blender_bone_children is None:
+ blender_bone_children = blender_bones_children[
+ blender_bone.parent.name] = []
+ else:
+ blender_bone_children = blender_bones_children[None]
+
+ blender_bone_children.append(blender_bone.name)
+
+ self.traverse_dependencies(
+ blender_bones_ordered,
+ blender_bones_children,
+ None)
+
+ return blender_bones_ordered
+
+
+ ###########################################################################
+ def traverse_dependencies(self, blender_bones_ordered,
+ blender_bones_children, key):
+ blender_bone_children = blender_bones_children.get(key)
+ if blender_bone_children:
+ for blender_bone_name in blender_bone_children:
+ blender_bones_ordered.append(blender_bone_name)
+ self.traverse_dependencies(
+ blender_bones_ordered,
+ blender_bones_children,
+ blender_bone_name)
+
+ ###########################################################################
+ def fill_keyframe_sets(self,
+ fcurves,
+ frames_location, frames_rotation, frames_scale,
+ frame_correction):
+ for fcurve in fcurves:
+ if fcurve.data_path.endswith(".location"):
+ frames = frames_location
+ elif fcurve.data_path.endswith(".rotation_euler"):
+ frames = frames_rotation
+ elif fcurve.data_path.endswith(".rotation_quaternion"):
+ frames = frames_rotation
+ elif fcurve.data_path.endswith(".scale"):
+ frames = frames_scale
+ else:
+ pass
+
+ for keyframe_point in fcurve.keyframe_points:
+ frames.add(int(keyframe_point.co[0] + frame_correction))
+
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+# ##### END OF FILE #####
diff --git a/io_scene_ms3d/ms3d_import.py b/io_scene_ms3d/ms3d_import.py
new file mode 100644
index 00000000..f4767f11
--- /dev/null
+++ b/io_scene_ms3d/ms3d_import.py
@@ -0,0 +1,1005 @@
+# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+
+
+# ##### BEGIN COPYRIGHT BLOCK #####
+#
+# initial script copyright (c)2011,2012 Alexander Nussbaumer
+#
+# ##### END COPYRIGHT BLOCK #####
+
+
+#import python stuff
+import io
+from mathutils import (
+ Vector,
+ Matrix,
+ )
+from os import (
+ path,
+ )
+from sys import (
+ exc_info,
+ )
+from time import (
+ time,
+ )
+
+
+# import io_scene_ms3d stuff
+from io_scene_ms3d.ms3d_strings import (
+ ms3d_str,
+ )
+from io_scene_ms3d.ms3d_spec import (
+ Ms3dSpec,
+ Ms3dModel,
+ Ms3dVertexEx2,
+ Ms3dVertexEx3,
+ )
+from io_scene_ms3d.ms3d_utils import (
+ select_all,
+ enable_pose_mode,
+ enable_edit_mode,
+ pre_setup_environment,
+ post_setup_environment,
+ get_edge_split_modifier_add_if,
+ )
+from io_scene_ms3d.ms3d_ui import (
+ Ms3dUi,
+ )
+
+
+#import blender stuff
+from bpy import (
+ ops,
+ )
+import bmesh
+from bpy_extras.image_utils import (
+ load_image,
+ )
+
+
+###############################################################################
+class Ms3dImporter():
+ """
+ Load a MilkShape3D MS3D File
+ """
+ def __init__(self,
+ report,
+ verbose=False,
+ use_extended_normal_handling=False,
+ use_animation=True,
+ use_quaternion_rotation=False,
+ use_joint_size=False,
+ joint_size=1.0,
+ use_joint_to_bones=False,
+ ):
+ self.report = report
+ self.options_verbose = verbose
+ self.options_use_extended_normal_handling = use_extended_normal_handling
+ self.options_use_animation = use_animation
+ self.options_use_quaternion_rotation = use_quaternion_rotation
+ self.options_use_joint_size = use_joint_size
+ self.options_joint_size = joint_size
+ self.options_use_joint_to_bones = use_joint_to_bones
+ pass
+
+ ###########################################################################
+ # create empty blender ms3d_model
+ # read ms3d file
+ # fill blender with ms3d_model content
+ """ read ms3d file and convert ms3d content to bender content """
+ def read(self, blender_context, filepath):
+
+ t1 = time()
+ t2 = None
+ self.has_textures = False
+
+ try:
+ # setup environment
+ pre_setup_environment(self, blender_context)
+
+ # inject splitted filepath
+ self.directory_name, self.file_name = path.split(filepath)
+
+ # create an empty ms3d template
+ ms3d_model = Ms3dModel(self.file_name)
+
+ try:
+ # open ms3d file
+ with io.FileIO(filepath, 'rb') as raw_io:
+ # read and inject ms3d data from disk to internal structure
+ ms3d_model.read(raw_io)
+ raw_io.close()
+ finally:
+ pass
+
+ # if option is set, this time will enlargs the io time
+ if self.options_verbose:
+ ms3d_model.print_internal()
+
+ t2 = time()
+
+ is_valid, statistics = ms3d_model.is_valid()
+
+ if is_valid:
+ # inject ms3d data to blender
+ self.to_blender(blender_context, ms3d_model)
+
+ blender_scene = blender_context.scene
+
+ # finalize/restore environment
+ blender_scene.update()
+
+ post_setup_environment(self, blender_context)
+
+ print()
+ print("##########################################################")
+ print("Import from MS3D to Blender")
+ print(statistics)
+ print("##########################################################")
+
+ except Exception:
+ type, value, traceback = exc_info()
+ print("read - exception in try block\n type: '{0}'\n"
+ " value: '{1}'".format(type, value, traceback))
+
+ if t2 is None:
+ t2 = time()
+
+ raise
+
+ else:
+ pass
+
+ t3 = time()
+ print(ms3d_str['SUMMARY_IMPORT'].format(
+ (t3 - t1), (t2 - t1), (t3 - t2)))
+
+ return {"FINISHED"}
+
+
+ def internal_read(self, blender_context, raw_io):
+ try:
+ # setup environment
+ pre_setup_environment(self, blender_context)
+
+ try:
+ ms3d_model.read(raw_io)
+ finally:
+ pass
+
+ # if option is set, this time will enlargs the io time
+ if self.options_verbose:
+ ms3d_model.print_internal()
+
+ is_valid, statistics = ms3d_model.is_valid()
+
+ if is_valid:
+ # inject ms3d data to blender
+ blender_empty_object, blender_mesh_object = self.to_blender(blender_context, ms3d_model)
+
+ blender_scene = blender_context.scene
+
+ # finalize/restore environment
+ blender_scene.update()
+
+ post_setup_environment(self, blender_context)
+
+ except Exception:
+ type, value, traceback = exc_info()
+ print("read - exception in try block\n type: '{0}'\n"
+ " value: '{1}'".format(type, value, traceback))
+
+ raise
+
+ else:
+ pass
+
+ return blender_empty_object, blender_mesh_object
+
+
+ ###########################################################################
+ def to_blender(self, blender_context, ms3d_model):
+ blender_mesh_object = self.create_geometry(blender_context, ms3d_model)
+ blender_armature_object = self.create_animation(
+ blender_context, ms3d_model, blender_mesh_object)
+
+ blender_empty_object = self.organize_objects(
+ blender_context, ms3d_model,
+ [blender_mesh_object, blender_armature_object])
+
+ return blender_empty_object, blender_mesh_object
+
+
+ ###########################################################################
+ def organize_objects(self, blender_context, ms3d_model, blender_objects):
+ ##########################
+ # blender_armature_object to blender_mesh_object
+ # that has bad side effects to the armature
+ # and causes cyclic dependecies
+ ###blender_armature_object.parent = blender_mesh_object
+ ###blender_mesh_object.parent = blender_armature_object
+
+ blender_scene = blender_context.scene
+
+ blender_group = blender_context.blend_data.groups.new(
+ "{}.g".format(ms3d_model.name))
+ blender_empty_object = blender_context.blend_data.objects.new(
+ "{}.e".format(ms3d_model.name), None)
+ blender_empty_object.location = blender_scene.cursor_location
+ blender_scene.objects.link(blender_empty_object)
+ blender_group.objects.link(blender_empty_object)
+
+ for blender_object in blender_objects:
+ if blender_object is not None:
+ blender_group.objects.link(blender_object)
+ blender_object.parent = blender_empty_object
+
+ return blender_empty_object
+
+
+ ###########################################################################
+ def create_geometry(self, blender_context, ms3d_model):
+ ##########################
+ # blender stuff:
+ # create a blender Mesh
+ blender_mesh = blender_context.blend_data.meshes.new(
+ "{}.m".format(ms3d_model.name))
+ blender_mesh.ms3d.name = ms3d_model.name
+
+ ms3d_comment = ms3d_model.comment_object
+ if ms3d_comment is not None:
+ blender_mesh.ms3d.comment = ms3d_comment.comment
+ ms3d_model_ex = ms3d_model.model_ex_object
+ if ms3d_model_ex is not None:
+ blender_mesh.ms3d.joint_size = ms3d_model_ex.joint_size
+ blender_mesh.ms3d.alpha_ref = ms3d_model_ex.alpha_ref
+ blender_mesh.ms3d.transparency_mode \
+ = Ms3dUi.transparency_mode_from_ms3d(
+ ms3d_model_ex.transparency_mode)
+
+ ##########################
+ # blender stuff:
+ # link to blender object
+ blender_mesh_object = blender_context.blend_data.objects.new(
+ "{}.m".format(ms3d_model.name), blender_mesh)
+
+ ##########################
+ # blender stuff:
+ # create edge split modifire, to make sharp edges visible
+ blender_modifier = get_edge_split_modifier_add_if(blender_mesh_object)
+
+ ##########################
+ # blender stuff:
+ # link to blender scene
+ blender_scene = blender_context.scene
+ blender_scene.objects.link(blender_mesh_object)
+ #blender_mesh_object.location = blender_scene.cursor_location
+ enable_edit_mode(False, blender_context)
+ select_all(False)
+ blender_mesh_object.select = True
+ blender_scene.objects.active = blender_mesh_object
+
+ ##########################
+ # take this as active object after import
+ self.active_object = blender_mesh_object
+
+ ##########################
+ # blender stuff:
+ # create all (ms3d) groups
+ ms3d_to_blender_group_index = {}
+ blender_group_manager = blender_mesh.ms3d
+ for ms3d_group_index, ms3d_group in enumerate(ms3d_model.groups):
+ blender_group = blender_group_manager.create_group()
+ blender_group.name = ms3d_group.name
+ blender_group.flags = Ms3dUi.flags_from_ms3d(ms3d_group.flags)
+ blender_group.material_index = ms3d_group.material_index
+
+ ms3d_comment = ms3d_group.comment_object
+ if ms3d_comment is not None:
+ blender_group.comment = ms3d_comment.comment
+
+ # translation dictionary
+ ms3d_to_blender_group_index[ms3d_group_index] = blender_group.id
+
+ ####################################################
+ # begin BMesh stuff
+ #
+
+ ##########################
+ # BMesh stuff:
+ # create an empty BMesh
+ bm = bmesh.new()
+
+ ##########################
+ # BMesh stuff:
+ # create new Layers for custom data per "mesh face"
+ layer_texture = bm.faces.layers.tex.get(
+ ms3d_str['OBJECT_LAYER_TEXTURE'])
+ if layer_texture is None:
+ layer_texture = bm.faces.layers.tex.new(
+ ms3d_str['OBJECT_LAYER_TEXTURE'])
+
+ layer_smoothing_group = bm.faces.layers.int.get(
+ ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
+ if layer_smoothing_group is None:
+ layer_smoothing_group = bm.faces.layers.int.new(
+ ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
+
+ layer_group = bm.faces.layers.int.get(
+ ms3d_str['OBJECT_LAYER_GROUP'])
+ if layer_group is None:
+ layer_group = bm.faces.layers.int.new(
+ ms3d_str['OBJECT_LAYER_GROUP'])
+
+ ##########################
+ # BMesh stuff:
+ # create new Layers for custom data per "face vertex"
+ layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV'])
+ if layer_uv is None:
+ layer_uv = bm.loops.layers.uv.new(ms3d_str['OBJECT_LAYER_UV'])
+
+ ##########################
+ # BMesh stuff:
+ # create new Layers for custom data per "vertex"
+ layer_extra = bm.verts.layers.int.get(ms3d_str['OBJECT_LAYER_EXTRA'])
+ if layer_extra is None:
+ layer_extra = bm.verts.layers.int.new(ms3d_str['OBJECT_LAYER_EXTRA'])
+
+ ##########################
+ # BMesh stuff:
+ # create all vertices
+ for ms3d_vertex_index, ms3d_vertex in enumerate(ms3d_model.vertices):
+ bmv = bm.verts.new(self.geometry_correction(ms3d_vertex.vertex))
+
+ if layer_extra and ms3d_vertex.vertex_ex_object and \
+ (isinstance(ms3d_vertex.vertex_ex_object, Ms3dVertexEx2) \
+ or isinstance(ms3d_vertex.vertex_ex_object, Ms3dVertexEx3)):
+
+ #bmv[layer_extra] = ms3d_vertex.vertex_ex_object.extra
+ # bm.verts.layers.int does only support signed int32
+ # convert unsigned int32 to signed int32 (little-endian)
+ unsigned_int32 = ms3d_vertex.vertex_ex_object.extra
+ bytes_int32 = unsigned_int32.to_bytes(
+ 4, byteorder='little', signed=False)
+ signed_int32 = int.from_bytes(
+ bytes_int32, byteorder='little', signed=True)
+ bmv[layer_extra] = signed_int32
+
+ ##########################
+ # blender stuff (uses BMesh stuff):
+ # create all materials / image textures
+ ms3d_to_blender_material = {}
+ for ms3d_material_index, ms3d_material in enumerate(
+ ms3d_model.materials):
+ blender_material = blender_context.blend_data.materials.new(
+ ms3d_material.name)
+
+ # custom datas
+ blender_material.ms3d.name = ms3d_material.name
+ blender_material.ms3d.ambient = ms3d_material.ambient
+ blender_material.ms3d.diffuse = ms3d_material.diffuse
+ blender_material.ms3d.specular = ms3d_material.specular
+ blender_material.ms3d.emissive = ms3d_material.emissive
+ blender_material.ms3d.shininess = ms3d_material.shininess
+ blender_material.ms3d.transparency = ms3d_material.transparency
+ blender_material.ms3d.mode = Ms3dUi.texture_mode_from_ms3d(
+ ms3d_material.mode)
+
+ if ms3d_material.texture:
+ blender_material.ms3d.texture = ms3d_material.texture
+
+ if ms3d_material.alphamap:
+ blender_material.ms3d.alphamap = ms3d_material.alphamap
+
+ ms3d_comment = ms3d_material.comment_object
+ if ms3d_comment is not None:
+ blender_material.ms3d.comment = ms3d_comment.comment
+
+ # blender datas
+ blender_material.ambient = (
+ (ms3d_material.ambient[0]
+ + ms3d_material.ambient[1]
+ + ms3d_material.ambient[2]) / 3.0)
+
+ blender_material.diffuse_color[0] = ms3d_material.diffuse[0]
+ blender_material.diffuse_color[1] = ms3d_material.diffuse[1]
+ blender_material.diffuse_color[2] = ms3d_material.diffuse[2]
+
+ blender_material.specular_color[0] = ms3d_material.specular[0]
+ blender_material.specular_color[1] = ms3d_material.specular[1]
+ blender_material.specular_color[2] = ms3d_material.specular[2]
+
+ blender_material.emit = (
+ (ms3d_material.emissive[0]
+ + ms3d_material.emissive[1]
+ + ms3d_material.emissive[2]) / 3.0)
+
+ blender_material.specular_hardness = ms3d_material.shininess * 4.0
+ blender_material.alpha = 1.0 - ms3d_material.transparency
+
+ # diffuse texture
+ if ms3d_material.texture:
+ dir_name_diffuse = self.directory_name
+ file_name_diffuse = path.split(ms3d_material.texture)[1]
+ blender_image_diffuse = load_image(
+ file_name_diffuse, dir_name_diffuse)
+ blender_texture_diffuse = \
+ blender_context.blend_data.textures.new(
+ name=file_name_diffuse, type='IMAGE')
+ blender_texture_diffuse.image = blender_image_diffuse
+ blender_texture_slot_diffuse \
+ = blender_material.texture_slots.add()
+ blender_texture_slot_diffuse.texture = blender_texture_diffuse
+ blender_texture_slot_diffuse.texture_coords = 'UV'
+ blender_texture_slot_diffuse.uv_layer = layer_uv.name
+ blender_texture_slot_diffuse.use_map_color_diffuse = True
+ blender_texture_slot_diffuse.use_map_alpha = False
+ if blender_image_diffuse is not None:
+ self.has_textures = True
+ else:
+ blender_image_diffuse = None
+
+ # alpha texture
+ if ms3d_material.alphamap:
+ dir_name_alpha = self.directory_name
+ file_name_alpha = path.split(ms3d_material.alphamap)[1]
+ blender_image_alpha = load_image(
+ file_name_alpha, dir_name_alpha)
+ blender_texture_alpha = blender_context.blend_data.textures.new(
+ name=file_name_alpha, type='IMAGE')
+ blender_texture_alpha.image = blender_image_alpha
+ blender_texture_slot_alpha \
+ = blender_material.texture_slots.add()
+ blender_texture_slot_alpha.texture = blender_texture_alpha
+ blender_texture_slot_alpha.texture_coords = 'UV'
+ blender_texture_slot_alpha.uv_layer = layer_uv.name
+ blender_texture_slot_alpha.use_map_color_diffuse = False
+ blender_texture_slot_alpha.use_map_alpha = True
+ blender_texture_slot_alpha.use_rgb_to_intensity = True
+ blender_material.alpha = 0
+ blender_material.specular_alpha = 0
+
+ # append blender material to blender mesh, to be linked to
+ blender_mesh.materials.append(blender_material)
+
+ # translation dictionary
+ ms3d_to_blender_material[ms3d_material_index] \
+ = blender_image_diffuse
+
+ ##########################
+ # BMesh stuff:
+ # create all triangles
+ length_verts = len(bm.verts)
+ vertex_extra_index = length_verts
+ blender_invalide_normal = Vector()
+ smoothing_group_blender_faces = {}
+ for ms3d_triangle_index, ms3d_triangle in enumerate(
+ ms3d_model.triangles):
+ bmv_list = []
+ bmf_normal = Vector()
+
+ for index, vert_index in enumerate(ms3d_triangle.vertex_indices):
+ if vert_index < 0 or vert_index >= length_verts:
+ continue
+ bmv = bm.verts[vert_index]
+
+ blender_normal = self.geometry_correction(
+ ms3d_triangle.vertex_normals[index])
+ if bmv.normal == blender_invalide_normal:
+ bmv.normal = blender_normal
+ elif bmv.normal != blender_normal \
+ and self.options_use_extended_normal_handling:
+ ## search for an already created extra vertex
+ bmv_new = None
+ for vert_index_candidat in range(
+ vertex_extra_index, length_verts):
+ bmv_candidat = bm.verts[vert_index_candidat]
+ if bmv_candidat.co == bmv.co \
+ and bmv_candidat.normal == blender_normal:
+ bmv_new = bmv_candidat
+ vert_index = vert_index_candidat
+ break
+
+ ## if not exists, create one in blender and ms3d as well
+ if bmv_new is None:
+ ms3d_model.vertices.append(
+ ms3d_model.vertices[vert_index])
+ bmv_new = bm.verts.new(bmv.co)
+ bmv_new.normal = blender_normal
+ bmv_new[layer_extra] = bmv[layer_extra]
+ vert_index = length_verts
+ length_verts += 1
+ self.report({'WARNING', 'INFO'},
+ ms3d_str['WARNING_IMPORT_EXTRA_VERTEX_NORMAL'].format(
+ bmv.normal, blender_normal))
+ bmv = bmv_new
+
+ if [[x] for x in bmv_list if x == bmv]:
+ self.report(
+ {'WARNING', 'INFO'},
+ ms3d_str['WARNING_IMPORT_SKIP_VERTEX_DOUBLE'].format(
+ ms3d_triangle_index))
+ continue
+ bmv_list.append(bmv)
+ bmf_normal += bmv.normal
+
+ if len(bmv_list) < 3:
+ self.report(
+ {'WARNING', 'INFO'},
+ ms3d_str['WARNING_IMPORT_SKIP_LESS_VERTICES'].format(
+ ms3d_triangle_index))
+ continue
+
+ bmf_normal.normalize()
+
+ bmf = bm.faces.get(bmv_list)
+ if bmf is not None:
+ self.report(
+ {'WARNING', 'INFO'},
+ ms3d_str['WARNING_IMPORT_SKIP_FACE_DOUBLE'].format(
+ ms3d_triangle_index))
+ continue
+
+ bmf = bm.faces.new(bmv_list)
+ bmf.normal = bmf_normal
+
+ # blender uv custom data per "face vertex"
+ bmf.loops[0][layer_uv].uv = Vector(
+ (ms3d_triangle.s[0], 1.0 - ms3d_triangle.t[0]))
+ bmf.loops[1][layer_uv].uv = Vector(
+ (ms3d_triangle.s[1], 1.0 - ms3d_triangle.t[1]))
+ bmf.loops[2][layer_uv].uv = Vector(
+ (ms3d_triangle.s[2], 1.0 - ms3d_triangle.t[2]))
+
+ # ms3d custom data per "mesh face"
+ bmf[layer_smoothing_group] = ms3d_triangle.smoothing_group
+
+ blender_group_id = ms3d_to_blender_group_index.get(
+ ms3d_triangle.group_index)
+ if blender_group_id is not None:
+ bmf[layer_group] = blender_group_id
+
+ if ms3d_triangle.group_index >= 0 \
+ and ms3d_triangle.group_index < len(ms3d_model.groups):
+ ms3d_material_index \
+ = ms3d_model.groups[ms3d_triangle.group_index].material_index
+ if ms3d_material_index != Ms3dSpec.NONE_GROUP_MATERIAL_INDEX:
+ bmf.material_index = ms3d_material_index
+ # apply diffuse texture image to face, to be visible in 3d view
+ bmf[layer_texture].image = ms3d_to_blender_material.get(
+ ms3d_material_index)
+
+ # helper dictionary for post-processing smoothing_groups
+ smoothing_group_blender_face = smoothing_group_blender_faces.get(
+ ms3d_triangle.smoothing_group)
+ if smoothing_group_blender_face is None:
+ smoothing_group_blender_face = []
+ smoothing_group_blender_faces[ms3d_triangle.smoothing_group] \
+ = smoothing_group_blender_face
+ smoothing_group_blender_face.append(bmf)
+
+ ##########################
+ # BMesh stuff:
+ # create all sharp edges for blender to make smoothing_groups visible
+ for ms3d_smoothing_group_index, blender_face_list \
+ in smoothing_group_blender_faces.items():
+ edge_dict = {}
+ for bmf in blender_face_list:
+ bmf.smooth = True
+ for bme in bmf.edges:
+ if edge_dict.get(bme) is None:
+ edge_dict[bme] = 0
+ else:
+ edge_dict[bme] += 1
+ bme.seam = (edge_dict[bme] == 0)
+ bme.smooth = (edge_dict[bme] != 0)
+
+ ##########################
+ # BMesh stuff:
+ # finally tranfer BMesh to Mesh
+ bm.to_mesh(blender_mesh)
+ bm.free()
+
+
+ #
+ # end BMesh stuff
+ ####################################################
+
+ blender_mesh.validate(self.options_verbose)
+
+ return blender_mesh_object
+
+
+ ###########################################################################
+ def create_animation(self, blender_context, ms3d_model, blender_mesh_object):
+ ##########################
+ # setup scene
+ blender_scene = blender_context.scene
+ blender_scene.render.fps = ms3d_model.animation_fps
+ if ms3d_model.animation_fps:
+ blender_scene.render.fps_base = (blender_scene.render.fps /
+ ms3d_model.animation_fps)
+
+ blender_scene.frame_start = 1
+ blender_scene.frame_end = (ms3d_model.number_total_frames
+ + blender_scene.frame_start) - 1
+ blender_scene.frame_current = (ms3d_model.current_time
+ * ms3d_model.animation_fps)
+
+ ##########################
+ if not ms3d_model.joints:
+ return
+
+ ##########################
+ ms3d_armature_name = "{}.a".format(ms3d_model.name)
+ ms3d_action_name = "{}.act".format(ms3d_model.name)
+
+ ##########################
+ # create new blender_armature_object
+ blender_armature = blender_context.blend_data.armatures.new(
+ ms3d_armature_name)
+ blender_armature.ms3d.name = ms3d_model.name
+ blender_armature.draw_type = 'STICK'
+ blender_armature.show_axes = True
+ blender_armature.use_auto_ik = True
+ blender_armature_object = blender_context.blend_data.objects.new(
+ ms3d_armature_name, blender_armature)
+ blender_scene.objects.link(blender_armature_object)
+ #blender_armature_object.location = blender_scene.cursor_location
+ blender_armature_object.show_x_ray = True
+
+ ##########################
+ # create new modifier
+ blender_modifier = blender_mesh_object.modifiers.new(
+ ms3d_armature_name, type='ARMATURE')
+ blender_modifier.show_expanded = False
+ blender_modifier.use_vertex_groups = True
+ blender_modifier.use_bone_envelopes = False
+ blender_modifier.object = blender_armature_object
+
+ ##########################
+ # prepare for vertex groups
+ ms3d_to_blender_vertex_groups = {}
+ for ms3d_vertex_index, ms3d_vertex in enumerate(ms3d_model.vertices):
+ # prepare for later use for blender vertex group
+ if ms3d_vertex.bone_id != Ms3dSpec.NONE_VERTEX_BONE_ID:
+ if ms3d_vertex.vertex_ex_object \
+ and ( \
+ ms3d_vertex.vertex_ex_object.bone_ids[0] != \
+ Ms3dSpec.NONE_VERTEX_BONE_ID \
+ or ms3d_vertex.vertex_ex_object.bone_ids[1] != \
+ Ms3dSpec.NONE_VERTEX_BONE_ID \
+ or ms3d_vertex.vertex_ex_object.bone_ids[2] != \
+ Ms3dSpec.NONE_VERTEX_BONE_ID \
+ ):
+ ms3d_vertex_group_ids_weights = []
+ ms3d_vertex_group_ids_weights.append(
+ (ms3d_vertex.bone_id,
+ float(ms3d_vertex.vertex_ex_object.weights[0] % 101) / 100.0,
+ ))
+ if ms3d_vertex.vertex_ex_object.bone_ids[0] != \
+ Ms3dSpec.NONE_VERTEX_BONE_ID:
+ ms3d_vertex_group_ids_weights.append(
+ (ms3d_vertex.vertex_ex_object.bone_ids[0],
+ float(ms3d_vertex.vertex_ex_object.weights[1] % 101) / 100.0
+ ))
+ if ms3d_vertex.vertex_ex_object.bone_ids[1] != \
+ Ms3dSpec.NONE_VERTEX_BONE_ID:
+ ms3d_vertex_group_ids_weights.append(
+ (ms3d_vertex.vertex_ex_object.bone_ids[1],
+ float(ms3d_vertex.vertex_ex_object.weights[2] % 101) / 100.0
+ ))
+ if ms3d_vertex.vertex_ex_object.bone_ids[2] != \
+ Ms3dSpec.NONE_VERTEX_BONE_ID:
+ ms3d_vertex_group_ids_weights.append(
+ (ms3d_vertex.vertex_ex_object.bone_ids[2],
+ 1.0 -
+ float((ms3d_vertex.vertex_ex_object.weights[0] % 101)
+ + (ms3d_vertex.vertex_ex_object.weights[1] % 101)
+ + (ms3d_vertex.vertex_ex_object.weights[2] % 101)) / 100.0
+ ))
+
+ else:
+ ms3d_vertex_group_ids_weights = [(ms3d_vertex.bone_id, 1.0), ]
+
+ for ms3d_vertex_group_id_weight in ms3d_vertex_group_ids_weights:
+ ms3d_vertex_group_id = ms3d_vertex_group_id_weight[0]
+ blender_vertex_weight = ms3d_vertex_group_id_weight[1]
+ blender_vertex_group = ms3d_to_blender_vertex_groups.get(
+ ms3d_vertex_group_id)
+ if blender_vertex_group is None:
+ ms3d_to_blender_vertex_groups[ms3d_vertex_group_id] \
+ = blender_vertex_group = []
+ blender_vertex_group.append((ms3d_vertex_index,
+ blender_vertex_weight))
+
+ ##########################
+ # blender stuff:
+ # create all vertex groups to be used for bones
+ for ms3d_bone_id, blender_vertex_index_weight_list \
+ in ms3d_to_blender_vertex_groups.items():
+ ms3d_name = ms3d_model.joints[ms3d_bone_id].name
+ blender_vertex_group = blender_mesh_object.vertex_groups.new(
+ ms3d_name)
+ for blender_vertex_id_weight in blender_vertex_index_weight_list:
+ blender_vertex_index = blender_vertex_id_weight[0]
+ blender_vertex_weight = blender_vertex_id_weight[1]
+ blender_vertex_group.add((blender_vertex_index, ),
+ blender_vertex_weight, 'ADD')
+
+ ##########################
+ # bring joints in the correct order
+ ms3d_joints_ordered = []
+ self.build_ms3d_joint_dependency_order(ms3d_model.joints,
+ ms3d_joints_ordered)
+
+ ##########################
+ # prepare joint data for later use
+ ms3d_joint_by_name = {}
+ for ms3d_joint in ms3d_joints_ordered:
+ item = ms3d_joint_by_name.get(ms3d_joint.name)
+ if item is None:
+ ms3d_joint.__children = []
+ ms3d_joint_by_name[ms3d_joint.name] = ms3d_joint
+
+ matrix_local_rot = (Matrix.Rotation(ms3d_joint.rotation[2], 4, 'Z')
+ * Matrix.Rotation(ms3d_joint.rotation[1], 4, 'Y')
+ ) * Matrix.Rotation(ms3d_joint.rotation[0], 4, 'X')
+ matrix_local = Matrix.Translation(Vector(ms3d_joint.position)
+ ) * matrix_local_rot
+
+ ms3d_joint.__matrix_local_rot = matrix_local_rot
+ ms3d_joint.__matrix_global_rot = matrix_local_rot
+ ms3d_joint.__matrix_local = matrix_local
+ ms3d_joint.__matrix_global = matrix_local
+
+ if ms3d_joint.parent_name:
+ ms3d_joint_parent = ms3d_joint_by_name.get(
+ ms3d_joint.parent_name)
+ if ms3d_joint_parent is not None:
+ ms3d_joint_parent.__children.append(ms3d_joint)
+
+ matrix_global = ms3d_joint_parent.__matrix_global \
+ * matrix_local
+ ms3d_joint.__matrix_global = matrix_global
+
+ matrix_global_rot = ms3d_joint_parent.__matrix_global_rot \
+ * matrix_local_rot
+ ms3d_joint.__matrix_global_rot = matrix_global_rot
+
+ ##########################
+ # ms3d_joint to blender_edit_bone
+ if ms3d_model.model_ex_object and not self.options_use_joint_size:
+ joint_length = ms3d_model.model_ex_object.joint_size
+ else:
+ joint_length = self.options_joint_size
+ if joint_length < 0.01:
+ joint_length = 0.01
+
+ blender_scene.objects.active = blender_armature_object
+ enable_edit_mode(True, blender_context)
+ for ms3d_joint in ms3d_joints_ordered:
+ blender_edit_bone = blender_armature.edit_bones.new(ms3d_joint.name)
+ blender_edit_bone.use_connect = False
+ blender_edit_bone.use_inherit_rotation = True
+ blender_edit_bone.use_inherit_scale = True
+ blender_edit_bone.use_local_location = True
+ blender_armature.edit_bones.active = blender_edit_bone
+
+ ms3d_joint = ms3d_joint_by_name[ms3d_joint.name]
+ ms3d_joint_vector = ms3d_joint.__matrix_global * Vector()
+
+ blender_edit_bone.head \
+ = self.geometry_correction(ms3d_joint_vector)
+
+ vector_tail_end_up = ms3d_joint.__matrix_global_rot * Vector((0,1,0))
+ vector_tail_end_dir = ms3d_joint.__matrix_global_rot * Vector((0,0,1))
+ vector_tail_end_up.normalize()
+ vector_tail_end_dir.normalize()
+ blender_edit_bone.tail = blender_edit_bone.head \
+ + self.geometry_correction(
+ vector_tail_end_dir * joint_length)
+ blender_edit_bone.align_roll(self.geometry_correction(
+ vector_tail_end_up))
+
+ if ms3d_joint.parent_name:
+ ms3d_joint_parent = ms3d_joint_by_name[ms3d_joint.parent_name]
+ blender_edit_bone_parent = ms3d_joint_parent.blender_edit_bone
+ blender_edit_bone.parent = blender_edit_bone_parent
+
+ ms3d_joint.blender_bone_name = blender_edit_bone.name
+ ms3d_joint.blender_edit_bone = blender_edit_bone
+ enable_edit_mode(False, blender_context)
+
+ if self.options_use_joint_to_bones:
+ enable_edit_mode(True, blender_context)
+ for ms3d_joint in ms3d_joints_ordered:
+ blender_edit_bone = blender_armature.edit_bones[ms3d_joint.name]
+ if blender_edit_bone.children:
+ new_length = 0.0
+ for child_bone in blender_edit_bone.children:
+ length = (child_bone.head - blender_edit_bone.head).length
+ if new_length <= 0 or length < new_length:
+ new_length = length
+ if new_length >= 0.01:
+ direction = blender_edit_bone.tail - blender_edit_bone.head
+ direction.normalize()
+ blender_edit_bone.tail = blender_edit_bone.head + (direction * new_length)
+ enable_edit_mode(False, blender_context)
+
+ ##########################
+ # post process bones
+ enable_edit_mode(False, blender_context)
+ for ms3d_joint_name, ms3d_joint in ms3d_joint_by_name.items():
+ blender_bone = blender_armature.bones.get(
+ ms3d_joint.blender_bone_name)
+ if blender_bone is None:
+ continue
+
+ blender_bone.ms3d.name = ms3d_joint.name
+ blender_bone.ms3d.flags = Ms3dUi.flags_from_ms3d(ms3d_joint.flags)
+
+ ms3d_joint_ex = ms3d_joint.joint_ex_object
+ if ms3d_joint_ex is not None:
+ blender_bone.ms3d.color = ms3d_joint_ex.color
+
+ ms3d_comment = ms3d_joint.comment_object
+ if ms3d_comment is not None:
+ blender_bone.ms3d.comment = ms3d_comment.comment
+
+ ##########################
+ if not self.options_use_animation:
+ return blender_armature_object
+
+
+ ##########################
+ # process pose bones
+ enable_pose_mode(True, blender_context)
+
+ blender_action = blender_context.blend_data.actions.new(ms3d_action_name)
+ if blender_armature_object.animation_data is None:
+ blender_armature_object.animation_data_create()
+ blender_armature_object.animation_data.action = blender_action
+
+ ##########################
+ # transition between keys may be incorrect
+ # because of the gimbal-lock problem!
+ # http://www.youtube.com/watch?v=zc8b2Jo7mno
+ # http://www.youtube.com/watch?v=rrUCBOlJdt4
+ # you can fix it manually by selecting the affected keyframes
+ # and allpy the following option to it:
+ # "Graph Editor -> Key -> Discontinuity (Euler) Filter"
+ # ==> "bpy.ops.graph.euler_filter()"
+ # but this option is only available for Euler rotation f-curves!
+ #
+ for ms3d_joint_name, ms3d_joint in ms3d_joint_by_name.items():
+ blender_pose_bone = blender_armature_object.pose.bones.get(
+ ms3d_joint.blender_bone_name)
+ if blender_pose_bone is None:
+ continue
+
+ data_path = blender_pose_bone.path_from_id('location')
+ fcurve_location_x = blender_action.fcurves.new(data_path, index=0)
+ fcurve_location_y = blender_action.fcurves.new(data_path, index=1)
+ fcurve_location_z = blender_action.fcurves.new(data_path, index=2)
+ for translation_key_frames in ms3d_joint.translation_key_frames:
+ frame = (translation_key_frames.time * ms3d_model.animation_fps)
+ matrix_local = Matrix.Translation(
+ Vector(translation_key_frames.position))
+ v = (matrix_local) * Vector()
+ fcurve_location_x.keyframe_points.insert(frame, -v[0])
+ fcurve_location_y.keyframe_points.insert(frame, v[2])
+ fcurve_location_z.keyframe_points.insert(frame, v[1])
+
+ if self.options_use_quaternion_rotation:
+ blender_pose_bone.rotation_mode = 'QUATERNION'
+ data_path = blender_pose_bone.path_from_id("rotation_quaternion")
+ fcurve_rotation_w = blender_action.fcurves.new(data_path, index=0)
+ fcurve_rotation_x = blender_action.fcurves.new(data_path, index=1)
+ fcurve_rotation_y = blender_action.fcurves.new(data_path, index=2)
+ fcurve_rotation_z = blender_action.fcurves.new(data_path, index=3)
+ for rotation_key_frames in ms3d_joint.rotation_key_frames:
+ frame = (rotation_key_frames.time * ms3d_model.animation_fps)
+ matrix_local_rot = (
+ Matrix.Rotation(
+ rotation_key_frames.rotation[2], 4, 'Y')
+ * Matrix.Rotation(
+ rotation_key_frames.rotation[1], 4, 'Z')
+ ) * Matrix.Rotation(
+ -rotation_key_frames.rotation[0], 4, 'X')
+ q = (matrix_local_rot).to_quaternion()
+ fcurve_rotation_w.keyframe_points.insert(frame, q.w)
+ fcurve_rotation_x.keyframe_points.insert(frame, q.x)
+ fcurve_rotation_y.keyframe_points.insert(frame, q.y)
+ fcurve_rotation_z.keyframe_points.insert(frame, q.z)
+ else:
+ blender_pose_bone.rotation_mode = 'XZY'
+ data_path = blender_pose_bone.path_from_id("rotation_euler")
+ fcurve_rotation_x = blender_action.fcurves.new(data_path, index=0)
+ fcurve_rotation_y = blender_action.fcurves.new(data_path, index=1)
+ fcurve_rotation_z = blender_action.fcurves.new(data_path, index=2)
+ for rotation_key_frames in ms3d_joint.rotation_key_frames:
+ frame = (rotation_key_frames.time * ms3d_model.animation_fps)
+ fcurve_rotation_x.keyframe_points.insert(
+ frame, -rotation_key_frames.rotation[0])
+ fcurve_rotation_y.keyframe_points.insert(
+ frame, rotation_key_frames.rotation[2])
+ fcurve_rotation_z.keyframe_points.insert(
+ frame, rotation_key_frames.rotation[1])
+
+ enable_pose_mode(False, blender_context)
+
+ return blender_armature_object
+
+
+ ###########################################################################
+ def geometry_correction(self, value):
+ return Vector((value[2], value[0], value[1]))
+
+
+ ###########################################################################
+ def build_ms3d_joint_dependency_order(self, ms3d_joints, ms3d_joints_ordered):
+ ms3d_joints_children = {"": {}}
+ for ms3d_joint in ms3d_joints:
+ if ms3d_joint.parent_name:
+ ms3d_joint_children = ms3d_joints_children.get(
+ ms3d_joint.parent_name)
+ if ms3d_joint_children is None:
+ ms3d_joint_children = ms3d_joints_children[
+ ms3d_joint.parent_name] = {}
+ else:
+ ms3d_joint_children = ms3d_joints_children[""]
+
+ ms3d_joint_children[ms3d_joint.name] = ms3d_joint
+
+ self.traverse_dependencies(
+ ms3d_joints_ordered,
+ ms3d_joints_children,
+ "")
+
+
+ return ms3d_joints_ordered
+
+
+ ###########################################################################
+ def traverse_dependencies(self, ms3d_joints_ordered, ms3d_joints_children,
+ key):
+ ms3d_joint_children = ms3d_joints_children.get(key)
+ if ms3d_joint_children:
+ for item in ms3d_joint_children.items():
+ ms3d_joint_name = item[0]
+ ms3d_joint = item[1]
+ ms3d_joints_ordered.append(ms3d_joint)
+ self.traverse_dependencies(
+ ms3d_joints_ordered,
+ ms3d_joints_children,
+ ms3d_joint_name)
+
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+# ##### END OF FILE #####
diff --git a/io_scene_ms3d/ms3d_spec.py b/io_scene_ms3d/ms3d_spec.py
new file mode 100644
index 00000000..1138a01e
--- /dev/null
+++ b/io_scene_ms3d/ms3d_spec.py
@@ -0,0 +1,2069 @@
+# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+
+
+# ##### BEGIN COPYRIGHT BLOCK #####
+#
+# initial script copyright (c)2011,2012 Alexander Nussbaumer
+#
+# ##### END COPYRIGHT BLOCK #####
+
+
+from struct import (
+ pack,
+ unpack,
+ )
+from sys import (
+ exc_info,
+ )
+
+###############################################################################
+#
+# MilkShape 3D 1.8.5 File Format Specification
+#
+# all specifications were taken from SDK 1.8.5
+#
+# some additional specifications were taken from
+# MilkShape 3D Viewer v2.0 (Nov 06 2007) - msMesh.h
+#
+
+
+###############################################################################
+#
+# sizes
+#
+
+class Ms3dSpec:
+ ###########################################################################
+ #
+ # max values
+ #
+ MAX_VERTICES = 65534 # 0..65533; note: (65534???, 65535???)
+ MAX_TRIANGLES = 65534 # 0..65533; note: (65534???, 65535???)
+ MAX_GROUPS = 255 # 1..255; note: (0 default group)
+ MAX_MATERIALS = 128 # 0..127; note: (-1 no material)
+ MAX_JOINTS = 128 # 0..127; note: (-1 no joint)
+ MAX_SMOOTH_GROUP = 32 # 0..32; note: (0 no smoothing group)
+ MAX_TEXTURE_FILENAME_SIZE = 128
+
+ ###########################################################################
+ #
+ # flags
+ #
+ FLAG_NONE = 0
+ FLAG_SELECTED = 1
+ FLAG_HIDDEN = 2
+ FLAG_SELECTED2 = 4
+ FLAG_DIRTY = 8
+ FLAG_ISKEY = 16 # additional spec from [2]
+ FLAG_NEWLYCREATED = 32 # additional spec from [2]
+ FLAG_MARKED = 64 # additional spec from [2]
+
+ FLAG_TEXTURE_NONE = 0x00
+ FLAG_TEXTURE_COMBINE_ALPHA = 0x20
+ FLAG_TEXTURE_HAS_ALPHA = 0x40
+ FLAG_TEXTURE_SPHERE_MAP = 0x80
+
+ MODE_TRANSPARENCY_SIMPLE = 0
+ MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF = 1
+ MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES = 2
+
+
+ ###########################################################################
+ #
+ # values
+ #
+ HEADER = "MS3D000000"
+
+
+ ###########################################################################
+ #
+ # min, max, default values
+ #
+ NONE_VERTEX_BONE_ID = -1
+ NONE_GROUP_MATERIAL_INDEX = -1
+
+ DEFAULT_HEADER = HEADER
+ DEFAULT_HEADER_VERSION = 4
+ DEFAULT_VERTEX_BONE_ID = NONE_VERTEX_BONE_ID
+ DEFAULT_TRIANGLE_SMOOTHING_GROUP = 0
+ DEFAULT_TRIANGLE_GROUP = 0
+ DEFAULT_MATERIAL_MODE = FLAG_TEXTURE_NONE
+ DEFAULT_GROUP_MATERIAL_INDEX = NONE_GROUP_MATERIAL_INDEX
+ DEFAULT_MODEL_JOINT_SIZE = 1.0
+ DEFAULT_MODEL_TRANSPARENCY_MODE = MODE_TRANSPARENCY_SIMPLE
+ DEFAULT_MODEL_ANIMATION_FPS = 25.0
+ DEFAULT_MODEL_SUB_VERSION_COMMENTS = 1
+ DEFAULT_MODEL_SUB_VERSION_VERTEX_EXTRA = 2
+ DEFAULT_MODEL_SUB_VERSION_JOINT_EXTRA = 1
+ DEFAULT_MODEL_SUB_VERSION_MODEL_EXTRA = 1
+ DEFAULT_FLAGS = FLAG_NONE
+ MAX_MATERIAL_SHININESS = 128
+
+ # blender default / OpenGL default
+ DEFAULT_MATERIAL_AMBIENT = (0.2, 0.2, 0.2, 1.0)
+ DEFAULT_MATERIAL_DIFFUSE = (0.8, 0.8, 0.8, 1.0)
+ DEFAULT_MATERIAL_SPECULAR = (1.0, 1.0, 1.0, 1.0)
+ DEFAULT_MATERIAL_EMISSIVE = (0.0, 0.0, 0.0, 1.0)
+ DEFAULT_MATERIAL_SHININESS = 12.5
+
+ DEFAULT_JOINT_COLOR = (0.8, 0.8, 0.8)
+
+###############################################################################
+#
+# helper class for basic raw io
+#
+class Ms3dIo:
+ # sizes for IO
+ SIZE_BYTE = 1
+ SIZE_SBYTE = 1
+ SIZE_WORD = 2
+ SIZE_DWORD = 4
+ SIZE_FLOAT = 4
+ LENGTH_ID = 10
+ LENGTH_NAME = 32
+ LENGTH_FILENAME = 128
+
+ PRECISION = 4
+
+ @staticmethod
+ def read_byte(raw_io):
+ """ read a single byte from raw_io """
+ buffer = raw_io.read(Ms3dIo.SIZE_BYTE)
+ if not buffer:
+ raise EOFError()
+ value = unpack('<B', buffer)[0]
+ return value
+
+ @staticmethod
+ def write_byte(raw_io, value):
+ """ write a single byte to raw_io """
+ raw_io.write(pack('<B', value))
+
+ @staticmethod
+ def read_sbyte(raw_io):
+ """ read a single signed byte from raw_io """
+ buffer = raw_io.read(Ms3dIo.SIZE_BYTE)
+ if not buffer:
+ raise EOFError()
+ value = unpack('<b', buffer)[0]
+ return value
+
+ @staticmethod
+ def write_sbyte(raw_io, value):
+ """ write a single signed byte to raw_io """
+ raw_io.write(pack('<b', value))
+
+ @staticmethod
+ def read_word(raw_io):
+ """ read a word from raw_io """
+ buffer = raw_io.read(Ms3dIo.SIZE_WORD)
+ if not buffer:
+ raise EOFError()
+ value = unpack('<H', buffer)[0]
+ return value
+
+ @staticmethod
+ def write_word(raw_io, value):
+ """ write a word to raw_io """
+ raw_io.write(pack('<H', value))
+
+ @staticmethod
+ def read_dword(raw_io):
+ """ read a double word from raw_io """
+ buffer = raw_io.read(Ms3dIo.SIZE_DWORD)
+ if not buffer:
+ raise EOFError()
+ value = unpack('<I', buffer)[0]
+ return value
+
+ @staticmethod
+ def write_dword(raw_io, value):
+ """ write a double word to raw_io """
+ raw_io.write(pack('<I', value))
+
+ @staticmethod
+ def read_float(raw_io):
+ """ read a float from raw_io """
+ buffer = raw_io.read(Ms3dIo.SIZE_FLOAT)
+ if not buffer:
+ raise EOFError()
+ value = unpack('<f', buffer)[0]
+ return value
+
+ @staticmethod
+ def write_float(raw_io, value):
+ """ write a float to raw_io """
+ raw_io.write(pack('<f', value))
+
+ @staticmethod
+ def read_array(raw_io, itemReader, count):
+ """ read an array[count] of objects from raw_io, by using a itemReader """
+ value = []
+ for i in range(count):
+ itemValue = itemReader(raw_io)
+ value.append(itemValue)
+ return tuple(value)
+
+ @staticmethod
+ def write_array(raw_io, itemWriter, count, value):
+ """ write an array[count] of objects to raw_io, by using a itemWriter """
+ for i in range(count):
+ itemValue = value[i]
+ itemWriter(raw_io, itemValue)
+
+ @staticmethod
+ def read_array2(raw_io, itemReader, count, count2):
+ """ read an array[count][count2] of objects from raw_io,
+ by using a itemReader """
+ value = []
+ for i in range(count):
+ itemValue = Ms3dIo.read_array(raw_io, itemReader, count2)
+ value.append(tuple(itemValue))
+ return value
+
+ @staticmethod
+ def write_array2(raw_io, itemWriter, count, count2, value):
+ """ write an array[count][count2] of objects to raw_io,
+ by using a itemWriter """
+ for i in range(count):
+ itemValue = value[i]
+ Ms3dIo.write_array(raw_io, itemWriter, count2, itemValue)
+
+ @staticmethod
+ def read_string(raw_io, length):
+ """ read a string of a specific length from raw_io """
+ value = []
+ skip = False
+ for i in range(length):
+ buffer = raw_io.read(Ms3dIo.SIZE_SBYTE)
+ if not buffer:
+ raise EOFError()
+ raw = (int)(unpack('<b', buffer)[0])
+ if (raw >= 32) & (raw <= 255):
+ pass
+ else:
+ if (raw == 0):
+ raw = 0
+ skip = True
+ else:
+ raw = 32
+
+ c = chr(raw)
+
+ if (not skip):
+ value.append(c)
+
+ finalValue = "".join(value)
+ return finalValue
+
+ @staticmethod
+ def write_string(raw_io, length, value):
+ """ write a string of a specific length to raw_io """
+ l = len(value)
+ for i in range(length):
+ if(i < l):
+ c = value[i]
+
+ if (isinstance(c, str)):
+ c = c[0]
+ raw = ord(c)
+ elif (isinstance(c, int)):
+ raw = c
+ else:
+ pass
+ else:
+ raw = 0
+
+ raw_io.write(pack('<b', (int)(raw % 256)))
+
+
+###############################################################################
+#
+# multi complex types
+#
+
+###############################################################################
+class Ms3dHeader:
+ """ Ms3dHeader """
+ __slots__ = (
+ 'id',
+ 'version',
+ )
+
+ def __init__(
+ self,
+ default_id=Ms3dSpec.DEFAULT_HEADER,
+ default_version=Ms3dSpec.DEFAULT_HEADER_VERSION
+ ):
+ self.id = default_id
+ self.version = default_version
+
+ def __repr__(self):
+ return "\n<id='{}', version={}>".format(
+ self.id,
+ self.version
+ )
+
+ def __hash__(self):
+ return hash(self.id) ^ hash(self.version)
+
+ def __eq__(self, other):
+ return ((self is not None) and (other is not None)
+ and (self.id == other.id)
+ and (self.version == other.version))
+
+ def read(self, raw_io):
+ self.id = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_ID)
+ self.version = Ms3dIo.read_dword(raw_io)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_ID, self.id)
+ Ms3dIo.write_dword(raw_io, self.version)
+
+
+###############################################################################
+class Ms3dVertex:
+ """ Ms3dVertex """
+ """
+ __slots__ was taking out,
+ to be able to inject additional attributes during runtime
+ __slots__ = (
+ 'flags',
+ 'bone_id',
+ 'reference_count',
+ '_vertex',
+ '_vertex_ex_object', # Ms3dVertexEx
+ )
+ """
+
+ def __init__(
+ self,
+ default_flags=Ms3dSpec.DEFAULT_FLAGS,
+ default_vertex=(0.0, 0.0, 0.0),
+ default_bone_id=Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
+ default_reference_count=0,
+ default_vertex_ex_object=None, # Ms3dVertexEx
+ ):
+ self.flags = default_flags
+ self._vertex = default_vertex
+ self.bone_id = default_bone_id
+ self.reference_count = default_reference_count
+
+ if default_vertex_ex_object is None:
+ default_vertex_ex_object = Ms3dVertexEx2()
+ # Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_VERTEX_EXTRA = 2
+ self._vertex_ex_object = default_vertex_ex_object
+ # Ms3dVertexEx
+
+ def __repr__(self):
+ return "\n<flags={}, vertex=({:.{p}f}, {:.{p}f}, {:.{p}f}), bone_id={},"\
+ " reference_count={}>".format(
+ self.flags,
+ self._vertex[0],
+ self._vertex[1],
+ self._vertex[2],
+ self.bone_id,
+ self.reference_count,
+ p=Ms3dIo.PRECISION
+ )
+
+ def __hash__(self):
+ return (hash(self.vertex)
+ #^ hash(self.flags)
+ #^ hash(self.bone_id)
+ #^ hash(self.reference_count)
+ )
+
+ def __eq__(self, other):
+ return ((self.vertex == other.vertex)
+ #and (self.flags == other.flags)
+ #and (self.bone_id == other.bone_id)
+ #and (self.reference_count == other.reference_count)
+ )
+
+
+ @property
+ def vertex(self):
+ return self._vertex
+
+ @property
+ def vertex_ex_object(self):
+ return self._vertex_ex_object
+
+
+ def read(self, raw_io):
+ self.flags = Ms3dIo.read_byte(raw_io)
+ self._vertex = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
+ self.bone_id = Ms3dIo.read_sbyte(raw_io)
+ self.reference_count = Ms3dIo.read_byte(raw_io)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_byte(raw_io, self.flags)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.vertex)
+ Ms3dIo.write_sbyte(raw_io, self.bone_id)
+ Ms3dIo.write_byte(raw_io, self.reference_count)
+
+
+###############################################################################
+class Ms3dTriangle:
+ """ Ms3dTriangle """
+ """
+ __slots__ was taking out,
+ to be able to inject additional attributes during runtime
+ __slots__ = (
+ 'flags',
+ 'smoothing_group',
+ 'group_index',
+ '_vertex_indices',
+ '_vertex_normals',
+ '_s',
+ '_t',
+ )
+ """
+
+ def __init__(
+ self,
+ default_flags=Ms3dSpec.DEFAULT_FLAGS,
+ default_vertex_indices=(0, 0, 0),
+ default_vertex_normals=(
+ (0.0, 0.0, 0.0),
+ (0.0, 0.0, 0.0),
+ (0.0, 0.0, 0.0)),
+ default_s=(0.0, 0.0, 0.0),
+ default_t=(0.0, 0.0, 0.0),
+ default_smoothing_group=Ms3dSpec.DEFAULT_TRIANGLE_SMOOTHING_GROUP,
+ default_group_index=Ms3dSpec.DEFAULT_TRIANGLE_GROUP
+ ):
+ self.flags = default_flags
+ self._vertex_indices = default_vertex_indices
+ self._vertex_normals = default_vertex_normals
+ self._s = default_s
+ self._t = default_t
+ self.smoothing_group = default_smoothing_group
+ self.group_index = default_group_index
+
+ def __repr__(self):
+ return "\n<flags={}, vertex_indices={}, vertex_normals=(({:.{p}f}, "\
+ "{:.{p}f}, {:.{p}f}), ({:.{p}f}, {:.{p}f}, {:.{p}f}), ({:.{p}f}, "\
+ "{:.{p}f}, {:.{p}f})), s=({:.{p}f}, {:.{p}f}, {:.{p}f}), "\
+ "t=({:.{p}f}, {:.{p}f}, {:.{p}f}), smoothing_group={}, "\
+ "group_index={}>".format(
+ self.flags,
+ self.vertex_indices,
+ self.vertex_normals[0][0],
+ self.vertex_normals[0][1],
+ self.vertex_normals[0][2],
+ self.vertex_normals[1][0],
+ self.vertex_normals[1][1],
+ self.vertex_normals[1][2],
+ self.vertex_normals[2][0],
+ self.vertex_normals[2][1],
+ self.vertex_normals[2][2],
+ self.s[0],
+ self.s[1],
+ self.s[2],
+ self.t[0],
+ self.t[1],
+ self.t[2],
+ self.smoothing_group,
+ self.group_index,
+ p=Ms3dIo.PRECISION
+ )
+
+
+ @property
+ def vertex_indices(self):
+ return self._vertex_indices
+
+ @property
+ def vertex_normals(self):
+ return self._vertex_normals
+
+ @property
+ def s(self):
+ return self._s
+
+ @property
+ def t(self):
+ return self._t
+
+
+ def read(self, raw_io):
+ self.flags = Ms3dIo.read_word(raw_io)
+ self._vertex_indices = Ms3dIo.read_array(raw_io, Ms3dIo.read_word, 3)
+ self._vertex_normals = Ms3dIo.read_array2(raw_io, Ms3dIo.read_float, 3, 3)
+ self._s = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
+ self._t = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
+ self.smoothing_group = Ms3dIo.read_byte(raw_io)
+ self.group_index = Ms3dIo.read_byte(raw_io)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_word(raw_io, self.flags)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_word, 3, self.vertex_indices)
+ Ms3dIo.write_array2(raw_io, Ms3dIo.write_float, 3, 3, self.vertex_normals)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.s)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.t)
+ Ms3dIo.write_byte(raw_io, self.smoothing_group)
+ Ms3dIo.write_byte(raw_io, self.group_index)
+
+
+###############################################################################
+class Ms3dGroup:
+ """ Ms3dGroup """
+ """
+ __slots__ was taking out,
+ to be able to inject additional attributes during runtime
+ __slots__ = (
+ 'flags',
+ 'name',
+ 'material_index',
+ '_triangle_indices',
+ '_comment_object', # Ms3dComment
+ )
+ """
+
+ def __init__(
+ self,
+ default_flags=Ms3dSpec.DEFAULT_FLAGS,
+ default_name="",
+ default_triangle_indices=None,
+ default_material_index=Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX,
+ default_comment_object=None, # Ms3dComment
+ ):
+ if (default_name is None):
+ default_name = ""
+
+ if (default_triangle_indices is None):
+ default_triangle_indices = []
+
+ self.flags = default_flags
+ self.name = default_name
+ self._triangle_indices = default_triangle_indices
+ self.material_index = default_material_index
+
+ if default_comment_object is None:
+ default_comment_object = Ms3dCommentEx()
+ self._comment_object = default_comment_object # Ms3dComment
+
+ def __repr__(self):
+ return "\n<flags={}, name='{}', number_triangles={},"\
+ " triangle_indices={}, material_index={}>".format(
+ self.flags,
+ self.name,
+ self.number_triangles,
+ self.triangle_indices,
+ self.material_index
+ )
+
+
+ @property
+ def number_triangles(self):
+ if self.triangle_indices is None:
+ return 0
+ return len(self.triangle_indices)
+
+ @property
+ def triangle_indices(self):
+ return self._triangle_indices
+
+ @property
+ def comment_object(self):
+ return self._comment_object
+
+
+ def read(self, raw_io):
+ self.flags = Ms3dIo.read_byte(raw_io)
+ self.name = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_NAME)
+ _number_triangles = Ms3dIo.read_word(raw_io)
+ self._triangle_indices = Ms3dIo.read_array(
+ raw_io, Ms3dIo.read_word, _number_triangles)
+ self.material_index = Ms3dIo.read_sbyte(raw_io)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_byte(raw_io, self.flags)
+ Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_NAME, self.name)
+ Ms3dIo.write_word(raw_io, self.number_triangles)
+ Ms3dIo.write_array(
+ raw_io, Ms3dIo.write_word, self.number_triangles,
+ self.triangle_indices)
+ Ms3dIo.write_sbyte(raw_io, self.material_index)
+
+
+###############################################################################
+class Ms3dMaterial:
+ """ Ms3dMaterial """
+ """
+ __slots__ was taking out,
+ to be able to inject additional attributes during runtime
+ __slots__ = (
+ 'name',
+ 'shininess',
+ 'transparency',
+ 'mode',
+ 'texture',
+ 'alphamap',
+ '_ambient',
+ '_diffuse',
+ '_specular',
+ '_emissive',
+ '_comment_object', # Ms3dComment
+ )
+ """
+
+ def __init__(
+ self,
+ default_name="",
+ default_ambient=list(Ms3dSpec.DEFAULT_MATERIAL_AMBIENT),
+ default_diffuse=list(Ms3dSpec.DEFAULT_MATERIAL_DIFFUSE),
+ default_specular=list(Ms3dSpec.DEFAULT_MATERIAL_SPECULAR),
+ default_emissive=list(Ms3dSpec.DEFAULT_MATERIAL_EMISSIVE),
+ default_shininess=Ms3dSpec.DEFAULT_MATERIAL_SHININESS,
+ default_transparency=0.0,
+ default_mode=Ms3dSpec.DEFAULT_MATERIAL_MODE,
+ default_texture="",
+ default_alphamap="",
+ default_comment_object=None, # Ms3dComment
+ ):
+ if (default_name is None):
+ default_name = ""
+
+ if (default_texture is None):
+ default_texture = ""
+
+ if (default_alphamap is None):
+ default_alphamap = ""
+
+ self.name = default_name
+ self._ambient = default_ambient
+ self._diffuse = default_diffuse
+ self._specular = default_specular
+ self._emissive = default_emissive
+ self.shininess = default_shininess
+ self.transparency = default_transparency
+ self.mode = default_mode
+ self.texture = default_texture
+ self.alphamap = default_alphamap
+
+ if default_comment_object is None:
+ default_comment_object = Ms3dCommentEx()
+ self._comment_object = default_comment_object # Ms3dComment
+
+ def __repr__(self):
+ return "\n<name='{}', ambient=({:.{p}f}, {:.{p}f}, {:.{p}f}, {:.{p}f}), "\
+ "diffuse=({:.{p}f}, {:.{p}f}, {:.{p}f}, {:.{p}f}), specular=("\
+ "{:.{p}f}, {:.{p}f}, {:.{p}f}, {:.{p}f}), emissive=({:.{p}f}, "\
+ "{:.{p}f}, {:.{p}f}, {:.{p}f}), shininess={:.{p}f}, transparency="\
+ "{:.{p}f}, mode={}, texture='{}', alphamap='{}'>".format(
+ self.name,
+ self.ambient[0],
+ self.ambient[1],
+ self.ambient[2],
+ self.ambient[3],
+ self.diffuse[0],
+ self.diffuse[1],
+ self.diffuse[2],
+ self.diffuse[3],
+ self.specular[0],
+ self.specular[1],
+ self.specular[2],
+ self.specular[3],
+ self.emissive[0],
+ self.emissive[1],
+ self.emissive[2],
+ self.emissive[3],
+ self.shininess,
+ self.transparency,
+ self.mode,
+ self.texture,
+ self.alphamap,
+ p=Ms3dIo.PRECISION
+ )
+
+ def __hash__(self):
+ return (hash(self.name)
+
+ ^ hash(self.ambient)
+ ^ hash(self.diffuse)
+ ^ hash(self.specular)
+ ^ hash(self.emissive)
+
+ ^ hash(self.shininess)
+ ^ hash(self.transparency)
+ ^ hash(self.mode)
+
+ ^ hash(self.texture)
+ ^ hash(self.alphamap)
+ )
+
+ def __eq__(self, other):
+ return ((self.name == other.name)
+
+ and (self.ambient == other.ambient)
+ and (self.diffuse == other.diffuse)
+ and (self.specular == other.specular)
+ and (self.emissive == other.emissive)
+
+ and (self.shininess == other.shininess)
+ and (self.transparency == other.transparency)
+ and (self.mode == other.mode)
+
+ #and (self.texture == other.texture)
+ #and (self.alphamap == other.alphamap)
+ )
+
+
+ @property
+ def ambient(self):
+ return self._ambient
+
+ @property
+ def diffuse(self):
+ return self._diffuse
+
+ @property
+ def specular(self):
+ return self._specular
+
+ @property
+ def emissive(self):
+ return self._emissive
+
+ @property
+ def comment_object(self):
+ return self._comment_object
+
+
+ def read(self, raw_io):
+ self.name = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_NAME)
+ self._ambient = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 4)
+ self._diffuse = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 4)
+ self._specular = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 4)
+ self._emissive = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 4)
+ self.shininess = Ms3dIo.read_float(raw_io)
+ self.transparency = Ms3dIo.read_float(raw_io)
+ self.mode = Ms3dIo.read_byte(raw_io)
+ self.texture = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_FILENAME)
+ self.alphamap = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_FILENAME)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_NAME, self.name)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 4, self.ambient)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 4, self.diffuse)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 4, self.specular)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 4, self.emissive)
+ Ms3dIo.write_float(raw_io, self.shininess)
+ Ms3dIo.write_float(raw_io, self.transparency)
+ Ms3dIo.write_byte(raw_io, self.mode)
+ Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_FILENAME, self.texture)
+ Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_FILENAME, self.alphamap)
+
+
+###############################################################################
+class Ms3dRotationKeyframe:
+ """ Ms3dRotationKeyframe """
+ __slots__ = (
+ 'time',
+ '_rotation',
+ )
+
+ def __init__(
+ self,
+ default_time=0.0,
+ default_rotation=(0.0, 0.0, 0.0)
+ ):
+ self.time = default_time
+ self._rotation = default_rotation
+
+ def __repr__(self):
+ return "\n<time={:.{p}f}, rotation=({:.{p}f}, {:.{p}f}, {:.{p}f})>".format(
+ self.time,
+ self.rotation[0],
+ self.rotation[1],
+ self.rotation[2],
+ p=Ms3dIo.PRECISION
+ )
+
+
+ @property
+ def rotation(self):
+ return self._rotation
+
+
+ def read(self, raw_io):
+ self.time = Ms3dIo.read_float(raw_io)
+ self._rotation = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_float(raw_io, self.time)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.rotation)
+
+
+###############################################################################
+class Ms3dTranslationKeyframe:
+ """ Ms3dTranslationKeyframe """
+ __slots__ = (
+ 'time',
+ '_position',
+ )
+
+ def __init__(
+ self,
+ default_time=0.0,
+ default_position=(0.0, 0.0, 0.0)
+ ):
+ self.time = default_time
+ self._position = default_position
+
+ def __repr__(self):
+ return "\n<time={:.{p}f}, position=({:.{p}f}, {:.{p}f}, {:.{p}f})>".format(
+ self.time,
+ self.position[0],
+ self.position[1],
+ self.position[2],
+ p=Ms3dIo.PRECISION
+ )
+
+
+ @property
+ def position(self):
+ return self._position
+
+
+ def read(self, raw_io):
+ self.time = Ms3dIo.read_float(raw_io)
+ self._position = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_float(raw_io, self.time)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.position)
+
+
+###############################################################################
+class Ms3dJoint:
+ """ Ms3dJoint """
+ """
+ __slots__ was taking out,
+ to be able to inject additional attributes during runtime
+ __slots__ = (
+ 'flags',
+ 'name',
+ 'parent_name',
+ '_rotation',
+ '_position',
+ '_rotation_keyframes',
+ '_translation_keyframes',
+ '_joint_ex_object', # Ms3dJointEx
+ '_comment_object', # Ms3dComment
+ )
+ """
+
+ def __init__(
+ self,
+ default_flags=Ms3dSpec.DEFAULT_FLAGS,
+ default_name="",
+ default_parent_name="",
+ default_rotation=(0.0, 0.0, 0.0),
+ default_position=(0.0, 0.0, 0.0),
+ default_rotation_keyframes=None,
+ default_translation_keyframes=None,
+ default_joint_ex_object=None, # Ms3dJointEx
+ default_comment_object=None, # Ms3dComment
+ ):
+ if (default_name is None):
+ default_name = ""
+
+ if (default_parent_name is None):
+ default_parent_name = ""
+
+ if (default_rotation_keyframes is None):
+ default_rotation_keyframes = [] #Ms3dRotationKeyframe()
+
+ if (default_translation_keyframes is None):
+ default_translation_keyframes = [] #Ms3dTranslationKeyframe()
+
+ self.flags = default_flags
+ self.name = default_name
+ self.parent_name = default_parent_name
+ self._rotation = default_rotation
+ self._position = default_position
+ self._rotation_keyframes = default_rotation_keyframes
+ self._translation_keyframes = default_translation_keyframes
+
+ if default_comment_object is None:
+ default_comment_object = Ms3dCommentEx()
+ self._comment_object = default_comment_object # Ms3dComment
+
+ if default_joint_ex_object is None:
+ default_joint_ex_object = Ms3dJointEx()
+ self._joint_ex_object = default_joint_ex_object # Ms3dJointEx
+
+ def __repr__(self):
+ return "\n<flags={}, name='{}', parent_name='{}', rotation=({:.{p}f}, "\
+ "{:.{p}f}, {:.{p}f}), position=({:.{p}f}, {:.{p}f}, {:.{p}f}), "\
+ "number_rotation_keyframes={}, number_translation_keyframes={},"\
+ " rotation_key_frames={}, translation_key_frames={}>".format(
+ self.flags,
+ self.name,
+ self.parent_name,
+ self.rotation[0],
+ self.rotation[1],
+ self.rotation[2],
+ self.position[0],
+ self.position[1],
+ self.position[2],
+ self.number_rotation_keyframes,
+ self.number_translation_keyframes,
+ self.rotation_key_frames,
+ self.translation_key_frames,
+ p=Ms3dIo.PRECISION
+ )
+
+
+ @property
+ def rotation(self):
+ return self._rotation
+
+ @property
+ def position(self):
+ return self._position
+
+ @property
+ def number_rotation_keyframes(self):
+ if self.rotation_key_frames is None:
+ return 0
+ return len(self.rotation_key_frames)
+
+ @property
+ def number_translation_keyframes(self):
+ if self.translation_key_frames is None:
+ return 0
+ return len(self.translation_key_frames)
+
+ @property
+ def rotation_key_frames(self):
+ return self._rotation_keyframes
+
+ @property
+ def translation_key_frames(self):
+ return self._translation_keyframes
+
+
+ @property
+ def joint_ex_object(self):
+ return self._joint_ex_object
+
+
+ @property
+ def comment_object(self):
+ return self._comment_object
+
+
+ def read(self, raw_io):
+ self.flags = Ms3dIo.read_byte(raw_io)
+ self.name = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_NAME)
+ self.parent_name = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_NAME)
+ self._rotation = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
+ self._position = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
+ _number_rotation_keyframes = Ms3dIo.read_word(raw_io)
+ _number_translation_keyframes = Ms3dIo.read_word(raw_io)
+ self._rotation_keyframes = []
+ for i in range(_number_rotation_keyframes):
+ self.rotation_key_frames.append(Ms3dRotationKeyframe().read(raw_io))
+ self._translation_keyframes = []
+ for i in range(_number_translation_keyframes):
+ self.translation_key_frames.append(
+ Ms3dTranslationKeyframe().read(raw_io))
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_byte(raw_io, self.flags)
+ Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_NAME, self.name)
+ Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_NAME, self.parent_name)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.rotation)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.position)
+ Ms3dIo.write_word(raw_io, self.number_rotation_keyframes)
+ Ms3dIo.write_word(raw_io, self.number_translation_keyframes)
+ for i in range(self.number_rotation_keyframes):
+ self.rotation_key_frames[i].write(raw_io)
+ for i in range(self.number_translation_keyframes):
+ self.translation_key_frames[i].write(raw_io)
+
+
+###############################################################################
+class Ms3dCommentEx:
+ """ Ms3dCommentEx """
+ __slots__ = (
+ 'index',
+ 'comment',
+ )
+
+ def __init__(
+ self,
+ default_index=0,
+ default_comment=""
+ ):
+ if (default_comment is None):
+ default_comment = ""
+
+ self.index = default_index
+ self.comment = default_comment
+
+ def __repr__(self):
+ return "\n<index={}, comment_length={}, comment='{}'>".format(
+ self.index,
+ self.comment_length,
+ self.comment
+ )
+
+
+ @property
+ def comment_length(self):
+ if self.comment is None:
+ return 0
+ return len(self.comment)
+
+
+ def read(self, raw_io):
+ self.index = Ms3dIo.read_dword(raw_io)
+ _comment_length = Ms3dIo.read_dword(raw_io)
+ self.comment = Ms3dIo.read_string(raw_io, _comment_length)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_dword(raw_io, self.index)
+ Ms3dIo.write_dword(raw_io, self.comment_length)
+ Ms3dIo.write_string(raw_io, self.comment_length, self.comment)
+
+
+###############################################################################
+class Ms3dComment:
+ """ Ms3dComment """
+ __slots__ = (
+ 'comment',
+ )
+
+ def __init__(
+ self,
+ default_comment=""
+ ):
+ if (default_comment is None):
+ default_comment = ""
+
+ self.comment = default_comment
+
+ def __repr__(self):
+ return "\n<comment_length={}, comment='{}'>".format(
+ self.comment_length,
+ self.comment
+ )
+
+
+ @property
+ def comment_length(self):
+ if self.comment is None:
+ return 0
+ return len(self.comment)
+
+
+ def read(self, raw_io):
+ _comment_length = Ms3dIo.read_dword(raw_io)
+ self.comment = Ms3dIo.read_string(raw_io, _comment_length)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_dword(raw_io, self.comment_length)
+ Ms3dIo.write_string(raw_io, self.comment_length, self.comment)
+
+
+###############################################################################
+class Ms3dVertexEx1:
+ """ Ms3dVertexEx1 """
+ __slots__ = (
+ '_bone_ids',
+ '_weights',
+ )
+
+ def __init__(
+ self,
+ default_bone_ids=(
+ Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
+ Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
+ Ms3dSpec.DEFAULT_VERTEX_BONE_ID),
+ default_weights=(100, 0, 0)
+ ):
+ self._bone_ids = default_bone_ids
+ self._weights = default_weights
+
+ def __repr__(self):
+ return "\n<bone_ids={}, weights={}>".format(
+ self.bone_ids,
+ self.weights
+ )
+
+
+ @property
+ def bone_ids(self):
+ return self._bone_ids
+
+ @property
+ def weights(self):
+ return self._weights
+
+
+ @property
+ def weight_bone_id(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return self._weights
+ return 100
+
+ @property
+ def weight_bone_id0(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return self._weights[0]
+ return 0
+
+ @property
+ def weight_bone_id1(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return self._weights[1]
+ return 0
+
+ @property
+ def weight_bone_id2(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return 100 - (self._weights[0] + self._weights[1] \
+ + self._weights[2])
+ return 0
+
+
+ def read(self, raw_io):
+ self._bone_ids = Ms3dIo.read_array(raw_io, Ms3dIo.read_sbyte, 3)
+ self._weights = Ms3dIo.read_array(raw_io, Ms3dIo.read_byte, 3)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_sbyte, 3, self.bone_ids)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_byte, 3, self.weights)
+
+
+###############################################################################
+class Ms3dVertexEx2:
+ """ Ms3dVertexEx2 """
+ __slots__ = (
+ 'extra',
+ '_bone_ids',
+ '_weights',
+ )
+
+ def __init__(
+ self,
+ default_bone_ids=(
+ Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
+ Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
+ Ms3dSpec.DEFAULT_VERTEX_BONE_ID),
+ default_weights=(100, 0, 0),
+ default_extra=0
+ ):
+ self._bone_ids = default_bone_ids
+ self._weights = default_weights
+ self.extra = default_extra
+
+ def __repr__(self):
+ return "\n<bone_ids={}, weights={}, extra={}>".format(
+ self.bone_ids,
+ self.weights,
+ self.extra
+ )
+
+
+ @property
+ def bone_ids(self):
+ return self._bone_ids
+
+ @property
+ def weights(self):
+ return self._weights
+
+
+ @property
+ def weight_bone_id(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return self._weights
+ return 100
+
+ @property
+ def weight_bone_id0(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return self._weights[0]
+ return 0
+
+ @property
+ def weight_bone_id1(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return self._weights[1]
+ return 0
+
+ @property
+ def weight_bone_id2(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return 100 - (self._weights[0] + self._weights[1] \
+ + self._weights[2])
+ return 0
+
+
+ def read(self, raw_io):
+ self._bone_ids = Ms3dIo.read_array(raw_io, Ms3dIo.read_sbyte, 3)
+ self._weights = Ms3dIo.read_array(raw_io, Ms3dIo.read_byte, 3)
+ self.extra = Ms3dIo.read_dword(raw_io)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_sbyte, 3, self.bone_ids)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_byte, 3, self.weights)
+ Ms3dIo.write_dword(raw_io, self.extra)
+
+
+###############################################################################
+class Ms3dVertexEx3:
+ """ Ms3dVertexEx3 """
+ #char bone_ids[3]; // index of joint or -1, if -1, then that weight is
+ # ignored, since subVersion 1
+ #byte weights[3]; // vertex weight ranging from 0 - 100, last weight is
+ # computed by 1.0 - sum(all weights), since subVersion 1
+ #// weight[0] is the weight for bone_id in Ms3dVertex
+ #// weight[1] is the weight for bone_ids[0]
+ #// weight[2] is the weight for bone_ids[1]
+ #// 1.0f - weight[0] - weight[1] - weight[2] is the weight for bone_ids[2]
+ #unsigned int extra; // vertex extra, which can be used as color or
+ # anything else, since subVersion 2
+ __slots__ = (
+ 'extra',
+ '_bone_ids',
+ '_weights',
+ )
+
+ def __init__(
+ self,
+ default_bone_ids=(
+ Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
+ Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
+ Ms3dSpec.DEFAULT_VERTEX_BONE_ID),
+ default_weights=(100, 0, 0),
+ default_extra=0
+ ):
+ self._bone_ids = default_bone_ids
+ self._weights = default_weights
+ self.extra = default_extra
+
+ def __repr__(self):
+ return "\n<bone_ids={}, weights={}, extra={}>".format(
+ self.bone_ids,
+ self.weights,
+ self.extra
+ )
+
+
+ @property
+ def bone_ids(self):
+ return self._bone_ids
+
+ @property
+ def weights(self):
+ return self._weights
+
+
+ @property
+ def weight_bone_id(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return self._weights
+ return 100
+
+ @property
+ def weight_bone_id0(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return self._weights[0]
+ return 0
+
+ @property
+ def weight_bone_id1(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return self._weights[1]
+ return 0
+
+ @property
+ def weight_bone_id2(self):
+ if self._weights[0] or self._weights[1] or self._weights[2]:
+ return 100 - (self._weights[0] + self._weights[1] \
+ + self._weights[2])
+ return 0
+
+
+ def read(self, raw_io):
+ self._bone_ids = Ms3dIo.read_array(raw_io, Ms3dIo.read_sbyte, 3)
+ self._weights = Ms3dIo.read_array(raw_io, Ms3dIo.read_byte, 3)
+ self.extra = Ms3dIo.read_dword(raw_io)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_sbyte, 3, self.bone_ids)
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_byte, 3, self.weights)
+ Ms3dIo.write_dword(raw_io, self.extra)
+
+
+###############################################################################
+class Ms3dJointEx:
+ """ Ms3dJointEx """
+ __slots__ = (
+ '_color',
+ )
+
+ def __init__(
+ self,
+ default_color=Ms3dSpec.DEFAULT_JOINT_COLOR
+ ):
+ self._color = default_color
+
+ def __repr__(self):
+ return "\n<color=({:.{p}f}, {:.{p}f}, {:.{p}f})>".format(
+ self.color[0],
+ self.color[1],
+ self.color[2],
+ p=Ms3dIo.PRECISION
+ )
+
+
+ @property
+ def color(self):
+ return self._color
+
+
+ def read(self, raw_io):
+ self._color = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.color)
+
+
+###############################################################################
+class Ms3dModelEx:
+ """ Ms3dModelEx """
+ __slots__ = (
+ 'joint_size',
+ 'transparency_mode',
+ 'alpha_ref',
+ )
+
+ def __init__(
+ self,
+ default_joint_size=Ms3dSpec.DEFAULT_MODEL_JOINT_SIZE,
+ default_transparency_mode\
+ =Ms3dSpec.DEFAULT_MODEL_TRANSPARENCY_MODE,
+ default_alpha_ref=0.0
+ ):
+ self.joint_size = default_joint_size
+ self.transparency_mode = default_transparency_mode
+ self.alpha_ref = default_alpha_ref
+
+ def __repr__(self):
+ return "\n<joint_size={:.{p}f}, transparency_mode={}, alpha_ref={:.{p}f}>".format(
+ self.joint_size,
+ self.transparency_mode,
+ self.alpha_ref,
+ p=Ms3dIo.PRECISION
+ )
+
+ def read(self, raw_io):
+ self.joint_size = Ms3dIo.read_float(raw_io)
+ self.transparency_mode = Ms3dIo.read_dword(raw_io)
+ self.alpha_ref = Ms3dIo.read_float(raw_io)
+ return self
+
+ def write(self, raw_io):
+ Ms3dIo.write_float(raw_io, self.joint_size)
+ Ms3dIo.write_dword(raw_io, self.transparency_mode)
+ Ms3dIo.write_float(raw_io, self.alpha_ref)
+
+
+###############################################################################
+#
+# file format
+#
+###############################################################################
+class Ms3dModel:
+ """ Ms3dModel """
+ __slot__ = (
+ 'header',
+ 'animation_fps',
+ 'current_time',
+ 'number_total_frames',
+ 'sub_version_comments',
+ 'sub_version_vertex_extra',
+ 'sub_version_joint_extra',
+ 'sub_version_model_extra',
+ 'name',
+ '_vertices',
+ '_triangles',
+ '_groups',
+ '_materials',
+ '_joints',
+ '_has_model_comment',
+ '_comment_object', # Ms3dComment
+ '_model_ex_object', # Ms3dModelEx
+ )
+
+ def __init__(
+ self,
+ default_name=""
+ ):
+ if (default_name is None):
+ default_name = ""
+
+ self.name = default_name
+
+ self.animation_fps = Ms3dSpec.DEFAULT_MODEL_ANIMATION_FPS
+ self.current_time = 0.0
+ self.number_total_frames = 0
+ self.sub_version_comments \
+ = Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_COMMENTS
+ self.sub_version_vertex_extra \
+ = Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_VERTEX_EXTRA
+ self.sub_version_joint_extra \
+ = Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_JOINT_EXTRA
+ self.sub_version_model_extra \
+ = Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_MODEL_EXTRA
+
+ self._vertices = [] #Ms3dVertex()
+ self._triangles = [] #Ms3dTriangle()
+ self._groups = [] #Ms3dGroup()
+ self._materials = [] #Ms3dMaterial()
+ self._joints = [] #Ms3dJoint()
+
+ self.header = Ms3dHeader()
+ self._model_ex_object = Ms3dModelEx()
+ self._comment_object = None #Ms3dComment()
+
+
+ @property
+ def number_vertices(self):
+ if self.vertices is None:
+ return 0
+ return len(self.vertices)
+
+ @property
+ def vertices(self):
+ return self._vertices
+
+
+ @property
+ def number_triangles(self):
+ if self.triangles is None:
+ return 0
+ return len(self.triangles)
+
+ @property
+ def triangles(self):
+ return self._triangles
+
+
+ @property
+ def number_groups(self):
+ if self.groups is None:
+ return 0
+ return len(self.groups)
+
+ @property
+ def groups(self):
+ return self._groups
+
+
+ @property
+ def number_materials(self):
+ if self.materials is None:
+ return 0
+ return len(self.materials)
+
+ @property
+ def materials(self):
+ return self._materials
+
+
+ @property
+ def number_joints(self):
+ if self.joints is None:
+ return 0
+ return len(self.joints)
+
+ @property
+ def joints(self):
+ return self._joints
+
+
+ @property
+ def number_group_comments(self):
+ if self.groups is None:
+ return 0
+ number = 0
+ for item in self.groups:
+ if item.comment_object is not None and item.comment_object.comment:
+ number += 1
+ return number
+
+ @property
+ def group_comments(self):
+ if self.groups is None:
+ return None
+ items = []
+ for item in self.groups:
+ if item.comment_object is not None and item.comment_object.comment:
+ items.append(item)
+ return items
+
+
+ @property
+ def number_material_comments(self):
+ if self.materials is None:
+ return 0
+ number = 0
+ for item in self.materials:
+ if item.comment_object is not None and item.comment_object.comment:
+ number += 1
+ return number
+
+ @property
+ def material_comments(self):
+ if self.materials is None:
+ return None
+ items = []
+ for item in self.materials:
+ if item.comment_object is not None and item.comment_object.comment:
+ items.append(item)
+ return items
+
+
+ @property
+ def number_joint_comments(self):
+ if self.joints is None:
+ return 0
+ number = 0
+ for item in self.joints:
+ if item.comment_object is not None and item.comment_object.comment:
+ number += 1
+ return number
+
+ @property
+ def joint_comments(self):
+ if self.joints is None:
+ return None
+ items = []
+ for item in self.joints:
+ if item.comment_object is not None and item.comment_object.comment:
+ items.append(item)
+ return items
+
+
+ @property
+ def has_model_comment(self):
+ if self.comment_object is not None and self.comment_object.comment:
+ return 1
+ return 0
+
+ @property
+ def comment_object(self):
+ return self._comment_object
+
+
+ @property
+ def vertex_ex(self):
+ if not self.sub_version_vertex_extra:
+ return None
+ return [item.vertex_ex_object for item in self.vertices]
+
+ @property
+ def joint_ex(self):
+ if not self.sub_version_joint_extra:
+ return None
+ return [item.joint_ex_object for item in self.joints]
+
+ @property
+ def model_ex_object(self):
+ if not self.sub_version_model_extra:
+ return None
+ return self._model_ex_object
+
+
+ def print_internal(self):
+ print()
+ print("##############################################################")
+ print("## the internal data of Ms3dModel object...")
+ print("##")
+
+ print("header={}".format(self.header))
+
+ print("number_vertices={}".format(self.number_vertices))
+ print("vertices=[", end="")
+ if self.vertices:
+ for obj in self.vertices:
+ print("{}".format(obj), end="")
+ print("]")
+
+ print("number_triangles={}".format(self.number_triangles))
+ print("triangles=[", end="")
+ if self.triangles:
+ for obj in self.triangles:
+ print("{}".format(obj), end="")
+ print("]")
+
+ print("number_groups={}".format(self.number_groups))
+ print("groups=[", end="")
+ if self.groups:
+ for obj in self.groups:
+ print("{}".format(obj), end="")
+ print("]")
+
+ print("number_materials={}".format(self.number_materials))
+ print("materials=[", end="")
+ if self.materials:
+ for obj in self.materials:
+ print("{}".format(obj), end="")
+ print("]")
+
+ print("animation_fps={}".format(self.animation_fps))
+ print("current_time={}".format(self.current_time))
+ print("number_total_frames={}".format(self.number_total_frames))
+
+ print("number_joints={}".format(self.number_joints))
+ print("joints=[", end="")
+ if self.joints:
+ for obj in self.joints:
+ print("{}".format(obj), end="")
+ print("]")
+
+ print("sub_version_comments={}".format(self.sub_version_comments))
+
+ print("number_group_comments={}".format(self.number_group_comments))
+ print("group_comments=[", end="")
+ if self.group_comments:
+ for obj in self.group_comments:
+ print("{}".format(obj.comment_object), end="")
+ print("]")
+
+ print("number_material_comments={}".format(
+ self.number_material_comments))
+ print("material_comments=[", end="")
+ if self.material_comments:
+ for obj in self.material_comments:
+ print("{}".format(obj.comment_object), end="")
+ print("]")
+
+ print("number_joint_comments={}".format(self.number_joint_comments))
+ print("joint_comments=[", end="")
+ if self.joint_comments:
+ for obj in self.joint_comments:
+ print("{}".format(obj.comment_object), end="")
+ print("]")
+
+ print("has_model_comment={}".format(self.has_model_comment))
+ print("model_comment={}".format(self.comment_object))
+
+ print("sub_version_vertex_extra={}".format(
+ self.sub_version_vertex_extra))
+ print("vertex_ex=[", end="")
+ if self.vertex_ex:
+ for obj in self.vertex_ex:
+ print("{}".format(obj), end="")
+ print("]")
+
+ print("sub_version_joint_extra={}".format(
+ self.sub_version_joint_extra))
+ print("joint_ex=[", end="")
+ if self.joint_ex:
+ for obj in self.joint_ex:
+ print("{}".format(obj), end="")
+ print("]")
+
+ print("sub_version_model_extra={}".format(
+ self.sub_version_model_extra))
+ print("model_ex={}".format(self.model_ex_object))
+
+ print("##")
+ print("## ...end")
+ print("##############################################################")
+ print()
+
+
+ def read(self, raw_io):
+ """
+ opens, reads and pars MS3D file.
+ add content to blender scene
+ """
+
+ self.header.read(raw_io)
+ if (self.header != Ms3dHeader()):
+ print("\nwarning, invalid file header")
+
+ _number_vertices = Ms3dIo.read_word(raw_io)
+ if (_number_vertices > Ms3dSpec.MAX_VERTICES):
+ print("\nwarning, invalid count: number_vertices: {}".format(
+ _number_vertices))
+ self._vertices = []
+ for i in range(_number_vertices):
+ self.vertices.append(Ms3dVertex().read(raw_io))
+
+ _number_triangles = Ms3dIo.read_word(raw_io)
+ if (_number_triangles > Ms3dSpec.MAX_TRIANGLES):
+ print("\nwarning, invalid count: number_triangles: {}".format(
+ _number_triangles))
+ self._triangles = []
+ for i in range(_number_triangles):
+ self.triangles.append(Ms3dTriangle().read(raw_io))
+
+ _number_groups = Ms3dIo.read_word(raw_io)
+ if (_number_groups > Ms3dSpec.MAX_GROUPS):
+ print("\nwarning, invalid count: number_groups: {}".format(
+ _number_groups))
+ self._groups = []
+ for i in range(_number_groups):
+ self.groups.append(Ms3dGroup().read(raw_io))
+
+ _number_materials = Ms3dIo.read_word(raw_io)
+ if (_number_materials > Ms3dSpec.MAX_MATERIALS):
+ print("\nwarning, invalid count: number_materials: {}".format(
+ _number_materials))
+ self._materials = []
+ for i in range(_number_materials):
+ self.materials.append(Ms3dMaterial().read(raw_io))
+
+ self.animation_fps = Ms3dIo.read_float(raw_io)
+ self.current_time = Ms3dIo.read_float(raw_io)
+ self.number_total_frames = Ms3dIo.read_dword(raw_io)
+
+ _progress = set()
+
+ try:
+ # optional data
+ # doesn't matter if doesn't existing.
+
+ _number_joints = Ms3dIo.read_word(raw_io)
+ _progress.add('NUMBER_JOINTS')
+ if (_number_joints > Ms3dSpec.MAX_JOINTS):
+ print("\nwarning, invalid count: number_joints: {}".format(
+ _number_joints))
+ self._joints = []
+ for i in range(_number_joints):
+ self.joints.append(Ms3dJoint().read(raw_io))
+ _progress.add('JOINTS')
+
+ self.sub_version_comments = Ms3dIo.read_dword(raw_io)
+ _progress.add('SUB_VERSION_COMMENTS')
+ _number_group_comments = Ms3dIo.read_dword(raw_io)
+ _progress.add('NUMBER_GROUP_COMMENTS')
+ if (_number_group_comments > Ms3dSpec.MAX_GROUPS):
+ print("\nwarning, invalid count:"\
+ " number_group_comments: {}".format(
+ _number_group_comments))
+ if _number_group_comments > _number_groups:
+ print("\nwarning, invalid count:"\
+ " number_group_comments: {}, number_groups: {}".format(
+ _number_group_comments, _number_groups))
+ for i in range(_number_group_comments):
+ item = Ms3dCommentEx().read(raw_io)
+ if item.index >= 0 and item.index < _number_groups:
+ self.groups[item.index]._comment_object = item
+ else:
+ print("\nwarning, invalid index:"\
+ " group_index: {}, number_groups: {}".format(
+ item.index, _number_groups))
+ _progress.add('GROUP_COMMENTS')
+
+ _number_material_comments = Ms3dIo.read_dword(raw_io)
+ _progress.add('NUMBER_MATERIAL_COMMENTS')
+ if (_number_material_comments > Ms3dSpec.MAX_MATERIALS):
+ print("\nwarning, invalid count:"\
+ " number_material_comments: {}".format(
+ _number_material_comments))
+ if _number_material_comments > _number_materials:
+ print("\nwarning, invalid count:"\
+ " number_material_comments:"\
+ " {}, number_materials: {}".format(
+ _number_material_comments, _number_materials))
+ for i in range(_number_material_comments):
+ item = Ms3dCommentEx().read(raw_io)
+ if item.index >= 0 and item.index < _number_materials:
+ self.materials[item.index]._comment_object = item
+ else:
+ print("\nwarning, invalid index:"\
+ " material_index: {}, number_materials:"\
+ " {}".format(item.index, _number_materials))
+ _progress.add('MATERIAL_COMMENTS')
+
+ _number_joint_comments = Ms3dIo.read_dword(raw_io)
+ _progress.add('NUMBER_JOINT_COMMENTS')
+ if (_number_joint_comments > Ms3dSpec.MAX_JOINTS):
+ print("\nwarning, invalid count:"\
+ " number_joint_comments: {}".format(
+ _number_joint_comments))
+ if _number_joint_comments > _number_joints:
+ print("\nwarning, invalid count:"\
+ " number_joint_comments: {}, number_joints: {}".format(
+ _number_joint_comments, _number_joints))
+ for i in range(_number_joint_comments):
+ item = Ms3dCommentEx().read(raw_io)
+ if item.index >= 0 and item.index < _number_joints:
+ self.joints[item.index]._comment_object = item
+ else:
+ print("\nwarning, invalid index:"\
+ " joint_index: {}, number_joints: {}".format(
+ item.index, _number_joints))
+ _progress.add('JOINT_COMMENTS')
+
+ _has_model_comment = Ms3dIo.read_dword(raw_io)
+ _progress.add('HAS_MODEL_COMMENTS')
+ if (_has_model_comment != 0):
+ self._comment_object = Ms3dComment().read(raw_io)
+ else:
+ self._comment_object = None
+ _progress.add('MODEL_COMMENTS')
+
+ self.sub_version_vertex_extra = Ms3dIo.read_dword(raw_io)
+ _progress.add('SUB_VERSION_VERTEX_EXTRA')
+ if self.sub_version_vertex_extra > 0:
+ length = len(self.joints)
+ for i in range(_number_vertices):
+ if self.sub_version_vertex_extra == 1:
+ item = Ms3dVertexEx1()
+ elif self.sub_version_vertex_extra == 2:
+ item = Ms3dVertexEx2()
+ elif self.sub_version_vertex_extra == 3:
+ item = Ms3dVertexEx3()
+ else:
+ print("\nwarning, invalid version:"\
+ " sub_version_vertex_extra: {}".format(
+ sub_version_vertex_extra))
+ continue
+ self.vertices[i]._vertex_ex_object = item.read(raw_io)
+ _progress.add('VERTEX_EXTRA')
+
+ self.sub_version_joint_extra = Ms3dIo.read_dword(raw_io)
+ _progress.add('SUB_VERSION_JOINT_EXTRA')
+ if self.sub_version_joint_extra > 0:
+ for i in range(_number_joints):
+ self.joints[i]._joint_ex_object = Ms3dJointEx().read(raw_io)
+ _progress.add('JOINT_EXTRA')
+
+ self.sub_version_model_extra = Ms3dIo.read_dword(raw_io)
+ _progress.add('SUB_VERSION_MODEL_EXTRA')
+ if self.sub_version_model_extra > 0:
+ self._model_ex_object.read(raw_io)
+ _progress.add('MODEL_EXTRA')
+
+ except EOFError:
+ # reached end of optional data.
+ print("Ms3dModel.read - optional data read: {}".format(_progress))
+ pass
+
+ except Exception:
+ type, value, traceback = exc_info()
+ print("Ms3dModel.read - exception in optional try block,"
+ " _progress={0}\n type: '{1}'\n value: '{2}'".format(
+ _progress, type, value, traceback))
+
+ else:
+ pass
+
+ # try best to continue far as possible
+ if not 'JOINTS' in _progress:
+ _number_joints = 0
+ self._joints = []
+
+ if not 'GROUP_COMMENTS' in _progress:
+ self.sub_version_comments = 0
+ _number_group_comments = 0
+
+ if not 'MATERIAL_COMMENTS' in _progress:
+ _number_material_comments = 0
+
+ if not 'JOINT_COMMENTS' in _progress:
+ _number_joint_comments = 0
+
+ if not 'MODEL_COMMENTS' in _progress:
+ _has_model_comment = 0
+ self._comment_object = None # Ms3dComment()
+
+ if not 'VERTEX_EXTRA' in _progress:
+ self.sub_version_vertex_extra = 0
+
+ if not 'JOINT_EXTRA' in _progress:
+ self.sub_version_joint_extra = 0
+
+ if not 'MODEL_EXTRA' in _progress:
+ self.sub_version_model_extra = 0
+ self._model_ex_object = Ms3dModelEx()
+
+ return
+
+
+ def write(self, raw_io):
+ """
+ add blender scene content to MS3D
+ creates, writes MS3D file.
+ """
+
+ self.header.write(raw_io)
+
+ Ms3dIo.write_word(raw_io, self.number_vertices)
+ for i in range(self.number_vertices):
+ self.vertices[i].write(raw_io)
+
+ Ms3dIo.write_word(raw_io, self.number_triangles)
+ for i in range(self.number_triangles):
+ self.triangles[i].write(raw_io)
+
+ Ms3dIo.write_word(raw_io, self.number_groups)
+ for i in range(self.number_groups):
+ self.groups[i].write(raw_io)
+
+ Ms3dIo.write_word(raw_io, self.number_materials)
+ for i in range(self.number_materials):
+ self.materials[i].write(raw_io)
+
+ Ms3dIo.write_float(raw_io, self.animation_fps)
+ Ms3dIo.write_float(raw_io, self.current_time)
+ Ms3dIo.write_dword(raw_io, self.number_total_frames)
+
+ try:
+ # optional part
+ # doesn't matter if it doesn't complete.
+ Ms3dIo.write_word(raw_io, self.number_joints)
+ for i in range(self.number_joints):
+ self.joints[i].write(raw_io)
+
+ Ms3dIo.write_dword(raw_io, self.sub_version_comments)
+
+ Ms3dIo.write_dword(raw_io, self.number_group_comments)
+ for i in range(self.number_group_comments):
+ self.group_comments[i].comment_object.write(raw_io)
+
+ Ms3dIo.write_dword(raw_io, self.number_material_comments)
+ for i in range(self.number_material_comments):
+ self.material_comments[i].comment_object.write(raw_io)
+
+ Ms3dIo.write_dword(raw_io, self.number_joint_comments)
+ for i in range(self.number_joint_comments):
+ self.joint_comments[i].comment_object.write(raw_io)
+
+ Ms3dIo.write_dword(raw_io, self.has_model_comment)
+ if (self.has_model_comment != 0):
+ self.comment_object.write(raw_io)
+
+ Ms3dIo.write_dword(raw_io, self.sub_version_vertex_extra)
+ if (self.sub_version_vertex_extra in {1, 2, 3}):
+ for i in range(self.number_vertices):
+ self.vertex_ex[i].write(raw_io)
+
+ Ms3dIo.write_dword(raw_io, self.sub_version_joint_extra)
+ for i in range(self.number_joints):
+ self.joint_ex[i].write(raw_io)
+
+ Ms3dIo.write_dword(raw_io, self.sub_version_model_extra)
+ self.model_ex_object.write(raw_io)
+
+ except Exception:
+ type, value, traceback = exc_info()
+ print("Ms3dModel.write - exception in optional try block"
+ "\n type: '{0}'\n value: '{1}'".format(
+ type, value, traceback))
+ pass
+
+ else:
+ pass
+
+ return
+
+
+ def is_valid(self):
+ valid = True
+ result = []
+
+ format1 = "\n number of {0}: {1}"
+ format2 = " limit exceeded! (limit is {0})"
+
+ result.append("MS3D statistics:")
+ result.append(format1.format("vertices ........",
+ self.number_vertices))
+ if (self.number_vertices > Ms3dSpec.MAX_VERTICES):
+ result.append(format2.format(Ms3dSpec.MAX_VERTICES))
+ valid &= False
+
+ result.append(format1.format("triangles .......",
+ self.number_triangles))
+ if (self.number_triangles > Ms3dSpec.MAX_TRIANGLES):
+ result.append(format2.format(Ms3dSpec.MAX_TRIANGLES))
+ valid &= False
+
+ result.append(format1.format("groups ..........",
+ self.number_groups))
+ if (self.number_groups > Ms3dSpec.MAX_GROUPS):
+ result.append(format2.format(Ms3dSpec.MAX_GROUPS))
+ valid &= False
+
+ result.append(format1.format("materials .......",
+ self.number_materials))
+ if (self.number_materials > Ms3dSpec.MAX_MATERIALS):
+ result.append(format2.format(Ms3dSpec.MAX_MATERIALS))
+ valid &= False
+
+ result.append(format1.format("joints ..........",
+ self.number_joints))
+ if (self.number_joints > Ms3dSpec.MAX_JOINTS):
+ result.append(format2.format(Ms3dSpec.MAX_JOINTS))
+ valid &= False
+
+ result.append(format1.format("model comments ..",
+ self.has_model_comment))
+ result.append(format1.format("group comments ..",
+ self.number_group_comments))
+ result.append(format1.format("material comments",
+ self.number_material_comments))
+ result.append(format1.format("joint comments ..",
+ self.number_joint_comments))
+
+ #if (not valid):
+ # result.append("\n\nthe data may be corrupted.")
+
+ return (valid, ("".join(result)))
+
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+# ##### END OF FILE #####
diff --git a/io_scene_ms3d/ms3d_strings.py b/io_scene_ms3d/ms3d_strings.py
new file mode 100644
index 00000000..84a5a568
--- /dev/null
+++ b/io_scene_ms3d/ms3d_strings.py
@@ -0,0 +1,263 @@
+# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+
+
+# ##### BEGIN COPYRIGHT BLOCK #####
+#
+# initial script copyright (c)2011,2012 Alexander Nussbaumer
+#
+# ##### END COPYRIGHT BLOCK #####
+SEE_MS3D_DOC = "see MilkShape 3D documentation"
+
+ms3d_str = {
+ 'lang': "en-US",
+ 'RUNTIME_KEY': "Human friendly presentation",
+
+ ###############################
+ # blender key names
+ 'OBJECT_LAYER_EXTRA': "ms3d_extra_layer",
+ 'OBJECT_LAYER_GROUP': "ms3d_group_layer",
+ 'OBJECT_LAYER_SMOOTHING_GROUP': "ms3d_smoothing_group_layer",
+ 'OBJECT_MODIFIER_SMOOTHING_GROUP': "ms3d_smoothing_groups",
+ # for some reason after bm.to_mesh(..)
+ # the names of 'bm.loops.layers.uv' becomes to 'bm.faces.layers.tex'
+ # to bypass this issue, i give both the same name.
+ # 'OBJECT_LAYER_TEXTURE': "ms3d_texture_layer",
+ 'OBJECT_LAYER_TEXTURE': "ms3d_uv_layer",
+ 'OBJECT_LAYER_UV': "ms3d_uv_layer",
+
+ ###############################
+ # strings to be used with 'str().format()'
+ 'STRING_FORMAT_GROUP': "Group.{:03d}",
+ 'WARNING_IMPORT_SKIP_FACE_DOUBLE': "skipped face #{}:"\
+ " contains double faces with same vertices!",
+ 'WARNING_IMPORT_SKIP_LESS_VERTICES': "skipped face #{}:"\
+ " contains faces too less vertices!",
+ 'WARNING_IMPORT_SKIP_VERTEX_DOUBLE': "skipped face #{}:"\
+ " contains faces with double vertices!",
+ 'WARNING_IMPORT_EXTRA_VERTEX_NORMAL': "created extra vertex"\
+ " because of different normals #{} -> {}.",
+ 'SUMMARY_IMPORT': "elapsed time: {0:.4}s (media io:"\
+ " ~{1:.4}s, converter: ~{2:.4}s)",
+ 'SUMMARY_EXPORT': "elapsed time: {0:.4}s (converter:"\
+ " ~{1:.4}s, media io: ~{2:.4}s)",
+ 'WARNING_EXPORT_SKIP_WEIGHT' : "skipped weight",
+ 'WARNING_EXPORT_SKIP_WEIGHT_EX' : "skipped weight:"\
+ " limit exceeded",
+
+ ###############################
+ 'TEXT_OPERATOR': "MilkShape 3D (.ms3d)",
+ 'FILE_EXT': ".ms3d",
+ 'FILE_FILTER': "*.ms3d",
+ 'BL_DESCRIPTION_EXPORTER': "Export to a MilkShape 3D file format (.ms3d)",
+ 'BL_DESCRIPTION_IMPORTER': "Import from a MilkShape 3D file format (.ms3d)",
+ 'BL_LABEL_EXPORTER': "Export MS3D",
+ 'BL_LABEL_GROUP_OPERATOR': "MS3D - Group Collection Operator",
+ 'BL_LABEL_IMPORTER': "Import MS3D",
+ 'BL_LABEL_PANEL_SMOOTHING_GROUP': "MS3D - Smoothing Group",
+ 'BL_LABEL_SMOOTHING_GROUP_OPERATOR': "MS3D Set Smoothing Group"\
+ " Operator",
+ 'BL_LABEL_MATERIAL_OPERATOR' : "MS3D - Copy Material Operator",
+ 'ENUM_ADD_GROUP_1': "Add",
+ 'ENUM_ADD_GROUP_2': "adds an item",
+ 'ENUM_ASSIGN_1': "Assign",
+ 'ENUM_ASSIGN_2_GROUP': "assign selected faces to selected group",
+ 'ENUM_ASSIGN_2_SMOOTHING_GROUP': "assign all selected faces to"\
+ " selected smoothing group",
+ 'ENUM_DESELECT_1': "Deselect",
+ 'ENUM_DESELECT_2_GROUP': "deselects faces of selected group",
+ 'ENUM_DESELECT_2_SMOOTHING_GROUP': "deselects all faces of selected"\
+ " smoothing group",
+ 'ENUM_FLAG_DIRTY_1': "Dirty",
+ 'ENUM_FLAG_DIRTY_2': SEE_MS3D_DOC,
+ 'ENUM_FLAG_HIDDEN_1': "Hidden",
+ 'ENUM_FLAG_HIDDEN_2': SEE_MS3D_DOC,
+ 'ENUM_FLAG_ISKEY_1': "Is Key",
+ 'ENUM_FLAG_ISKEY_2': SEE_MS3D_DOC,
+ 'ENUM_FLAG_MARKED_1': "Marked",
+ 'ENUM_FLAG_MARKED_2': SEE_MS3D_DOC,
+ 'ENUM_FLAG_NEWLYCREATED_1': "Newly Created",
+ 'ENUM_FLAG_NEWLYCREATED_2': SEE_MS3D_DOC,
+ 'ENUM_FLAG_NONE_1': "None",
+ 'ENUM_FLAG_NONE_2': SEE_MS3D_DOC,
+ 'ENUM_FLAG_SELECTED_1': "Selected",
+ 'ENUM_FLAG_SELECTED_2': SEE_MS3D_DOC,
+ 'ENUM_FLAG_SELECTED2_1': "Selected Ex.",
+ 'ENUM_FLAG_SELECTED2_2': SEE_MS3D_DOC,
+ 'ENUM_REMOVE_1': "Remove",
+ 'ENUM_REMOVE_2_GROUP': "remove selected faces from selected group",
+ 'ENUM_REMOVE_GROUP_1': "Remove",
+ 'ENUM_REMOVE_GROUP_2': "removes an item",
+ 'ENUM_SELECT_1': "Select",
+ 'ENUM_SELECT_2_GROUP': "selects faces of selected group",
+ 'ENUM_SELECT_2_SMOOTHING_GROUP': "selects all faces of selected"\
+ " smoothing group",
+ 'LABEL_NAME_ANIMATION': "Animation Processing:",
+ 'LABEL_NAME_OBJECT': "World Processing:",
+ 'LABEL_NAME_OPTIONS': "Advanced Options:",
+ 'LABEL_NAME_PROCESSING': "Object Processing:",
+ 'LABEL_NAME_MODIFIER': "Modifier Processing:",
+ 'LABEL_PANEL_BUTTON_NONE': "None",
+ 'LABEL_PANEL_GROUPS': "MS3D - Groups",
+ 'LABEL_PANEL_JOINTS': "MS3D - Joint",
+ 'LABEL_PANEL_MATERIALS': "MS3D - Material",
+ 'LABEL_PANEL_MODEL': "MS3D - Model",
+ 'PROP_DESC_ALPHA_REF': "ms3d internal raw 'alpha_ref' of Model",
+ 'PROP_DESC_ALPHAMAP': "ms3d internal raw 'alphamap' file name of"\
+ " Material",
+ 'PROP_DESC_AMBIENT': "ms3d internal raw 'ambient' of Material",
+ 'PROP_DESC_USE_ANIMATION': "keyframes (rotations, positions)",
+ 'PROP_DESC_COLOR_JOINT': "ms3d internal raw 'color' of Joint",
+ 'PROP_DESC_COMMENT_GROUP': "ms3d internal raw 'comment' of Group",
+ 'PROP_DESC_COMMENT_JOINT': "ms3d internal raw 'comment' of Joint",
+ 'PROP_DESC_COMMENT_MATERIAL': "ms3d internal raw 'comment' of Material",
+ 'PROP_DESC_COMMENT_MODEL': "ms3d internal raw 'comment' of Model",
+ 'PROP_DESC_DIFFUSE': "ms3d internal raw 'diffuse' of Material",
+ 'PROP_DESC_EMISSIVE': "ms3d internal raw 'emissive' of Material",
+ 'PROP_DESC_FLAGS_GROUP': "ms3d internal raw 'flags' of Group",
+ 'PROP_DESC_FLAGS_JOINT': "ms3d internal raw 'flags' of Joint",
+ 'PROP_DESC_GROUP_NAME': "ms3d internal raw 'name' of Group",
+ 'PROP_DESC_JOINT_SIZE': "ms3d internal raw 'joint_size' of Model",
+ 'PROP_DESC_MODE_TEXTURE': "ms3d internal raw 'mode' of Material",
+ 'PROP_DESC_NAME_ARMATURE': "ms3d internal raw 'name' of Model (not used"\
+ " for export)",
+ 'PROP_DESC_NAME_JOINT': "ms3d internal raw 'name' of Joint",
+ 'PROP_DESC_NAME_MATERIAL': "ms3d internal raw 'name' of Material",
+ 'PROP_DESC_NAME_MODEL': "ms3d internal raw 'name' of Model (not used for export)",
+ 'PROP_DESC_SHININESS': "ms3d internal raw 'shininess' of Material",
+ 'PROP_DESC_SPECULAR': "ms3d internal raw 'specular' of Material",
+ 'PROP_DESC_TEXTURE': "ms3d internal raw 'texture' file name of"\
+ " Material",
+ 'PROP_DESC_TRANSPARENCY': "ms3d internal raw 'transparency' of"\
+ " Material",
+ 'PROP_DESC_TRANSPARENCY_MODE': "ms3d internal raw 'transparency_mode'"\
+ " of Model",
+ 'PROP_DESC_VERBOSE': "Run the converter in debug mode."\
+ " Check the console for output (Warning, may be very slow)",
+ 'PROP_FLAG_TEXTURE_COMBINE_ALPHA_1': "Combine Alpha",
+ 'PROP_FLAG_TEXTURE_COMBINE_ALPHA_2': SEE_MS3D_DOC,
+ 'PROP_FLAG_TEXTURE_HAS_ALPHA_1': "Has Alpha",
+ 'PROP_FLAG_TEXTURE_HAS_ALPHA_2': SEE_MS3D_DOC,
+ 'PROP_FLAG_TEXTURE_SPHERE_MAP_1': "Sphere Map",
+ 'PROP_FLAG_TEXTURE_SPHERE_MAP_2': SEE_MS3D_DOC,
+ 'PROP_MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF_1': "Depth"\
+ " Buffered with Alpha Ref",
+ 'PROP_MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF_2': SEE_MS3D_DOC,
+ 'PROP_MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES_1': "Depth Sorted"\
+ " Triangles",
+ 'PROP_MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES_2': SEE_MS3D_DOC,
+ 'PROP_MODE_TRANSPARENCY_SIMPLE_1': "Simple",
+ 'PROP_MODE_TRANSPARENCY_SIMPLE_2': SEE_MS3D_DOC,
+ 'PROP_NAME_ALPHA_REF': "Alpha Ref.",
+ 'PROP_NAME_ALPHAMAP': "Alphamap",
+ 'PROP_NAME_AMBIENT': "Ambient",
+ 'PROP_NAME_USE_ANIMATION': "Animation",
+ 'PROP_NAME_COLOR': "Color",
+ 'PROP_NAME_COMMENT': "Comment",
+ 'PROP_NAME_DIFFUSE': "Diffuse",
+ 'PROP_NAME_EMISSIVE': "Emissive",
+ 'PROP_NAME_FLAGS': "Flags",
+ 'PROP_NAME_JOINT_SIZE': "Joint Size",
+ 'PROP_NAME_MODE': "Mode",
+ 'PROP_NAME_NAME': "Name",
+ 'PROP_NAME_ACTIVE': "Active Mesh:",
+ 'PROP_NAME_SHININESS': "Shininess",
+ 'PROP_NAME_SPECULAR': "Specular",
+ 'PROP_NAME_TEXTURE': "Texture",
+ 'PROP_NAME_TRANSPARENCY': "Transparency",
+ 'PROP_NAME_TRANSPARENCY_MODE': "Transp. Mode",
+ 'PROP_NAME_VERBOSE': "Verbose",
+ 'PROP_SMOOTHING_GROUP_INDEX': "Smoothing group id",
+ 'PROP_NAME_ROTATION_MODE' : "Bone Rotation Mode",
+ 'PROP_DESC_ROTATION_MODE' : "set the preferred rotation mode of bones",
+ 'PROP_ITEM_ROTATION_MODE_EULER_1' : "Euler",
+ 'PROP_ITEM_ROTATION_MODE_EULER_2' : "use euler bone rotation"\
+ " (gimbal-lock can be fixed by using "\
+ "'Graph Editor -> Key -> Discontinuity (Euler) Filter')",
+ 'PROP_ITEM_ROTATION_MODE_QUATERNION_1' : "Quaternion",
+ 'PROP_ITEM_ROTATION_MODE_QUATERNION_2' : "use quaternion bone rotation"\
+ " (no gimbal-lock filter available!)",
+ 'PROP_NAME_USE_JOINT_SIZE': "Override Joint Size",
+ 'PROP_DESC_USE_JOINT_SIZE': "use value of 'Joint Size', the value of the"\
+ " ms3d file is ignored for representation.",
+ 'PROP_NAME_IMPORT_JOINT_SIZE': "Joint Size",
+ 'PROP_DESC_IMPORT_JOINT_SIZE': "size of the joint representation in"\
+ " blender",
+ 'BL_LABEL_SET_SCENE_TO_METRIC' : "Set Scene to 'Metric' [1 mm]",
+ 'BL_DESC_SET_SCENE_TO_METRIC' : "set Scene | Units to Metric"\
+ " (1 Unit = 1 mm),"\
+ " Display | Textured Solid,"\
+ " View | Clip (0.001 mm ... 1 km)",
+ 'PROP_NAME_NORMALIZE_WEIGHTS' : "Normalize Weights",
+ 'PROP_DESC_NORMALIZE_WEIGHTS' : "normalize weights to 100%,"\
+ " when its sum of weights is greater than 100%",
+ 'PROP_NAME_SHRINK_TO_KEYS' : "Shrink To Keys",
+ 'PROP_DESC_SHRINK_TO_KEYS' : "shrinks the animation to region from"\
+ " first keyframe to last keyframe",
+ 'PROP_NAME_BAKE_EACH_FRAME' : "Bake Each Frame As Key",
+ 'PROP_DESC_BAKE_EACH_FRAME' : "if enabled, to each frame there will be"\
+ " a key baked",
+ 'LABEL_NAME_JOINT_TO_BONES' : "works only with some models!",
+ 'PROP_NAME_JOINT_TO_BONES' : "Joints To Bones",
+ 'PROP_DESC_JOINT_TO_BONES' : "changes the length of the bones",
+ 'PROP_NAME_USE_BLENDER_NAMES' : "Use Blender Names Only",
+ 'PROP_DESC_USE_BLENDER_NAMES' : "use only blender names, ignores ms3d"\
+ " names (bone names will always be taken from blender)",
+ 'PROP_NAME_USE_BLENDER_MATERIALS' : "Use Blender Materials",
+ 'PROP_DESC_USE_BLENDER_MATERIALS' : "ignores ms3d material definition"\
+ " (you loose some information by choosing this option)",
+ 'ENUM_FROM_BLENDER_1' : "Copy From Blender",
+ 'ENUM_FROM_BLENDER_2' : "takes and copies all available values from"\
+ " blender",
+ 'ENUM_TO_BLENDER_1' : "Copy To Blender",
+ 'ENUM_TO_BLENDER_2' : "copies and puts all available values to blender",
+ 'PROP_NAME_EXTENDED_NORMAL_HANDLING': "Extended Normal Handling",
+ 'PROP_DESC_EXTENDED_NORMAL_HANDLING': "adds extra vertices if normals"\
+ " are different",
+ 'PROP_NAME_APPLY_TRANSFORM': "Apply Transform",
+ 'PROP_DESC_APPLY_TRANSFORM': "applies location, rotation and scale on"\
+ " export",
+ 'PROP_NAME_APPLY_MODIFIERS': "Apply Modifiers",
+ 'PROP_DESC_APPLY_MODIFIERS': "applies modifiers on export that are"\
+ " enabled (except of armature modifiers)",
+ 'PROP_NAME_APPLY_MODIFIERS_MODE': "Apply Mode",
+ 'PROP_DESC_APPLY_MODIFIERS_MODE': "apply modifier, if enabled in its"\
+ " mode",
+ 'PROP_ITEM_APPLY_MODIFIERS_MODE_VIEW_1': "View",
+ 'PROP_ITEM_APPLY_MODIFIERS_MODE_VIEW_2': "apply modifiers that are"\
+ " enabled in viewport",
+ 'PROP_ITEM_APPLY_MODIFIERS_MODE_RENDER_1': "Render",
+ 'PROP_ITEM_APPLY_MODIFIERS_MODE_RENDER_2': "apply modifiers that are"\
+ " enabled in renderer",
+
+ 'PROP_NAME_': "Name",
+ 'PROP_DESC_': "Description",
+ # ms3d_str['']
+ }
+
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+# ##### END OF FILE #####
diff --git a/io_scene_ms3d/ms3d_ui.py b/io_scene_ms3d/ms3d_ui.py
new file mode 100644
index 00000000..b3e52b1e
--- /dev/null
+++ b/io_scene_ms3d/ms3d_ui.py
@@ -0,0 +1,1723 @@
+# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+
+
+# ##### BEGIN COPYRIGHT BLOCK #####
+#
+# initial script copyright (c)2011,2012 Alexander Nussbaumer
+#
+# ##### END COPYRIGHT BLOCK #####
+
+
+#import python stuff
+from random import (
+ randrange,
+ )
+
+
+# import io_scene_ms3d stuff
+from io_scene_ms3d.ms3d_strings import (
+ ms3d_str,
+ )
+from io_scene_ms3d.ms3d_spec import (
+ Ms3dSpec,
+ )
+from io_scene_ms3d.ms3d_utils import (
+ enable_edit_mode,
+ get_edge_split_modifier_add_if,
+ set_sence_to_metric,
+ )
+
+
+#import blender stuff
+from bmesh import (
+ from_edit_mesh,
+ )
+from bpy.utils import (
+ register_class,
+ unregister_class,
+ )
+from bpy_extras.io_utils import (
+ ExportHelper,
+ ImportHelper,
+ )
+from bpy.props import (
+ BoolProperty,
+ CollectionProperty,
+ EnumProperty,
+ FloatProperty,
+ FloatVectorProperty,
+ IntProperty,
+ StringProperty,
+ PointerProperty,
+ )
+from bpy.types import (
+ Operator,
+ PropertyGroup,
+ Panel,
+ Armature,
+ Bone,
+ Mesh,
+ Material,
+ Action,
+ Group,
+ UIList,
+ )
+from bpy.app import (
+ debug,
+ )
+
+
+class Ms3dUi:
+ DEFAULT_VERBOSE = debug
+
+ ###########################################################################
+ FLAG_TEXTURE_COMBINE_ALPHA = 'COMBINE_ALPHA'
+ FLAG_TEXTURE_HAS_ALPHA = 'HAS_ALPHA'
+ FLAG_TEXTURE_SPHERE_MAP = 'SPHERE_MAP'
+
+ @staticmethod
+ def texture_mode_from_ms3d(ms3d_value):
+ ui_value = set()
+ if (ms3d_value & Ms3dSpec.FLAG_TEXTURE_COMBINE_ALPHA) \
+ == Ms3dSpec.FLAG_TEXTURE_COMBINE_ALPHA:
+ ui_value.add(Ms3dUi.FLAG_TEXTURE_COMBINE_ALPHA)
+ if (ms3d_value & Ms3dSpec.FLAG_TEXTURE_HAS_ALPHA) \
+ == Ms3dSpec.FLAG_TEXTURE_HAS_ALPHA:
+ ui_value.add(Ms3dUi.FLAG_TEXTURE_HAS_ALPHA)
+ if (ms3d_value & Ms3dSpec.FLAG_TEXTURE_SPHERE_MAP) \
+ == Ms3dSpec.FLAG_TEXTURE_SPHERE_MAP:
+ ui_value.add(Ms3dUi.FLAG_TEXTURE_SPHERE_MAP)
+ return ui_value
+
+ @staticmethod
+ def texture_mode_to_ms3d(ui_value):
+ ms3d_value = Ms3dSpec.FLAG_TEXTURE_NONE
+
+ if Ms3dUi.FLAG_TEXTURE_COMBINE_ALPHA in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_TEXTURE_COMBINE_ALPHA
+ if Ms3dUi.FLAG_TEXTURE_HAS_ALPHA in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_TEXTURE_HAS_ALPHA
+ if Ms3dUi.FLAG_TEXTURE_SPHERE_MAP in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_TEXTURE_SPHERE_MAP
+ return ms3d_value
+
+
+ MODE_TRANSPARENCY_SIMPLE = 'SIMPLE'
+ MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF \
+ = 'DEPTH_BUFFERED_WITH_ALPHA_REF'
+ MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES = 'DEPTH_SORTED_TRIANGLES'
+
+ @staticmethod
+ def transparency_mode_from_ms3d(ms3d_value):
+ if(ms3d_value == Ms3dSpec.MODE_TRANSPARENCY_SIMPLE):
+ return Ms3dUi.MODE_TRANSPARENCY_SIMPLE
+ elif(ms3d_value == \
+ Ms3dSpec.MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF):
+ return Ms3dUi.MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF
+ elif(ms3d_value == Ms3dSpec.MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES):
+ return Ms3dUi.MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES
+ return None
+
+ @staticmethod
+ def transparency_mode_to_ms3d(ui_value):
+ if(ui_value == Ms3dUi.MODE_TRANSPARENCY_SIMPLE):
+ return Ms3dSpec.MODE_TRANSPARENCY_SIMPLE
+ elif(ui_value == Ms3dUi.MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF):
+ return Ms3dSpec.MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF
+ elif(ui_value == Ms3dUi.MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES):
+ return Ms3dSpec.MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES
+ return None
+
+
+ FLAG_NONE = 'NONE'
+ FLAG_SELECTED = 'SELECTED'
+ FLAG_HIDDEN = 'HIDDEN'
+ FLAG_SELECTED2 = 'SELECTED2'
+ FLAG_DIRTY = 'DIRTY'
+ FLAG_ISKEY = 'ISKEY'
+ FLAG_NEWLYCREATED = 'NEWLYCREATED'
+ FLAG_MARKED = 'MARKED'
+
+ @staticmethod
+ def flags_from_ms3d(ms3d_value):
+ ui_value = set()
+ if (ms3d_value & Ms3dSpec.FLAG_SELECTED) == Ms3dSpec.FLAG_SELECTED:
+ ui_value.add(Ms3dUi.FLAG_SELECTED)
+ if (ms3d_value & Ms3dSpec.FLAG_HIDDEN) == Ms3dSpec.FLAG_HIDDEN:
+ ui_value.add(Ms3dUi.FLAG_HIDDEN)
+ if (ms3d_value & Ms3dSpec.FLAG_SELECTED2) == Ms3dSpec.FLAG_SELECTED2:
+ ui_value.add(Ms3dUi.FLAG_SELECTED2)
+ if (ms3d_value & Ms3dSpec.FLAG_DIRTY) == Ms3dSpec.FLAG_DIRTY:
+ ui_value.add(Ms3dUi.FLAG_DIRTY)
+ if (ms3d_value & Ms3dSpec.FLAG_ISKEY) == Ms3dSpec.FLAG_ISKEY:
+ ui_value.add(Ms3dUi.FLAG_ISKEY)
+ if (ms3d_value & Ms3dSpec.FLAG_NEWLYCREATED) == \
+ Ms3dSpec.FLAG_NEWLYCREATED:
+ ui_value.add(Ms3dUi.FLAG_NEWLYCREATED)
+ if (ms3d_value & Ms3dSpec.FLAG_MARKED) == Ms3dSpec.FLAG_MARKED:
+ ui_value.add(Ms3dUi.FLAG_MARKED)
+ return ui_value
+
+ @staticmethod
+ def flags_to_ms3d(ui_value):
+ ms3d_value = Ms3dSpec.FLAG_NONE
+ if Ms3dUi.FLAG_SELECTED in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_SELECTED
+ if Ms3dUi.FLAG_HIDDEN in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_HIDDEN
+ if Ms3dUi.FLAG_SELECTED2 in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_SELECTED2
+ if Ms3dUi.FLAG_DIRTY in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_DIRTY
+ if Ms3dUi.FLAG_ISKEY in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_ISKEY
+ if Ms3dUi.FLAG_NEWLYCREATED in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_NEWLYCREATED
+ if Ms3dUi.FLAG_MARKED in ui_value:
+ ms3d_value |= Ms3dSpec.FLAG_MARKED
+ return ms3d_value
+
+ ###########################################################################
+ ICON_OPTIONS = 'LAMP'
+ ICON_OBJECT = 'WORLD'
+ ICON_PROCESSING = 'OBJECT_DATAMODE'
+ ICON_MODIFIER = 'MODIFIER'
+ ICON_ANIMATION = 'RENDER_ANIMATION'
+ ICON_ROTATION_MODE = 'BONE_DATA'
+ ICON_ERROR = 'ERROR'
+
+ ###########################################################################
+ PROP_DEFAULT_VERBOSE = DEFAULT_VERBOSE
+
+ ###########################################################################
+ PROP_DEFAULT_USE_JOINT_SIZE = False
+ PROP_DEFAULT_JOINT_SIZE = 0.01
+ PROP_JOINT_SIZE_MIN = 0.01
+ PROP_JOINT_SIZE_MAX = 10.0
+ PROP_JOINT_SIZE_STEP = 0.1
+ PROP_JOINT_SIZE_PRECISION = 2
+
+ ###########################################################################
+ PROP_DEFAULT_USE_ANIMATION = True
+ PROP_DEFAULT_NORMALIZE_WEIGHTS = True
+ PROP_DEFAULT_SHRINK_TO_KEYS = False
+ PROP_DEFAULT_BAKE_EACH_FRAME = True
+ PROP_DEFAULT_JOINT_TO_BONES = False
+ PROP_DEFAULT_USE_BLENDER_NAMES = True
+ PROP_DEFAULT_USE_BLENDER_MATERIALS = False
+ PROP_DEFAULT_EXTENDED_NORMAL_HANDLING = False
+ PROP_DEFAULT_APPLY_TRANSFORM = True
+ PROP_DEFAULT_APPLY_MODIFIERS = True
+
+ ###########################################################################
+ PROP_ITEM_APPLY_MODIFIERS_MODE_VIEW = 'PREVIEW'
+ PROP_ITEM_APPLY_MODIFIERS_MODE_RENDER = 'RENDER'
+ PROP_DEFAULT_APPLY_MODIFIERS_MODE = PROP_ITEM_APPLY_MODIFIERS_MODE_VIEW
+
+ ###########################################################################
+ PROP_ITEM_ROTATION_MODE_EULER = 'EULER'
+ PROP_ITEM_ROTATION_MODE_QUATERNION = 'QUATERNION'
+ PROP_DEFAULT_ANIMATION_ROTATION = PROP_ITEM_ROTATION_MODE_EULER
+
+ ###########################################################################
+ OPT_SMOOTHING_GROUP_APPLY = 'io_scene_ms3d.apply_smoothing_group'
+ OPT_GROUP_APPLY = 'io_scene_ms3d.apply_group'
+ OPT_MATERIAL_APPLY = 'io_scene_ms3d.apply_material'
+
+
+###############################################################################
+class Ms3dImportOperator(Operator, ImportHelper):
+ """ Load a MilkShape3D MS3D File """
+ bl_idname = 'import_scene.ms3d'
+ bl_label = ms3d_str['BL_LABEL_IMPORTER']
+ bl_description = ms3d_str['BL_DESCRIPTION_IMPORTER']
+ bl_options = {'PRESET', }
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+
+ filepath = StringProperty(
+ subtype='FILE_PATH',
+ options={'HIDDEN', }
+ )
+
+ verbose = BoolProperty(
+ name=ms3d_str['PROP_NAME_VERBOSE'],
+ description=ms3d_str['PROP_DESC_VERBOSE'],
+ default=Ms3dUi.PROP_DEFAULT_VERBOSE,
+ )
+
+ use_animation = BoolProperty(
+ name=ms3d_str['PROP_NAME_USE_ANIMATION'],
+ description=ms3d_str['PROP_DESC_USE_ANIMATION'],
+ default=Ms3dUi.PROP_DEFAULT_USE_ANIMATION,
+ )
+
+ rotation_mode = EnumProperty(
+ name=ms3d_str['PROP_NAME_ROTATION_MODE'],
+ description=ms3d_str['PROP_DESC_ROTATION_MODE'],
+ items=( (Ms3dUi.PROP_ITEM_ROTATION_MODE_EULER,
+ ms3d_str['PROP_ITEM_ROTATION_MODE_EULER_1'],
+ ms3d_str['PROP_ITEM_ROTATION_MODE_EULER_2']),
+ (Ms3dUi.PROP_ITEM_ROTATION_MODE_QUATERNION,
+ ms3d_str['PROP_ITEM_ROTATION_MODE_QUATERNION_1'],
+ ms3d_str['PROP_ITEM_ROTATION_MODE_QUATERNION_2']),
+ ),
+ default=Ms3dUi.PROP_DEFAULT_ANIMATION_ROTATION,
+ )
+
+ use_joint_size = BoolProperty(
+ name=ms3d_str['PROP_NAME_USE_JOINT_SIZE'],
+ description=ms3d_str['PROP_DESC_USE_JOINT_SIZE'],
+ default=Ms3dUi.PROP_DEFAULT_USE_JOINT_SIZE,
+ )
+
+ joint_size = FloatProperty(
+ name=ms3d_str['PROP_NAME_IMPORT_JOINT_SIZE'],
+ description=ms3d_str['PROP_DESC_IMPORT_JOINT_SIZE'],
+ min=Ms3dUi.PROP_JOINT_SIZE_MIN, max=Ms3dUi.PROP_JOINT_SIZE_MAX,
+ precision=Ms3dUi.PROP_JOINT_SIZE_PRECISION, \
+ step=Ms3dUi.PROP_JOINT_SIZE_STEP,
+ default=Ms3dUi.PROP_DEFAULT_JOINT_SIZE,
+ subtype='FACTOR',
+ #options={'HIDDEN', },
+ )
+
+ use_joint_to_bones = BoolProperty(
+ name=ms3d_str['PROP_NAME_JOINT_TO_BONES'],
+ description=ms3d_str['PROP_DESC_JOINT_TO_BONES'],
+ default=Ms3dUi.PROP_DEFAULT_JOINT_TO_BONES,
+ )
+
+ use_extended_normal_handling = BoolProperty(
+ name=ms3d_str['PROP_NAME_EXTENDED_NORMAL_HANDLING'],
+ description=ms3d_str['PROP_DESC_EXTENDED_NORMAL_HANDLING'],
+ default=Ms3dUi.PROP_DEFAULT_EXTENDED_NORMAL_HANDLING,
+ )
+
+ filename_ext = StringProperty(
+ default=ms3d_str['FILE_EXT'],
+ options={'HIDDEN', }
+ )
+
+ filter_glob = StringProperty(
+ default=ms3d_str['FILE_FILTER'],
+ options={'HIDDEN', }
+ )
+
+
+ @property
+ def use_euler_rotation(self):
+ return (Ms3dUi.PROP_ITEM_ROTATION_MODE_EULER \
+ in self.rotation_mode)
+
+ @property
+ def use_quaternion_rotation(self):
+ return (Ms3dUi.PROP_ITEM_ROTATION_MODE_QUATERNION \
+ in self.rotation_mode)
+
+
+ # draw the option panel
+ def draw(self, blender_context):
+ layout = self.layout
+
+ box = layout.box()
+ box.label(ms3d_str['LABEL_NAME_OPTIONS'], icon=Ms3dUi.ICON_OPTIONS)
+ box.prop(self, 'verbose', icon='SPEAKER')
+
+ box = layout.box()
+ box.label(ms3d_str['LABEL_NAME_PROCESSING'],
+ icon=Ms3dUi.ICON_PROCESSING)
+ box.prop(self, 'use_extended_normal_handling')
+
+ box = layout.box()
+ box.label(ms3d_str['LABEL_NAME_ANIMATION'], icon=Ms3dUi.ICON_ANIMATION)
+ box.prop(self, 'use_animation')
+ if (self.use_animation):
+ box.prop(self, 'rotation_mode', icon=Ms3dUi.ICON_ROTATION_MODE,
+ expand=False)
+ box.prop(self, 'use_joint_size')
+ if (self.use_joint_size):
+ col = box.column()
+ row = col.row()
+ row.prop(self, 'joint_size')
+ box.prop(self, 'use_joint_to_bones')
+ if (self.use_joint_to_bones):
+ box.box().label(ms3d_str['LABEL_NAME_JOINT_TO_BONES'],
+ icon=Ms3dUi.ICON_ERROR)
+
+ # entrypoint for MS3D -> blender
+ def execute(self, blender_context):
+ """ start executing """
+ from io_scene_ms3d.ms3d_import import (Ms3dImporter, )
+ return Ms3dImporter(
+ report=self.report,
+ verbose=self.verbose,
+ use_extended_normal_handling=self.use_extended_normal_handling,
+ use_animation=self.use_animation,
+ use_quaternion_rotation=self.use_quaternion_rotation,
+ use_joint_size=self.use_joint_size,
+ joint_size=self.joint_size,
+ use_joint_to_bones=self.use_joint_to_bones,
+ ).read(
+ blender_context,
+ self.filepath
+ )
+
+ def invoke(self, blender_context, event):
+ blender_context.window_manager.fileselect_add(self)
+ return {'RUNNING_MODAL', }
+
+ @staticmethod
+ def menu_func(cls, blender_context):
+ cls.layout.operator(
+ Ms3dImportOperator.bl_idname,
+ text=ms3d_str['TEXT_OPERATOR'],
+ )
+
+
+class Ms3dExportOperator(Operator, ExportHelper):
+ """Save a MilkShape3D MS3D File"""
+ bl_idname = 'export_scene.ms3d'
+ bl_label = ms3d_str['BL_LABEL_EXPORTER']
+ bl_description = ms3d_str['BL_DESCRIPTION_EXPORTER']
+ bl_options = {'PRESET', }
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+
+ filepath = StringProperty(
+ subtype='FILE_PATH',
+ options={'HIDDEN', }
+ )
+
+ verbose = BoolProperty(
+ name=ms3d_str['PROP_NAME_VERBOSE'],
+ description=ms3d_str['PROP_DESC_VERBOSE'],
+ default=Ms3dUi.PROP_DEFAULT_VERBOSE,
+ )
+
+ use_blender_names = BoolProperty(
+ name=ms3d_str['PROP_NAME_USE_BLENDER_NAMES'],
+ description=ms3d_str['PROP_DESC_USE_BLENDER_NAMES'],
+ default=Ms3dUi.PROP_DEFAULT_USE_BLENDER_NAMES,
+ )
+
+ use_blender_materials = BoolProperty(
+ name=ms3d_str['PROP_NAME_USE_BLENDER_MATERIALS'],
+ description=ms3d_str['PROP_DESC_USE_BLENDER_MATERIALS'],
+ default=Ms3dUi.PROP_DEFAULT_USE_BLENDER_MATERIALS,
+ )
+
+ apply_transform = BoolProperty(
+ name=ms3d_str['PROP_NAME_APPLY_TRANSFORM'],
+ description=ms3d_str['PROP_DESC_APPLY_TRANSFORM'],
+ default=Ms3dUi.PROP_DEFAULT_APPLY_TRANSFORM,
+ )
+
+ apply_modifiers = BoolProperty(
+ name=ms3d_str['PROP_NAME_APPLY_MODIFIERS'],
+ description=ms3d_str['PROP_DESC_APPLY_MODIFIERS'],
+ default=Ms3dUi.PROP_DEFAULT_APPLY_MODIFIERS,
+ )
+
+ apply_modifiers_mode = EnumProperty(
+ name=ms3d_str['PROP_NAME_APPLY_MODIFIERS_MODE'],
+ description=ms3d_str['PROP_DESC_APPLY_MODIFIERS_MODE'],
+ items=( (Ms3dUi.PROP_ITEM_APPLY_MODIFIERS_MODE_VIEW,
+ ms3d_str['PROP_ITEM_APPLY_MODIFIERS_MODE_VIEW_1'],
+ ms3d_str['PROP_ITEM_APPLY_MODIFIERS_MODE_VIEW_2']),
+ (Ms3dUi.PROP_ITEM_APPLY_MODIFIERS_MODE_RENDER,
+ ms3d_str['PROP_ITEM_APPLY_MODIFIERS_MODE_RENDER_1'],
+ ms3d_str['PROP_ITEM_APPLY_MODIFIERS_MODE_RENDER_2']),
+ ),
+ default=Ms3dUi.PROP_DEFAULT_APPLY_MODIFIERS_MODE,
+ )
+
+ use_animation = BoolProperty(
+ name=ms3d_str['PROP_NAME_USE_ANIMATION'],
+ description=ms3d_str['PROP_DESC_USE_ANIMATION'],
+ default=Ms3dUi.PROP_DEFAULT_USE_ANIMATION,
+ )
+
+ normalize_weights = BoolProperty(
+ name=ms3d_str['PROP_NAME_NORMALIZE_WEIGHTS'],
+ description=ms3d_str['PROP_DESC_NORMALIZE_WEIGHTS'],
+ default=Ms3dUi.PROP_DEFAULT_NORMALIZE_WEIGHTS,
+ )
+
+ shrink_to_keys = BoolProperty(
+ name=ms3d_str['PROP_NAME_SHRINK_TO_KEYS'],
+ description=ms3d_str['PROP_DESC_SHRINK_TO_KEYS'],
+ default=Ms3dUi.PROP_DEFAULT_SHRINK_TO_KEYS,
+ )
+
+ bake_each_frame = BoolProperty(
+ name=ms3d_str['PROP_NAME_BAKE_EACH_FRAME'],
+ description=ms3d_str['PROP_DESC_BAKE_EACH_FRAME'],
+ default=Ms3dUi.PROP_DEFAULT_BAKE_EACH_FRAME,
+ )
+
+ check_existing = BoolProperty(
+ default=False,
+ options={'HIDDEN', }
+ )
+
+ filename_ext = StringProperty(
+ default=ms3d_str['FILE_EXT'],
+ options={'HIDDEN', }
+ )
+
+ filter_glob = StringProperty(
+ default=ms3d_str['FILE_FILTER'],
+ options={'HIDDEN', }
+ )
+
+
+ ##EXPORT_ACTIVE_ONLY:
+ ##limit availability to only active mesh object
+ @classmethod
+ def poll(cls, blender_context):
+ return (blender_context
+ and blender_context.active_object
+ and blender_context.active_object.type in {'MESH', }
+ and blender_context.active_object.data
+ and blender_context.active_object.data.ms3d is not None
+ )
+
+ # draw the option panel
+ def draw(self, blender_context):
+ layout = self.layout
+
+ box = layout.box()
+ box.label(ms3d_str['LABEL_NAME_OPTIONS'], icon=Ms3dUi.ICON_OPTIONS)
+ box.prop(self, 'verbose', icon='SPEAKER')
+
+ box = layout.box()
+ box.label(ms3d_str['LABEL_NAME_PROCESSING'],
+ icon=Ms3dUi.ICON_PROCESSING)
+ row = box.row()
+ row.label(ms3d_str['PROP_NAME_ACTIVE'], icon='ROTACTIVE')
+ row.label(blender_context.active_object.name)
+ #box.prop(self, 'use_blender_names', icon='LINK_BLEND')
+ box.prop(self, 'use_blender_names')
+ box.prop(self, 'use_blender_materials')
+
+ box = layout.box()
+ box.label(ms3d_str['LABEL_NAME_MODIFIER'],
+ icon=Ms3dUi.ICON_MODIFIER)
+ box.prop(self, 'apply_transform')
+ row = box.row()
+ row.prop(self, 'apply_modifiers')
+ sub = row.row()
+ sub.active = self.apply_modifiers
+ sub.prop(self, 'apply_modifiers_mode', text="")
+
+ box = layout.box()
+ box.label(ms3d_str['LABEL_NAME_ANIMATION'],
+ icon=Ms3dUi.ICON_ANIMATION)
+ box.prop(self, 'use_animation')
+ if (self.use_animation):
+ box.prop(self, 'normalize_weights')
+ box.prop(self, 'shrink_to_keys')
+ box.prop(self, 'bake_each_frame')
+
+ # entrypoint for blender -> MS3D
+ def execute(self, blender_context):
+ """start executing"""
+ from io_scene_ms3d.ms3d_export import (Ms3dExporter, )
+ return Ms3dExporter(
+ self.report,
+ verbose=self.verbose,
+ use_blender_names=self.use_blender_names,
+ use_blender_materials=self.use_blender_materials,
+ apply_transform=self.apply_transform,
+ apply_modifiers=self.apply_modifiers,
+ apply_modifiers_mode=self.apply_modifiers_mode,
+ use_animation=self.use_animation,
+ normalize_weights=self.normalize_weights,
+ shrink_to_keys=self.shrink_to_keys,
+ bake_each_frame=self.bake_each_frame,
+ ).write(
+ blender_context,
+ self.filepath
+ )
+
+ #
+ def invoke(self, blender_context, event):
+ blender_context.window_manager.fileselect_add(self)
+ return {"RUNNING_MODAL", }
+
+ @staticmethod
+ def menu_func(cls, blender_context):
+ cls.layout.operator(
+ Ms3dExportOperator.bl_idname,
+ text=ms3d_str['TEXT_OPERATOR']
+ )
+
+
+###############################################################################
+##
+###############################################################################
+
+
+###############################################################################
+class Ms3dSetSmoothingGroupOperator(Operator):
+ bl_idname = Ms3dUi.OPT_SMOOTHING_GROUP_APPLY
+ bl_label = ms3d_str['BL_LABEL_SMOOTHING_GROUP_OPERATOR']
+ bl_options = {'INTERNAL', }
+
+ smoothing_group_index = IntProperty(
+ name=ms3d_str['PROP_SMOOTHING_GROUP_INDEX'],
+ options={'HIDDEN', 'SKIP_SAVE', },
+ )
+
+ @classmethod
+ def poll(cls, blender_context):
+ return (blender_context
+ and blender_context.object
+ and blender_context.object.type in {'MESH', }
+ and blender_context.object.data
+ and blender_context.object.data.ms3d is not None
+ and blender_context.mode == 'EDIT_MESH'
+ and blender_context.tool_settings.mesh_select_mode[2]
+ )
+
+ def execute(self, blender_context):
+ custom_data = blender_context.object.data.ms3d
+ blender_mesh = blender_context.object.data
+ bm = from_edit_mesh(blender_mesh)
+ layer_smoothing_group = bm.faces.layers.int.get(
+ ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
+ if custom_data.apply_mode in {'SELECT', 'DESELECT', }:
+ if layer_smoothing_group is not None:
+ is_select = (custom_data.apply_mode == 'SELECT')
+ for bmf in bm.faces:
+ if (bmf[layer_smoothing_group] \
+ == self.smoothing_group_index):
+ bmf.select_set(is_select)
+ elif custom_data.apply_mode == 'ASSIGN':
+ if layer_smoothing_group is None:
+ layer_smoothing_group = bm.faces.layers.int.new(
+ ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
+ blender_mesh_object = blender_context.object
+ get_edge_split_modifier_add_if(blender_mesh_object)
+ blender_face_list = []
+ for bmf in bm.faces:
+ if not bmf.smooth:
+ bmf.smooth = True
+ if bmf.select:
+ bmf[layer_smoothing_group] = self.smoothing_group_index
+ blender_face_list.append(bmf)
+ edge_dict = {}
+ for bmf in blender_face_list:
+ bmf.smooth = True
+ for bme in bmf.edges:
+ if edge_dict.get(bme) is None:
+ edge_dict[bme] = 0
+ else:
+ edge_dict[bme] += 1
+ is_border = (edge_dict[bme] == 0)
+ if is_border:
+ surround_face_smoothing_group_index \
+ = self.smoothing_group_index
+ for bmf in bme.link_faces:
+ if bmf[layer_smoothing_group] \
+ != surround_face_smoothing_group_index:
+ surround_face_smoothing_group_index \
+ = bmf[layer_smoothing_group]
+ break;
+ if surround_face_smoothing_group_index \
+ == self.smoothing_group_index:
+ is_border = False
+ bme.seam = is_border
+ bme.smooth = not is_border
+ bm.free()
+ enable_edit_mode(False, blender_context)
+ enable_edit_mode(True, blender_context)
+ return {'FINISHED', }
+
+
+class Ms3dGroupOperator(Operator):
+ bl_idname = Ms3dUi.OPT_GROUP_APPLY
+ bl_label = ms3d_str['BL_LABEL_GROUP_OPERATOR']
+ bl_options = {'INTERNAL', }
+
+ mode = EnumProperty(
+ items=( ('', "", ""),
+ ('ADD_GROUP',
+ ms3d_str['ENUM_ADD_GROUP_1'],
+ ms3d_str['ENUM_ADD_GROUP_2']),
+ ('REMOVE_GROUP',
+ ms3d_str['ENUM_REMOVE_GROUP_1'],
+ ms3d_str['ENUM_REMOVE_GROUP_2']),
+ ('ASSIGN',
+ ms3d_str['ENUM_ASSIGN_1'],
+ ms3d_str['ENUM_ASSIGN_2_GROUP']),
+ ('REMOVE',
+ ms3d_str['ENUM_REMOVE_1'],
+ ms3d_str['ENUM_REMOVE_2_GROUP']),
+ ('SELECT',
+ ms3d_str['ENUM_SELECT_1'],
+ ms3d_str['ENUM_SELECT_2_GROUP']),
+ ('DESELECT',
+ ms3d_str['ENUM_DESELECT_1'],
+ ms3d_str['ENUM_DESELECT_2_GROUP']),
+ ),
+ options={'HIDDEN', 'SKIP_SAVE', },
+ )
+
+ @classmethod
+ def poll(cls, blender_context):
+ return (blender_context
+ and blender_context.object
+ and blender_context.object.type in {'MESH', }
+ and blender_context.object.data
+ and blender_context.object.data.ms3d is not None
+ and blender_context.mode == 'EDIT_MESH'
+ #and blender_context.object.data.ms3d.selected_group_index != -1
+ )
+
+ def execute(self, blender_context):
+ custom_data = blender_context.object.data.ms3d
+ blender_mesh = blender_context.object.data
+ bm = None
+ bm = from_edit_mesh(blender_mesh)
+
+ if self.mode == 'ADD_GROUP':
+ item = custom_data.create_group()
+ layer_group = bm.faces.layers.int.get(
+ ms3d_str['OBJECT_LAYER_GROUP'])
+ if layer_group is None:
+ bm.faces.layers.int.new(ms3d_str['OBJECT_LAYER_GROUP'])
+
+ elif self.mode == 'REMOVE_GROUP':
+ custom_data.remove_group()
+
+ elif (custom_data.selected_group_index >= 0) and (
+ custom_data.selected_group_index < len(custom_data.groups)):
+ if self.mode in {'SELECT', 'DESELECT', }:
+ layer_group = bm.faces.layers.int.get(
+ ms3d_str['OBJECT_LAYER_GROUP'])
+ if layer_group is not None:
+ is_select = (self.mode == 'SELECT')
+ id = custom_data.groups[
+ custom_data.selected_group_index].id
+ for bmf in bm.faces:
+ if bmf[layer_group] == id:
+ bmf.select_set(is_select)
+
+ elif self.mode in {'ASSIGN', 'REMOVE', }:
+ layer_group = bm.faces.layers.int.get(
+ ms3d_str['OBJECT_LAYER_GROUP'])
+ if layer_group is None:
+ layer_group = bm.faces.layers.int.new(
+ ms3d_str['OBJECT_LAYER_GROUP'])
+
+ is_assign = (self.mode == 'ASSIGN')
+ id = custom_data.groups[custom_data.selected_group_index].id
+ for bmf in bm.faces:
+ if bmf.select:
+ if is_assign:
+ bmf[layer_group] = id
+ else:
+ bmf[layer_group] = -1
+ if bm is not None:
+ bm.free()
+ enable_edit_mode(False, blender_context)
+ enable_edit_mode(True, blender_context)
+ return {'FINISHED', }
+
+
+class Ms3dMaterialOperator(Operator):
+ bl_idname = Ms3dUi.OPT_MATERIAL_APPLY
+ bl_label = ms3d_str['BL_LABEL_MATERIAL_OPERATOR']
+ bl_options = {'INTERNAL', }
+
+ mode = EnumProperty(
+ items=( ('', "", ""),
+ ('FROM_BLENDER',
+ ms3d_str['ENUM_FROM_BLENDER_1'],
+ ms3d_str['ENUM_FROM_BLENDER_2']),
+ ('TO_BLENDER',
+ ms3d_str['ENUM_TO_BLENDER_1'],
+ ms3d_str['ENUM_TO_BLENDER_2']),
+ ),
+ options={'HIDDEN', 'SKIP_SAVE', },
+ )
+
+ @classmethod
+ def poll(cls, blender_context):
+ return (blender_context
+ and blender_context.object
+ and blender_context.object.type in {'MESH', }
+ and blender_context.object.data
+ and blender_context.object.data.ms3d is not None
+ and blender_context.material
+ and blender_context.material.ms3d is not None
+ )
+
+ def execute(self, blender_context):
+ blender_material = blender_context.active_object.active_material
+ ms3d_material = blender_material.ms3d
+
+ if self.mode == 'FROM_BLENDER':
+ Ms3dMaterialHelper.copy_from_blender(self, blender_context,
+ ms3d_material, blender_material)
+ pass
+
+ elif self.mode == 'TO_BLENDER':
+ # not implemented
+ pass
+
+ return {'FINISHED', }
+
+ # entrypoint for option via UI
+ def invoke(self, blender_context, event):
+ return blender_context.window_manager.invoke_props_dialog(self)
+
+
+###############################################################################
+class Ms3dGroupProperties(PropertyGroup):
+ name = StringProperty(
+ name=ms3d_str['PROP_NAME_NAME'],
+ description=ms3d_str['PROP_DESC_GROUP_NAME'],
+ default="",
+ #options={'HIDDEN', },
+ )
+
+ flags = EnumProperty(
+ name=ms3d_str['PROP_NAME_FLAGS'],
+ description=ms3d_str['PROP_DESC_FLAGS_GROUP'],
+ items=(#(Ms3dUi.FLAG_NONE, ms3d_str['ENUM_FLAG_NONE_1'],
+ # ms3d_str['ENUM_FLAG_NONE_2'],
+ # Ms3dSpec.FLAG_NONE),
+ (Ms3dUi.FLAG_SELECTED,
+ ms3d_str['ENUM_FLAG_SELECTED_1'],
+ ms3d_str['ENUM_FLAG_SELECTED_2'],
+ Ms3dSpec.FLAG_SELECTED),
+ (Ms3dUi.FLAG_HIDDEN,
+ ms3d_str['ENUM_FLAG_HIDDEN_1'],
+ ms3d_str['ENUM_FLAG_HIDDEN_2'],
+ Ms3dSpec.FLAG_HIDDEN),
+ (Ms3dUi.FLAG_SELECTED2,
+ ms3d_str['ENUM_FLAG_SELECTED2_1'],
+ ms3d_str['ENUM_FLAG_SELECTED2_2'],
+ Ms3dSpec.FLAG_SELECTED2),
+ (Ms3dUi.FLAG_DIRTY,
+ ms3d_str['ENUM_FLAG_DIRTY_1'],
+ ms3d_str['ENUM_FLAG_DIRTY_2'],
+ Ms3dSpec.FLAG_DIRTY),
+ (Ms3dUi.FLAG_ISKEY,
+ ms3d_str['ENUM_FLAG_ISKEY_1'],
+ ms3d_str['ENUM_FLAG_ISKEY_2'],
+ Ms3dSpec.FLAG_ISKEY),
+ (Ms3dUi.FLAG_NEWLYCREATED,
+ ms3d_str['ENUM_FLAG_NEWLYCREATED_1'],
+ ms3d_str['ENUM_FLAG_NEWLYCREATED_2'],
+ Ms3dSpec.FLAG_NEWLYCREATED),
+ (Ms3dUi.FLAG_MARKED,
+ ms3d_str['ENUM_FLAG_MARKED_1'],
+ ms3d_str['ENUM_FLAG_MARKED_2'],
+ Ms3dSpec.FLAG_MARKED),
+ ),
+ default=Ms3dUi.flags_from_ms3d(Ms3dSpec.DEFAULT_FLAGS),
+ options={'ENUM_FLAG', 'ANIMATABLE', },
+ )
+
+ comment = StringProperty(
+ name=ms3d_str['PROP_NAME_COMMENT'],
+ description=ms3d_str['PROP_DESC_COMMENT_GROUP'],
+ default="",
+ #options={'HIDDEN', },
+ )
+
+ id = IntProperty(options={'HIDDEN', },)
+
+
+class Ms3dModelProperties(PropertyGroup):
+ name = StringProperty(
+ name=ms3d_str['PROP_NAME_NAME'],
+ description=ms3d_str['PROP_DESC_NAME_MODEL'],
+ default="",
+ #options={'HIDDEN', },
+ )
+
+ joint_size = FloatProperty(
+ name=ms3d_str['PROP_NAME_JOINT_SIZE'],
+ description=ms3d_str['PROP_DESC_JOINT_SIZE'],
+ min=Ms3dUi.PROP_JOINT_SIZE_MIN, max=Ms3dUi.PROP_JOINT_SIZE_MAX,
+ precision=Ms3dUi.PROP_JOINT_SIZE_PRECISION, \
+ step=Ms3dUi.PROP_JOINT_SIZE_STEP,
+ default=Ms3dUi.PROP_DEFAULT_JOINT_SIZE,
+ subtype='FACTOR',
+ #options={'HIDDEN', },
+ )
+
+ transparency_mode = EnumProperty(
+ name=ms3d_str['PROP_NAME_TRANSPARENCY_MODE'],
+ description=ms3d_str['PROP_DESC_TRANSPARENCY_MODE'],
+ items=( (Ms3dUi.MODE_TRANSPARENCY_SIMPLE,
+ ms3d_str['PROP_MODE_TRANSPARENCY_SIMPLE_1'],
+ ms3d_str['PROP_MODE_TRANSPARENCY_SIMPLE_2'],
+ Ms3dSpec.MODE_TRANSPARENCY_SIMPLE),
+ (Ms3dUi.MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES,
+ ms3d_str['PROP_MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES_1'],
+ ms3d_str['PROP_MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES_2'],
+ Ms3dSpec.MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES),
+ (Ms3dUi.MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF,
+ ms3d_str['PROP_MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF_1'],
+ ms3d_str['PROP_MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF_2'],
+ Ms3dSpec.MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF),
+ ),
+ default=Ms3dUi.transparency_mode_from_ms3d(
+ Ms3dSpec.DEFAULT_MODEL_TRANSPARENCY_MODE),
+ #options={'HIDDEN', },
+ )
+
+ alpha_ref = FloatProperty(
+ name=ms3d_str['PROP_NAME_ALPHA_REF'],
+ description=ms3d_str['PROP_DESC_ALPHA_REF'],
+ min=0, max=1, precision=3, step=0.1,
+ default=0.5,
+ subtype='FACTOR',
+ #options={'HIDDEN', },
+ )
+
+ comment = StringProperty(
+ name=ms3d_str['PROP_NAME_COMMENT'],
+ description=ms3d_str['PROP_DESC_COMMENT_MODEL'],
+ default="",
+ #options={'HIDDEN', },
+ )
+
+ ##########################
+ # ms3d group handling
+ #
+ apply_mode = EnumProperty(
+ items=( ('ASSIGN',
+ ms3d_str['ENUM_ASSIGN_1'],
+ ms3d_str['ENUM_ASSIGN_2_SMOOTHING_GROUP']),
+ ('SELECT',
+ ms3d_str['ENUM_SELECT_1'],
+ ms3d_str['ENUM_SELECT_2_SMOOTHING_GROUP']),
+ ('DESELECT',
+ ms3d_str['ENUM_DESELECT_1'],
+ ms3d_str['ENUM_DESELECT_2_SMOOTHING_GROUP']),
+ ),
+ default='SELECT',
+ options={'HIDDEN', 'SKIP_SAVE', },
+ )
+
+ selected_group_index = IntProperty(
+ default=-1,
+ min=-1,
+ options={'HIDDEN', 'SKIP_SAVE', },
+ )
+ #
+ # ms3d group handling
+ ##########################
+
+ groups = CollectionProperty(
+ type=Ms3dGroupProperties,
+ #options={'HIDDEN', },
+ )
+
+
+ def generate_unique_id(self):
+ return randrange(1, 0x7FFFFFFF) # pseudo unique id
+
+ def create_group(self):
+ item = self.groups.add()
+ item.id = self.generate_unique_id()
+ length = len(self.groups)
+ self.selected_group_index = length - 1
+
+ item.name = ms3d_str['STRING_FORMAT_GROUP'].format(length)
+ return item
+
+ def remove_group(self):
+ index = self.selected_group_index
+ length = len(self.groups)
+ if (index >= 0) and (index < length):
+ if index > 0 or length == 1:
+ self.selected_group_index = index - 1
+ self.groups.remove(index)
+
+
+class Ms3dArmatureProperties(PropertyGroup):
+ name = StringProperty(
+ name=ms3d_str['PROP_NAME_NAME'],
+ description=ms3d_str['PROP_DESC_NAME_ARMATURE'],
+ default="",
+ #options={'HIDDEN', },
+ )
+
+
+class Ms3dJointProperties(PropertyGroup):
+ name = StringProperty(
+ name=ms3d_str['PROP_NAME_NAME'],
+ description=ms3d_str['PROP_DESC_NAME_JOINT'],
+ default="",
+ #options={'HIDDEN', },
+ )
+
+ flags = EnumProperty(
+ name=ms3d_str['PROP_NAME_FLAGS'],
+ description=ms3d_str['PROP_DESC_FLAGS_JOINT'],
+ items=(#(Ms3dUi.FLAG_NONE,
+ # ms3d_str['ENUM_FLAG_NONE_1'],
+ # ms3d_str['ENUM_FLAG_NONE_2'],
+ # Ms3dSpec.FLAG_NONE),
+ (Ms3dUi.FLAG_SELECTED,
+ ms3d_str['ENUM_FLAG_SELECTED_1'],
+ ms3d_str['ENUM_FLAG_SELECTED_2'],
+ Ms3dSpec.FLAG_SELECTED),
+ (Ms3dUi.FLAG_HIDDEN,
+ ms3d_str['ENUM_FLAG_HIDDEN_1'],
+ ms3d_str['ENUM_FLAG_HIDDEN_2'],
+ Ms3dSpec.FLAG_HIDDEN),
+ (Ms3dUi.FLAG_SELECTED2,
+ ms3d_str['ENUM_FLAG_SELECTED2_1'],
+ ms3d_str['ENUM_FLAG_SELECTED2_2'],
+ Ms3dSpec.FLAG_SELECTED2),
+ (Ms3dUi.FLAG_DIRTY,
+ ms3d_str['ENUM_FLAG_DIRTY_1'],
+ ms3d_str['ENUM_FLAG_DIRTY_2'],
+ Ms3dSpec.FLAG_DIRTY),
+ (Ms3dUi.FLAG_ISKEY,
+ ms3d_str['ENUM_FLAG_ISKEY_1'],
+ ms3d_str['ENUM_FLAG_ISKEY_2'],
+ Ms3dSpec.FLAG_ISKEY),
+ (Ms3dUi.FLAG_NEWLYCREATED,
+ ms3d_str['ENUM_FLAG_NEWLYCREATED_1'],
+ ms3d_str['ENUM_FLAG_NEWLYCREATED_2'],
+ Ms3dSpec.FLAG_NEWLYCREATED),
+ (Ms3dUi.FLAG_MARKED,
+ ms3d_str['ENUM_FLAG_MARKED_1'],
+ ms3d_str['ENUM_FLAG_MARKED_2'],
+ Ms3dSpec.FLAG_MARKED),
+ ),
+ default=Ms3dUi.flags_from_ms3d(Ms3dSpec.DEFAULT_FLAGS),
+ options={'ENUM_FLAG', 'ANIMATABLE', },
+ )
+
+ color = FloatVectorProperty(
+ name=ms3d_str['PROP_NAME_COLOR'],
+ description=ms3d_str['PROP_DESC_COLOR_JOINT'],
+ subtype='COLOR', size=3, min=0, max=1, precision=3, step=0.1,
+ default=Ms3dSpec.DEFAULT_JOINT_COLOR,
+ #options={'HIDDEN', },
+ )
+
+ comment = StringProperty(
+ name=ms3d_str['PROP_NAME_COMMENT'],
+ description=ms3d_str['PROP_DESC_COMMENT_JOINT'],
+ default="",
+ #options={'HIDDEN', },
+ )
+
+
+class Ms3dMaterialHelper:
+ @staticmethod
+ def copy_to_blender_ambient(cls, blender_context):
+ pass
+
+ @staticmethod
+ def copy_to_blender_diffuse(cls, blender_context):
+ cls.id_data.diffuse_color = cls.diffuse[0:3]
+ #cls.id_data.diffuse_intensity = cls.diffuse[3]
+ pass
+
+ @staticmethod
+ def copy_to_blender_specular(cls, blender_context):
+ cls.id_data.specular_color = cls.specular[0:3]
+ #cls.id_data.specular_intensity = cls.specular[3]
+ pass
+
+ @staticmethod
+ def copy_to_blender_emissive(cls, blender_context):
+ cls.id_data.emit = (cls.emissive[0] + cls.emissive[1] \
+ + cls.emissive[2]) / 3.0
+ pass
+
+ @staticmethod
+ def copy_to_blender_shininess(cls, blender_context):
+ cls.id_data.specular_hardness = cls.shininess * 4.0
+ pass
+
+ @staticmethod
+ def copy_to_blender_transparency(cls, blender_context):
+ cls.id_data.alpha = 1.0 - cls.transparency
+ pass
+
+
+ @staticmethod
+ def copy_from_blender(cls, blender_context, ms3d_material, blender_material):
+ # copy, bacause of auto update, it would distord original values
+ blender_material_diffuse_color = blender_material.diffuse_color.copy()
+ blender_material_diffuse_intensity = blender_material.diffuse_intensity
+ blender_material_specular_color = blender_material.specular_color.copy()
+ blender_material_specular_intensity = \
+ blender_material.specular_intensity
+ blender_material_emit = blender_material.emit
+ blender_material_specular_hardness = \
+ blender_material.specular_hardness
+ blender_material_alpha = blender_material.alpha
+
+ blender_material_texture = None
+ for slot in blender_material.texture_slots:
+ if slot and slot.use_map_color_diffuse \
+ and slot.texture.type == 'IMAGE':
+ blender_material_texture = slot.texture.image.filepath
+ break
+
+ blender_material_alphamap = None
+ for slot in blender_material.texture_slots:
+ if slot and not slot.use_map_color_diffuse \
+ and slot.use_map_alpha and slot.texture.type == 'IMAGE':
+ blender_material_alphamap = slot.texture.image.filepath
+ break
+
+ ms3d_material.diffuse[0] = blender_material_diffuse_color[0]
+ ms3d_material.diffuse[1] = blender_material_diffuse_color[1]
+ ms3d_material.diffuse[2] = blender_material_diffuse_color[2]
+ ms3d_material.diffuse[3] = 1.0
+ ms3d_material.specular[0] = blender_material_specular_color[0]
+ ms3d_material.specular[1] = blender_material_specular_color[1]
+ ms3d_material.specular[2] = blender_material_specular_color[2]
+ ms3d_material.specular[3] = 1.0
+ ms3d_material.emissive[0] = blender_material_emit
+ ms3d_material.emissive[1] = blender_material_emit
+ ms3d_material.emissive[2] = blender_material_emit
+ ms3d_material.emissive[3] = 1.0
+ ms3d_material.shininess = blender_material_specular_hardness / 4.0
+ ms3d_material.transparency = 1.0 - blender_material_alpha
+
+ if blender_material_texture:
+ ms3d_material.texture = blender_material_texture
+ else:
+ ms3d_material.texture = ""
+
+ if blender_material_alphamap:
+ ms3d_material.alphamap = blender_material_alphamap
+ else:
+ ms3d_material.alphamap = ""
+
+
+class Ms3dMaterialProperties(PropertyGroup):
+ name = StringProperty(
+ name=ms3d_str['PROP_NAME_NAME'],
+ description=ms3d_str['PROP_DESC_NAME_MATERIAL'],
+ default="",
+ #options={'HIDDEN', },
+ )
+
+ ambient = FloatVectorProperty(
+ name=ms3d_str['PROP_NAME_AMBIENT'],
+ description=ms3d_str['PROP_DESC_AMBIENT'],
+ subtype='COLOR', size=4, min=0, max=1, precision=3, step=0.1,
+ default=Ms3dSpec.DEFAULT_MATERIAL_AMBIENT,
+ update=Ms3dMaterialHelper.copy_to_blender_ambient,
+ #options={'HIDDEN', },
+ )
+
+ diffuse = FloatVectorProperty(
+ name=ms3d_str['PROP_NAME_DIFFUSE'],
+ description=ms3d_str['PROP_DESC_DIFFUSE'],
+ subtype='COLOR', size=4, min=0, max=1, precision=3, step=0.1,
+ default=Ms3dSpec.DEFAULT_MATERIAL_DIFFUSE,
+ update=Ms3dMaterialHelper.copy_to_blender_diffuse,
+ #options={'HIDDEN', },
+ )
+
+ specular = FloatVectorProperty(
+ name=ms3d_str['PROP_NAME_SPECULAR'],
+ description=ms3d_str['PROP_DESC_SPECULAR'],
+ subtype='COLOR', size=4, min=0, max=1, precision=3, step=0.1,
+ default=Ms3dSpec.DEFAULT_MATERIAL_SPECULAR,
+ update=Ms3dMaterialHelper.copy_to_blender_specular,
+ #options={'HIDDEN', },
+ )
+
+ emissive = FloatVectorProperty(
+ name=ms3d_str['PROP_NAME_EMISSIVE'],
+ description=ms3d_str['PROP_DESC_EMISSIVE'],
+ subtype='COLOR', size=4, min=0, max=1, precision=3, step=0.1,
+ default=Ms3dSpec.DEFAULT_MATERIAL_EMISSIVE,
+ update=Ms3dMaterialHelper.copy_to_blender_emissive,
+ #options={'HIDDEN', },
+ )
+
+ shininess = FloatProperty(
+ name=ms3d_str['PROP_NAME_SHININESS'],
+ description=ms3d_str['PROP_DESC_SHININESS'],
+ min=0, max=Ms3dSpec.MAX_MATERIAL_SHININESS, precision=3, step=0.1,
+ default=Ms3dSpec.DEFAULT_MATERIAL_SHININESS,
+ subtype='FACTOR',
+ update=Ms3dMaterialHelper.copy_to_blender_shininess,
+ #options={'HIDDEN', },
+ )
+
+ transparency = FloatProperty(
+ name=ms3d_str['PROP_NAME_TRANSPARENCY'],
+ description=ms3d_str['PROP_DESC_TRANSPARENCY'],
+ min=0, max=1, precision=3, step=0.1,
+ default=0,
+ subtype='FACTOR',
+ update=Ms3dMaterialHelper.copy_to_blender_transparency,
+ #options={'HIDDEN', },
+ )
+
+ mode = EnumProperty(
+ name=ms3d_str['PROP_NAME_MODE'],
+ description=ms3d_str['PROP_DESC_MODE_TEXTURE'],
+ items=( (Ms3dUi.FLAG_TEXTURE_COMBINE_ALPHA,
+ ms3d_str['PROP_FLAG_TEXTURE_COMBINE_ALPHA_1'],
+ ms3d_str['PROP_FLAG_TEXTURE_COMBINE_ALPHA_2'],
+ Ms3dSpec.FLAG_TEXTURE_COMBINE_ALPHA),
+ (Ms3dUi.FLAG_TEXTURE_HAS_ALPHA,
+ ms3d_str['PROP_FLAG_TEXTURE_HAS_ALPHA_1'],
+ ms3d_str['PROP_FLAG_TEXTURE_HAS_ALPHA_2'],
+ Ms3dSpec.FLAG_TEXTURE_HAS_ALPHA),
+ (Ms3dUi.FLAG_TEXTURE_SPHERE_MAP,
+ ms3d_str['PROP_FLAG_TEXTURE_SPHERE_MAP_1'],
+ ms3d_str['PROP_FLAG_TEXTURE_SPHERE_MAP_2'],
+ Ms3dSpec.FLAG_TEXTURE_SPHERE_MAP),
+ ),
+ default=Ms3dUi.texture_mode_from_ms3d(
+ Ms3dSpec.DEFAULT_MATERIAL_MODE),
+ options={'ANIMATABLE', 'ENUM_FLAG', },
+ )
+
+ texture = StringProperty(
+ name=ms3d_str['PROP_NAME_TEXTURE'],
+ description=ms3d_str['PROP_DESC_TEXTURE'],
+ default="",
+ subtype = 'FILE_PATH'
+ #options={'HIDDEN', },
+ )
+
+ alphamap = StringProperty(
+ name=ms3d_str['PROP_NAME_ALPHAMAP'],
+ description=ms3d_str['PROP_DESC_ALPHAMAP'],
+ default="",
+ subtype = 'FILE_PATH'
+ #options={'HIDDEN', },
+ )
+
+ comment = StringProperty(
+ name=ms3d_str['PROP_NAME_COMMENT'],
+ description=ms3d_str['PROP_DESC_COMMENT_MATERIAL'],
+ default="",
+ #options={'HIDDEN', },
+ )
+
+
+###############################################################################
+# http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=53355
+class Ms3dGroupUILise(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ layout.label(item.name, icon_value=icon)
+
+
+###############################################################################
+class Ms3dMeshPanel(Panel):
+ bl_label = ms3d_str['LABEL_PANEL_MODEL']
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = 'object'
+
+ @classmethod
+ def poll(cls, blender_context):
+ return (blender_context
+ and blender_context.object
+ and blender_context.object.type in {'MESH', }
+ and blender_context.object.data
+ and blender_context.object.data.ms3d is not None
+ )
+
+ def draw_header(self, blender_context):
+ layout = self.layout
+ layout.label(icon='PLUGIN')
+
+ def draw(self, blender_context):
+ layout = self.layout
+ custom_data = blender_context.object.data.ms3d
+
+ row = layout.row()
+ row.prop(custom_data, 'name')
+
+ col = layout.column()
+ row = col.row()
+ row.prop(custom_data, 'joint_size')
+ row = col.row()
+ row.prop(custom_data, 'transparency_mode')
+ row = col.row()
+ row.prop(custom_data, 'alpha_ref', )
+
+ row = layout.row()
+ row.prop(custom_data, 'comment')
+
+
+class Ms3dMaterialPanel(Panel):
+ bl_label = ms3d_str['LABEL_PANEL_MATERIALS']
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = 'material'
+
+ @classmethod
+ def poll(cls, blender_context):
+ return (blender_context
+ and blender_context.object
+ and blender_context.object.type in {'MESH', }
+ and blender_context.object.data
+ and blender_context.object.data.ms3d is not None
+ and blender_context.material
+ and blender_context.material.ms3d is not None
+ )
+
+ def draw_header(self, blender_context):
+ layout = self.layout
+ layout.label(icon='PLUGIN')
+
+ def draw(self, blender_context):
+ layout = self.layout
+ custom_data = blender_context.material.ms3d
+
+ row = layout.row()
+ row.prop(custom_data, 'name')
+
+ col = layout.column()
+ row = col.row()
+ row.prop(custom_data, 'diffuse')
+ row.prop(custom_data, 'ambient')
+ row = col.row()
+ row.prop(custom_data, 'specular')
+ row.prop(custom_data, 'emissive')
+ row = col.row()
+ row.prop(custom_data, 'shininess')
+ row.prop(custom_data, 'transparency')
+
+ col = layout.column()
+ row = col.row()
+ row.prop(custom_data, 'texture')
+ row = col.row()
+ row.prop(custom_data, 'alphamap')
+ row = col.row()
+ row.prop(custom_data, 'mode', expand=True)
+
+ row = layout.row()
+ row.prop(custom_data, 'comment')
+
+ layout.row().operator(
+ Ms3dUi.OPT_MATERIAL_APPLY,
+ text=ms3d_str['ENUM_FROM_BLENDER_1'],
+ icon='APPEND_BLEND').mode = 'FROM_BLENDER'
+ pass
+
+
+class Ms3dBonePanel(Panel):
+ bl_label = ms3d_str['LABEL_PANEL_JOINTS']
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = 'bone'
+
+ @classmethod
+ def poll(cls, blender_context):
+ return (blender_context
+ and blender_context.object.type in {'ARMATURE', }
+ and blender_context.active_bone
+ and isinstance(blender_context.active_bone, Bone)
+ and blender_context.active_bone.ms3d is not None
+ )
+
+ def draw_header(self, blender_context):
+ layout = self.layout
+ layout.label(icon='PLUGIN')
+
+ def draw(self, blender_context):
+ import bpy
+ layout = self.layout
+ custom_data = blender_context.active_bone.ms3d
+
+ row = layout.row()
+ row.prop(custom_data, 'name')
+ row = layout.row()
+ row.prop(custom_data, 'flags', expand=True)
+ row = layout.row()
+ row.prop(custom_data, 'color')
+ row = layout.row()
+ row.prop(custom_data, 'comment')
+
+
+class Ms3dGroupPanel(Panel):
+ bl_label = ms3d_str['LABEL_PANEL_GROUPS']
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = 'data'
+
+ @classmethod
+ def poll(cls, blender_context):
+ return (blender_context
+ and blender_context.object
+ and blender_context.object.type in {'MESH', }
+ and blender_context.object.data
+ and blender_context.object.data.ms3d is not None
+ )
+
+ def draw_header(self, blender_context):
+ layout = self.layout
+ layout.label(icon='PLUGIN')
+
+ def draw(self, blender_context):
+ layout = self.layout
+ custom_data = blender_context.object.data.ms3d
+ layout.enabled = (blender_context.mode == 'EDIT_MESH') and (
+ blender_context.tool_settings.mesh_select_mode[2])
+
+ row = layout.row()
+
+ # http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=53355
+ row.template_list(
+ listtype_name='Ms3dGroupUILise',
+ dataptr=custom_data,
+ propname='groups',
+ active_dataptr=custom_data,
+ active_propname='selected_group_index',
+ rows=2,
+ type='DEFAULT',
+ )
+
+ col = row.column(align=True)
+ col.operator(
+ Ms3dUi.OPT_GROUP_APPLY,
+ text="", icon='ZOOMIN').mode = 'ADD_GROUP'
+ col.operator(
+ Ms3dUi.OPT_GROUP_APPLY,
+ text="", icon='ZOOMOUT').mode = 'REMOVE_GROUP'
+
+ index = custom_data.selected_group_index
+ collection = custom_data.groups
+ if (index >= 0 and index < len(collection)):
+ row = layout.row()
+ row.prop(collection[index], 'name')
+
+ row = layout.row()
+ subrow = row.row(align=True)
+ subrow.operator(
+ Ms3dUi.OPT_GROUP_APPLY,
+ text=ms3d_str['ENUM_ASSIGN_1']).mode = 'ASSIGN'
+ subrow.operator(
+ Ms3dUi.OPT_GROUP_APPLY,
+ text=ms3d_str['ENUM_REMOVE_1']).mode = 'REMOVE'
+ subrow = row.row(align=True)
+ subrow.operator(
+ Ms3dUi.OPT_GROUP_APPLY,
+ text=ms3d_str['ENUM_SELECT_1']).mode = 'SELECT'
+ subrow.operator(
+ Ms3dUi.OPT_GROUP_APPLY,
+ text=ms3d_str['ENUM_DESELECT_1']).mode = 'DESELECT'
+
+ row = layout.row()
+ row.prop(collection[index], 'flags', expand=True)
+
+ row = layout.row()
+ row.prop(collection[index], 'comment')
+
+
+class Ms3dSmoothingGroupPanel(Panel):
+ bl_label = ms3d_str['BL_LABEL_PANEL_SMOOTHING_GROUP']
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = 'data'
+
+ def preview(self, dict, id, text):
+ item = dict.get(id)
+ if item is None:
+ return "{}".format(text)
+ elif item:
+ return "{}:".format(text)
+
+ return "{}.".format(text)
+
+ def build_preview(self, blender_context):
+ dict = {}
+ if (blender_context.mode != 'EDIT_MESH') or (
+ not blender_context.tool_settings.mesh_select_mode[2]):
+ return dict
+
+ custom_data = blender_context.object.data.ms3d
+ blender_mesh = blender_context.object.data
+ bm = from_edit_mesh(blender_mesh)
+ layer_smoothing_group = bm.faces.layers.int.get(
+ ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
+ if layer_smoothing_group is not None:
+ for bmf in bm.faces:
+ item = dict.get(bmf[layer_smoothing_group])
+ if item is None:
+ dict[bmf[layer_smoothing_group]] = bmf.select
+ else:
+ if not item:
+ dict[bmf[layer_smoothing_group]] = bmf.select
+ return dict
+
+ @classmethod
+ def poll(cls, blender_context):
+ return (blender_context
+ and blender_context.object
+ and blender_context.object.type in {'MESH', }
+ and blender_context.object.data
+ and blender_context.object.data.ms3d is not None
+ )
+
+ def draw_header(self, blender_context):
+ layout = self.layout
+ layout.label(icon='PLUGIN')
+
+ def draw(self, blender_context):
+ dict = self.build_preview(blender_context)
+
+ custom_data = blender_context.object.data.ms3d
+ layout = self.layout
+ layout.enabled = (blender_context.mode == 'EDIT_MESH') and (
+ blender_context.tool_settings.mesh_select_mode[2])
+
+ row = layout.row()
+ subrow = row.row()
+ subrow.prop(custom_data, 'apply_mode', expand=True)
+
+ col = layout.column(align=True)
+ subrow = col.row(align=True)
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 1, "1")
+ ).smoothing_group_index = 1
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 2, "2")
+ ).smoothing_group_index = 2
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 3, "3")
+ ).smoothing_group_index = 3
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 4, "4")
+ ).smoothing_group_index = 4
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 5, "5")
+ ).smoothing_group_index = 5
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 6, "6")
+ ).smoothing_group_index = 6
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 7, "7")
+ ).smoothing_group_index = 7
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 8, "8")
+ ).smoothing_group_index = 8
+ subrow = col.row(align=True)
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 9, "9")
+ ).smoothing_group_index = 9
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 10, "10")
+ ).smoothing_group_index = 10
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 11, "11")
+ ).smoothing_group_index = 11
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 12, "12")
+ ).smoothing_group_index = 12
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 13, "13")
+ ).smoothing_group_index = 13
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 14, "14")
+ ).smoothing_group_index = 14
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 15, "15")
+ ).smoothing_group_index = 15
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 16, "16")
+ ).smoothing_group_index = 16
+ subrow = col.row(align=True)
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 17, "17")
+ ).smoothing_group_index = 17
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 18, "18")
+ ).smoothing_group_index = 18
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 19, "19")
+ ).smoothing_group_index = 19
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 20, "20")
+ ).smoothing_group_index = 20
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 21, "21")
+ ).smoothing_group_index = 21
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 22, "22")
+ ).smoothing_group_index = 22
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 23, "23")
+ ).smoothing_group_index = 23
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 24, "24")
+ ).smoothing_group_index = 24
+ subrow = col.row(align=True)
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 25, "25")
+ ).smoothing_group_index = 25
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 26, "26")
+ ).smoothing_group_index = 26
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 27, "27")
+ ).smoothing_group_index = 27
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 28, "28")
+ ).smoothing_group_index = 28
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 29, "29")
+ ).smoothing_group_index = 29
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 30, "30")
+ ).smoothing_group_index = 30
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 31, "31")
+ ).smoothing_group_index = 31
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 32, "32")
+ ).smoothing_group_index = 32
+ subrow = col.row()
+ subrow.operator(
+ Ms3dUi.OPT_SMOOTHING_GROUP_APPLY,
+ text=self.preview(dict, 0, ms3d_str['LABEL_PANEL_BUTTON_NONE'])
+ ).smoothing_group_index = 0
+
+
+###############################################################################
+class Ms3dSetSceneToMetricOperator(Operator):
+ """ . """
+ bl_idname = 'io_scene_ms3d.set_sence_to_metric'
+ bl_label = ms3d_str['BL_LABEL_SET_SCENE_TO_METRIC']
+ bl_description = ms3d_str['BL_DESC_SET_SCENE_TO_METRIC']
+
+
+ #
+ @classmethod
+ def poll(cls, blender_context):
+ return True
+
+ # entrypoint for option
+ def execute(self, blender_context):
+ return self.set_sence_to_metric(blender_context)
+
+ # entrypoint for option via UI
+ def invoke(self, blender_context, event):
+ return blender_context.window_manager.invoke_props_dialog(self)
+
+
+ ###########################################################################
+ def set_sence_to_metric(self, blender_context):
+ set_sence_to_metric(blender_context)
+ return {"FINISHED"}
+
+
+###############################################################################
+def register():
+ register_class(Ms3dSetSceneToMetricOperator)
+ register_class(Ms3dGroupProperties)
+ register_class(Ms3dModelProperties)
+ register_class(Ms3dArmatureProperties)
+ register_class(Ms3dJointProperties)
+ register_class(Ms3dMaterialProperties)
+ inject_properties()
+ register_class(Ms3dSetSmoothingGroupOperator)
+ register_class(Ms3dGroupOperator)
+
+def unregister():
+ unregister_class(Ms3dGroupOperator)
+ unregister_class(Ms3dSetSmoothingGroupOperator)
+ delete_properties()
+ unregister_class(Ms3dMaterialProperties)
+ unregister_class(Ms3dJointProperties)
+ unregister_class(Ms3dArmatureProperties)
+ unregister_class(Ms3dModelProperties)
+ unregister_class(Ms3dGroupProperties)
+ unregister_class(Ms3dSetSceneToMetricOperator)
+
+def inject_properties():
+ Mesh.ms3d = PointerProperty(type=Ms3dModelProperties)
+ Armature.ms3d = PointerProperty(type=Ms3dArmatureProperties)
+ Bone.ms3d = PointerProperty(type=Ms3dJointProperties)
+ Material.ms3d = PointerProperty(type=Ms3dMaterialProperties)
+ Action.ms3d = PointerProperty(type=Ms3dArmatureProperties)
+ Group.ms3d = PointerProperty(type=Ms3dGroupProperties)
+
+def delete_properties():
+ del Mesh.ms3d
+ del Armature.ms3d
+ del Bone.ms3d
+ del Material.ms3d
+ del Action.ms3d
+ del Group.ms3d
+
+###############################################################################
+
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+# ##### END OF FILE #####
diff --git a/io_scene_ms3d/ms3d_utils.py b/io_scene_ms3d/ms3d_utils.py
new file mode 100644
index 00000000..6617a8da
--- /dev/null
+++ b/io_scene_ms3d/ms3d_utils.py
@@ -0,0 +1,222 @@
+# ##### 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+
+
+# ##### BEGIN COPYRIGHT BLOCK #####
+#
+# initial script copyright (c)2011,2012 Alexander Nussbaumer
+#
+# ##### END COPYRIGHT BLOCK #####
+
+
+#import python stuff
+from os import (
+ path
+ )
+
+
+# import io_scene_ms3d stuff
+from io_scene_ms3d.ms3d_strings import (
+ ms3d_str,
+ )
+
+
+#import blender stuff
+from bpy import (
+ ops,
+ )
+
+
+###############################################################################
+def enable_edit_mode(enable, blender_context):
+ if blender_context.active_object is None \
+ or not blender_context.active_object.type in {'MESH', 'ARMATURE', }:
+ return
+
+ if enable:
+ modeString = 'EDIT'
+ else:
+ modeString = 'OBJECT'
+
+ if ops.object.mode_set.poll():
+ ops.object.mode_set(mode=modeString)
+
+
+###############################################################################
+def enable_pose_mode(enable, blender_context):
+ if blender_context.active_object is None \
+ or not blender_context.active_object.type in {'ARMATURE', }:
+ return
+
+ if enable:
+ modeString = 'POSE'
+ else:
+ modeString = 'OBJECT'
+
+ if ops.object.mode_set.poll():
+ ops.object.mode_set(mode=modeString)
+
+
+###############################################################################
+def select_all(select):
+ if select:
+ actionString = 'SELECT'
+ else:
+ actionString = 'DESELECT'
+
+ if ops.object.select_all.poll():
+ ops.object.select_all(action=actionString)
+
+ if ops.mesh.select_all.poll():
+ ops.mesh.select_all(action=actionString)
+
+ if ops.pose.select_all.poll():
+ ops.pose.select_all(action=actionString)
+
+
+###############################################################################
+def pre_setup_environment(porter, blender_context):
+ # inject undo to porter
+ # and turn off undo
+ porter.undo = blender_context.user_preferences.edit.use_global_undo
+ blender_context.user_preferences.edit.use_global_undo = False
+
+ # inject active_object to self
+ porter.active_object = blender_context.scene.objects.active
+
+ # change to a well defined mode
+ enable_edit_mode(True, blender_context)
+
+ # enable face-selection-mode
+ blender_context.tool_settings.mesh_select_mode = (False, False, True)
+
+ # change back to object mode
+ enable_edit_mode(False, blender_context)
+
+ blender_context.scene.update()
+
+
+###############################################################################
+def post_setup_environment(porter, blender_context):
+ # restore active object
+ blender_context.scene.objects.active = porter.active_object
+
+ if not blender_context.scene.objects.active \
+ and blender_context.selected_objects:
+ blender_context.scene.objects.active \
+ = blender_context.selected_objects[0]
+
+ # restore pre operator undo state
+ blender_context.user_preferences.edit.use_global_undo = porter.undo
+
+
+###############################################################################
+def get_edge_split_modifier_add_if(blender_mesh_object):
+ blender_modifier = blender_mesh_object.modifiers.get(
+ ms3d_str['OBJECT_MODIFIER_SMOOTHING_GROUP'])
+
+ if blender_modifier is None:
+ blender_modifier = blender_mesh_object.modifiers.new(
+ ms3d_str['OBJECT_MODIFIER_SMOOTHING_GROUP'],
+ type='EDGE_SPLIT')
+ blender_modifier.show_expanded = False
+ blender_modifier.use_edge_angle = False
+ blender_modifier.use_edge_sharp = True
+
+ blender_mesh_object.data.show_edge_seams = True
+ blender_mesh_object.data.show_edge_sharp = True
+
+ return blender_modifier
+
+
+###########################################################################
+def rotation_matrix(v_track, v_up):
+ ## rotation matrix from two vectors
+ ## http://gamedev.stackexchange.com/questions/20097/how-to-calculate-a-3x3-rotation-matrix-from-2-direction-vectors
+ ## http://www.fastgraph.com/makegames/3drotation/
+ matrix = Matrix().to_3x3()
+
+ c1 = v_track
+ c1.normalize()
+
+ c0 = c1.cross(v_up)
+ c0.normalize()
+
+ c2 = c0.cross(c1)
+ c2.normalize()
+
+ matrix.col[0] = c0
+ matrix.col[1] = c1
+ matrix.col[2] = c2
+
+ return matrix
+
+
+###############################################################################
+def matrix_difference(mat_src, mat_dst):
+ mat_dst_inv = mat_dst.copy()
+ mat_dst_inv.invert()
+ return mat_dst_inv * mat_src
+
+
+###############################################################################
+def set_sence_to_metric(blender_context):
+ try:
+ # set metrics
+ blender_context.scene.unit_settings.system = 'METRIC'
+ blender_context.scene.unit_settings.system_rotation = 'DEGREES'
+ blender_context.scene.unit_settings.scale_length = 0.001 # 1.0mm
+ blender_context.scene.unit_settings.use_separate = False
+ blender_context.tool_settings.normal_size = 1.0 # 1.0mm
+
+ # set all 3D views to texture shaded
+ # and set up the clipping
+ for screen in blender_context.blend_data.screens:
+ for area in screen.areas:
+ if (area.type != 'VIEW_3D'):
+ continue
+
+ for space in area.spaces:
+ if (space.type != 'VIEW_3D'):
+ continue
+
+ #space.viewport_shade = 'SOLID'
+ space.show_textured_solid = True
+ space.clip_start = 0.1 # 0.1mm
+ space.clip_end = 1000000.0 # 1km
+ #screen.scene.game_settings.material_mode = 'MULTITEXTURE'
+
+ except Exception:
+ raise
+
+ else:
+ pass
+
+
+###############################################################################
+
+###############################################################################
+#234567890123456789012345678901234567890123456789012345678901234567890123456789
+#--------1---------2---------3---------4---------5---------6---------7---------
+# ##### END OF FILE #####