Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!BPY
- #**************************************************************************************************
- # Supreme Commander Exporter for Blender3D - www.blender3d.org
- #
- # Written by dan - www.sup-com.net), Brent (www.scmods.net)
- #
- # further improvements by GeomanNL and Darius
- #
- # History
- #
- # 0.1.0 2006-07-02 Dan Initial version.
- #
- # 0.2.0 2007-03-11 Brent Fixed UV coords, V was inverted.
- # Support for exporting quads.
- # Fixed a padding issue.
- #
- # 0.3.0 2007-03-18 Dan Code refactoring / Clean up.
- # Fixed 'INFO' section size in header.
- #
- # 0.3.3 2007-09-25 GeomanNL fixed a file-write bug
- # orientation fix, changed to matrix rotation
- # other excellent stuff
- # (me darius took the freedom to write your entry:D)
- #
- # 0.3.5 2009-03-20 Darius_ tangent and binormal calc
- # vertex optimation
- # blender front to supcom front
- # some more fixes and reorganizing/cleanup code
- #
- #
- # Todo
- # - GUI improvements
- # - Support for LOD exporting. Eg. not merging all meshes for an armature into one mech but rather only
- # sub-meshes and export the top level meshes to different files.
- # - Validation, ensure that
- # - Prompt before overwriting files & check that directories exists
- # - Second UV set?
- # - Set animation time per frame
- # - Export LUA script for use in the animation viewer (eg, start anim, set texture etc)..
- # - Set root rot/pos for sca
- #
- #**************************************************************************************************
- """
- Name: 'Supreme Commander 3.5'
- Blender: 242
- Group: 'Export'
- Tooltip: 'Model / Animation Exporter for Supreme Commander'
- """
- import Blender
- import struct
- from Blender.BGL import *
- from Blender import Draw
- from Blender.Draw import *
- from Blender import Mathutils
- from Blender.Mathutils import *
- from Blender import Window
- import os
- from os import path
- VERSION = '3.5'
- ######################################################
- # User defined behaviour, Select as you need
- ######################################################
- #if you want to leave an info in your scm file put it in there
- USER_INFO = ""
- #Enable Progress Bar ( 0 = faster )
- PROG_BAR_ENABLE = 1
- #how many steps a progress bar has (the lesser the faster)
- PROG_BAR_STEP = 25
- #slower - reduce vertex amount
- VERTEX_OPTIMIZE = 1
- #LOG File for debuging
- #Enable LOG File (0 = Disabled , 1 = Enabled )
- LOG_ENABLE = 0
- #Filename / Path. Default is blender directory Filename SC-E_LOG.txt
- LOG_FILENAME = "SC-E_LOG.txt"
- LOG_BONE = 1
- LOG_VERT = 0
- ######################################################
- # Init Supreme Commander SCM( _bone, _vertex, _mesh), SCA(_bone, _frame, _anim) Layout
- ######################################################
- #Transform matrix z -> yx -> xy -> z
- xy_to_xz_transform = Matrix([ 1, 0, 0],
- [ 0, 0, -1],
- [ 0, 1, 0])
- #xy_to_xz_transform = Matrix([ 1, 0, 0], [ 0, 1, 0], [ 0, 0, 1])
- # Armature world matrix
- MArmatureWorld = Matrix()
- BONES = []
- ANIMATION_DURATION = 1.5
- class scm_bone :
- rest_pose = []
- rest_pose_inv = []
- rotation = []
- position = []
- parent_index = 0
- used = False
- name = ""
- def __init__(self, name, rest_pose_inv, rotation, position, parent_index):
- self.rest_pose_inv = rest_pose_inv
- self.rotation = rotation
- self.position = position
- self.parent_index = parent_index
- self.used = False
- self.name = name
- def save(self, file):
- bonestruct = '16f3f4f4i'
- #bonestruct = '16f3f4f4L' #Deprecation warning L and mistyrious binary output
- rp_inv = [0] * 16
- icount = 0
- for irow in xrange(4):
- #rest pose_inv
- for icol in xrange(4):
- rp_inv[icount] = self.rest_pose_inv[irow][icol]
- icount = icount + 1
- bonedata = struct.pack(bonestruct,
- rp_inv[0], rp_inv[1], rp_inv[2], rp_inv[3],
- rp_inv[4], rp_inv[5], rp_inv[6], rp_inv[7],
- rp_inv[8], rp_inv[9], rp_inv[10],rp_inv[11],
- rp_inv[12],rp_inv[13],rp_inv[14],rp_inv[15],
- self.position[0],self.position[1],self.position[2],
- self.rotation.w,self.rotation.x,self.rotation.y,self.rotation.z, #Quaternion (w,x,y,z)#w,x,y,z
- self.name_offset, self.parent_index,
- 0,0)
- #print self.name
- #print self.rest_pose_inv
- if LOG_BONE :
- LOGn(" %s rp_inv: [%.3f, %.3f, %.3f, %.3f],\t [%.3f, %.3f, %.3f, %.3f],\t [%.3f, %.3f, %.3f, %.3f],\t [%.3f, %.3f, %.3f, %.3f] \tpos: [%.3f, %.3f, %.3f] \trot: [%.3f, %.3f, %.3f, %.3f] %d"
- % ( self.name, rp_inv[0], rp_inv[1], rp_inv[2], rp_inv[3],
- rp_inv[4], rp_inv[5], rp_inv[6], rp_inv[7],
- rp_inv[8], rp_inv[9], rp_inv[10],rp_inv[11],
- rp_inv[12],rp_inv[13],rp_inv[14],rp_inv[15],
- self.position[0],self.position[1],self.position[2],
- self.rotation[0],self.rotation[1],self.rotation[2],self.rotation[3], self.parent_index))
- file.write(bonedata)
- class scm_vertex :
- global xy_to_xz_transform
- position = []
- tangent = []
- normal = []
- binormal = []
- uvc = 0
- uv1 = []
- uv2 = []
- bone_index = []
- def __init__(self, pos , no , uv1, bone_index):
- self.position = pos
- self.normal = no
- #tangent and binormal wil be calculated by face
- self.tangent = Vector( 0, 0, 0)
- self.binormal = Vector( 0, 0, 0)
- self.uvc = 1
- self.uv1 = uv1
- self.uv2 = uv1# Vector(0,0) #uv1 #better results with copy ... strange, where is the use of that?
- self.bone_index = bone_index
- def save(self, file):
- vertstruct = '3f3f3f3f2f2f4B'
- #so finaly we can norm because here it is sure that no tang norm will be added
- #self.normal = CrossVecs(self.tangent, self.binormal).normalize()
- self.tangent.normalize()
- self.binormal.normalize()
- self.normal.normalize()
- if False :
- self.tangent = Vector(0,0,0)
- self.binormal= Vector(0,0,0)
- #self.normal = Vector(0,0,0)
- if LOG_VERT :
- LOGn( " pos: [%.3f, %.3f, %.3f] \tn: [%.3f, %.3f, %.3f] \tt: [%.3f, %.3f, %.3f] \tb: [%.3f, %.3f, %.3f] \tuv [ %.3f, %.3f | %.3f, %.3f ] \tbi: [%d, %d, %d, %d]"
- % (
- self.position[0], self.position[1], self.position[2],
- self.normal[0], self.normal[1], self.normal[2],
- self.tangent[0], self.tangent[1], self.tangent[2],
- self.binormal[0], self.binormal[1], self.binormal[2],
- self.uv1[0], self.uv1[1],
- self.uv2[0], self.uv2[1],
- self.bone_index[0], self.bone_index[1],
- self.bone_index[2], self.bone_index[3]) )
- # so you store in this order:
- # pos, normal, tangent, binormal, uv1, uv2, ibone
- vertex = struct.pack(vertstruct,
- self.position[0], self.position[1], self.position[2],
- self.normal[0], self.normal[1], self.normal[2],
- self.tangent[0], self.tangent[1], self.tangent[2],
- self.binormal[0], self.binormal[1], self.binormal[2],
- self.uv1[0], self.uv1[1],
- self.uv2[0], self.uv2[1],
- self.bone_index[0], self.bone_index[1],
- self.bone_index[2], self.bone_index[3])
- file.write(vertex)
- #helper the real scm face 'tupel is stored in mesh
- #quad face
- class qFace :
- vertex_cont = []
- def __init__(self):
- self.vertex_cont = []
- def addVert(self, vertex):
- self.vertex_cont.extend( vertex )
- def addToMesh(self, mesh):
- face1 = Face()
- face1.addVert([ self.vertex_cont[0], self.vertex_cont[1], self.vertex_cont[2] ])
- face1.CalcTB()
- face2 = Face()
- face2.addVert([ self.vertex_cont[2], self.vertex_cont[3], self.vertex_cont[0] ])
- face2.CalcTB()
- mesh.addQFace(face1, face2)
- #helper the real scm face 'tupel is stored in mesh
- #tri face
- class Face :
- vertex_cont = []
- def __init__(self):
- self.vertex_cont = []
- def addVert(self, vertex):
- self.vertex_cont.extend(vertex)
- #now contains 3 vertexes calculate bi and ta and add to mesh
- def CalcTB( self ) :
- vert1 = self.vertex_cont[0]
- vert2 = self.vertex_cont[1]
- vert3 = self.vertex_cont[2]
- uv = [ vert1.uv1, vert2.uv1, vert3.uv1]
- # Calculate Tangent and Binormal
- # (v3 - v1).(p2 - p1) - (v2 - v1).(p3 - p1)
- # T = ------------------------------------------------
- # (u2 - u1).(v3 - v1) - (v2 - v1).(u3 - u1)
- # (u3 - u1).(p2 - p1) - (u2 - u1).(p3 - p1)
- # B = -------------------------------------------------
- # (v2 - v1).(u3 - u1) - (u2 - u1).(v3 - v1)
- P2P1 = vert2.position - vert1.position
- P3P1 = vert3.position - vert1.position
- #UV2UV1 = [ uv[1][0]-uv[0][0], uv[1][1]-uv[0][1] ]
- #UV3UV1 = [ uv[2][0]-uv[0][0], uv[2][1]-uv[0][1] ]
- UV2UV1 = uv[1] - uv[0]
- UV3UV1 = uv[2] - uv[0]
- divide = (UV2UV1[1]*UV3UV1[0] - UV2UV1[0]*UV3UV1[1])
- if ( divide != 0.0 ) :
- tangent = Vector((UV3UV1[1]*P2P1 - UV2UV1[1]*P3P1)/(divide))
- binormal = Vector((UV3UV1[0]*P2P1 - UV2UV1[0]*P3P1)/(-divide))
- else :
- countLOG("<Warning: Vertex-T-B divided through zero")
- tangent = Vector(0,0,0)
- binormal = Vector(0,0,0)
- #add calculated tangent and binormal to vertices
- for ind in xrange(3):
- self.vertex_cont[ind].tangent = tangent
- self.vertex_cont[ind].binormal = binormal
- def addToMesh( self, mesh ) :
- self.CalcTB()
- mesh.addFace( self )
- class scm_mesh :
- bones = []
- vertices = []
- vertcounter = 0
- faces = []
- info = []
- def __init__(self):
- self.bones = []
- self.vertices = []
- self.faces = []
- self.info = []
- self.vertcounter = 0
- def addVert( self, nvert ):
- if VERTEX_OPTIMIZE :
- #search for vertex already in list
- vertind = 0
- for vert in self.vertices :
- if nvert.uv1 == vert.uv1 and nvert.position == vert.position :
- break #found vert in list keep that index
- vertind += 1 #hmm not that one
- if vertind == len(self.vertices) :
- self.vertices.append( nvert )
- else:
- vert = self.vertices[vertind]
- vert.tangent = Vector( (vert.tangent + nvert.tangent) )
- vert.binormal = Vector( (vert.binormal + nvert.binormal) )
- vert.normal = Vector( (vert.normal + nvert.normal) )
- self.vertices[vertind] = vert
- return vertind
- else:
- self.vertices.append(nvert)
- return len(self.vertices)-1
- def addFace( self, face ):
- facein = [ self.addVert(nvert) for nvert in face.vertex_cont]
- self.faces.append(facein)
- def addQFace( self, face1, face2):
- facein = [ self.addVert(nvert) for nvert in face1.vertex_cont]
- self.faces.append(facein)
- facein = [ facein[2], self.addVert(face2.vertex_cont[1]), facein[0]]
- self.faces.append(facein)
- def save(self, filename):
- LOGp('Writing Mesh...')
- scm = file(filename, 'wb')
- #headerstruct = '12L' #Deprecation warning L and mistyrious binary output
- headerstruct = '4s11L'
- headersize = struct.calcsize(headerstruct)
- #marker = 'MODL'
- marker = 'MODL'
- version = 5
- boneoffset = 0
- bonecount = 0
- vertoffset = 0
- extravertoffset = 0
- vertcount = len(self.vertices)
- indexoffset = 0
- indexcount = len(self.faces) * 3
- infooffset = 0
- infosize = 0
- totalbonecount = len(self.bones)
- # Write dummy header
- header = struct.pack(headerstruct + '',
- marker, version, boneoffset, bonecount, vertoffset,
- extravertoffset, vertcount, indexoffset, indexcount,
- infooffset, infosize, totalbonecount)
- scm.write(header)
- # Write bone names
- pad_file(scm, 'NAME')
- for bone in self.bones:
- bone.name_offset = scm.tell()
- name = bone.name
- buffer = struct.pack(str(len(name) + 1)+'s', name)
- scm.write(buffer)
- #Log(buffer)
- LOGn("[/bone struckt]")
- # Write bones
- boneoffset = pad_file(scm, 'SKEL')
- for bone in self.bones:
- bone.save(scm)
- # if bone.used == True:
- bonecount = bonecount + 1
- # Write vertices
- vertoffset = pad_file(scm, 'VTXL')
- for vertex in self.vertices:
- vertex.save(scm)
- # Write Faces
- indexoffset = pad_file(scm, 'TRIS')
- for f in range(len(self.faces)):
- face = struct.pack('3H', self.faces[f][0], self.faces[f][1], self.faces[f][2])
- #face = struct.pack('3h', self.faces[f][0], self.faces[f][1], self.faces[f][2])
- scm.write(face)
- LOGp( "Bones: %d, Vertices: %d, Faces: %d; \n" % (bonecount, len(self.vertices), len(self.faces)))
- #Write Info
- if len(self.info) > 0:
- infooffset = pad_file(scm, 'INFO')
- for i in range(len(self.info)):
- info = self.info[i]
- infolen = len(info) + 1
- buffer = struct.pack(str(infolen)+'s', info)
- scm.write(buffer)
- infosize = scm.tell() - infooffset;
- # Now we can update the header
- scm.seek(0, 0)
- header = struct.pack(headerstruct,
- marker, version, boneoffset, bonecount, vertoffset,
- extravertoffset, vertcount, indexoffset, indexcount,
- infooffset, infosize, totalbonecount)
- scm.write(header)
- scm.close()
- class sca_bone:
- position = Vector( 0, 0, 0)
- rotation = Quaternion( 0, 0, 0, 0 )
- def __init__(self, pos, rot):
- self.position = pos
- self.rotation = rot
- class sca_frame:
- keytime = 0.0
- keyflags = 0
- bones = []
- anim = None
- def __init__(self, anim):
- self.keytime = 0.0
- self.keyflags = 0
- self.anim = anim
- self.bones = []
- def save(self, file):
- frameheader_fmt = 'fl'
- frameheader_size = struct.calcsize(frameheader_fmt)
- posrot_fmt = '3f4f'
- posrot_size = struct.calcsize(posrot_fmt)
- # Frame header
- buffer = struct.pack(frameheader_fmt, self.keytime, self.keyflags)
- file.write(buffer)
- #Log(":%d:" % (len(self.bones)))
- # Bones
- for bone in self.bones:
- buffer = struct.pack( posrot_fmt,
- bone.position.x, bone.position.y, bone.position.z,
- bone.rotation.w, bone.rotation.x, bone.rotation.y, bone.rotation.z)
- file.write(buffer)
- class sca_anim :
- frames = []
- bonelinks = []
- bonenames = []
- duration = 0.0
- def __init__(self):
- global ANIMATION_DURATION
- self.frames = []
- self.bonelinks = []
- self.bonenames = []
- self.duration = ANIMATION_DURATION
- def save(self, filename):
- LOGp('Writing SCA...')
- #self.filename = filename
- sca = file(filename, 'wb')
- headerstruct = '4sllflllll'
- # Write temp header
- magic = 'ANIM'
- version = 5
- numframes = len(self.frames)
- numbones = len(self.bonenames)
- namesoffset = 0
- linksoffset = 0
- animoffset = 0
- framesize = 0
- header = struct.pack(headerstruct,
- magic, version, numframes, self.duration, numbones,
- namesoffset, linksoffset, animoffset, framesize)
- #note: this header is seen correctly by the GPG dumpsca.py
- sca.write(header)
- # Write bone names
- namesoffset = pad_file(sca, 'NAME')
- for bone_name in self.bonenames:
- buffer = struct.pack(str(len(bone_name) + 1)+'s', bone_name)
- sca.write(buffer)
- # Write bone links
- linksoffset = pad_file(sca, 'LINK')
- for link in self.bonelinks:
- buffer = struct.pack('l', link)
- sca.write(buffer)
- # Write data
- animoffset = pad_file(sca, 'DATA')
- #the space occupied by postion and rotation info on the bones.
- posrot_fmt = '3f4f'
- posrot_size = struct.calcsize(posrot_fmt)
- #this writes the position/rotation of the root bone in the first animation, as if it is at position 0, and no rotation
- #note: it looks like rot=1,0,0,0 is needed to indicate no rotation.
- buffer = struct.pack(posrot_fmt, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0)
- sca.write(buffer)
- for frame in self.frames:
- framesize = sca.tell()
- frame.save(sca)
- framesize = sca.tell() - framesize
- # Update header
- sca.seek(0, 0)
- header = struct.pack(headerstruct,
- magic, version, numframes, self.duration, numbones,
- namesoffset, linksoffset, animoffset, framesize)
- sca.write(header)
- sca.close()
- LOGp( "Bones: %d, Frames: %d;\n" % (numbones, numframes) )
- #Log('OFFSETS: names = %d links = %d anim = %d framesize = %d' % (namesoffset, linksoffset, animoffset, framesize))
- ######################################################
- # Exporter Functions
- ######################################################
- # Helper methods
- ######################################################
- def pad(size):
- val = 32 - (size % 32)
- if (val < 4):
- val = val + 32
- return val
- def pad_file(file, s4comment):
- N = pad(file.tell()) - 4
- filldata = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
- padding = struct.pack(str(N)+'s4s', filldata[0:N], s4comment)
- file.write(padding)
- return file.tell()
- #
- ######################################################
- # Helper method for itterating through the bone tree
- def itterate_bones(mesh, bone, parent = None, scm_parent_index = -1):
- global MArmatureWorld
- global BONES
- global xy_to_xz_transform
- if (parent != None and bone.parent.name != parent.name):
- PupMenu("Error: Invalid parenting in bone ... multiple parents?!%t|OK")
- Exit()
- #print "Invalid parenting in bone", bone.name," and parent ", parent.name
- return
- b_rest_pose = Matrix([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0])
- b_rest_pose_inv = Matrix([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0])
- b_rotation = Quaternion( 0,0,0,0 )
- b_position = Vector( 0,0,0 )
- b_index = len(mesh.bones)
- #MArmatureWorld = Matrix(arm_obj.matrixWorld)
- bone_matrix = Matrix(bone.matrix['ARMATURESPACE'])
- # Calculate the inverse rest pose for the bone #instead bonearmmat*worldmat = Matrix['BONESPACE']
- b_rest_pose = Matrix( bone_matrix * MArmatureWorld )
- b_rest_pose_inv = Matrix( b_rest_pose * xy_to_xz_transform ).invert()
- if (parent == None):
- rel_mat = b_rest_pose * xy_to_xz_transform
- #root pos is the same as the rest-pose
- else:
- parent_matrix_inv = Matrix( parent.matrix['ARMATURESPACE'] ).invert()
- rel_mat = Matrix(bone_matrix * parent_matrix_inv)
- # must be BM * PMI in that order
- # do not use an extra (absolute) extra rotation here, cause this is only relative
- # Position & Rotation relative to parent (if there is a parent)
- b_rotation = rel_mat.toQuat()#.normalize()
- #row 3, cols 0,1,2 indicate position
- b_position = Vector( rel_mat[3] )
- #def __init__(self, name, rest_pose_inv, rotation, position, parent_index):
- sc_bone = scm_bone( bone.name, b_rest_pose_inv, b_rotation, b_position, scm_parent_index )
- BONES.append(sc_bone)
- mesh.bones.append(sc_bone)
- # recursive call for all children
- if (bone.children != None):
- for child in bone.children:
- itterate_bones( mesh, child, bone, b_index )
- def make_scm(arm_obj):
- global MArmatureWorld
- global xy_to_xz_transform
- arm = arm_obj.getData()
- scn = Blender.Scene.GetCurrent()
- # Get all mesh objects for the selected armature & calculate progbar length
- pb_length = 0
- mesh_objs = []
- for obj in scn.objects:
- if obj.parent == arm_obj and obj.getType() == 'Mesh':
- #calculate progbar length
- bmesh_data = obj.getData(False, True)
- pb_length += len(bmesh_data.faces)
- mesh_objs.append(obj)
- ProgBarFaces = ProgressBar( "Exp: Verts", pb_length )
- # Create SCM Mesh
- supcom_mesh = scm_mesh()
- # Traverse the bone tree and check if there is one root bone
- numroots = 0
- for bone in arm.bones.values():
- if (bone.parent == None):
- numroots += 1
- itterate_bones(supcom_mesh, bone)
- if numroots > 1:
- PupMenu("Error: there are multiple root bones -> check you bone relations!%t|OK")
- Exit()
- return
- #this inserts a converted armature back into the existing model, to see
- #if the bone locations are correct (was used for debugging)
- #test_the_armature = 1
- #if test_the_armature:
- # #create an extra test armature
- # testarm_data= Blender.Armature.New('testArmature')
- # testarm_ob = scn.objects.new(testarm_data)
- # testarm_data.makeEditable()
- # prev_eb = Non
- # for bone in supcom_mesh.bones:
- # print "mesh bone: ", bone.name
- # eb = Blender.Armature.Editbone()
- # eb.name = bone.name
- # rest_pose = bone.rest_pose[3]
- # eb.head = Vector(rest_pose[0], rest_pose[1], rest_pose[2])
- # eb.tail = eb.head + Vector(1,0,0)
- # if bone.parent_index != -1:
- # eb.parent = prev_eb
- # prev_eb = eb
- # testarm_data.bones[eb.name]= eb
- # testarm_data.update()
- # Process all the meshes
- for mesh_obj in mesh_objs:
- bmesh_data = mesh_obj.getData(False, True)
- if not bmesh_data.faceUV :
- PupMenu("Error: Mesh has no texture values -> Please set your UV!%t|OK")
- Exit()
- return
- MatrixMesh = Matrix(mesh_obj.matrixWorld)
- mesh_name = mesh_obj.name
- for face in bmesh_data.faces:
- ProgBarFaces.do()
- vertList = []
- for i in xrange(len(face.verts)):
- vert = face.verts[i]
- v_nor = Vector( 0, 0, 0 )
- v_pos = Vector( 0, 0, 0 )
- v_uv1 = Vector( 0, 0) #SC allows 2 uv's
- v_boneIndex = [0]*4 # SC supports up to 4 bones we will use only one
- #v_boneIndex = [-1,0,0,0]
- #Find controling bone
- v_boneIndex[0] = -1
- inf = bmesh_data.getVertexInfluences(vert.index)
- for j in xrange(len(inf)) :
- bonename = inf[j][0]
- for b in range(len(supcom_mesh.bones)):
- bone = supcom_mesh.bones[b]
- if bone.name == bonename:
- bone.used = True
- v_boneIndex[0] = b
- break
- if (v_boneIndex[0] == -1):
- v_boneIndex[0] = 0
- Blender.Window.EditMode(0)
- vert.sel = 1
- countLOG("Warning: Verticle without Bone Influence in %s. Selected " % (mesh_name))
- v_pos = Vector( vert.co * (MatrixMesh * xy_to_xz_transform))
- v_nor = vert.no * (MatrixMesh * xy_to_xz_transform)
- #needed cause supcom scans an image in the opposite vertical direction or something?.
- v_uv1 = Vector(face.uv[i][0], 1.0 - face.uv[i][1])
- vertList.append( scm_vertex( v_pos, v_nor, v_uv1 , v_boneIndex) )
- if len(vertList) > 3:
- newFace = qFace()
- else:
- newFace = Face()
- newFace.addVert(vertList)
- newFace.addToMesh(supcom_mesh)
- return supcom_mesh
- def make_sca(arm_obj, action):
- global BONES
- global MArmatureWorld
- global xy_to_xz_transform
- action.setActive(arm_obj)
- scene = Blender.Scene.GetCurrent()
- render_context = scene.getRenderingContext()
- endframe = render_context.endFrame()
- animation = sca_anim()
- #animation.duration = 1.5
- # Add bone names & links
- for bone in BONES:
- animation.bonenames.append(bone.name)
- animation.bonelinks.append(bone.parent_index)
- LOGn('adding bone: %s with parent %d ' % (bone.name, bone.parent_index))
- ProgBarAnimation = ProgressBar( "Exp: Anim", endframe)
- # Add frames
- frame_counter = 1
- while frame_counter <= endframe:
- LOGn('adding frame %d of %d' % (frame_counter, endframe))
- ProgBarAnimation.do()
- frame = sca_frame(animation)
- arm_obj.evaluatePose(frame_counter)
- frame_counter += 1
- POSED_BONES = {}
- for posebone in arm_obj.getPose().bones.values():
- POSED_BONES[posebone.name] = posebone.poseMatrix
- for bone in BONES:
- pose_bone_matrix = POSED_BONES[bone.name]
- if (bone.parent_index == -1):
- rel_mat = (Matrix(pose_bone_matrix) * MArmatureWorld) * xy_to_xz_transform
- else:
- rel_mat = Matrix(pose_bone_matrix) * Matrix(POSED_BONES[BONES[bone.parent_index].name]).invert()
- rotation = rel_mat.toQuat().normalize()
- #rot = rotation #[ rotation.w, rotation.x, rotation.y, rotation.z ]
- pos = Vector( rel_mat[3][0], rel_mat[3][1], rel_mat[3][2] )
- anim_bone = sca_bone(pos, rotation)
- frame.bones.append(anim_bone)
- animation.frames.append(frame)
- return animation
- def export(outdir):
- global VERSION, USER_INFO
- global MArmatureWorld
- global xy_to_xz_transform
- w_edit_mode = Blender.Window.EditMode()
- #No animation export in editmode
- if w_edit_mode :
- Blender.Window.EditMode(0)
- Blender.Window.WaitCursor(1)
- xy_to_xz_transform.resize4x4()
- scn = Blender.Scene.GetCurrent()
- # Get Selected object(s)
- selected_objects = Blender.Object.GetSelected()
- # Look for an armature
- arm = None
- arm_obj = None
- for obj in selected_objects:
- data = obj.getData()
- if type(data) is Blender.Types.ArmatureType:
- arm = data
- arm_obj = obj
- break
- # Is there one armature? Take this one
- if arm == None :
- for obj in scn.objects:
- data = obj.getData()
- if obj.getType() == 'Armature' :
- if arm == None:
- arm = data
- arm_obj = obj
- else :
- arm = None
- break
- if arm == None:
- PupMenu("Error: Please select your armature.%t|OK")
- Exit()
- return
- # this defines the ARMATURE_SPACE.
- # all bones in the armature are positioned relative to this space.
- MArmatureWorld = Matrix(arm_obj.matrixWorld)
- # SCM
- LOGp(' ')
- LOGp(' ')
- LOGp('Exporting model: ' + arm_obj.name )
- LOGp('----------------------------------')
- mesh = make_scm(arm_obj)
- if mesh == None :
- LOGp('Aborted!')
- return
- mesh.info.append('Exported with Blender SupCom-Exporter ' + VERSION)
- if USER_INFO != "" :
- mesh.info.append( USER_INFO )
- mesh.save(outdir + arm_obj.name + '.scm')
- mesh = None
- # SCA
- actions = Blender.Armature.NLA.GetActions().iteritems()
- for action in actions:
- #action[0] = the key, action[1] = the dictionary
- ####maybe this could help?
- LOGp(' ')
- LOGp('Animation: ' + action[0])
- animation = make_sca(arm_obj, action[1])
- animation.save(outdir + action[0] + '.sca')
- Blender.Window.EditMode(w_edit_mode)
- Blender.Window.WaitCursor(0)
- LOGp('----------------------------------')
- closeLog()
- ######################################################
- # GUI
- ######################################################
- log = []
- log_max_lines = 14
- LOG_FILE = None
- #log to file
- def LOGn(message):
- global LOG_FILE
- global LOG_ENABLE
- global LOG_FILENAME
- if LOG_ENABLE :
- if LOG_FILE == None :
- LOG_FILE = open( LOG_FILENAME, 'w')
- LOG_FILE.write('SupCom Exporter LOG File:\n\n')
- LOGp( "LOG enabled: %s" % (LOG_FILENAME))
- Log(message + '\n')
- else :
- LOG_FILE.write(message + '\n')
- #Log to file, to console and exp window
- def LOGp(message):
- global log, log_max_lines
- LOGn(message)
- print message
- log.append(message)
- if len(log) > log_max_lines:
- del log[0]
- counter = []
- cLog = []
- #log for a amount of errors like vertex errors
- def countLOG(message):
- global cLog
- global counter
- cont = False
- for i in xrange(len(cLog)):
- if cLog[i] == message:
- cont = True
- counter[i] +=1
- break
- if not cont :
- cLog.append( message)
- counter.append( 1)
- def closeLog():
- global cLog, LOG_FILE
- global counter
- for i in xrange(len(cLog)):
- LOGp("%s (Times:%d)" % (cLog[i], counter[i]))
- if LOG_FILE != None :
- LOG_FILE.close()
- Blender.Window.RedrawAll()
- class ProgressBar :
- global PROG_BAR_STEP
- global PROG_BAR_ENABLE
- progress = 0
- progressold = 0
- current = 0
- end = 0
- div = 0
- text = "None"
- def __init__(self, text, end):
- self.progress = 0
- self.progressold = 0
- self.current = 0
- self.end = end
- self.text = text
- self.div = PROG_BAR_STEP
- #it looks like blender needs to init this progress bar with 0.0
- if PROG_BAR_ENABLE :
- Blender.Window.DrawProgressBar ( 0.0 , text)
- def do(self):
- if PROG_BAR_ENABLE :
- self.current += 1
- self.progress = (self.current*self.div)/self.end
- if self.progress != self.progressold :
- self.progressold = self.progress
- Blender.Window.DrawProgressBar ( float(self.progress)/self.div , self.text)
- # Events
- EVENT_NOEVENT = 1
- EVENT_DRAW = 2
- EVENT_EXIT = 3
- EVENT_CLOSE_LOG = 4
- EVENT_EXPORTDIR_TEXT = 5
- EVENT_EXPORTDIR = 6
- export_directory = Blender.Draw.Create("sds")
- show_log = 0
- def fileselector_callback(filename):
- modelpath, modelfile = os.path.split(filename)
- export_directory.val = modelpath + '/'
- def draw():
- global EVENT_NOEVENT, EVENT_DRAW, EVENT_EXIT, EVENT_CLOSE_LOG
- global export_directory, show_log
- global log_max_lines, log
- global VERSION
- # Titles
- glClear(GL_COLOR_BUFFER_BIT)
- top = 60 + log_max_lines * 12 + 8
- #top = 500
- top_x = 304
- glColor3f(0.8, 0.8, 1)
- glRecti(top_x, top, 4, 4)
- glBegin(GL_LINES)
- glColor3f(0.8, 0.8, 0.8)
- glVertex2d(4, top)
- glVertex2d(4, 4)
- glVertex2d(4, 4)
- glVertex2d(top_x, 4)
- glColor3f(0.5, 0.5, 0.5)
- glVertex2d(top_x, top)
- glVertex2d(4, top)
- glVertex2d(top_x, top)
- glVertex2d(top_x, top-1)
- glEnd()
- glColor3f(0, 0, 0)
- glRasterPos2d(10, top-16)
- Text("Supreme Commander Exporter " + VERSION)
- # Show exporting log
- if show_log:
- for index in range(0, len(log)):
- i = (len(log) - 1) - index
- glRasterPos2i(10, 40 + i*12)
- Text(log[index]) #, 'tiny')
- Button("Close", EVENT_EXIT , 10, 10, 80, 18)
- #Blender.Window.RedrawAll()
- # Exporter GUI
- else:
- Blender.Draw.Button("Browse...", EVENT_EXPORTDIR, 10, 40, 80, 18, "")
- #if export_directory.val == 'sds':
- #automatically launch the browse window once
- # Blender.Window.FileSelector (fileselector_callback, "Select output DIR")
- # Blender.Redraw()
- export_directory = Blender.Draw.String("", EVENT_EXPORTDIR_TEXT, 100, 40, 200, 18, export_directory.val, 255, "Where to save the exported files")
- # Draw and Exit Buttons
- Button("Export", EVENT_DRAW , 10, 10, 80, 18)
- Button("Exit", EVENT_EXIT , 100, 10, 80, 18)
- def event(evt, val):
- if (evt == QKEY and not val):
- Exit()
- def bevent(evt):
- global EVENT_NOEVENT,EVENT_DRAW,EVENT_EXIT
- global export_directory
- global show_log
- if (evt == EVENT_EXIT):
- show_log = 1
- Exit()
- elif (evt == EVENT_EXPORTDIR):
- Blender.Window.FileSelector (fileselector_callback, "Select output DIR")
- #Blender.Redraw()
- elif (evt == EVENT_DRAW):
- if (export_directory.val == ""):
- return
- show_log = 1
- modelpath, modelfile = os.path.split(export_directory.val)
- export(modelpath + '/')
- #changed cause filename was included in the dir selection
- #Blender.Redraw()
- Register(draw, event, bevent)
- #automatically launch the browse window once
- Blender.Window.FileSelector (fileselector_callback, "Select output DIR")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement