diff options
Diffstat (limited to 'io_scene_ms3d/ms3d_spec.py')
-rw-r--r-- | io_scene_ms3d/ms3d_spec.py | 2069 |
1 files changed, 2069 insertions, 0 deletions
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 ##### |