#!BPY # """ # Name: 'Parrot Mesh Exporter' # Blender: 242a # Group: 'Export' # """ # *************************************************************************** # # 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 # # *************************************************************************** # # Author: Stefan Gaffga # Visit http://www.3dcoding.de for more stuff # # *************************************************************************** import os.path import Blender import Blender.Scene import Blender.Object import Blender.NMesh import Blender.Mesh from Blender.Window import FileSelector from Blender import * from Blender.Mathutils import * from Blender.BGL import * from Blender.Draw import * from Blender.Mesh import * # IDs for the events that the buttons can fire --------------------------------------- EVENT_EXIT = 90 EVENT_EXPORTIEREN = 91 EVENT_SUCHEN = 92 # The settings of this export skript ------------------------------------------------- toggleBlendDir = 1 dateiname = "mesh.xml" status = "" error = 0 # ------------------------------------------------------------------------------------ # # Creates a mat4 XML-Tag that contains the given matrix. The matrix is transposed # because Blender projects vectors by calculating "vector * matrix", which is the # opposite of what I do. # # ------------------------------------------------------------------------------------ def packMatrix4(mat): txt = "\n" + \ "" + str(mat[0][0])+"" + \ "" + str(mat[1][0])+"" + \ "" + str(mat[2][0])+"" + \ "" + str(mat[3][0])+"\n" + \ "" + str(mat[0][1])+"" + \ "" + str(mat[1][1])+"" + \ "" + str(mat[2][1])+"" + \ "" + str(mat[3][1])+"\n" + \ "" + str(mat[0][2])+"" + \ "" + str(mat[1][2])+"" + \ "" + str(mat[2][2])+"" + \ "" + str(mat[3][2])+"\n" + \ "" + str(mat[0][3])+"" + \ "" + str(mat[1][3])+"" + \ "" + str(mat[2][3])+"" + \ "" + str(mat[3][3])+"\n" + \ "\n" return txt # ------------------------------------------------------------------------------------ # # Returns a XML-Tag for a given matrix with 3 rows and columns. As mentioned above, # this matrix is transposed, too. # # ------------------------------------------------------------------------------------ def packMatrix3(mat): txt = "\n" + \ "" + str(mat[0][0])+"" + \ "" + str(mat[1][0])+"" + \ "" + str(mat[2][0])+"\n" + \ "" + str(mat[0][1])+"" + \ "" + str(mat[1][1])+"" + \ "" + str(mat[2][1])+"\n" + \ "" + str(mat[0][2])+"" + \ "" + str(mat[1][2])+"" + \ "" + str(mat[2][2])+"\n" + \ "\n" return txt # ------------------------------------------------------------------------------------ # # Returns a XML-Tag that contains the given color components # # ------------------------------------------------------------------------------------ def packColor(r,g,b,a): txt = "" + str(r) + "" + str(g) + \ "" + str(b) + "" + str(a) + "\n"; return txt # ------------------------------------------------------------------------------------ # # Returns a XML-Tag that contains a vector of three elements # # ------------------------------------------------------------------------------------ def packVector3(x,y,z): txt = "" + str(x) + "" + str(y) + \ "" + str(z) + ""; return txt # ------------------------------------------------------------------------------------ # # Returns a XML-Tag that contains a vector of four elements # # ------------------------------------------------------------------------------------ def packVector4(x,y,z,t): txt = "" + str(x) + "" + str(y) + \ "" + str(z) + "" + str(t) + ""; return txt # ------------------------------------------------------------------------------------ # # Fills a tag that contains all the given texture image names # # ------------------------------------------------------------------------------------ def packTextures(txlist): # No textures - no tag if len(txlist)==0: return None out = "\n" for i in txlist: out = out + " \n" out = out + " " + i + "\n" out = out + " \n" out = out + "\n" return out # ------------------------------------------------------------------------------------ # # Creates a XML-Tag containing all the given vertices. The vertices are transformed # using the given matrix before being written to the output string. # # ------------------------------------------------------------------------------------ def packVertices(mat, verts): # No vertices - no tag if len(verts)==0: return None out = "\n" for ii in verts: # Make the vertex coordinates world-coordinates jj = Vector(ii[0],ii[1],ii[2],1) * mat # Export the vertex out += " " + packVector3(jj[0], jj[1], jj[2]) + "\n" out = out + "\n" return out # ------------------------------------------------------------------------------------ # # Creates a XML-Tag containing all the face data of the given faces # # ------------------------------------------------------------------------------------ def packFaces(mesh, faces, textures): global status, error out = "\n" for i in faces: # Arrays to collect the data of a single face indices = [] normals = [] u = [] v = [] # The indices of the points that make auf the face for j in i: indices.append(j.index) # The normals of all points for j in i.v: normals.append(j.no) # The u/v texture-coordinates for j in i.uv: u.append(j[0]) v.append(-j[1]) # Now lets create the tag for the face out = out + " \n" for j in range(0,len(indices)): out = out + " \n" index = indices[j] normal = normals[j] out += " " + str(index) + "\n" out += " " + packVector3(normal[0],normal[1],normal[2]) + "\n" out += " " + str(u[j]) + "" + str(v[j]) + "\n" out = out + " \n" if i.image: # This face is textured - create a tag that indicates which texture is used nr = textures.index(os.path.basename(i.image.filename)) out = out + " " + str(nr) + "\n" out = out + " \n" out = out + "\n" return out # ------------------------------------------------------------------------------------ # # Returns a XML-Tag containing all bone data and their hierarchy information # # ------------------------------------------------------------------------------------ def packBones(bones, mat): # No bones - no fun if len(bones)==0: return None # Find the root bone... for i in bones: if i["parent"]=="" : rootBone = i # ...and apply the skeleton matrix to it - so the bones are now in the same # orientation and location as the mesh itself rootBone["head"] = rootBone["head"] * mat rootBone["matrix"]= rootBone["matrix"] * mat.rotationPart() out = "\n" for i in bones: out = out + " \n" out = out + " " + i["name"] + "\n" if i["parent"]!="": out = out + " " + i["parent"]+ "\n" out = out + " " + packMatrix3(i["matrix"] ) + "\n" out = out + " " + str(i["length"]) + "\n" out = out + " " + packVector3(i["head"][0],i["head"][1],i["head"][2])+"\n" out = out + " \n" out = out + "\n" return out # ------------------------------------------------------------------------------------ # # Creates a XML-Tag containing all vertex groups that are needed to skin the mesh object # # ------------------------------------------------------------------------------------ def packVertexgroups(vgroups): # Only if vertex groups are present if len(vgroups)==0: return None out = "\n" for i in vgroups: out = out + " \n" out = out + " " + i["name"] + "\n" liste="" for j in i["list"]: liste = liste + " " + str(j) + "\n" out = out + " \n" + liste + "\n" out = out + " \n" out = out + "\n" return out # ------------------------------------------------------------------------------------ # # Creates an XML-Tag containing all curves of an action. # # ------------------------------------------------------------------------------------ def packIpos(name, ipolist, arma_mat): # Only if there are IPOs if len(ipolist)==0: return None out = " \n" out = out + " " + name + "\n" # Find the range the animation covers von_frame=999999; bis_frame=0; for i in ipolist: cs = i["kurven"] for c in cs: for j in range(len(c["punkte"])): # Just use the mid supporting points, not the ones left and right of it # because they go out of animation range if ((j+2)%3) == 0 : cc = c["punkte"][j] von_frame = min(von_frame, cc[0]) bis_frame = max(bis_frame, cc[0]) # Now export the animation out = out + " " + str(von_frame) + "" out = out + "" + str(bis_frame) + "\n" for i in ipolist: cs = i["kurven"] # Only export animations for bones that do have curves if len(cs) > 0 : out = out + " \n" out = out + " " + i["name"] + "\n" for c in cs: out = out + " \n" out = out + " " + c["name"] + "\n" if c["interpolation"] == "Linear": out = out + " linear\n" else: out = out + " bezier\n" pps="" for cc in c["punkte"]: pps = pps + " " +packVector3(cc[0],cc[1],cc[2]) + "\n" out = out + pps + " \n" out = out + " \n" out = out + " \n" return out # ------------------------------------------------------------------------------------ # # Creates a XML-Tag that conains all Animations # # ------------------------------------------------------------------------------------ def packActions(animlist, arma_mat): out = "\n" # Get all actions and export each actions = Blender.Armature.NLA.GetActions() for i in actions: t = packIpos(i, animlist[i], arma_mat) if t: out = out + t out = out + "\n" return out # ------------------------------------------------------------------------------------ # # Build and show the GUI, collect the data and export it to the given file # # ------------------------------------------------------------------------------------ def export(filename): global error, status status = "Exporting..." Redraw() error = 0 if toggleBlendDir==1 : filename = Blender.Get("filename") filename = Blender.sys.dirname(filename) + "/mesh.xml" file = open(filename, "w") scene = Blender.Scene.GetCurrent() elements=[] textures = [] bones=[] vgroups=[] animlist={} # # First, collect all the data we need to export. To achieve this # we loop through the scene and watch out for things we can use. # for m in scene.objects: # # The Armature contains the bones # if m.getType() == "Armature" : # The matrix that transforms the armature object itself - its the same as the # matrix we used to transform the vertices arma_mat = m.getMatrix("worldspace") boneList = m.getData().bones.items() for bb in boneList: b = bb[1] bone={} bone["name"]=b.name if b.hasParent(): parent = b.parent bone["parent"] = parent.name else: bone["parent"] = "" h = b.head["BONESPACE"] t = b.tail["BONESPACE"] bone["matrix"] = b.matrix["BONESPACE"] bone["length"] = b.length bone["head"] = h bones.append(bone) # # The Mesh data contain the object itself # elif m.getType() == "Mesh": mesh = m.getData() # get the vertex groups names = mesh.getVertGroupNames() for i in names: vg={} g = mesh.getVertsFromGroup(i) vg["name"]=i vg["list"]=g vgroups.append(vg) mat = m.getMatrix("worldspace") meshMatrix = mat # get the textures faces = mesh.faces for i in faces: if i.image: if os.path.basename(i.image.filename) not in textures: textures.append(os.path.basename(i.image.filename)) # # Read all IPOs and actions # actionlist = Blender.Armature.NLA.GetActions() for actionname in actionlist: action = actionlist[actionname] ipolist=[] ipos = action.getAllChannelIpos() for i in ipos: ipo = ipos[i] curve = ipo.getCurves() kurven=[] for c in curve: name = c.name kurve={} kurve["name"]=name kurve["interpolation"]=c.getInterpolation() kurve["punkte"]=[] points = c.getPoints() kurve["punkte"]=[] for p in points: pp = p.getTriple() for q in pp: kurve["punkte"].append(q) kurven.append(kurve) # "kurven" now contains all animation curves of the bone "i" myipo={} myipo["name"]=i myipo["kurven"]=kurven ipolist.append(myipo) animlist[actionname]=ipolist # ============================================================================ # # We now successfully collected all the data - lets write it to the file # # ============================================================================ file.write("\n") t = packTextures(textures) if t: file.write(t) t = packVertices(meshMatrix, mesh.verts) if t: file.write(t) t = packFaces(mesh, mesh.faces, textures) if t: file.write(t) if len(bones) > 0: t = packBones(bones, arma_mat) if t: file.write(t) t = packVertexgroups(vgroups) if t: file.write(t) t = packActions(animlist, arma_mat) if t: file.write(t) file.write("\n") file.close() if error==0: status="OK - export done." # ------------------------------------------------------------------------------------ # # Draw the GUI # # ------------------------------------------------------------------------------------ def draw(): global dateiname, toggleArmature, status, toggleBlendDir glClear(GL_COLOR_BUFFER_BIT) glColor3f(0,0,0) glRasterPos2d(10,150) Text(status) glRasterPos2d(10,80) Text("Parrot XML Object export") String("File: ", 200, 10, 40, 300, 20, dateiname, 100) #Toggle("Armature", 999, 10, 100, 200, 20, toggleArmature) Toggle("Export to same directory", 201, 10, 100, 200, 20, toggleBlendDir) Button("Export!", EVENT_EXPORTIEREN, 10,10,80,20) Button("...", EVENT_SUCHEN, 310, 40, 20, 20) Button("Exit", EVENT_EXIT, 100,10,80,20) # ------------------------------------------------------------------------------------ # # query events # # ------------------------------------------------------------------------------------ def event(event, value): if (event == ESCKEY): Exit() # ------------------------------------------------------------------------------------ # # callback for the FileSelector # # ------------------------------------------------------------------------------------ def setFile(fname): global dateiname dateiname=fname # ------------------------------------------------------------------------------------ # # check for button events # # ------------------------------------------------------------------------------------ def bevent(event): if ( event == EVENT_EXIT): Exit() elif (event == EVENT_EXPORTIEREN): export(dateiname) Redraw() elif (event == EVENT_SUCHEN): FileSelector(setFile, "Choose file", dateiname) # # Register and activate our GUI # Register(draw, event, bevent)