#!BPY """ Name: 'COLLADA 1.3.1 (.dae) ...' Blender: 240 Group: 'Export' Tooltip: 'Export scene to COLLADA format (.dae)' """ __author__ = "Mikael Lagre" __url__ = ("blender", "blenderartists.org", "Project homepage, http://colladablender.sourceforge.net", "Official Collada site, http://www.collada.org") __version__ = "0.4" __bpydoc__ = """ Description: Exports Blender scene to the COLLADA 1.3.1 format. Usage: run the script from the menu or inside Blender. Notes: the script does not export animations yet. """ # -------------------------------------------------------------------------- # Collada exporter version 0.4 # -------------------------------------------------------------------------- # ***** BEGIN GPL LICENSE BLOCK ***** # # Copyright (C) 2005: Mikael Lagre' contactme@mikaellagre.com # # 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 ***** # -------------------------------------------------------------------------- _ERROR = False try: import math except: print "Error! Could not find math module" _ERROR = True try: import Blender from Blender import * except: print "Error! Could not find Blender modules!" _ERROR = True try: from xml.dom.minidom import Document, Element, Childless, Text, _write_data except: print "\nError! Could not find XML modules!" _ERROR = True if _ERROR: from sys import version_info version = '%s.%s' % version_info[0:2] print """ This script requires the xml module that is part of a default standalone Python install. To run the collada importer and exporter you need to have Python version %s installed in your system. It can be downloaded from: http://www.python.org Notes: - The minor (third) version number doesn't matter, you can have either Python %s.1 or %s.2 or higher. - If you do have Python %s installed and still can't run the scripts, then make sure Blender's Python interpreter is finding the standalone modules (run 'System Information' from Blender's Help -> System menu). """ % (version, version, version, version) Draw.PupMenu("Please install full version of python %t | Check the console for more info") # === GLOBAL EXPORT SETTINGS === exportBakedTransform = True # Export element transform exportSelected = False # Export selected objects only niceFormat = False # Creates a more readable document # ============================== # Global FPS for animation export (exporter uses render->anim settings) fps = 25 # ---------------------------------------------- # Class structures # ---------------------------------------------- class COLLADADocument( Document ): """ A COLLADA Document ( DAE - Digital Asset Exangche) """ __file_ref = None def openFile( self, file ): self.__file_ref = open( file, "w" ) return def buildXML( self ): if not ( self.__file_ref == None ): self.writexml( self.__file_ref, "", "\t", '\n', "utf-8" ) return def cleanUp( self ): self.unlink() self.__file_ref.close() return # Definition of create[ColladaElementTypes] def createCOLLADAElement( self, version=None ): e = _COLLADAElement( version ) e.ownerDocument = self return e def createSceneElement( self, id=None, name=None ): e = _SceneElement( id, name ) e.ownerDocument = self return e def createNodeElement( self, name=None, id=None, nodeType=None ): e = _NodeElement( name, id, nodeType ) e.ownerDocument = self return e def createBoundingBoxElement( self ): e = _BoundingBoxElement( ) e.ownerDocument = self return e def createCameraElement( self, id=None, name=None ): e = _CameraElement( id, name ) e.ownerDocument = self return e def createOpticsElement( self ): e = _OpticsElement( ) e.ownerDocument = self return e def createImagerElement( self ): e = _ImagerElement( ) e.ownerDocument = self return e def createInstanceElement( self, url ): e = _InstanceElement( url ) e.ownerDocument = self return e def createLibraryElement( self, type ): e = _LibraryElement( type ) e.ownerDocument = self return e def createAnimationElement( self, id=None, name=None ): e = _AnimationElement( id, name ) e.ownerDocument = self return e def createChannelElement( self, id=None, name=None, source=None, target=None ): e = _ChannelElement( id, name, source, target ) e.ownerDocument = self return e def createSamplerElement( self, id=None, name=None ): e = _SamplerElement( id, name ) e.ownerDocument = self return e def createControllerElement( self ): e = _ControllerElement( ) e.ownerDocument = self return e def createSkinElement( self ): e = _SkinElement( ) e.ownerDocument = self return e def createCombinerElement( self ): e = _CombinerElement( ) e.ownerDocument = self return e def createJointsElement( self ): e = _JointsElement( ) e.ownerDocument = self return e def createGeometryElement( self, id=None, name=None ): e = _GeometryElement( id, name ) e.ownerDocument = self return e def createMeshElement( self, id=None, name=None ): e = _MeshElement( id, name ) e.ownerDocument = self return e def createLinesElement( self ): e = _LinesElement( ) e.ownerDocument = self return e def createLinestripsElement( self ): e = _LinestripsElement( ) e.ownerDocument = self return e def createPolygonsElement( self, count=0, material=None ): e = _PolygonsElement( count, material ) e.ownerDocument = self return e def createPElement( self ): e = _PElement( ) e.ownerDocument = self return e def createTrianglesElement( self ): e = _TrianglesElement( ) e.ownerDocument = self return e def createTrifansElement( self ): e = _TrifansElement( ) e.ownerDocument = self return e def createTristripsElement( self ): e = _TristripsElement( ) e.ownerDocument = self return e def createVerticesElement( self, id, name, count ): e = _VerticesElement( id, name, count ) e.ownerDocument = self return e def createSourceElement( self, id=None, name=None ): e = _SourceElement( id, name ) e.ownerDocument = self return e def createAccessorElement( self, count=0, source="", id=None, offset=None, stride=None ): e = _AccessorElement( count, id, offset, source, stride) e.ownerDocument = self return e def createArrayElement( self ): e = _ArrayElement( ) e.ownerDocument = self return e def createBoolArrayElement( self ): e = _BoolArrayElement( ) e.ownerDocument = self return e def createFloatArrayElement( self, count, id=None, name=None, digits=None, magnitude=None ): e = _FloatArrayElement( count, id, name, digits, magnitude) e.ownerDocument = self return e def createIntArrayElement( self ): e = _IntArrayElement( ) e.ownerDocument = self return e def createNameArrayElement( self ): e = _NameArrayElement( ) e.ownerDocument = self return e def createInputElement( self, idx=None, semantic=None, source=None ): e = _InputElement( idx, semantic, source ) e.ownerDocument = self return e def createMaterialElement( self, id=None, name=None ): e = _MaterialElement( id, name ) e.ownerDocument = self return e def createShaderElement( self, id=None, name=None ): e = _ShaderElement( id, name ) e.ownerDocument = self return e def createPassElement( self ): e = _PassElement( ) e.ownerDocument = self return e def createTechniqueElement( self, profile=None ): e = _TechniqueElement( profile ) e.ownerDocument = self return e def createImageElement( self, id=None, name=None, height=None, width=None, depth=None, source=None, format=None ): e = _ImageElement( id, name, height, width, depth, source, format ) e.ownerDocument = self return e def createLightElement( self, id=None, name=None, type=None ): e = _LightElement( id, name, type ) e.ownerDocument = self return e def createTextureElement( self, id=None, name=None ): e = _TextureElement( id, name, ) e.ownerDocument = self return e def createProgramElement( self, id=None, name=None, url=None ): e = _ProgramElement( id, name, url ) e.ownerDocument = self return e def createCodeElement( self ): e = _CodeElement( ) e.ownerDocument = self return e def createEntryElement( self ): e = _EntryElement( ) e.ownerDocument = self return e def createParamElement( self, id=None, name=None, type=None, flow=None, semantic=None, sid=None ): e = _ParamElement( id, name, type, flow, semantic, sid ) e.ownerDocument = self return e def createMatrixElement( self, sid=None ): e = _MatrixElement( sid ) e.ownerDocument = self return e def createLookAtElement( self ): e = _LookAtElement( ) e.ownerDocument = self return e def createPerspectiveElement( self ): e = _PerspectiveElement( ) e.ownerDocument = self return e def createRotateElement( self, sid=None ): e = _RotateElement( sid ) e.ownerDocument = self return e def createScaleElement( self, sid=None ): e = _ScaleElement( sid ) e.ownerDocument = self return e def createSkewElement( self ): e = _SkewElement( ) e.ownerDocument = self return e def createTranslateElement( self, sid=None ): e = _TranslateElement( sid ) e.ownerDocument = self return e def createAssetElement( self ): e = _AssetElement( ) e.ownerDocument = self return e def createAuthorElement( self, data=None ): e = _AuthorElement( data ) e.ownerDocument = self return e def createAuthoringToolElement( self, data=None ): e = _AuthoringToolElement( data ) e.ownerDocument = self return e def createCreatedElement( self, data=None ): e = _CreatedElement( data ) e.ownerDocument = self return e def createModifiedElement( self, data=None ): e = _ModifiedElement( data ) e.ownerDocument = self return e def createRevisionElement( self, data=None ): e = _RevisionElement( data ) e.ownerDocument = self return e def createSourceDataElement( self, data=None ): e = _SourceDataElement( data ) e.ownerDocument = self return e def createElement( self, data=None ): e = _( data ) e.ownerDocument = self return e def createCopyrightElement( self, data=None ): e = _CopyrightElement( data ) e.ownerDocument = self return e def createTitleElement( self, data=None ): e = _TitleElement( data ) e.ownerDocument = self return e def createSubjectElement( self, data=None ): e = _SubjectElement( data ) e.ownerDocument = self return e def createKeywordsElement( self, data=None ): e = _KeywordsElement( data ) e.ownerDocument = self return e def createCommentsElement( self, data=None ): e = _CommentsElement( data ) e.ownerDocument = self return e def createUnitElement( self, name=None, meter=None ): e = _UnitElement( name, meter ) e.ownerDocument = self return e def createUpAxisElement( self, data=None ): e = _UpAxisElement( data ) e.ownerDocument = self return e def createExtraElement( self ): e = _ExtraElement( ) e.ownerDocument = self return e # COLLADA Common Profile constants strings # ( for COLLADA specification 1.3.1 ) # Also in this collada common profile class is library type constants # flow types and other xs:NMTOKEN constants definied in the schema class _CommonProfile: COMMON = 1 BLENDER = 2 str = [ "", "COMMON", "BLENDER" ] class _ParamName: A = 1 AMBIENT = 2 ANGLE = 3 ATTENUATION = 4 ATTENUATION_SCALE = 5 B = 6 BOTTOM = 7 COLOR = 8 DIFFUSE = 9 EMISSION = 10 FALLOFF = 11 FALLOFF_SCALE = 12 G = 13 LEFT = 14 P = 15 Q = 16 R = 17 REFLECTIVE = 18 REFLECTIVITY = 19 RIGHT = 20 S = 21 SHININESS = 22 SPECULAR = 23 T = 24 TANGENT_X = 25 TANGENT_Y = 26 TANGENT_Z = 27 TIME = 28 TOP = 29 TRANSPARENCY = 30 TRANSPARENT = 31 U = 32 V = 33 W = 34 X = 35 XFOV = 36 Y = 37 YFOV = 38 Z = 39 ZFAR = 40 ZNEAR = 41 MATRIX4X4 = 42 # Not in Common Profile really but here for baked animation param name str = [ "", "A", "AMBIENT", "ANGLE", "ATTENUATION", "ATTENUATION_SCALE", "B", "BOTTOM", "COLOR", "DIFFUSE", "EMISSION", "FALLOFF", "FALLOFF_SCALE", "G", "LEFT", "P", "Q", "R", "REFLECTIVE", "REFLECTIVITY", "RIGHT", "S", "SHININESS", "SPECULAR", "T", "TANGENT.X", "TANGENT.Y", "TANGENT.Z", "TIME", "TOP", "TRANSPARENCY", "TRANSPARENT", "U", "V", "W", "X", "XFOV", "Y", "YFOV", "Z", "ZFAR", "ZNEAR", "matrix" ] class _ProgramIDAndURL: ANGLE_MAP = 1 BEZIER = 2 BSPLINE = 3 CARDINAL = 4 CONSTANT = 5 CUBE_MAP = 6 FISH_EYE = 7 HERMITE = 8 LAMBERT = 9 LINEAR = 10 ORTHOGRAPHIC = 11 PANORAMA = 12 PERSPECTIVE = 13 PHONG = 14 REAR_FISH_EYE = 15 SPHERICAL = 16 str = [ "", "ANGLE_MAP", "BEZIER", "BSPLINE", "CARDINAL", "CONSTANT", "CUBE_MAP", "FISH_EYE", "HERMITE", "LAMBERT", "LINEAR", "ORTHOGRAPHIC", "PANORAMA", "PERSPECTIVE", "PHONG", "REAR_FISH_EYE", "SPHERICAL" ] class _CodeAndEntrySemantic: FRAGMENT_PROGRAM = 1 VERTEX_PROGRAM = 2 class _InputSemantic: BIND_SHAPE_NORMAL = 1 BIND_SHAPE_POSITION = 2 BINORMAL = 3 COLOR = 4 IMAGE = 5 INPUT = 6 IN_TANGENT = 7 INTERPOLATION = 8 INV_BIND_MATRIX = 9 JOINT = 10 JOINTS_AND_WEIGHTS = 11 NORMAL = 12 OUTPUT = 13 OUT_TANGENT = 14 POSITION = 15 TANGENT = 16 TEXCOORD = 17 TEXTURE = 18 UV = 19 VERTEX = 20 WEIGHT = 21 str = [ "", "BIND_SHAPE_NORMAL", "BIND_SHAPE_POSITION", "BINORMAL", "COLOR", "IMAGE", "INPUT", "IN_TANGENT", "INETRPOLATION", "INV_BIND_MATRIX", "JOINT", "JOINTS_AND_WEIGHTS", "NORMAL", "OUTPUT", "OUT_TANGENT", "POSITION", "TANGENT", "TEXCOORD", "TEXTURE", "UV", "VERTEX", "WEIGHT" ] class _ChannelAndControllerTarget: #( # )[( # )] A = 1 ANGLE = 2 B = 3 G = 4 P = 5 Q = 6 R = 7 S = 8 T = 9 TIME = 10 U = 11 V = 12 W = 13 X = 14 Y = 15 Z = 16 class _LibraryType: ANIMATION = 1 CAMERA = 2 CODE = 3 CONTROLLER = 4 GEOMETRY = 5 IMAGE = 6 LIGHT = 7 MATERIAL = 8 PROGRAM = 9 TEXTURE = 10 str = [ "", "ANIMATION", "CAMERA", "CODE", "CONTROLLER", "GEOMETRY", "IMAGE", "LIGHT", "MATERIAL", "PROGRAM", "TEXTURE" ] class _FlowType: IN = 1 OUT = 2 INOUT = 3 str = [ "", "IN", "OUT", "INOUT" ] class _NodeType: NODE = 1 JOINT = 2 str = [ "", "NODE", "JOINT" ] class _LightType: AMBIENT = 1 DIRECTIONAL = 2 POINT = 3 SPOT = 4 str = [ "", "AMBIENT", "DIRECTIONAL", "POINT", "SPOT" ] # Definition of modules for easier access in code # Note: This is pretty stupid I know ... class PN( _ParamName ): pass class PIAU( _ProgramIDAndURL ): pass class CAES( _CodeAndEntrySemantic ): pass class IS( _InputSemantic ): pass class CACT( _ChannelAndControllerTarget ): pass class LT( _LibraryType ): pass class FT( _FlowType ): pass class NT( _NodeType ): pass class LIGHT( _LightType ): pass # Common Profile class CP( _CommonProfile ): pass # Element types # Note that attributes are local here defined as their types (string, float) # and not Attr object types. Every element # has defined set and get methods for their types to create a better interface # for its element type # NOTE: Do not create instances of these class directly. Use the create... # functions in COLLADADocument class _COLLADAElement( Element ): __version = "1.3.1" __xmlns = "http://www.collada.org/2005/COLLADASchema" __xmlbase = None def setVersion( self, version ): self.__version = version self.setAttribute( "version", self.__version ) return def getVersion( self ): return self.__version def __init__( self, version=None ): Element.__init__( self, "COLLADA" ) self.__version = version if ( self.__version == None ): self.__version = "1.3.1" self.setAttribute( "version", self.__version ) self.setAttribute( "xmlns", self.__xmlns ) class _SceneElement( Element ): _name = "" _id = "" def __init__( self, id, name ): Element.__init__( self, "scene" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", id ) if not ( self._name == None ): self.setAttribute( "name", name ) class _NodeElement( Element ): _name = None _id = None _nodeType = None def __init__( self, name, id, nodeType ): Element.__init__( self, "node" ) self._id = id self._name = name self._nodeType = nodeType if not ( self._id == None ): self.setAttribute( "id", id ) if not ( self._name == None ): self.setAttribute( "name", name ) if not ( self._nodeType == None ): self.setAttribute( "type", CP.NT.str[ self._nodeType ] ) class _BoundingBoxElement( Element ): pass class _CameraElement( Element ): _name = "" _id = "" def __init__( self, id, name ): Element.__init__( self, "camera" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", id ) if not ( self._name == None ): self.setAttribute( "name", name ) class _OpticsElement( Element) : def __init__( self ): Element.__init__( self, "optics" ) class _ImagerElement( Element ): pass class _InstanceElement( Element, Childless ): _url = None def __init__( self, url ): Element.__init__( self, "instance" ) self._url = url if not ( self._url == None ): self.setAttribute( "url", "#" + self._url ) class _LibraryElement( Element ): _libraryType = None _name = None _id = None def __init__( self, libraryType ): Element.__init__( self, "library" ) self._libraryType = libraryType self.setAttribute( "type", CP.LT.str[ self._libraryType ] ) class _AnimationElement( Element ): _name = None _id = None def __init__( self, id, name ): Element.__init__( self, "animation" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", id ) if not ( self._name == None ): self.setAttribute( "name", name ) class _ChannelElement( Element ): _name = None _id = None _source = None _target = None def __init__( self, id, name, source, target ): Element.__init__( self, "channel" ) self._id = id self._name = name self._source = source self._target = target if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "name", self._name ) if not ( self._source == None ): self.setAttribute( "source", '#' + self._source ) if not ( self._target == None ): self.setAttribute( "target", self._target ) class _SamplerElement( Element ): _name = None _id = None def __init__( self, id, name ): Element.__init__( self, "sampler" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "name", self._name ) class _ControllerElement( Element ): pass class _SkinElement( Element ): pass class _CombinerElement( Element ): pass class _JointsElement( Element ): pass class _GeometryElement( Element ): _name = "" _id = "" def __init__( self, id, name ): Element.__init__( self, "geometry" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", id ) if not ( self._name == None ): self.setAttribute( "name", name ) class _MeshElement( Element ): _name = "" _id = "" def __init__( self, id, name ): Element.__init__( self, "mesh" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", id ) if not ( self._name == None ): self.setAttribute( "name", name ) class _LinesElement( Element ): pass class _LinestripsElement( Element ): pass class _PolygonsElement( Element ): _count = None _material = None def __init__( self, count, material ): Element.__init__( self, "polygons" ) self._count = count self._material = material if not ( self._count == None ): self.setAttribute( "count", "%i" % self._count ) if not ( self._material == None ): self.setAttribute( "material", "#" + self._material ) class _PElement( Element, Childless ): _data = None def setData( self, data ): self._data = data def getData( self, data ): return self._data def __init__( self ): Element.__init__( self, "p" ) # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _TrianglesElement( Element ): pass class _TrifansElement( Element ): pass class _TristripsElement( Element ): pass class _VerticesElement( Element ): _id = None _name = None _count = None def __init__( self, id, name, count ): Element.__init__( self, "vertices" ) self._id = id self._name = name self._count = count if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "name", self._name ) if not ( self._count == None ): self.setAttribute( "count", "%i" % self._count ) class _SourceElement( Element ): _id = None _name = None def __init__( self, id, name ): Element.__init__( self, "source" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", id ) if not ( self._name == None ): self.setAttribute( "name", name ) class _AccessorElement( Element ): _count = None _id = None _offset = None _source = None _stride = None def __init__( self, count, id, offset, source, stride ): Element.__init__( self, "accessor" ) self._count = count self._id = id self._offset = offset self._source = source self._stride = stride if not ( self._count == None ): self.setAttribute( "count", "%i" % self._count ) if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._offset == None ): self.setAttribute( "offset", "%i" % self._offset ) if not ( self._source == None ): self.setAttribute( "source", "#" + self._source ) if not ( self._stride == None ): self.setAttribute( "stride", "%i" % self._stride ) class _ArrayElement( Element ): pass class _BoolArrayElement( Element ): pass class _FloatArrayElement( Element ): _count = None _id = None _name = None _digits = None _magnitude = None _data = None _dataType = 'STRING' #_fps = 25 def setData( self, data ): self._data = data def getData( self, data ): return self._data def setDataType( self, dataType ): self._dataType = dataType def setCount( self, count ): self._count = count self.setAttribute( "count", "%i" % self._count ) # def setFPS( self, fps ): # self._fps = fps def __init__( self, count, id, name, digits, magnitude ): Element.__init__( self, "float_array" ) self._count = count self._id = id self._name = name self._digits = digits self._magnitude = magnitude if not ( self._count == None ): self.setAttribute( "count", "%i" % self._count ) if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "name", self._name ) if not ( self._digits == None ): self.setAttribute( "digits", "%i" % self._digits ) if not ( self._magnitude == None ): self.setAttribute( "magnitude", "%i" % self._magnitude ) # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): global niceFormat global fps writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: # writer.write(">%s%s%s" % ( self._data, newl + indent, self.tagName, newl ) ) writer.write( ">" ) dataString = '' if ( self._dataType == 'POSITION' ): if ( niceFormat ): for v in self._data: dataString = "\n%.6f %.6f %.6f" % ( v.co[0], v.co[1], v.co[2] ) writer.write( dataString ) else: v = self._data dataString = "%.6f %.6f %.6f " % ( v[0].co[0], v[0].co[1], v[0].co[2] ) writer.write( dataString ) size = len( self._data ) for i in range( 1, size - 1 ): dataString = "%.6f %.6f %.6f " % ( v[i].co[0], v[i].co[1], v[i].co[2] ) writer.write( dataString ) dataString = "%.6f %.6f %.6f" % ( v[size-1].co[0], v[size-1].co[1], v[size-1].co[2] ) writer.write( dataString ) elif ( self._dataType == 'NORMAL' ): if ( niceFormat ): for n in self._data: dataString = "\n%.6f %.6f %.6f" % ( n[0], n[1], n[2] ) writer.write( dataString ) else: n = self._data dataString = "%.6f %.6f %.6f " % ( n[0][0], n[0][1], n[0][2] ) writer.write( dataString ) size = len( self._data ) for i in range( 1, size - 1 ): dataString = "%.6f %.6f %.6f " % ( n[i][0], n[i][1], n[i][2] ) writer.write( dataString ) dataString = "%.6f %.6f %.6f" % ( n[size-1][0], n[size-1][1], n[size-1][2] ) writer.write( dataString ) elif ( self._dataType == 'UV' ): if ( niceFormat ): for uv in self._data: dataString = "\n%.6f %.6f" % ( uv[0], uv[1] ) writer.write( dataString ) else: uv = self._data dataString = "%.6f %.6f " % ( uv[0][0], uv[0][1] ) writer.write( dataString ) size = len( self._data ) for i in range( 1, size - 1 ): dataString = "%.6f %.6f " % ( uv[i][0], uv[i][1] ) writer.write( dataString ) dataString = "%.6f %.6f" % ( uv[size-1][0], uv[size-1][1] ) writer.write( dataString ) elif ( self._dataType == 'ANIMATIONINPUT-MATRIX' ): if ( niceFormat ): for tValue in self._data: dataString = "\n%.6f" % ( tValue / fps ) writer.write( dataString ) else: tValue = self._data size = len( self._data ) if ( size > 1 ): dataString = '%.6f ' % ( tValue[0] / fps ) writer.write( dataString ) for i in range( 1, size - 1 ): dataString = '%.6f ' % ( tValue[i] / fps ) writer.write( dataString ) dataString = "%.6f" % ( tValue[size-1] / fps ) writer.write( dataString ) elif ( self._dataType == 'ANIMATIONINPUT' ): if ( niceFormat ): for tValue in self._data: dataString = "\n%.6f" % ( tValue.pt[0] / fps ) writer.write( dataString ) else: tValue = self._data size = len( self._data ) if ( size > 1 ): dataString = '%.6f ' % ( tValue[0].pt[0] / fps ) writer.write( dataString ) for i in range( 1, size - 1 ): dataString = '%.6f ' % ( tValue[i].pt[0] / fps ) writer.write( dataString ) dataString = "%.6f" % ( tValue[size-1].pt[0] / fps ) writer.write( dataString ) elif ( self._dataType == 'ANIMATIONOUTPUT-MATRIX' ): if ( niceFormat ): dataString = '' for m in self._data: dataString = '\n%.6f %.6f %.6f %.6f\n%.6f %.6f %.6f %.6f\n%.6f %.6f %.6f %.6f\n%.6f %.6f %.6f %.6f' % ( m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3] ) writer.write( dataString ) else: m = self._data[ 0 ] dataString = '%.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f ' % ( m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3] ) writer.write( dataString ) size = len( self._data ) for i in range( 1, size - 1 ): m = self._data[ i ] dataString = '%.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f ' % ( m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3] ) writer.write( dataString ) m = self._data[ size - 1 ] dataString = '%.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f' % ( m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3] ) writer.write( dataString ) elif ( self._dataType == 'ANIMATIONOUTPUT-SHININESS' ): if ( niceFormat ): for tValue in self._data: dataString = "\n%.6f" % ( tValue.pt[1] / 4.0 ) writer.write( dataString ) else: tValue = self._data dataString = "%.6f " % ( tValue[0].pt[1] / 4.0 ) writer.write( dataString ) size = len( self._data ) for i in range( 1, size - 1 ): dataString = '%.6f ' % ( tValue[i].pt[1] / 4.0 ) writer.write( dataString ) dataString = "%.6f" % ( tValue[size-1].pt[1] / 4.0 ) writer.write( dataString ) elif ( self._dataType == 'ANIMATIONOUTPUT-ALPHA' ): if ( niceFormat ): for tValue in self._data: dataString = "\n%.6f" % ( 1.0 - tValue.pt[1] ) writer.write( dataString ) else: tValue = self._data dataString = "%.6f " % ( 1.0 - tValue[0].pt[1] ) writer.write( dataString ) size = len( self._data ) for i in range( 1, size - 1 ): dataString = '%.6f ' % ( 1.0 - tValue[i].pt[1] ) writer.write( dataString ) dataString = "%.6f" % ( 1.0 - tValue[size-1].pt[1] ) writer.write( dataString ) elif ( self._dataType == 'ANIMATIONOUTPUT-ROTATION' ): if ( niceFormat ): for tValue in self._data: dataString = "\n%.6f" % ( tValue.pt[1] * 10.0 ) writer.write( dataString ) else: tValue = self._data dataString = "%.6f " % ( tValue[0].pt[1] * 10.0 ) writer.write( dataString ) size = len( self._data ) for i in range( 1, size - 1 ): dataString = '%.6f ' % ( tValue[i].pt[1] * 10.0 ) writer.write( dataString ) dataString = "%.6f" % ( tValue[size-1].pt[1] * 10.0 ) writer.write( dataString ) elif ( self._dataType == 'ANIMATIONOUTPUT' ): if ( niceFormat ): for tValue in self._data: dataString = "\n%.6f" % ( tValue.pt[1] ) writer.write( dataString ) else: tValue = self._data dataString = "%.6f " % ( tValue[0].pt[1] ) writer.write( dataString ) size = len( self._data ) for i in range( 1, size - 1 ): dataString = '%.6f ' % ( tValue[i].pt[1] ) writer.write( dataString ) dataString = "%.6f" % ( tValue[size-1].pt[1] ) writer.write( dataString ) else: # Replace '\n' with '\n + indent + addindent' if ( niceFormat ): replaceString = '\n' + indent + addindent self._data = self._data.replace( '\n', replaceString ) _write_data( writer, self._data ) if ( niceFormat ): writer.write("%s%s" % ( newl + indent, self.tagName, newl ) ) else: writer.write("%s" % ( self.tagName, newl ) ) class _IntArrayElement( Element ): pass class _NameArrayElement( Element ): pass class _InputElement( Element ): _idx = None _semantic = None _source = None def __init__( self, idx, semantic, source ): Element.__init__( self, "input" ) self._idx = idx self._semantic = semantic self._source = source if not ( self._idx == None ): self.setAttribute( "idx", "%i" % (self._idx) ) if not ( self._semantic == None ): self.setAttribute( "semantic", CP.IS.str[ self._semantic ] ) if not ( self._source == None ): self.setAttribute( "source", "#" + self._source ) class _MaterialElement( Element ): _id = None _name = None def __init__( self, id, name ): Element.__init__( self, "material" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", id ) if not ( self._name == None ): self.setAttribute( "name", name ) class _ShaderElement( Element ): _id = None _name = None def __init__( self, id, name ): Element.__init__( self, "shader" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "id", self._name ) class _PassElement( Element ): def __init__( self ): Element.__init__( self, "pass" ) class _TechniqueElement( Element ): _profile = None def setProfile( self, profile ): self._profile = profile def __init__( self, profile ): Element.__init__( self, "technique" ) self._profile = profile if not ( self._profile == None ): self.setAttribute( "profile", CP.str[ self._profile ] ) class _ImageElement( Element ): _id = None _name = None _height = None _width = None _depth = None _source = None _format = None def setIdAndName( self, arg ): _id = arg _name = arg self.setAttribute( "id", _id ) self.setAttribute( "name", _name ) def setWidth( self, width ): self._width = width self.setAttribute( "width", "%i" % (self._width) ) def setHeight( self, height ): self._height = height self.setAttribute( "height", "%i" % (self._height) ) def setSource( self, source ): self._source = source self.setAttribute( "source", self._source ) def __init__( self, id, name, height, width, depth, source, format ): Element.__init__( self, "image" ) self._id = id self._name = name self._height = height self._width = width self._depth = depth self._source = source self._format = format if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "name", self._name ) if not ( self._height == None ): self.setAttribute( "height", "%i" % self._height ) if not ( self._width == None ): self.setAttribute( "width", "%i" % self._width ) if not ( self._depth == None ): self.setAttribute( "depth", "%i" % self._depth ) if not ( self._source == None ): self.setAttribute( "source", self._source ) if not ( self._format == None ): self.setAttribute( "format", self._format ) class _LightElement( Element ): _id = None _name = None _type = None def __init__( self, id, name, type ): Element.__init__( self, "light" ) self._id = id self._name = name self._type = type if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "name", self._name ) if not ( self._type == None ): self.setAttribute( "type", "%s" % CP.LIGHT.str[ self._type ] ) class _TextureElement( Element ): _id = None _name = None def __init__( self, id, name ): Element.__init__( self, "texture" ) self._id = id self._name = name if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "name", self._name ) class _ProgramElement( Element ): _id = None _name = None _url = None def __init__( self, id, name, url ): Element.__init__( self, "program" ) self._id = id self._name = name self._url = url if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "name", self._name ) if not ( self._url == None ): self.setAttribute( "url", self._url ) class _CodeElement( Element ): pass class _EntryElement( Element ): pass class _ParamElement( Element, Childless ): _id = None _name = None _type = None _flow = None _semantic = None _sid = None _data = None def setData( self, data ): self._data = data def getData( self, data ): return self._data def __init__( self, id, name, type, flow, semantic, sid ): Element.__init__( self, "param" ) self._id = id self._name = name self._type = type self._flow = flow self._semantic = semantic self._sid = sid if not ( self._id == None ): self.setAttribute( "id", self._id ) if not ( self._name == None ): self.setAttribute( "name", CP.PN.str[ self._name ] ) if not ( self._type == None ): self.setAttribute( "type", self._type ) if not ( self._flow == None ): self.setAttribute( "flow", CP.FT.str[ self._flow ] ) if not ( self._semantic == None ): self.setAttribute( "semantic", self._semantic ) if not ( self._sid == None ): self.setAttribute( "sid", self._sid ) # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _MatrixElement( Element, Childless ): _sid = None _data = None def setData( self, data ): self._data = data def getData( self, data ): return self._data def __init__( self, sid ): Element.__init__( self, "matrix" ) self._sid = sid if not ( self._sid == None ): self.setAttribute( "sid", self._sid ) # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): global niceFormat writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: # Replace '\n' with '\n + indent + addindent' if ( niceFormat ): replaceString = '\n' + indent + addindent self._data = self._data.replace( '\n', replaceString ) writer.write(">%s%s%s" % ( self._data, newl + indent, self.tagName, newl ) ) else: writer.write(">%s%s" % ( self._data, self.tagName, newl ) ) class _LookAtElement( Element ): pass class _PerspectiveElement( Element ): pass class _RotateElement( Element, Childless ): _sid = None _data = None def setData( self, data ): self._data = data def getData( self, data ): return self._data def __init__( self, sid ): Element.__init__( self, "rotate" ) self._sid = sid if not ( self._sid == None ): self.setAttribute( "sid", self._sid ) # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _ScaleElement( Element, Childless ): _sid = None _data = None def setData( self, data ): self._data = data def getData( self, data ): return self._data def __init__( self, sid ): Element.__init__( self, "scale" ) self._sid = sid if not ( self._sid == None ): self.setAttribute( "sid", self._sid ) # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _SkewElement( Element ): pass class _TranslateElement( Element, Childless ): _sid = None _data = None def setData( self, data ): self._data = data def getData( self, data ): return self._data def __init__( self, sid ): Element.__init__( self, "translate" ) self._sid = sid if not ( self._sid == None ): self.setAttribute( "sid", self._sid ) # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _AuthorElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "author" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _AuthoringToolElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "authoring_tool" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _CreatedElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "created" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _ModifiedElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "modified" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _RevisionElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "modified" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _SourceDataElement( Element, Childless ): _data = None def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "source_data" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: # Fast data write # writer.write(">%s%s" % (self._data, self.tagName, newl ) ) writer.write( ">" ) _write_data( writer, self._data ) writer.write( "%s" % (self.tagName, newl ) ) class _CopyrightElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "copyright" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _TitleElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "title" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _SubjectElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "subject" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _KeywordsElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "keywords" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _CommentsElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "comments" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _UnitElement( Element, Childless ): _name = None _meter = None def __init__( self, name, meter ): Element.__init__( self, "unit" ) self._name = name self._meter = meter if not ( self._name == None ): self.setAttribute( "name", self._name ) if not ( self._meter == None ): self.setAttribute( "meter", self._meter ) # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") writer.write( "/>%s" % newl ) class _UpAxisElement( Element, Childless ): _data = "" def setData( self, data ): self._data = data def getData( self ): return self._data def __init__( self, data ): Element.__init__( self, "up_axis" ) if not ( data == None ): self._data = data # Overloaded writexml function so we can keep data within one line # This implementation was taken from the Python 2.3 minidom impl. # of class Element def writexml( self, writer, indent="", addindent="", newl="" ): writer.write(indent+"<" + self.tagName) attrs = self._get_attributes() a_names = attrs.keys() a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data( writer, attrs[a_name].value) writer.write("\"") if ( self._data == None ): writer.write( "/>%s" % newl ) else: writer.write(">%s%s" % (self._data, self.tagName, newl ) ) class _AssetElement( Element ): def __init__( self ): Element.__init__( self, "asset" ) class _ExtraElement( Element ): pass # ---------------------------------------------- # Utility functions # ---------------------------------------------- def toAngle( radians ): return ( radians * 180 ) / 3.14159265 """ Return True if IPO curveName applies to a transform """ def isTransformCurve( curveName ): if ( curveName == 'LocX' or curveName == 'LocY' or curveName == 'LocZ' or curveName == 'RotX' or curveName == 'RotY' or curveName == 'RotZ' or curveName == 'SizeX' or curveName == 'SizeY' or curveName == 'SizeZ' ): return True return False """ Return True if IPO curveName applies to a translate """ def isTranslateCurve( curveName ): if ( curveName == 'LocX' or curveName == 'LocY' or curveName == 'LocZ' ): return True return False """ Return True if IPO curveName applies to a rotation """ def isRotationCurve( curveName ): if ( curveName == 'RotX' or curveName == 'RotY' or curveName == 'RotZ' ): return True return False """ Return a COLLADA param element from IPO curve name """ def getParamElementFromCurveName( curveName ): # Output TIME if no correct output could be found... (yes kind of stupid # I know) paramOutput = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT ) if ( curveName == 'LocX' or curveName == 'SizeX'): paramOutput = dae.createParamElement( None, CP.PN.X, "float", CP.FT.OUT ) elif ( curveName == 'LocY' or curveName == 'SizeY' ): paramOutput = dae.createParamElement( None, CP.PN.Y, "float", CP.FT.OUT ) elif ( curveName == 'LocZ' or curveName == 'SizeZ' ): paramOutput = dae.createParamElement( None, CP.PN.Z, "float", CP.FT.OUT ) elif ( curveName == 'RotX' or curveName == 'RotY' or curveName == 'RotZ' ): paramOutput = dae.createParamElement( None, CP.PN.ANGLE, "float", CP.FT.OUT ) elif ( curveName == 'R' or curveName == 'ColR' or curveName == 'SpecR' or curveName == 'MirR' ): paramOutput = dae.createParamElement( None, CP.PN.R, "float", CP.FT.OUT ) elif ( curveName == 'G' or curveName == 'ColG' or curveName == 'SpecG' or curveName == 'MirG' ): paramOutput = dae.createParamElement( None, CP.PN.G, "float", CP.FT.OUT ) elif ( curveName == 'B' or curveName == 'ColB' or curveName == 'SpecB' or curveName == 'MirB' ): paramOutput = dae.createParamElement( None, CP.PN.B, "float", CP.FT.OUT ) elif ( curveName == 'Alpha' ): paramOutput = dae.createParamElement( None, CP.PN.A, "float", CP.FT.OUT ) elif ( curveName == 'Ref' ): paramOutput = dae.createParamElement( None, CP.PN.REFLECTIVITY, "float", CP.FT.OUT ) elif ( curveName == 'Hard' ): paramOutput = dae.createParamElement( None, CP.PN.SHININESS, "float", CP.FT.OUT ) return paramOutput """ Return a COLLADA Target written according to the Address Syntax specification. The sid values (except the Common Profile constants) are my own Blender specific values. However they follow the Maya plug-in sid transform syntax. """ def getTargetNameFromCurveName( curveName ): if ( curveName == 'LocX' ): return 'translate.X' elif ( curveName == 'LocY' ): return 'translate.Y' elif ( curveName == 'LocZ' ): return 'translate.Z' elif ( curveName == 'RotX' ): return 'rotateX.ANGLE' elif ( curveName == 'RotY' ): return 'rotateY.ANGLE' elif ( curveName == 'RotZ' ): return 'rotateZ.ANGLE' elif ( curveName == 'SizeX' ): return 'scale.X' elif ( curveName == 'SizeY' ): return 'scale.Y' elif ( curveName == 'SizeZ' ): return 'scale.Z' elif ( curveName == 'R' ): return 'diffuse.R' elif ( curveName == 'G' ): return 'diffuse.G' elif ( curveName == 'B' ): return 'diffuse.B' elif ( curveName == 'Alpha' ): return 'transparency' elif ( curveName == 'SpecR' ): return 'specular.R' elif ( curveName == 'SpecG' ): return 'specular.G' elif ( curveName == 'SpecB' ): return 'specular.B' elif ( curveName == 'MirR' ): return 'reflective.R' elif ( curveName == 'MirR' ): return 'reflective.G' elif ( curveName == 'MirR' ): return 'reflective.B' elif ( curveName == 'Ref' ): return 'reflectivity' elif ( curveName == 'Hard' ): return 'shininess' else: return '' # ---------------------------------------------- # BLENDER to COLLADA helper functions # ---------------------------------------------- # --- Write mesh information to dae file --- def writeLight( libraryElement, light ): lightName = light.name lightID = lightName + "-Lib" lightType = light.getType( ) lightFlags = light.getMode( ) distance = light.getDist( ) energy = light.getEnergy( ) quad1 = light.getQuad1( ) quad2 = light.getQuad2( ) # Blender LAMP type --> Collada POINT type if ( lightType == 0 ): lightElement = dae.createLightElement( lightID, lightName, CP.LIGHT.POINT ) colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, None ) colorParam.setData( "%.6f %.6f %.6f" % ( light.col[ 0 ], light.col[ 1 ], light.col[ 2 ] ) ) attenuationParam = dae.createParamElement( None, CP.PN.ATTENUATION, "token", CP.FT.IN, None, None ) attenuationScaleParam = dae.createParamElement( None, CP.PN.ATTENUATION_SCALE, "float", CP.FT.IN, None, None ) if ( lightFlags & light.Modes[ 'Quad' ] ): attenuationScale = 2.0 / ( quad2 * distance * energy ) attenuationParam.setData( "QUADRATIC" ) attenuationScaleParam.setData( "%.6f" % ( attenuationScale ) ) else: attenuationScale = 2.0 / ( distance * energy ) attenuationParam.setData( "LINEAR" ) attenuationScaleParam.setData( "%.6f" % ( attenuationScale ) ) lightElement.appendChild( colorParam ) lightElement.appendChild( attenuationParam ) lightElement.appendChild( attenuationScaleParam ) libraryElement.appendChild( lightElement ) # Blender SUN type --> Collada DIRECTIONAL type elif ( lightType == 1 ): lightElement = dae.createLightElement( lightID, lightName, CP.LIGHT.DIRECTIONAL ) colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, None ) colorParam.setData( "%.6f %.6f %.6f" % ( light.col[ 0 ], light.col[ 1 ], light.col[ 2 ] ) ) lightElement.appendChild( colorParam ) libraryElement.appendChild( lightElement ) # Blender SPOT type --> Collada SPOT type elif ( lightType == 2 ): lightElement = dae.createLightElement( lightID, lightName, CP.LIGHT.SPOT ) colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, None ) colorParam.setData( "%.6f %.6f %.6f" % ( light.col[ 0 ], light.col[ 1 ], light.col[ 2 ] ) ) attenuationParam = dae.createParamElement( None, CP.PN.ATTENUATION, "token", CP.FT.IN, None, None ) attenuationScaleParam = dae.createParamElement( None, CP.PN.ATTENUATION_SCALE, "float", CP.FT.IN, None, None ) # Is this the correct attenuation algorithm? if ( lightFlags & light.Modes[ 'Quad' ] ): attenuationScale = 2.0 / ( quad2 * distance * energy ) attenuationParam.setData( "QUADRATIC" ) attenuationScaleParam.setData( "%.6f" % ( attenuationScale ) ) else: attenuationScale = 2.0 / ( distance * energy ) attenuationParam.setData( "LINEAR" ) attenuationScaleParam.setData( "%.6f" % ( attenuationScale ) ) # Export ANGLE, FALLOFF and FALLOFF_SCALE angle = light.getSpotSize( ) angleParam = dae.createParamElement( None, CP.PN.ANGLE, "float", CP.FT.IN, None, None ) angleParam.setData( "%.6f" % angle ) falloff = light.getSpotSize( ) falloffParam = dae.createParamElement( None, CP.PN.FALLOFF, "token", CP.FT.IN, None, None ) falloffParam.setData( "LINEAR" ) falloffScale = light.getSpotBlend( ) * 128.0 falloffScaleParam = dae.createParamElement( None, CP.PN.FALLOFF_SCALE, "float", CP.FT.IN, None, None ) falloffScaleParam.setData( "%.6f" % falloffScale ) lightElement.appendChild( colorParam ) lightElement.appendChild( attenuationParam ) lightElement.appendChild( attenuationScaleParam ) lightElement.appendChild( angleParam ) lightElement.appendChild( falloffParam ) lightElement.appendChild( falloffScaleParam ) libraryElement.appendChild( lightElement ) elif ( lightType == 3 ): lightElement = dae.createLightElement( lightID, lightName, CP.LIGHT.AMBIENT ) colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, None ) colorParam.setData( "%.6f %.6f %.6f" % ( light.col[ 0 ], light.col[ 1 ], light.col[ 2 ] ) ) lightElement.appendChild( colorParam ) libraryElement.appendChild( lightElement ) elif ( lightType == 4 ): print "Warning! Export of light type Area not supported! Light will not export." elif ( lightType == 5 ): print "Warning! Export of light type Photon not supported! Light will not export." # --- Write mesh information to dae file --- def writeMesh( libraryElement, mesh ): meshName = mesh.name meshID = mesh.name + "-Lib" hasFaceUV = mesh.hasFaceUV() nrVerts = len( mesh.verts ) nrFaces = len( mesh.faces ) geometry = dae.createGeometryElement( meshID, meshName ) meshElement = dae.createMeshElement( ) posID = meshName + "-Pos" normalID = meshName + "-Normal" uvID = meshName + "-UV1" position = dae.createSourceElement( posID, posID ) normal = dae.createSourceElement( normalID, normalID ) uv = dae.createSourceElement( uvID, uvID ) posArrayID = posID + "-Array" noArrayID = normalID + "-Array" uvArrayID = uvID + "-Array" floatArrayPos = dae.createFloatArrayElement( nrVerts * 3, posArrayID, posArrayID ) floatArrayNo = dae.createFloatArrayElement( -1, noArrayID, noArrayID ) floatArrayUV = dae.createFloatArrayElement( -1, uvArrayID, uvArrayID ) # Set elements data as list data for faster output! floatArrayPos.setDataType( 'POSITION' ) floatArrayNo.setDataType( 'NORMAL' ) floatArrayUV.setDataType( 'UV' ) # Output nice format for vertex data # TODO: Make this routine better # startTime = sys.time() # posDataArray = array('f') # posData = "" ## for v in mesh.verts: ## #posDataArray.append( v.co[ 0 ] ) ## #posDataArray.append( v.co[ 1 ] ) ## #posDataArray.append( v.co[ 2 ] ) ## posData += "\n%.6f %.6f %.6f" % ( v.co[0], v.co[1], v.co[2] ) posData = mesh.verts # Get normal and UV data #no = "" no = [] #st = "" st = [] nrExclusiveVertices = 0 nrUVCoords = 0 faceNr = 0 for f in mesh.faces: nrVert = len( f.v ) if ( (nrVert == 3) or (nrVert == 4 ) ): if ( f.smooth != 0 ): # If smooth than fetch normal for every vertex in face for v2 in f.v: #no += "\n%.6f %.6f %.6f" % ( v2.no[0], v2.no[1], v2.no[2] ) no.append( v2.no ) nrExclusiveVertices += 1 elif ( f.smooth == 0 ): # FIXME: There is unknown bug here... for i in f.v: if ( len( f.no ) > 0 ): #no += "\n%.6f %.6f %.6f" % ( f.no[0], f.no[1], f.no[2] ) no.append( f.no ) else: print "Warning! Face has no normal. Outputing (0,0,0) as normal instead!" # TODO: Calculate normal instead! #no += "\n%.6f %.6f %.6f" % ( 0.0, 0.0, 0.0 ) no.append( [ 0.0, 0.0, 0.0 ] ) nrExclusiveVertices += 1 if ( hasFaceUV ): # Mesh has face UV set so let's export UV coordinates for i in range( nrVert ): #st += "\n%.6f %.6f" % ( f.uv[i][0], f.uv[i][1] ) st.append( f.uv[i] ) nrUVCoords += 1 else: print "Warning: Face in %s" % meshName + " is not a triangle or quad! Face ignored." # endTime = sys.time( ) # print "Getting mesh data time: %.6f" % ( endTime - startTime ) floatArrayNo.setCount( nrExclusiveVertices * 3 ) floatArrayNo.setData( no ) floatArrayPos.setData( posData ) #floatArrayPos.setData( posDataArray.tostring( ) ) normal.appendChild( floatArrayNo ) position.appendChild( floatArrayPos ) if ( hasFaceUV ): floatArrayUV.setCount( nrUVCoords * 2 ) floatArrayUV.setData( st ) uv.appendChild( floatArrayUV ) meshElement.appendChild( position ) meshElement.appendChild( normal ) # Write COMMON technique elements techniquePos = dae.createTechniqueElement( CP.COMMON ) techniqueNormal = dae.createTechniqueElement( CP.COMMON ) accessorPos = dae.createAccessorElement( nrExclusiveVertices, posArrayID, posArrayID + "-Accessor", 0, 3 ) accessorNormal = dae.createAccessorElement( nrExclusiveVertices, noArrayID, noArrayID + "-Accessor", 0 , 3 ) paramPosX = dae.createParamElement( None, CP.PN.X, "float", None ) paramPosY = dae.createParamElement( None, CP.PN.Y, "float", None ) paramPosZ = dae.createParamElement( None, CP.PN.Z, "float", None ) paramNoX = dae.createParamElement( None, CP.PN.X, "float", None ) paramNoY = dae.createParamElement( None, CP.PN.Y, "float", None ) paramNoZ = dae.createParamElement( None, CP.PN.Z, "float", None ) accessorPos.appendChild( paramPosX ) accessorPos.appendChild( paramPosY ) accessorPos.appendChild( paramPosZ ) accessorNormal.appendChild( paramNoX ) accessorNormal.appendChild( paramNoY ) accessorNormal.appendChild( paramNoZ ) techniquePos.appendChild( accessorPos ) position.appendChild( techniquePos ) techniqueNormal.appendChild( accessorNormal ) normal.appendChild( techniqueNormal ) if ( hasFaceUV ): meshElement.appendChild( uv ) techniqueUV = dae.createTechniqueElement( CP.COMMON ) accessorUV = dae.createAccessorElement( nrUVCoords, uvArrayID, uvArrayID + "-Accessor", 0, 2 ) paramS = dae.createParamElement( None, CP.PN.S, "float", None ) paramT = dae.createParamElement( None, CP.PN.T, "float", None ) accessorUV.appendChild( paramS ) accessorUV.appendChild( paramT ) techniqueUV.appendChild( accessorUV ) uv.appendChild( techniqueUV ) # Write vertices and polygons information verticesName = meshName + "-Vertices" vertices = dae.createVerticesElement( verticesName, verticesName, nrExclusiveVertices ) vInput = dae.createInputElement( None, CP.IS.POSITION, posID ) # TODO: Write UV here if we have sticky vertices. Also write normal data # if the whole mesh is smooth # Write polygon element materials = mesh.getMaterials( 1 ) if ( len( materials ) > 1 ): print "Warning! Mesh has multiple materials. Will only export the first one" # TODO: Write polygon element for each material material = None polygons = None if len( materials ) > 0: material = materials[ 0 ] if ( material != None ): materialSource = material.getName( ) + "-Lib" polygons = dae.createPolygonsElement( nrFaces, materialSource ) else: polygons = dae.createPolygonsElement( nrFaces ) else: polygons = dae.createPolygonsElement( nrFaces ) # Write input semantics for polygons vertexInput = dae.createInputElement( 0, CP.IS.VERTEX, verticesName ) normalInput = dae.createInputElement( 1, CP.IS.NORMAL, normalID ) polygons.appendChild( vertexInput ) polygons.appendChild( normalInput ) if ( hasFaceUV ): uvInput = dae.createInputElement( 2, CP.IS.TEXCOORD, uvID ) polygons.appendChild( uvInput ) # Write

elements # NOTE: index here points to normal and (if present) texcoord index in floatarray index = -1 for f in mesh.faces: pData = "" nrVertices = len( f.v ) if ( (nrVertices == 3) or (nrVertices == 4 ) ): for v in f.v: index += 1 if ( hasFaceUV ): pData = pData + "%i %i %i" % ( v.index, index, index ) + " " else: pData = pData + "%i %i" % ( v.index, index ) + " " pData = pData.strip() p = dae.createPElement( ) p.setData( pData ) polygons.appendChild( p ) vertices.appendChild( vInput ) meshElement.appendChild( vertices ) meshElement.appendChild( polygons ) geometry.appendChild( meshElement ) libraryElement.appendChild( geometry ) # Blender to OpenGL materials # With help from Nathan (Waffler at Elysiun) def writeMaterial( libraryElement, material ): name = material.getName( ) id = name + "-Lib" materialElement = dae.createMaterialElement( id, name ) # Create common phong shader with one phong pass shaderElement = dae.createShaderElement( None, name + "-Phong" ) technique = dae.createTechniqueElement( CP.COMMON ) # Get material data col = material.getRGBCol( ) speccol = material.getSpecCol( ) spec = material.getSpec( ) * 0.5 ambient = material.getAmb( ) emit = material.getEmit( ) transparency = 1.0 - material.getAlpha( ) ref = material.getRef( ) refcol = material.getMirCol() shininess = material.getHardness() / 4.0 # refID = material.getIOR() mtextures = material.getTextures( ) passElement = dae.createPassElement( ) # TODO: Perhaps add an option to split texture channels into # different elements instead # Input semantics for texture channel(s) for mtex in mtextures: if not ( mtex == None ): texture = mtex.tex if ( texture.type == Texture.Types.IMAGE ): texSource = texture.getName() + "-Lib" input = dae.createInputElement( None, CP.IS.TEXTURE, texSource ) passElement.appendChild( input ) # Appereantly I cannot access the shaders so ... output # PHONG for now phongProgram = dae.createProgramElement( None, None, CP.PIAU.str[ CP.PIAU.PHONG ] ) # PHONG PARAMS colorParam = dae.createParamElement( None, CP.PN.COLOR, "float3", CP.FT.IN, None, 'color' ) colorParam.setData( "%.6f %.6f %.6f" % ( col[0], col[1], col[2] ) ) ambientParam = dae.createParamElement( None, CP.PN.AMBIENT, "float3", CP.FT.IN, None, 'ambient' ) ambientParam.setData( "%.6f %.6f %.6f" % ( ambient * col[0], ambient * col[1], ambient * col[2] ) ) diffuseParam = dae.createParamElement( None, CP.PN.DIFFUSE, "float3", CP.FT.IN, None, 'diffuse' ) diffuseParam.setData( "%.6f %.6f %.6f" % ( col[0], col[1], col[2] ) ) #transparencyParam = dae.createParamElement( None, CP.PN.TRANSPARENCY, "float", CP.FT.IN ) #transparencyParam.setData( "%.6f" % transparency ) specularParam = dae.createParamElement( None, CP.PN.SPECULAR, "float3", CP.FT.IN, None, 'specular' ) specularParam.setData( "%.6f %.6f %.6f" % ( speccol[0] * spec, speccol[1] * spec, speccol[2] * spec ) ) emissionParam = dae.createParamElement( None, CP.PN.EMISSION, "float3", CP.FT.IN, None, 'emission' ) emissionParam.setData( "%.6f %.6f %.6f" % ( emit * col[0], emit * col[1], emit * col[2] ) ) shininessParam = dae.createParamElement( None, CP.PN.SHININESS, "float", CP.FT.IN, None, 'shininess' ) shininessParam.setData( "%.6f" % ( shininess ) ) # Output color as transparent color for now transparentParam = dae.createParamElement( None, CP.PN.TRANSPARENT, "float", CP.FT.IN, None, 'transparent' ) transparentParam.setData( "%.6f %.6f %.6f" % ( col[0], col[1], col[2] ) ) transparencyParam = dae.createParamElement( None, CP.PN.TRANSPARENCY, "float", CP.FT.IN, None, 'transparency' ) transparencyParam.setData( "%.6f" % ( transparency ) ) reflectParam = dae.createParamElement( None, CP.PN.REFLECTIVE, "float3", CP.FT.IN, None, 'reflective' ) reflectParam.setData( "%.6f %.6f %.6f" % ( refcol[0], refcol[1], refcol[2] ) ) reflectivityParam = dae.createParamElement( None, CP.PN.REFLECTIVITY, "float", CP.FT.IN, None,'reflectivity' ) reflectivityParam.setData( "%.6f" % ( ref ) ) # refractiveParam = dae.createParamElement( None, CP.PN.REFRACTIVEINDEX, "float3", CP.FT.IN ) # refractiveParam.setData( "%.6f %.6f %.6f" % ( refID[0], refID[1], refID[2] ) ) # TODO: Output SHININESS here. Perhaps calc from # Specular HARDNESS and SPECULARITY (?) phongProgram.appendChild( colorParam ) phongProgram.appendChild( diffuseParam ) phongProgram.appendChild( ambientParam ) phongProgram.appendChild( transparencyParam ) phongProgram.appendChild( specularParam ) phongProgram.appendChild( emissionParam ) phongProgram.appendChild( shininessParam ) phongProgram.appendChild( transparentParam ) phongProgram.appendChild( transparencyParam ) phongProgram.appendChild( reflectParam ) phongProgram.appendChild( reflectivityParam ) # phongProgram.appendChild( refractiveParam ) passElement.appendChild( phongProgram ) technique.appendChild( passElement ) shaderElement.appendChild( technique ) materialElement.appendChild( shaderElement ) libraryElement.appendChild( materialElement ) # --- Write Image information to dae file --- def writeImage( libraryElement, image ): name = image.getName( ) id = name + "-Lib" imageElement = dae.createImageElement( id, name ) # Getting the image size seems to generate # python errors sometimes (for some reason)... # imageElement.setWidth( image.size[0] ) # imageElement.setHeight( image.size[1] ) filename = sys.expandpath( image.getFilename( ) ) filename = filename.replace( "//", "/" ) filename = filename.replace( sys.sep, "/" ) filename = "file://" + filename imageElement.setSource( filename ) libraryElement.appendChild( imageElement ) def writeTexture( libraryElement, texture ): name = texture.getName( ) id = name + "-Lib" if ( texture.getType() == "Image" ): # Create DIFFUSE texture element texID = name + "-Lib" textureElement = dae.createTextureElement( texID, name ) # TODO: Depending on type here create different params and techniques textureParamElement = dae.createParamElement( None, CP.PN.DIFFUSE, "float3", CP.FT.OUT ) textureElement.appendChild( textureParamElement ) # Create COMMON Technique technique = dae.createTechniqueElement( CP.COMMON ) textureElement.appendChild( technique ) source = texture.getImage( ) if not ( source == None ): sourceName = source.getName( ) + "-Lib" input = dae.createInputElement( None, CP.IS.IMAGE, sourceName ) technique.appendChild( input ) libraryElement.appendChild( textureElement ) else: print "Warning! Texture is not of Image type. Texture not exported!" """ Write animation information to dae file """ def writeAnimation( libraryElement, ipo, ipoOwner ): global fps global exportBakedTransform ipoName = ipo.getName() ipoID = ipoName + "-Lib" curves = ipo.getCurves( ) animationElement = dae.createAnimationElement( ipoID, ipoName ) transformInputElement = None transformOutputElement = None transformSamplerElement = None transformChannelElement = None # Store information about curves before creating sources transformCurves = [] otherCurves = [] transformXMin = 10000 transformXMax = -10000 # Get curve types for curve in curves: curveName = curve.getName( ) if ( exportBakedTransform and isTransformCurve( curveName ) ): transformCurves.append( curve ) # Get control points (keyframes) keyFrames = curve.getPoints( ) nrKeyFrames = len( keyFrames ) # Get the min and max values from this curve for keyFrame in keyFrames: points = keyFrame.getPoints( ) if ( points[ 0 ] < transformXMin ): transformXMin = int( points[ 0 ] ) if ( points[ 0 ] > transformXMax ): transformXMax = int( points[ 0 ] ) else: otherCurves.append( curve ) # Check for curves... nrTransformCurves = len( transformCurves ) nrOtherCurves = len( otherCurves ) nrCurves = nrTransformCurves + nrOtherCurves if ( nrCurves == 0 ): return # Calculate and Write baked transform sources if ( exportBakedTransform and ( nrTransformCurves > 0 ) ): animationInput = [] animationOutput = [] sourceID = ipoName + '-Transform-Input' transformInputElement = dae.createSourceElement( sourceID, sourceID ) floatArrayName = sourceID + "-Array" nrKeyFrames = ( transformXMax + 1 ) - transformXMin floatArrayTime = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName ) floatArrayTime.setData( animationInput ) floatArrayTime.setDataType( 'ANIMATIONINPUT-MATRIX' ) transformInputElement.appendChild( floatArrayTime ) # Create common profile technique technique = dae.createTechniqueElement( CP.COMMON ) # Create accessor element with TIME param accessorTime = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 ) paramTime = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT ) accessorTime.appendChild( paramTime ) technique.appendChild( accessorTime ) transformInputElement.appendChild( technique ) # animationElement.appendChild( sourceElement ) # Loop through Xmin to XMax for frame in range( transformXMin, transformXMax + 1 ): time = float( frame ) animationInput.append( time ) translateXYZ = Blender.Mathutils.Vector( ) rotateXYZ = Blender.Mathutils.Vector( ) sizeXYZ = Blender.Mathutils.Vector( ) # Gather data for curve in transformCurves: curveName = curve.name value = curve[time] # print '%s: Time: %i Value: %f' % ( curveName, time, value ) if ( curveName == 'LocX' ): translateXYZ.x = value elif ( curveName == 'LocY' ): translateXYZ.y = value elif ( curveName == 'LocZ' ): translateXYZ.z = value elif ( curveName == 'RotX' ): rotateXYZ.x = value * 10.0 elif ( curveName == 'RotY' ): rotateXYZ.y = value * 10.0 elif ( curveName == 'RotZ' ): rotateXYZ.z = value * 10.0 elif ( curveName == 'SizeX' ): sizeXYZ.x = value elif ( curveName == 'SizeY' ): sizeXYZ.y = value elif ( curveName == 'SizeZ' ): sizeXYZ.z = value # Now add these values to our transformMatrix transformMatrix = Blender.Mathutils.ScaleMatrix( sizeXYZ.x, 4, Mathutils.Vector( 1.0, 0.0, 0.0 ) ) transformMatrix *= Blender.Mathutils.ScaleMatrix( sizeXYZ.y, 4, Mathutils.Vector( 0.0, 1.0, 0.0 ) ) transformMatrix *= Blender.Mathutils.ScaleMatrix( sizeXYZ.z, 4, Mathutils.Vector( 0.0, 0.0, 1.0 ) ) transformMatrix *= Blender.Mathutils.RotationMatrix( rotateXYZ.x, 4, 'x' ) transformMatrix *= Blender.Mathutils.RotationMatrix( rotateXYZ.y, 4, 'y' ) transformMatrix *= Blender.Mathutils.RotationMatrix( rotateXYZ.z, 4, 'z' ) transformMatrix *= Blender.Mathutils.TranslationMatrix( translateXYZ ) # print transformMatrix animationOutput.append( transformMatrix ) # Write animation output source... sourceID2 = ipoName + '-Transform-Output' transformOutputElement = dae.createSourceElement( sourceID2, sourceID2 ) floatArrayName = sourceID2 + "-Array" floatArrayOutput = dae.createFloatArrayElement( nrKeyFrames * 16, floatArrayName, floatArrayName ) floatArrayOutput.setData( animationOutput ) floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-MATRIX' ) transformOutputElement.appendChild( floatArrayOutput ) # Create common profile technique techniqueOutput = dae.createTechniqueElement( CP.COMMON ) # Create accessor element with output param accessorOutput = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 16 ) # Create float4x4 param element paramOutput = dae.createParamElement( None, CP.PN.MATRIX4X4, "float4x4", CP.FT.OUT ) accessorOutput.appendChild( paramOutput ) techniqueOutput.appendChild( accessorOutput ) transformOutputElement.appendChild( techniqueOutput ) # animationElement.appendChild( sourceElement ) # Create sampler and channel elements for this baked transform sourceID = ipoName + '-Transform' samplerID = ipoName + '-Transform-Sampler' transformSamplerElement = dae.createSamplerElement( samplerID, samplerID ) inputInput = dae.createInputElement( None, CP.IS.INPUT, sourceID + '-Input' ) inputOutput = dae.createInputElement( None, CP.IS.OUTPUT, sourceID + '-Output' ) transformSamplerElement.appendChild( inputInput ) transformSamplerElement.appendChild( inputOutput ) #animationElement.appendChild( samplerElement ) # Create channel element channelID = ipoName + '-Transform-Channel' target = ipoOwner + '/transform' transformChannelElement = dae.createChannelElement( channelID, channelID, samplerID, target ) # Add transform sources first animationElement.appendChild( transformInputElement ) animationElement.appendChild( transformOutputElement ) ## # Else if transform is not baked: ## else: ## for curve in transformCurves: ## ## curveName = curve.getName( ) ## keyFrames = curve.getPoints( ) ## nrKeyFrames = len( keyFrames ) ## ## # Create input source element ## # TODO: If keyframe-input are same (same position-points) then perhaps create one input source? ## sourceID = ipoName + "-" + curveName + "-Input" ## sourceElement = dae.createSourceElement( sourceID, sourceID ) ## floatArrayName = sourceID + "-Array" ## floatArrayTime = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName ) ## floatArrayTime.setData( keyFrames ) ## floatArrayTime.setDataType( 'ANIMATIONINPUT' ) ## sourceElement.appendChild( floatArrayTime ) ## ## # Create common profile technique ## technique = dae.createTechniqueElement( CP.COMMON ) ## ## # Create accessor element with TIME param ## accessorTime = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 ) ## paramTime = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT ) ## ## accessorTime.appendChild( paramTime ) ## technique.appendChild( accessorTime ) ## sourceElement.appendChild( technique ) ## animationElement.appendChild( sourceElement ) ## ## ## # Create output source element ## sourceID2 = ipoName + "-" + curveName + "-Output" ## sourceElement = dae.createSourceElement( sourceID2, sourceID2 ) ## floatArrayName = sourceID2 + "-Array" ## floatArrayOutput = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName ) ## floatArrayOutput.setData( keyFrames ) ## if ( curveName == 'Hard' ): ## floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-SHININESS' ) ## else: ## floatArrayOutput.setDataType( 'ANIMATIONOUTPUT' ) ## ## sourceElement.appendChild( floatArrayOutput ) ## ## # Create common profile technique ## techniqueOutput = dae.createTechniqueElement( CP.COMMON ) ## ## # Create accessor element with output param ## accessorOutput = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 ) ## ## # Create different params depending on curve name (this should be driven channel for objects but ## # for now let's use the curve name because that seems to work) ## paramOutput = getParamElementFromCurveName( curveName ) ## ## ## accessorOutput.appendChild( paramOutput ) ## techniqueOutput.appendChild( accessorOutput ) ## sourceElement.appendChild( techniqueOutput ) ## animationElement.appendChild( sourceElement ) # Now that we have written transform channels write every other channel # TODO: Combine channels if possible (for example RGB sources -> material diffuse channel) for curve in otherCurves: curveName = curve.getName( ) keyFrames = curve.getPoints( ) nrKeyFrames = len( keyFrames ) # Create input source element # TODO: If keyframe-input are same (same position-points) then perhaps create one input source? sourceID = ipoName + "-" + curveName + "-Input" sourceElement = dae.createSourceElement( sourceID, sourceID ) floatArrayName = sourceID + "-Array" floatArrayTime = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName ) floatArrayTime.setData( keyFrames ) floatArrayTime.setDataType( 'ANIMATIONINPUT' ) sourceElement.appendChild( floatArrayTime ) # Create common profile technique technique = dae.createTechniqueElement( CP.COMMON ) # Create accessor element with TIME param accessorTime = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 ) paramTime = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT ) accessorTime.appendChild( paramTime ) technique.appendChild( accessorTime ) sourceElement.appendChild( technique ) animationElement.appendChild( sourceElement ) # Create output source element sourceID2 = ipoName + "-" + curveName + "-Output" sourceElement = dae.createSourceElement( sourceID2, sourceID2 ) floatArrayName = sourceID2 + "-Array" floatArrayOutput = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName ) floatArrayOutput.setData( keyFrames ) if ( curveName == 'Hard' ): floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-SHININESS' ) elif ( curveName == 'Alpha' ): floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-ALPHA' ) elif ( isRotationCurve( curveName ) ): floatArrayOutput.setDataType( 'ANIMATIONOUTPUT-ROTATION' ) else: floatArrayOutput.setDataType( 'ANIMATIONOUTPUT' ) sourceElement.appendChild( floatArrayOutput ) # Create common profile technique techniqueOutput = dae.createTechniqueElement( CP.COMMON ) # Create accessor element with output param accessorOutput = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 ) # Create different params depending on curve name (this should be driven channel for objects but # for now let's use the curve name because that seems to work) paramOutput = getParamElementFromCurveName( curveName ) accessorOutput.appendChild( paramOutput ) techniqueOutput.appendChild( accessorOutput ) sourceElement.appendChild( techniqueOutput ) animationElement.appendChild( sourceElement ) # Add transform sampler element first if ( transformSamplerElement != None ): animationElement.appendChild( transformSamplerElement ) # Add other samples for curve in otherCurves: curveName = curve.getName( ) sourceID = ipoName + "-" + curveName # Create sampler element samplerID = ipoName + "-" + curveName + '-Sampler' samplerElement = dae.createSamplerElement( samplerID, samplerID ) # Create input semantics inputInput = dae.createInputElement( None, CP.IS.INPUT, sourceID + '-Input' ) inputOutput = dae.createInputElement( None, CP.IS.OUTPUT, sourceID + '-Output' ) samplerElement.appendChild( inputInput ) samplerElement.appendChild( inputOutput ) animationElement.appendChild( samplerElement ) # Add transform channel element first if ( transformChannelElement != None ): animationElement.appendChild( transformChannelElement ) # TODO: Write other channels here for curve in otherCurves: curveName = curve.getName( ) sourceID = ipoName + "-" + curveName + '-Sampler' # Create channel element channelID = ipoName + "-" + curveName + '-Channel' # Get IPO Curve driver object # Important! If this is a animation channel that is not targetet against # a transform then target lib instead (add '-Lib' to target id) if ( not isTransformCurve( curveName ) ): target = ipoOwner + '-Lib/' + getTargetNameFromCurveName( curveName ) else: target = ipoOwner + '/' + getTargetNameFromCurveName( curveName ) channelElement = dae.createChannelElement( channelID, channelID, sourceID, target ) animationElement.appendChild( channelElement ) libraryElement.appendChild( animationElement ) # Write transform animation first ## if ( exportBakedTransform ): ## ## transformXMin = 1000.0 ## transformXMax = -1000.0 ## ## # Store which IPO curves that are transform based ## transformCurves = [] ## ## # Create sources for each curve ## for curve in curves: ## ## # Get information about our Ipo curve ## curveName = curve.getName( ) ## ## # Get control points (keyframes) ## keyFrames = curve.getPoints( ) ## nrKeyFrames = len( keyFrames ) ## ## # Get the min and max values from this curve ## if ( exportBakedTransform ): ## if ( isTransformCurve( curveName ) ): ## for keyFrame in keyFrames: ## points = keyFrame.getPoints( ) ## if ( points[ 0 ] < transformXMin ): ## transformXMin = points[ 0 ] ## if ( points[ 0 ] > transformXMax ): ## transformXMax = points[ 0 ] ## print curveName + ' has Xmin[%f] and Xmax[%f]' % ( transformXMin, transformXMax ) ## else: ## # Create input source element ## # TODO: If keyframe-input are same (same position-points) then perhaps create one input source? ## sourceID = ipoName + "-" + curveName + "-Input" ## sourceElement = dae.createSourceElement( sourceID, sourceID ) ## floatArrayName = sourceID + "-Array" ## floatArrayTime = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName ) ## floatArrayTime.setData( keyFrames ) ## floatArrayTime.setDataType( 'ANIMATIONINPUT' ) ## sourceElement.appendChild( floatArrayTime ) ## ## # Create common profile technique ## technique = dae.createTechniqueElement( CP.COMMON ) ## ## # Create accessor element with TIME param ## accessorTime = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 ) ## paramTime = dae.createParamElement( None, CP.PN.TIME, "float", CP.FT.OUT ) ## ## accessorTime.appendChild( paramTime ) ## technique.appendChild( accessorTime ) ## sourceElement.appendChild( technique ) ## animationElement.appendChild( sourceElement ) ## ## ## # Create output source element ## sourceID2 = ipoName + "-" + curveName + "-Output" ## sourceElement = dae.createSourceElement( sourceID2, sourceID2 ) ## floatArrayName = sourceID2 + "-Array" ## floatArrayOutput = dae.createFloatArrayElement( nrKeyFrames, floatArrayName, floatArrayName ) ## floatArrayOutput.setData( keyFrames ) ## floatArrayOutput.setDataType( 'ANIMATIONOUTPUT' ) ## ## sourceElement.appendChild( floatArrayOutput ) ## ## # Create common profile technique ## techniqueOutput = dae.createTechniqueElement( CP.COMMON ) ## ## # Create accessor element with output param ## accessorOutput = dae.createAccessorElement( nrKeyFrames, floatArrayName, floatArrayName + "-Accessor", 0 , 1 ) ## ## # Create different params depending on curve name (this should be driven channel for objects but ## # for now let's use the curve name because that seems to work) ## paramOutput = getParamElementFromCurveName( curveName ) ## ## ## accessorOutput.appendChild( paramOutput ) ## techniqueOutput.appendChild( accessorOutput ) ## sourceElement.appendChild( techniqueOutput ) ## animationElement.appendChild( sourceElement ) ## ## ## # If baking animation: ## # Loop through ## # if ( exportBakedTransform ): ## ## ## ## ## # Create sampler element ## for curve in curves: ## ## curveName = curve.getName( ) ## ## sourceID = ipoName + "-" + curveName ## ## # Create sampler element ## samplerID = ipoName + "-" + curveName + '-Sampler' ## samplerElement = dae.createSamplerElement( samplerID, samplerID ) ## ## # Create input semantics ## inputInput = dae.createInputElement( None, CP.IS.INPUT, sourceID + '-Input' ) ## inputOutput = dae.createInputElement( None, CP.IS.OUTPUT, sourceID + '-Output' ) ## ## samplerElement.appendChild( inputInput ) ## samplerElement.appendChild( inputOutput ) ## animationElement.appendChild( samplerElement ) ## ## ## # Create channel element ## for curve in curves: ## ## curveName = curve.getName( ) ## ## sourceID = ipoName + "-" + curveName + '-Sampler' ## ## # Create channel element ## channelID = ipoName + "-" + curveName + '-Channel' ## ## # Get IPO Curve driver object ## target = ipoOwner + '/' + getTargetNameFromCurveName( curveName ) ## channelElement = dae.createChannelElement( channelID, channelID, sourceID, target ) ## ## animationElement.appendChild( channelElement ) ## ## ## libraryElement.appendChild( animationElement ) # Write camera information to dae file def writeCamera( libraryElement, camera ): cameraName = camera.getName() cameraID = cameraName + "-Lib" cameraType = camera.getType() cameraElement = dae.createCameraElement( cameraID, cameraName ) technique = dae.createTechniqueElement( CP.COMMON ) optics = dae.createOpticsElement( ) # Create PERSPECTIVE camera or ORTHO camera program = None # PERSPECTIVE Camera # print cameraType if ( cameraType == 0 ): program = dae.createProgramElement( None, None, CP.PIAU.str[ CP.PIAU.PERSPECTIVE ] ) paramYFOV = dae.createParamElement( None, CP.PN.YFOV, "float", CP.FT.IN, None, None ) #paramXFOV = dae.createParamElement( None, CP.PN.XFOV, "float", CP.FT.IN, None, None ) # Calculate Y-FOV based on LENS value lens = camera.getLens( ) yfov = 2 * ( math.atan( 16.0 / lens ) ) * ( 180.0 / 3.1415926 ) paramYFOV.setData( "%.6f" % yfov ) program.appendChild( paramYFOV ) #paramXFOV.setData( "%.6f" % xfov ) #program.appendChild( paramXFOV ) else: print "Warning! Orthographic cameras not supported. Camera not exported! " return #program = dae.createProgramElement( None, CP.PIAU.str[ CP.PIAU.ORTHOGRAPHIC ], None ) paramZNear = dae.createParamElement( None, CP.PN.ZNEAR, "float", CP.FT.IN, None, None ) paramZFar = dae.createParamElement( None, CP.PN.ZFAR, "float", CP.FT.IN, None, None ) znear = camera.getClipStart( ) zfar = camera.getClipEnd( ) paramZNear.setData( "%.6f" % znear ) paramZFar.setData( "%.6f" % zfar ) program.appendChild( paramZNear ) program.appendChild( paramZFar ) optics.appendChild( program ) technique.appendChild( optics ) cameraElement.appendChild( technique ) libraryElement.appendChild( cameraElement ) # --- Write header information to dae file --- def writeHeader( colladaElement ): # Write asset information asset = dae.createAssetElement( ) author = dae.createAuthorElement( __author__ ) authoringtooldata = "Blender " + "%i" % Blender.Get( 'version' ) + " COLLADA Exporter" authoringtool = dae.createAuthoringToolElement( authoringtooldata ) # Can I change this in Blender? upaxisdata = "Z_UP" upaxis = dae.createUpAxisElement( upaxisdata ) # createddata = date( 2005, 12, 21) # created = dae.createCreatedElement( createddata ) # Create a unit element (mostly for Maya import to work better ) unit = dae.createUnitElement( 'centimeter', '%s' % 0.01 ) asset.appendChild( author ) asset.appendChild( authoringtool ) asset.appendChild( upaxis ) asset.appendChild( unit ) colladaElement.appendChild( asset ) # --- Write libraries to dae file --- def writeLibrary( colladaElement ): imageLibraryElement = dae.createLibraryElement( CP.LT.IMAGE ) textureLibraryElement = dae.createLibraryElement( CP.LT.TEXTURE ) materialLibraryElement = dae.createLibraryElement( CP.LT.MATERIAL ) geometryLibraryElement = dae.createLibraryElement( CP.LT.GEOMETRY ) animationLibraryElement = dae.createLibraryElement( CP.LT.ANIMATION ) lightLibraryElement = dae.createLibraryElement( CP.LT.LIGHT ) cameraLibraryElement = dae.createLibraryElement( CP.LT.CAMERA ) meshes = dict() lights = dict() cameras = dict() ipos = dict() for obj in objects: objType = obj.getType( ) dataName = obj.getData( True ) data = obj.getData( False ) ipo = obj.getIpo( ) objName = obj.name if ( ipo != None ): ipos[ objName ] = ipo if ( objType == 'Mesh' ): meshes[ dataName ] = NMesh.GetRaw( dataName ) elif ( objType == 'Lamp' ): lights[ dataName ] = data elif ( objType == 'Camera' ): cameras[ dataName ] = data # Get raw meshes materials = dict() nrMeshes = len( meshes ) if ( nrMeshes > 0 ): progress = 0.0 addProgress = 1.0 / nrMeshes Window.DrawProgressBar( 0.0, "Writing mesh data..." ) for key in meshes: rawMesh = meshes[ key ] if ( rawMesh.users > 0 ): writeMesh( geometryLibraryElement, rawMesh ) progress += addProgress Window.DrawProgressBar( progress, "Exporting geometry %.0f %%..." % ( progress * 100.0 ) ) meshMaterials = rawMesh.getMaterials( -1 ) for material in meshMaterials: if material==None: continue key = material.getName( ) materials[ key ] = material # Ipo on material? ipo = material.getIpo( ) if ( ipo != None ): ipos[ key ] = ipo # Get materials textures = dict() nrMaterials = len( materials ) if ( nrMaterials > 0 ): progress = 0.0 addProgress = 1.0 / nrMaterials for key in materials: material = materials[ key ] writeMaterial( materialLibraryElement, material ) progress += addProgress Window.DrawProgressBar( progress, "Exporting materials %.0f %%..." % ( progress * 100.0 ) ) materialTextures = material.getTextures( ) for texture in materialTextures: if not ( texture == None ): if ( texture.tex.type == Texture.Types.IMAGE ): key = texture.tex.getName( ) textures[ key ] = texture.tex # Ipo on texture? ipo = texture.tex.getIpo( ) if ( ipo != None ): ipos[ key ] = ipo # Write textures images = dict() nrTextures = len( textures ) if ( nrTextures > 0 ): progress = 0.0 addProgress = 1.0 / nrTextures for key in textures: texture = textures[ key ] writeTexture( textureLibraryElement, texture ) progress += addProgress Window.DrawProgressBar( progress, "Exporting textures %.0f %%..." % ( progress * 100.0 ) ) image = texture.getImage( ) if ( image != None ): imageName = image.getName( ) images[ imageName ] = image # Write images nrImages = len( images ) if ( nrImages > 0 ): progress = 0.0 addProgress = 1.0 / nrImages for key in images: image = images[ key ] writeImage( imageLibraryElement, image ) progress += addProgress Window.DrawProgressBar( progress, "Exporting images %.0f %%..." % ( progress * 100.0 ) ) # Write lights nrLights = len( lights ) if ( nrLights > 0 ): progress = 0.0 addProgress = 1.0 / nrLights for key in lights: light = lights[ key ] writeLight( lightLibraryElement, light ) progress += addProgress Window.DrawProgressBar( progress, "Exporting lights %.0f %%..." % ( progress * 100.0 ) ) # Write cameras nrCameras = len( cameras ) if ( nrCameras > 0 ): progress = 0.0 addProgress = 1.0 / nrCameras for key in cameras: camera = cameras[ key ] writeCamera( cameraLibraryElement, camera ) progress += addProgress Window.DrawProgressBar( progress, "Exporting cameras %.0f %%..." % ( progress * 100.0 ) ) # Write animations nrAnimations = len( ipos ) if ( nrAnimations > 0 ): progress = 0.0 addProgress = 1.0 / nrAnimations for key in ipos: ipo = ipos[ key ] writeAnimation( animationLibraryElement, ipo, key ) progress += addProgress Window.DrawProgressBar( progress, "Exporting animation %.0f %%..." % ( progress * 100.0 ) ) # Write library element. Put animation first... colladaElement.appendChild( imageLibraryElement ) colladaElement.appendChild( textureLibraryElement ) colladaElement.appendChild( materialLibraryElement ) colladaElement.appendChild( geometryLibraryElement ) colladaElement.appendChild( lightLibraryElement ) colladaElement.appendChild( cameraLibraryElement ) colladaElement.appendChild( animationLibraryElement ) # --- Write node to dae --- def writeNode( object, parentNode ): global exportBakedTransform newNodeName = object.name # newNodeName = object.name + "-Node" newNode = dae.createNodeElement( newNodeName, newNodeName, CP.NT.NODE ) #print "Creating %s" % newNodeName # Create data for this node here url = object.getData( True ) if not ( url == None ): url += "-Lib" instance = dae.createInstanceElement( url ) newNode.appendChild( instance ) # No need to check for IPO connection here simply output sid values anyway. # sid values are according to target values in library and these # names follows the naming convention that the Maya exporter use #sidTranslate = newNodeName + "-Translate" #sidRotateX = newNodeName + "-Rotate-X" if ( exportBakedTransform ): matrixElement = dae.createMatrixElement( 'transform' ) matrix = object.getMatrix( 'localspace' ) data = "" matrix.transpose() if ( niceFormat ): for i in range( 4 ): data += "\n%.6f %.6f %.6f %.6f" % ( matrix[ i ].x, matrix[ i ].y, matrix[ i ].z, matrix[ i ].w ) else: data += "%.6f %.6f %.6f %.6f " % ( matrix[ 0 ].x, matrix[ 0 ].y, matrix[ 0 ].z, matrix[ 0 ].w ) data += "%.6f %.6f %.6f %.6f " % ( matrix[ 1 ].x, matrix[ 1 ].y, matrix[ 1 ].z, matrix[ 1 ].w ) data += "%.6f %.6f %.6f %.6f " % ( matrix[ 2 ].x, matrix[ 2 ].y, matrix[ 2 ].z, matrix[ 2 ].w ) data += "%.6f %.6f %.6f %.6f" % ( matrix[ 3 ].x, matrix[ 3 ].y, matrix[ 3 ].z, matrix[ 3 ].w ) matrixElement.setData( data ) newNode.appendChild( matrixElement ) else: translate = dae.createTranslateElement( 'translate' ) rotateX = dae.createRotateElement( 'rotateX' ) rotateY = dae.createRotateElement( 'rotateY' ) rotateZ = dae.createRotateElement( 'rotateZ' ) scale = dae.createScaleElement( 'scale' ) location = object.getLocation() rotation = object.getEuler() size = object.getSize() data = "%.6f %.6f %.6f" % ( location[ 0 ], location[ 1 ], location[ 2 ] ) dataX = "1 0 0 %.6f" % ( toAngle( rotation[ 0 ] ) ) dataY = "0 1 0 %.6f" % ( toAngle( rotation[ 1 ] ) ) dataZ = "0 0 1 %.6f" % ( toAngle( rotation[ 2 ] ) ) dataScale = "%.6f %.6f %.6f" % ( size[ 0 ], size[ 1 ], size[ 2 ] ) translate.setData( data ) rotateX.setData( dataX ) rotateY.setData( dataY ) rotateZ.setData( dataZ ) scale.setData( dataScale ) newNode.appendChild( translate ) newNode.appendChild( rotateX ) newNode.appendChild( rotateY ) newNode.appendChild( rotateZ ) newNode.appendChild( scale ) # Check if anyone has Me as Parent returnNode = None for child in objects: parent = child.getParent() if ( object == parent ): returnNode = writeNode( child, newNode ) if not ( returnNode == None ): newNode.appendChild( returnNode ) parentNode.appendChild( newNode ) return newNode # --- Write scene to dae file --- def writeScene( colladaElement ): # Write element currentScene = Scene.GetCurrent( ) sceneName = currentScene.getName( ) sceneElement = dae.createSceneElement( sceneName, sceneName ) colladaElement.appendChild( sceneElement ) # Write nodes if not ( objects == None ): nrObjects = len( objects ) if ( nrObjects > 0 ): addProgress = 1.0 / nrObjects progress = 0.0 Window.DrawProgressBar( 0.0, "Exporting Scene 0.0% ..." ) for object in objects: if ( object.getParent() == None ): writeNode( object, sceneElement ) progress += addProgress Window.DrawProgressBar( progress, "Exporting Scene %.0f%% ..." % ( progress * 100.0 ) ) Window.DrawProgressBar( 1.0, "Finished!" ) # print objects # ---------------------------------------------- # ---------------------------------------------- # HELPER FUNCTIONS # ---------------------------------------------- # --- Set id and name tag to element --- #def setIdAndName( element, string ): # element.setAttribute( "id", string ) # element.setAttribute( "name", string ) # return # --- Create COMMON Technique element --- #def createCommonTechnique( ): # technique = dae.createElement( "technique" ) # technique.setAttribute( "profile", "COMMON" ) # # return technique # --- Create Param element --- #def createParamElement( name, type ): # param = dae.createElement( "param" ) # param.setAttribute( "name", name ) # param.setAttribute( "type", type ) # # return param # ---------------------------------------------- # --- MAIN --- def main( filePath ): global dae global objects global exportSelected global fps if not ( filePath == None ): print "Exporting: " + filePath + "..." startTime = sys.time() dae = COLLADADocument() dae.openFile( filePath ) # Build node tree here collada = dae.createCOLLADAElement( ) dae.appendChild( collada ) if ( exportSelected == True ): objects = Object.GetSelected( ) # print "Selected objects only!" else: objects = Object.Get( ) # Write header information writeHeader( collada ) # Set fps scn = Scene.GetCurrent( ) context = scn.getRenderingContext( ) fps = context.framesPerSec( ) #Write library information writeLibrary( collada ) # Write scene information writeScene( collada ) dae.buildXML( ) dae.cleanUp( ) # Get scene objects # objects = Object.Get() endTime = sys.time() exportTime = endTime - startTime print "Export time: %.6f" % (exportTime ) #print "" # Window.DrawProgressBar( 1.0, "" ) def callback_fileselector( filename ): if ( sys.exists( filename ) == 1 ): overwrite = Draw.PupMenu( "File Already Exists, Overwrite?%t|Yes%x1|No%x0" ) if ( overwrite == 1 ): main( filename ) else: main( filename ) def ExportGUI( ): global exportSelected, exportBakedTransform # Window.DrawProgressBar( 0.0, ">>> COLLADA-" ) # print "" # Export selected or all progressString = "COLLADA-" answer = Draw.PupMenu( "Export what?%t|All%x1|Selected only%x0" ) if ( answer == 1 ): exportSelected = False progressString += "All-" elif ( answer == 0 ): exportSelected = True progressString +="Selected-" else: # print "" # Window.DrawProgressBar( 1.0, "" ) return # Window.DrawProgressBar( 0.0, progressString ) answer2 = Draw.PupMenu( "Export as matrix element?%t|Yes%x1|No%x0" ) if ( answer2 == 1 ): exportBakedTransform = True progressString +="Matrix" elif ( answer2 == 0 ): exportBakedTransform = False progressString +="Transform" else: # print "" # Window.DrawProgressBar( 1.0, "" ) return # Window.DrawProgressBar( 0.0, progressString ) print "Export options: " + progressString defaultFileName = Blender.Get('filename') + ".dae" defaultFileName = defaultFileName.replace( '.blend', '' ) Window.FileSelector( callback_fileselector, 'Export .dae', defaultFileName ) # Run the script if not ( _ERROR == True ): ExportGUI() #main( 'C:\\ColladaBlender\\test.xml' )