2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Support for MS3D file format.
8
24/11/10 - Yar - Foxed range check error
9
22/06/10 - Yar - Added checking of existing material in material library
10
31/05/10 - Yar - Fixes for Linux x64
11
04/23/10 - TL - Animations now load properly (note: All animations must be full key frames. All bones selected in MS3D)
12
The entire animation will be available in TActor.Animations[0]
13
04/23/10 - TL - Added support for double sided textures. To make a double sided texture, you must set the transparency
14
slider to the left just a little bit in MS3D. This loader will notice that, and turn off backface culling for
16
04/23/10 - TL - Added weighted vertex animations
17
04/23/10 - TL - Fixed the way normals are loaded. They will now be loaded properly.
18
04/23/10 - TL - Added support to read the comments section of MS3D files.
20
16/10/08 - UweR - Compatibility fix for Delphi 2009: MaterialIndex is now Byte instead of Char
21
31/03/07 - DaStr - Added $I GLScene.inc
22
24/03/07 - DaStr - Added explicit pointer dereferencing
23
(thanks Burkhard Carstens) (Bugtracker ID = 1678644)
24
19/12/04 - PhP - Added capabilities function
25
28/10/03 - SG - Partly implemented skeletal animation,
26
asynchronous animations will fail however.
27
31/08/03 - DanB - Some code standardisation (by Philipp)
28
03/06/03 - EG - Added header, now self-registers
40
GLCrossPlatform, GLVectorFileObjects,
41
GLVectorTypes, GLMaterial, GLColor, GLTexture,
42
GLVectorGeometry, GLVectorLists, GLApplicationFileIO;
46
MAX_MS3D_VERTICES = 8192;
47
MAX_MS3D_TRIANGLES = 16384;
48
MAX_MS3D_GROUPS = 128;
49
MAX_MS3D_MATERIALS = 128;
50
MAX_MS3D_JOINTS = 128;
51
MAX_MS3D_KEYFRAMES = 5000;
56
// byte flags; // SELECTED | HIDDEN
58
// word numtriangles; //
59
// word triangleIndices[numtriangles]; // the groups group the triangles
60
// char materialIndex; // -1 = no material
65
Name: array[0..31] of AnsiChar;
67
TriangleIndices: TList;
68
MaterialIndex: Shortint;
70
destructor Destroy; override;
75
// char id[10]; // always "MS3D000000"
81
ID: array[0..9] of AnsiChar;
88
// byte flags; // SELECTED | SELECTED2 | HIDDEN
89
// float vertex[3]; //
90
// char boneId; // -1 = no bone
91
// byte referenceCount;
101
PMS3DVertexArray = ^TMS3DVertexArray;
102
TMS3DVertexArray = array[0..MAX_MS3D_VERTICES - 1] of TMS3DVertex;
106
// word flags; // SELECTED | SELECTED2 | HIDDEN
107
// word vertexIndices[3]; //
108
// float vertexNormals[3][3]; //
111
// byte smoothingGroup; // 1 - 32
112
// byte groupIndex; //
113
// } ms3d_triangle_t;
115
TMS3DTriangle = record
117
VertexIndices: array[0..2] of word;
118
VertexNormals: array[0..2] of TD3DVector;
119
S: array[0..2] of single;
120
T: array[0..2] of single;
121
SmoothingGroup: byte; // 1 - 32
125
PMS3DTriangleArray = ^TMS3DTriangleArray;
126
TMS3DTriangleArray = array[0..MAX_MS3D_TRIANGLES - 1] of TMS3DTriangle;
133
// float ambient[4]; //
134
// float diffuse[4]; //
135
// float specular[4]; //
136
// float emissive[4]; //
137
// float shininess; // 0.0f - 128.0f
138
// float transparency; // 0.0f - 1.0f
139
// char mode; // 0, 1, 2 is unused now
140
// char texture[128]; // texture.bmp
141
// char alphamap[128]; // alpha.bmp
142
// } ms3d_material_t;
143
TMS3DMaterial = record
144
Name: array[0..31] of AnsiChar;
145
Ambient: TColorVector;
146
Diffuse: TColorVector;
147
Specular: TColorVector;
148
Emissive: TColorVector;
150
Transparency: single;
152
Texture: array[0..127] of AnsiChar;
153
Alphamap: array[0..127] of AnsiChar;
159
// float time; // time in seconds
160
// float rotation[3]; // x, y, z angles
161
// } ms3d_keyframe_rot_t;
162
TMS3DKeyframeRotation = record
164
Rotation: TD3DVector;
167
PMS3DKeyframeRotationArray = ^TMS3DKeyframeRotationArray;
168
TMS3DKeyframeRotationArray = array[0..MAX_MS3D_KEYFRAMES - 1] of TMS3DKeyframeRotation;
172
// float time; // time in seconds
173
// float position[3]; // local position
174
// } ms3d_keyframe_pos_t;
175
TMS3DKeyframePosition = record
177
Position: TD3DVector;
180
PMS3DKeyframePositionArray = ^TMS3DKeyframePositionArray;
181
TMS3DKeyframePositionArray = array[0..MAX_MS3D_KEYFRAMES - 1] of TMS3DKeyframePosition;
185
// byte flags; // SELECTED | DIRTY
187
// char parentName[32]; //
188
// float rotation[3]; // local reference matrix
189
// float position[3];
191
// word numKeyFramesRot; //
192
// word numKeyFramesTrans; //
194
// ms3d_keyframe_rot_t keyFramesRot[numKeyFramesRot]; // local animation matrices
195
// ms3d_keyframe_pos_t keyFramesTrans[numKeyFramesTrans]; // local animation matrices
198
TMS3DJointBase = record
200
Name: array[0..31] of AnsiChar;
201
ParentName: array[0..31] of AnsiChar;
202
Rotation: TD3DVector;
203
Position: TD3DVector;
204
NumKeyFramesRot: word;
205
NumKeyFramesTrans: word;
209
Base : TMS3DJointBase;
210
KeyFramesRot: PMS3DKeyframeRotationArray;
211
KeyFramesTrans: PMS3DKeyframePositionArray;
214
PMS3DJointArray = ^TMS3DJointArray;
215
TMS3DJointArray = array[0..MAX_MS3D_JOINTS - 1] of TMS3DJoint;
221
commentLength: integer;
222
comment: array of AnsiChar;
224
pMS3DComment=^TMS3DComment;
226
TMS3DCommentList=class(TList)
230
destructor Destroy; override;
231
function NewComment: pMS3DComment;
234
TMS3D_vertex_ex_t=record
235
boneIds: array[0..2] of byte;
236
weights: array[0..2] of byte;
240
pMS3D_vertex_ex_t=^TMS3D_vertex_ex_t;
243
TVertexWeightList=class(TList)
245
FsubVersion: Integer;
246
function GetWeight(idx: Integer): pMS3D_vertex_ex_t;
247
procedure SetsubVersion(const Value: Integer);
250
function newWeight: pMS3D_vertex_ex_t;
251
procedure Clear; override;
252
destructor Destroy; override;
253
property Weight[idx: Integer]: pMS3D_vertex_ex_t read GetWeight;
254
property subVersion: Integer read FsubVersion write SetsubVersion;
263
{ The MilkShape vector file.
264
By Mattias Fagerlund, mattias@cambrianlabs.com. Yada yada. Eric rules! }
266
TGLMS3DVectorFile = class(TGLVectorFile)
268
class function Capabilities: TGLDataFileCapabilities; override;
269
procedure LoadFromStream(aStream: TStream); override;
275
// ------------------------------------------------------------------
276
// ------------------------------------------------------------------
277
// ------------------------------------------------------------------
279
// ------------------------------------------------------------------
280
// ------------------------------------------------------------------
281
// ------------------------------------------------------------------
287
constructor TMS3DGroup.Create;
289
TriangleIndices := TList.Create;
294
destructor TMS3DGroup.Destroy;
296
TriangleIndices.Free;
302
destructor TMS3DCommentList.destroy;
305
comment: pMS3DComment;
307
for i:=0 to count-1 do begin
309
comment^.comment:=nil;
315
function TMS3DCommentList.NewComment: pMS3DComment;
323
procedure TVertexWeightList.clear;
327
for i:=0 to count-1 do Dispose(Weight[i]);
331
destructor TVertexWeightList.destroy;
337
function TVertexWeightList.GetWeight(idx: Integer): pMS3D_vertex_ex_t;
339
result:=pMS3D_vertex_ex_t(items[idx]);
342
function TVertexWeightList.newWeight: pMS3D_vertex_ex_t;
344
p: pMS3D_vertex_ex_t;
353
procedure TVertexWeightList.SetsubVersion(const Value: Integer);
355
FsubVersion := Value;
363
class function TGLMS3DVectorFile.Capabilities: TGLDataFileCapabilities;
370
procedure TGLMS3DVectorFile.LoadFromStream(aStream: TStream);
377
FaceGroup: TFGVertexNormalTexIndexList;
378
Sk_MO: TGLSkeletonMeshObject;
381
GLLibMaterial: TGLLibMaterial;
384
ms3d_header: TMS3DHeader;
387
ms3d_vertices: PMS3DVertexArray;
390
ms3d_triangle: TMS3DTriangle;
391
ms3d_triangle2: TMS3DTriangle;
392
ms3d_triangles: PMS3DTriangleArray;
397
ms3d_material: TMS3DMaterial;
399
fAnimationFPS: single;
400
fCurrentTime: single;
401
iTotalFrames: integer;
404
ms3d_joints: PMS3DJointArray;
406
bonelist: TStringList;
407
bone: TGLSkeletonBone;
408
frame: TGLSkeletonFrame;
412
subVersionComments: integer;
413
subVersionVertexExtra: integer;
415
nNumGroupComments: integer;
416
nNumMaterialComments: integer;
417
nNumJointComments: integer;
418
nHasModelComment: integer;
420
ms3d_comment: pMS3DComment;
421
vertexWeight: pMS3D_vertex_ex_t;
422
ms3d_norm_Array: array of TD3DVector;
423
ms3d_norm: TD3DVector;
425
path, libtexture: string;
428
//Helper classes for MS3D comments if you want to use them.
430
groupCommentList: TMS3DCommentList;
431
materialCommentList: TMS3DCommentList;
432
jointCommentList: TMS3DCommentList;
433
modelCommentList: TMS3DCommentList;
435
procedure AddFaceVertex(ID: integer);
438
TexCoordID := MO.TexCoords.Add(ms3d_triangle.s[ID], -ms3d_triangle.t[ID]);
439
//Ok, here we add the vertex and the normal. We pass in the vertex index for both the vertex and the normal.
440
// This is because we have already added the normals to the Mesh in the same order as the vertices.
441
FaceGroup.Add(ms3d_triangle.vertexIndices[ID], ms3d_triangle.vertexIndices[ID], TexCoordID);
445
function AddRotations(rot, baserot: TAffineVector): TAffineVector;
447
mat1, mat2, rmat: TMatrix;
449
Trans: TTransformations;
451
mat1 := IdentityHMGMatrix;
452
mat2 := IdentityHMGMatrix;
454
SinCos(rot.V[0], s, c);
455
rmat := CreateRotationMatrixX(s, c);
456
mat1 := MatrixMultiply(mat1, rmat);
457
SinCos(rot.V[1], s, c);
458
rmat := CreateRotationMatrixY(s, c);
459
mat1 := MatrixMultiply(mat1, rmat);
460
SinCos(rot.V[2], s, c);
461
rmat := CreateRotationMatrixZ(s, c);
462
mat1 := MatrixMultiply(mat1, rmat);
464
SinCos(baserot.V[0], s, c);
465
rmat := CreateRotationMatrixX(s, c);
466
mat2 := MatrixMultiply(mat2, rmat);
467
SinCos(baserot.V[1], s, c);
468
rmat := CreateRotationMatrixY(s, c);
469
mat2 := MatrixMultiply(mat2, rmat);
470
SinCos(baserot.V[2], s, c);
471
rmat := CreateRotationMatrixZ(s, c);
472
mat2 := MatrixMultiply(mat2, rmat);
474
mat1 := MatrixMultiply(mat1, mat2);
475
if MatrixDecompose(mat1, Trans) then
476
SetVector(Result, Trans[ttRotateX], Trans[ttRotateY], Trans[ttRotateZ])
478
Result := NullVector;
482
GroupList := TList.Create;
484
ms3d_vertices := nil;
485
ms3d_triangles := nil;
487
ms3d_norm_Array := nil;
488
groupCommentList := nil;
489
materialCommentList := nil;
490
jointCommentList := nil;
491
modelCommentList := nil;
494
//Save the path of the MS3D so we can load the texture from that location instead of the EXE location.
495
path := ExtractFilePath(ResourceName);
496
if Length(path)>0 then
497
path := IncludeTrailingPathDelimiter( path );
499
// First comes the header.
500
aStream.ReadBuffer(ms3d_header, sizeof(TMS3DHeader));
501
Assert(ms3d_header.version = 4, Format('The MilkShape3D importer can only handle MS3D files of version 4, this is version ', [ms3d_header.id]));
503
// Then comes the number of vertices
504
aStream.ReadBuffer(nNumVertices, sizeof(nNumVertices));
506
// Create the vertex list
507
if Owner is TGLActor then
509
MO := TGLSkeletonMeshObject.CreateOwned(Owner.MeshObjects);
510
TGLSkeletonMeshObject(MO).BonesPerVertex := 4;
513
MO := TGLMeshObject.CreateOwned(Owner.MeshObjects);
514
MO.Mode := momFaceGroups;
516
// Then comes nNumVertices * sizeof (ms3d_vertex_t)
517
ms3d_vertices := AllocMem(sizeof(TMS3DVertex) * nNumVertices);
518
aStream.ReadBuffer(ms3d_vertices^, sizeof(TMS3DVertex) * nNumVertices);
520
for i := 0 to nNumVertices - 1 do
521
with ms3d_vertices^[i] do
523
// Add the vertex to the vertexlist
524
MO.Vertices.Add(vertex.v);
525
if Owner is TGLActor then
526
TGLSkeletonMeshObject(MO).AddWeightedBone(Byte(BoneID), 1);
529
// number of triangles
530
aStream.ReadBuffer(nNumTriangles, sizeof(nNumTriangles));
532
// nNumTriangles * sizeof (ms3d_triangle_t)
533
ms3d_triangles := AllocMem(sizeof(TMS3DTriangle) * nNumTriangles);
534
aStream.ReadBuffer(ms3d_triangles^, sizeof(TMS3DTriangle) * nNumTriangles);
536
// Now we have to match up the vertices with the normals that are in the triangles list
537
// This is because Milkshape stores normals in the triangles group. A vertex can be used
538
// many times by different faces. We need to compress that down to 1 vertex = 1 normal
542
setLength(ms3d_norm_Array, nNumVertices);
543
for i := 0 to nNumVertices - 1 do
544
ms3d_norm_Array[i] := ms3d_norm;
545
for i := 0 to nNumTriangles - 1 do
547
ms3d_triangle2 := ms3d_triangles^[i];
548
ms3d_norm_Array[ms3d_triangle2.VertexIndices[0]] := ms3d_triangle2.VertexNormals[0];
549
ms3d_norm_Array[ms3d_triangle2.VertexIndices[1]] := ms3d_triangle2.VertexNormals[1];
550
ms3d_norm_Array[ms3d_triangle2.VertexIndices[2]] := ms3d_triangle2.VertexNormals[2];
553
// Now add the normals in the same order as the vertices to the mesh
554
for i := 0 to nNumVertices - 1 do
556
MO.Normals.Add(ms3d_norm_Array[i].v);
558
ms3d_norm_Array := nil;
561
aStream.ReadBuffer(nNumGroups, sizeof(nNumGroups));
563
// nNumGroups * sizeof (ms3d_group_t)
564
for i := 0 to nNumGroups - 1 do
566
// Read the first part of the group
567
Group := TMS3DGroup.Create;
568
GroupList.Add(Group);
569
aStream.ReadBuffer(Group.Flags, sizeof(Group.Flags));
570
aStream.ReadBuffer(Group.name, sizeof(Group.name));
571
aStream.ReadBuffer(Group.numtriangles, sizeof(Group.numtriangles));
573
for j := 0 to Group.numtriangles - 1 do
575
aStream.ReadBuffer(wtemp, sizeof(wtemp));
577
Group.triangleIndices.Add(pointer(itemp));
579
aStream.ReadBuffer(Group.materialIndex, sizeof(Group.materialIndex));
581
// if materialindex=-1, then there is no material, and all faces should
582
// be added to a base VIL
583
if Group.materialIndex = -1 then
585
// If there's no base VIL, create one!
586
if FaceGroup = nil then
587
FaceGroup := TFGVertexNormalTexIndexList.CreateOwned(MO.FaceGroups);
589
for j := 0 to Group.numtriangles - 1 do
591
ms3d_triangle := ms3d_triangles^[PtrUInt(Group.triangleIndices[j])];
598
// number of materials
599
aStream.ReadBuffer(nNumMaterials, sizeof(nNumMaterials));
600
// nNumMaterials * sizeof (ms3d_material_t)
601
for i := 0 to nNumMaterials - 1 do
603
aStream.ReadBuffer(ms3d_material, sizeof(TMS3DMaterial));
604
// Create the material, if there's a materiallibrary!
605
if Assigned(Owner.MaterialLibrary) then
607
libtexture := string(ms3d_material.texture);
608
dotpos := System.Pos('.', libtexture);
609
Delete(libtexture, dotpos, Length(libtexture)-dotpos+1);
610
GLLibMaterial := Owner.MaterialLibrary.LibMaterialByName(libtexture);
611
if Assigned(GLLibMaterial) then
613
GLLibMaterial.Material.Texture.Disabled := False;
615
else if FileStreamExists(path + string(ms3d_material.texture)) then
616
GLLibMaterial := Owner.MaterialLibrary.AddTextureMaterial(libtexture, path + string(ms3d_material.texture))
619
if not Owner.IgnoreMissingTextures then
620
Exception.Create('Texture file not found: ' + path + string(ms3d_material.texture));
621
GLLibMaterial := Owner.MaterialLibrary.Materials.Add;
622
GLLibMaterial.Name := string(ms3d_material.name);
624
GLLibMaterial.Material.FrontProperties.Emission.Color := ms3d_material.emissive;
625
GLLibMaterial.Material.FrontProperties.Ambient.Color := ms3d_material.ambient;
626
GLLibMaterial.Material.FrontProperties.Diffuse.Color := ms3d_material.diffuse;
627
GLLibMaterial.Material.FrontProperties.Specular.Color := ms3d_material.specular;
629
// Shinintess is 0 to 128 in both MS3D and GLScene. Why not 0 to 127? Odd.
630
GLLibMaterial.Material.FrontProperties.Shininess := round(ms3d_material.shininess);
632
// ms3d_material.transparency is allready set as alpha channel on all
634
if ms3d_material.transparency < 1 then
636
GLLibMaterial.Material.BlendingMode := bmTransparency;
637
GLLibMaterial.Material.FaceCulling := fcNoCull; //Make transparent materials two sided.
639
GLLibMaterial.Material.Texture.TextureMode := tmModulate;
641
// Create a new face group and add all triangles for this material
642
// here. We must cycle through all groups that have this material
643
FaceGroup := TFGVertexNormalTexIndexList.CreateOwned(MO.FaceGroups);
644
FaceGroup.MaterialName := GLLibMaterial.Name;
646
for j := 0 to GroupList.Count - 1 do
648
Group := TMS3DGroup(GroupList[j]);
649
if Group.materialIndex = i then
650
for k := 0 to Group.numtriangles - 1 do
652
ms3d_triangle := ms3d_triangles^[PtrUInt(Group.triangleIndices[k])];
662
Exception.Create(ResourceName + ' has materials but there is no material library assigned to the object loading this MS3D file.' + #10#13 + 'If this is what you want, then you can safely ignore this exception.');
666
// save some keyframer data
667
aStream.ReadBuffer(fAnimationFPS, sizeof(fAnimationFPS));
668
aStream.ReadBuffer(fCurrentTime, sizeof(fCurrentTime));
669
aStream.ReadBuffer(iTotalFrames, sizeof(iTotalFrames));
671
if Owner is TGLActor then
673
TGLActor(Owner).Interval := trunc(1 / fAnimationFPS * 1000);
677
aStream.ReadBuffer(nNumJoints, sizeof(nNumJoints));
679
// nNumJoints * sizeof (ms3d_joint_t)
680
ms3d_joints := AllocMem(sizeof(TMS3DJoint) * nNumJoints);
682
// We have to read the joints one by one!
683
for i := 0 to nNumJoints - 1 do
685
// Read the joint base
686
aStream.ReadBuffer(ms3d_joints^[i].Base, sizeof(TMS3DJointBase));
688
Assert(ms3d_joints^[i].base.numKeyFramesRot = iTotalFrames, 'This importer only works if the number of key frames = the number of total frames. i.e. Every frame must be a key frame');
689
if ms3d_joints^[i].base.numKeyFramesRot > 0 then
691
// Allocate memory for the rotations
692
ms3d_joints^[i].keyFramesRot := AllocMem(sizeof(TMS3DKeyframeRotation) * ms3d_joints^[i].base.numKeyFramesRot);
693
// Read the rotations
694
aStream.ReadBuffer(ms3d_joints^[i].keyFramesRot^, sizeof(TMS3DKeyframeRotation) * ms3d_joints^[i].base.numKeyFramesRot);
697
ms3d_joints^[i].keyFramesRot := nil;
698
if ms3d_joints^[i].base.numKeyFramesTrans > 0 then
700
// Allocate memory for the translations
701
ms3d_joints^[i].keyFramesTrans := AllocMem(sizeof(TMS3DKeyframePosition) * ms3d_joints^[i].base.numKeyFramesTrans);
702
// Read the translations
703
aStream.ReadBuffer(ms3d_joints^[i].keyFramesTrans^, sizeof(TMS3DKeyframePosition) * ms3d_joints^[i].base.numKeyFramesTrans);
706
ms3d_joints^[i].keyFramesTrans := nil;
709
//Below is the Comments sections. We don't do anything with them at all. Only read in for future use if needed
710
aStream.ReadBuffer(subVersionComments, sizeof(subVersionComments));
712
//*******************
713
//* now read in the Group Comments.
714
//*******************
715
aStream.ReadBuffer(nNumGroupComments, sizeof(nNumGroupComments));
716
groupCommentList := TMS3DCommentList.Create;
717
if (nNumGroupComments > 0) then
718
groupCommentList.Capacity := nNumGroupComments;
719
for i := 0 to nNumGroupComments - 1 do
721
ms3d_comment := groupCommentList.NewComment;
722
aStream.ReadBuffer(ms3d_comment^.index, sizeOf(ms3d_comment^.index));
723
aStream.ReadBuffer(ms3d_comment^.commentLength, sizeOf(ms3d_comment^.commentLength));
724
setLength(ms3d_comment^.comment, ms3d_comment^.commentLength);
725
aStream.ReadBuffer(ms3d_comment^.comment[0], ms3d_comment^.commentLength);
729
//*******************
730
//* now read in the Material Comments.
731
//*******************
732
aStream.ReadBuffer(nNumMaterialComments, sizeof(nNumMaterialComments));
733
MaterialCommentList := TMS3DCommentList.Create;
734
if (nNumMaterialComments > 0) then
735
MaterialCommentList.Capacity := nNumMaterialComments;
736
for i := 0 to nNumMaterialComments - 1 do
738
ms3d_comment := MaterialCommentList.NewComment;
739
aStream.ReadBuffer(ms3d_comment^.index, sizeOf(ms3d_comment^.index));
740
aStream.ReadBuffer(ms3d_comment^.commentLength, sizeOf(ms3d_comment^.commentLength));
741
setLength(ms3d_comment^.comment, ms3d_comment^.commentLength);
742
aStream.ReadBuffer(ms3d_comment^.comment[0], ms3d_comment^.commentLength);
746
//*******************
747
//* now read in the Joint Comments.
748
//*******************
749
aStream.ReadBuffer(nNumJointComments, sizeof(nNumJointComments));
750
JointCommentList := TMS3DCommentList.Create;
751
if (nNumJointComments > 0) then
752
JointCommentList.Capacity := nNumJointComments;
753
for i := 0 to nNumJointComments - 1 do
755
ms3d_comment := JointCommentList.NewComment;
756
aStream.ReadBuffer(ms3d_comment^.index, sizeOf(ms3d_comment^.index));
757
aStream.ReadBuffer(ms3d_comment^.commentLength, sizeOf(ms3d_comment^.commentLength));
758
setLength(ms3d_comment^.comment, ms3d_comment^.commentLength);
759
aStream.ReadBuffer(ms3d_comment^.comment[0], ms3d_comment^.commentLength);
763
//*******************
764
//* now read in the Model Comment (if any). The milkshape spec on this is somewhat wrong, as it does not use the same
765
//* comments structure as the previous ones. Index is not included and I guess is assumed to always be 0 as there
767
//*******************
768
aStream.ReadBuffer(nHasModelComment, sizeof(nHasModelComment));
769
ModelCommentList := TMS3DCommentList.Create;
770
for i := 0 to nHasModelComment - 1 do
772
ms3d_comment := ModelCommentList.NewComment;
773
ms3d_comment^.index := 0;
774
aStream.ReadBuffer(ms3d_comment^.commentLength, sizeOf(ms3d_comment^.commentLength));
775
setLength(ms3d_comment^.comment, ms3d_comment^.commentLength);
776
aStream.ReadBuffer(ms3d_comment^.comment[0], ms3d_comment^.commentLength);
780
//Read in the vertex weights
782
aStream.ReadBuffer(subVersionVertexExtra, sizeof(subVersionVertexExtra));
783
Sk_MO := TGLSkeletonMeshObject(MO);
784
if Owner is TGLActor then
786
for i := 0 to nNumVertices - 1 do
789
aStream.ReadBuffer(vertexWeight^.boneIds[0], sizeOf(vertexWeight^.boneIds));
790
aStream.ReadBuffer(vertexWeight^.weights[0], sizeOf(vertexWeight^.weights));
791
aStream.ReadBuffer(vertexWeight^.extra, sizeOf(vertexWeight^.extra));
792
if (subVersionVertexExtra = 3) then
793
aStream.ReadBuffer(vertexWeight^.unknown, sizeOf(vertexWeight^.unknown));
795
Sk_MO.VerticesBonesWeights^[i]^[0].Weight := 1;
796
if (vertexWeight.boneIds[0] <> 255) then
798
Sk_MO.VerticesBonesWeights^[i]^[0].Weight := vertexWeight.weights[0] / 100;
799
Sk_MO.VerticesBonesWeights^[i]^[1].Weight := vertexWeight.weights[1] / 100;
800
Sk_MO.VerticesBonesWeights^[i]^[1].BoneID := vertexWeight.boneIds[0];
804
Sk_MO.VerticesBonesWeights^[i]^[1].Weight := 0;
805
Sk_MO.VerticesBonesWeights^[i]^[1].BoneID := 0;
807
if (vertexWeight.boneIds[1] <> 255) then
809
Sk_MO.VerticesBonesWeights^[i]^[2].Weight := vertexWeight.weights[2] / 100;
810
Sk_MO.VerticesBonesWeights^[i]^[2].BoneID := vertexWeight.boneIds[1];
814
Sk_MO.VerticesBonesWeights^[i]^[2].Weight := 0;
815
Sk_MO.VerticesBonesWeights^[i]^[2].BoneID := 0;
817
if (vertexWeight.boneIds[2] <> 255) then
819
Sk_MO.VerticesBonesWeights^[i]^[3].Weight := 1.0 - (vertexWeight.weights[0] + vertexWeight.weights[1] + vertexWeight.weights[2]) / 100;
820
Sk_MO.VerticesBonesWeights^[i]^[3].BoneID := vertexWeight.boneIds[2];
824
Sk_MO.VerticesBonesWeights^[i]^[3].Weight := 0;
825
Sk_MO.VerticesBonesWeights^[i]^[3].BoneID := 0;
827
dispose(vertexWeight);
832
// Mesh Transformation:
834
// 0. Build the transformation matrices from the rotation and position
835
// 1. Multiply the vertices by the inverse of local reference matrix (lmatrix0)
836
// 2. then translate the result by (lmatrix0 * keyFramesTrans)
837
// 3. then multiply the result by (lmatrix0 * keyFramesRot)
839
// For normals skip step 2.
843
// NOTE: this file format may change in future versions!
849
if (Owner is TGLActor) and (nNumJoints > 0) then
851
// Bone names are added to a list initally to sort out parents
852
bonelist := TStringList.Create;
853
for i := 0 to nNumJoints - 1 do
854
bonelist.Add(string(ms3d_joints^[i].Base.Name));
855
// Find parent bones and add their children
856
for i := 0 to nNumJoints - 1 do
858
j := bonelist.IndexOf(string(ms3d_joints^[i].Base.ParentName));
860
bone := TGLSkeletonBone.CreateOwned(Owner.Skeleton.RootBones)
862
bone := TGLSkeletonBone.CreateOwned(Owner.Skeleton.RootBones.BoneByID(j));
863
bone.Name := string(ms3d_joints^[i].Base.Name);
867
// Set up the base pose
868
frame := TGLSkeletonFrame.CreateOwned(Owner.Skeleton.Frames);
869
for i := 0 to nNumJoints - 1 do
871
pos := ms3d_joints^[i].Base.Position.V;
872
rot := ms3d_joints^[i].Base.Rotation.V;
873
frame.Position.Add(pos);
874
frame.Rotation.Add(rot);
877
// Now load the animations
878
for i := 0 to nNumJoints - 1 do
880
for j := 0 to ms3d_joints^[i].Base.NumKeyFramesRot - 1 do
882
if (j + 1) = Owner.Skeleton.Frames.Count then
883
frame := TGLSkeletonFrame.CreateOwned(Owner.Skeleton.Frames)
885
frame := Owner.Skeleton.Frames[j + 1];
886
if ms3d_joints^[i].Base.ParentName = '' then
888
pos := ms3d_joints^[i].KeyFramesTrans^[j].Position.V;
889
//pos:=ms3d_joints^[i].Base.Position.V;
890
rot := ms3d_joints^[i].KeyFramesRot^[j].Rotation.V;
894
pos := ms3d_joints^[i].KeyFramesTrans^[0].Position.V; //Always read tranlation position from the first frame
895
AddVector(pos, ms3d_joints^[i].Base.Position.V);
896
rot := ms3d_joints^[i].KeyFramesRot^[j].Rotation.V;
897
rot := AddRotations(rot, ms3d_joints^[i].Base.Rotation.V);
899
frame.Position.Add(pos);
900
frame.Rotation.Add(rot);
903
Owner.Skeleton.RootBones.PrepareGlobalMatrices;
904
TGLSkeletonMeshObject(MO).PrepareBoneMatrixInvertedMeshes;
905
with TGLActor(Owner).Animations.Add do
907
Reference := aarSkeleton;
909
EndFrame := Owner.Skeleton.Frames.Count;
913
if Assigned(ms3d_vertices) then
914
FreeMem(ms3d_vertices);
915
if Assigned(ms3d_triangles) then
916
FreeMem(ms3d_triangles);
917
if Assigned(ms3d_joints) then
919
// Free the internal storage of the joint
920
for i := 0 to nNumJoints - 1 do
922
if Assigned(ms3d_joints^[i].keyFramesRot) then
923
FreeMem(ms3d_joints^[i].keyFramesRot);
924
if Assigned(ms3d_joints^[i].keyFramesTrans) then
925
FreeMem(ms3d_joints^[i].keyFramesTrans);
927
FreeMem(ms3d_joints);
931
for i := 0 to GroupList.Count - 1 do
932
TMS3DGroup(GroupList[i]).Free;
934
if (assigned(groupCommentList)) then
935
groupCommentList.free;
936
if (assigned(materialCommentList)) then
937
materialCommentList.free;
938
if (assigned(jointCommentList)) then
939
jointCommentList.free;
940
if (assigned(modelCommentList)) then
941
modelCommentList.free;
945
// ------------------------------------------------------------------
946
// ------------------------------------------------------------------
947
// ------------------------------------------------------------------
949
// ------------------------------------------------------------------
950
// ------------------------------------------------------------------
951
// ------------------------------------------------------------------
953
RegisterVectorFileFormat('ms3d', 'MilkShape3D files', TGLMS3DVectorFile);