view SceneGraph/BlenderScript/export_xml3.py @ 1479:163220e54cc0 draft

remove hard code for TaskLog
author Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
date Tue, 24 Jul 2012 17:15:15 +0900
parents 759798f134e3
children
line wrap: on
line source

#!BPY
"""Registration info for Blender menus:
Name: 'Libps3 (.xml)'
Blender: 240
Group: 'Export'
Tooltip: 'Export to (.xml) for libps3'
"""

bl_info = {
    "name": "PS3 Cerium (.xml)",
    "author": "Shinji KONO",
    "version": (2, 0, 0),
    "blender": (2, 5, 8),
    "api": 37702,
    "location": "File > Import-Export",
    "description": "Export PS3 Cerium (.xml)",
    "warning": "",
   # "wiki_url": "",
   # "tracker_url": "",
    "category": "Import-Export"}



######################################################
# Importing modules
######################################################

import math
import os
import struct
import base64
import bpy

global anim
anim = 0


global images, imageCount
images = {}
imageCount = 0


__author__ = ["Shinji KONO"]
__url__ = ("www.ie.u-ryukyu.ac.jp/~kono/")
__version__ = "0.01a"
__bpydoc__ = """\

Cerium XML converter

"""


######################################################
# Data Structures
######################################################




######################################################
# Functions
######################################################


def create_derived_objects(ob):
	if ob.parent and ob.parent.dupli_type != 'NONE':
		return False, None

	if ob.dupli_type != 'NONE':
		ob.create_dupli_list()
		return True, [(dob.object, dob.matrix_basis) for dob in ob.dupli_list]
	else:
		return False, [(ob, ob.matrix_basis)] # Which do we use basis, local or world for matrix?

# also used by X3D exporter
def free_derived_objects(ob):
	ob.free_dupli_list()


#exporting an anime
###change
def export_anime(object_name,file):
	startF = Blender.Get('staframe')
	endF = Blender.Get('endframe')
	#str = ""
	file.write("")
	file.write("\t\t<anim frame=\"{0:d}\">\n".format(endF))
	for i in range (startF, endF+1):
		Blender.Set('curframe', i)
		Blender.Redraw()
#		time1 = Blender.sys.time()

		##### XML header ######
		#get all the objects in this scene
		activelayers = Window.ViewLayer()
		for i in range(len(activelayers)):
			activelayers[i] = 2**(activelayers[i]-1)
		object_list1 = Blender.Scene.GetCurrent().getChildren()
		object_list = []
		matnames= []
		for obj in object_list1:
			if obj.Layer in activelayers:
				object_list.append(obj)

				if obj.type == 'Mesh':
					materials_obj_list = []
					materials_obj_list = obj.getData().materials
					for mat in materials_obj_list:
						if mat.name not in matnames:
							matnames.append(mat.name)

		##### Process Meshes ######
		for obj in object_list:
			matrix = obj.getMatrix()
			if obj == object_name:
				file.write("\t\t\t{0:f} {1:f} {2:f}\n".format(matrix[3][0], matrix[3][1], matrix[3][2]))

	file.write("\t\t</anim>\n")
	#return str



# exporting a mesh
##change
def exportMesh(mesh, obj, file):

	vdata = []   # list of [ii0, ii1, ii2, ...] lists indexed by Blender-Vertex-index
	vlist = []
	flist = []
	tri_first = []
	tri_second = []
	tri_third = []

	def addVertex(bvindex, coord, normal, uv):
		index = -1
		if bvindex < len(vdata):
			for ivindex in vdata[bvindex]:
				v = vlist[ivindex]
				if (abs(v[0][0]-coord[0])<0.0001) and \
				(abs(v[0][1]-coord[1])<0.0001) and \
				(abs(v[0][2]-coord[2])<0.0001) and \
				(abs(v[1][0]-normal[0])<0.0001) and \
				(abs(v[1][1]-normal[1])<0.0001) and \
				(abs(v[1][2]-normal[2])<0.0001):
					if ((v[2]==[]) and (uv==[])) or \
					((abs(v[2][0]-uv[0])<0.0001) and \
					(abs(v[2][1]-uv[1])<0.0001)):
						index = ivindex
		if index < 0:
			index = len(vlist)
			vlist.append([coord, normal, uv])
			while bvindex >= len(vdata):
				vdata.append([])
			vdata[bvindex].append(index)
		return index

	def addFace(mindex, index0, index1, index2):
		while mindex >= len(flist):
			flist.append([])
		flist[mindex].append([index0, index1, index2])

	###change
	def getFaces():
		##change
		file.write("")
		# already calcurated?
		matrix = [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]

		for mindex in range(len(flist)):
			fl = flist[mindex]
			if fl != []:
				parent_name = obj.parent
				if parent_name:
					parent_name = "{0:s}".format(parent_name)
					###change
					file.write("\t<surface name=\"{0:s}\" size=\"{1:d}\" prim=\"Triangle\" parent={2:s}>\n".format(obj.name, len(fl)*3, parent_name[8:-1]))
				else:
					###change
					file.write("\t<surface name=\"{0:s}\" size=\"{1:d}\" prim=\"Triangle\" parent=\"NULL\">\n".format(obj.name, len(fl)*3))
				###change
				file.write("\t\t<coordinate>\n")
				for f in fl:
					tri_first = vlist[f[0]]
					tri_second = vlist[f[1]]
					tri_third = vlist[f[2]]

					file.write("\t\t\t{0:f} {1:f} {2:f}\n".format(tri_first[0][0] + matrix[3][0], tri_first[0][1] + matrix[3][1], tri_first[0][2] + matrix[3][2] ))
					file.write("\t\t\t{0:f} {1:f} {2:f}\n".format(tri_second[0][0] + matrix[3][0], tri_second[0][1] + matrix[3][1], tri_second[0][2] + matrix[3][2] ))
					file.write("\t\t\t{0:f} {1:f} {2:f}\n".format(tri_third[0][0] + matrix[3][0], tri_third[0][1] + matrix[3][1], tri_third[0][2] + matrix[3][2]))
				file.write("\t\t</coordinate>\n")

				file.write("\t\t<normal>\n")
				for f in fl:
					tri_first = vlist[f[0]]
					tri_second = vlist[f[1]]
					tri_third = vlist[f[2]]

					file.write("\t\t\t{0:f} {1:f} {2:f}\n".format(tri_first[1][0], tri_first[1][1], tri_first[1][2]))
					file.write("\t\t\t{0:f} {1:f} {2:f}\n".format(tri_second[1][0], tri_second[1][1], tri_second[1][2]))
					file.write("\t\t\t{0:f} {1:f} {2:f}\n".format(tri_third[1][0], tri_third[1][1], tri_third[1][2]))
				file.write("\t\t</normal>\n" )

				file.write("\t\t<model>\n" )
				###parameter of translate
				file.write("\t\t\t{0:f} {1:f} {2:f}\n".format(matrix[3][0], matrix[3][1], matrix[3][2]))
				file.write("\t\t</model>\n")

				if tri_first[2] != []:
					file.write("\t\t<texture>\n")
					for f in fl:
						tri_first = vlist[f[0]]
						tri_second = vlist[f[1]]
						tri_third = vlist[f[2]]

						file.write("\t\t\t{0:f} {1:f}\n".format(tri_first[2][0], tri_first[2][1]))
						file.write("\t\t\t{0:f} {1:f}\n".format(tri_second[2][0], tri_second[2][1]))
						file.write("\t\t\t{0:f} {0:f}\n".format(tri_third[2][0], tri_third[2][1]))
					file.write("\t\t</texture>\n")
				else:
					file.write("\t\t<texture/>\n")


				### get texture_image and change base64 data
				texture = None
				if mesh.uv_texture_stencil and  mesh.uv_texture_stencil.data.values() != []:
					texture = mesh.uv_texture_stencil.data[0].image
				if texture:
					file.write(loadTexture(texture))
				else:
					file.write("\t\t<image name=\"{0:s}\">\n".format("sample_white.png"))
					#sample_whited = 0 
					#if (sample_whited == 0):
					file.write("\t\t\tiVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAEElEQVQImWP8zwABTAwUMQBJQQEP\n")
					file.write("\t\t\tlYH+agAAAABJRU5ErkJggg==\n")
					#sample_whited=1
					file.write("\t\t</image>\n")

					



	vdata = []
	vlist = []
	flist = []
	for face in mesh.faces:
		iis = [-1, -1, -1, -1]
		for vi in range(len(face.vertices)):
#			vert = face.vertices[vi]
			vert = mesh.vertices[face.vertices[vi]]
			if face.use_smooth:
				normal = vert.normal
			else:
				normal = face.normal
			uvs = []
			if mesh.uv_texture_stencil and mesh.uv_texture_stencil.data.values() != []:
				uv_tex = mesh.uv_texture_stencil.data[face.index]
				uvs = [uv_tex.uv1, uv_tex.uv2, uv_tex.uv3, uv_tex.uv4]
			if len(uvs) == len(face.vertices):
				uv = uvs[vi]
			else:
				uv = []
			iis[vi] = addVertex(vert.index, vert.co, normal, uv)
			# MEMO: bpy.context.scene.objects['Cube'].data.uv_textures['UVTex'].data[0].uv1
		addFace(face.material_index, iis[0], iis[1], iis[2])
		if len(face.vertices) == 4:
			addFace(face.material_index, iis[2], iis[3], iis[0])

	#str = ""
	#str += getFaces()
	getFaces();

	#return str
	


#sample_whited = 0
# don't call this method#
#def make_material_chunk(material, image, file):
#	if image:
#		file.write(loadTexture(image))
#	else:
#		file.write("\t\t<image name=\"{0:s}\">\n".format("sample_white.png"))
#		global sample_whited
#		if (sample_whited == 0):
#		    file.write("\t\t\tiVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAEElEQVQImWP8zwABTAwUMQBJQQEP\n");
#		    file.write("\t\t\tlYH+agAAAABJRU5ErkJggg==\n");
#		    sample_whited=1
#
#		file.write("\t\t</image>\n")

######################################################
# EXPORT
######################################################


def save_xml(filename, context):
	'''Save the Blender scene to a Cerium xml file.'''
	# Time the export
	global MatSaved
	global anim
	MatSaved = 0
	
	if not filename.lower().endswith('.xml'):
		filename += '.xml' 
	print("Saving to '" + filename + "'...\n")
	file = open(filename, 'w')
    
	# XXX
#       if not BPyMessages.Warning_SaveOver(filename):
#               return
	
	# XXX
#	time1 = time.clock()
#       time1= Blender.sys.time()
#       Blender.Window.WaitCursor(1)

	##### XML header ######
	file.write("<?xml version=\"1.0\"?>\n")
	file.write("<OBJECT-3D>\n")

	sce = context.scene
  
	# Get all the supported objects selected in this scene:
	# ob_sel= list(sce.objects.context)
	# mesh_objects = [ (ob, me) for ob in ob_sel   for me in (BPyMesh.getMeshFromObject(ob, None, True, False, sce),) if me ]
	# empty_objects = [ ob for ob in ob_sel if ob.type == 'Empty' ]

	# Make a list of all materials used in the selected meshes (use a dictionary,
	# each material is added once):
	materialDict = {}
	mesh_objects = []
	for ob in [ob for ob in context.scene.objects if ob.is_visible(bpy.context.scene)]:
#       for ob in sce.objects.context:

		# get derived objects
		free, derived = create_derived_objects(ob)

		if derived == None: continue

		for ob_derived, mat in derived:
			if ob.type not in ('MESH', 'CURVE', 'SURFACE', 'TEXT', 'META'):
				continue

			data = ob_derived.data

			if data:
				data.transform(mat)
				mesh_objects.append((ob_derived, data))
				mat_ls = data.materials
				mat_ls_len = len(mat_ls)

				# get material/image tuples.
				if len(data.uv_textures):
					if not mat_ls:
						mat = mat_name = None

					for f, uf in zip(data.faces, data.uv_texture_stencil.data):
						if mat_ls:
							mat_index = f.material_index
							if mat_index >= mat_ls_len:
								mat_index = f.mat = 0
							mat = mat_ls[mat_index]
							if mat: mat_name = mat.name
							else:   mat_name = None
						# else there alredy set to none

						img = uf.image
						if img: img_name = img.name
						else:   img_name = None

						materialDict.setdefault((mat_name, img_name), (mat, img) )


				else:
					for mat in mat_ls:
						if mat: # material may be None so check its not.
							materialDict.setdefault((mat.name, None), (mat, None) )

					# Why 0 Why!
					for f in data.faces:
						if f.material_index >= mat_ls_len:
							f.material_index = 0
							# f.mat = 0

		if free:
			free_derived_objects(ob)

	# Make material chunks for all materials used in the meshes:
	# for mat_and_image in materialDict.values():
	# 	print("make material chunk {0:s}\n".format(mat_and_image[1]))
	# 	make_material_chunk(mat_and_image[0], mat_and_image[1], file)

	# Give all objects a unique ID and build a dictionary from object name to object id:
	"""
	name_to_id = {}
	for ob, data in mesh_objects:
		name_to_id[ob.name]= len(name_to_id)
	#for ob in empty_objects:
	#       name_to_id[ob.name]= len(name_to_id)
	"""

	# Create object chunks for all meshes:
	for ob, blender_mesh in mesh_objects:
		print("export mesh {0:s}\n".format(ob.name))
		exportMesh(blender_mesh,ob,file)
		if (anim):
		    export_anime(obj,file)
		file.write("\t</surface>\n")
#               if not blender_mesh.users:
#		bpy.data.remove_mesh(blender_mesh)
#		bpy.data.meshes.remove(blender_mesh)
#               blender_mesh.verts = None

	file.write("</OBJECT-3D>\n")
	# Close the file:
	file.close()
# reinitialize
	global images
	images = {}





def loadTexture(texture):
	global images, imageCount
	name = texture.name
	if name in images:
		return "\t\t<image name=\"" + name + "\"/>\n"	
	out = "\t\t<image name=\"" + name + "\">\n"
	imageCount += 1
	images[name] = imageCount
	image_path = texture.filepath
	input = open(bpy.path.abspath(image_path), 'rb')
	output = open('output.txt', 'wb')
	base64.encode(input,output)
	input.close()
	output.close()
	input = open('output.txt', 'r')
	for b64 in input.readlines():
		out += "\t\t\t{0:s}".format(b64)
	input.close()
	os.remove('output.txt')
	out += "\t\t</image>\n"
	return out

from bpy.props import *
class ExportPS3(bpy.types.Operator):
	'''Export to Cerium XML file format.'''
	bl_idname = "export.ps3cerium"
	bl_label = 'Export PS3 Cerium'
	filepath = StringProperty(subtype='FILE_PATH')

	# List of operator properties, the attributes will be assigned
	# to the class instance from the operator settings before calling.

	def execute(self, context):
		save_xml(bpy.path.ensure_ext(self.filepath, ".xml"), context)
		return {'FINISHED'}
	def invoke(self, context, event):
		wm = context.window_manager
		wm.fileselect_add(self)
		return {'RUNNING_MODAL'}


# Add to a menu

def menu_func(self, context):
    default_path = bpy.data.filepath.replace(".blend", ".xml")
    self.layout.operator(ExportPS3.bl_idname, text="PS3 Cerium (.xml)").filepath = default_path 

    
def register():
    bpy.utils.register_module(__name__)

    bpy.types.INFO_MT_file_export.append(menu_func)


def unregister():
    bpy.utils.unregister_module(__name__)

    bpy.types.INFO_MT_file_export.remove(menu_func)


if __name__ == "__main__":
    register()

# end