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

MD2 loader/animator class by ozak2005
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

Romanski2009
How to use, example pls?


Code Archives Forum