################################################################################
# Exports a Houdini .clip animation channel file from xsi
# it will only export the t[x,y,z] channels but can be modified for more!
# Works with XSI 6.5 and Houding (for import) 8 and above
# to transfer geometry use an obj file mesh
# Author Jon Macey jmacey@bmth.ac.uk
# Version 1.0  Date : 20/1/08
# The user must select geometry before running the script it only works
# on animated meshes whith animation baked (using plot shapes)
# Usage ClipExport(NAME of File, Start Frame, End Frame)
# 
################################################################################


import sys
# get a reference to the application level
xsi = Application
# and the scene root
oRoot = Application.ActiveSceneRoot
# grab the XSI constansts to the namespace C (for constants!)
# we can now refer to XSI constants using C.xxx ie C.siConstructionModeAnimation
from win32com.client import constants as C


def ClipExport(FileName,StartFrame,EndFrame) :
	# get the currently selected model
	oObj = xsi.selection(0)
	#// grab the verts of the model
	oPoints = oObj.ActivePrimitive.GetGeometry2(StartFrame).Points		
	numPoints=len(oPoints)
	# lets make a progress bar so it looks like we are doing something
	progressbar = XSIUIToolkit.progressbar
	# we will update for every point logged so max for prog bar is this value
	progressbar.maximum = numPoints
	# increment in ones
	progressbar.step = 1
	# better worn people that this is a slow process
	progressbar.Caption = "Exporting Clip This may take some time!"
	# make the progress bar visible as we are starting
	progressbar.visible = 1

	# lets grab the data for the export
	# we are going to create a list for each channel
	XData=[]
	YData=[]
	ZData=[]
	""" get pointer to the apped function as it will make things quicker"""
	Xappend=XData.append
	Yappend=YData.append
	Zappend=ZData.append

	#  now a list for each vertex value per frame
	vx=[]
	vy=[]
	vz=[]
	""" grab a reference to the GetGeometry2 Function as this is much quicker than calling
			it each time in the script, in fact this has reduced execution time by about 70%
			"""
	Geom=oObj.ActivePrimitive.GetGeometry2
	# now loop per vertex / per frame and create an array for the data to be stored
	# in the clip format, this is marginally quicker than writing it to the disk each time
	# but either way works ok
	for v in range(0,numPoints) :
		for f in range(StartFrame,EndFrame) :
			# grab the geom points for the current frame
			oPoints = Geom(f,C.siConstructionModeAnimation).Points		
			# and get the pint value
			oPos = oPoints[v].position
			#store this in a list whith space seperations
			vx.append('%f ' %(oPos.X))
			vy.append('%f ' %(oPos.Y))
			vz.append('%f ' %(oPos.Z))
			#xsi.LogMessage(" vx %s" %(vx))
		# and now store it in the various lists
		Xappend(vx)
		Yappend(vy)
		Zappend(vz)
#			# now empty the temp list
		vx=[]
		vy=[]
		vz=[]
		# update progress
		progressbar.increment(1)
		# see if the user got bored and pressed cancel if so exit
 		if progressbar.CancelPressed == True :
 			return

	# now we can write out the data
	# det the progress bar to show the file being written
	progressbar.maximum = numPoints*3
	progressbar.step = 1
	progressbar.Caption = "Writing File"
	file=open(FileName,'w')
 
  # export the clip header file
	# {
	#  rate = 24 (frame rate hard coded but can be changed in houdini
	#  start =   (the start frame user specified)
	#  tracklength (how many track in the file (basically end-start))
	#  tracks = (how much data we are storing numPoints * tx ty tx (3))

 	file.write('{\n')
 	file.write('\t rate = 24 \n')
 	file.write('\t start = %d\n' %(StartFrame))
 	file.write('\t tracklength = %d\n' %(EndFrame-StartFrame))
 	file.write('\t tracks = %d\n' %(numPoints*3))
	
	# The track data looks like below 
	# { 
	#   tname = t[xyz]number e.g. tx1
	#   date = 0.5 0.3 0.3 ... which is the channgel data per frame
	# }
	# This is repeated for each of the channels in the file in this case t[xyz]
	# Note the \t tabs below are purely cosmetic to aid reading of output file ;-)
	
	# now the channel data for x
	for i in range(0,numPoints) :
				file.write('\t\t{\n')
 				file.write('\t\tname = tx%d\n' %(i))
 				file.write('\t\tdata = ')
				# this is quite sweet, we use join on the string
				# to join the tuple into 1 string (note the space separator in the
				# append above
				file.write(''.join(XData[i]))	 			
 				# now close the brace for the data
 				file.write('\n\t\t}\n')
 				progressbar.increment(1)
 				if progressbar.CancelPressed == True :
 					return

# now we repeate for the y values

	for i in range(0,numPoints) :
				file.write('\t\t{\n')
 				file.write('\t\tname = ty%d\n' %(i))
 				file.write('\t\tdata = ')
				# this is quite sweet, we use join on the string
				# to join the tuple into 1 string (note the space separator in the
				# append above
				file.write(''.join(YData[i]))	 			
 				# now close the brace for the data
 				file.write('\n\t\t}\n')
 				progressbar.increment(1)
 				if progressbar.CancelPressed == True :
 					return

# and for the Z

	for i in range(0,numPoints) :
				file.write('\t\t{\n')
 				file.write('\t\tname = tz%d\n' %(i))
 				file.write('\t\tdata = ')
				# this is quite sweet, we use join on the string
				# to join the tuple into 1 string (note the space separator in the
				# append above
				file.write(''.join(ZData[i]))	 			
 				# now close the brace for the data
 				file.write('\n\t\t}\n')
 				progressbar.increment(1)
 				if progressbar.CancelPressed == True :
 					return

 	# now close the brace and then the file
 	file.write('}\n')
 	file.close()


ClipExport("c:\\clothTest.clip",1,20)