k heres the code, slightly older version, will try and find the new one later.
'doom 3\quake 4 model format loader
Type MD5_BBox
Field BMin:Vector3
Field BMax:Vector3
Method New()
BMin = New Vector3
BMax = New Vector3
End Method
End Type
Type MD5_Anim
Field NumFrames:Int
Field NumJoints:Int
Field FrameRate:Int
Field SkelIndex:MD5_SkelIndex[]
Field BBoxes:MD5_BBox[]
End Type
Type MD5_AnimInfo
Field CurrFrame:Int
Field NextFrame:Int
Field LastTime:Double
Field MaxTime:Double
End Type
Type MD5_SkelIndex
Field SkelFrames:MD5_Joint[]
Method GetJoint:MD5_Joint(nParent:String)
For Local i:MD5_Joint = EachIn SkelFrames
If i.Name = nParent
Return i
EndIf
Next
End Method
End Type
Type MD5_Joint
Field Name:String
Field Parent:Int
Field Pos:Vector3
Field Pos2:Float[3]
Field Orient:Quat_Class
Method New()
Pos = New Vector3
Orient = New Quat_Class
End Method
End Type
Type MD5_JointInfo
Field Name:String
Field Parent:Int
Field Flags:Int
Field StartIndex:Int
End Type
Type MD5_BaseFrameJoint
Field Pos:Vector3
Field Orient:Quat_Class
Method New()
Pos = New Vector3
Orient = New Quat_Class
End Method
End Type
Type MD5_Vertex
Field St:Float[2]
Field Start:Int
Field Count:Int
Field Normal:Vector3
Field Tangent:Vector3[2]
Field TangentNormal:Vector3
Field xyz:Float[3]
End Type
Type MD5_Triangle
Field Index:Int[3]
End Type
Type MD5_Weight
Field Joint:Int
Field Bias:Float
Field Pos2:Float[3]
Field Pos:Vector3
Field Normal:Vector3
End Type
Type MD5_Mesh
Field Vertices:MD5_Vertex[]
Field Triangles:MD5_Triangle[]
Field Weights:MD5_Weight[]
Field NumVerts:Int
Field NumTris:Int
Field NumWeights:Int
Field Shader:String
Field VertexIndices:Int[]
Field VertexBuffer:Float[]
Field NormalBuffer:Float[]
Field TextureBuffer:Float[]
Method New()
End Method
End Type
Type MD5_Class Extends Entity_Class
Field Anim:MD5_Anim
Field AnimInfo:MD5_AnimInfo
Field BaseSkel:MD5_Joint[]
Field Skeleton:MD5_Joint[]
Field Meshes:MD5_Mesh[]
Field NumJoints:Int
Field NumMeshes:Int
Field animinc:Double
Method New()
ListAddLast(Entity_List,Self)
Entity_Matrix = New Matrix4
Entity_Scale_Matrix = New Matrix4
End Method
Method Delete()
Remove()
End Method
Method Remove()
Entity_Matrix = Null
Entity_Scale_Matrix = Null
ListRemove(Entity_List,Self)
End Method
Method Load:Int(nFile:String,nAnimFile:String="")
Local FileIn:TStream
Local LineIn:String
Local Version:Int,CommandLine:String
Local CurrMesh:Int = 0
Local i:Int
Local ParseIndex:Int[2]
'read file and parse data
FileIn = OpenStream(nFile,True,False)
While Not Eof(FileIn)
'read line
LineIn = ReadLine(FileIn)
'skip if line is blank
If LineIn.length = 0 Then Continue
'version
If Instr(LineIn,"MD5Version")
Version = Int(Mid(LineIn,Instr(LineIn," ")+1))
'if its not a version 10 then fail the file
If Not Version = 10 Then Return False
Continue
'commandline
ElseIf Instr(LineIn,"commandline")
CommandLine = Mid(LineIn,Instr(LineIn," ")+1)
Continue
'joint count
ElseIf Instr(LineIn,"numJoints")
NumJoints = Int(Mid(LineIn,Instr(LineIn," ")+1))
'check we have joints
If NumJoints > 0
BaseSkel = BaseSkel[..NumJoints]
EndIf
Continue
'mesh count
ElseIf Instr(LineIn,"numMeshes")
NumMeshes = Int(Mid(LineIn,Instr(LineIn," ")+1))
'check we have meshes
If NumMeshes > 0
Meshes = Meshes[..NumMeshes]
EndIf
Continue
'read joints
ElseIf Instr(LineIn,"joints {")
For i:Int = 0 Until NumJoints
'read joint data
LineIn = ReadLine(FileIn)
LineIn = Mid(LineIn,Instr(LineIn,Chr(34))+1)
ParseIndex[0] = Instr(LineIn,Chr(34))
'name
BaseSkel[i] = New MD5_Joint
BaseSkel[i].Name = Mid(LineIn,1,ParseIndex[0]-1)
'parent
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn,"(")
BaseSkel[i].Parent = Int(Replace(Mid(LineIn,1,ParseIndex[0]-1)," ",""))
'position
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn,")")
Local TmpLineIn:String
Local TmpParseFinished:Int
TmpLineIn = Mid(LineIn,1,ParseIndex[0]-1)
LineIn = Mid(LineIn,ParseIndex[0]+3)
For Local h:Int = 0 To 2
TmpParseFinished = False
For Local o:Int = 1 To Len(TmpLineIn)
If Mid(TmpLineIn,o,1) <> " "
ParseIndex[0] = o
For o = ParseIndex[0]+1 To Len(TmpLineIn)
If Mid(TmpLineIn,o,1) = " "
ParseIndex[1] = o-1
BaseSkel[i].Pos2[h] = Float(Mid(TmpLineIn,ParseIndex[0],ParseIndex[1]))
TmpLineIn = Mid(TmpLineIn,ParseIndex[1]+1)
TmpParseFinished = True
Exit
EndIf
Next
EndIf
If TmpParseFinished Then Exit
Next
Next
BaseSkel[i].Pos.x = BaseSkel[i].Pos2[0]
BaseSkel[i].Pos.y = BaseSkel[i].Pos2[1]
BaseSkel[i].Pos.z = BaseSkel[i].Pos2[2]
TmpLineIn = Mid(LineIn,1,Instr(LineIn,")")-1)
'orientation
For h:Int = 0 To 2
TmpParseFinished = False
For o:Int = 1 To Len(TmpLineIn)
If Mid(TmpLineIn,o,1) <> " "
ParseIndex[0] = o
For o = ParseIndex[0]+1 To Len(TmpLineIn)
If Mid(TmpLineIn,o,1) = " "
ParseIndex[1] = o-1
BaseSkel[i].Orient.Val[h] = Float(Mid(TmpLineIn,ParseIndex[0],ParseIndex[1]))
TmpLineIn = Mid(TmpLineIn,ParseIndex[1]+1)
TmpParseFinished = True
Exit
EndIf
Next
EndIf
If TmpParseFinished Then Exit
Next
Next
BaseSkel[i].Orient.ComputeW(BaseSkel[i].Orient)
Next
Continue
'read meshes
ElseIf Instr(LineIn,"mesh {")
'read mesh data
Meshes[CurrMesh] = New MD5_Mesh
'shader
LineIn = ReadLine(FileIn)
If Instr(LineIn,"//")
LineIn = ReadLine(FileIn)
EndIf
LineIn = Mid(LineIn,Instr(LineIn,Chr(34))+1)
Meshes[CurrMesh].Shader = Replace(LineIn,Chr(34),"")
LineIn = ReadLine(FileIn)
'verts
LineIn = ReadLine(FileIn)
LineIn = Mid(LineIn,Instr(LineIn,"numverts")+9)
Meshes[CurrMesh].NumVerts = Int(LineIn)
'check we have verts
If Meshes[CurrMesh].NumVerts > 0
Meshes[CurrMesh].Vertices = Meshes[CurrMesh].Vertices[..Meshes[CurrMesh].NumVerts]
EndIf
For h:Int = 0 Until Meshes[CurrMesh].NumVerts
LineIn = ReadLine(FileIn)
ParseIndex[0] = Instr(LineIn,".")
ParseIndex[1] = Instr(LineIn,".",ParseIndex[0]+1)
TmpLineIn = Mid(LineIn,ParseIndex[0]-1)
ParseIndex[1] = Instr(TmpLineIn,".",3)
Meshes[CurrMesh].Vertices[h] = New MD5_Vertex
Meshes[CurrMesh].Vertices[h].St[0] = Float(Mid(TmpLineIn,1,ParseIndex[1]-2))
TmpLineIn = Mid(TmpLineIn,ParseIndex[1]-1)
ParseIndex[0] = Instr(TmpLineIn,")")
Meshes[CurrMesh].Vertices[h].St[1] = Float(Mid(TmpLineIn,1,ParseIndex[0]-2))
TmpLineIn = Mid(TmpLineIn,ParseIndex[0]+2)
ParseIndex[1] = Instr(TmpLineIn," ")
Meshes[CurrMesh].Vertices[h].Start = Int(Mid(TmpLineIn,1,ParseIndex[1]-1))
Meshes[CurrMesh].Vertices[h].Count = Int(Mid(TmpLineIn,ParseIndex[1]+1))
Meshes[CurrMesh].Vertices[h].Normal = New Vector3
Next
LineIn = ReadLine(FileIn)
'tris
LineIn = ReadLine(FileIn)
LineIn = Mid(LineIn,Instr(LineIn,"numtris")+8)
Meshes[CurrMesh].NumTris = Int(LineIn)
'check we have tris
If Meshes[CurrMesh].NumTris > 0
Meshes[CurrMesh].VertexIndices = Meshes[CurrMesh].VertexIndices[..Meshes[CurrMesh].NumTris*3]
Meshes[CurrMesh].Triangles = Meshes[CurrMesh].Triangles[..Meshes[CurrMesh].NumTris]
EndIf
For h:Int = 0 Until Meshes[CurrMesh].NumTris
LineIn = ReadLine(FileIn)
Meshes[CurrMesh].Triangles[h] = New MD5_Triangle
LineIn = Mid(LineIn,Instr(LineIn,"tri ")+5)
ParseIndex[0] = Instr(LineIn," ")
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
Meshes[CurrMesh].Triangles[h].Index[0] = Int(Mid(LineIn,1,ParseIndex[0]+1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
Meshes[CurrMesh].Triangles[h].Index[1] = Int(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
Meshes[CurrMesh].Triangles[h].Index[2] = Int(LineIn)
Next
LineIn = ReadLine(FileIn)
'weights
LineIn = ReadLine(FileIn)
LineIn = Mid(LineIn,Instr(LineIn,"numweights")+11)
Meshes[CurrMesh].NumWeights = Int(LineIn)
'check we have weights
If Meshes[CurrMesh].NumWeights > 0
Meshes[CurrMesh].Weights = Meshes[CurrMesh].Weights[..Meshes[CurrMesh].NumWeights]
EndIf
For h:Int = 0 Until Meshes[CurrMesh].NumWeights
LineIn = ReadLine(FileIn)
Meshes[CurrMesh].Weights[h] = New MD5_Weight
Meshes[CurrMesh].Weights[h].Pos = New Vector3
LineIn = Mid(LineIn,Instr(LineIn,"weight ")+8)
ParseIndex[0] = Instr(LineIn," ")
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
Meshes[CurrMesh].Weights[h].Joint = Int(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
Meshes[CurrMesh].Weights[h].Bias = Float(Mid(LineIn,1,ParseIndex[0]-1))
ParseIndex[0] = Instr(LineIn,"(")
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[1] = Instr(LineIn,")")
LineIn = Mid(LineIn,1,ParseIndex[1]-1)
TmpLineIn = LineIn
'positions
For Local n:Int = 0 To 2
TmpParseFinished = False
For o:Int = 1 To Len(TmpLineIn)
If Mid(TmpLineIn,o,1) <> " "
ParseIndex[0] = o
For o = ParseIndex[0]+1 To Len(TmpLineIn)
If Mid(TmpLineIn,o,1) = " "
ParseIndex[1] = o-1
Meshes[CurrMesh].Weights[h].Pos2[n] = Float(Mid(TmpLineIn,ParseIndex[0],ParseIndex[1]))
TmpLineIn = Mid(TmpLineIn,ParseIndex[1]+1)
TmpParseFinished = True
Exit
EndIf
Next
EndIf
If TmpParseFinished Then Exit
Next
Next
Meshes[CurrMesh].Weights[h].Pos.x = Meshes[CurrMesh].Weights[h].Pos2[0]
Meshes[CurrMesh].Weights[h].Pos.y = Meshes[CurrMesh].Weights[h].Pos2[1]
Meshes[CurrMesh].Weights[h].Pos.z = Meshes[CurrMesh].Weights[h].Pos2[2]
Next
CurrMesh:+1
Continue
EndIf
Wend
CloseStream(FileIn)
If nAnimFile
Anim = New MD5_Anim
AnimInfo = New MD5_AnimInfo
If Not LoadAnim(nAnimFile,Anim)
Anim = Null
AnimInfo = Null
Else
AnimInfo.CurrFrame = 0.0
AnimInfo.NextFrame = 1.0
AnimInfo.LastTime = 0.0
AnimInfo.MaxTime = 1.0/Anim.FrameRate
Skeleton = Skeleton[..Anim.NumJoints]
For i:Int = 0 Until Anim.NumJoints
Skeleton[i] = New MD5_Joint
Next
EndIf
For i:Int = 0 Until NumMeshes
For j:Int = 0 Until Anim.NumFrames
BuildWeightNormals(Meshes[i],Anim.SkelIndex[j])
Next
Next
EndIf
TurnEntity(-90.0,0.0,-90.0)
End Method
Method LoadAnim:Int(nFile:String,nAnim:MD5_Anim Var)
Local FileIn:TStream
Local LineIn:String
Local Version:Int,CommandLine:String
Local i:Int,h:Int,o:Int
Local ParseIndex:Int[2]
Local ParseLine:String[2]
Local NumAnimatedComponents:Int
Local BaseFrame:MD5_BaseFrameJoint[]
Local JointInfos:MD5_JointInfo[]
Local AnimFrameData:Float[]
Local FrameIndex:Int
'read file and parse data
FileIn = OpenStream(nFile,True,False)
While Not Eof(FileIn)
'read line
LineIn = ReadLine(FileIn)
'skip if line is blank
If LineIn.length = 0 Then Continue
'version
If Instr(LineIn,"MD5Version")
Version = Int(Mid(LineIn,Instr(LineIn," ")+1))
'if its not a version 10 then fail the file
If Not Version = 10 Then Return False
Continue
'commandline
ElseIf Instr(LineIn,"commandline")
CommandLine = Mid(LineIn,Instr(LineIn," ")+1)
Continue
'frame count
ElseIf Instr(LineIn,"numFrames")
nAnim.NumFrames = Int(Mid(LineIn,Instr(LineIn," ")+1))
nAnim.SkelIndex = nAnim.SkelIndex[..nAnim.NumFrames]
'check we have frames
If nAnim.NumFrames > 0
For i:Int = 0 Until nAnim.NumFrames
nAnim.SkelIndex[i] = New MD5_SkelIndex
Next
nAnim.BBoxes = nAnim.BBoxes[..nAnim.NumFrames]
EndIf
Continue
'joint count
ElseIf Instr(LineIn,"numJoints")
nAnim.NumJoints = Int(Mid(LineIn,Instr(LineIn," ")+1))
'check we have joints
If nAnim.NumJoints > 0
For i:Int = 0 Until nAnim.NumFrames
nAnim.SkelIndex[i].SkelFrames = nAnim.SkelIndex[i].SkelFrames[..nAnim.NumJoints]
For o:Int = 0 Until nAnim.NumJoints
nAnim.SkelIndex[i].SkelFrames[o] = New MD5_Joint
Next
Next
BaseFrame = BaseFrame[..nAnim.NumJoints]
JointInfos = JointInfos[..nAnim.NumJoints]
EndIf
Continue
'framerate
ElseIf Instr(LineIn,"frameRate")
nAnim.Framerate = Int(Mid(LineIn,Instr(LineIn," ")+1))
Continue
'animated components
ElseIf Instr(LineIn,"numAnimatedComponents")
NumAnimatedComponents = Int(Mid(LineIn,Instr(LineIn," ")+1))
If NumAnimatedComponents > 0
AnimFrameData = AnimFrameData[..NumAnimatedComponents]
EndIf
Continue
'hierarchy
ElseIf Instr(LineIn,"hierarchy {")
'read joint info
For i = 0 Until nAnim.NumJoints
LineIn = ReadLine(FileIn)
LineIn = Mid(LineIn,Instr(LineIn,Chr(34))+1)
ParseIndex[0] = Instr(LineIn,Chr(34))
JointInfos[i] = New MD5_JointInfo
JointInfos[i].Name = Mid(LineIn,1,ParseIndex[0]-1)
LineIn = Mid(LineIn,ParseIndex[0]+1)
For o:Int = 1 To Len(LineIn)
If Mid(LineIn,o,1) <> " "
LineIn = Mid(LineIn,o)
ParseIndex[0] = Instr(LineIn," ")
JointInfos[i].Parent = Int(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
JointInfos[i].Flags = Int(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
JointInfos[i].StartIndex = Int(Mid(LineIn,1,ParseIndex[0]-1))
Exit
EndIf
Next
Next
Continue
'bounds
ElseIf Instr(LineIn,"bounds {")
'read bounding box info
For i:Int = 0 Until nAnim.NumFrames
nAnim.BBoxes[i] = New MD5_BBox
LineIn = ReadLine(FileIn)
ParseIndex[0] = Instr(LineIn,"(")
LineIn = Mid(LineIn,ParseIndex[0]+1)
For o:Int = 1 To Len(LineIn)
If Mid(LineIn,o,1) <> " "
LineIn = Mid(LineIn,o)
ParseIndex[0] = Instr(LineIn," ")
nAnim.BBoxes[i].BMin.x = Float(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
nAnim.BBoxes[i].BMin.y = Float(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn,")")
nAnim.BBoxes[i].BMin.z = Float(Mid(LineIn,1,ParseIndex[0]-2))
ParseIndex[0] = Instr(LineIn,"(")
LineIn = Mid(LineIn,ParseIndex[0]+1)
Exit
EndIf
Next
For o:Int = 1 To Len(LineIn)
If Mid(LineIn,o,1) <> " "
LineIn = Mid(LineIn,o)
ParseIndex[0] = Instr(LineIn," ")
nAnim.BBoxes[i].BMax.x = Float(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
nAnim.BBoxes[i].BMax.y = Float(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn,")")
nAnim.BBoxes[i].BMax.z = Float(Mid(LineIn,1,ParseIndex[0]-1))
Exit
EndIf
Next
Next
Continue
'baseframe
ElseIf Instr(LineIn,"baseframe {")
For i = 0 Until nAnim.NumJoints
'read base frame joint
BaseFrame[i] = New MD5_BaseFrameJoint
LineIn = ReadLine(FileIn)
'pos
ParseIndex[0] = Instr(LineIn,"(")
LineIn = Mid(LineIn,ParseIndex[0]+2)
ParseIndex[0] = Instr(LineIn," ")
BaseFrame[i].Pos.x = Float(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
BaseFrame[i].Pos.y = Float(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
BaseFrame[i].Pos.z = Float(Mid(LineIn,1,ParseIndex[0]-1))
'orient
ParseIndex[0] = Instr(LineIn,"(")
LineIn = Mid(LineIn,ParseIndex[0]+2)
ParseIndex[0] = Instr(LineIn," ")
BaseFrame[i].Orient.Val[0] = Float(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
BaseFrame[i].Orient.Val[1] = Float(Mid(LineIn,1,ParseIndex[0]-1))
LineIn = Mid(LineIn,ParseIndex[0]+1)
ParseIndex[0] = Instr(LineIn," ")
BaseFrame[i].Orient.Val[2] = Float(Mid(LineIn,1,ParseIndex[0]-1))
BaseFrame[i].Orient.ComputeW(BaseFrame[i].Orient)
Next
Continue
'frames
ElseIf Instr(LineIn,"frame ")
FrameIndex = Int(Mid(LineIn,Instr(LineIn," ")+1))
AnimFrameData = AnimFrameData[..NumAnimatedComponents]
'read frame data
Local k:Int = 0
Repeat
LineIn = ReadLine(FileIn)
If Instr(LineIn,"}") Then Exit
ParseLine[0]:+LineIn
Forever
ParseLine[0] = Replace(ParseLine[0]," ","|")
For i:Int = 0 Until NumAnimatedComponents
ParseIndex[0] = Instr(ParseLine[0],"|")
ParseLine[0] = Mid(ParseLine[0],ParseIndex[0]+1)
ParseIndex[0] = Instr(ParseLine[0],"|")
ParseLine[1] = Mid(ParseLine[0],1,ParseIndex[0]-1)
ParseLine[1] = Replace(ParseLine[1]," ","")
AnimFrameData[i] = Float(ParseLine[1])
Next
BuildFrameSkeleton(JointInfos,BaseFrame,AnimFrameData,..
nAnim.SkelIndex[FrameIndex].SkelFrames,nAnim.NumJoints)
Continue
EndIf
Wend
CloseStream(FileIn)
If ValidateAnim() = False Then Return False
Return True
End Method
Method ValidateAnim:Int()
Local i:Int
'check joints
If Not NumJoints = Anim.NumJoints
Return False
EndIf
'check frames
For i:Int = 0 Until NumJoints
'joints must have same parent index
If BaseSkel[i].Parent <> Anim.SkelIndex[0].SkelFrames[i].Parent
Return False
EndIf
'joints must have same name
If BaseSkel[i].Name <> Anim.SkelIndex[0].SkelFrames[i].Name
Return False
EndIf
Next
Return True
End Method
Method Draw()
If Anim
'Animate(Anim,Varptr AnimInfo,(CurrTime-LastTime))
InterpolateSkeletons(Anim.SkelIndex[AnimInfo.CurrFrame],..
Anim.SkelIndex[AnimInfo.NextFrame],..
Anim.NumJoints,..
AnimInfo.LastTime*Anim.FrameRate,..
Skeleton)
Else
Skeleton = BaseSkel
EndIf
'draw skeleton
'DrawSkeleton(Skeleton,NumJoints)
'draw model
Local nTexEnabled:Byte = glIsEnabled(GL_TEXTURE_2D)
Local nVertexArrayEnabled:Byte = glIsEnabled(GL_VERTEX_ARRAY)
Local nNormalArrayEnabled:Byte = glIsEnabled(GL_NORMAL_ARRAY)
Local nTextureArrayEnabled:Byte = glIsEnabled(GL_TEXTURE_COORD_ARRAY)
glFrontFace(GL_CW)
If Not nVertexArrayEnabled Then glEnableClientState(GL_VERTEX_ARRAY)
If Not nNormalArrayEnabled Then glEnableClientState(GL_NORMAL_ARRAY)
If Not nTextureArrayEnabled Then glEnableClientState(GL_TEXTURE_COORD_ARRAY)
If Not nTexEnabled Then glEnable(GL_TEXTURE_2D)
For Local i:Int = 0 Until NumMeshes
PrepareMesh(Meshes[i],Skeleton)
glVertexPointer(3,GL_FLOAT,0,Meshes[i].VertexBuffer)
glNormalPointer(GL_FLOAT,0,Meshes[i].NormalBuffer)
glTexCoordPointer(2,GL_FLOAT,0,Meshes[i].TextureBuffer)
glDrawElements(GL_TRIANGLES,Meshes[i].NumTris*3,GL_UNSIGNED_INT,Meshes[i].VertexIndices)
Next
If Not nTexEnabled Then glDisable(GL_TEXTURE_2D)
If Not nVertexArrayEnabled Then glDisableClientState(GL_VERTEX_ARRAY)
If Not nNormalArrayEnabled Then glDisableClientState(GL_NORMAL_ARRAY)
If Not nTextureArrayEnabled Then glDisableClientState(GL_TEXTURE_COORD_ARRAY)
End Method
Method DrawSkeleton(Joints:MD5_Joint[],nNumJoints:Int)
Local i:Int
'draw each bone
glDisable(GL_LIGHTING)
glColor3f(1.0,1.0,1.0)
glBegin(GL_LINES)
For i:Int = 0 Until nNumJoints
If Joints[i].Parent > -1
glVertex3f(Joints[Joints[i].Parent].Pos.x,Joints[Joints[i].Parent].Pos.y,Joints[Joints[i].Parent].Pos.z)
glVertex3f(Joints[i].Pos.x,Joints[i].Pos.y,Joints[i].Pos.z)
EndIf
Next
glEnd()
glEnable(GL_LIGHTING)
glColor3f(1.0,1.0,1.0)
End Method
Method BuildFrameSkeleton(nJointInfos:MD5_JointInfo[],nBaseFrame:MD5_BaseFrameJoint[],..
nFrameData:Float[],nSkelFrame:MD5_Joint[] Var,..
nNumJoints:Int)
Local i:Int
For i:Int = 0 Until nNumJoints
Local BaseJoint:MD5_BaseFrameJoint Ptr
BaseJoint = Varptr nBaseFrame[i]
Local AnimatedPos:Vector3 = New Vector3
Local AnimatedOrient:Quat_Class = New Quat_Class
Local j:Int = 0
AnimatedPos.x = BaseJoint[0].Pos.x
AnimatedPos.y = BaseJoint[0].Pos.y
AnimatedPos.z = BaseJoint[0].Pos.z
AnimatedOrient.Val[0] = BaseJoint[0].Orient.Val[0]
AnimatedOrient.Val[1] = BaseJoint[0].Orient.Val[1]
AnimatedOrient.Val[2] = BaseJoint[0].Orient.Val[2]
AnimatedOrient.Val[3] = BaseJoint[0].Orient.Val[3]
If nJointInfos[i].Flags & 1'Tx
AnimatedPos.x = nFrameData[nJointInfos[i].StartIndex+j]
j:+1
EndIf
If nJointInfos[i].Flags & 2'Ty
AnimatedPos.y = nFrameData[nJointInfos[i].StartIndex+j]
j:+1
EndIf
If nJointInfos[i].Flags & 4'Tz
AnimatedPos.z = nFrameData[nJointInfos[i].StartIndex+j]
j:+1
EndIf
If nJointInfos[i].Flags & 8'Qx
AnimatedOrient.Val[0] = nFrameData[nJointInfos[i].StartIndex+j]
j:+1
EndIf
If nJointInfos[i].Flags & 16'Qy
AnimatedOrient.Val[1] = nFrameData[nJointInfos[i].StartIndex+j]
j:+1
EndIf
If nJointInfos[i].Flags & 32'Qz
AnimatedOrient.Val[2] = nFrameData[nJointInfos[i].StartIndex+j]
j:+1
EndIf
'compute orient w val
AnimatedOrient.ComputeW(AnimatedOrient)
Local ThisJoint:MD5_Joint Ptr
ThisJoint = Varptr nSkelFrame[i]
Local Parent:Int = nJointInfos[i].Parent
ThisJoint[0].Parent = Parent
ThisJoint[0].Name = nJointInfos[i].Name
'has parent?
If ThisJoint[0].Parent < 0
ThisJoint[0].Pos.x = AnimatedPos.x
ThisJoint[0].Pos.y = AnimatedPos.y
ThisJoint[0].Pos.z = AnimatedPos.z
ThisJoint[0].Orient.Val[0] = AnimatedOrient.Val[0]
ThisJoint[0].Orient.Val[1] = AnimatedOrient.Val[1]
ThisJoint[0].Orient.Val[2] = AnimatedOrient.Val[2]
ThisJoint[0].Orient.Val[3] = AnimatedOrient.Val[3]
Else
Local ParentJoint:MD5_Joint Ptr
ParentJoint = Varptr nSkelFrame[Parent]
Local RPos:Vector3 = New Vector3
ThisJoint[0].Orient.RotatePoint(ParentJoint[0].Orient,AnimatedPos,Rpos)
ThisJoint[0].Pos.x = RPos.x+ParentJoint[0].Pos.x
ThisJoint[0].Pos.y = RPos.y+ParentJoint[0].Pos.y
ThisJoint[0].Pos.z = RPos.z+ParentJoint[0].Pos.z
ThisJoint[0].Orient.MultQuat(AnimatedOrient,ParentJoint[0].Orient,ThisJoint[0].Orient)
ThisJoint[0].Orient.Normalize(ThisJoint[0].Orient)
EndIf
Next
End Method
Method BuildWeightNormals(nMesh:MD5_Mesh,nSkelFrame:MD5_SkelIndex)
Local BindPoseVerts:Vector3[nMesh.NumVerts]
Local BindPoseNorms:Vector3[nMesh.NumVerts]
Local pWeight:MD5_Weight
Local pJoint:MD5_Joint
Local WV:Vector3 = New Vector3
For Local i:Int = 0 Until nMesh.NumVerts
For Local j:Int = 0 Until nMesh.Vertices[i].Count
pWeight = nMesh.Weights[nMesh.Vertices[i].Start+j]
pJoint = nSkelFrame.SkelFrames[pWeight.Joint]
WV.x = pWeight.Pos.x
WV.y = pWeight.Pos.y
WV.z = pWeight.Pos.z
BindPoseVerts[i] = New Vector3
BindPoseNorms[i] = New Vector3
BindPoseVerts[i].x:+(pJoint.Pos.x+WV.x)*pWeight.Bias
BindPoseVerts[i].y:+(pJoint.Pos.y+WV.y)*pWeight.Bias
BindPoseVerts[i].z:+(pJoint.Pos.z+WV.z)*pWeight.Bias
Next
Next
'tri normals
Local pTri:MD5_Triangle
Local TriNorm:Vector3 = New Vector3
For i:Int = 0 Until nMesh.NumTris
pTri = nMesh.Triangles[i]
TriNorm.ComputeNormal(TriNorm,BindPoseVerts[pTri.Index[0]],..
BindPoseVerts[pTri.Index[1]],..
BindPoseVerts[pTri.Index[2]])
For j:Int = 0 Until 3
BindPoseNorms[pTri.Index[j]].x:+TriNorm.x
BindPoseNorms[pTri.Index[j]].y:+TriNorm.y
BindPoseNorms[pTri.Index[j]].z:+TriNorm.z
Next
Next
'average surface normals
For i = 0 Until nMesh.NumVerts
BindPoseNorms[i].Normalize()
nMesh.Vertices[i].Normal.x = BindPoseNorms[i].x
nMesh.Vertices[i].Normal.y = BindPoseNorms[i].y
nMesh.Vertices[i].Normal.z = BindPoseNorms[i].z
Next
Rem
Local InvRot:Quat_Class = New Quat_Class
Local WN:Vector3
'compute weight normals by invert-transforming the normal
For i:Int = 0 Until nMesh.NumVerts
For i:Int = 0 Until nMesh.Vertices[i].Count
pWeight = nMesh.Weights[nMesh.Vertices[i].Start+j]
pJoint = nSkelFrame.SkelFrames[pWeight.Joint]
WN = BindPoseNorms[i]
'compute inverse quat rotation
'InvRot =
'InvRot.RotateVec(WV)
'WN.RotVec(WN)
pWeight.Normal.x:+WN.x
pWeight.Normal.y:+WN.y
pWeight.Normal.z:+WN.z
Next
Next
'normalize all weight normals
For i:Int = 0 Until nMesh.NumWeights
nMesh.Weights[i].Normal.Normalize()
nMesh.NormalBuffer[vbi] = nMesh.Weights[i].Normal.x'BindPoseNorms[i].x
nMesh.NormalBuffer[vbi+1] = nMesh.Weights[i].Normal.y'BindPoseNorms[i].y
nMesh.NormalBuffer[vbi+2] = nMesh.Weights[i].Normal.z'BindPoseNorms[i].z
vbi:+3
Next
EndRem
pWeight = Null
pJoint = Null
WV = Null
BindPoseVerts = Null
BindPoseNorms = Null
End Method
Method InterpolateSkeletons(SkelA:MD5_SkelIndex,SkelB:MD5_SkelIndex,nNumJoints:Int,Interp:Float,..
SkelOut:MD5_Joint[] Var)
Local i:Int
For i = 0 Until nNumJoints
'copy parent index
SkelOut[i].Parent = SkelA.SkelFrames[i].Parent
'linear interpolation (position)
SkelOut[i].Pos.x = SkelA.SkelFrames[i].Pos.x+Interp*(SkelB.SkelFrames[i].Pos.x-SkelA.SkelFrames[i].Pos.x)
SkelOut[i].Pos.y = SkelA.SkelFrames[i].Pos.y+Interp*(SkelB.SkelFrames[i].Pos.y-SkelA.SkelFrames[i].Pos.y)
SkelOut[i].Pos.z = SkelA.SkelFrames[i].Pos.z+Interp*(SkelB.SkelFrames[i].Pos.z-SkelA.SkelFrames[i].Pos.z)
'spherical linear interpolation (orientation)
SkelOut[i].Orient.Slerp(SkelA.SkelFrames[i].Orient,SkelB.SkelFrames[i].Orient,Interp,SkelOut[i].Orient)
Next
End Method
Method Animate(nAnim:MD5_Anim,nAnimInfo:MD5_AnimInfo Ptr,dt:Double)
Local MaxFrames:Int = nAnim.NumFrames-1
nAnimInfo[0].Lasttime:+dt
'move to next frame
If nAnimInfo[0].Lasttime >= nAnimInfo[0].MaxTime
nAnimInfo[0].CurrFrame:+1
nAnimInfo[0].NextFrame:+1
nAnimInfo[0].LastTime = 0.0
EndIf
If nAnimInfo[0].CurrFrame > MaxFrames
nAnimInfo[0].CurrFrame = 0
ElseIf nAnimInfo[0].NextFrame > MaxFrames
nAnimInfo[0].NextFrame = 0
EndIf
End Method
Method PrepareMesh(nMesh:MD5_Mesh,nJoint:MD5_Joint[])
Local i:Int,j:Int,k:Int
'setup vertex indices
For i = 0 Until nMesh.NumTris
For j = 0 Until 3
nMesh.VertexIndices[k] = nMesh.Triangles[i].Index[j]
k:+1
Next
Next
Local vbi:Int,tbi:Int
'setup vertices
nMesh.VertexBuffer = nMesh.VertexBuffer[..nMesh.NumVerts*3]
nMesh.NormalBuffer = nMesh.NormalBuffer[..nMesh.NumVerts*3]
nMesh.TextureBuffer = nMesh.TextureBuffer[..nMesh.NumVerts*2]
For i = 0 Until nMesh.NumVerts
Local FinalVertex:Vector3 = Vector3.Create(0.0,0.0,0.0)
'calculate final vertex to draw with weights
For j = 0 Until nMesh.Vertices[i].Count
Local nWeight:MD5_Weight Ptr
nWeight = Varptr nMesh.Weights[nMesh.Vertices[i].Start+j]
Local nJoint2:MD5_Joint Ptr
nJoint2 = Varptr nJoint[nWeight[0].Joint]
Local WV:Vector3 = New Vector3
nJoint2[0].Orient.RotatePoint(nJoint2[0].Orient,nWeight[0].Pos,WV)
'sum of all weight bias should be 1.0
FinalVertex.x :+ (nJoint2[0].Pos.x+WV.x)*nWeight[0].Bias
FinalVertex.y :+ (nJoint2[0].Pos.y+WV.y)*nWeight[0].Bias
FinalVertex.z :+ (nJoint2[0].Pos.z+WV.z)*nWeight[0].Bias
Next
nMesh.Vertices[i].xyz[0] = FinalVertex.x
nMesh.Vertices[i].xyz[1] = FinalVertex.y
nMesh.Vertices[i].xyz[2] = FinalVertex.z
nMesh.VertexBuffer[vbi] = FinalVertex.x
nMesh.VertexBuffer[vbi+1] = FinalVertex.y
nMesh.VertexBuffer[vbi+2] = FinalVertex.z
nMesh.NormalBuffer[vbi] = nMesh.Vertices[i].Normal.x
nMesh.NormalBuffer[vbi+1] = nMesh.Vertices[i].Normal.y
nMesh.NormalBuffer[vbi+2] = nMesh.Vertices[i].Normal.z
nMesh.TextureBuffer[tbi] = nMesh.Vertices[i].St[0]
nMesh.TextureBuffer[tbi+1] = nMesh.Vertices[i].St[1]
tbi:+2
vbi:+3
FinalVertex = Null
WV = Null
Next
End Method
End Type