#!BPY

"""
Name: 'Point Cache 2 (.pc2)...'
Blender: 248
Group: 'Export'
Tooltip: 'Export animated object to Point Cache 2 format'
"""

__author__ = "Matt Ebb"
__url__ = ['mke3.net', 'blenderartists.org']
__version__ = "1.0"

__bpydoc__ = """\
This script exports to The Point Cache 2 file format.

Usage:

Choosing "Point Cache 2 (.pc2)" in the File->Export menu will export the active object to
an animated point sequence.

The Point Cache format just contains vertex positions, so to bring your animated mesh into 
another application, such as 3DS Max, you will also need to export the mesh itself in another 
format such as OBJ.

For use in Max, import the OBJ into Max with the standard File->Import, then add a Point Cache modifier,
click 'Load', and open the point cache file.

All objects that can be represented as a mesh (mesh, curve, metaball, surface, text)
will be exported as mesh data.
"""


# --------------------------------------------------------------------------
# PC2 Export v1.0 by Matt Ebb
# Thanks to Rangi Sutton for PC2 Python code snippets
# and Campbell Barton who's OBJ exporter was used as reference for much
# of this script
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------

import Blender, struct
from Blender import *
from Blender.Scene import Render
import BPyMesh
import BPyObject
import BPyMessages

def export_pc2(filename, ob, scn, \
EXPORT_WORLDSPACE, EXPORT_ROTX90, EXPORT_STARTFRAME, \
EXPORT_ENDFRAME, EXPORT_SAMPLERATE):

	temp_mesh_name = '~tmp-mesh'
	# Get the container mesh to copy the mesh's vertex positions to
	containerMesh = meshName = tempMesh = None
	for meshName in Blender.NMesh.GetNames():
		if meshName.startswith(temp_mesh_name):
			tempMesh = Mesh.Get(meshName)
			if not tempMesh.users:
				containerMesh = tempMesh
	if not containerMesh:
		containerMesh = Mesh.New(temp_mesh_name)
	
	if EXPORT_ROTX90:
		mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
		
	del meshName
	del tempMesh
	
	me= BPyMesh.getMeshFromObject(ob, containerMesh, True, False, scn)

	numPoints = len(me.verts)
	startFrame = float(EXPORT_STARTFRAME)
	numSamples = float(EXPORT_ENDFRAME - EXPORT_STARTFRAME)
	sampleRate = float(EXPORT_SAMPLERATE)
	
	# .pc2 files have a header defined as such:

	# char    cacheSignature[12];   // Will be 'POINTCACHE2' followed by a trailing null character.
	# int     fileVersion;          // Currently 1
	# int     numPoints;            // Number of points per sample
	# float   startFrame;           // Corresponds to the UI value of the same name.
	# float   sampleRate;           // Corresponds to the UI value of the same name.
	# int     numSamples;           // Defines how many samples are stored in the fi

	# Create the header
	headerFormat='<12ciiffi'
	headerStr = struct.pack(headerFormat, 'P','O','I','N','T','C','A','C','H','E','2','\0', 1, numPoints, startFrame, sampleRate, numSamples)

	file = open(filename, "w")
	file.write(headerStr)

	for frame in range(startFrame, startFrame+numSamples, sampleRate):
	
		Blender.Set('curframe', frame)
		me= BPyMesh.getMeshFromObject(ob, containerMesh, True, False, scn)
		
		if EXPORT_WORLDSPACE:
			me.transform(ob.matrixWorld)
		
		if EXPORT_ROTX90:
			me.transform(mat_xrot90)
	
		for v in me.verts:
			thisVertex = struct.pack('<fff', float(v.co[0]), float(v.co[1]), float(v.co[2]))
			file.write(thisVertex)
		
			
	file.flush()
	file.close()

def write_ui(filename):
	
	if not filename.lower().endswith('.pc2'):
		filename += '.pc2'
	
	if not BPyMessages.Warning_SaveOver(filename):
		return
	
	scn = Scene.GetCurrent()
	ren = scn.getRenderingContext()
	ob = scn.objects.active
	
	if not ob: ob = scn.objects.context[0]
	if not ob: return
	
	EXPORT_WORLDSPACE = Draw.Create(0)
	EXPORT_ROTX90 = Draw.Create(0)
	EXPORT_STARTFRAME = Draw.Create(ren.sFrame)
	EXPORT_ENDFRAME = Draw.Create(ren.eFrame)
	EXPORT_SAMPLERATE = Draw.Create(1)
	
	# Get USER Options
	pup_block = [\
	('World Space', EXPORT_WORLDSPACE, 'Use this if you have moving object (centers), rather than just a deforming object.'),\
	('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders Z axis up is translated into Y axis up'),\
	('Start: ', EXPORT_STARTFRAME, -300000, 300000, 'Start frame of animation to export'),\
	('End: ', EXPORT_ENDFRAME, -300000, 300000, 'End frame of animation to export'),\
	('Sample Rate: ', EXPORT_SAMPLERATE, 1, 10000, 'How frequently to sample (or skip) the frames. Only integers are supported'),\
	]
	
	if not Draw.PupBlock('Export...', pup_block):
		return
		
	Window.EditMode(0)
	Window.WaitCursor(1)
	
	EXPORT_WORLDSPACE = EXPORT_WORLDSPACE.val
	EXPORT_ROTX90 = EXPORT_ROTX90.val
	EXPORT_STARTFRAME = EXPORT_STARTFRAME.val
	EXPORT_ENDFRAME = EXPORT_ENDFRAME.val
	EXPORT_SAMPLERATE = EXPORT_SAMPLERATE.val
	
	export_pc2(filename, ob, scn, EXPORT_WORLDSPACE, EXPORT_ROTX90, EXPORT_STARTFRAME, EXPORT_ENDFRAME, EXPORT_SAMPLERATE)

	Window.WaitCursor(0)
	
if __name__ == '__main__':
	Window.FileSelector(write_ui, 'Export Point Cache 2', sys.makename(ext='.pc2'))
