MD2 Loader + Animation - Texturing

BlitzMax Forums/BlitzMax OpenGL Programming/MD2 Loader + Animation - Texturing

Hi all,

After being obsessed one full day at work with this texture problem, I finallly figured out the solution.

Find yourself an MD2 model and enjoy it in Blitzmax!

Nennig




Global ScreenWidth:Int=1024
Global ScreenHeight:Int=768
Global ScreenDepth:Int=32

Global Framecounter_framerate
Global Checkimage:Byte[256,256,3]
Global texname:Int[20]


bglCreateContext(ScreenWidth,ScreenHeight,ScreenDepth,0,BGL_BACKBUFFER | BGL_DEPTHBUFFER)


Type Face
	Field vertIndex:Int[3]
	Field uvIndex:Int[3]
End Type


Type animFrame
	Field name:String
	Field vertices:Float[]
End Type


Type MD2

Field myCamera:TCamera 
Field name:String
Field magic:Int
Field version:Int
Field skinWitdh: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


Field uvs:Float[]
Field faces:Face[]
Field normals:Float[]
Field interpolatedFrame:animFrame
Field frames:animFrame[]

Field startFrame:Int=0
Field endFrame:Int=0

Field curAnimFrame:Int=0
Field nextAnimFrame:Int=1

Field lastAnimTime:Long=0

Field fps:Int=30
Field animate=False



Function LoadGLTexture(filename:String)
	Local PointeurImg:Byte Ptr
	Local TexWidth
	Local TexHeight
	tex01:TPixmap=LoadPixmap(filename)
	TexWidth=tex01.Width
	TexHeight=tex01.Height
	PointeurImg=PixmapPixelPtr(tex01,0,0)
	pp=0
	For y=TexHeight-1 To 0 Step -1
		For x=0 To TexWidth-1
			Checkimage[y,x,0]=PointeurImg[pp]
			Checkimage[y,x,1]=PointeurImg[pp+1]
			Checkimage[y,x,2]=PointeurImg[pp+2]
			pp=pp+3
		Next
	Next
	tex01=Null
	glEnable(GL_TEXTURE_2D)
	glGenTextures 2, Varptr Texname[0]

	glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
	glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
	glTexImage2D GL_TEXTURE_2D, 0, 3, TexWidth, TexHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, Checkimage
	
	


End Function


Method New()
	myCamera = New TCamera
	LoadGLTexture("blade_red.png")
	filename:String="tris.md2"
	glClearColor(0.0, 2.0, 0.0, 0.0)
	glClearDepth 1.0
	glDepthFunc(GL_LESS)
	glEnable(GL_DEPTH_TEST)
	glFrontFace(GL_CW)
	glShadeModel(GL_SMOOTH)
	glViewport(0,1,ScreenWidth,ScreenHeight)
	glMatriXMode(GL_PROJECTION)
	glLoadIdentitY()
	gluPerspective(45.0,Float(ScreenWidth)/Float(ScreenHeight),1.0,1000.0)
	gluLookAt(mYCamera.Eye.X,mYCamera.Eye.Y,mYCamera.Eye.Z,mYCamera.Target.X,mYCamera.Target.Y,mYCamera.Target.Z,mYCamera.Up.X,mYCamera.Up.Y,mYCamera.Up.Z)
	glMatriXMode(GL_MODELVIEW)
		
	
	fichier=OpenFile(filename)
	taille= FileSize(fichier)
	magic=Readint(fichier)
	version=Readint(fichier)
	skinWitdh=Readint(fichier)
	skinHeight=Readint(fichier)
	framSize=Readint(fichier)
	numSkins=Readint(fichier)
	numVertices=Readint(fichier)
	numTexCoords=Readint(fichier)
	numTriangles=Readint(fichier)
	numGLcommands=Readint(fichier)
	numFrames=Readint(fichier)
	offsetSkins=Readint(fichier)
	offsetTexCoords=Readint(fichier)
	offsetTriangles=Readint(fichier)
	offsetFrames=Readint(fichier)
	offsetGLcommands=Readint(fichier)
	offsetEnd=Readint(fichier)
			
	
	uvs= New Float[numTexCoords*2]
	SeekStream (fichier, offsetTexCoords)
	For i=0 To numTexCoords-1
		uvs[i*2]=Float ReadShort(fichier)/ skinWitdh
		uvs[(i*2)+1]=1- Float ReadShort(fichier)/ skinHeight
	Next 
		
	SeekStream (fichier, offsetTriangles)
	faces=New Face[numTriangles]
	For i=0 To numTriangles-1
		faces[i]= New Face
		curFace:Face=faces[i]
		curFace.vertIndex[2] = ReadShort(fichier)
		curFace.vertIndex[1] = ReadShort(fichier)
		curFace.vertIndex[0] = ReadShort(fichier)
		curFace.uvIndex[2] = ReadShort(fichier)
		curFace.uvIndex[1] = ReadShort(fichier)
		curFace.uvIndex[0] = ReadShort(fichier)
	Next

	frames = New animFrame[numFrames]
	interpolatedFrame = New animFrame
	interpolatedFrame.vertices = New Float[numVertices*3]
	SeekStream(fichier, offsetFrames)
	Local scale:Float [3]
	Local translate:Float[3]
	Local curFrame:animFrame
	Local tempx:Int
	Local tempy:Int
	Local tempz:Int
	Local dummy:Int
	
	For i=0 To numFrames-1
            
                frames[i] = New animFrame
                frames[i].vertices = New Float[numVertices * 3]
                curFrame = frames[i]                                
                                                
                scale[0] = ReadFloat(fichier)
		       scale[1] = ReadFloat(fichier)
		       scale[2] = ReadFloat(fichier)
		       translate[0] = ReadFloat(fichier)
		       translate[1] = ReadFloat(fichier)
		       translate[2] = ReadFloat(fichier)
		       curFrame.name = ReadString(fichier,16)
                                
                For v= 0 To numVertices-1
                                
                    tempx = ReadByte(fichier)
                    tempy = ReadByte(fichier)
                    tempz = ReadByte(fichier)
                    dummy = ReadByte(fichier)
                    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		
	CloseStream(fichier)	
	
End Method

Method Render()
		glClearColor(0.0, 0.1, 0.6, 0.0)
		glClear GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT
		glLoadIdentitY()
		glTranslatef(0.0,0.0,155.0)
		gluLookAt(mYCamera.Eye.X,mYCamera.Eye.Y,mYCamera.Eye.Z,mYCamera.Target.X,mYCamera.Target.Y,mYCamera.Target.Z,mYCamera.Up.X,mYCamera.Up.Y,mYCamera.Up.Z)
		bglDrawText("Eye.X " + mYCamera.Eye.X,10,24)
		bglDrawText("Eye.Y " + mYCamera.Eye.Y,10,44)
		bglDrawText("Eye.Z " + mYCamera.Eye.Z,10,64)
		
		bglDrawText("Target.X " + mYCamera.Target.X,260,24)
		bglDrawText("Target.Y " + mYCamera.Target.Y,260,44)
		bglDrawText("Target.Z " + mYCamera.Target.Z,260,64)
		
		bglDrawText("FPS : "+Framecounter_framerate,10,100)
		bglDrawText("CurFrame : "+curAnimFrame,10,120)
        frame:animFrame = frames[startFrame]
		        
        If (animate=True) Then
      
            createInterpolatedFrame()
            frame = interpolatedFrame

      	End If 
	   
	    glBegin GL_TRIANGLES
  		glBindTexture GL_TEXTURE_2D,Texname[0]
	    	For  i = 0 To faces.length-1 
           
         	curFace:Face = faces[i]
            
         	For v= 0 To  2
			
				glTexCoord2f(uvs[(curFace.uvIndex[v]*2)], uvs[(curFace.uvIndex[v]*2)+1])
         		glVertex3f(frame.vertices[(curFace.vertIndex[v]*3)], frame.vertices[(curFace.vertIndex[v]*3)+1], frame.vertices[(curFace.vertIndex[v]*3)+2])               
      				
			Next 
        	Next
		glEnd
		

		
End Method

Method setFrameRange(startFrame:Int,endFrame:Int)
    
        self.startFrame = startFrame
        self.endFrame = endFrame
       
  		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

End Method
    
Method setFPS(fps:Int)
           
        self.fps = fps
End Method   


Method toggleAnim(enable:Int)
    
	self.animate = enable
    
End Method    



Method resetAnim()
        curAnimFrame = startFrame
        nextAnimFrame = startFrame+1
        lastAnimTime = 0
End Method

Method createInterpolatedFrame()
              
        curTime:Long = MilliSecs()
        elapsedTime:Long = curTime - lastAnimTime
               
	    t:Float = elapsedTime / (1000.0 / self.fps)
        
        nextAnimFrame = (curAnimFrame + 1)' Mod endFrame
        If (nextAnimFrame > endFrame) Then  nextAnimFrame = startFrame
        	
        If(elapsedTime > (1000.0 / fps)) Then
	       curAnimFrame = nextAnimFrame                                  
           lastAnimTime = curTime
	    End If
	        
         For 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 

End Method

End Type

Type TCamera 
	
	Field Eye:Vector3 = New Vector3
	Field Target:Vector3 = New Vector3
	Field Dir:Vector3 = New Vector3
	Field Up:Vector3 = New Vector3
	Field VRight:Vector3= New Vector3
	
	Method New()
		
		Eye.X=0.0
		Eye.Y=10.0
		Eye.Z=-22.0
		Target.X=0.0
		Target.Y=0.0
		Target.Z=100.0
		Up.X=0.0
		Up.Y=1.0
		Up.Z=0.0
		VRight.X=0.0
		VRight.Y=0.0
		VRight.Z=0.0
		
	End Method
	
	Method Move(speed:Float)
		
		Dir=Target.Sub(Eye)
		Eye.X:+Dir.X *speed
		Eye.Z:+Dir.Z *speed
		
		Target.X:+Dir.X *speed
		Target.Z:+Dir.Z *speed
		
	End Method		
	
	Method Rotate(speed:Float)
			
		Dir=Target.Sub(Eye)
		s:Float=DegreeToRadian(speed)
		Target.Z=(Eye.Z+Sin(s)*Dir.X + Cos(s)*Dir.Z)
		Target.X=(Eye.X+Cos(s)*Dir.X - Sin(s)*Dir.Z)
	End Method


	Function  DegreeToRadian:Float(degree:Float)
			 out:Float= degree * (3.1415926/180)
			 Return out	
	End Function
	

End Type


Type Vector3
	Field X:Float										
	Field Y:Float										
	Field Z:Float		
	
	Method Sub:Vector3(v:Vector3)
		result:Vector3=New Vector3
		result.X=X-v.X ; result.Y=Y-v.Y ; result.Z=Z-v.Z
		Return result
	End Method
	
	Method New()
		X=0.0 ; Y=0.0 ; Z=0.0
	End Method

End Type


Global myModel:MD2= New MD2
myModel.setFrameRange(40,45)
myModel.toggleAnim(1)
myModel.setFPS(2)

While Not KeyHit( KEY_ESCAPE )
	If KeyDown(KEY_DOWN) Then myModel.mYCamera.Move(+0.01)
	If KeyDown(KEY_UP) Then myModel.mYCamera.Move(-0.01)
	If KeyDown(KEY_LEFT) Then myModel.mYCamera.Rotate(10)
	If KeyDown(KEY_RIGHT) Then myModel.mYCamera.Rotate(-10)
		 	
	Framecounter_counter=Framecounter_counter+1
	If Framecounter_time=0 Then Framecounter_time=MilliSecs()
	If Framecounter_time+1001 <MilliSecs() Then
		Framecounter_framerate=Framecounter_counter
		Framecounter_counter=0
		Framecounter_time=MilliSecs()
	EndIf
	
		
	myModel.Render()
	bglSwapBuffers
	FlushMem
Wend