Saving animation sequences

Blitz3D Forums/Blitz3D Programming/Saving animation sequences

Is there any way to save manually created animation sequences to a file, to be loaded later using LoadAnimSeq() ?

It depends really on what kind of animation you are referring to. If its skeletal animation then it is possible to write the animation to a .b3d file that can be loaded with LoadAnimSeq(). The file just needs to contain the Nodes and the animation keys. Just convert the Euler angles to quaternions for each frame.

Alternatively PaceMaker 1.34 allows you to load and save individual sequences - even between skeletons of different size/proportion as it uses an "adaptive scaling and rotation" algorithm. This update will be released this weekend.

Yay Smiff - I just got round to downloading 1.33 yesterday (sent you an email asking for activation key)...

... and now I have an upgrade to look forward to !

I am working on a SaveAnimMesh procedure at the moment. Here is the worklog:
http://www.blitzbasic.com/logs/userlog.php?user=9289&log=681

Thanks for putting me on the right track, I am trying to develop an animation editor of my own but will give PaceMaker a look (no sense in reinventing the wheel).

I deleted the worklog, but here is a new version.
;-----------------------------------------------------------------------------------------------------
; 											SaveAnimMesh()
;-----------------------------------------------------------------------------------------------------
;
; This needs the mak_robotic.x file in the same directory. It will load it and attempt to save
; it to disk again. 
;
; by bram32bit thanks to leadwerks
	

	Graphics3D 800, 600, 0, 3
	SetBuffer BackBuffer()
	
	;setup camera
	camera 			= CreateCamera()
	PositionEntity 	camera, 0, 25, -50

	;Load original mesh
    filename$ 		= "mak_robotic.x"
	mesh 			= LoadAnimMesh(filename$)

	;Save mesh
	SaveAnimMesh 	mesh, "tester.x"
	
	;Verify mesh
	mesh2 			= iLoadAnimMesh("tester.x")
	
	;move the mesh to the left
	PositionEntity 	mesh, -10, 0, 0
	
	;move the test object to the right
	PositionEntity 	mesh2, +10, 0, 0
	
	;turn on animation
	Animate 		mesh
	Animate 		mesh2

	;---------	
	;main loop
	;---------	
	While Not KeyHit(1)
	
		UpdateWorld
		RenderWorld
		
		Text 0, 0, "READY!"
		
		Flip
		
	Wend
	
	End
	
;-----------------------------------------------------------------------------------------------------
; 											SaveAnimMesh
;-----------------------------------------------------------------------------------------------------

Type iObj
	Field m
End Type


Global 	dindex
Global 	orgmesh 

;-----------------------------------------------------------------------------------------------------
;												SaveAnimMesh()
;-----------------------------------------------------------------------------------------------------
;saves an animated mesh
Function SaveAnimMesh(mesh, filename$)

	orgmesh = mesh
		
	maxframe = AnimLength(mesh)
	ff = WriteFile(filename$)
	
	WriteLine ff, "xof 0302txt 0064"
	WriteLine ff, " "
	WriteLine ff, "Header {"
	WriteLine ff, " 1;"
	WriteLine ff, " 0;"
	WriteLine ff, " 1;"
	WriteLine ff, "}"
	WriteLine ff, " "

	FindChildren(mesh)
	
	For i.iObj = Each iObj
		SaveAnimObject(ff, i\m, maxframe)
	Next
	
	Delete Each iObj
	
	WriteLine ff, "AnimationSequences {"
	WriteLine ff, "1; 0; 0;"
	WriteLine ff, "2; 0; " + maxframe + ";"
	WriteLine ff, "}"
	WriteLine ff, " "
	
	CloseFile ff	
	
End Function

;-----------------------------------------------------------------------------------------------------
;												SaveAnimObject()
;-----------------------------------------------------------------------------------------------------
;writes a single object to the file
Function SaveAnimObject(ff, mesh, maxframe)

	If CountSurfaces(mesh) > 0 Then 

		x = CountSurfaces(mesh)
		UpdateNormals mesh
				
		For surfindex = 1 To CountSurfaces(mesh)
		
		objectname$ = "Object" + dindex
		dindex = dindex + 1
		
		;start mesh
		WriteLine ff, "Frame frm_" + objectname$ + " {"
		WriteLine ff, " "
		WriteLine ff, " FrameTransformMatrix { "
		WriteLine ff, " 1.000000,0.000000,0.000000,0.000000,"
		WriteLine ff, " 0.000000,1.000000,0.000000,0.000000,"
		WriteLine ff, " 0.000000,0.000000,1.000000,0.000000,"
		WriteLine ff, " 0.000000,0.000000,0.000000,1.000000;"
		WriteLine ff, "}"
		WriteLine ff, " "
	
		;get surface
		surf 		= GetSurface(mesh, surfindex)
		numVert  	= CountVertices(surf)
		numTris 	= CountTriangles(surf)
		
		;get texname
		brush 		= GetSurfaceBrush(surf)
		tex			= GetBrushTexture(brush)
		texname$	= TextureName$(tex)
		If Instr(texname$, "") > 0 Then
			test = 1
			For i = Len(texname$) To 1 Step -1
				 If Mid$(texname$, i, 1) = "" Then test = i: Exit
			Next
			texname$ = Mid$(texname$, test + 1, Len(texname$))
		End If
		FreeTexture tex
		FreeBrush brush
		
		WriteLine 	ff, " Mesh " + objectname$ + " { "
			
		;write vertices
		WriteLine 	ff, " " + numVert + ";"
		
		For i = 0 To numVert - 1
			xx# = VertexX(surf, i)
			yy# = VertexY(surf, i)
			zz# = VertexZ(surf, i)
			WriteLine ff, xx# + ";" + yy# + ";" + zz# + ";,"
		Next
	
		;write triangles	
		WriteLine ff, " " + numTris + ";"
		
		For i = 0 To numTris - 1
			aa = TriangleVertex(surf, i, 0)
			bb = TriangleVertex(surf, i, 1)
			cc = TriangleVertex(surf, i, 2)
			If i = numTris - 1 Then st$ = ";" Else st$ = ","
			WriteLine ff, "3;" + aa + "," + bb + "," + cc + ";" + st$
		Next
	
		;write material properties	
		WriteLine ff, " "
		WriteLine ff, "MeshMaterialList {"
		WriteLine ff, "1;"
		WriteLine ff, "1;"
		WriteLine ff, "0;;"
		WriteLine ff, " "
			
		WriteLine ff, "Material {"
		WriteLine ff, " 1.000000,1.000000,1.000000,1.000000;;"
		WriteLine ff, " 1.000000;"
		WriteLine ff, " 0.500000,0.500000,0.500000;;"
		WriteLine ff, " 0.000000,0.000000,0.000000;;"
		
		;write texture file name	
		If FileType(texname$) = 1 Then
			WriteLine ff, "      TextureFilename {"
			WriteLine ff, "        " + Chr$(34) + texname$ + Chr$(34) + "; }"
		End If
		
		;close material block		
		WriteLine ff, "}"
		WriteLine ff, "}"
		WriteLine ff, " "
	
		;write normals	
		WriteLine ff, "MeshNormals {"	
		WriteLine ff, " " + numVert + ";"
		
		;write normal vertices
		For i = 0 To numVert - 1
			xx# 		= VertexNX(surf, i)
			yy# 		= VertexNY(surf, i)
			zz# 		= VertexNZ(surf, i)
			WriteLine 	ff, xx# + ";" + yy# + ";" + zz# + ";,"
		Next
		
		;write normal triangles
		WriteLine ff, " " + numTris + ";"
		For i = 0 To numTris - 1
			aa 			= TriangleVertex(surf, i, 0)
			bb 			= TriangleVertex(surf, i, 1)
			cc 			= TriangleVertex(surf, i, 2)
			If ( i = numTris - 1 ) Then st$ = ";" Else st$ = ","
			WriteLine 	ff, "3;" + aa + "," + bb + "," + cc + ";" + st$
		Next
	
		;close normals block	
		WriteLine ff, 	"}"
		WriteLine ff, 	" "
		
		;write texture coordinates U,V
		WriteLine ff, 	"MeshTextureCoords {"	
		WriteLine ff, 	" " + numVert + ";"
		
		For i = 0 To numVert - 1
			If ( i = numVert - 1 ) Then st$ = ";" Else st$ = ","
			uu# 		= VertexU(surf, i)
			vv# 		= VertexV(surf, i)
			WriteLine 	ff, uu# + ";" + vv# + ";" + st$
		Next
	
		WriteLine ff, "  }"
	
		;close mesh block	
		WriteLine ff, " }"
		WriteLine ff, " "
		WriteLine ff, "}"
		WriteLine ff, " "
	
		;start animation block
		WriteLine ff, "AnimationSet set_" + objectname$ + " {"
		WriteLine ff, "Animation ani_" + objectname$ + " {"
		WriteLine ff, "{frm_" + objectname$ + "} "
		WriteLine ff, " "
	
			;write position data
			WriteLine ff, "AnimationKey {"
			WriteLine ff, "2;"
			WriteLine ff, (maxframe + 0) + ";"
				For i = 1 To maxframe
					oldp = GetParent(mesh)
					iSetAnimTime orgmesh, i
					EntityParent mesh, 0
					WriteLine ff, PositionToString(i, EntityX(mesh), EntityY(mesh), EntityZ(mesh))
					EntityParent mesh, oldp
				Next
			WriteLine ff, "}"
			WriteLine ff, " "
			
			;write rotation data
			WriteLine ff, "AnimationKey {"
			WriteLine ff, "0;"
			WriteLine ff, (maxframe + 0) + ";"
				For i = 1 To maxframe
					oldp = GetParent(mesh)
					iSetAnimTime orgmesh, i
					EntityParent mesh, 0
					WriteLine ff, RotationToString(i, EntityPitch(mesh), EntityYaw(mesh), EntityRoll(mesh))
					EntityParent mesh, oldp
				Next	
			WriteLine ff, "}"
			WriteLine ff, " "
			
			;write scaling data
			WriteLine ff, "AnimationKey {"
			WriteLine ff, "1;"
			WriteLine ff, (maxframe + 0) + ";"
				For i = 1 To maxframe
					oldp = GetParent(mesh)
					iSetAnimTime orgmesh, i
					EntityParent mesh, 0
					WriteLine ff, ScalingToString(i, EntityWidth(mesh), EntityHeight(mesh), EntityDepth(mesh))
					EntityParent mesh, oldp
				Next
			WriteLine ff, "}"
			WriteLine ff, " "
		
		;write animation options
		WriteLine ff, "AnimationOptions {"
		WriteLine ff , "1;"		;0 = closed (default)  1 = open
		WriteLine ff , "1; }"	;0 = splines  1 = linear
		
		;close animation block
		WriteLine ff, "}"
		WriteLine ff, "}"
		WriteLine ff, " "
		
		Next

	End If
			
End Function

;-----------------------------------------------------------------------------------------------------
;											iLoadAnimMesh()	
;-----------------------------------------------------------------------------------------------------
;loads animated mesh and loads "AnimationSequences" block 
Function iLoadAnimMesh( f$ )

	If FileType(f$) <> 1 Then Return 0
	
	mesh = LoadAnimMesh(f$)
	
	file = ReadFile( f$ )
	
	Repeat
	
		;scan (text) .x file for the term "animationsequences"
		ll$ = ReadLine$( file )
		If Instr(ll$, "AnimationSequences") > 0 Then
			;read from { to }
			While (Instr(ll$, "}") < 1) 
				ll$ = ReadLine$( file )
				If Eof(file) Then Exit
				If Instr(ll$, ";") > 0 Then
					cc = Instr(ll$, ";")
					ll$ = Mid$(ll$, cc + 1, Len(ll$))

					cc = Instr(ll$, ";")
					v1 = Left$(ll$, cc - 1)
					v2 = Mid$(ll$, cc + 1, Len(ll$))
					index = ExtractAnimSeq (mesh, v1, v2)
					
				End If
			Wend
		End If

	If Eof(file) Then Exit
	
	Until Eof(file)
	
	CloseFile file
		
	Return mesh
	
End Function

;-----------------------------------------------------------------------------------------------------
; 										    RotationToString$()
;-----------------------------------------------------------------------------------------------------
;convert rotation information to string
Function RotationToString$(ptime, iPitch#, iYaw#, iRoll#)	

	;this code was written by LeadWerks
	;http://www.blitzbasic.com/Community/posts.php?topic=51579
	sp# = Sin(iYaw   / 2)
	cp# = Cos(iYaw   / 2)
	sy# = Sin(iRoll  / 2)
	cy# = Cos(iRoll  / 2)
	sr# = Sin(iPitch / 2)
	cr# = Cos(iPitch / 2)
	
	w# = + (cr * cp * cy - sr * sp * sy)
	x# = - (sr * cp * cy - cr * sp * sy)
	y# = + (cr * sp * cy + sr * cp * sy)
	z# = - (sr * sp * cy + cr * cp * sy)
	
	Return ptime + "; 4; " + w + "," + x + "," + y + "," + z + ";;;"
	
End Function

;-----------------------------------------------------------------------------------------------------
;											 PositionToString$()
;-----------------------------------------------------------------------------------------------------
;convert position information to string
Function PositionToString$(ptime, iX#, iY#, iZ#)
	
	Return pTime + "; 3;" + iX + "," + iY + "," + iZ + ";;,"
	
End Function

;-----------------------------------------------------------------------------------------------------
;											ScalingToString$()
;-----------------------------------------------------------------------------------------------------
;convert scaling information to string
Function ScalingToString$(pTime, iWidth#, iHeight#, iDepth#)
	
	Return pTime + "; 3;" + iWidth + "," + iHeight + "," + iDepth + ";;,"
	
End Function

;-----------------------------------------------------------------------------------------------------
;											EntityWidth()
;-----------------------------------------------------------------------------------------------------
;returns width of an entity
Function EntityWidth#( mesh )

	If MeshWidth(mesh) = 0 Then Return 0

	TFormPoint MeshWidth(mesh), 0, 0, mesh, 0	
	xx# = TFormedX()
	yy# = TFormedY()
	zz# = TFormedZ()
	TFormPoint 0, 0, 0, mesh, 0	
	xx# = TFormedX()-xx
	yy# = TFormedY()-yy
	zz# = TFormedZ()-zz	
	ll# = Sqr(xx * xx + yy * yy + zz * zz) / MeshWidth(mesh)
	
	Return ll
	
End Function

;-----------------------------------------------------------------------------------------------------
;											EntityHeight()
;-----------------------------------------------------------------------------------------------------
;returns height of an entity
Function EntityHeight#( mesh )

	If MeshHeight(mesh) = 0 Then Return 0
	
	TFormPoint 0, MeshHeight(mesh), 0, mesh, 0
	xx# = TFormedX()
	yy# = TFormedY()
	zz# = TFormedZ()
	TFormPoint 0, 0, 0, mesh, 0
	xx# = TFormedX()-xx
	yy# = TFormedY()-yy
	zz# = TFormedZ()-zz
	ll# = Sqr(xx * xx + yy * yy + zz * zz) / MeshHeight(mesh)
	
	Return ll
	
End Function

;-----------------------------------------------------------------------------------------------------
;											EntityDepth()
;-----------------------------------------------------------------------------------------------------
;returns depth of an entity
Function EntityDepth#( mesh )

	If MeshDepth(mesh) = 0 Then Return 0
	
	TFormPoint 0, 0, MeshDepth(mesh), mesh, 0	
	xx# = TFormedX()
	yy# = TFormedY()
	zz# = TFormedZ()
	TFormPoint 0, 0, 0, mesh, 0
	xx# = TFormedX()-xx
	yy# = TFormedY()-yy
	zz# = TFormedZ()-zz
	
	ll# = Sqr(xx * xx + yy * yy + zz * zz) / MeshDepth(mesh)
	
	Return ll
		
End Function

;-----------------------------------------------------------------------------------------------------
;											iSetAnimTime()
;-----------------------------------------------------------------------------------------------------
;user defined SetAnimTime
Function iSetAnimTime( mesh, time# )
	If time >= AnimLength(mesh) Then time = AnimLength(mesh) - 0.01
	SetAnimTime mesh, time
End Function

	
;-----------------------------------------------------------------------------------------------------
;											iEntityPitch()
;-----------------------------------------------------------------------------------------------------
;get entity's pitch
Function iEntityPitch#(mesh)

	imesh 	= mesh
	pivot	= CreatePivot()

	pt# = 0	
	Repeat	
		TurnEntity pivot, EntityPitch(imesh), EntityYaw(imesh), EntityRoll(imesh), 1
		imesh = GetParent(imesh)
		If imesh = 0 Then Exit
	Forever

	pt# = EntityPitch(pivot, 0)		
	FreeEntity pivot
	Return pt#

End Function

;-----------------------------------------------------------------------------------------------------
;											iEntityYaw()
;-----------------------------------------------------------------------------------------------------
;get entity's yaw
Function iEntityYaw#(mesh)

	imesh 	= mesh
	pivot	= CreatePivot()

	Repeat	
		TurnEntity pivot, EntityPitch(imesh), EntityYaw(imesh), EntityRoll(imesh), 1
		imesh = GetParent(imesh)
		If imesh = 0 Then Exit
	Forever

	yw# = EntityYaw(pivot, 0)
	FreeEntity pivot
	Return yw#

End Function

;-----------------------------------------------------------------------------------------------------
;											iEntityRoll()
;-----------------------------------------------------------------------------------------------------
;get entity's roll
Function iEntityRoll#(mesh)

	imesh 	= mesh
	pivot	= CreatePivot()

	Repeat	
		TurnEntity pivot, EntityPitch(imesh), EntityYaw(imesh), EntityRoll(imesh), 1
		imesh = GetParent(imesh)
		If imesh = 0 Then Exit
	Forever

	rl# = EntityRoll(pivot, 0)
	FreeEntity pivot
	Return rl#

End Function


;-----------------------------------------------------------------------------------------------------
;											FindChildren()
;-----------------------------------------------------------------------------------------------------
;store all children to iObj instances
Function FindChildren(mesh)

	i.iObj = New iObj
	i\m = mesh
	
	If CountChildren(mesh) < 1 Then Return
	
	For ij = 1 To CountChildren(mesh)
		g = GetChild(mesh, ij)
		FindChildren(g)
	Next
	
End Function