LZScene

Форк
0
/
GLFileMDC.pas 
375 строк · 12.4 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
   Code for loading animated MDC files into GLScene FreeForms
6
   and Actors.
7

8
  This file format uses in Return To Castle Wolfenstein instead
9
  of MD3 files. It has got all MD3 features (such as Tag frames)
10
  plus very small data!
11

12
  Original code by Osman Turan (osmanturancom@yahoo.com)
13

14
   History :
15
   06/06/10 - Yar - Fixes for Linux x64
16
   08/11/09 - DaStr - Compatibility fix for FPC
17
  (thanks Predator) (BugtrackerID = 2893580)
18
   16/10/08 - UweR - Compatibility fix for Delphi 2009
19
   31/03/07 - DaStr - Added $I GLScene.inc
20
   11/05/04 - SG - Added to CVS
21
   07/02/04 - OT - Creation (Osman Turan)
22

23
}
24
unit GLFileMDC;
25

26
interface
27

28
{$I GLScene.inc}
29

30
uses
31
  Classes, SysUtils,
32
   
33
  GLVectorFileObjects, GLMaterial, GLApplicationFileIO,
34
  GLVectorGeometry;
35

36
const
37
  MDCFILE_IDENTITY = 'IDPC';
38
  MDCFILE_VERSION = 2;
39

40
  MDC_BASEVERTEX_FACTOR = 0.015625; // 1/64;
41
  MDC_COMPVERTEX_FACTOR = 0.046875; // 3/64;
42

43
type
44
  TMDCPoint = array [0 .. 2] of Single;
45
  TMDCAngle = TMDCPoint;
46

47
  TMDCFileHeader = packed record
48
    Ident: array [0 .. 3] of AnsiChar;
49
    Version: Cardinal;
50
    Name: array [0 .. 63] of AnsiChar;
51
    Flags: Cardinal;
52
    NumFrames: Cardinal;
53
    NumTags: Cardinal;
54
    NumSurfaces: Cardinal;
55
    NumSkins: Cardinal;
56
    OffsetBorderFrames: Cardinal;
57
    OffsetTagNames: Cardinal;
58
    OffsetTagFrames: Cardinal;
59
    OffsetSurfaces: Cardinal;
60
    OffsetEnd: Cardinal;
61
  end;
62

63
  TMDCBorderFrame = packed record
64
    BBMin, BBMax: TMDCPoint;
65
    LocalOrigin: TMDCPoint;
66
    Radius: Single;
67
    Name: array [0 .. 15] of AnsiChar;
68
  end;
69

70
  PMDCTagName = ^TMDCTagName;
71

72
  TMDCTagName = packed record
73
    Name: array [0 .. 63] of AnsiChar;
74
  end;
75

76
  PMDCTagFrame = ^TMDCTagFrame;
77

78
  TMDCTagFrame = packed record
79
    TagPosition: array [0 .. 2] of Word; // or ShortInt?
80
    TagAngle: array [0 .. 2] of Word; // or ShortInt?
81
  end;
82

83
  TMDCTag = packed record
84
    TagName: PMDCTagName;
85
    TagFrame: PMDCTagFrame;
86
  end;
87

88
  TMDCSurfaceHeader = packed record
89
    Ident: array [0 .. 3] of AnsiChar;
90
    Name: array [0 .. 63] of AnsiChar;
91
    Flags: Cardinal;
92
    NumCompFrames: Cardinal;
93
    NumBaseFrames: Cardinal;
94
    NumSkins: Cardinal;
95
    NumVertices: Cardinal;
96
    NumTriangles: Cardinal;
97
    OffsetTriangles: Cardinal;
98
    OffsetSkins: Cardinal;
99
    OffsetTexCoords: Cardinal;
100
    OffsetBaseVerts: Cardinal;
101
    OffsetCompVerts: Cardinal;
102
    OffsetFrameBaseFrames: Cardinal;
103
    OffsetFrameCompFrames: Cardinal;
104
    OffsetEnd: Cardinal;
105
  end;
106

107
  TMDCTriangle = array [0 .. 2] of Cardinal;
108

109
  TMDCSkin = packed record
110
    Shader: array [0 .. 63] of AnsiChar;
111
    Flags: Cardinal;
112
  end;
113

114
  TMDCTexCoord = array [0 .. 1] of Single;
115

116
  TMDCBaseVertex = array [0 .. 3] of SmallInt;
117

118
  TMDCCompVertex = array [0 .. 3] of Byte;
119

120
  TMDCBaseFrame = packed record
121
    BaseVertices: array of TMDCBaseVertex;
122
  end;
123

124
  TMDCCompFrame = packed record
125
    CompVertices: array of TMDCCompVertex;
126
  end;
127

128
type
129
  TGLMDCVectorFile = class(TGLVectorFile)
130
  public
131
    class function Capabilities: TGLDataFileCapabilities; override;
132
    procedure LoadFromStream(AStream: TStream); override;
133
  end;
134

135
  // ------------------------------------------------------------------
136
  // ------------------------------------------------------------------
137
  // ------------------------------------------------------------------
138
implementation
139

140
// ------------------------------------------------------------------
141
// ------------------------------------------------------------------
142
// ------------------------------------------------------------------
143

144
// ------------------
145
// ------------------ TGLMDCVectorFile ------------------
146
// ------------------
147

148
// Capabilities
149
//
150
class function TGLMDCVectorFile.Capabilities: TGLDataFileCapabilities;
151
begin
152
  Result := [DfcRead];
153
end;
154

155
// LoadFromStream
156
//
157
procedure TGLMDCVectorFile.LoadFromStream(AStream: TStream);
158

159
type
160
  PPackedNormal = ^TPackedNormal;
161
  TPackedNormal = array [0 .. 1] of Byte;
162

163
var
164
  I, J, K, NumVerts, Numtris: Integer;
165
  Mesh: TMorphableMeshObject;
166
  FaceGroup: TFGIndexTexCoordList;
167
  MorphTarget: TMeshMorphTarget;
168

169
  function UnpackNormal(Pn: TPackedNormal): TAffineVector;
170
  var
171
    Lat, Lng: Single;
172
  begin
173
    // The MDC normal is a latitude/longitude value that needs
174
    // to be calculated into cartesian space.
175
    Lat := (Pn[0]) * (2 * Pi) / 255;
176
    Lng := (Pn[1]) * (2 * Pi) / 255;
177
    Result.V[0] := Cos(Lat) * Sin(Lng);
178
    Result.V[1] := Sin(Lat) * Sin(Lng);
179
    Result.V[2] := Cos(Lng);
180
  end;
181

182
  procedure AllocateMaterial(Meshname: string);
183
  var
184
    LibMat: TGLLibMaterial;
185
  begin
186
    // If a material library is assigned to the actor/freeform the
187
    // mesh name will be added as a material.
188
    if Assigned(Owner.MaterialLibrary) then
189
      with Owner.MaterialLibrary do
190
      begin
191
        if Assigned(Materials.GetLibMaterialByName(Meshname)) then
192
          Exit;
193
        LibMat := Materials.Add;
194
        LibMat.Name := Meshname;
195
        LibMat.Material.Texture.Disabled := False;
196
      end;
197
  end;
198

199
var
200
  Fileheader: TMDCFileHeader;
201
  Surfheader: TMDCSurfaceHeader;
202
  Borderframes: array of TMDCBorderFrame;
203
  Baseframetable, Compframetable: array of Word;
204
  Baseframe: TMDCBaseFrame;
205
  Compframe: TMDCCompFrame;
206
  Xyz, Normal: TAffineVector;
207
  St: array of array [0 .. 1] of Single;
208
  Triangles: array of TMDCTriangle;
209
  FrameOffset: Cardinal;
210
begin
211
  AStream.Read(Fileheader, SizeOf(Fileheader));
212
  Assert(Fileheader.Ident = MDCFILE_IDENTITY, 'Incorrect MDC file Ident');
213
  Assert(Fileheader.Version = MDCFILE_VERSION, 'Incorrect MDC version number');
214

215
  try
216
    AStream.Seek(Fileheader.OffsetBorderFrames, SoFromBeginning);
217
    SetLength(Borderframes, Fileheader.NumFrames);
218
    AStream.Read(Borderframes[0], SizeOf(TMDCBorderFrame) *
219
      Fileheader.NumFrames);
220

221
    FrameOffset := Fileheader.OffsetSurfaces;
222

223
    for I := 0 to Fileheader.NumSurfaces - 1 do
224
    begin
225
      // read header
226
      AStream.Seek(FrameOffset, SoFromBeginning);
227
      AStream.Read(Surfheader, SizeOf(TMDCSurfaceHeader));
228

229
      // triangles for this surface
230
      SetLength(Triangles, Surfheader.NumTriangles);
231
      AStream.Seek(FrameOffset + Surfheader.OffsetTriangles, SoFromBeginning);
232
      AStream.Read(Triangles[0], SizeOf(TMDCTriangle) *
233
        Surfheader.NumTriangles);
234

235
      // texture coordinates for this surface
236
      SetLength(St, Surfheader.NumVertices);
237
      AStream.Seek(FrameOffset + Surfheader.OffsetTexCoords, SoFromBeginning);
238
      AStream.Read(St[0], 2 * SizeOf(Single) * Surfheader.NumVertices);
239

240
      // base frame table for this surface (for only loading)
241
      SetLength(Baseframetable, Fileheader.NumFrames);
242
      AStream.Seek(FrameOffset + Surfheader.OffsetFrameBaseFrames,
243
        SoFromBeginning);
244
      AStream.Read(Baseframetable[0], SizeOf(Word) * Fileheader.NumFrames);
245
      // compressed frame table for this surface (for only loading)
246
      SetLength(Compframetable, Fileheader.NumFrames);
247
      AStream.Seek(FrameOffset + Surfheader.OffsetFrameCompFrames,
248
        SoFromBeginning);
249
      AStream.Read(Compframetable[0], SizeOf(Word) * Fileheader.NumFrames);
250

251
      Mesh := TMorphableMeshObject.CreateOwned(Owner.MeshObjects);
252
      // easiest way to convert a char array to string ;)
253
      Mesh.Name := Trim(string(PChar(Surfheader.Name[0])));
254
      with Mesh do
255
      begin
256
        Mode := MomFaceGroups;
257
        FaceGroup := TFGIndexTexCoordList.CreateOwned(FaceGroups);
258
        with FaceGroup do
259
        begin
260
          AllocateMaterial(Mesh.Name);
261
          MaterialName := Mesh.Name;
262
          NumTris := Surfheader.NumTriangles;
263
          VertexIndices.Capacity := NumTris * 3;
264
          TexCoords.Capacity := NumTris * 3;
265
          // Get the vertex indices and texture coordinates
266
          for J := 0 to Surfheader.NumTriangles - 1 do
267
          begin
268
            Add(Triangles[J, 0], St[Triangles[J, 0]][0],
269
              1 - St[Triangles[J, 0]][1]);
270
            Add(Triangles[J, 2], St[Triangles[J, 2]][0],
271
              1 - St[Triangles[J, 2]][1]);
272
            Add(Triangles[J, 1], St[Triangles[J, 1]][0],
273
              1 - St[Triangles[J, 1]][1]);
274
          end;
275
        end;
276

277
        // Get the mesh data for each morph frame
278
        for J := 0 to Fileheader.NumFrames - 1 do
279
        begin
280
          MorphTarget := TMeshMorphTarget.CreateOwned(MorphTargets);
281
          MorphTarget.Name := Trim(string(Pchar(Surfheader.Name[0]))) + '[' +
282
            IntToStr(J) + ']';
283
          NumVerts := Surfheader.NumVertices;
284
          MorphTarget.Vertices.Capacity := NumVerts;
285

286
          // base frames
287
          SetLength(Baseframe.BaseVertices, Surfheader.NumVertices);
288
          AStream.Seek(FrameOffset + Surfheader.OffsetBaseVerts + Baseframetable
289
            [J] * Surfheader.NumVertices * 8, SoFromBeginning);
290
          AStream.Read(Baseframe.BaseVertices[0], SizeOf(TMDCBaseVertex) *
291
            Surfheader.NumVertices);
292

293
          // compressed frames
294
          if Compframetable[J] <> $FFFF then // is there a valid frame?
295
          begin
296
            SetLength(Compframe.CompVertices, Surfheader.NumVertices);
297
            AStream.Seek(FrameOffset + Surfheader.OffsetCompVerts +
298
              Compframetable[J] * Surfheader.NumVertices * 4, SoFromBeginning);
299
            AStream.Read(Compframe.CompVertices[0], SizeOf(TMDCCompVertex) *
300
              Surfheader.NumVertices);
301
          end;
302

303
          for K := 0 to Surfheader.NumVertices - 1 do
304
          begin
305
            Xyz.V[0] :=
306
              (Baseframe.BaseVertices[K, 0] * MDC_BASEVERTEX_FACTOR) +
307
              Borderframes[J].Localorigin[0];
308
            Xyz.V[1] :=
309
              (Baseframe.BaseVertices[K, 1] * MDC_BASEVERTEX_FACTOR) +
310
              Borderframes[J].Localorigin[1];
311
            Xyz.V[2] :=
312
              (Baseframe.BaseVertices[K, 2] * MDC_BASEVERTEX_FACTOR) +
313
              Borderframes[J].Localorigin[2];
314
            Normal := UnpackNormal
315
              (PPackedNormal(@Baseframe.BaseVertices[K, 3])^);
316

317
            if Compframetable[J] <> $FFFF then
318
            begin
319
              Xyz.V[0] := Xyz.V[0] +
320
                ((Compframe.CompVertices[K, 0] - 128) * MDC_COMPVERTEX_FACTOR);
321
              Xyz.V[1] := Xyz.V[1] +
322
                ((Compframe.CompVertices[K, 1] - 128) * MDC_COMPVERTEX_FACTOR);
323
              Xyz.V[2] := Xyz.V[2] +
324
                ((Compframe.CompVertices[K, 2] - 128) * MDC_COMPVERTEX_FACTOR);
325
              // FIXME:
326
              // I'm sure compframe.CompVertices[3] points a packed normal.
327
              // And it must be add the current normal like xyz.
328
              // But, I don't know a way to unpacked this value
329
              // I found a precalculated normal list in RTCW 1.41 mod source (q_math.c)
330
              //
331
              // NUMVERTEXNORMALS = 162
332
              // vec3_t bytedirs[NUMVERTEXNORMALS] = {
333
              // {-0.525731, 0.000000, 0.850651}, (...)
334
              //
335
              // But, I had noticed some compframe.CompVertices[3] value is bigger
336
              // than NUMVERTEXNORMALS constant. So, there must be another list.
337
              // Can you find it?
338
              // Osman Turan (osmanturancom@yahoo.com)
339
            end;
340

341
            // all id Sofware based games uses Z axis as up instead of Y. So, convert them
342
            MorphTarget.Vertices.Add(Xyz.V[0], Xyz.V[2], -Xyz.V[1]);
343
            MorphTarget.Normals.Add(Normal.V[0], Normal.V[2],
344
              -Normal.V[1]);
345
          end;
346
        end;
347
      end;
348

349
      FrameOffset := FrameOffset + Surfheader.OffsetEnd;
350

351
      if Mesh.MorphTargets.Count > 0 then
352
        Mesh.MorphTo(0);
353
    end;
354
  finally
355
    // save memory free space
356
    Borderframes := nil;
357
    Baseframetable := nil;
358
    Compframetable := nil;
359
    St := nil;
360
    Triangles := nil;
361
  end;
362
end;
363

364
// ------------------------------------------------------------------
365
// ------------------------------------------------------------------
366
// ------------------------------------------------------------------
367
initialization
368

369
// ------------------------------------------------------------------
370
// ------------------------------------------------------------------
371
// ------------------------------------------------------------------
372

373
RegisterVectorFileFormat('mdc', 'MDC files', TGLMDCVectorFile);
374

375
end.
376

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

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

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

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