1
# ##### BEGIN GPL LICENSE BLOCK #####
3
# This program is free software; you can redistribute it and/or
4
# modify it under the terms of the GNU General Public License
5
# as published by the Free Software Foundation; either version 2
6
# of the License, or (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software Foundation,
15
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
# ##### END GPL LICENSE BLOCK #####
21
###############################################################################
22
#234567890123456789012345678901234567890123456789012345678901234567890123456789
23
#--------1---------2---------3---------4---------5---------6---------7---------
26
# ##### BEGIN COPYRIGHT BLOCK #####
28
# initial script copyright (c)2011 Alexander Nussbaumer
30
# ##### END COPYRIGHT BLOCK #####
41
import bpy_extras.io_utils
44
PROP_NAME_NAME = "name"
45
PROP_NAME_MODE = "mode"
46
PROP_NAME_TEXTURE = "texture"
47
PROP_NAME_ALPHAMAP = "alphamap"
48
PROP_NAME_FLAGS = "flags"
49
PROP_NAME_PARENTNAME = "parentName"
50
PROP_NAME_EXTRA = "extra"
51
PROP_NAME_COMMENT = "comment"
52
PROP_NAME_AMBIENT = "ambient"
53
PROP_NAME_EMISSIVE = "emissive"
54
PROP_NAME_COLOR = "color"
59
# MilkShape 3D 1.8.5 File Format Specification
62
# This specifcation is written in Python 3.1 style. (C was original)
65
# The data structures are defined in the order as they appear
74
###############################################################################
78
MAX_VERTICES = 65534 # 0..65533; note: (65534???, 65535???)
79
MAX_TRIANGLES = 65534 # 0..65533; note: (65534???, 65535???)
80
MAX_GROUPS = 255 # 1..255; note: (0 default group)
81
MAX_MATERIALS = 128 # 0..127; note: (-1 no material)
82
MAX_JOINTS = 128 # 0..127; note: (-1 no joint)
83
MAX_SMOOTH_GROUP = 32 # 0..32; note: (0 no smoothing group)
86
###############################################################################
97
###############################################################################
101
HEADER = "MS3D000000"
103
###############################################################################
116
LENGTH_FILENAME = 128
119
###############################################################################
121
""" read a single byte from file """
122
value = struct.unpack("<B", file.read(SIZE_BYTE))[0]
125
def write_byte(file, value):
126
""" write a single byte to file """
127
file.write(struct.pack("<B", value))
129
###############################################################################
131
""" read a single char (signed byte) from file """
132
value = struct.unpack("<b", file.read(SIZE_CHAR))[0]
135
def write_char(file, value):
136
""" write a single char (signed byte) to file """
137
file.write(struct.pack("<b", value))
139
###############################################################################
141
""" read a single word from file """
142
value = struct.unpack("<H", file.read(SIZE_WORD))[0]
145
def write_word(file, value):
146
""" write a single word to file """
147
file.write(struct.pack("<H", value))
149
###############################################################################
150
def read_dword(file):
151
""" read a single double word from file """
152
value = struct.unpack("<I", file.read(SIZE_DWORD))[0]
155
def write_dword(file, value):
156
""" write a single double word to file """
157
file.write(struct.pack("<I", value))
159
###############################################################################
160
def read_float(file):
161
""" read a single float from file """
162
value = struct.unpack("<f", file.read(SIZE_FLOAT))[0]
165
def write_float(file, value):
166
""" write a single float to file """
167
file.write(struct.pack("<f", value))
169
###############################################################################
170
def read_array(file, itemReader, count):
171
""" read an array[count] of objects from file, by using a itemReader """
173
for i in range(count):
174
itemValue = itemReader(file)
175
value.append(itemValue)
178
###############################################################################
179
def write_array(file, itemWriter, count, value):
180
""" write an array[count] of objects to file, by using a itemWriter """
181
for i in range(count):
183
itemWriter(file, itemValue)
185
###############################################################################
186
def read_array2(file, itemReader, count, count2):
187
""" read an array[count][count2] of objects from file,
188
by using a itemReader """
190
for i in range(count):
191
itemValue = read_array(file, itemReader, count2)
192
value.append(tuple(itemValue))
193
return value #tuple(value)
195
###############################################################################
196
def write_array2(file, itemWriter, count, count2, value):
197
""" write an array[count][count2] of objects to file,
198
by using a itemWriter """
199
for i in range(count):
201
write_array(file, itemWriter, count2, itemValue)
203
###############################################################################
204
def read_string(file, length):
205
""" read a string of a specific length from file """
208
for i in range(length):
209
raw = struct.unpack("<b", file.read(SIZE_CHAR))[0]
210
if (raw >= 32) & (raw <= 255):
224
finalValue = "".join(value)
227
###############################################################################
228
def write_string(file, length, value):
229
""" write a string of a specific length to file """
231
for i in range(length):
235
if (isinstance(c, str)):
238
elif (isinstance(c, int)):
245
file.write(struct.pack("<b", raw % 255))
248
###############################################################################
250
# multi complex types
252
###############################################################################
257
#char id[LENGTH_ID]; // always "MS3D000000"
272
:arg id: magic number of file
273
:type id: :class:`string`
274
:arg version: version number of file
275
:type version: :class:`dword`
279
self.version = defaultVersion
282
return "\n<id='{0}', version={1}>".format(
288
return hash(self.id) ^ hash(self.version)
290
def __eq__(self, other):
291
return ((self is not None) and (other is not None)
292
and (self.id == other.id)
293
and (self.version == other.version))
295
def read(self, file):
296
self.id = read_string(file, LENGTH_ID)
297
self.version = read_dword(file)
300
def write(self, file):
301
write_string(file, LENGTH_ID, self.id)
302
write_dword(file, self.version)
305
###############################################################################
310
#byte flags; // FLAG_NONE | FLAG_SELECTED | FLAG_SELECTED2 | FLAG_HIDDEN
312
#char boneId; // -1 = no bone
313
#byte referenceCount;
323
defaultFlags=FLAG_NONE,
324
defaultVertex=(0.0 ,0.0 ,0.0),
326
defaultReferenceCount=0
331
:arg flags: selection flag
332
:type flags: :class:`byte`
334
:type vertex: :class:`float[3]`
336
:type boneId: :class:`char`
337
:arg referenceCount: reference count
338
:type referenceCount: :class:`byte`
341
self.flags = defaultFlags
342
self._vertex = defaultVertex
343
self.boneId = defaultBoneId
344
self.referenceCount = defaultReferenceCount
348
return "\n<flags={0}, vertex={1}, boneId={2},"\
349
" referenceCount={3}>".format(
357
return (hash(self.vertex)
360
#^ hash(self.referenceCount)
363
def __eq__(self, other):
364
return ((self.vertex == other.vertex)
365
#and (self.flags == other.flags)
366
#and (self.boneId == other.boneId)
367
#and (self.referenceCount == other.referenceCount)
376
def read(self, file):
377
self.flags = read_byte(file)
378
self._vertex = read_array(file, read_float, 3)
379
self.boneId = read_char(file)
380
self.referenceCount = read_byte(file)
383
def write(self, file):
384
write_byte(file, self.flags)
385
write_array(file, write_float, 3, self.vertex)
386
write_char(file, self.boneId)
387
write_byte(file, self.referenceCount)
390
###############################################################################
391
class ms3d_triangle_t:
395
#word flags; // FLAG_NONE | FLAG_SELECTED | FLAG_SELECTED2 | FLAG_HIDDEN
396
#word vertexIndices[3];
397
#float vertexNormals[3][3];
400
#byte smoothingGroup; // 1 - 32
414
defaultFlags=FLAG_NONE,
415
defaultVertexIndices=(0, 0, 0),
416
defaultVertexNormals=(
420
defaultS=(0.0, 0.0, 0.0),
421
defaultT=(0.0, 0.0, 0.0),
422
defaultSmoothingGroup=1,
428
:arg flags: selection flag
429
:type flags: :class:`word`
430
:arg vertexIndices: vertex indices
431
:type vertexIndices: :class:`word[3]`
432
:arg vertexNormals: vertex normales
433
:type vertexNormals: :class:`float[3][3]`
435
:type s: :class:`float[3]`
437
:type t: :class:`float[3]`
438
:arg smoothingGroup: smooth group
439
:type smoothingGroup: :class:`byte`
440
:arg groupIndex: group index
441
:type groupIndex: :class:`byte`
444
self.flags = defaultFlags
445
self._vertexIndices = defaultVertexIndices
446
self._vertexNormals = defaultVertexNormals
449
self.smoothingGroup = defaultSmoothingGroup
450
self.groupIndex = defaultGroupIndex
453
return "\n<flags={0}, vertexIndices={1}, vertexNormals={2}, s={3},"\
454
" t={4}, smoothingGroup={5}, groupIndex={6}>".format(
466
def vertexIndices(self):
467
return self._vertexIndices
470
def vertexNormals(self):
471
return self._vertexNormals
482
def read(self, file):
483
self.flags = read_word(file)
484
self._vertexIndices = read_array(file, read_word, 3)
485
self._vertexNormals = read_array2(file, read_float, 3, 3)
486
self._s = read_array(file, read_float, 3)
487
self._t = read_array(file, read_float, 3)
488
self.smoothingGroup = read_byte(file)
489
self.groupIndex = read_byte(file)
492
def write(self, file):
493
write_word(file, self.flags)
494
write_array(file, write_word, 3, self.vertexIndices)
495
write_array2(file, write_float, 3, 3, self.vertexNormals)
496
write_array(file, write_float, 3, self.s)
497
write_array(file, write_float, 3, self.t)
498
write_byte(file, self.smoothingGroup)
499
write_byte(file, self.groupIndex)
502
###############################################################################
507
#byte flags; // FLAG_NONE | FLAG_SELECTED | FLAG_HIDDEN
510
#word triangleIndices[numtriangles]; // the groups group the triangles
511
#char materialIndex; // -1 = no material
522
defaultFlags=FLAG_NONE,
524
defaultNumtriangles=0,
525
defaultTriangleIndices=None,
526
defaultMaterialIndex=-1
531
:arg flags: selection flag
532
:type flags: :class:`byte`
534
:type name: :class:`string`
535
:arg numtriangles: number of triangles
536
:type numtriangles: :class:`word`
537
:arg triangleIndices: array of triangle indices
538
:type triangleIndices: :class:`word`
539
:arg materialIndex: material index
540
:type materialIndex: :class:`char`
543
if (defaultName is None):
546
if (defaultTriangleIndices is None):
547
defaultTriangleIndices = []
549
self.flags = defaultFlags
550
self.name = defaultName
551
#self._numtriangles = defaultNumtriangles
552
self._triangleIndices = defaultTriangleIndices
553
self.materialIndex = defaultMaterialIndex
556
return "\n<flags={0}, name='{1}', numtriangles={2},"\
557
" triangleIndices={3}, materialIndex={4}>".format(
561
self.triangleIndices,
567
def numtriangles(self):
568
if self.triangleIndices is None:
570
return len(self.triangleIndices)
573
def triangleIndices(self):
574
return self._triangleIndices
577
def read(self, file):
578
self.flags = read_byte(file)
579
self.name = read_string(file, LENGTH_NAME)
580
_numtriangles = read_word(file)
581
self._triangleIndices = read_array(file, read_word, _numtriangles)
582
self.materialIndex = read_char(file)
585
def write(self, file):
586
write_byte(file, self.flags)
587
write_string(file, LENGTH_NAME, self.name)
588
write_word(file, self.numtriangles)
589
write_array(file, write_word, self.numtriangles, self.triangleIndices)
590
write_char(file, self.materialIndex)
593
###############################################################################
594
class ms3d_material_t:
598
#char name[LENGTH_NAME];
603
#float shininess; // 0.0f - 128.0f
604
#float transparency; // 0.0f - 1.0f
605
#char mode; // 0, 1, 2 is unused now
606
#char texture[LENGTH_FILENAME]; // texture.bmp
607
#char alphamap[LENGTH_FILENAME]; // alpha.bmp
624
defaultAmbient=(0.0, 0.0, 0.0, 0.0),
625
defaultDiffuse=(0.0, 0.0, 0.0, 0.0),
626
defaultSpecular=(0.0, 0.0, 0.0, 0.0),
627
defaultEmissive=(0.0, 0.0, 0.0, 0.0),
628
defaultShininess=0.0,
629
defaultTransparency=0.0,
638
:type name: :class:`string`
639
:arg ambient: ambient
640
:type ambient: :class:`float[4]`
641
:arg diffuse: diffuse
642
:type diffuse: :class:`float[4]`
643
:arg specular: specular
644
:type specular: :class:`float[4]`
645
:arg emissive: emissive
646
:type emissive: :class:`float[4]`
647
:arg shininess: shininess
648
:type shininess: :class:`float`
649
:arg transparency: transparency
650
:type transparency: :class:`float`
652
:type mode: :class:`char`
653
:arg texture: texture name
654
:type texture: :class:`string`
655
:arg alphamap: alphamap name
656
:type alphamap: :class:`string`
659
if (defaultName is None):
662
if (defaultTexture is None):
665
if (defaultAlphamap is None):
668
self.name = defaultName
669
self._ambient = defaultAmbient
670
self._diffuse = defaultDiffuse
671
self._specular = defaultSpecular
672
self._emissive = defaultEmissive
673
self.shininess = defaultShininess
674
self.transparency = defaultTransparency
675
self.mode = defaultMode
676
self.texture = defaultTexture
677
self.alphamap = defaultAlphamap
680
return "\n<name='{0}', ambient={1}, diffuse={2}, specular={3},"\
681
" emissive={4}, shininess={5}, transparency={6}, mode={7},"\
682
" texture='{8}', alphamap='{9}'>".format(
696
return (hash(self.name)
700
^ hash(self.specular)
701
^ hash(self.emissive)
703
^ hash(self.shininess)
704
^ hash(self.transparency)
708
^ hash(self.alphamap)
711
def __eq__(self, other):
712
return ((self.name == other.name)
714
and (self.ambient == other.ambient)
715
and (self.diffuse == other.diffuse)
716
and (self.specular == other.specular)
717
and (self.emissive == other.emissive)
719
and (self.shininess == other.shininess)
720
and (self.transparency == other.transparency)
721
and (self.mode == other.mode)
723
#and (self.texture == other.texture)
724
#and (self.alphamap == other.alphamap)
738
return self._specular
742
return self._emissive
745
def read(self, file):
746
self.name = read_string(file, LENGTH_NAME)
747
self._ambient = read_array(file, read_float, 4)
748
self._diffuse = read_array(file, read_float, 4)
749
self._specular = read_array(file, read_float, 4)
750
self._emissive = read_array(file, read_float, 4)
751
self.shininess = read_float(file)
752
self.transparency = read_float(file)
753
self.mode = read_char(file)
754
self.texture = read_string(file, LENGTH_FILENAME)
755
self.alphamap = read_string(file, LENGTH_FILENAME)
758
def write(self, file):
759
write_string(file, LENGTH_NAME, self.name)
760
write_array(file, write_float, 4, self.ambient)
761
write_array(file, write_float, 4, self.diffuse)
762
write_array(file, write_float, 4, self.specular)
763
write_array(file, write_float, 4, self.emissive)
764
write_float(file, self.shininess)
765
write_float(file, self.transparency)
766
write_char(file, self.mode)
767
write_string(file, LENGTH_FILENAME, self.texture)
768
write_string(file, LENGTH_FILENAME, self.alphamap)
771
###############################################################################
772
class ms3d_keyframe_rot_t:
776
#float time; // time in seconds
777
#float rotation[3]; // x, y, z angles
786
defaultRotation=(0.0, 0.0, 0.0)
792
:type time: :class:float`
793
:arg rotation: rotation
794
:type rotation: :class:`float[3]`
797
self.time = defaultTime
798
self._rotation = defaultRotation
801
return "\n<time={0}, rotation={1}>".format(
809
return self._rotation
812
def read(self, file):
813
self.time = read_float(file)
814
self._rotation = read_array(file, read_float, 3)
817
def write(self, file):
818
write_float(file, self.time)
819
write_array(file, write_float, 3, self.rotation)
822
###############################################################################
823
class ms3d_keyframe_pos_t:
827
#float time; // time in seconds
828
#float position[3]; // local position
837
defaultPosition=(0.0, 0.0, 0.0)
843
:type time: :class:`float`
844
:arg position: position
845
:type position: :class:`float[3]`
848
self.time = defaultTime
849
self._position = defaultPosition
852
return "\n<time={0}, position={1}>".format(
860
return self._position
863
def read(self, file):
864
self.time = read_float(file)
865
self._position = read_array(file, read_float, 3)
868
def write(self, file):
869
write_float(file, self.time)
870
write_array(file, write_float, 3, self.position)
873
###############################################################################
878
#byte flags; // FLAG_NONE | FLAG_SELECTED | FLAG_DIRTY
879
#char name[LENGTH_NAME];
880
#char parentName[LENGTH_NAME];
881
#float rotation[3]; // local reference matrix
883
#word numKeyFramesRot;
884
#word numKeyFramesTrans;
885
#// local animation matrices
886
#ms3d_keyframe_rot_t keyFramesRot[numKeyFramesRot];
887
#// local animation matrices
888
#ms3d_keyframe_pos_t keyFramesTrans[numKeyFramesTrans];
892
PROP_NAME_PARENTNAME,
896
"_numKeyFramesTrans",
903
defaultFlags=FLAG_NONE,
905
defaultParentName="",
906
defaultRotation=(0.0, 0.0, 0.0),
907
defaultPosition=(0.0, 0.0, 0.0),
908
defaultNumKeyFramesRot=0,
909
defaultNumKeyFramesTrans=0,
910
defaultKeyFramesRot=None,
911
defaultKeyFramesTrans=None
917
:type flags: :class:`byte`
919
:type name: :class:`string`
920
:arg parentName: parentName
921
:type parentName: :class:`string`
922
:arg rotation: rotation
923
:type rotation: :class:`float[3]`
924
:arg position: position
925
:type position: :class:`float[3]`
926
:arg numKeyFramesRot: numKeyFramesRot
927
:type numKeyFramesRot: :class:`word`
928
:arg numKeyFramesTrans: numKeyFramesTrans
929
:type numKeyFramesTrans: :class:`word`
930
:arg keyFramesRot: keyFramesRot
931
:type nkeyFramesRotame: :class:`ms3d_spec.ms3d_keyframe_rot_t[]`
932
:arg keyFramesTrans: keyFramesTrans
933
:type keyFramesTrans: :class:`ms3d_spec.ms3d_keyframe_pos_t[]`
936
if (defaultName is None):
939
if (defaultParentName is None):
940
defaultParentName = ""
942
if (defaultKeyFramesRot is None):
943
defaultKeyFramesRot = [] #ms3d_keyframe_rot_t()
945
if (defaultKeyFramesTrans is None):
946
defaultKeyFramesTrans = [] #ms3d_keyframe_pos_t()
948
self.flags = defaultFlags
949
self.name = defaultName
950
self.parentName = defaultParentName
951
self._rotation = defaultRotation
952
self._position = defaultPosition
953
#self._numKeyFramesRot = defaultNumKeyFramesRot
954
#self._numKeyFramesTrans = defaultNumKeyFramesTrans
955
self._keyFramesRot = defaultKeyFramesRot
956
self._keyFramesTrans = defaultKeyFramesTrans
959
return "\n<flags={0}, name='{1}', parentName='{2}', rotation={3},"\
960
" position={4}, numKeyFramesRot={5}, numKeyFramesTrans={6},"\
961
" keyFramesRot={7}, keyFramesTrans={8}>".format(
967
self.numKeyFramesRot,
968
self.numKeyFramesTrans,
976
return self._rotation
980
return self._position
983
def numKeyFramesRot(self):
984
if self.keyFramesRot is None:
986
return len(self.keyFramesRot)
989
def numKeyFramesTrans(self):
990
if self.keyFramesTrans is None:
992
return len(self.keyFramesTrans)
995
def keyFramesRot(self):
996
return self._keyFramesRot
999
def keyFramesTrans(self):
1000
return self._keyFramesTrans
1003
def read(self, file):
1004
self.flags = read_byte(file)
1005
self.name = read_string(file, LENGTH_NAME)
1006
self.parentName = read_string(file, LENGTH_NAME)
1007
self._rotation = read_array(file, read_float, 3)
1008
self._position = read_array(file, read_float, 3)
1009
_numKeyFramesRot = read_word(file)
1010
_numKeyFramesTrans = read_word(file)
1011
self._keyFramesRot = []
1012
for i in range(_numKeyFramesRot):
1013
self.keyFramesRot.append(ms3d_keyframe_rot_t().read(file))
1014
self._keyFramesTrans = []
1015
for i in range(_numKeyFramesTrans):
1016
self.keyFramesTrans.append(ms3d_keyframe_pos_t().read(file))
1019
def write(self, file):
1020
write_byte(file, self.flags)
1021
write_string(file, LENGTH_NAME, self.name)
1022
write_string(file, LENGTH_NAME, self.parentName)
1023
write_array(file, write_float, 3, self.rotation)
1024
write_array(file, write_float, 3, self.position)
1025
write_word(file, self.numKeyFramesRot)
1026
write_word(file, self.numKeyFramesTrans)
1027
for i in range(self.numKeyFramesRot):
1028
self.keyFramesRot[i].write(file)
1029
for i in range(self.numKeyFramesTrans):
1030
self.keyFramesTrans[i].write(file)
1033
###############################################################################
1034
class ms3d_comment_t:
1038
#int index; // index of group, material or joint
1039
#int commentLength; // length of comment (terminating '\0' is not saved),
1040
# "MC" has comment length of 2 (not 3)
1041
#char comment[commentLength]; // comment
1051
defaultCommentLength=0,
1058
:type index: :class:`dword`
1059
:arg commentLength: commentLength
1060
:type commentLength: :class:`dword`
1061
:arg comment: comment
1062
:type comment: :class:`string`
1065
if (defaultComment is None):
1068
self.index = defaultIndex
1069
#self._commentLength = defaultCommentLength
1070
self.comment = defaultComment
1073
return "\n<index={0}, commentLength={1}, comment={2}>".format(
1081
def commentLength(self):
1082
if self.comment is None:
1084
return len(self.comment)
1087
def read(self, file):
1088
self.index = read_dword(file)
1089
_commentLength = read_dword(file)
1090
self.comment = read_string(file, _commentLength)
1093
def write(self, file):
1094
write_dword(file, self.index)
1095
write_dword(file, self.commentLength)
1096
write_string(file, self.commentLength, self.comment)
1099
###############################################################################
1100
class ms3d_modelcomment_t:
1104
#int commentLength; // length of comment (terminating '\0' is not saved),
1105
# "MC" has comment length of 2 (not 3)
1106
#char comment[commentLength]; // comment
1114
defaultCommentLength=0,
1120
:arg commentLength: commentLength
1121
:type commentLength: :class:`dword`
1122
:arg comment: comment
1123
:type comment: :class:`string`
1126
if (defaultComment is None):
1129
#self._commentLength = defaultCommentLength
1130
self.comment = defaultComment
1133
return "\n<commentLength={0}, comment={1}>".format(
1140
def commentLength(self):
1141
if self.comment is None:
1143
return len(self.comment)
1146
def read(self, file):
1147
_commentLength = read_dword(file)
1148
self.comment = read_string(file, _commentLength)
1151
def write(self, file):
1152
write_dword(file, self.commentLength)
1153
write_string(file, self.commentLength, self.comment)
1156
###############################################################################
1157
class ms3d_vertex_ex1_t:
1161
#char boneIds[3]; // index of joint or -1, if -1, then that weight is
1162
# ignored, since subVersion 1
1163
#byte weights[3]; // vertex weight ranging from 0 - 255, last weight is
1164
# computed by 1.0 - sum(all weights), since subVersion 1
1165
#// weight[0] is the weight for boneId in ms3d_vertex_t
1166
#// weight[1] is the weight for boneIds[0]
1167
#// weight[2] is the weight for boneIds[1]
1168
#// 1.0f - weight[0] - weight[1] - weight[2] is the weight for boneIds[2]
1176
defaultBoneIds=(-1, -1, -1),
1177
defaultWeights=(0, 0, 0)
1182
:arg boneIds: boneIds
1183
:type boneIds: :class:`char[3]`
1184
:arg weights: weights
1185
:type weights: :class:`byte[3]`
1188
self._boneIds = defaultBoneIds
1189
self._weights = defaultWeights
1192
return "\n<boneIds={0}, weights={1}>".format(
1200
return self._boneIds
1204
return self._weights
1207
def read(self, file):
1208
self._boneIds = read_array(file, read_char, 3)
1209
self._weights = read_array(file, read_byte, 3)
1212
def write(self, file):
1213
write_array(file, write_char, 3, self.boneIds)
1214
write_array(file, write_byte, 3, self.weights)
1217
###############################################################################
1218
class ms3d_vertex_ex2_t:
1222
#char boneIds[3]; // index of joint or -1, if -1, then that weight is
1223
# ignored, since subVersion 1
1224
#byte weights[3]; // vertex weight ranging from 0 - 100, last weight is
1225
# computed by 1.0 - sum(all weights), since subVersion 1
1226
#// weight[0] is the weight for boneId in ms3d_vertex_t
1227
#// weight[1] is the weight for boneIds[0]
1228
#// weight[2] is the weight for boneIds[1]
1229
#// 1.0f - weight[0] - weight[1] - weight[2] is the weight for boneIds[2]
1230
#unsigned int extra; // vertex extra, which can be used as color or
1231
# anything else, since subVersion 2
1240
defaultBoneIds=(-1, -1, -1),
1241
defaultWeights=(0, 0, 0),
1247
:arg boneIds: boneIds
1248
:type boneIds: :class:`char[3]`
1249
:arg weights: weights
1250
:type weights: :class:`byte[3]`
1252
:type extra: :class:`dword`
1255
self._boneIds = defaultBoneIds
1256
self._weights = defaultWeights
1257
self.extra = defaultExtra
1260
return "\n<boneIds={0}, weights={1}, extra={2}>".format(
1269
return self._boneIds
1273
return self._weights
1276
def read(self, file):
1277
self._boneIds = read_array(file, read_char, 3)
1278
self._weights = read_array(file, read_byte, 3)
1279
self.extra = read_dword(file)
1282
def write(self, file):
1283
write_array(file, write_char, 3, self.boneIds)
1284
write_array(file, write_byte, 3, self.weights)
1285
write_dword(file, self.extra)
1288
###############################################################################
1289
class ms3d_vertex_ex3_t:
1293
#char boneIds[3]; // index of joint or -1, if -1, then that weight is
1294
# ignored, since subVersion 1
1295
#byte weights[3]; // vertex weight ranging from 0 - 100, last weight is
1296
# computed by 1.0 - sum(all weights), since subVersion 1
1297
#// weight[0] is the weight for boneId in ms3d_vertex_t
1298
#// weight[1] is the weight for boneIds[0]
1299
#// weight[2] is the weight for boneIds[1]
1300
#// 1.0f - weight[0] - weight[1] - weight[2] is the weight for boneIds[2]
1301
#unsigned int extra; // vertex extra, which can be used as color or
1302
# anything else, since subVersion 2
1311
defaultBoneIds=(-1, -1, -1),
1312
defaultWeights=(0, 0, 0),
1318
:arg boneIds: boneIds
1319
:type boneIds: :class:`char[3]`
1320
:arg weights: weights
1321
:type weights: :class:`byte[3]`
1323
:type extra: :class:`dword`
1326
self._boneIds = defaultBoneIds
1327
self._weights = defaultWeights
1328
self.extra = defaultExtra
1331
return "\n<boneIds={0}, weights={1}, extra={2}>".format(
1340
return self._boneIds
1344
return self._weights
1347
def read(self, file):
1348
self._boneIds = read_array(file, read_char, 3)
1349
self._weights = read_array(file, read_byte, 3)
1350
self.extra = read_dword(file)
1353
def write(self, file):
1354
write_array(file, write_char, 3, self.boneIds)
1355
write_array(file, write_byte, 3, self.weights)
1356
write_dword(file, self.extra)
1359
###############################################################################
1360
class ms3d_joint_ex_t:
1364
#float color[3]; // joint color, since subVersion == 1
1371
defaultColor=(0.0, 0.0, 0.0)
1377
:type color: :class:`float[3]`
1380
self._color = defaultColor
1383
return "\n<color={0}>".format(self.color)
1391
def read(self, file):
1392
self._color = read_array(file, read_float, 3)
1395
def write(self, file):
1396
write_array(file, write_float, 3, self.color)
1399
###############################################################################
1400
class ms3d_model_ex_t:
1404
#float jointSize; // joint size, since subVersion == 1
1405
#int transparencyMode; // 0 = simple, 1 = depth buffered with alpha ref,
1406
# 2 = depth sorted triangles, since subVersion == 1
1407
#float alphaRef; // alpha reference value for transparencyMode = 1,
1408
# since subVersion == 1
1417
defaultJointSize=0.0,
1418
defaultTransparencyMode=0,
1424
:arg jointSize: jointSize
1425
:type jointSize: :class:`float[3]`
1426
:arg transparencyMode: transparencyMode
1427
:type transparencyMode: :class:`dword`
1428
:arg alphaRef: alphaRef
1429
:type alphaRef: :class:`float[3]`
1432
self.jointSize = defaultJointSize
1433
self.transparencyMode = defaultTransparencyMode
1434
self.alphaRef = defaultAlphaRef
1437
return "\n<jointSize={0}, transparencyMode={1}, alphaRef={2}>".format(
1439
self.transparencyMode,
1443
def read(self, file):
1444
self.jointSize = read_float(file)
1445
self.transparencyMode = read_dword(file)
1446
self.alphaRef = read_float(file)
1449
def write(self, file):
1450
write_float(file, self.jointSize)
1451
write_dword(file, self.transparencyMode)
1452
write_float(file, self.alphaRef)
1455
###############################################################################
1459
###############################################################################
1479
"subVersionComments",
1480
"_nNumGroupComments",
1482
"_nNumMaterialComments",
1483
"_materialComments",
1484
"_nNumJointComments",
1486
"_nHasModelComment",
1488
"subVersionVertexExtra",
1490
"subVersionJointExtra",
1492
"subVersionModelExtra",
1506
if (defaultName is None):
1509
self.name = defaultName
1511
# First comes the header (sizeof(ms3d_header_t) == 14)
1512
self.header = ms3d_header_t()
1514
# Then comes the number of vertices
1515
#self.nNumVertices = 0
1517
# Then comes nNumVertices times ms3d_vertex_t structs
1518
# (sizeof(ms3d_vertex_t) == 15)
1519
self._vertices = [] #ms3d_vertex_t()
1521
# Then comes the number of triangles
1522
#self.nNumTriangles = 0
1524
# Then come nNumTriangles times ms3d_triangle_t structs
1525
# (sizeof(ms3d_triangle_t) == 70)
1526
self._triangles = [] #ms3d_triangle_t()
1529
# Then comes the number of groups
1530
#self.nNumGroups = 0
1532
# Then comes nNumGroups times groups (the sizeof a group is dynamic,
1533
# because of triangleIndices is numtriangles long)
1534
self._groups = [] #ms3d_group_t()
1537
# number of materials
1538
#self.nNumMaterials = 0
1540
# Then comes nNumMaterials times ms3d_material_t structs
1541
# (sizeof(ms3d_material_t) == 361)
1542
self._materials = [] #ms3d_material_t()
1545
# save some keyframer data
1546
self.fAnimationFPS = 0.0
1547
self.fCurrentTime = 0.0
1548
self.iTotalFrames = 0
1552
#self.nNumJoints = 0
1554
# Then comes nNumJoints joints (the size of joints are dynamic,
1555
# because each joint has a differnt count of keys
1556
self._joints = [] #ms3d_joint_t()
1559
# Then comes the subVersion of the comments part, which is not
1560
# available in older files
1561
self.subVersionComments = 1
1564
# Then comes the numer of group comments
1565
#self.nNumGroupComments = 0
1567
# Then comes nNumGroupComments times group comments, which are dynamic,
1568
# because the comment can be any length
1569
self._groupComments = [] #ms3d_comment_t()
1572
# Then comes the number of material comments
1573
#self.nNumMaterialComments = 0
1575
# Then comes nNumMaterialComments times material comments, which are
1576
# dynamic, because the comment can be any length
1577
self._materialComments = [] #ms3d_comment_t()
1580
# Then comes the number of joint comments
1581
#self.nNumJointComments = 0
1583
# Then comes nNumJointComments times joint comments, which are dynamic,
1584
# because the comment can be any length
1585
self._jointComments = [] #ms3d_comment_t()
1588
# Then comes the number of model comments, which is always 0 or 1
1589
#self.nHasModelComment = 0
1591
# Then comes nHasModelComment times model comments, which are dynamic,
1592
# because the comment can be any length
1593
self._modelComment = None #ms3d_modelcomment_t()
1596
# Then comes the subversion of the vertex extra information like bone
1597
# weights, extra etc.
1598
self.subVersionVertexExtra = 2
1600
# ms3d_vertex_ex_t for subVersionVertexExtra in {1, 2, 3}
1601
#ms3d_vertex_ex1_t() #ms3d_vertex_ex2_t() #ms3d_vertex_ex3_t()
1602
self._vertex_ex = []
1603
# Then comes nNumVertices times ms3d_vertex_ex_t structs
1604
# (sizeof(ms3d_vertex_ex_t) == 10)
1607
# Then comes the subversion of the joint extra information like
1609
self.subVersionJointExtra = 1 # ??? in spec it is 2,
1610
# but in MilkShake3D 1.8.4 a joint subversion of 2 is unknown
1612
# ms3d_joint_ex_t for subVersionJointExtra == 1
1613
self._joint_ex = [] #ms3d_joint_ex_t()
1614
# Then comes nNumJoints times ms3d_joint_ex_t structs
1615
# (sizeof(ms3d_joint_ex_t) == 12)
1618
# Then comes the subversion of the model extra information
1619
self.subVersionModelExtra = 1
1621
# ms3d_model_ex_t for subVersionModelExtra == 1
1622
self.model_ex = ms3d_model_ex_t()
1626
def nNumVertices(self):
1627
if self.vertices is None:
1629
return len(self.vertices)
1633
return self._vertices
1637
def nNumTriangles(self):
1638
if self.triangles is None:
1640
return len(self.triangles)
1643
def triangles(self):
1644
return self._triangles
1648
def nNumGroups(self):
1649
if self.groups is None:
1651
return len(self.groups)
1659
def nNumMaterials(self):
1660
if self.materials is None:
1662
return len(self.materials)
1665
def materials(self):
1666
return self._materials
1670
def nNumJoints(self):
1671
if self.joints is None:
1673
return len(self.joints)
1681
def nNumGroupComments(self):
1682
if self.groupComments is None:
1684
return len(self.groupComments)
1687
def groupComments(self):
1688
return self._groupComments
1692
def nNumMaterialComments(self):
1693
if self.materialComments is None:
1695
return len(self.materialComments)
1698
def materialComments(self):
1699
return self._materialComments
1703
def nNumJointComments(self):
1704
if self.jointComments is None:
1706
return len(self.jointComments)
1709
def jointComments(self):
1710
return self._jointComments
1714
def nHasModelComment(self):
1715
if self.modelComment is None:
1720
def modelComment(self):
1721
return self._modelComment
1725
def vertex_ex(self):
1726
return self._vertex_ex
1730
return self._joint_ex
1733
def print_internal(self):
1735
print("##############################################################")
1736
print("## the internal data of ms3d_file_t object...")
1739
print("header={0}".format(self.header))
1741
print("nNumVertices={0}".format(self.nNumVertices))
1742
print("vertices=[", end="")
1744
for obj in self.vertices:
1745
print("{0}".format(obj), end="")
1748
print("nNumTriangles={0}".format(self.nNumTriangles))
1749
print("triangles=[", end="")
1751
for obj in self.triangles:
1752
print("{0}".format(obj), end="")
1755
print("nNumGroups={0}".format(self.nNumGroups))
1756
print("groups=[", end="")
1758
for obj in self.groups:
1759
print("{0}".format(obj), end="")
1762
print("nNumMaterials={0}".format(self.nNumMaterials))
1763
print("materials=[", end="")
1765
for obj in self.materials:
1766
print("{0}".format(obj), end="")
1769
print("fAnimationFPS={0}".format(self.fAnimationFPS))
1770
print("fCurrentTime={0}".format(self.fCurrentTime))
1771
print("iTotalFrames={0}".format(self.iTotalFrames))
1773
print("nNumJoints={0}".format(self.nNumJoints))
1774
print("joints=[", end="")
1776
for obj in self.joints:
1777
print("{0}".format(obj), end="")
1780
print("subVersionComments={0}".format(self.subVersionComments))
1782
print("nNumGroupComments={0}".format(self.nNumGroupComments))
1783
print("groupComments=[", end="")
1784
if self.groupComments:
1785
for obj in self.groupComments:
1786
print("{0}".format(obj), end="")
1789
print("nNumMaterialComments={0}".format(self.nNumMaterialComments))
1790
print("materialComments=[", end="")
1791
if self.materialComments:
1792
for obj in self.materialComments:
1793
print("{0}".format(obj), end="")
1796
print("nNumJointComments={0}".format(self.nNumJointComments))
1797
print("jointComments=[", end="")
1798
if self.jointComments:
1799
for obj in self.jointComments:
1800
print("{0}".format(obj), end="")
1803
print("nHasModelComment={0}".format(self.nHasModelComment))
1804
print("modelComment={0}".format(self.modelComment))
1806
print("subVersionVertexExtra={0}".format(self.subVersionVertexExtra))
1807
print("vertex_ex={0}".format(self.vertex_ex))
1809
print("subVersionJointExtra={0}".format(self.subVersionJointExtra))
1810
print("joint_ex={0}".format(self.joint_ex))
1812
print("subVersionModelExtra={0}".format(self.subVersionModelExtra))
1813
print("model_ex={0}".format(self.model_ex))
1817
print("##############################################################")
1821
def read(self, file):
1823
opens, reads and pars MS3D file.
1824
add content to blender scene
1827
:type file: :class:`io.FileIO`
1830
self.header.read(file)
1832
_nNumVertices = read_word(file)
1834
for i in range(_nNumVertices):
1835
self.vertices.append(ms3d_vertex_t().read(file))
1837
_nNumTriangles = read_word(file)
1838
self._triangles = []
1839
for i in range(_nNumTriangles):
1840
self.triangles.append(ms3d_triangle_t().read(file))
1842
_nNumGroups = read_word(file)
1844
for i in range(_nNumGroups):
1845
self.groups.append(ms3d_group_t().read(file))
1847
_nNumMaterials = read_word(file)
1848
self._materials = []
1849
for i in range(_nNumMaterials):
1850
self.materials.append(ms3d_material_t().read(file))
1852
self.fAnimationFPS = read_float(file)
1853
self.fCurrentTime = read_float(file)
1854
self.iTotalFrames = read_dword(file)
1860
# doesn't matter if doesn't existing.
1862
_nNumJoints = read_word(file)
1864
for i in range(_nNumJoints):
1865
self.joints.append(ms3d_joint_t().read(file))
1869
self.subVersionComments = read_dword(file)
1873
_nNumGroupComments = read_dword(file)
1874
self._groupComments = []
1875
for i in range(_nNumGroupComments):
1876
self.groupComments.append(ms3d_comment_t().read(file))
1880
_nNumMaterialComments = read_dword(file)
1881
self._materialComments = []
1882
for i in range(_nNumMaterialComments):
1883
self.materialComments.append(ms3d_comment_t().read(file))
1887
_nNumJointComments = read_dword(file)
1888
self._jointComments = []
1889
for i in range(_nNumJointComments):
1890
self.jointComments.append(ms3d_comment_t().read(file))
1894
_nHasModelComment = read_dword(file)
1895
if (_nHasModelComment != 0):
1896
self._modelComment = ms3d_modelcomment_t().read(file)
1898
self._modelComment = None
1902
self.subVersionVertexExtra = read_dword(file)
1903
if (self.subVersionVertexExtra in {1, 2, 3}):
1904
self._vertex_ex = []
1905
for i in range(_nNumVertices):
1906
if self.subVersionVertexExtra == 1:
1907
item = ms3d_vertex_ex1_t()
1908
if self.subVersionVertexExtra == 2:
1909
item = ms3d_vertex_ex2_t()
1910
if self.subVersionVertexExtra == 3:
1911
item = ms3d_vertex_ex3_t()
1912
self.vertex_ex.append(item.read(file))
1914
self._vertex_ex = None
1918
self.subVersionJointExtra = read_dword(file)
1920
for i in range(_nNumJoints):
1921
self.joint_ex.append(ms3d_joint_ex_t().read(file))
1925
self.subVersionModelExtra = read_dword(file)
1929
self.model_ex.read(file)
1932
#type, value, traceback = sys.exc_info()
1933
#print("ms3d_file.read - exception in optional try block,"
1934
# " progressCount={0}\n type: '{1}'\n value: '{2}'".format(
1935
# progressCount, type, value, traceback))
1938
if (progressCount <= 0):
1942
if (progressCount <= 1):
1943
self.subVersionComments = None
1945
if (progressCount <= 2):
1946
_nNumGroupComments = None
1947
self._groupComments = None
1949
if (progressCount <= 3):
1950
_nNumMaterialComments = None
1951
self._materialComments = None
1953
if (progressCount <= 4):
1954
_nNumJointComments = None
1955
self._jointComments = None
1957
if (progressCount <= 5):
1958
_nHasModelComment = None
1959
self._modelComment = None
1961
if (progressCount <= 6):
1962
self.subVersionVertexExtra = None
1963
self._vertex_ex = None
1965
if (progressCount <= 7):
1966
self.subVersionJointExtra = None
1967
self._joint_ex = None
1969
if (progressCount <= 8):
1970
self.subVersionModelExtra = None
1972
if (progressCount <= 9):
1973
self.model_ex = None
1981
def write(self, file):
1983
add blender scene content to MS3D
1984
creates, writes MS3D file.
1987
:type file: :class:`io.FileIO`
1990
self.header.write(file)
1992
write_word(file, self.nNumVertices)
1993
for i in range(self.nNumVertices):
1994
self.vertices[i].write(file)
1996
write_word(file, self.nNumTriangles)
1997
for i in range(self.nNumTriangles):
1998
self.triangles[i].write(file)
2000
write_word(file, self.nNumGroups)
2001
for i in range(self.nNumGroups):
2002
self.groups[i].write(file)
2004
write_word(file, self.nNumMaterials)
2005
for i in range(self.nNumMaterials):
2006
self.materials[i].write(file)
2008
write_float(file, self.fAnimationFPS)
2009
write_float(file, self.fCurrentTime)
2010
write_dword(file, self.iTotalFrames)
2014
# doesn't matter if it doesn't complete.
2015
write_word(file, self.nNumJoints)
2016
for i in range(self.nNumJoints):
2017
self.joints[i].write(file)
2019
write_dword(file, self.subVersionComments)
2021
write_dword(file, self.nNumGroupComments)
2022
for i in range(self.nNumGroupComments):
2023
self.groupComments[i].write(file)
2025
write_dword(file, self.nNumMaterialComments)
2026
for i in range(self.nNumMaterialComments):
2027
self.materialComments[i].write(file)
2029
write_dword(file, self.nNumJointComments)
2030
for i in range(self.nNumJointComments):
2031
self.jointComments[i].write(file)
2033
write_dword(file, self.nHasModelComment)
2034
if (self.nHasModelComment != 0):
2035
self.modelComment.write(file)
2037
write_dword(file, self.subVersionVertexExtra)
2038
if (self.subVersionVertexExtra in {1, 2, 3}):
2039
for i in range(self.nNumVertices):
2040
self.vertex_ex[i].write(file)
2042
write_dword(file, self.subVersionJointExtra)
2043
for i in range(self.nNumJoints):
2044
self.joint_ex[i].write(file)
2046
write_dword(file, self.subVersionModelExtra)
2047
self.model_ex.write(file)
2050
#type, value, traceback = sys.exc_info()
2051
#print("ms3d_file.write - exception in optional try block"
2052
# "\n type: '{0}'\n value: '{1}'".format(
2053
# type, value, traceback))
2066
format1 = "\n number of {0}: {1}"
2067
format2 = " limit exceeded! (limit is {0})"
2069
result.append("MS3D statistics:")
2070
result.append(format1.format("vertices ........", self.nNumVertices))
2071
if (self.nNumVertices > MAX_VERTICES):
2072
result.append(format2.format(MAX_VERTICES))
2075
result.append(format1.format("triangles .......", self.nNumTriangles))
2076
if (self.nNumTriangles > MAX_TRIANGLES):
2077
result.append(format2.format(MAX_TRIANGLES))
2080
result.append(format1.format("groups ..........", self.nNumGroups))
2081
if (self.nNumGroups > MAX_GROUPS):
2082
result.append(format2.format(MAX_GROUPS))
2085
result.append(format1.format("materials .......", self.nNumMaterials))
2086
if (self.nNumMaterials > MAX_MATERIALS):
2087
result.append(format2.format(MAX_MATERIALS))
2090
result.append(format1.format("joints ..........", self.nNumJoints))
2091
if (self.nNumJoints > MAX_JOINTS):
2092
result.append(format2.format(MAX_JOINTS))
2095
result.append(format1.format("model comments ..",
2096
self.nHasModelComment))
2097
result.append(format1.format("group comments ..",
2098
self.nNumGroupComments))
2099
result.append(format1.format("material comments",
2100
self.nNumMaterialComments))
2101
result.append(format1.format("joint comments ..",
2102
self.nNumJointComments))
2105
# result.append("\n\nthe data may be corrupted.")
2107
return (valid, ("".join(result)))
2111
def get_group_by_key(self, key):
2120
elif isinstance(key, int):
2121
if (key >= 0) and (key < self.nNumGroups):
2124
elif isinstance(key, string):
2126
if item.name == key:
2129
elif isinstance(key, ms3d_spec.ms3d_triangle_t):
2130
if (key.groupIndex >= 0) and (key.groupIndex < self.nNumGroups):
2131
return item[key.groupIndex]
2136
def get_group_comment_by_key(self, key):
2140
items = self.groupComments
2145
elif isinstance(key, int):
2147
if (item.index == key):
2153
def get_material_by_key(self, key):
2157
items = self.materials
2162
elif isinstance(key, int):
2163
if (key >= 0) and (key < self.nNumMaterials):
2166
elif isinstance(key, string):
2168
if item.name == key:
2171
elif isinstance(key, ms3d_spec.ms3d_group_t):
2172
if (key.materialIndex >= 0) and (key.materialIndex < self.nNumMaterials):
2173
return item[key.materialIndex]
2178
def get_material_comment_by_key(self, key):
2182
items = self.materialComments
2187
elif isinstance(key, int):
2189
if (item.index == key):
2195
def get_joint_by_key(self, key):
2204
elif isinstance(key, int):
2205
if (key >= 0) and (key < self.nNumJoints):
2208
elif isinstance(key, string):
2210
if item.name == key:
2213
elif isinstance(key, ms3d_spec.ms3d_vertex_t):
2214
if (key.boneId >= 0) and (key.boneId < self.nNumJoints):
2215
return item[key.boneId]
2220
def get_joint_ex_by_key(self, key):
2224
items = self.joint_ex
2229
elif isinstance(key, int):
2230
if (key >= 0) and (key < self.nNumJoints):
2233
elif isinstance(key, string):
2234
for i, item in enumerate(self.joints):
2235
if item.name == key:
2238
elif isinstance(key, ms3d_spec.ms3d_joint_t):
2239
for i, item in enumerate(self.joints):
2240
if item.name == key.name:
2243
elif isinstance(key, ms3d_spec.ms3d_vertex_t):
2244
if (key.boneId >= 0) and (key.boneId < self.nNumJoints):
2245
return item[key.boneId]
2250
def get_joint_comment_by_key(self, key):
2254
items = self.jointComments
2259
elif isinstance(key, int):
2261
if (item.index == key):
2267
###############################################################################
2268
#234567890123456789012345678901234567890123456789012345678901234567890123456789
2269
#--------1---------2---------3---------4---------5---------6---------7---------
2270
# ##### END OF FILE #####