view SceneGraph/BlenderScript/export_xml3.py @ 1249:fd9b7519a17b draft

add createFromCOLLADAfile
author Taiki TAIRA <e095767@ie.u-ryukyu.ac.jp>
date Fri, 11 Nov 2011 18:05:47 +0900
parents 1bb43068289b
children bf913abaed15
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 subprocess
import os
#import Blender
import struct
import base64
import bpy
#from Blender import NMesh, Scene, Object, Material, Texture, Window
#from Blender import sys as bsys, Mathutils, Draw, BGL
#from Blender.sys import *

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):
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):
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
		#str = ""
		file.write("")
		# matrix = obj.matrix
		# 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
					#str += "\t<surface name=\"{0:s}\" size=\"{0:d}\" prim=\"Triangle\" parent={0:s}>\n".format((obj.name, len(fl)*3, parent_name[8:-1])
					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
					#str += "\t<surface name=\"{0:s}\" size=\"{0:d}\" prim=\"Triangle\" parent=\"NULL\">\n".format((obj.name, len(fl)*3)
					file.write("\t<surface name=\"{0:s}\" size=\"{1:d}\" prim=\"Triangle\" parent=\"NULL\">\n".format(obj.name, len(fl)*3))
				###change
				#str += "\t\t<coordinate>\n"
				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 = mesh.faces[0].image
				texture = None
				if mesh.uv_texture_stencil:
					texture = mesh.uv_texture_stencil.data[0].image
				if texture:
					file.write(loadTexture(texture.name))	
				else:
					file.write("\t\t<image name=\"{0:s}\">\n".format("sample_white.png"))
					file.write("\t\t</image>\n")

		#return str

	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:
				uv_texture = mesh.uv_texture_stencil.data[face.index]
				uvs = [uv_texture.uv1, uv_texture.uv2, uv_texture.uv3, uv_texture.uv4]
			print(len(uvs))
			print(" ")
			print(len(face.vertices))
			print("\n")
			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

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:
#               for ob_derived, mat in getDerivedObjects(ob, False):

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

			data = ob_derived.to_mesh(sce, True, 'PREVIEW')
#			data = bpy.data.meshes[ob_derived.name]
			data.uv_texture_stencil = bpy.data.meshes[ob_derived.name].uv_texture_stencil
#                       data = getMeshFromObject(ob_derived, None, True, False, sce)
			if data:
				data.transform(mat)
#                               data.transform(mat, recalc_normals=False)
				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 data.faceUV:
					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
#                                                       mat_index = f.mat
							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
#                                               img = f.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:
#                                               if f.mat >= 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

	# Close the file:
	file.close()




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(expandpath(image_path), 'r')	
	output = open('output.txt', 'w')
	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)").path = 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