diff --git a/release/scripts/mirror_bone_weights.py b/release/scripts/mirror_bone_weights.py new file mode 100644 index 00000000000..615a7ffb5ab --- /dev/null +++ b/release/scripts/mirror_bone_weights.py @@ -0,0 +1,218 @@ +#!BPY +""" +Name: 'Mirror Bone Weights' +Blender: 239 +Group: 'Mesh' +Submenu: '-x to +x' nxtopx +Submenu: '+x to -x' pxtonx +Tooltip: 'Mirror vertex group influences of a model' +""" + +__author__ = "Thomas Oppl" +__version__ = "5.12" +__url__ = "elysiun" +__email__ = "scripts" +__bpydoc__ = """\ +Description: + +This script copies vertex group influences from one half of a model to the +other half of it. + +Usage: + +- Select the model
+- Start the script (Object -> Scripts -> Mirror Bone Weights)
+- Use the "-x to +x" or the "+x to -x" submenu depending on which side should + be the source and which the destination.
+ +Notes: + +- The model has to be in the center of the world along the x-axis.
+- The model has to be symmetrical along the x-axis.
+- You have to use the ".R" and ".L" suffix naming scheme for your vertex groups.
+ +""" + +#------------------------------------------------------------ +# Mirror Bone Weights - (c) 2005 thomas oppl - toppl@fh-sbg.ac.at +#------------------------------------------------------------ +# ***** 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 ***** +#------------------------------------------------------------ + + + + + +from Blender import NMesh, Object, Draw, sys, Types, Window + + + + + +threshold = 0.001 + +################################################################################ +def mirror(mode): + print + print "mirror bone weights: %s" % (mode) + print "threshold: %.6f" % (threshold) + + objects = Object.GetSelected() + if not objects: + Draw.PupMenu("Error: no object selected!") + print "no object selected!" + return + mesh = objects[0].getData() + if type(mesh) != Types.NMeshType: + Draw.PupMenu("Error: object must be a mesh!") + print "object is no mesh!" + return + + # nmesh.getvertexinfluences function seems to be broken so i create a dictionary instead + Window.WaitCursor(1) + time = sys.time() + in_editmode = Window.EditMode() + if in_editmode: Window.EditMode(0) + vertexinfluences = {} + for i in range(len(mesh.verts)): + vertexinfluences[i] = [] + for groupname in mesh.getVertGroupNames(): + for vertex in mesh.getVertsFromGroup(groupname, 1): + index, weight = vertex[0], vertex[1] + vertexinfluences[index].append((groupname, weight)) + influencestime = sys.time() - time + print "influence dictionary generated in %.6f seconds!" % (influencestime) + + # generate binary tree to speed up looking for opposite vertex + time = sys.time() + tree = c_tree(mesh.verts) + treetime = sys.time() - time + print "binary tree generated in %.6f seconds!" % (treetime) + + # mirror vertex group influences + time = sys.time() + if mode == "-x to +x": + verticeshalf = [v for v in mesh.verts if v.co[0] < 0] + else: + verticeshalf = [v for v in mesh.verts if v.co[0] > 0] + i = 0 + for vertex in verticeshalf: + oppositeposition = (-vertex.co[0], vertex.co[1], vertex.co[2]) + foundvertex = [] + tree.findvertex(oppositeposition, foundvertex, threshold) + if foundvertex: + oppositevertex = foundvertex[0] + # remove all influences from opposite vertex + for influence in vertexinfluences[oppositevertex.index]: + mesh.removeVertsFromGroup(influence[0], [oppositevertex.index]) + # copy influences to opposite vertex + for influence in vertexinfluences[vertex.index]: + name = influence[0] + if name[-2:] == ".R": + name = name[:-2] + ".L" + elif name[-2:] == ".L": + name = name[:-2] + ".R" + if name not in mesh.getVertGroupNames(): # create opposite group if it doesn't exist + mesh.addVertGroup(name) + mesh.assignVertsToGroup(name, [oppositevertex.index], influence[1], "add") + i += 1 + mirrortime = sys.time() - time + print "%d vertices mirrored in %.6f seconds!" % (i, mirrortime) + + # done! + print "done in %.6f seconds total!" % (influencestime + treetime + mirrortime) + if in_editmode: Window.EditMode(1) + Window.WaitCursor(0) + + + + +################################################################################ +NODE_VERTEX_LIMIT = 50 + +class c_boundingbox: + def __init__(self, vertices): + self.min_x = self.max_x = vertices[0].co[0] + self.min_y = self.max_y = vertices[0].co[1] + self.min_z = self.max_z = vertices[0].co[2] + for vertex in vertices: + self.min_x = min(self.min_x, vertex.co[0]) + self.min_y = min(self.min_y, vertex.co[1]) + self.min_z = min(self.min_z, vertex.co[2]) + self.max_x = max(self.max_x, vertex.co[0]) + self.max_y = max(self.max_y, vertex.co[1]) + self.max_z = max(self.max_z, vertex.co[2]) + self.dim_x = self.max_x - self.min_x + self.dim_y = self.max_y - self.min_y + self.dim_z = self.max_z - self.min_z + self.splitaxis = [self.dim_x, self.dim_y, self.dim_z].index(max(self.dim_x, self.dim_y, self.dim_z)) + self.center_x = self.max_x - (self.dim_x / 2.0) + self.center_y = self.max_y - (self.dim_y / 2.0) + self.center_z = self.max_z - (self.dim_z / 2.0) + self.splitcenter = [self.center_x, self.center_y, self.center_z][self.splitaxis] + def __str__(self): + return "min: %.3f %.3f %.3f max: %.3f %.3f %.3f dim: %.3f %.3f %.3f" %\ + (self.min_x, self.min_y, self.min_z, + self.max_x, self.max_y, self.max_z, + self.dim_x, self.dim_y, self.dim_z) + def isinside(self, position, threshold): + return (position[0] <= self.max_x + threshold and position[1] <= self.max_y + threshold and \ + position[2] <= self.max_z + threshold and position[0] >= self.min_x - threshold and \ + position[1] >= self.min_y - threshold and position[2] >= self.min_z - threshold) + +class c_tree: + def __init__(self, vertices, level = 0): + self.level = level + self.children = [] + self.vertices = [] + self.boundingbox = c_boundingbox(vertices) + splitaxis = self.boundingbox.splitaxis + splitcenter = self.boundingbox.splitcenter + if len(vertices) > NODE_VERTEX_LIMIT: + self.children.append(c_tree( + [v for v in vertices if v.co[splitaxis] > splitcenter], self.level + 1)) + self.children.append(c_tree( + [v for v in vertices if v.co[splitaxis] <= splitcenter], self.level + 1)) + else: # leaf node + self.vertices = vertices + def __str__(self): + s = " " * self.level + "-node %d\n" % (len(self.vertices)) + for child in self.children: + s += str(child) + return s + def findvertex(self, position, foundvertex, threshold): + if self.boundingbox.isinside(position, threshold): + if self.children: + for child in self.children: + child.findvertex(position, foundvertex, threshold) + else: # node found + for vertex in self.vertices: + v, p, t = vertex.co, position, threshold + if abs(v[0] - p[0]) < t and abs(v[1] - p[1]) < t and abs(v[2] - p[2]) < t: # vertex found + foundvertex.append(vertex) + + + + + +################################################################################ +if __script__["arg"] == "nxtopx": + mirror("-x to +x") +if __script__["arg"] == "pxtonx": + mirror("+x to -x") diff --git a/release/scripts/xsi_export.py b/release/scripts/xsi_export.py new file mode 100644 index 00000000000..0f31024c799 --- /dev/null +++ b/release/scripts/xsi_export.py @@ -0,0 +1,1245 @@ +#!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", "elysiun"] +__email__ = ["scripts"] +__version__ = "2005/11/01" + + +__bpydoc__ = """\ +This script exports to the XSI format. + +Usage: + +Run this script from "File->Export" menu. + +Note:
+- 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.Get() + +# --------------------------------------------------------------------------- +# 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.getType(): + return mats + + # now drop down to the mesh level + #mesh = Blender.NMesh.GetRaw(obj.data.name) + mesh = obj.data + + if mesh.materials: + for mat in mesh.materials: + mats.append(mat) + + # return the materials list + return mats + + + +# --------------------------------------------------------------------------- +# apply_transform converts a vertex to co-ords +# --------------------------------------------------------------------------- +def apply_transform(vert, matrix): + vc = Mathutils.CopyVec(vert) + vc.resize4D() + return Mathutils.VecMultMat(vc, matrix) + + + +# --------------------------------------------------------------------------- +# 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 + ambient = WORLD[0].getAmb() + + 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.getName() + + # 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.getName() + 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.getName() + + # 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.getName() + 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.getName() + + # 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.getName() + + + # 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") + + print img.getSize () + + # image width, and height + ix, iy = img.getSize() + 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 + iru = img.getXRep() + FD.write(" %d,\n" % iru ) + irv = img.getYRep() + 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.getName() ) + " {\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.getName()) + "\",\n" ) + FD.write(" \"NODE\",\n" ) + FD.write(" }\n\n" ) + + + +def meshHasUV ( mesh ): + if mesh.hasFaceUV(): + return TRUE +# materials = mesh.materials +# if len(materials) > 0: + + return FALSE + +# --------------------------------------------------------------------------- +# 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 i in range(len(f)): + UVI.append(j) + UVC.append(f.uv[i]) + 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 i in range(len(f)): + VCI.append(j) + VCC.append(f.col[i]) + 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 = Blender.NMesh.GetRaw(obj.data.name) + + # 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.getName() ) + "-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.getName()) + " {\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.getName()) + " {\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.getName() ) + "\",\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.getName()) + " {\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.getType(): + return + + # check if the mesh is valid + if validMesh(obj) <> 0: + print "INVALID MESH " + obj.getName () + return + + + print "Exporting model " + obj.getName () + + # start model + FD.write(" SI_Model MDL-" + removeSpacesFromName(obj.getName()) + " {\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 = Blender.NMesh.GetRaw(obj.data.name) + 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.getType(): + return + + print "Exporting light " + obj.getName () + + aLampType = 1 + + lmpName=Lamp.Get(obj.data.getName()) + 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.getName()) + " {\n") + + # do type + FD.write(" %d,\n" % aLampType) + + lampName=Lamp.Get(obj.data.getName()) + 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.getType(): + return + + print "Exporting camera " + obj.getName () + + + + # start model + FD.write(" SI_Camera " + removeSpacesFromName(obj.getName()) + " {\n") + + + cameraName=Camera.Get(obj.data.getName()) + + # 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(): + ambient = WORLD[0].getAmb() + if ambient == [0.0,0.0,0.0]: + ambient = [0.5,0.5,0.5] + + 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 = 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)