Code archives/3D Graphics - Mesh/MD2 loader/animator class
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| Allows you to load/animate an MD2 model in the most simple way. You just need to load/set the texture yourself. For updates check http://www.furi.dk/blitzmax | |||||
' MD2 model class by Odin Jensen (www.furi.dk)
' Free to use as you please :)
Strict
' MD2 animation frame
Type MD2AnimFrame
Field Name:String
Field Vertices:Float[]
EndType
' MD2 file header
Type MD2FileHeader
Field Name:String
Field Magic:Int
Field Version:Int
Field SkinWidth:Int
Field SkinHeight:Int
Field FrameSize:Int
Field NumSkins:Int
Field NumVertices:Int
Field NumTexCoords:Int
Field NumTriangles:Int
Field NumGLcommands:Int
Field NumFrames:Int
Field OffsetSkins:Int
Field OffsetTexCoords:Int
Field OffsetTriangles:Int
Field OffsetFrames:Int
Field OffsetGLcommands:Int
Field OffsetEnd:Int
EndType
' MD2 main model class
Type MD2Model
' Frame rate of animation
Field FPS:Int = 30
' Animation flag
Field Animate:Int = False
' Current, next, start and end animation frame numbers
Field CurAnimFrame:Int = 0
Field NextAnimFrame:Int = 1
Field StartFrame:Int = 0
Field EndFrame:Int = 0
' Animation timer values
Field LastAnimTime:Long=0
' Model frames + face data + uvs
Field InterpolatedFrame:MD2AnimFrame
Field Frames:MD2AnimFrame[]
Field UVs:Float[]
Field VertIndices:Int[3]
Field UVIndices:Int[3]
' Attempt to load model
Method Load(FileName:String)
' Open file
Local FileHandle:TStream = ReadStream("littleendian::" + FileName)
' Read header
Local Header:MD2FileHeader= New MD2FileHeader
Header.Magic = Readint(FileHandle)
Header.Version = Readint(FileHandle)
Header.SkinWidth = Readint(FileHandle)
Header.SkinHeight = Readint(FileHandle)
Header.FrameSize = Readint(FileHandle)
Header.NumSkins = Readint(FileHandle)
Header.NumVertices = Readint(FileHandle)
Header.NumTexCoords = Readint(FileHandle)
Header.NumTriangles = Readint(FileHandle)
Header.NumGLcommands = Readint(FileHandle)
Header.NumFrames = Readint(FileHandle)
Header.OffsetSkins = Readint(FileHandle)
Header.OffsetTexCoords = Readint(FileHandle)
Header.OffsetTriangles = Readint(FileHandle)
Header.OffsetFrames = Readint(FileHandle)
Header.OffsetGLcommands = Readint(FileHandle)
Header.OffsetEnd = Readint(FileHandle)
' Load UVs
UVs = New Float[Header.NumTexCoords*2]
SeekStream(FileHandle, Header.OffsetTexCoords)
For Local i = 0 To Header.NumTexCoords-1
UVs[i*2]=Float ReadShort(FileHandle) / Header.SkinWidth
UVs[(i*2)+1]=Float ReadShort(FileHandle) / Header.SkinHeight
Next
' Load faces (triangle indices)
SeekStream (FileHandle, Header.OffsetTriangles)
VertIndices = New Int[Header.NumTriangles * 3];
UVIndices = New Int[Header.NumTriangles * 3];
Local CurIndex:Int = 0
For Local i = 0 To Header.NumTriangles-1
VertIndices[CurIndex + 2] = ReadShort(FileHandle)
VertIndices[CurIndex + 1] = ReadShort(FileHandle)
VertIndices[CurIndex] = ReadShort(FileHandle)
UVIndices[CurIndex + 2] = ReadShort(FileHandle)
UVIndices[CurIndex + 1] = ReadShort(FileHandle)
UVIndices[CurIndex] = ReadShort(FileHandle)
CurIndex = CurIndex + 3
Next
' Load animation frames
Frames = New MD2AnimFrame[Header.NumFrames]
InterpolatedFrame = New MD2AnimFrame
InterpolatedFrame.Vertices = New Float[Header.NumVertices*3]
SeekStream(FileHandle, Header.OffsetFrames)
Local Scale:Float [3]
Local Translate:Float[3]
Local CurFrame:MD2AnimFrame
Local Tempx:Int
Local Tempy:Int
Local Tempz:Int
Local Dummy:Int
For Local i = 0 To Header.NumFrames-1
Frames[i] = New MD2AnimFrame
Frames[i].vertices = New Float[Header.NumVertices * 3]
CurFrame = Frames[i]
Scale[0] = ReadFloat(FileHandle)
Scale[1] = ReadFloat(FileHandle)
Scale[2] = ReadFloat(FileHandle)
Translate[0] = ReadFloat(FileHandle)
Translate[1] = ReadFloat(FileHandle)
Translate[2] = ReadFloat(FileHandle)
CurFrame.Name = ReadString(FileHandle,16)
For Local v = 0 To Header.NumVertices-1
Tempx = ReadByte(FileHandle)
Tempy = ReadByte(FileHandle)
Tempz = ReadByte(FileHandle)
Dummy = ReadByte(FileHandle)
CurFrame.Vertices[(v*3)] = Tempx * Scale[0] + Translate[0]
CurFrame.Vertices[(v*3)+2] = -1 * (Tempy * Scale[1] + Translate[1])
CurFrame.Vertices[(v*3)+1] = Tempz * Scale[2] + Translate[2]
Next
Next
' Finally, close stream
CloseStream(FileHandle)
EndMethod
' Set animation FPS
Method SetFPS(FPS:Int)
Self.FPS = FPS;
EndMethod
' Toggle animation on/off
Method ToggleAnim(Enable:Int)
Animate = Enable
EndMethod
' Reset animation
Method ResetAnim()
CurAnimFrame = StartFrame
NextAnimFrame = StartFrame+1
LastAnimTime = 0
EndMethod
' Set animation range
Method SetAnimRange(StartFrame:Int, EndFrame:Int)
' Set values
self.StartFrame = StartFrame
self.EndFrame = EndFrame
' Make sure they're within range
If (StartFrame < 0) Then StartFrame = 0
If (StartFrame > Frames.length) Then StartFrame = Frames.length
If (EndFrame < 0) Then EndFrame = 0
If (EndFrame > Frames.length) Then EndFrame = Frames.length
CurAnimFrame = StartFrame
NextAnimFrame = StartFrame+1
EndMethod
' Create interpolated frame (Private function used internally)
Method CreateInterpolatedFrame()
' Grab current time
Local CurTime:Long = MilliSecs()
' Calculate delta time between last frame and now
Local ElapsedTime:Long = CurTime - LastAnimTime
' Calculate interpolation value from delta time + fps
Local T:Float = ElapsedTime / (1000.0 / self.FPS)
' Calculate next frame to interpolate against
NextAnimFrame = (CurAnimFrame + 1)
' Over the edge? Then wrap animation
If(NextAnimFrame > EndFrame) Then NextAnimFrame = StartFrame
' Calculate current animation frame
If(ElapsedTime > (1000.0 / fps)) Then
CurAnimFrame = NextAnimFrame
LastAnimTime = CurTime
End If
' Go through all vertices of current
For Local v = 0 To Frames[CurAnimFrame].Vertices.length -1
InterpolatedFrame.Vertices[v] = (Frames[CurAnimFrame].Vertices[v] + T * (Frames[NextAnimFrame].Vertices[v] - Frames[CurAnimFrame].Vertices[v]))
Next
EndMethod
' Render model
Method Render()
' Grab first frame
Local Frame:MD2AnimFrame = Frames[StartFrame]
' If we're animating we are going to create a temporary interpolated frame and use that instead
If (Animate=True) Then
CreateInterpolatedFrame()
Frame = InterpolatedFrame
End If
' Start triangle based rendering (Will optimize soon :)
glBegin GL_TRIANGLES
' Go through vertices/uv coords grabbing them from their respective indices
For Local v = 0 To VertIndices.length-1
glTexCoord2f(UVs[(UVIndices[v]*2)], UVs[(UVIndices[v]*2)+1])
glVertex3f(Frame.Vertices[(VertIndices[v]*3)], Frame.Vertices[(VertIndices[v]*3)+1], Frame.Vertices[(VertIndices[v]*3)+2])
Next
' End triangle rendering
glEnd
EndMethod
EndType |
Comments
| ||
| How to use, example pls? |
Code Archives Forum