blender/release/scripts/xsi_export.py

1228 lines
30 KiB
Python

#!BPY
"""
Name: 'SoftImage XSI (.xsi)...'
Blender: 236
Group: 'Export'
Tooltip: 'Export to a SoftImage XSI file'
"""
__author__ = ("Elira")
__url__ = ["Author's site, http://www.creative-realms.net/~elira/blender.html",
"SoftImage's site, www.softimage.com", "blenderartists.org"]
__email__ = ["scripts"]
__version__ = "2005/11/01"
__bpydoc__ = """\
This script exports to the XSI format.
Usage:
Run this script from "File->Export" menu.
Note:<br>
- Updates by Mal Duffin, to assist with XSI to Shockwave 3D conversion.
"""
# $Id: xsi_export.py,v 1.4.6 2005/11/01
#
#------------------------------------------------------------------------
# XSI exporter for blender 2.36 or above
#
# ***** 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 *****
#
#
# ---------------------------------------------------------------------------
# XSI Export V 1.4.1 by Elira (at) creative-realms (dot) net
#
# Updates by Mal Duffin, to assist with XSI to Shockwave 3D conversion
# ---------------------------------------------------------------------------
# 0.0.0 - This header and having blender ID the file.
# 0.1.0 - Output the statis xsi header elements
# 0.2.0 - create a full shell output (no content just structure)
# 0.3.0 - output used materials from the full materials list
# 0.4.0 - output the object model minor data
# 0.5.0 - output the object shape data, storing a uv table
# 0.6.0 - output the triangle lists (uv references stored uv table)
# 0.7.0 - convert output to genuine file writes.
# 1.0.0 - Admit this script exists and wait for flames
# 1.1.0 - Correctly export mesh shapes
# 1.2.0 - Mesh positioning corrected, added back normals
# 1.3.0 - conditionally output uv co-ordinates
# 1.4.0 - export vertex paint colours.
# ---------------------------------------------------------------------------
# 1.4.1 - added basic normal export code,
# to get XSI to Shockwave 3D converter working ( Mal Duffin )
# 1.4.2 - invalid mesh checking
# better normal exporting
# general code clean up
# 1.4.3 - basic light exporting
# fix for ambient light being ignored by Shockwave 3D converter
# 1.4.4 - basic camera exporting
# 1.4.5 - exports normals correctly
# 1.4.6 - exports multiple materials per object
# ---------------------------------------------------------------------------
# TO DO
# - Support texturing
# - for both methods of texturing ( render method, and Game Engine method )
# ---------------------------------------------------------------------------
# add required modules
import Blender
from Blender import sys as bsys
from Blender import Mathutils
from Blender import Lamp
from Blender import Camera
import math
# ---------------------------------------------------------------------------
# globals to make things a lot lot easier
OBJ = [] # the object list
MAT = [] # the materials list
UVC = [] # uv vert co-ords
UVI = [] # uv vert index
VCC = [] # vert colour co-ords
VCI = [] # vert colour index
FD = [] # file handle
NORMALS = [] # normal list
mats = []
EXPORT_DIR = ''
WORLD = Blender.World.GetCurrent()
# ---------------------------------------------------------------------------
# get_path returns the path portion o/wf the supplied filename.
# ---------------------------------------------------------------------------
def get_path(file):
l=len(file)
r=0
for i in range(l, 0, -1):
if r == 0:
if file[i-1] == "/" or file[i-1] == "\\":
r = i
return file[:r]
# ---------------------------------------------------------------------------
# r2d - radians to degrees
# ---------------------------------------------------------------------------
def r2d(r):
return round(r*180.0/math.pi,4)
# ---------------------------------------------------------------------------
# d2r - degrees to radians
# ---------------------------------------------------------------------------
def d2r(d):
return (d*math.pi)/180.0
# ---------------------------------------------------------------------------
# get_filename returns the filename
# ---------------------------------------------------------------------------
def get_filename(file):
l=len(file)
r=0
for i in range(l, 0, -1):
if r == 0:
if file[i-1] == "/" or file[i-1] == "\\":
r = i
return file[r:]
# ---------------------------------------------------------------------------
# find materials returns all materials on an object.
# ---------------------------------------------------------------------------
def get_materials(obj):
# any materials attached to the object itself
mats = obj.getMaterials(0)
if 'Mesh' != obj.type:
return mats
# now drop down to the mesh level
#mesh = Blender.NMesh.GetRaw(obj.data.name)
mats.extend(obj.getData(mesh=1).materials)
# return the materials list
# Is this correct!!?? - None materials raise an error otherwise
# but it might screw up the indicies.. TODO... check the exported files.
return [m for m in mats if m]
# ---------------------------------------------------------------------------
# do_header writes out the header data
# ---------------------------------------------------------------------------
def do_header():
global FD
# this says which xsi version
FD.write("xsi 0300txt 0032\n\n")
# static fileinfo block
FD.write("SI_FileInfo {\n")
FD.write(" \"Blender Scene\",\n")
FD.write(" \"Blender User\",\n")
FD.write(" \"Now\",\n")
FD.write(" \"xsi_export Blender Scene Exporter\",\n")
FD.write("}\n\n")
# static scene block
FD.write("SI_Scene no_name {\n")
FD.write(" \"FRAMES\",\n")
FD.write(" 0.000000,\n")
FD.write(" 100.000000,\n")
FD.write(" 30.000000,\n")
FD.write("}\n\n")
# static co-ordinate system block
FD.write("SI_CoordinateSystem coord {\n")
FD.write(" 1,\n")
FD.write(" 0,\n")
FD.write(" 1,\n")
FD.write(" 0,\n")
FD.write(" 5,\n")
FD.write(" 2,\n")
FD.write("}\n\n")
# static angle block
FD.write("SI_Angle {\n")
FD.write(" 0,\n")
FD.write("}\n\n")
# static ambience block
if WORLD: ambient = WORLD.getAmb()
else: ambient = 0,0,0
FD.write("SI_Ambience {\n")
FD.write(" %f,\n" % ambient[0])
FD.write(" %f,\n" % ambient[1])
FD.write(" %f,\n" % ambient[2])
FD.write("}\n\n")
# ---------------------------------------------------------------------------
# do_materiallibrary writes out the materials subsection.
# ---------------------------------------------------------------------------
def do_materiallibrary():
global OBJ, MAT, FD
# set some flags first
mnum = 0
# run through every material, how many used?
for mat in MAT:
nmat = mat.name
# first, is this material on any of the objects.
f = 0
for obj in OBJ:
ml = get_materials(obj)
for mli in ml:
nmli = mli.name
if nmli == nmat:
f = 1
mnum += 1
break
if f == 1:
break
bCreateDefault = 0
# if none then exit
if not mnum:
bCreateDefault = 1
# return
# get to work create the materiallibrary wrapper and fill.
FD.write("SI_MaterialLibrary {\n")
FD.write(" " + str(mnum) + ",\n")
# run through every material, write the used ones
for mat in MAT:
nmat = mat.name
# find out if on any object, if so we write.
f = 0
for obj in OBJ:
ml = get_materials(obj)
for mli in ml:
nmli = mli.name
if nmli == nmat:
do_material(mat)
f = 1
break
if f == 1:
break
if bCreateDefault == 1:
do_material ( 0 )
# clean up
FD.write("}\n\n")
def removeSpacesFromName(name):
name = name.replace ( " ", "_" )
return name
# ---------------------------------------------------------------------------
# do_material writes out this material.
# ---------------------------------------------------------------------------
def do_material(mat):
global FD
if mat == 0:
name = "__default"
cr = 1.0
cg = 1.0
cb = 1.0
ca = 1.0
sp = 0.0
sr = 0.0
sg = 0.0
sb = 0.0
em = 0.0
am = 1.0
sm = 0
else:
# get the name first
name = mat.name
# face colour r, g, b, a
# power (spec decay) fl
# spec colour r, g, b
# emmisive colourm r, g, b
# shading model int constant, lambert, phong, blinn, shadow, vertex
# ambient colour r, g, b
# get and print the base material block
cr, cg, cb = mat.getRGBCol()
ca = mat.getAlpha()
sp = 0.0
sr, sg, sb = mat.getSpecCol()
em = mat.getEmit()
am = mat.getAmb()
# how do we render this material? start with constant (0)
sm = 0
fl = mat.getMode()
if fl & Blender.Material.Modes['VCOL_PAINT']:
sm = 5
FD.write(" SI_Material " + removeSpacesFromName(name) + " {\n")
FD.write(" %f,\n" % cr)
FD.write(" %f,\n" % cg)
FD.write(" %f,\n" % cb)
FD.write(" %f,\n" % ca)
FD.write(" %f,\n" % sp)
FD.write(" %f,\n" % sr)
FD.write(" %f,\n" % sg)
FD.write(" %f,\n" % sb)
FD.write(" %f,\n" % em)
FD.write(" %f,\n" % em)
FD.write(" %f,\n" % em)
FD.write(" %d,\n" % sm)
#FD.write(" %f,\n" % am)
#FD.write(" %f,\n" % am)
#FD.write(" %f,\n" % am)
FD.write(" %f,\n" % cr)
FD.write(" %f,\n" % cg)
FD.write(" %f,\n" % cb)
if mat != 0:
# if this material has a texture, then add here
mtex = mat.getTextures()
for mt in mtex:
if mt:
do_texture(mt)
FD.write(" }\n")
# ---------------------------------------------------------------------------
# do_texture writes out this texture if usable.
# ---------------------------------------------------------------------------
def do_texture(mtex):
global FD
# get our texture
tex = mtex.tex
tn = tex.name
# what type of texture, we are limitd
if tex.type != Blender.Texture.Types.IMAGE:
return
FD.write(" SI_Texture2D " + tn + " {\n")
img = tex.getImage()
iname = get_filename(img.getFilename())
FD.write(" \"" + iname + "\",\n")
# mapping type ? uv map wrapped is 4, how to detect?
# start with a simple xy mapping ie 0
FD.write(" 4,\n")
if img.has_data: ix, iy = img.getSize()
else: ix, iy = 512,512
# image width, and height
FD.write(" %d,\n" % ix)
FD.write(" %d,\n" % iy)
# u crop min/max, v crop min/max
mincu, mincv, maxcu, maxcv = tex.crop
FD.write(" %d,\n" % ( mincu * ix ) )
FD.write(" %d,\n" % ( maxcu * ix - 1 ) )
FD.write(" %d,\n" % ( mincv * iy ) )
FD.write(" %d,\n" % ( maxcv * iy - 1) )
# uv swap
uvs =0
if (tex.flags & Blender.Texture.Flags.FLIPBLEND):
uvs = 1
FD.write(" %d,\n" % uvs )
# u/v repeat
if img.has_data: iru = img.getXRep()
else: iru = 1
FD.write(" %d,\n" % iru )
if img.has_data: irv = img.getYRep()
else: irv = 1
FD.write(" %d,\n" % irv )
# u/v alt - 0, 0
FD.write(" 0,\n" )
FD.write(" 0,\n" )
# u/v scale - 1,1
FD.write(" 1.000000,\n" )
FD.write(" 1.000000,\n" )
# u/v offset - 0,0
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
# proj mat 4x4 1 0 0 0, 0 1 0 0, 0 0 1 0, 0 0 0 1 is default
FD.write(" 1.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 1.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 1.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 0.000000,\n" )
FD.write(" 1.000000,\n" )
# blending type - 3
FD.write(" 3,\n" )
# blending - 1
FD.write(" 1.000000,\n" )
# ambient - 0
FD.write(" 0.000000,\n" )
# diffuse - 1
FD.write(" 1.000000,\n" )
# speculara - 0
FD.write(" 0.000000,\n" )
# transparent - 0
FD.write(" 0.000000,\n" )
# reflective - 0
FD.write(" 0.000000,\n" )
# roughness - 0
FD.write(" 0.000000,\n" )
# close off this texture
FD.write(" }\n")
# ---------------------------------------------------------------------------
# do_model_transform dumps out the transform data
# ---------------------------------------------------------------------------
def do_model_transform(obj):
global FD
# now output
FD.write(" SI_Transform SRT-" + removeSpacesFromName( obj.name ) + " {\n" )
# write out the object size? (scaling)
FD.write(" %f,\n" % obj.SizeX )
FD.write(" %f,\n" % obj.SizeY )
FD.write(" %f,\n" % obj.SizeZ )
# write out the object rotation
FD.write(" %f,\n" % r2d(obj.RotX) )
FD.write(" %f,\n" % r2d(obj.RotY) )
FD.write(" %f,\n" % r2d(obj.RotZ) )
# this is the position of the object's axis
FD.write(" %f,\n" % obj.LocX )
FD.write(" %f,\n" % obj.LocY )
FD.write(" %f,\n" % obj.LocZ )
FD.write(" }\n\n")
# ---------------------------------------------------------------------------
# do_model_visibility marks if the model is visible or not???
# ---------------------------------------------------------------------------
def do_model_visibility(obj):
global FD
# for now this is a static block
FD.write(" SI_Visibility {\n" )
FD.write(" 1,\n" )
FD.write(" }\n\n" )
# ---------------------------------------------------------------------------
# do_model_material sets the global material for the model
# ---------------------------------------------------------------------------
def do_model_material(obj):
global FD
# do we have one?
ml = get_materials(obj)
n = 0
for mli in ml:
if mli:
n+=1
if n == 1:
mat=mli
# if no materials just go back
if n == 0:
return
# for now we grab the first material on the list.
for mat in ml:
FD.write(" SI_GlobalMaterial {\n" )
FD.write(" \"" + removeSpacesFromName(mat.name) + "\",\n" )
FD.write(" \"NODE\",\n" )
FD.write(" }\n\n" )
# ---------------------------------------------------------------------------
# do_collect_uv, makes an easy to use list out of the uv data
# todo, remove duplicates and compress the list size, xsi supports this.
# ---------------------------------------------------------------------------
def do_collect_uv(mesh):
global UVC, UVI
# reset the uv details first.
UVI = []
UVC = []
#print "Textures..."
#mtex = mat.getTextures()
#for mt in mtex:
# print mt
# if no uv data then return
if not mesh.hasFaceUV():
return
# run through all the faces
j = 0
for f in mesh.faces:
for uv in f.uv:
UVI.append(j)
UVC.append(uv)
j+=1
UVI.append(-1)
# ---------------------------------------------------------------------------
# do_collect_colour, makes an easy to use list out of the colour data
# todo, remove duplicates and compress the list size, xsi supports this.
# ---------------------------------------------------------------------------
def do_collect_colour(mesh):
global VCC, VCI
# reset the uv details first.
VCC = []
VCI = []
# if no uv data then return
if not mesh.hasVertexColours():
return
# run through all the faces
j = 0
for f in mesh.faces:
for c in f.col:
VCI.append(j)
VCC.append(c)
j+=1
VCI.append(-1)
# ---------------------------------------------------------------------------
# do_mesh_shape outputs the shape data
# ---------------------------------------------------------------------------
def do_mesh_shape(obj):
global UVC, UVI, VCC, VCI, FD, NORMALS
# Grab the mesh itself
mesh = obj.data
# get the world matrix
matrix = obj.getMatrix('worldspace')
# we need to decide about vertex and uv details first.
do_collect_uv(mesh)
do_collect_colour(mesh)
# output the shell
elements=2
if len(UVC):
elements+=1
if len(VCC):
elements+=1
FD.write(" SI_Shape SHP-" + removeSpacesFromName ( obj.name ) + "-ORG {\n" )
FD.write(" %d,\n" % elements )
FD.write(" \"ORDERED\",\n\n" )
# vertices first
FD.write(" %d,\n" % len(mesh.verts) )
FD.write(" \"POSITION\",\n" )
for v in mesh.verts:
FD.write(" %f,%f,%f,\n" % (v.co[0], v.co[1], v.co[2]) )
FD.write("\n")
print " MESH NAME = " + mesh.name
NORMALS = []
for f in mesh.faces:
NORMALS.append ( f.no )
for v in mesh.verts:
aTemp = [v.no[0], v.no[1], v.no[2]]
NORMALS.append ( aTemp )
FD.write(" %d,\n" % len(NORMALS) )
FD.write(" \"NORMAL\",\n" )
for n in NORMALS:
FD.write(" %f,%f,%f,\n" % ( n[0], n[1], n[2] ) )
# if vertex colour data then process
if mesh.hasVertexColours():
# put out the co-ord header
FD.write(" %d,\n" % len(VCC) )
FD.write(" \"COLOR\",\n" )
# now output them
for vc in VCC:
FD.write(" %f,%f,%f,%f,\n" % (vc.r/255.0, vc.g/255.0, vc.b/255.0, vc.a/255.0) )
# if uv data then process
if mesh.hasFaceUV():
# put out the co-ord header
FD.write(" %d,\n" % len(UVC) )
FD.write(" \"TEX_COORD_UV\",\n" )
# now output them
for uv in UVC:
FD.write(" %f,%f\n" % (uv[0], uv[1]) )
# close off
FD.write(" }\n" )
# ---------------------------------------------------------------------------
# do_mesh_faces outputs the faces data
# ---------------------------------------------------------------------------
def do_mesh_faces(obj):
global FD, UVI, VCI, mats
# do we have a texture?
ml = get_materials(obj)
n = 0
for mli in ml:
if mli:
n+=1
if n == 1:
mat=mli
# Grab the mesh itself
# mesh = Blender.NMesh.GetRaw(obj.data.name)
# mesh = Blender.NMesh.GetRawFromObject(obj.name)
mesh = obj.data
tris = []
normalX = []
mats = []
for f in mesh.faces:
tris.extend ( triangulate_face(f) )
aVal = triangulate_normals(mesh,f)
for v in aVal:
normalX.append ( v )
triangles = len(tris)
if n == 0:
FD.write(" SI_TriangleList " + removeSpacesFromName(obj.name) + " {\n")
FD.write(" %d,\n" % triangles)
ostring=" \"NORMAL"
if len(VCI):
ostring += "|COLOR"
if len(UVC):
ostring += "|TEX_COORD_UV"
ostring += "\",\n"
FD.write(ostring)
FD.write(" \"\",\n\n")
for t in tris:
FD.write(" %d,%d,%d,\n" % (t[0], t[2], t[1]))
FD.write("\n")
for n in normalX:
FD.write(" %d,%d,%d,\n" % ( n[0], n[1], n[2] ) )
# finally close this triangle list off
FD.write(" }\n\n")
print "total materials"
print ml
for mIndex in range (0,len(ml)):
mat = ml[mIndex]
print "checking materials"
print mat
aTriCount = 0
for tIndex in range ( 0, len ( tris ) ):
aMat = mats[tIndex]
if aMat == mIndex:
aTriCount = aTriCount + 1
#
# output the shell
FD.write(" SI_TriangleList " + removeSpacesFromName(obj.name) + " {\n")
# FD.write(" %d,\n" % triangles)
FD.write(" %d,\n" % aTriCount)
ostring=" \"NORMAL"
if len(VCI):
ostring += "|COLOR"
if len(UVC):
ostring += "|TEX_COORD_UV"
ostring += "\",\n"
FD.write(ostring)
FD.write(" \"" + removeSpacesFromName ( mat.name ) + "\",\n\n")
# FD.write(" \"\",\n\n")
for tIndex in range ( 0, len ( tris ) ):
aMat = mats[tIndex]
if mIndex == aMat:
t = tris[tIndex]
FD.write(" %d,%d,%d,\n" % (t[0], t[2], t[1]))
FD.write("\n")
# for n in normalX:
for tIndex in range ( 0, len ( tris ) ):
aMat = mats[tIndex]
if mIndex == aMat:
n = normalX[tIndex]
FD.write(" %d,%d,%d,\n" % ( n[0], n[1], n[2] ) )
# if we have it, put out the colour vertex list
# ostring = " "
# for i in range(len(VCI)):
# if a -1 its end of line, write.
# if VCI[i] == -1:
# ostring = ostring + "\n"
# FD.write(ostring)
# ostring=" "
# else:
# ostring = ostring + "%d," % VCI[i]
# The final set is to work out the uv list, its one set per face
# ostring = " "
# for i in range(len(UVI)):
# # if a -1 its end of line, write.
# if UVI[i] == -1:
# ostring = ostring + "\n"
# FD.write(ostring)
# ostring=" "
# else:
# ostring = ostring + "%d," % UVI[i]
# finally close this triangle list off
FD.write(" }\n\n")
def getNormalInfo(mesh, faceInfo):
global NORMALS
aNL = []
for fi in faceInfo:
aN = []
aFace = mesh.faces[fi[0]]
print aFace
if (aFace.smooth):
aN.append ( NORMALS.index ( aFace.v.no[0] ) )
aN.append ( NORMALS.index ( aFace.v.no[1] ) )
aN.append ( NORMALS.index ( aFace.v.no[2] ) )
else:
aN.append ( NORMALS.index ( aFace.no ) )
aN.append ( NORMALS.index ( aFace.no ) )
aN.append ( NORMALS.index ( aFace.no ) )
# aN.append ( NORMALS.index ( mesh.faces[fi[0]].no ) )
# aN.append ( NORMALS.index ( mesh.faces[fi[0]].no ) )
# aN.append ( NORMALS.index ( mesh.faces[fi[0]].no ) )
aNL.append ( aN )
return aNL
# copy of code to triangulate mesh
##################################
def triangulate_face(f):
if len(f.v) <= 3:
#newFaces = [ [f.v[0].index, f.v[1].index, f.v[2].index] ]
newFaces = [ [f.v[0].index, f.v[2].index, f.v[1].index] ]
mats.append ( f.materialIndex )
else:
#newFaces = [ [f.v[0].index, f.v[1].index, f.v[2].index] ]
#newFaces.append ( [f.v[3].index, f.v[0].index, f.v[2].index] )
newFaces = [ [f.v[0].index, f.v[2].index, f.v[1].index] ]
newFaces.append ( [f.v[3].index, f.v[2].index, f.v[0].index] )
mats.append ( f.materialIndex )
mats.append ( f.materialIndex )
return newFaces
# copy of code to triangulate mesh
##################################
def triangulate_normals(mesh, f):
if len(f.v) <= 3:
if f.smooth:
n1 = get_normal_index ( mesh, [f.v[0].no[0], f.v[0].no[1], f.v[0].no[2]] )
n2 = get_normal_index ( mesh, [f.v[1].no[0], f.v[1].no[1], f.v[1].no[2]] )
n3 = get_normal_index ( mesh, [f.v[2].no[0], f.v[2].no[1], f.v[2].no[2]] )
newNormals = [[ n1, n2, n3 ]]
else:
n1 = get_normal_index ( mesh, [f.no[0], f.no[1], f.no[2]] )
newNormals = [[ n1, n1, n1 ]]
else:
if f.smooth:
n1 = get_normal_index ( mesh, [f.v[0].no[0], f.v[0].no[1], f.v[0].no[2]] )
n2 = get_normal_index ( mesh, [f.v[1].no[0], f.v[1].no[1], f.v[1].no[2]] )
n3 = get_normal_index ( mesh, [f.v[2].no[0], f.v[2].no[1], f.v[2].no[2]] )
n4 = get_normal_index ( mesh, [f.v[3].no[0], f.v[3].no[1], f.v[3].no[2]] )
newNormals = [ [ n1, n2, n3 ] ]
newNormals.append ( [ n4, n1, n3 ] )
# newNormals = [[ n1, n3, n2 ]]
# newNormals.append ( [ n4, n3, n1 ] )
else:
n1 = get_normal_index ( mesh, [f.no[0], f.no[1], f.no[2]] )
newNormals = [[ n1, n1, n1 ]]
newNormals.append ( [ n1, n1, n1 ] )
return newNormals
##################################
def get_normal_index(mesh,normal):
global NORMALS
indx=NORMALS.index(normal)
return indx
# ---------------------------------------------------------------------------
# do_model_mesh outputs the shape/triangelist wrapper block
# ---------------------------------------------------------------------------
def do_model_mesh(obj):
global FD
# output the shell
FD.write(" SI_Mesh MSH-" + removeSpacesFromName(obj.name) + " {\n")
# todo, add calc normals and calc uv here
# these can be used in both the following sections.
# next the shape
do_mesh_shape(obj)
# finally the trangle list
do_mesh_faces(obj)
# finally close this mesh off
FD.write(" }\n\n")
# ---------------------------------------------------------------------------
# do_model actually outputs a mesh model
# ---------------------------------------------------------------------------
def do_model(obj):
global FD
# we only want meshes for now.
if 'Mesh' != obj.type:
return
# check if the mesh is valid
if validMesh(obj) <> 0:
print "INVALID MESH " + obj.name
return
print "Exporting model " + obj.name
# start model
FD.write(" SI_Model MDL-" + removeSpacesFromName(obj.name) + " {\n")
# do transform
do_model_transform(obj)
# do visibility
do_model_visibility(obj)
# do global material
do_model_material(obj)
# do the mesh
do_model_mesh(obj)
# close this model
FD.write(" }\n")
#
# check for invalid mesh ( faces that have < 3 vertices )
#
def validMesh (obj):
mesh = obj.data
for f in mesh.faces:
if len(f.v) < 3:
print "MESH HAS FACES WITH < 3 VERTICES"
return 1
if len (mesh.faces) == 0:
print "MESH HAS NO FACES"
return 1
return 0
# ---------------------------------------------------------------------------
# do_models is the process which allows us to write out a bunch of models
# ---------------------------------------------------------------------------
def do_models():
global OBJ, MAT, FD
#create the full scene wrapper object
FD.write("SI_Model MDL-SceneRoot {\n")
FD.write(" SI_Transform SRT-SceneRoot {\n" )
FD.write(" 1.000000,\n")
FD.write(" 1.000000,\n")
FD.write(" 1.000000,\n")
FD.write(" -90.000000,\n")
FD.write(" 0.000000,\n")
FD.write(" 0.000000,\n")
FD.write(" 0.000000,\n")
FD.write(" 0.000000,\n")
FD.write(" 0.000000,\n")
FD.write(" }\n\n")
# now process the actual selected meshes themselves
for obj in OBJ:
do_model(obj)
for obj in OBJ:
do_light(obj)
for obj in OBJ:
do_camera(obj)
do_light_ambient ()
# finally close off the model list
FD.write("}\n")
# ---------------------------------------------------------------------------
# do_light actually outputs a light model
# ---------------------------------------------------------------------------
def do_light(obj):
global FD
# we only want lights for now.
if 'Lamp' != obj.type:
return
print "Exporting light " + obj.name
aLampType = 1
lmpName=Lamp.Get(obj.getData(name_only=1))
lmpType=lmpName.getType()
if lmpType == Lamp.Types.Lamp:
aLampType = 0
elif lmpType == Lamp.Types.Spot:
aLampType = 0
elif lmpType == Lamp.Types.Sun:
aLampType = 1
else:
aLampType = 0
# start model
FD.write(" SI_Light " + removeSpacesFromName(obj.name) + " {\n")
# do type
FD.write(" %d,\n" % aLampType)
lampName= obj.data
colour = lampName.col
# do color
FD.write(" %f,\n" % colour[0] )
FD.write(" %f,\n" % colour[1] )
FD.write(" %f,\n" % colour[2] )
# do position
FD.write(" %f,\n" % obj.LocX )
FD.write(" %f,\n" % obj.LocY )
FD.write(" %f,\n" % obj.LocZ )
# close this model
FD.write(" }\n")
# ---------------------------------------------------------------------------
# do_light actually outputs a light model
# ---------------------------------------------------------------------------
def do_camera(obj):
global FD
# we only want cameras for now.
if 'Camera' != obj.type:
return
print "Exporting camera " + obj.name
# start model
FD.write(" SI_Camera " + removeSpacesFromName(obj.name) + " {\n")
cameraName=obj.data
# colour = cameraName.col
# do position
FD.write(" %f,\n" % obj.LocX )
FD.write(" %f,\n" % obj.LocY )
FD.write(" %f,\n" % obj.LocZ )
# looking at
FD.write(" %f,\n" % 0.0 )
FD.write(" %f,\n" % 0.0 )
FD.write(" %f,\n" % 0.0 )
# roll
FD.write(" %f,\n" % 0.0 )
aLens = cameraName.getLens()
# field of view
FD.write(" %f,\n" % aLens )
# near plane
FD.write(" %f,\n" % 1.0 )
# far plane
FD.write(" %f,\n" % 10000000.0 )
# close this model
FD.write(" }\n")
# ---------------------------------------------------------------------------
# write out the ambient light ( for Shockwave 3D converter )
# ---------------------------------------------------------------------------
def do_light_ambient():
if WORLD: ambient = WORLD.getAmb()
else: ambient = 0,0,0
FD.write(" SI_Light ambient_sw3d {\n")
FD.write(" 9,\n")
FD.write(" %f,\n" % ambient[0])
FD.write(" %f,\n" % ambient[1])
FD.write(" %f,\n" % ambient[2])
FD.write(" 0.00000000,\n")
FD.write(" 0.00000000,\n")
FD.write(" 0.00000000,\n")
FD.write(" }\n")
# ---------------------------------------------------------------------------
# export_xsi is the wrapper function to process the loading of an xsi model.
# ---------------------------------------------------------------------------
def export_xsi(filename):
global OBJ, MAT, FD, EXPORT_DIR
# safety check
if filename.find('.xsi', -4) <= 0:
print "XSI not found"
filename += '.xsi'
export_dir = bsys.dirname(filename)
if export_dir != EXPORT_DIR:
EXPORT_DIR = export_dir
# open our output
FD = open(filename, 'w')
# get the selected objects, otherwise get them all
#OBJ = Blender.Object.GetSelected()
#if not OBJ:
OBJ = list(Blender.Scene.GetCurrent().objects) #Blender.Object.Get()
# we need some objects, if none specified stop
if not OBJ:
return
# if any exist, grab the materials
MAT = Blender.Material.Get()
# output the header data
do_header()
# output the materials used by the selected objects.
do_materiallibrary()
# we punch out the models, that is, the meshes themselves
do_models()
# finally close our file
FD.close()
# ---------------------------------------------------------------------------
# Lets trigger it off now
# Blender.Window.FileSelector(export_xsi, 'Export SoftImage XSI')
fname = bsys.makename(ext=".xsi")
if EXPORT_DIR <> '':
fname = bsys.join(EXPORT_DIR, bsys.basename(fname))
Blender.Window.FileSelector(export_xsi, "Export SoftImage XSI", fname)