#!BPY

""" Registration info for Blender menus:
Name: 'DirectX (.x)...'
Blender: 234
Group: 'Export'
Submenu: 'Only mesh data...' mesh
Submenu: 'Animation(not armature yet)...' anim
Tip: 'Export to DirectX text file format'
"""

__author__ = "Arben (Ben) Omari"
__url__ = ("blender", "elysiun", "Author's site, http://www.omariben.too.it")
__version__ = "1.0"

__bpydoc__ = """\
This script exports Blender uv-textured meshes with animation frame keys to
DirectX 7's text file format.

Usage:

Run the script and check console for possible warning messages.

Supported:<br>
    UV-textured meshes with animation frame (location, rotation) keys.

Known issues:<br>
    Some DX format viewers don't support Material names with dots
('.') in them.

Notes:<br>
    Check author's site or the elYsiun forum for a new beta version of the
DX exporter.
"""


# $Id: DirectXExporter.py,v 1.6 2004/11/07 16:31:13 ianwill Exp $
#
# DirectX.py version 1.0
# Copyright (C) 2003  Arben OMARI -- omariarben@everyday.com  
#
# 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.

# This script export meshes created with Blender in DirectX file format
# it exports meshes,materials,normals,texturecoords and and animations

# Grab the latest version here :www.omariben.too.it

import Blender
from Blender import Types, Object, NMesh, Material
#import string
from math import *



	
#***********************************************
#***********************************************
#                EXPORTER
#***********************************************
#***********************************************

class xExport:
	def __init__(self, filename):
		self.file = open(filename, "w")

	#***********************************************
	#  Export animations
	#***********************************************
	def exportAnim(self):
		tex = []
		print "exporting ..."
		self.writeHeader()
		for name in Object.Get():
			obj = name.getData()
			if type(obj) == Types.NMeshType :
					
				self.writeFrames(name, obj)	
				self.writeMeshcoord(name, obj )
				self.writeMeshMaterialList(name, obj, tex)
				self.writeMeshNormals(name, obj)
				self.writeMeshTextureCoords(name, obj)
				self.file.write("}\n")
				self.file.write("}\n")
				self.writeAnimation(name, obj)
			
		self.writeEnd()

	#***********************************************
	#  Export geometry
	#***********************************************
	def exportTex(self):
		tex = []
		print "exporting ..."
		self.writeHeader()
		for name in Object.Get():
			obj = name.getData()
			if type(obj) == Types.NMeshType :		
				self.writeMeshcoord(name, obj )
				self.writeMeshMaterialList(name, obj, tex)
				self.writeMeshNormals(name, obj)
				self.writeMeshTextureCoords(name, obj)
				self.file.write("}\n")

		self.writeEnd()
    
	#***********************************************
	#HEADER
	#***********************************************  
	def writeHeader(self):
		self.file.write("xof 0302txt 0064\n")
		self.file.write("\n")
		self.file.write("Header{\n")
		self.file.write("1;0;1;\n")
		self.file.write("}\n")

	#***********************************************
	#CLOSE FILE
	#***********************************************
	def writeEnd(self):
		self.file.close()
		print "... finished"
	
		

	#***********************************************
	#EXPORT TEXTURES
	#***********************************************
	def writeTextures(self,name, tex):
		mesh = name.data
		for face in mesh.faces:
			if face.image and face.image.name not in tex:
				tex.append(face.image.name)
				

	#***********************************************
	#EXPORT MESH DATA
	#***********************************************
	def writeMeshcoord(self, name, obj ):
		
		self.file.write("Mesh Mesh_%s {\n" % (name.name))    
		numfaces=len(obj.faces)
		#POSITION
		loc = name.getMatrix()
		x = loc[3][0]
		y = loc[3][1]
		z = loc[3][2]
		#VERTICES NUMBER
		mesh = name.data
		numvert = 0
		for face in mesh.faces:
			numvert = numvert + len(face.v)
		self.file.write("%s;\n" % (numvert))
		#VERTICES COORDINATES
		counter = 0
		for face in mesh.faces:
			counter += 1
			if counter == numfaces:
				if len(face.v) == 4:
					self.file.write("%s; %s; %s;,\n" % ((face.v[0].co[0] + x), face.v[0].co[1] + y, face.v[0].co[2] + z))
					self.file.write("%s; %s; %s;,\n" % ((face.v[1].co[0] + x), face.v[1].co[1] + y, face.v[1].co[2] + z))		
					self.file.write("%s; %s; %s;,\n" % ((face.v[2].co[0] + x), face.v[2].co[1] + y, face.v[2].co[2] + z))
					self.file.write("%s; %s; %s;;\n" % ((face.v[3].co[0] + x), face.v[3].co[1] + y, face.v[3].co[2] + z))
				elif len(face.v) == 3 :
					self.file.write("%s; %s; %s;,\n" % ((face.v[0].co[0] + x), face.v[0].co[1] + y, face.v[0].co[2] + z))
					self.file.write("%s; %s; %s;,\n" % ((face.v[1].co[0] + x), face.v[1].co[1] + y, face.v[1].co[2] + z))		
					self.file.write("%s; %s; %s;;\n" % ((face.v[2].co[0] + x), face.v[2].co[1] + y, face.v[2].co[2] + z))
					
			else :
				if len(face.v) == 4:
					self.file.write("%s; %s; %s;,\n" % ((face.v[0].co[0] + x), face.v[0].co[1] + y, face.v[0].co[2] + z))
					self.file.write("%s; %s; %s;,\n" % ((face.v[1].co[0] + x), face.v[1].co[1] + y, face.v[1].co[2] + z))		
					self.file.write("%s; %s; %s;,\n" % ((face.v[2].co[0] + x), face.v[2].co[1] + y, face.v[2].co[2] + z))
					self.file.write("%s; %s; %s;,\n" % ((face.v[3].co[0] + x), face.v[3].co[1] + y, face.v[3].co[2] + z))
				elif len(face.v) == 3:
					self.file.write("%s; %s; %s;,\n" % ((face.v[0].co[0] + x), face.v[0].co[1] + y, face.v[0].co[2] + z))
					self.file.write("%s; %s; %s;,\n" % ((face.v[1].co[0] + x), face.v[1].co[1] + y, face.v[1].co[2] + z))		
					self.file.write("%s; %s; %s;,\n" % ((face.v[2].co[0] + x), face.v[2].co[1] + y, face.v[2].co[2] + z))
					


		#FACES NUMBER 
		
		self.file.write("%s;\n" % (numfaces))  
		#FACES INDEX
		numface=len(obj.faces)
		coun,counter = 0, 0
		for face in mesh.faces :
			coun += 1
			if coun == numface:
				if len(face.v) == 3:
					self.file.write("3; %s; %s; %s;;\n" % (counter, counter + 1, counter + 2))
					counter += 3
				elif len(face.v) == 4:
					self.file.write("4; %s; %s; %s; %s;;\n" % (counter, counter + 1, counter + 2, counter + 3))
					counter += 4
				elif len(face.v) == 2:
					print "WARNING:the mesh has faces with less then 3 vertices"
			else:
				
				if len(face.v) == 3:
					self.file.write("3; %s; %s; %s;,\n" % (counter, counter + 1, counter + 2))
					counter += 3
				elif len(face.v) == 4:
					self.file.write("4; %s; %s; %s; %s;,\n" % (counter, counter + 1, counter + 2, counter + 3))
					counter += 4
				elif len(face.v) == 2:
					print "WARNING:the mesh has faces with less then 3 vertices"
				
		
		
		
		
	#***********************************************
	#MESH MATERIAL LIST
	#***********************************************
	def writeMeshMaterialList(self, name, obj, tex):
		self.file.write("  MeshMaterialList {\n")
		#HOW MANY MATERIALS ARE USED
		count = 0
		for mat in Material.Get():
			count+=1
		self.file.write("    %s;\n" % (len(tex) + count))
		#HOW MANY FACES IT HAS
		numfaces=len(obj.faces)
		self.file.write("    %s;\n" % (numfaces))
		##MATERIALS INDEX FOR EVERY FACE
		counter = 0
		for face in obj.faces :
			counter += 1
			mater = face.materialIndex
			if counter == numfaces:
				if face.image and face.image.name in tex :
					self.file.write("    %s;;\n" % (tex.index(face.image.name) + count))
				else :
					self.file.write("    %s;;\n" % (mater))
			else :
				if face.image and face.image.name in tex :
					self.file.write("    %s,\n" % (tex.index(face.image.name) + count))
				else :
					self.file.write("    %s,\n" % (mater))
			
		##MATERIAL NAME
		for mat in Material.Get():
			self.file.write("  Material")
			for a in range(0,len(mat.name)):
				if mat.name[a] == ".":
					print "WARNING:the material " + mat.name + " contains '.' within.Many viewers may refuse to read the exported file"
			self.file.write(" %s "% (mat.name))
			self.file.write("{\n")
			self.file.write("    %s; %s; %s;" % (mat.R, mat.G, mat.B))
			self.file.write("%s;;\n" % (mat.alpha))
			self.file.write("    %s;\n" % (mat.spec))
			self.file.write("    %s; %s; %s;;\n" % (mat.specR, mat.specG, mat.specB))
			self.file.write("    0.0; 0.0; 0.0;;\n")
			self.file.write("  }\n") 
		
		for mat in tex:
			self.file.write("  Material Mat")
			self.file.write("%s "% (len(tex)))
			self.file.write("{\n")
			self.file.write("    1.0; 1.0; 1.0; 1.0;;\n")
			self.file.write("    1.0;\n")
			self.file.write("    1.0; 1.0; 1.0;;\n")
			self.file.write("    0.0; 0.0; 0.0;;\n")
			self.file.write("  TextureFilename {\n")
			self.file.write('    "%s" ;'% (face.image.name))
			self.file.write("  }\n")
			self.file.write("  }\n") 
		self.file.write("    }\n")
	#***********************************************
	#MESH NORMALS
	#***********************************************
	def writeMeshNormals(self,name,obj):
		self.file.write(" MeshNormals {\n")
		#VERTICES NUMBER
		numvert=len(obj.verts)
		self.file.write("%s;\n" % (numvert))
		#VERTICES NORMAL
		counter = 0
		for vert in obj.verts:
			counter += 1  
			if counter == numvert:
				self.file.write("%s; %s; %s;;\n" % (vert.no[0], vert.no[1], vert.no[2]))
			else :
				self.file.write("%s; %s; %s;,\n" % (vert.no[0], vert.no[1], vert.no[2]))
		#FACES NUMBER 
		numfaces=len(obj.faces)
		self.file.write("%s;\n" % (numfaces))  
		#FACES INDEX
		counter = 0
		for face in obj.faces :
			counter += 1
			if counter == numfaces:
				if len(face.v) == 3:
					self.file.write("3; %s; %s; %s;;\n" % (face[0].index, face[1].index, face[2].index))
				elif len(face.v) == 4:
					self.file.write("4; %s; %s; %s; %s;;\n" % (face[0].index, face[1].index, face[2].index, face[3].index))
			else:
				if len(face.v) == 3:
					self.file.write("3; %s; %s; %s;,\n" % (face[0].index, face[1].index, face[2].index))
				elif len(face.v) == 4 :
					self.file.write("4; %s; %s; %s; %s;,\n" % (face[0].index, face[1].index, face[2].index, face[3].index))
		self.file.write("}\n")
	#***********************************************
	#MESH TEXTURE COORDS
	#***********************************************
	def writeMeshTextureCoords(self, name, obj):
			if obj.hasFaceUV():
				self.file.write("MeshTextureCoords {\n")
				#VERTICES NUMBER
				mesh = name.data
				numvert = 0
				for face in mesh.faces:
					numvert = numvert + len(face.v)
				self.file.write("%s;\n" % (numvert))
				#UV COORDS
				counter = -1
				for face in mesh.faces:
					counter += 1
					if len(face.v) == 4:
						self.file.write("%s;%s;,\n" % (mesh.faces[counter].uv[0][0], -mesh.faces[counter].uv[0][1]))
						self.file.write("%s;%s;,\n" % (mesh.faces[counter].uv[1][0], -mesh.faces[counter].uv[1][1]))
						self.file.write("%s;%s;,\n" % (mesh.faces[counter].uv[2][0], -mesh.faces[counter].uv[2][1]))
						self.file.write("%s;%s;,\n" % (mesh.faces[counter].uv[3][0], -mesh.faces[counter].uv[3][1]))
					elif len(face.v) == 3:
						self.file.write("%s;%s;,\n" % (mesh.faces[counter].uv[0][0], -mesh.faces[counter].uv[0][1]))
						self.file.write("%s;%s;,\n" % (mesh.faces[counter].uv[1][0], -mesh.faces[counter].uv[1][1]))
						self.file.write("%s;%s;,\n" % (mesh.faces[counter].uv[2][0], -mesh.faces[counter].uv[2][1]))

				self.file.write("}\n")

	#***********************************************
	#FRAMES
	#***********************************************
	def writeFrames(self, name, obj):
		matx = name.getMatrix()
		self.file.write("Frame Fr_")  
		self.file.write("%s {\n" % (obj.name))
		self.file.write(" FrameTransformMatrix {\n")
		self.file.write(" %s,%s,%s,%s,\n" %
							(round(matx[0][0],6),round(matx[0][1],6),round(matx[0][2],6),round(matx[0][3],6)))
		self.file.write(" %s,%s,%s,%s,\n" %
							(round(matx[1][0],6),round(matx[1][1],6),round(matx[1][2],6),round(matx[1][3],6)))
		self.file.write(" %s,%s,%s,%s,\n" %
							(round(matx[2][0],6),round(matx[2][1],6),round(matx[2][2],6),round(matx[2][3],6)))
		self.file.write(" %s,%s,%s,%s;;\n" %
							(round(matx[3][0],6),round(matx[3][1],6),round(matx[3][2],6),round(matx[3][3],6)))
		self.file.write(" }\n")
	#***********************************************
	#WRITE ANIMATION KEYS
	#***********************************************
	def writeAnimation(self, name, obj):
		startFr = Blender.Get('staframe')
		endFr = Blender.Get('endframe')
		self.file.write("AnimationSet animset_")
		self.file.write("%s {\n" % (obj.name))
		self.file.write(" Animation anim_")
		self.file.write("%s { \n" % (obj.name))
		self.file.write("  {Fr_")
		self.file.write("%s }\n" % (obj.name))
		self.file.write("   AnimationKey { \n")
		self.file.write("   0;\n")
		self.file.write("   %s; \n" % (endFr))
		for fr in range(startFr,endFr + 1) :
			self.file.write("   %s; " % (fr))
			self.file.write("4; ")
			Blender.Set('curframe',fr)
			rot = name.rot
			rot_x = rot[0]
			rot_y = rot[1]
			rot_z = rot[2]
			quat = self.euler2quat(rot_x,rot_y,rot_z)
			self.file.write("%s, %s, %s,%s;;" % 
							(quat[0],quat[1],quat[2],quat[3]))
			if fr == endFr:
				self.file.write(";\n")
			else:
				self.file.write(",\n")
		self.file.write("   }\n")
		self.file.write("   AnimationKey { \n")
		self.file.write("   2;\n")
		self.file.write("   %s; \n" % (endFr))
		for fr in range(startFr,endFr + 1) :
			self.file.write("   %s; " % (fr))
			self.file.write("3; ")
			Blender.Set('curframe',fr)
			loc = name.loc
			self.file.write("%s, %s, %s;;" %
							(loc[0],loc[1],loc[2]))
			if fr == endFr:
				self.file.write(";\n")
			else:
				self.file.write(",\n")
		self.file.write("   }\n")
		self.file.write("   AnimationKey { \n")
		self.file.write("   1;\n")
		self.file.write("   %s; \n" % (endFr))
		for fr in range(startFr,endFr + 1) :
			self.file.write("   %s; " % (fr))
			self.file.write("3; ")
			Blender.Set('curframe',fr)
			size = name.size
			self.file.write("%s, %s, %s;;" %
							(size[0],size[1],size[2]))
			if fr == endFr:
				self.file.write(";\n")
			else:
				self.file.write(",\n")
		self.file.write("   }\n")
		self.file.write("  }\n")
		self.file.write(" }\n")

	def euler2quat(self,rot_x,rot_y,rot_z):
		c_x = cos(rot_x / 2)
		c_y = cos(rot_y / 2)
		c_z = cos(rot_z / 2)

		s_x = sin(rot_x / 2)
		s_y = sin(rot_y / 2)
		s_z = sin(rot_z / 2)

		cy_cz = c_y * c_z
		sy_sz = s_y * s_z
 
		quat_w = c_x * cy_cz - s_x * sy_sz
		quat_x = s_x * cy_cz + c_x * sy_sz
		quat_y = c_x * s_y * c_z - s_x * c_y * s_z
		quat_z = c_x * c_y * s_z + s_x * s_y * c_z

		return(quat_w,quat_x,quat_y,quat_z)

#***********************************************
# MAIN
#***********************************************

	
def my_callback(filename):
	if filename.find('.x', -2) <= 0: filename += '.x' # add '.x' if the user didn't
	xexport = xExport(filename)
	arg = __script__['arg']
	if arg == 'anim':
		xexport.exportAnim()
	else:
		xexport.exportTex()

fname = Blender.sys.makename(ext = ".x")
Blender.Window.FileSelector(my_callback, "Export DirectX",fname)
