Cal3d Loader

BlitzMax Forums/MiniB3D Module/Cal3d Loader

Leon Drake(Posted 2011) [#1]
Hi guys, I havent had time to finish this or even work on it, not sure when i can get to it next but here is a Cal3d loader i was working on, currently i believe i was at the point of trying to weight the vertices to the loaded bones , but i had problems doing that at runtime.

Anyhoo here is the code thus far


Type C3DAnimation

	Field duration#
	Field numtracks
	Field Tracks:C3DTrack[]
	
	Method SetTracks()
	
		Local ntracks:C3DTrack[numtracks]
		Tracks = ntracks
	
	End Method
	

End Type


Type C3DTrack

	Field numkeyframes
	Field ID
	Field keys:C3DKey[]

	Method SetKeys()
	
		Local nkeys:C3DKey[numkeyframes]
		keys = nkeys
	
	End Method

End Type

Type C3DKey

	Field time#
	Field rot:C3DQuat = New C3DQuat

End Type

Type C3DFace

	Field v1,v2,v3

End Type

Type C3DInfluence

	Field v
	Field ID
	Field weight#
	Field submesh:C3DSubMesh
	
End Type

Type C3DVertex
	
	Field numinfluences
	Field pos:C3DCoord = New C3DCoord
	Field norm:C3DCoord = New C3DCoord
	Field color:C3DCoord = New C3DCoord
	Field u#,v#
	Field influence:C3DInfluence[]
	Field tmp_curr_influence = 0
	Method SetInfluences()
	
		Local nflue:C3DInfluence[numinfluences]
		influence = nflue
	
	End Method

End Type

Type C3DSubMesh

	Field numvertices
	Field numfaces
	Field numlodsteps
	Field numsprings
	Field nummorphs
	Field numtexcoords
	Field matid
	Field Vertices:C3DVertex[]
	Field Faces:C3DFace[]
	Field tmp_curr_face = 0
	Field surface:TSurface
	Field animsurf:TSurface
	Method SetVertex()
	
		Local nverts:C3DVertex[numvertices]
		Vertices = nverts
	
	End Method
	
	Method SetFace()
	
		Local nface:C3DFace[numfaces]
		Faces = nface
	
	End Method
	

	
		

End Type

Type C3DMesh


	Field xmf:TBank
	Field xsf:TBank
	Field numbones
	Field numsubmesh
	
	Field mesh:TMesh = CreateMesh()' = New TMesh
	
	Field bones:C3DBone[]
	Field submeshes:C3DSubMesh[]
	Field animations:C3DAnimation[]
	Field numanims = 0
	
	Method AddB3dBones()
	
	
		Local dbones:TBone[numbones]
		
		For id = 0 To numbones-1
		
		
			dbones[id] = New TBone
			dbones[id].name$ = bones[id].name$
			dbones[id].class$="Bone"
			dbones[id].px#=EntityX(bones[id].mesh,True)
			dbones[id].py#=EntityY(bones[id].mesh,True)
			dbones[id].pz#=EntityZ(bones[id].mesh,True)

			dbones[id].rx#=EntityPitch(bones[id].mesh,True)
			dbones[id].ry#=EntityYaw(bones[id].mesh,True)
			dbones[id].rz#=EntityRoll(bones[id].mesh,True)
			dbones[id].qw#=bones[id].rotation.QuatfromEuler(EntityPitch(bones[id].mesh,True),EntityYaw(bones[id].mesh,True),EntityRoll(bones[id].mesh,True)).quat[3]
			dbones[id].qx#=bones[id].rotation.QuatfromEuler(EntityPitch(bones[id].mesh,True),EntityYaw(bones[id].mesh,True),EntityRoll(bones[id].mesh,True)).quat[0]
			dbones[id].qy#=bones[id].rotation.QuatfromEuler(EntityPitch(bones[id].mesh,True),EntityYaw(bones[id].mesh,True),EntityRoll(bones[id].mesh,True)).quat[1]
			dbones[id].qz#=bones[id].rotation.QuatfromEuler(EntityPitch(bones[id].mesh,True),EntityYaw(bones[id].mesh,True),EntityRoll(bones[id].mesh,True)).quat[2]			


			dbones[id].n_px#=EntityX(bones[id].mesh,True)
			dbones[id].n_py#=EntityY(bones[id].mesh,True)
			dbones[id].n_pz#=EntityZ(bones[id].mesh,True)
			
			dbones[id].n_rx#=EntityPitch(bones[id].mesh,True)
			dbones[id].n_ry#=EntityYaw(bones[id].mesh,True)
			dbones[id].n_rz#=EntityRoll(bones[id].mesh,True)
			dbones[id].n_qw#=bones[id].rotation.QuatfromEuler(EntityPitch(bones[id].mesh,True),EntityYaw(bones[id].mesh,True),EntityRoll(bones[id].mesh,True)).quat[3]
			dbones[id].n_qx#=bones[id].rotation.QuatfromEuler(EntityPitch(bones[id].mesh,True),EntityYaw(bones[id].mesh,True),EntityRoll(bones[id].mesh,True)).quat[0]
			dbones[id].n_qy#=bones[id].rotation.QuatfromEuler(EntityPitch(bones[id].mesh,True),EntityYaw(bones[id].mesh,True),EntityRoll(bones[id].mesh,True)).quat[1]
			dbones[id].n_qz#=bones[id].rotation.QuatfromEuler(EntityPitch(bones[id].mesh,True),EntityYaw(bones[id].mesh,True),EntityRoll(bones[id].mesh,True)).quat[2]			

			
			PositionEntity(dbones[id],dbones[id].n_px#,dbones[id].n_py#,dbones[id].n_pz#,True)
			RotateEntity(dbones[id],dbones[id].n_rx#,dbones[id].n_ry#,dbones[id].n_rz#,True)			

			'TQuaternion.QuatToMat(-dbones[id].n_qw#,dbones[id].n_qx#,dbones[id].n_qy#,-dbones[id].n_qz#,dbones[id].mat)
			
			'dbones[id].mat.grid[3,0]=dbones[id].n_px#
			'dbones[id].mat.grid[3,1]=dbones[id].n_py#
			'dbones[id].mat.grid[3,2]=dbones[id].n_pz#



			'dbones[id].inv_mat=dbones[id].mat.Inverse()
		
			
				'dbones[id].EntityListAdd(TEntity.entity_list)
				

			
			
		Next
		'mesh.bones = dbones
				'mesh.bones[id-1]=dbones[id]
				'last_ent=dbones[id]
		
		For id = 0 To numbones-1
		
			If bones[id].parent <> -1 Then
			
				dbones[id].parent = TEntity(dbones[bones[id].parent])
				EntityParent(dbones[id],dbones[id].parent)
			
			EndIf
		
		Next
			mesh.bones = dbones
		
	
	End Method
	
	Method DrawB3dLines(camera:TCamera)
	
	

		
			For id = 0 To numbones-1
		
				
				If mesh.bones[id].parent <> Null Then
				
				CameraProject(camera, EntityX(TBone(mesh.bones[id].parent),True),EntityY(TBone(mesh.bones[id].parent),True),EntityZ(TBone(mesh.bones[id].parent),True))
				lineax = ProjectedX()
				lineay = ProjectedY()
				lineaz = ProjectedZ()
			
				CameraProject(camera, EntityX(mesh.bones[id],True),EntityY(mesh.bones[id],True),EntityZ(mesh.bones[id],True))
				linebx = ProjectedX()
				lineby = ProjectedY()
				linebz = ProjectedZ()
				
				
				DrawLine(lineax,lineay,linebx,lineby)				
				
				EndIf
						

			Next
	
		
	
	
	
	End Method
	
	Method Drawlines(camera:TCamera,id = -1)
	
		If id = -1 Then
		
			For id = 0 To numbones-1
				If bones[id].parent = -1 Then	
				
					If bones[id].numchildren > 0 Then
						For a = EachIn bones[id].children
							
							Drawlines(camera,a)
						
						Next
						CameraProject(camera, EntityX(bones[id].mesh,True),EntityY(bones[id].mesh,True),EntityZ(bones[id].mesh,True))
						linebx = ProjectedX()
						lineby = ProjectedY()
						linebz = ProjectedZ()						
						DrawText(bones[id].name$,linebx,lineby)
					
					EndIf				
				Exit
				EndIf
				
			Next
		
		Else

			If EntityVisible(camera,bones[id].mesh) = True Then

				CameraProject(camera, EntityX(bones[bones[id].parent].mesh,True),EntityY(bones[bones[id].parent].mesh,True),EntityZ(bones[bones[id].parent].mesh,True))
				lineax = ProjectedX()
				lineay = ProjectedY()
				lineaz = ProjectedZ()
			
				CameraProject(camera, EntityX(bones[id].mesh,True),EntityY(bones[id].mesh,True),EntityZ(bones[id].mesh,True))
				linebx = ProjectedX()
				lineby = ProjectedY()
				linebz = ProjectedZ()
				
				
				DrawLine(lineax,lineay,linebx,lineby)
				'DrawText(bones[id].name$,linebx,lineby)
			EndIf
			
			For a = EachIn bones[id].children
				
				
				Drawlines(camera,a)
			
			Next

		
		
		EndIf
		
	
	End Method

	Method InitSkeleton(id = -1)
	
		Local ppivot:TPivot
		
		If id = -1 Then
		
			For id = 0 To numbones-1
				If bones[id].parent = -1 Then

					PositionEntity(bones[id].mesh,bones[id].translation.coord[0],bones[id].translation.coord[1],bones[id].translation.coord[2],True)
					
					
					If bones[id].numchildren > 0 Then
						For a = EachIn bones[id].children
							
							InitSkeleton(a)
						
						Next
						
					
					EndIf
				
				
				Exit
				
				EndIf	
				
			
		
			Next
			AddB3dBones()
		
		Else


				PositionEntity(bones[id].mesh,EntityX(bones[bones[id].parent].mesh,True),EntityY(bones[bones[id].parent].mesh,True),EntityZ(bones[bones[id].parent].mesh,True))
				RotateEntity(bones[id].mesh,EntityPitch(bones[bones[id].parent].mesh,True),EntityYaw(bones[bones[id].parent].mesh,True),EntityRoll(bones[bones[id].parent].mesh,True))
				EntityParent(bones[id].mesh,bones[bones[id].parent].mesh)
				TurnEntity(bones[id].mesh,bones[id].rotation.QuattoEuler().coord[0],bones[id].rotation.QuattoEuler().coord[1],-bones[id].rotation.QuattoEuler().coord[2])

				PositionEntity(bones[id].mesh,bones[id].translation.coord[0],bones[id].translation.coord[1],bones[id].translation.coord[2])
				
			If bones[id].numchildren > 0 Then
				For a = EachIn bones[id].children
					
					InitSkeleton(a)
				
				Next
				
			
			EndIf
		
		EndIf
	

	
		
	
	
	
	End Method
	


	
	
	Method GenerateInfluenceList:TList()
	
		Local i,e,o
		Local Inlist:TList = New TList
		If numsubmesh = 0 Then Return Null
		
		For i = 0 To numsubmesh-1
		
			
			If submeshes[i].Vertices.length = 0 Then 
				Continue
			Else
			
				For e = 0 To submeshes[i].Vertices.length-1
				
					If submeshes[i].Vertices[e].influence.length = 0 Then
						Continue
					Else
						
						For o = 0 To submeshes[i].Vertices[e].influence.length-1
						
						
							ListAddLast(Inlist,submeshes[i].Vertices[e].influence[o])
						
						
						Next	
						
					EndIf
				
				
				Next
				
			
			EndIf
			
		
		
		Next
		Return Inlist
	
	End Method
	
	Method WeighCal3DMesh()
	
		Local i,l,e
		Local bo_bone:TBone
		Local influence:TList
		Local influ:C3DInfluence
		If bones.length = 0 Then Return False
		
		mesh.anim=True
		mesh.anim_seqs_first[0]=0
		mesh.anim_seqs_last[0]=0

		For Local surf:TSurface=EachIn mesh.surf_list
		
			Local anim_surf:TSurface=New TSurface
			
			For e = 0 To numsubmesh-1
			
				If submeshes[e].surface = surf Then submeshes[e].animsurf = anim_surf
			
			
			Next
			
			ListAddLast(mesh.anim_surf_list,anim_surf)
		
			anim_surf.no_verts=surf.no_verts
						
			anim_surf.vert_coords=surf.vert_coords[..]
		
			anim_surf.vert_bone1_no=anim_surf.vert_bone1_no[..surf.no_verts+1]
			anim_surf.vert_bone2_no=anim_surf.vert_bone2_no[..surf.no_verts+1]
			anim_surf.vert_bone3_no=anim_surf.vert_bone3_no[..surf.no_verts+1]
			anim_surf.vert_bone4_no=anim_surf.vert_bone4_no[..surf.no_verts+1]
			anim_surf.vert_weight1=anim_surf.vert_weight1[..surf.no_verts+1]
			anim_surf.vert_weight2=anim_surf.vert_weight2[..surf.no_verts+1]
			anim_surf.vert_weight3=anim_surf.vert_weight3[..surf.no_verts+1]
			anim_surf.vert_weight4=anim_surf.vert_weight4[..surf.no_verts+1]
			
			' transfer vmin/vmax values for using with TrimVerts func after
			anim_surf.vmin=surf.vmin
			anim_surf.vmax=surf.vmax
		
		Next
				
		influence = GenerateInfluenceList()
		
		
		
		For influ = EachIn influence
		
			Print "Vertex: "+influ.v+" Weight is "+influ.weight#+" vert weight 1 mb3d "+influ.submesh.animsurf.vert_weight1[influ.v]

			If influ.weight#>influ.submesh.animsurf.vert_weight1[influ.v]
								
				influ.submesh.animsurf.vert_bone4_no[influ.v]=influ.submesh.animsurf.vert_bone3_no[influ.v]
				influ.submesh.animsurf.vert_weight4[influ.v]=influ.submesh.animsurf.vert_weight3[influ.v]
				
				influ.submesh.animsurf.vert_bone3_no[influ.v]=influ.submesh.animsurf.vert_bone2_no[influ.v]
				influ.submesh.animsurf.vert_weight3[influ.v]=influ.submesh.animsurf.vert_weight2[influ.v]
				
				influ.submesh.animsurf.vert_bone2_no[influ.v]=influ.submesh.animsurf.vert_bone1_no[influ.v]
				influ.submesh.animsurf.vert_weight2[influ.v]=influ.submesh.animsurf.vert_weight1[influ.v]
				
				influ.submesh.animsurf.vert_bone1_no[influ.v]=influ.ID
				influ.submesh.animsurf.vert_weight1[influ.v]=influ.weight#
										
			Else If influ.weight#>influ.submesh.animsurf.vert_weight2[influ.v]
			
				influ.submesh.animsurf.vert_bone4_no[influ.v]=influ.submesh.animsurf.vert_bone3_no[influ.v]
				influ.submesh.animsurf.vert_weight4[influ.v]=influ.submesh.animsurf.vert_weight3[influ.v]
				
				influ.submesh.animsurf.vert_bone3_no[influ.v]=influ.submesh.animsurf.vert_bone2_no[influ.v]
				influ.submesh.animsurf.vert_weight3[influ.v]=influ.submesh.animsurf.vert_weight2[influ.v]
				
				influ.submesh.animsurf.vert_bone2_no[influ.v]=influ.ID
				influ.submesh.animsurf.vert_weight2[influ.v]=influ.weight#
																	
			Else If influ.weight#>influ.submesh.animsurf.vert_weight3[influ.v]
			
				influ.submesh.animsurf.vert_bone4_no[influ.v]=influ.submesh.animsurf.vert_bone3_no[influ.v]
				influ.submesh.animsurf.vert_weight4[influ.v]=influ.submesh.animsurf.vert_weight3[influ.v]

				influ.submesh.animsurf.vert_bone3_no[influ.v]=influ.ID
				influ.submesh.animsurf.vert_weight3[influ.v]=influ.weight#
	
			Else If influ.weight#>influ.submesh.animsurf.vert_weight4[influ.v]
			
				influ.submesh.animsurf.vert_bone4_no[influ.v]=influ.ID
				influ.submesh.animsurf.vert_weight4[influ.v]=influ.weight#
						
			EndIf			
		
		
		Next
		

	
	
	End Method
	
	Method BuildCal3DMesh()
	
		Local i,e,v
		Local s:TSurface
		'Local smesh:TMesh
		If bones.length = 0 Then Return False
		If mesh = Null Then
			mesh = CreateMesh()
		EndIf
		RotateEntity(mesh.bones[0],90,90,0)
		'RotateEntity(mesh,90,90,0)
			For i = 0 To numsubmesh-1
			
				s = mesh.CreateSurface()
				submeshes[i].surface = s
				For e = 0 To submeshes[i].numvertices-1
				
					v = s.AddVertex((submeshes[i].Vertices[e].pos.coord#[0])+bones[0].translation.coord#[0],(submeshes[i].Vertices[e].pos.coord#[1])+bones[0].translation.coord#[1],(submeshes[i].Vertices[e].pos.coord#[2])+bones[0].translation.coord#[2])	
					s.VertexTexCoords(v,submeshes[i].Vertices[e].u#,submeshes[i].Vertices[e].v#)
					s.VertexNormal(v,submeshes[i].Vertices[e].norm.coord#[0],submeshes[i].Vertices[e].norm.coord#[1],submeshes[i].Vertices[e].norm.coord#[2])				
					s.VertexColor(v,submeshes[i].Vertices[e].color.coord#[0],submeshes[i].Vertices[e].color.coord#[1],submeshes[i].Vertices[e].color.coord#[2])
				Next
				For e = 0 To submeshes[i].numfaces-1
				
					s.AddTriangle(submeshes[i].Faces[e].v1,submeshes[i].Faces[e].v2,submeshes[i].Faces[e].v3)
					Print "Adding Triangle: "+e
				Next	
			
			Next
			UpdateNormals(mesh)
			'ScaleMesh(mesh,0.02,0.02,0.02)
			'PositionMesh(mesh,bones[0].local_translation.coord#[0],bones[0].local_translation.coord#[1],bones[0].local_translation.coord#[2])

			
			'AddMesh(smesh,mesh)
			'mesh = amesh
			WeighCal3DMesh()
			mesh.UpdateMat()
	
	
	End Method

	Method LoadCal3dAnim(file:Object)
	
		If bones.length = 0 Then Return False
		Local animdoc:xmlDocument = New xmlDocument
		Local node:xmlNode,vid
		Local subnode:xmlNode
		Local infonode:xmlNode
		Local CalString:Tokenizer
		Local Info:String[]
		Local xaf:TBank = LoadBank(file)
		animdoc.Load(xaf)
		If xaf = Null Then Return False	
	
		Select Lower(animdoc.Root().Name)
		
			Case "animation"
				numanims = numanims + 1
				animations = animations[..numanims]
				animations[numanims-1] = New C3DAnimation
				animations[numanims-1].duration# = Float(animdoc.Root().Attribute("DURATION").value)
				animations[numanims-1].numtracks = Int(animdoc.Root().Attribute("NUMTRACKS").value)
				animations[numanims-1].SetTracks()
				If animdoc.Root().HasChildren() = True Then
					node = animdoc.Root().FirstChild()
					curtrack = 0
					While node <> Null
					
						animations[numanims-1].Tracks[curtrack] = New C3DTrack
								
						animations[numanims-1].Tracks[curtrack].numkeyframes = Int(node.Attribute("NUMKEYFRAMES").value)
						animations[numanims-1].Tracks[curtrack].ID = Int(node.Attribute("BONEID").value)
						animations[numanims-1].Tracks[curtrack].SetKeys()
						
						If node.HasChildren() = True Then
							subnode = node.FirstChild()
							curkey = 0
							While subnode <> Null
								Select Lower(subnode.Name)
								
									Case "keyframe"
										animations[numanims-1].Tracks[curtrack].keys[curkey] = New C3DKey
										animations[numanims-1].Tracks[curtrack].keys[curkey].time# = Float(subnode.Attribute("TIME").value)

										If subnode.HasChildren() = True Then
											infonode = subnode.FirstChild()
											While infonode <> Null
												Select Lower(infonode.Name)
											
													Case "rotation"
														
														animations[numanims-1].Tracks[curtrack].keys[curkey].rot.QuatfromString(infonode.value)
														'Print "have anim rotations: "+animations[numanims-1].Tracks[curtrack].keys[curkey].rot.quat#[0]+" "+
												End Select
											infonode = infonode.NextSibling()
											Wend
											
										EndIf	
									
								End Select
								curkey = curkey+1
								subnode = subnode.NextSibling()
							Wend
						EndIf								
					
					
						curtrack = curtrack + 1
				
						node = node.NextSibling()
					Wend	
				
				EndIf				

		End Select	
	
		
	
	
	
	End Method


	Method LoadCal3dMesh(file:Object)
	
		If bones.length = 0 Then Return False
		Local meshdoc:xmlDocument = New xmlDocument
		Local node:xmlNode,vid
		Local subnode:xmlNode
		Local infonode:xmlNode
		Local CalString:Tokenizer
		Local Info:String[]
		xmf = LoadBank(file)
		meshdoc.Load(xmf)
		If xmf = Null Then Return False
		Select Lower(meshdoc.Root().Name)
		
			Case "mesh"
				numsubmesh = Int(meshdoc.Root().Attribute("NUMSUBMESH").value)
				Local nsubs:C3dSubMesh[numsubmesh]
				submeshes = nsubs
				If meshdoc.Root().HasChildren() = True Then
					node = meshdoc.Root().FirstChild()
					cursub = 0
					While node <> Null
						submeshes[cursub] = New C3DSubMesh
   						submeshes[cursub].numvertices = Int(node.Attribute("NUMVERTICES").value)
						submeshes[cursub].numfaces = Int(node.Attribute("NUMFACES").value)					
						submeshes[cursub].numlodsteps = Int(node.Attribute("NUMLODSTEPS").value)
						submeshes[cursub].numsprings = Int(node.Attribute("NUMSPRINGS").value)
						submeshes[cursub].nummorphs = Int(node.Attribute("NUMMORPHS").value)
						submeshes[cursub].numtexcoords = Int(node.Attribute("NUMTEXCOORDS").value)
						submeshes[cursub].matid = Int(node.Attribute("MATERIAL").value)
						submeshes[cursub].SetVertex()
						submeshes[cursub].SetFace()
						submeshes[cursub].tmp_curr_face = 0
						If node.HasChildren() = True Then
							subnode = node.FirstChild()
							While subnode <> Null
								Select Lower(subnode.Name)	
							
									Case "vertex"
										vid = Int(subnode.Attribute("ID").value)
										submeshes[cursub].Vertices[vid] = New C3DVertex
										submeshes[cursub].Vertices[vid].numinfluences = Int(subnode.Attribute("NUMINFLUENCES").value)
										submeshes[cursub].Vertices[vid].SetInfluences()
										submeshes[cursub].Vertices[vid].tmp_curr_influence = 0
										If subnode.HasChildren() = True Then
											infonode = subnode.FirstChild()
											While infonode <> Null
												Select Lower(infonode.Name)
											
													Case "pos"
														'CalString = New Tokenizer
														'CalString.Set(infonode.value)
														'CalString.Tokenize()
														'Info = CalString.TokensToArray()
														submeshes[cursub].Vertices[vid].pos.CoordfromString(infonode.value)' = Float(Info[0])
														'submeshes[cursub].Vertices[vid].pos.coord#[1] = Float(Info[1])
														'submeshes[cursub].Vertices[vid].pos.coord#[2] = Float(Info[2])
																											
													Case "norm"													
														'CalString = New Tokenizer
														'CalString.Set(infonode.value)
														'CalString.Tokenize()
														'Info = CalString.TokensToArray()
														submeshes[cursub].Vertices[vid].norm.CoordfromString(infonode.value)' = Float(Info[0])
														'submeshes[cursub].Vertices[vid].norm.coord#[1] = Float(Info[1])
														'submeshes[cursub].Vertices[vid].norm.coord#[2] = Float(Info[2])
														
													Case "color"													
														'CalString = New Tokenizer
														'CalString.Set(infonode.value)
														'CalString.Tokenize()
														'Info = CalString.TokensToArray()
														submeshes[cursub].Vertices[vid].color.CoordfromString(infonode.value)' = Float(Info[0])
														'submeshes[cursub].Vertices[vid].color.coord#[1] = Float(Info[1])
														'submeshes[cursub].Vertices[vid].color.coord#[2] = Float(Info[2])	
														
													Case "texcoord"													
														CalString = New Tokenizer
														CalString.Set(infonode.value)
														CalString.Tokenize()
														Info = CalString.TokensToArray()
														submeshes[cursub].Vertices[vid].u# = Float(Info[0])
														submeshes[cursub].Vertices[vid].v# = Float(Info[1])

													Case "influence"	
														submeshes[cursub].Vertices[vid].Influence[submeshes[cursub].Vertices[vid].tmp_curr_influence] = New C3DInfluence
														submeshes[cursub].Vertices[vid].Influence[submeshes[cursub].Vertices[vid].tmp_curr_influence].ID = Int(infonode.Attribute("ID").value)	
														submeshes[cursub].Vertices[vid].Influence[submeshes[cursub].Vertices[vid].tmp_curr_influence].weight# = Float(infonode.value)
														submeshes[cursub].Vertices[vid].Influence[submeshes[cursub].Vertices[vid].tmp_curr_influence].v = vid
														submeshes[cursub].Vertices[vid].Influence[submeshes[cursub].Vertices[vid].tmp_curr_influence].submesh = submeshes[cursub]
															
														submeshes[cursub].Vertices[vid].tmp_curr_influence = submeshes[cursub].Vertices[vid].tmp_curr_influence + 1									
												End Select
												infonode = infonode.NextSibling()
											Wend
										EndIf

									Case "face"
										CalString = New Tokenizer
										CalString.Set(subnode.Attribute("VERTEXID").value)
										CalString.Tokenize()
										Info = CalString.TokensToArray()
										submeshes[cursub].Faces[submeshes[cursub].tmp_curr_face] = New C3DFace
										submeshes[cursub].Faces[submeshes[cursub].tmp_curr_face].v1 = Int(Info[0])
										submeshes[cursub].Faces[submeshes[cursub].tmp_curr_face].v2 = Int(Info[1])
										submeshes[cursub].Faces[submeshes[cursub].tmp_curr_face].v3 = Int(Info[2])
										Print "Tokenized Triangle: "+Info[0]+" "+Info[1]+" "+Info[2]
										submeshes[cursub].tmp_curr_face = submeshes[cursub].tmp_curr_face + 1										
								
								End Select
								subnode = subnode.NextSibling()
							Wend	
						EndIf
						
						
						
						
					
						cursub = cursub + 1
						node = node.NextSibling()
					Wend
				
				EndIf
		
		End Select
		BuildCal3DMesh()
		
	End Method


	Method LoadCal3dSkeleton(file:Object)
		
		Local skeletondoc:xmlDocument = New xmlDocument
		Local node:xmlNode
		Local subnode:xmlNode
		Local numchilds = 0
		xsf = LoadBank(file)
		If xsf = Null Then Return False
		skeletondoc.Load(xsf)
		Select Lower(skeletondoc.Root().Name)
		
			Case "skeleton"
			
				numbones = Int(skeletondoc.Root().Attribute("NUMBONES").value)
				Local nbones:C3DBone[numbones]
				bones = nbones
				If skeletondoc.Root().HasChildren() = True Then
					node = skeletondoc.Root().FirstChild()
					While node <> Null
						id = Int(node.Attribute("ID").value)
						bones[id] = New C3DBone
						bones[id].name$ = node.Attribute("NAME").value
						numchilds = Int(node.Attribute("NUMCHILDS").value)
						'Print "NAME: "+bones[id].name$+"NUMCHILDS: "+numchilds
						bones[id].setchildren(numchilds)
						If node.HasChildren() = True Then
							subnode = node.FirstChild()
							
							While subnode <> Null
								
								Select Lower(subnode.Name)					
								
								
									Case "translation"										
										bones[id].translation.CoordfromString(subnode.value)
										
									Case "rotation"
										bones[id].rotation.QuatfromString(subnode.value)
										
									Case "localtranslation"
										bones[id].local_translation.CoordfromString(subnode.value)
										
									Case "localrotation"
										bones[id].local_rotation.QuatfromString(subnode.value)
										
									Case "parentid"
										bones[id].parent = Int(subnode.value)
										
									Case "childid"
										bones[id].children[bones[id].curr_child] = Int(subnode.value)
										bones[id].curr_child = bones[id].curr_child + 1
										
								End Select
								subnode = subnode.NextSibling()
							Wend
						EndIf
						
						bones[id].mesh = CreatePivot()
						'EntityAlpha(bones[id].mesh,0.1)
						'ScaleEntity(bones[id].mesh,0.02,0.02,0.02)
						'bones[id].labelsprite = createsprite(bones[id].mesh)
						'SpriteViewMode(bones[id].labelsprite,3)
						'bones[id].labeltex = CreateTexture(128,64,2)
						
						'Cls
						'BeginMax2D()
						'DrawText bones[id].name$,0,0
						'EndMax2D()						
						
						'Flip
						'BackBufferToTex(bones[id].labeltex)
						'RotateTexture(bones[id].labeltex,180)
						'ScaleTexture(bones[id].labeltex,-1,1)
						'EntityTexture(bones[id].labelsprite,bones[id].labeltex )
						'ScaleSprite(bones[id].labelsprite,0.10,0.10)
						'EntityAlpha(bones[id].labelsprite,0.9)
						'HideEntity(bones[id].labelsprite)						
						node = node.NextSibling()
					Wend
									
				
				EndIf
			
			
		
		End Select	

	End Method


End Type



Type C3DBone

	Field name$
	Field children[]
	Field id
	Field translation:C3DCoord = New C3DCoord
	Field rotation:C3DQuat = New C3DQuat
	Field local_translation:C3DCoord = New C3DCoord
	Field local_rotation:C3DQuat = New C3DQuat
	Field parent
	Field numchildren = 0
	Field curr_child = 0
	
	Field mesh:TEntity
	Field labelsprite:TSprite
	Field labeltex:TTexture
	Method setchildren(amnt)
	
		Local chlds[amnt]
		children = chlds
		numchildren = amnt
	
	End Method
	
	
	Method Combined_translation:C3DCoord()
	
		Local mycoord:C3DCoord = New C3DCoord
		
		
		mycoord.coord[0] = translation.coord[0] - local_translation.coord[0]
		mycoord.coord[1] = translation.coord[1] - local_translation.coord[1]
		mycoord.coord[2] = translation.coord[2] - local_translation.coord[2]
		
	
		Return mycoord	
	End Method


End Type




Type C3DCoord

	Field coord#[3]
	
	Method CoordfromString(mstr$)
	
		
		a1 = Instr( mstr$," " )
		coord[0] = Float(Left$( mstr$,a1 ))
	 	mstr$ = Right( mstr$,Len(mstr$)-a1)


		a1 = Instr( mstr$," " )
		coord[1] = Float(Left$( mstr$,a1 ))
	 	mstr$ = Right( mstr$,Len(mstr$)-a1)
	
		coord[2] = Float(mstr$)	
	
	
		Print "x: "+coord[0]+" y: "+coord[1]+" z: "+coord[2]
	
	End Method

End Type

Type C3DQuat
	Field quat#[4]
	Field QuatToEulerAccuracy# = 0.001

	
	Method QuatfromString(mstr$)
	
		
		a1 = Instr( mstr$," " )
		quat[0] = Float(Left$( mstr$,a1 ))
	 	mstr$ = Right( mstr$,Len(mstr$)-a1)

		a1 = Instr( mstr$," " )
		quat[1] = Float(Left$( mstr$,a1 ))
	 	mstr$ = Right( mstr$,Len(mstr$)-a1)
	
		a1 = Instr( mstr$," " )
		quat[2] = Float(Left$( mstr$,a1 ))	
		mstr$ = Right( mstr$,Len(mstr$)-a1)
		
		
		quat[3] = Float(mstr$)		
		
		Print ""+quat[0]+" "+quat[1]+" "+quat[2]+" "+quat[3]
	
	End Method
	
	
	Method QuatfromEuler:C3DQuat(r#,p#,y#)
	
	Local out:C3DQuat = New C3DQuat
	
	Local cr# = Cos(-r/2)
	Local cp# = Cos(p/2)
	Local cy# = Cos(y/2)

	Local sr# = Sin(-r/2)
	Local sp# = Sin(p/2)
	Local sy# = Sin(y/2)

	' These variables are only here To cut down on the number of multiplications
	Local cpcy# = cp * cy
	Local spsy# = sp * sy
	Local spcy# = sp * cy
	Local cpsy# = cp * sy

	' Generate the output quat
	out.quat[3] = cr * cpcy + sr * spsy
	out.quat[0] = sr * cpcy - cr * spsy
	out.quat[1] = cr * spcy + sr * cpsy
	out.quat[2] = cr * cpsy - sr * spcy	
	
	Return out
	
	End Method
	
	
	Method QuattoEuler:C3DCoord()
	
		Local sint#, cost#, sinv#, cosv#, sinf#, cosf#
		Local cost_temp#
		Local out:C3DCoord = New C3DCoord
		
		sint = (2 * quat[3] * quat[1]) - (2 * quat[0] * quat[2])
		cost_temp = 1.0 - (sint * sint)
	
		If Abs(cost_temp) > QuatToEulerAccuracy
			cost = Sqr(cost_temp)
		Else
			cost = 0
		EndIf
	
		If Abs(cost) > QuatToEulerAccuracy
			sinv = ((2 * quat[1] * quat[2]) + (2 * quat[3] * quat[0])) / cost
			cosv = (1 - (2 * quat[0] * quat[0]) - (2 * quat[1] * quat[1])) / cost
			sinf = ((2 * quat[0] * quat[1]) + (2 * quat[3] * quat[2])) / cost
			cosf = (1 - (2 * quat[1] * quat[1]) - (2 * quat[2] * quat[2])) / cost
		Else
			sinv = (2 * quat[3] * quat[0]) - (2 * quat[1] * quat[2])
			cosv = 1 - (2 * quat[0] * quat[0]) - (2 * quat[2] * quat[2])
			sinf = 0
			cosf = 1
		EndIf
	
		' Generate the output rotation
		out.coord[0] = -ATan2(sinv, cosv) '  inverted due To change in handedness of coordinate system
		out.coord[1] = ATan2(sint, cost)
		out.coord[2] = ATan2(sinf, cosf)
	
		'Print "R: "+out.coord[0]+" P: "+out.coord[1]+" Y: "+out.coord[2]
		Return out
	
	End Method
		
	
End Type




Function c3ddemo()


	
	Local filter$="Skeleton Files:xsf; All Files:*"
	Local tfile$ = RequestFile( "Select file to open",filter$ )

	
	cmesh.LoadCal3dSkeleton(tfile$)
	cmesh.InitSkeleton()
	filter$="Mesh Files:xmf; All Files:*"
	tfile$ = RequestFile( "Select file to open",filter$ )	
	cmesh.LoadCal3dMesh(tfile$)
	filter$="Animation Files:xaf; All Files:*"
	tfile$ = RequestFile( "Select file to open",filter$ )	
	
	cmesh.LoadCal3dAnim(tfile$)

End Function



Type Tokenizer

  Field theString:String = ""
  Field tokenList:TList = New TList
  Field tokenLink:TLink = New TLink 
 

  Function Create:Tokenizer(theString:String)
    Local newTokenizer:Tokenizer = New Tokenizer 
    newTokenizer.theString = theString
    Return newTokenizer
  End Function


  Method Set(theString:String)
    Self.theString = theString
  End Method


  Method Get:String()
    Return ToString()
  End Method


  Method ToString:String()
		Return theString
	End Method

	
	Method Tokenize(delim:String = " ")
	  tokenList.Clear()
	  lastI = -1
	  token:String = ""
	  For i = 0 To theString.length - 1
	    If theString[i..(i+delim.length)] = delim Then
	      token = theString[(lastI+1)..i]
        tokenList.AddLast(token)
        i = i + delim.length - 1 ' Needed for the support of a delimiter with more than 1 char
	  		lastI = i 
	    EndIf
	  Next
	  token = theString[(lastI+1)..]
    tokenList.AddLast(token) 
	
    Self.GotoFirstToken()
	End Method


	Method CountTokens()
	  Return tokenList.Count()
	End Method
	
	
	Method NextToken:String()
    If tokenLink = Null Then Return ""
	  token:String = tokenLink.Value().ToString()
  	tokenLink = tokenLink.NextLink()
	  Return token
	End Method


  Method GotoFirstToken()
    tokenLink = tokenList.FirstLink()
  End Method


  Method HasMoreTokens()
    If tokenLink = Null Then Return False
    Return True
  End Method


  Method TokensToArray:String[]()
    Local array:Object[] 
    array = tokenList.ToArray()
    Local array2:String[array.length]
    For i = 0 To array.length - 1
      array2[i] = array[i].ToString()
    Next
    Return array2
  End Method


  Method Split:String[](delim:String = " ")
    Tokenize(delim)
    Return TokensToArray()
  End Method
End Type