view SceneGraph/BlenderScript/export_xml.py @ 658:30a72124c7fd

export_xml3 for Blender 2.5 ( not yet worked )
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Fri, 27 Nov 2009 18:22:20 +0900
parents fffbfbfc9e34
children 22d7263cec2d
line wrap: on
line source

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


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

import math
#import subprocess
import os
import Blender
import struct
import base64
from Blender import NMesh, Scene, Object, Material, Texture, Window
from Blender import sys as bsys, Mathutils, Draw, BGL
from Blender.sys import *

global images, imageCount
images = {}
imageCount = 0

def info(object, spacing=10, collapse=1):
	"""Print methods and doc strings.

	Takes module, class, list, dictionary, or string."""
	methodList = [e for e in dir(object) if callable(getattr(object, e))]
	processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
#	print "\n".join(["%s %s" %
#					 (method.ljust(spacing),
#					  processFunc(str(getattr(object, method).__doc__)))
#					 for method in methodList])


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




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

# Image Get ?
# New name based on old with a different extension
def newFName(ext):
	return Blender.Get('filename')[: -len(Blender.Get('filename').split('.', -1)[-1]) ] + ext


#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=\"%d\">\n" %(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.getType() == "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%f %f %f\n" %(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.getMatrix()

		for mindex in range(len(flist)):
			fl = flist[mindex]
			if fl != []:
				parent_name = obj.getParent()
				if parent_name:
					parent_name = "%s" %parent_name
					###change
					#str += "\t<surface name=\"%s\" size=\"%d\" prim=\"Triangle\" parent=%s>\n" %(obj.name, len(fl)*3, parent_name[8:-1])
					file.write("\t<surface name=\"%s\" size=\"%d\" prim=\"Triangle\" parent=%s>\n" %(obj.name, len(fl)*3, parent_name[8:-1]) )
				else:
					###change
					#str += "\t<surface name=\"%s\" size=\"%d\" prim=\"Triangle\" parent=\"NULL\">\n" %(obj.name, len(fl)*3)
					file.write("\t<surface name=\"%s\" size=\"%d\" prim=\"Triangle\" parent=\"NULL\">\n" %(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%f %f %f\n" %(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%f %f %f\n" %(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%f %f %f\n" %(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%f %f %f\n" %(tri_first[1][0], tri_first[1][1], tri_first[1][2]) )
					file.write("\t\t\t%f %f %f\n" %(tri_second[1][0], tri_second[1][1], tri_second[1][2]) )
					file.write("\t\t\t%f %f %f\n" %(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%f %f %f\n" % (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%f %f\n" %(tri_first[2][0], tri_first[2][1]) )
						file.write("\t\t\t%f %f\n" %(tri_second[2][0], tri_second[2][1]) )
						file.write("\t\t\t%f %f\n" %(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
				if texture:
					file.write(loadTexture(texture))	
					
				else:
					file.write("\t\t<image name=\"%s\">\n" %("sample_white.png") )

					file.write("\t\t\tiVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAAAAADhZOFXAAAAEElEQVQImWP8zwABTAwUMQBJQQEP\n");
					file.write("\t\t\tlYH+agAAAABJRU5ErkJggg==\n");

					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.v)):
			vert = face.v[vi]
			if face.smooth:
				normal = vert.no
			else:
				normal = face.no
			if len(face.uv) == len(face.v):
				uv = face.uv[vi]
			else:
				uv = []
			iis[vi] = addVertex(vert.index, vert.co, normal, uv)
		addFace(face.materialIndex, iis[0], iis[1], iis[2])
		if len(face.v)==4:
			addFace(face.materialIndex, iis[2], iis[3], iis[0])

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

	#return str


######################################################
# EXPORT
######################################################
def save_xml(filename, unindexedname, anim):
	print("XML EXPORT\n")
	time1 = Blender.sys.time()
	print("Saving to '" + filename + "'...\n")
	file = open(filename, 'w')

	count_h = 0
	n = 0
	filename_h = filename[:-4] + ".h"  #header file for cpp
	file_h = open(filename_h, 'w')

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

	#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.getType() == "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 ######
	meshlist = []
	file.write("<OBJECT-3D>\n")
	for obj in object_list:
		if obj.getType() == "Mesh":
			objectname = obj.getName()
			mesh = Blender.NMesh.GetRawFromObject(objectname)
			meshname = mesh.name
			meshlight = 0
			if len(mesh.materials) > 0:
				mat0 = mesh.materials[0]
				if mat0.emit > 0:
					meshlight = 1
			if meshlight:
				print "processing Object \"%s\" as Meshlight (Mesh \"%s\")..." %(objectname, meshname)
			else:
				print "processing Object \"%s\" (Mesh \"%s\")..." %(objectname, meshname)
			try:
				meshlist.index(meshname)
			except ValueError:
				###change
				#file.write(exportMesh(mesh,obj))
				exportMesh(mesh,obj,file)
				meshlist.append(meshname)
				if anim == 1:
					#file.write("\t\t<anim>\n")
					###change
					#file.write(export_anime(obj))
					export_anime(obj,file)
					#file.write("\t\t</anim>\n")
				file.write("\t</surface>\n")
				file_h.write("#define %s scene_graph" %(obj.name))
				while n != count_h:
					file_h.write("->next")
					n = n + 1
				file_h.write("\n")
				count_h = count_h + 1
				n = 0


	##### XML FOOTER ######
	file.write("</OBJECT-3D>")
	file.close()
	file_h.close()
	print("Finished.\n")
				
	time2 = Blender.sys.time()
	print("Processing time: %f\n" %(time2-time1))
	Draw.Exit()


### SAVE ANIMATION ###
def save_anim(filename):
	global MatSaved
	
	MatSaved = 0
	unindexedname = filename
	save_xml(filename, unindexedname, 1)


#### SAVE STILL (hackish...) ####
def save_still(filename):
	global MatSaved
	
	MatSaved = 0
	unindexedname = filename
	save_xml(filename, unindexedname, 0)

######################################################
# Settings GUI
######################################################

# Assign event numbers to buttons
evtNoEvt	= 0
evtExport	= 1
evtExportAnim	= 2

# Set initial values of buttons

##	<size>800 600</size>

sceneSizeX = Scene.GetCurrent().getRenderingContext().imageSizeX()
sceneSizeY = Scene.GetCurrent().getRenderingContext().imageSizeY()

SizeX = Draw.Create(sceneSizeX)
SizeY = Draw.Create(sceneSizeY)
TexExponent = Draw.Create(2.3)

##	<metropolis>1</metropolis>
MLT = Draw.Create(1)

##	<large_mutation_prob>0.1</large_mutation_prob>
LMP = Draw.Create(0.1)

##	<max_change>0.02</max_change>
MaxChange = Draw.Create(0.02)

##	<russian_roulette_live_prob>0.7</russian_roulette_live_prob>
RRLP = Draw.Create(0.7)

##	<max_depth>100</max_depth>
MaxDepth = Draw.Create(100)

##  <bidirectional>false</bidirectional>
Bidirectional = Draw.Create(0)

##	<strata_width>14</strata_width>
StrataWidth = Draw.Create(14)

##	<logging>0</logging>
Logging = Draw.Create(0)

##  <save_untonemapped_exr>false</save_untonemapped_exr>
SaveUTMExr = Draw.Create(0)

##  <save_tonemapped_exr>false</save_tonemapped_exr>
SaveTMExr = Draw.Create(0)

##	<lens_radius>0.0</lens_radius>
LensRadius = Draw.Create(0.0)

##	<focus_distance>2.0</focus_distance>
FocusDistance = Draw.Create(2.0)

##  <turbidity>2.0</turbidity>
Turbidity = Draw.Create(2.0)

GroundPlane = Draw.Create(1)

## Separate materials
MatFile = Draw.Create(1)

# text color fix
textcol = [0, 0, 0]


def gui():
    global evtNoEvt, evtExport, evtExportAnim
    global SizeX, SizeY, TexExponent, MLT, LMP, MaxChange, RRLP, MaxDepth, Bidirectional, StrataWidth, Logging, SaveUTMExr, SaveTMExr, LensRadius, FocusDistance,Turbidity, GroundPlane, MatFile
    global textcol

    Draw.Button("Export", evtExport, 10, 25, 100, 18, "Open file dialog and export")
    Draw.Button("Export Animation", evtExportAnim, 130, 25, 150, 18, "Open filedialog and export animation (careful: takes a lot of diskspace!!!)")
    BGL.glColor3f(textcol[0], textcol[1], textcol[2]) ; BGL.glRasterPos2i(10,10) ; Draw.Text("Press Q or ESC to quit.", "tiny")

    BGL.glRasterPos2i(10,60) ; Draw.Text("xml exporter for libps3")

    
def event(evt, val):  # function that handles keyboard and mouse events
    if evt == Draw.ESCKEY or evt == Draw.QKEY:
	stop = Draw.PupMenu("OK?%t|Cancel export %x1")
	if stop == 1:
	    Draw.Exit()
	    return
    
def buttonEvt(evt):  # function that handles button events
    if evt == evtExport:
	Blender.Window.FileSelector(save_still, "Export", newFName('xml'))
    if evt == evtExportAnim:
	Blender.Window.FileSelector(save_anim, "Export Animation", newFName('xml'))
    #if there was an event, redraw the window   
    if evt:
	Draw.Redraw()


def loadTexture(texture):
	global images, imageCount
	name = texture.getName()
	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.getFilename()
	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%s" %b64		
	input.close()
	os.remove('output.txt')
	out += "\t\t</image>\n"
	return out

Draw.Register(gui, event, buttonEvt)