| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- //
- // This unit is part of the GLScene Engine, http://glscene.org
- //
- {
- Ghoul2 (GLM/GLA) file format loading structures
- Note: Also referred to as MDX (MDXM/MDXA) format in C source.
- }
- unit FileGL2;
- interface
- uses
- System.Classes,
- System.SysUtils,
-
- GLVectorTypes,
- GLVectorGeometry;
- type
- TGLMHeader = record
- fileID : array[0..3] of char;
- version : integer;
- strFile,
- animName : array[0..63] of char;
- animIndex,
- numBones,
- numLODs,
- ofsLODs,
- numSurfaces,
- ofsSurfHierarchy,
- ofsEnd : integer;
- end;
- TGLMSurfaceHeirachyOffsets = array of integer;
- TGLMSurfaceHeirachy = record
- name : array[0..63] of Char;
- flags : LongWord;
- shader : array[0..63] of Char;
- shaderIndex,
- parentIndex,
- numChildren : integer;
- childIndices : array of integer;
- end;
- TGLMSurfaceHeader = record
- ident,
- thisSurfaceIndex,
- ofsHeader,
- numVerts,
- ofsVerts,
- numTriangles,
- ofsTriangles,
- numBoneReferences,
- ofsBoneReferences,
- ofsEnd : integer;
- end;
- TGLMTriangle = record
- indices : array[0..2] of integer;
- end;
- TGLMVertex = record
- normal,
- vertex : TVector3f;
- uiNumWeightsAndBoneIndices : Cardinal; // packed int
- BoneWeightings : array[0..3] of Byte;
- end;
- TGLMSurface = record
- SurfaceHeader : TGLMSurfaceHeader;
- Triangles : array of TGLMTriangle;
- Vertices : array of TGLMVertex;
- TexCoords : array of TVector2f;
- BoneReferences : array of Integer;
- end;
- TGLMLODInfo = record
- ofsEnd : integer;
- end;
- TGLMLODSurfaceOffsets = array of integer;
- TGLMLODs = record
- LODInfo : TGLMLODInfo;
- LODSurfaceOffsets : TGLMLODSurfaceOffsets;
- Surfaces : array of TGLMSurface;
- end;
- TGLAHeader = record
- fileID : array[0..3] of char;
- version : integer;
- Name : array[0..63] of char;
- fScale : single;
- numFrames,
- ofsFrames,
- numBones,
- ofsCompBonePool,
- ofsSkel,
- ofsEnd : integer;
- end;
- TGLABone = array[0..2] of TVector4f;
- TGLACompQuatBone = array[0..6] of Word; {14 bytes}
- TGLASkeletonOffsets = array of integer;
- TGLASkeleton = record
- name : array[0..63] of char;
- flags : LongWord;
- parent : Integer;
- BasePoseMat,
- BasePoseMatInv : TGLABone;
- numChildren : Integer;
- children : array of Integer;
- end;
- // Ghoul2 Model structure
- TFileGLM = class
- public
- ModelHeader : TGLMHeader;
- SurfaceHeirachyOffsets : TGLMSurfaceHeirachyOffsets;
- SurfaceHeirachy : array of TGLMSurfaceHeirachy;
- LODs : array of TGLMLODs;
- procedure LoadFromStream(aStream : TStream);
- end;
- // Ghoul2 Animation structure
- TFileGLA = class
- public
- AnimHeader : TGLAHeader;
- SkeletonOffsets : TGLASkeletonOffsets;
- Skeleton : array of TGLASkeleton;
- BoneIndices : array of Integer;
- CompBonePool : array of TGLACompQuatBone;
- function GetCompressedMatrix(Frame,Bone : Integer):TGLACompQuatBone;
- function GetUnCompressedMatrix(Frame,Bone : Integer):TMatrix;
- procedure LoadFromStream(aStream : TStream);
- end;
- function G2_GetVertWeights(const vert:TGLMVertex):Integer;
- function G2_GetVertBoneIndex(const vert:TGLMVertex; iWeightNum:Integer):Integer;
- function G2_GetVertBoneWeight(const vert:TGLMVertex; iWeightNum:Cardinal;
- var fTotalWeight:Single; const iNumWeights:Cardinal):single;
- procedure MC_UnCompressQuat(var mat : TMatrix; const comp : TGLACompQuatBone);
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- // ------------------
- // ------------------ Misc routines ------------------
- // ------------------
- // Adapted from mdx_format.h
- // static inline int G2_GetVertWeights( const mdxmVertex_t *pVert )
- // static inline int G2_GetVertBoneIndex( const mdxmVertex_t *pVert, const int iWeightNum)
- // static inline float G2_GetVertBoneWeight( const mdxmVertex_t *pVert, const int iWeightNum, float &fTotalWeight, int iNumWeights )
- function G2_GetVertWeights(const vert:TGLMVertex):Integer;
- begin
- // Get number of bones per vertex (0..3)+1 = (1..4)
- result:=(vert.uiNumWeightsAndBoneIndices shr 30)+1;
- end;
- function G2_GetVertBoneIndex(const vert:TGLMVertex; iWeightNum:Integer):Integer;
- begin
- // Extract the bone reference array index, a 5-bit integer
- result:=(vert.uiNumWeightsAndBoneIndices shr (5*iWeightNum)) and 31;
- end;
- function G2_GetVertBoneWeight(const vert:TGLMVertex; iWeightNum:Cardinal;
- var fTotalWeight:Single; const iNumWeights:Cardinal):single;
- var
- fBoneWeight : Single;
- iTemp : Cardinal;
- begin
- if (iWeightNum = iNumWeights-1) then begin
- // No need to calculate final weight value, return the
- // weight left over out of 1
- fBoneWeight:=1-fTotalWeight;
- end else begin
- // Get the initial 8-bit bone weight
- iTemp:=vert.BoneWeightings[iWeightNum];
- // Get the 2-bit overflow and 'or' it to the front of the
- // weight to get 10-bit integer weight (0..1023)
- iTemp:=iTemp or ((vert.uiNumWeightsAndBoneIndices shr (12+(iWeightNum*2))) and $300);
- // Convert to floating point weight (0..1)
- fBoneWeight:=iTemp/1023;
- // Accumulate total weight
- fTotalWeight:=fTotalWeight+fBoneWeight;
- end;
- Result:=fBoneWeight;
- end;
- // Adapted from matcomp.c
- // void MC_UnCompressQuat(float mat[3][4],const unsigned char * comp)
- procedure MC_UnCompressQuat(var mat : TMatrix; const comp : TGLACompQuatBone);
- begin
- mat:=QuaternionToMatrix(QuaternionMake([comp[1]-32726,comp[2]-32726,comp[3]-32726],comp[0]-32726));
- mat.V[3]:=VectorMake(comp[4]/64-512,comp[5]/64-512,comp[6]/64-512,1);
- end;
- // ------------------
- // ------------------ TFileGLM ------------------
- // ------------------
- procedure TFileGLM.LoadFromStream(aStream: TStream);
- var
- idstr : array[0..3] of char;
- i,j : integer;
- ofs,
- LODofs : int64;
- begin
- aStream.Read(idstr,sizeof(idstr));
- aStream.Position:=0;
- if not (idstr='2LGM') then begin
- raise Exception.Create(Format('Unknown or incorrect identity tag: [%s]',[idstr]));
- exit;
- end;
- aStream.Read(ModelHeader,SizeOf(ModelHeader));
- if ModelHeader.version<>6 then
- raise Exception.Create(Format('Only GLM (MDXM) version 6 is supported. File is version %d.',[ModelHeader.version]));
- SetLength(SurfaceHeirachyOffsets,ModelHeader.numSurfaces);
- aStream.Read(SurfaceHeirachyOffsets[0],sizeof(Integer)*ModelHeader.numSurfaces);
- SetLength(SurfaceHeirachy,ModelHeader.numSurfaces);
- for i:=0 to ModelHeader.numSurfaces-1 do
- with SurfaceHeirachy[i] do begin
- aStream.Read(name,Length(name));
- aStream.Read(flags,sizeof(LongWord));
- aStream.Read(shader,Length(shader));
- aStream.Read(shaderindex,sizeof(Integer));
- aStream.Read(parentindex,sizeof(Integer));
- aStream.Read(numChildren,sizeof(Integer));
- if numChildren>0 then begin
- SetLength(childIndices,numChildren);
- aStream.Read(childIndices[0],numChildren*sizeof(Integer));
- end else SetLength(childIndices,0);
- end;
- SetLength(LODs,ModelHeader.numLODs);
- for i:=0 to ModelHeader.numLODs-1 do
- with LODs[i] do begin
- LODofs:=aStream.Position;
- aStream.Read(LODInfo,sizeof(LODInfo));
- SetLength(LODSurfaceOffsets,ModelHeader.numSurfaces);
- aStream.Read(LODSurfaceOffsets[0],sizeof(integer)*ModelHeader.numSurfaces);
- SetLength(Surfaces,ModelHeader.numSurfaces);
- for j:=0 to ModelHeader.numSurfaces-1 do
- with Surfaces[j] do begin
- ofs:=aStream.Position;
- aStream.Read(SurfaceHeader,SizeOf(TGLMSurfaceHeader));
- SetLength(Triangles,SurfaceHeader.numTriangles);
- SetLength(Vertices,SurfaceHeader.numVerts);
- SetLength(TexCoords,SurfaceHeader.numVerts);
- SetLength(BoneReferences,SurfaceHeader.numBoneReferences);
- aStream.Position:=ofs+SurfaceHeader.ofsTriangles;
- aStream.Read(Triangles[0],SurfaceHeader.numTriangles*SizeOf(TGLMTriangle));
- aStream.Position:=ofs+SurfaceHeader.ofsVerts;
- aStream.Read(Vertices[0],SurfaceHeader.numVerts*SizeOf(TGLMVertex));
- aStream.Read(TexCoords[0],SurfaceHeader.numVerts*SizeOf(TVector2f));
- aStream.Position:=ofs+SurfaceHeader.ofsBoneReferences;
- aStream.Read(BoneReferences[0],SurfaceHeader.numBoneReferences*SizeOf(Integer));
- aStream.Position:=ofs+SurfaceHeader.ofsEnd;
- end;
- aStream.Position:=LODofs+LODInfo.ofsEnd;
- end;
- end;
- // ------------------
- // ------------------ TFileGLA ------------------
- // ------------------
- function TFileGLA.GetCompressedMatrix(Frame, Bone: Integer): TGLACompQuatBone;
- begin
- Result:=CompBonePool[BoneIndices[Frame*AnimHeader.numBones+Bone]];
- end;
- // GetUnCompressedMatrix
- //
- function TFileGLA.GetUnCompressedMatrix(Frame, Bone: Integer): TMatrix;
- begin
- MC_UnCompressQuat(Result,CompBonePool[BoneIndices[Frame*AnimHeader.numBones+Bone]]);
- end;
- procedure TFileGLA.LoadFromStream(aStream: TStream);
- var
- idstr : array[0..3] of char;
- i,temp : integer;
- buf : array of array[0..2] of Byte;
- begin
- aStream.Read(idstr,sizeof(idstr));
- aStream.Position:=0;
- if not (idstr='2LGA') then begin
- raise Exception.Create(Format('Unknown or incorrect identity tag: [%s]',[idstr]));
- exit;
- end;
- aStream.Read(AnimHeader,SizeOf(AnimHeader));
- if AnimHeader.version<>6 then
- raise Exception.Create(Format('Only GLA (MDXA) version 6 is supported. File is version %d.',[AnimHeader.version]));
- SetLength(SkeletonOffsets,AnimHeader.numBones);
- aStream.Read(SkeletonOffsets[0],sizeof(Integer)*AnimHeader.numBones);
- SetLength(Skeleton,AnimHeader.numBones);
- for i:=0 to AnimHeader.numBones-1 do
- with Skeleton[i] do begin
- aStream.Read(name,Length(name));
- aStream.Read(flags,sizeof(LongWord));
- aStream.Read(Parent,SizeOf(Integer));
- aStream.Read(basePoseMat,sizeof(TGLABone));
- aStream.Read(basePoseMatInv,sizeof(TGLABone));
- aStream.Read(numChildren,sizeof(Integer));
- if numChildren>0 then begin
- SetLength(children,numChildren);
- aStream.Read(children[0],numChildren*sizeof(Integer));
- end else SetLength(children,0);
- end;
- aStream.Position:=AnimHeader.ofsFrames;
- SetLength(BoneIndices,AnimHeader.numFrames*AnimHeader.numBones);
- SetLength(buf,AnimHeader.numFrames*AnimHeader.numBones*3);
- aStream.Read(buf[0],AnimHeader.numFrames*AnimHeader.numBones*3);
- for i:=0 to AnimHeader.numFrames*AnimHeader.numBones-1 do
- BoneIndices[i]:=(buf[i][2] shl 16) or (buf[i][1] shl 8) or buf[i][0];
- SetLength(buf,0);
- aStream.Position:=AnimHeader.ofsCompBonePool;
- temp:=AnimHeader.ofsEnd-AnimHeader.ofsCompBonePool;
- SetLength(CompBonePool,temp div SizeOf(TGLACompQuatBone));
- aStream.Read(CompBonePool[0],temp);
- end;
- end.
|