LZScene

Форк
0
/
GLFileMS3D.pas 
955 строк · 33.0 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
   Support for MS3D file format.
6

7
   History :
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
15
                          that group.
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.
19

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
29

30
}
31
unit GLFileMS3D;
32

33
interface
34

35
{$I GLScene.inc}
36

37
uses
38
  Classes, SysUtils,
39
   
40
  GLCrossPlatform, GLVectorFileObjects, 
41
  GLVectorTypes, GLMaterial, GLColor, GLTexture,
42
  GLVectorGeometry, GLVectorLists, GLApplicationFileIO;
43
  
44

45
const
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;
52

53
type
54
  // typedef struct
55
  // {
56
  //     byte            flags;                              // SELECTED | HIDDEN
57
  //     char            name[32];                           //
58
  //     word            numtriangles;                       //
59
  //     word            triangleIndices[numtriangles];      // the groups group the triangles
60
  //     char            materialIndex;                      // -1 = no material
61
  // } ms3d_group_t;
62
  TMS3DGroup = class
63
  public
64
    Flags: byte;
65
    Name: array[0..31] of AnsiChar;
66
    NumTriangles: word;
67
    TriangleIndices: TList;
68
    MaterialIndex: Shortint;
69
    constructor Create;
70
    destructor Destroy; override;
71
  end;
72

73
  // typdef struct
74
  // {
75
  //    char    id[10];                                     // always "MS3D000000"
76
  //    int     version;                                    // 4
77
  // } ms3d_header_t;
78
  {$A-}
79

80
  TMS3DHeader = record
81
    ID: array[0..9] of AnsiChar;
82
    Version: integer;
83
  end;
84

85

86
  // typedef struct
87
  // {
88
  //     byte    flags;                                      // SELECTED | SELECTED2 | HIDDEN
89
  //     float   vertex[3];                                  //
90
  //     char    boneId;                                     // -1 = no bone
91
  //     byte    referenceCount;
92
  // } ms3d_vertex_t;
93

94
  TMS3DVertex = record
95
    Flags: byte;
96
    Vertex: TD3DVector;
97
    BoneId: AnsiChar;
98
    ReferenceCount: byte;
99
  end;
100

101
  PMS3DVertexArray = ^TMS3DVertexArray;
102
  TMS3DVertexArray = array[0..MAX_MS3D_VERTICES - 1] of TMS3DVertex;
103

104
  // typedef struct
105
  // {
106
  //     word    flags;                                      // SELECTED | SELECTED2 | HIDDEN
107
  //     word    vertexIndices[3];                           //
108
  //     float   vertexNormals[3][3];                        //
109
  //     float   s[3];                                       //
110
  //     float   t[3];                                       //
111
  //     byte    smoothingGroup;                             // 1 - 32
112
  //     byte    groupIndex;                                 //
113
  // } ms3d_triangle_t;
114

115
  TMS3DTriangle = record
116
    Flags: word;
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
122
    GroupIndex: byte;
123
  end;
124

125
  PMS3DTriangleArray = ^TMS3DTriangleArray;
126
  TMS3DTriangleArray = array[0..MAX_MS3D_TRIANGLES - 1] of TMS3DTriangle;
127

128

129

130
  // typedef struct
131
  // {
132
  //     char            name[32];                           //
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;
149
    Shininess: single;
150
    Transparency: single;
151
    Mode: AnsiChar;
152
    Texture: array[0..127] of AnsiChar;
153
    Alphamap: array[0..127] of AnsiChar;
154
  end;
155

156

157
  // typedef struct
158
  // {
159
  //     float           time;                               // time in seconds
160
  //     float           rotation[3];                        // x, y, z angles
161
  // } ms3d_keyframe_rot_t;
162
  TMS3DKeyframeRotation = record
163
    Time: single;
164
    Rotation: TD3DVector;
165
  end;
166

167
  PMS3DKeyframeRotationArray = ^TMS3DKeyframeRotationArray;
168
  TMS3DKeyframeRotationArray = array[0..MAX_MS3D_KEYFRAMES - 1] of TMS3DKeyframeRotation;
169

170
  // typedef struct
171
  // {
172
  //     float           time;                               // time in seconds
173
  //     float           position[3];                        // local position
174
  // } ms3d_keyframe_pos_t;
175
  TMS3DKeyframePosition = record
176
    Time: single;
177
    Position: TD3DVector;
178
  end;
179

180
  PMS3DKeyframePositionArray = ^TMS3DKeyframePositionArray;
181
  TMS3DKeyframePositionArray = array[0..MAX_MS3D_KEYFRAMES - 1] of TMS3DKeyframePosition;
182

183
  // typedef struct
184
  // {
185
  //     byte            flags;                              // SELECTED | DIRTY
186
  //     char            name[32];                           //
187
  //     char            parentName[32];                     //
188
  //     float           rotation[3];                        // local reference matrix
189
  //     float           position[3];
190
  //
191
  //     word            numKeyFramesRot;                    //
192
  //     word            numKeyFramesTrans;                  //
193
  //
194
  //     ms3d_keyframe_rot_t keyFramesRot[numKeyFramesRot];      // local animation matrices
195
  //     ms3d_keyframe_pos_t keyFramesTrans[numKeyFramesTrans];  // local animation matrices
196
  // } ms3d_joint_t;
197

198
  TMS3DJointBase = record
199
    Flags: byte;
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;
206
  end;
207

208
  TMS3DJoint = record
209
    Base : TMS3DJointBase;
210
    KeyFramesRot: PMS3DKeyframeRotationArray;
211
    KeyFramesTrans: PMS3DKeyframePositionArray;
212
  end;
213

214
  PMS3DJointArray = ^TMS3DJointArray;
215
  TMS3DJointArray = array[0..MAX_MS3D_JOINTS - 1] of TMS3DJoint;
216

217

218

219
  TMS3DComment=record
220
      index: Integer;
221
      commentLength: integer;
222
      comment: array of AnsiChar;
223
  end;
224
  pMS3DComment=^TMS3DComment;
225

226
  TMS3DCommentList=class(TList)
227
  private
228
  protected
229
  public
230
    destructor Destroy; override;
231
    function NewComment: pMS3DComment;
232
  end;
233

234
  TMS3D_vertex_ex_t=record
235
    boneIds: array[0..2] of byte;
236
    weights: array[0..2] of byte;
237
    extra: cardinal;
238
    unknown: cardinal;
239
  end;
240
  pMS3D_vertex_ex_t=^TMS3D_vertex_ex_t;
241

242

243
  TVertexWeightList=class(TList)
244
  private
245
    FsubVersion: Integer;
246
    function GetWeight(idx: Integer): pMS3D_vertex_ex_t;
247
    procedure SetsubVersion(const Value: Integer);
248
  protected
249
  public
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;
255

256
  end;
257

258

259

260
type
261
  // TGLMS3DVectorFile
262
  //
263
  { The MilkShape vector file.
264
     By Mattias Fagerlund, mattias@cambrianlabs.com. Yada yada. Eric rules! }
265

266
  TGLMS3DVectorFile = class(TGLVectorFile)
267
  public
268
    class function Capabilities: TGLDataFileCapabilities; override;
269
    procedure LoadFromStream(aStream: TStream); override;
270
  end;
271

272

273
  {$A+}
274

275
// ------------------------------------------------------------------
276
// ------------------------------------------------------------------
277
// ------------------------------------------------------------------
278
implementation
279
// ------------------------------------------------------------------
280
// ------------------------------------------------------------------
281
// ------------------------------------------------------------------
282

283
{ TMS3DGroup }
284

285
// create
286
//
287
constructor TMS3DGroup.Create;
288
begin
289
  TriangleIndices := TList.Create;
290
end;
291

292
// destroy
293
//
294
destructor TMS3DGroup.Destroy;
295
begin
296
  TriangleIndices.Free;
297
  inherited;
298
end;
299

300
{ TMS3DCommentList }
301

302
destructor TMS3DCommentList.destroy;
303
var
304
    i: integer;
305
    comment: pMS3DComment;
306
begin
307
    for i:=0 to count-1 do begin
308
        comment:=items[i];
309
        comment^.comment:=nil;
310
        dispose(comment);
311
    end;
312
    inherited;
313
end;
314

315
function TMS3DCommentList.NewComment: pMS3DComment;
316
begin
317
    new(result);
318
    add(result);
319
end;
320

321
{ TVertexWeightList }
322

323
procedure TVertexWeightList.clear;
324
var
325
    i: integer;
326
begin
327
    for i:=0 to count-1 do Dispose(Weight[i]);
328
    inherited;
329
end;
330

331
destructor TVertexWeightList.destroy;
332
begin
333
    clear;
334
    inherited;
335
end;
336

337
function TVertexWeightList.GetWeight(idx: Integer): pMS3D_vertex_ex_t;
338
begin
339
    result:=pMS3D_vertex_ex_t(items[idx]);
340
end;
341

342
function TVertexWeightList.newWeight: pMS3D_vertex_ex_t;
343
var
344
    p: pMS3D_vertex_ex_t;
345
begin
346
    new(p);
347
    add(p);
348
    result:=p;
349

350
end;
351

352

353
procedure TVertexWeightList.SetsubVersion(const Value: Integer);
354
begin
355
  FsubVersion := Value;
356
end;
357

358
{ TGLMS3DVectorFile }
359

360
// capabilities
361
//
362

363
class function TGLMS3DVectorFile.Capabilities: TGLDataFileCapabilities;
364
begin
365
  Result := [dfcRead];
366
end;
367

368
// loadfromstream
369
//
370
procedure TGLMS3DVectorFile.LoadFromStream(aStream: TStream);
371
var
372
  i, j, k: integer;
373
  itemp: PtrUInt;
374
  wtemp: word;
375
  TexCoordID: integer;
376
  MO: TGLMeshObject;
377
  FaceGroup: TFGVertexNormalTexIndexList;
378
  Sk_MO: TGLSkeletonMeshObject;
379

380
  GroupList: TList;
381
  GLLibMaterial: TGLLibMaterial;
382

383
  // Milkshape 3d
384
  ms3d_header: TMS3DHeader;
385
  nNumVertices: word;
386

387
  ms3d_vertices: PMS3DVertexArray;
388
  nNumTriangles: word;
389

390
  ms3d_triangle: TMS3DTriangle;
391
  ms3d_triangle2: TMS3DTriangle;
392
  ms3d_triangles: PMS3DTriangleArray;
393

394
  nNumGroups: word;
395
  Group: TMS3DGroup;
396
  nNumMaterials: word;
397
  ms3d_material: TMS3DMaterial;
398

399
  fAnimationFPS: single;
400
  fCurrentTime: single;
401
  iTotalFrames: integer;
402

403
  nNumJoints: word;
404
  ms3d_joints: PMS3DJointArray;
405

406
  bonelist: TStringList;
407
  bone: TGLSkeletonBone;
408
  frame: TGLSkeletonFrame;
409
  rot, pos: TVector3f;
410

411
  //Tod
412
  subVersionComments: integer;
413
  subVersionVertexExtra: integer;
414

415
  nNumGroupComments: integer;
416
  nNumMaterialComments: integer;
417
  nNumJointComments: integer;
418
  nHasModelComment: integer;
419

420
  ms3d_comment: pMS3DComment;
421
  vertexWeight: pMS3D_vertex_ex_t;
422
  ms3d_norm_Array: array of TD3DVector;
423
  ms3d_norm: TD3DVector;
424

425
  path, libtexture: string;
426
  dotpos: Integer;
427

428
  //Helper classes for MS3D comments if you want to use them.
429

430
  groupCommentList: TMS3DCommentList;
431
  materialCommentList: TMS3DCommentList;
432
  jointCommentList: TMS3DCommentList;
433
  modelCommentList: TMS3DCommentList;
434

435
  procedure AddFaceVertex(ID: integer);
436
  begin
437
    // Add the texCoord
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);
442

443
  end;
444

445
  function AddRotations(rot, baserot: TAffineVector): TAffineVector;
446
  var
447
    mat1, mat2, rmat: TMatrix;
448
    s, c: Single;
449
    Trans: TTransformations;
450
  begin
451
    mat1 := IdentityHMGMatrix;
452
    mat2 := IdentityHMGMatrix;
453

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);
463

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);
473

474
    mat1 := MatrixMultiply(mat1, mat2);
475
    if MatrixDecompose(mat1, Trans) then
476
      SetVector(Result, Trans[ttRotateX], Trans[ttRotateY], Trans[ttRotateZ])
477
    else
478
      Result := NullVector;
479
  end;
480

481
begin
482
  GroupList := TList.Create;
483
  FaceGroup := nil;
484
  ms3d_vertices := nil;
485
  ms3d_triangles := nil;
486
  ms3d_joints := nil;
487
  ms3d_norm_Array := nil;
488
  groupCommentList := nil;
489
  materialCommentList := nil;
490
  jointCommentList := nil;
491
  modelCommentList := nil;
492

493
  try
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 );
498

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]));
502

503
    // Then comes the number of vertices
504
    aStream.ReadBuffer(nNumVertices, sizeof(nNumVertices));
505

506
    // Create the vertex list
507
    if Owner is TGLActor then
508
    begin
509
      MO := TGLSkeletonMeshObject.CreateOwned(Owner.MeshObjects);
510
      TGLSkeletonMeshObject(MO).BonesPerVertex := 4;
511
    end
512
    else
513
      MO := TGLMeshObject.CreateOwned(Owner.MeshObjects);
514
    MO.Mode := momFaceGroups;
515

516
    // Then comes nNumVertices * sizeof (ms3d_vertex_t)
517
    ms3d_vertices := AllocMem(sizeof(TMS3DVertex) * nNumVertices);
518
    aStream.ReadBuffer(ms3d_vertices^, sizeof(TMS3DVertex) * nNumVertices);
519

520
    for i := 0 to nNumVertices - 1 do
521
      with ms3d_vertices^[i] do
522
      begin
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);
527
      end;
528

529
    // number of triangles
530
    aStream.ReadBuffer(nNumTriangles, sizeof(nNumTriangles));
531

532
    // nNumTriangles * sizeof (ms3d_triangle_t)
533
    ms3d_triangles := AllocMem(sizeof(TMS3DTriangle) * nNumTriangles);
534
    aStream.ReadBuffer(ms3d_triangles^, sizeof(TMS3DTriangle) * nNumTriangles);
535

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
539
    ms3d_norm.X := 0;
540
    ms3d_norm.Y := 0;
541
    ms3d_norm.Z := 0;
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
546
    begin
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];
551
    end;
552

553
    // Now add the normals in the same order as the vertices to the mesh
554
    for i := 0 to nNumVertices - 1 do
555
    begin
556
      MO.Normals.Add(ms3d_norm_Array[i].v);
557
    end;
558
    ms3d_norm_Array := nil;
559

560
    // number of groups
561
    aStream.ReadBuffer(nNumGroups, sizeof(nNumGroups));
562

563
    // nNumGroups * sizeof (ms3d_group_t)
564
    for i := 0 to nNumGroups - 1 do
565
    begin
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));
572

573
      for j := 0 to Group.numtriangles - 1 do
574
      begin
575
        aStream.ReadBuffer(wtemp, sizeof(wtemp));
576
        itemp := wtemp;
577
        Group.triangleIndices.Add(pointer(itemp));
578
      end;
579
      aStream.ReadBuffer(Group.materialIndex, sizeof(Group.materialIndex));
580

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
584
      begin
585
        // If there's no base VIL, create one!
586
        if FaceGroup = nil then
587
          FaceGroup := TFGVertexNormalTexIndexList.CreateOwned(MO.FaceGroups);
588

589
        for j := 0 to Group.numtriangles - 1 do
590
        begin
591
          ms3d_triangle := ms3d_triangles^[PtrUInt(Group.triangleIndices[j])];
592
          AddFaceVertex(0);
593
          AddFaceVertex(1);
594
          AddFaceVertex(2);
595
        end;
596
      end;
597
    end;
598
    // number of materials
599
    aStream.ReadBuffer(nNumMaterials, sizeof(nNumMaterials));
600
    // nNumMaterials * sizeof (ms3d_material_t)
601
    for i := 0 to nNumMaterials - 1 do
602
    begin
603
      aStream.ReadBuffer(ms3d_material, sizeof(TMS3DMaterial));
604
      // Create the material, if there's a materiallibrary!
605
      if Assigned(Owner.MaterialLibrary) then
606
      begin
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
612
        begin
613
          GLLibMaterial.Material.Texture.Disabled := False;
614
        end
615
        else if FileStreamExists(path + string(ms3d_material.texture)) then
616
          GLLibMaterial := Owner.MaterialLibrary.AddTextureMaterial(libtexture, path + string(ms3d_material.texture))
617
        else
618
        begin
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);
623
        end;
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;
628

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);
631

632
        // ms3d_material.transparency is allready set as alpha channel on all
633
        // colors above
634
        if ms3d_material.transparency < 1 then
635
        begin
636
          GLLibMaterial.Material.BlendingMode := bmTransparency;
637
          GLLibMaterial.Material.FaceCulling := fcNoCull; //Make transparent materials two sided.
638
        end;
639
        GLLibMaterial.Material.Texture.TextureMode := tmModulate;
640

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;
645

646
        for j := 0 to GroupList.Count - 1 do
647
        begin
648
          Group := TMS3DGroup(GroupList[j]);
649
          if Group.materialIndex = i then
650
            for k := 0 to Group.numtriangles - 1 do
651
            begin
652
              ms3d_triangle := ms3d_triangles^[PtrUInt(Group.triangleIndices[k])];
653

654
              AddFaceVertex(0);
655
              AddFaceVertex(1);
656
              AddFaceVertex(2);
657
            end;
658
        end;
659
      end
660
      else
661
      begin
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.');
663
      end;
664
    end;
665

666
    // save some keyframer data
667
    aStream.ReadBuffer(fAnimationFPS, sizeof(fAnimationFPS));
668
    aStream.ReadBuffer(fCurrentTime, sizeof(fCurrentTime));
669
    aStream.ReadBuffer(iTotalFrames, sizeof(iTotalFrames));
670

671
    if Owner is TGLActor then
672
    begin
673
      TGLActor(Owner).Interval := trunc(1 / fAnimationFPS * 1000);
674
    end;
675

676
    // number of joints
677
    aStream.ReadBuffer(nNumJoints, sizeof(nNumJoints));
678

679
    // nNumJoints * sizeof (ms3d_joint_t)
680
    ms3d_joints := AllocMem(sizeof(TMS3DJoint) * nNumJoints);
681

682
    // We have to read the joints one by one!
683
    for i := 0 to nNumJoints - 1 do
684
    begin
685
      // Read the joint base
686
      aStream.ReadBuffer(ms3d_joints^[i].Base, sizeof(TMS3DJointBase));
687
      if (i = 0) then
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
690
      begin
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);
695
      end
696
      else
697
        ms3d_joints^[i].keyFramesRot := nil;
698
      if ms3d_joints^[i].base.numKeyFramesTrans > 0 then
699
      begin
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);
704
      end
705
      else
706
        ms3d_joints^[i].keyFramesTrans := nil;
707
    end;
708

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));
711

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
720
    begin
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);
726
    end;
727
    ////////
728

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
737
    begin
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);
743
    end;
744
    ////////
745

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
754
    begin
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);
760
    end;
761
    ////////
762

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
766
    //* can only be one
767
    //*******************
768
    aStream.ReadBuffer(nHasModelComment, sizeof(nHasModelComment));
769
    ModelCommentList := TMS3DCommentList.Create;
770
    for i := 0 to nHasModelComment - 1 do
771
    begin
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);
777
    end;
778
    ////////
779

780
    //Read in the vertex weights
781
    //
782
    aStream.ReadBuffer(subVersionVertexExtra, sizeof(subVersionVertexExtra));
783
    Sk_MO := TGLSkeletonMeshObject(MO);
784
    if Owner is TGLActor then
785
    begin
786
      for i := 0 to nNumVertices - 1 do
787
      begin
788
        new(vertexWeight);
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));
794

795
        Sk_MO.VerticesBonesWeights^[i]^[0].Weight := 1;
796
        if (vertexWeight.boneIds[0] <> 255) then
797
        begin
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];
801
        end
802
        else
803
        begin
804
          Sk_MO.VerticesBonesWeights^[i]^[1].Weight := 0;
805
          Sk_MO.VerticesBonesWeights^[i]^[1].BoneID := 0;
806
        end;
807
        if (vertexWeight.boneIds[1] <> 255) then
808
        begin
809
          Sk_MO.VerticesBonesWeights^[i]^[2].Weight := vertexWeight.weights[2] / 100;
810
          Sk_MO.VerticesBonesWeights^[i]^[2].BoneID := vertexWeight.boneIds[1];
811
        end
812
        else
813
        begin
814
          Sk_MO.VerticesBonesWeights^[i]^[2].Weight := 0;
815
          Sk_MO.VerticesBonesWeights^[i]^[2].BoneID := 0;
816
        end;
817
        if (vertexWeight.boneIds[2] <> 255) then
818
        begin
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];
821
        end
822
        else
823
        begin
824
          Sk_MO.VerticesBonesWeights^[i]^[3].Weight := 0;
825
          Sk_MO.VerticesBonesWeights^[i]^[3].BoneID := 0;
826
        end;
827
        dispose(vertexWeight);
828
      end;
829
    end;
830

831
    // ***
832
    // Mesh Transformation:
833
    //
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)
838
    //
839
    // For normals skip step 2.
840
    //
841
    //
842
    //
843
    // NOTE:  this file format may change in future versions!
844
    //
845
    //
846
    // - Mete Ciragan
847
    // ***
848

849
    if (Owner is TGLActor) and (nNumJoints > 0) then
850
    begin
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
857
      begin
858
        j := bonelist.IndexOf(string(ms3d_joints^[i].Base.ParentName));
859
        if j = -1 then
860
          bone := TGLSkeletonBone.CreateOwned(Owner.Skeleton.RootBones)
861
        else
862
          bone := TGLSkeletonBone.CreateOwned(Owner.Skeleton.RootBones.BoneByID(j));
863
        bone.Name := string(ms3d_joints^[i].Base.Name);
864
        bone.BoneID := i;
865
      end;
866
      bonelist.Free;
867
      // Set up the base pose
868
      frame := TGLSkeletonFrame.CreateOwned(Owner.Skeleton.Frames);
869
      for i := 0 to nNumJoints - 1 do
870
      begin
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);
875
      end;
876

877
      // Now load the animations
878
      for i := 0 to nNumJoints - 1 do
879
      begin
880
        for j := 0 to ms3d_joints^[i].Base.NumKeyFramesRot - 1 do
881
        begin
882
          if (j + 1) = Owner.Skeleton.Frames.Count then
883
            frame := TGLSkeletonFrame.CreateOwned(Owner.Skeleton.Frames)
884
          else
885
            frame := Owner.Skeleton.Frames[j + 1];
886
          if ms3d_joints^[i].Base.ParentName = '' then
887
          begin
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;
891
          end
892
          else
893
          begin
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);
898
          end;
899
          frame.Position.Add(pos);
900
          frame.Rotation.Add(rot);
901
        end;
902
      end;
903
      Owner.Skeleton.RootBones.PrepareGlobalMatrices;
904
      TGLSkeletonMeshObject(MO).PrepareBoneMatrixInvertedMeshes;
905
      with TGLActor(Owner).Animations.Add do
906
      begin
907
        Reference := aarSkeleton;
908
        StartFrame := 0;
909
        EndFrame := Owner.Skeleton.Frames.Count;
910
      end;
911
    end;
912
  finally
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
918
    begin
919
      // Free the internal storage of the joint
920
      for i := 0 to nNumJoints - 1 do
921
      begin
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);
926
      end;
927
      FreeMem(ms3d_joints);
928
    end;
929

930
    // Finalize
931
    for i := 0 to GroupList.Count - 1 do
932
      TMS3DGroup(GroupList[i]).Free;
933
    GroupList.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;
942
  end;
943
end;
944

945
// ------------------------------------------------------------------
946
// ------------------------------------------------------------------
947
// ------------------------------------------------------------------
948
initialization
949
  // ------------------------------------------------------------------
950
  // ------------------------------------------------------------------
951
  // ------------------------------------------------------------------
952

953
  RegisterVectorFileFormat('ms3d', 'MilkShape3D files', TGLMS3DVectorFile);
954

955
end.
956

957

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.