adding back changes from soc-2009-kaz branch.
authorCampbell Barton <ideasman42@gmail.com>
Tue, 29 Sep 2009 15:27:00 +0000 (15:27 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 29 Sep 2009 15:27:00 +0000 (15:27 +0000)
release/scripts/io/export_3ds.py
release/scripts/io/export_fbx.py
release/scripts/io/export_obj.py
release/scripts/io/export_ply.py
release/scripts/io/export_x3d.py
release/scripts/io/import_3ds.py
release/scripts/io/import_obj.py

index 87680bce1b0cb0b236c1180b54ddb2b53c7a2326..2c1999c3d45d94326065963c8051caa9c3b5cb3a 100644 (file)
@@ -46,14 +46,35 @@ from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode.
 # Importing modules
 ######################################################
 
-import Blender
+import struct
+import os
+import time
+
 import bpy
-from BPyMesh import getMeshFromObject
-from BPyObject import getDerivedObjects
-try: 
-    import struct
-except: 
-    struct = None
+
+# import Blender
+# from BPyMesh import getMeshFromObject
+# from BPyObject import getDerivedObjects
+# try: 
+#     import struct
+# except: 
+#     struct = None
+
+# also used by X3D exporter
+# return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects()
+def create_derived_objects(ob):
+       if ob.parent and ob.parent.dupli_type != 'NONE':
+               return False, None
+
+       if ob.dupli_type != 'NONE':
+               ob.create_dupli_list()
+               return True, [(dob.object, dob.matrix) for dob in ob.dupli_list]
+       else:
+               return False, [(ob, ob.matrix)]
+
+# also used by X3D exporter
+def free_derived_objects(ob):
+       ob.free_dupli_list()
 
 # So 3ds max can open files, limit names to 12 in length
 # this is verry annoying for filenames!
@@ -85,61 +106,62 @@ def sane_name(name):
 
 #Some of the chunks that we will export
 #----- Primary Chunk, at the beginning of each file
-PRIMARY= long("0x4D4D",16)
+PRIMARY= int("0x4D4D",16)
 
 #------ Main Chunks
-OBJECTINFO   =      long("0x3D3D",16);      #This gives the version of the mesh and is found right before the material and object information
-VERSION      =      long("0x0002",16);      #This gives the version of the .3ds file
-KFDATA       =      long("0xB000",16);      #This is the header for all of the key frame info
+OBJECTINFO   =      int("0x3D3D",16);      #This gives the version of the mesh and is found right before the material and object information
+VERSION      =      int("0x0002",16);      #This gives the version of the .3ds file
+KFDATA       =      int("0xB000",16);      #This is the header for all of the key frame info
 
 #------ sub defines of OBJECTINFO
 MATERIAL=45055         #0xAFFF                         // This stored the texture info
 OBJECT=16384           #0x4000                         // This stores the faces, vertices, etc...
 
 #>------ sub defines of MATERIAL
-MATNAME    =      long("0xA000",16);      # This holds the material name
-MATAMBIENT   =      long("0xA010",16);      # Ambient color of the object/material
-MATDIFFUSE   =      long("0xA020",16);      # This holds the color of the object/material
-MATSPECULAR   =      long("0xA030",16);      # SPecular color of the object/material
-MATSHINESS   =      long("0xA040",16);      # ??
-MATMAP       =      long("0xA200",16);      # This is a header for a new material
-MATMAPFILE    =      long("0xA300",16);      # This holds the file name of the texture
+MATNAME    =      int("0xA000",16);      # This holds the material name
+MATAMBIENT   =      int("0xA010",16);      # Ambient color of the object/material
+MATDIFFUSE   =      int("0xA020",16);      # This holds the color of the object/material
+MATSPECULAR   =      int("0xA030",16);      # SPecular color of the object/material
+MATSHINESS   =      int("0xA040",16);      # ??
+MATMAP       =      int("0xA200",16);      # This is a header for a new material
+MATMAPFILE    =      int("0xA300",16);      # This holds the file name of the texture
 
-RGB1=  long("0x0011",16)
-RGB2=  long("0x0012",16)
+RGB1=  int("0x0011",16)
+RGB2=  int("0x0012",16)
 
 #>------ sub defines of OBJECT
-OBJECT_MESH  =      long("0x4100",16);      # This lets us know that we are reading a new object
-OBJECT_LIGHT =      long("0x4600",16);      # This lets un know we are reading a light object
-OBJECT_CAMERA=      long("0x4700",16);      # This lets un know we are reading a camera object
+OBJECT_MESH  =      int("0x4100",16);      # This lets us know that we are reading a new object
+OBJECT_LIGHT =      int("0x4600",16);      # This lets un know we are reading a light object
+OBJECT_CAMERA=      int("0x4700",16);      # This lets un know we are reading a camera object
 
 #>------ sub defines of CAMERA
-OBJECT_CAM_RANGES=   long("0x4720",16);      # The camera range values
+OBJECT_CAM_RANGES=   int("0x4720",16);      # The camera range values
 
 #>------ sub defines of OBJECT_MESH
-OBJECT_VERTICES =   long("0x4110",16);      # The objects vertices
-OBJECT_FACES    =   long("0x4120",16);      # The objects faces
-OBJECT_MATERIAL =   long("0x4130",16);      # This is found if the object has a material, either texture map or color
-OBJECT_UV       =   long("0x4140",16);      # The UV texture coordinates
-OBJECT_TRANS_MATRIX  =   long("0x4160",16); # The Object Matrix
+OBJECT_VERTICES =   int("0x4110",16);      # The objects vertices
+OBJECT_FACES    =   int("0x4120",16);      # The objects faces
+OBJECT_MATERIAL =   int("0x4130",16);      # This is found if the object has a material, either texture map or color
+OBJECT_UV       =   int("0x4140",16);      # The UV texture coordinates
+OBJECT_TRANS_MATRIX  =   int("0x4160",16); # The Object Matrix
 
 #>------ sub defines of KFDATA
-KFDATA_KFHDR            = long("0xB00A",16);
-KFDATA_KFSEG            = long("0xB008",16);
-KFDATA_KFCURTIME        = long("0xB009",16);
-KFDATA_OBJECT_NODE_TAG  = long("0xB002",16);
+KFDATA_KFHDR            = int("0xB00A",16);
+KFDATA_KFSEG            = int("0xB008",16);
+KFDATA_KFCURTIME        = int("0xB009",16);
+KFDATA_OBJECT_NODE_TAG  = int("0xB002",16);
 
 #>------ sub defines of OBJECT_NODE_TAG
-OBJECT_NODE_ID          = long("0xB030",16);
-OBJECT_NODE_HDR         = long("0xB010",16);
-OBJECT_PIVOT            = long("0xB013",16);
-OBJECT_INSTANCE_NAME    = long("0xB011",16);
-POS_TRACK_TAG                  = long("0xB020",16);
-ROT_TRACK_TAG                  = long("0xB021",16);
-SCL_TRACK_TAG                  = long("0xB022",16);
+OBJECT_NODE_ID          = int("0xB030",16);
+OBJECT_NODE_HDR         = int("0xB010",16);
+OBJECT_PIVOT            = int("0xB013",16);
+OBJECT_INSTANCE_NAME    = int("0xB011",16);
+POS_TRACK_TAG                  = int("0xB020",16);
+ROT_TRACK_TAG                  = int("0xB021",16);
+SCL_TRACK_TAG                  = int("0xB022",16);
 
 def uv_key(uv):
-       return round(uv.x, 6), round(uv.y, 6)
+       return round(uv[0], 6), round(uv[1], 6)
+#      return round(uv.x, 6), round(uv.y, 6)
 
 # size defines:        
 SZ_SHORT = 2
@@ -272,7 +294,8 @@ class _3ds_rgb_color(object):
                return 3
        
        def write(self,file):
-               file.write( struct.pack('<3c', chr(int(255*self.r)), chr(int(255*self.g)), chr(int(255*self.b)) ) )
+               file.write( struct.pack('<3B', int(255*self.r), int(255*self.g), int(255*self.b) ) )
+#              file.write( struct.pack('<3c', chr(int(255*self.r)), chr(int(255*self.g)), chr(int(255*self.b)) ) )
        
        def __str__(self):
                return '{%f, %f, %f}' % (self.r, self.g, self.b)
@@ -343,12 +366,12 @@ class _3ds_named_variable(object):
        def dump(self,indent):
                if (self.value!=None):
                        spaces=""
-                       for i in xrange(indent):
+                       for i in range(indent):
                                spaces+="  ";
                        if (self.name!=""):
-                               print spaces, self.name, " = ", self.value
+                               print(spaces, self.name, " = ", self.value)
                        else:
-                               print spaces, "[unnamed]", " = ", self.value
+                               print(spaces, "[unnamed]", " = ", self.value)
 
 
 #the chunk class
@@ -408,9 +431,9 @@ class _3ds_chunk(object):
                Dump is used for debugging purposes, to dump the contents of a chunk to the standard output. 
                Uses the dump function of the named variables and the subchunks to do the actual work.'''
                spaces=""
-               for i in xrange(indent):
+               for i in range(indent):
                        spaces+="  ";
-               print spaces, "ID=", hex(self.ID.value), "size=", self.get_size()
+               print(spaces, "ID=", hex(self.ID.value), "size=", self.get_size())
                for variable in self.variables:
                        variable.dump(indent+1)
                for subchunk in self.subchunks:
@@ -424,14 +447,19 @@ class _3ds_chunk(object):
 
 def get_material_images(material):
        # blender utility func.
-       images = []
        if material:
-               for mtex in material.getTextures():
-                       if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
-                               image = mtex.tex.image
-                               if image:
-                                       images.append(image) # maye want to include info like diffuse, spec here.
-       return images
+               return [s.texture.image for s in material.textures if s and s.texture.type == 'IMAGE' and s.texture.image]
+
+       return []
+#      images = []
+#      if material:
+#              for mtex in material.getTextures():
+#                      if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
+#                              image = mtex.tex.image
+#                              if image:
+#                                      images.append(image) # maye want to include info like diffuse, spec here.
+#      return images
+
 
 def make_material_subchunk(id, color):
        '''Make a material subchunk.
@@ -454,7 +482,8 @@ def make_material_texture_chunk(id, images):
        mat_sub = _3ds_chunk(id)
        
        def add_image(img):
-               filename = image.filename.split('\\')[-1].split('/')[-1]
+               filename = os.path.basename(image.filename)
+#              filename = image.filename.split('\\')[-1].split('/')[-1]
                mat_sub_file = _3ds_chunk(MATMAPFILE)
                mat_sub_file.add_variable("mapfile", _3ds_string(sane_name(filename)))
                mat_sub.add_subchunk(mat_sub_file)
@@ -482,9 +511,12 @@ def make_material_chunk(material, image):
                material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, (1,1,1) ))
        
        else:
-               material_chunk.add_subchunk(make_material_subchunk(MATAMBIENT, [a*material.amb for a in material.rgbCol] ))
-               material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, material.rgbCol))
-               material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, material.specCol))
+               material_chunk.add_subchunk(make_material_subchunk(MATAMBIENT, [a*material.ambient for a in material.diffuse_color] ))
+#              material_chunk.add_subchunk(make_material_subchunk(MATAMBIENT, [a*material.amb for a in material.rgbCol] ))
+               material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, material.diffuse_color))
+#              material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, material.rgbCol))
+               material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, material.specular_color))
+#              material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, material.specCol))
                
                images = get_material_images(material) # can be None
                if image: images.append(image)
@@ -513,28 +545,39 @@ def extract_triangles(mesh):
        
        If the mesh contains quads, they will be split into triangles.'''
        tri_list = []
-       do_uv = mesh.faceUV
+       do_uv = len(mesh.uv_textures)
+#      do_uv = mesh.faceUV
        
-       if not do_uv:
-               face_uv = None
+#      if not do_uv:
+#              face_uv = None
        
        img = None
-       for face in mesh.faces:
-               f_v = face.v
+       for i, face in enumerate(mesh.faces):
+               f_v = face.verts
+#              f_v = face.v
+
+               uf = mesh.active_uv_texture.data[i] if do_uv else None
                
                if do_uv:
-                       f_uv = face.uv
-                       img = face.image
+                       f_uv = uf.uv
+                       # f_uv =  (uf.uv1, uf.uv2, uf.uv3, uf.uv4) if face.verts[3] else (uf.uv1, uf.uv2, uf.uv3)
+#                      f_uv = face.uv
+                       img = uf.image if uf else None
+#                      img = face.image
                        if img: img = img.name
                
+               # if f_v[3] == 0:
                if len(f_v)==3:
-                       new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img)
+                       new_tri = tri_wrapper((f_v[0], f_v[1], f_v[2]), face.material_index, img)
+#                      new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img)
                        if (do_uv): new_tri.faceuvs= uv_key(f_uv[0]), uv_key(f_uv[1]), uv_key(f_uv[2])
                        tri_list.append(new_tri)
                
                else: #it's a quad
-                       new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img)
-                       new_tri_2 = tri_wrapper((f_v[0].index, f_v[2].index, f_v[3].index), face.mat, img)
+                       new_tri = tri_wrapper((f_v[0], f_v[1], f_v[2]), face.material_index, img)
+#                      new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img)
+                       new_tri_2 = tri_wrapper((f_v[0], f_v[2], f_v[3]), face.material_index, img)
+#                      new_tri_2 = tri_wrapper((f_v[0].index, f_v[2].index, f_v[3].index), face.mat, img)
                        
                        if (do_uv):
                                new_tri.faceuvs= uv_key(f_uv[0]), uv_key(f_uv[1]), uv_key(f_uv[2])
@@ -555,11 +598,11 @@ def remove_face_uv(verts, tri_list):
        
        # initialize a list of UniqueLists, one per vertex:
        #uv_list = [UniqueList() for i in xrange(len(verts))]
-       unique_uvs= [{} for i in xrange(len(verts))]
+       unique_uvs= [{} for i in range(len(verts))]
        
        # for each face uv coordinate, add it to the UniqueList of the vertex
        for tri in tri_list:
-               for i in xrange(3):
+               for i in range(3):
                        # store the index into the UniqueList for future reference:
                        # offset.append(uv_list[tri.vertex_index[i]].add(_3ds_point_uv(tri.faceuvs[i])))
                        
@@ -589,7 +632,7 @@ def remove_face_uv(verts, tri_list):
                
                pt = _3ds_point_3d(vert.co) # reuse, should be ok
                uvmap = [None] * len(unique_uvs[i])
-               for ii, uv_3ds in unique_uvs[i].itervalues():
+               for ii, uv_3ds in unique_uvs[i].values():
                        # add a vertex duplicate to the vertex_array for every uv associated with this vertex:
                        vert_array.add(pt)
                        # add the uv coordinate to the uv array:
@@ -607,7 +650,7 @@ def remove_face_uv(verts, tri_list):
        
        # Make sure the triangle vertex indices now refer to the new vertex list:
        for tri in tri_list:
-               for i in xrange(3):
+               for i in range(3):
                        tri.offset[i]+=index_list[tri.vertex_index[i]]
                tri.vertex_index= tri.offset
        
@@ -626,7 +669,8 @@ def make_faces_chunk(tri_list, mesh, materialDict):
        face_list = _3ds_array()
        
        
-       if mesh.faceUV:
+       if len(mesh.uv_textures):
+#      if mesh.faceUV:
                # Gather materials used in this mesh - mat/image pairs
                unique_mats = {}
                for i,tri in enumerate(tri_list):
@@ -655,7 +699,7 @@ def make_faces_chunk(tri_list, mesh, materialDict):
                        # obj_material_faces[tri.mat].add(_3ds_short(i))
                
                face_chunk.add_variable("faces", face_list)
-               for mat_name, mat_faces in unique_mats.itervalues():
+               for mat_name, mat_faces in unique_mats.values():
                        obj_material_chunk=_3ds_chunk(OBJECT_MATERIAL)
                        obj_material_chunk.add_variable("name", mat_name)
                        obj_material_chunk.add_variable("face_list", mat_faces)
@@ -677,7 +721,7 @@ def make_faces_chunk(tri_list, mesh, materialDict):
                                obj_material_faces[tri.mat].add(_3ds_short(i))
                
                face_chunk.add_variable("faces", face_list)
-               for i in xrange(n_materials):
+               for i in range(n_materials):
                        obj_material_chunk=_3ds_chunk(OBJECT_MATERIAL)
                        obj_material_chunk.add_variable("name", obj_material_names[i])
                        obj_material_chunk.add_variable("face_list", obj_material_faces[i])
@@ -703,7 +747,8 @@ def make_mesh_chunk(mesh, materialDict):
        # Extract the triangles from the mesh:
        tri_list = extract_triangles(mesh)
        
-       if mesh.faceUV:
+       if len(mesh.uv_textures):
+#      if mesh.faceUV:
                # Remove the face UVs and convert it to vertex UV:
                vert_array, uv_array, tri_list = remove_face_uv(mesh.verts, tri_list)
        else:
@@ -712,10 +757,13 @@ def make_mesh_chunk(mesh, materialDict):
                for vert in mesh.verts:
                        vert_array.add(_3ds_point_3d(vert.co))
                # If the mesh has vertex UVs, create an array of UVs:
-               if mesh.vertexUV:
+               if len(mesh.sticky):
+#              if mesh.vertexUV:
                        uv_array = _3ds_array()
-                       for vert in mesh.verts:
-                               uv_array.add(_3ds_point_uv(vert.uvco))
+                       for uv in mesh.sticky:
+#                      for vert in mesh.verts:
+                               uv_array.add(_3ds_point_uv(uv.co))
+#                              uv_array.add(_3ds_point_uv(vert.uvco))
                else:
                        # no UV at all:
                        uv_array = None
@@ -862,20 +910,25 @@ def make_kf_obj_node(obj, name_to_id):
        return kf_obj_node
 """
 
-import BPyMessages
-def save_3ds(filename):
+import BPyMessages
+def save_3ds(filename, context):
        '''Save the Blender scene to a 3ds file.'''
        # Time the export
        
        if not filename.lower().endswith('.3ds'):
                filename += '.3ds'
        
-       if not BPyMessages.Warning_SaveOver(filename):
-               return
+       # XXX
+#      if not BPyMessages.Warning_SaveOver(filename):
+#              return
        
-       time1= Blender.sys.time()
-       Blender.Window.WaitCursor(1)
-       sce= bpy.data.scenes.active
+       # XXX
+       time1 = time.clock()
+#      time1= Blender.sys.time()
+#      Blender.Window.WaitCursor(1)
+
+       sce = context.scene
+#      sce= bpy.data.scenes.active
        
        # Initialize the main chunk (primary):
        primary = _3ds_chunk(PRIMARY)
@@ -901,22 +954,39 @@ def save_3ds(filename):
        # each material is added once):
        materialDict = {}
        mesh_objects = []
-       for ob in sce.objects.context:
-               for ob_derived, mat in getDerivedObjects(ob, False):
-                       data = getMeshFromObject(ob_derived, None, True, False, sce)
+       for ob in [ob for ob in context.scene.objects if ob.is_visible()]:
+#      for ob in sce.objects.context:
+
+               # get derived objects
+               free, derived = create_derived_objects(ob)
+
+               if derived == None: continue
+
+               for ob_derived, mat in derived:
+#              for ob_derived, mat in getDerivedObjects(ob, False):
+
+                       if ob.type not in ('MESH', 'CURVE', 'SURFACE', 'TEXT', 'META'):
+                               continue
+
+                       data = ob_derived.create_mesh(True, 'PREVIEW')
+#                      data = getMeshFromObject(ob_derived, None, True, False, sce)
                        if data:
-                               data.transform(mat, recalc_normals=False)
+                               data.transform(mat)
+#                              data.transform(mat, recalc_normals=False)
                                mesh_objects.append((ob_derived, data))
                                mat_ls = data.materials
                                mat_ls_len = len(mat_ls)
+
                                # get material/image tuples.
-                               if data.faceUV:
+                               if len(data.uv_textures):
+#                              if data.faceUV:
                                        if not mat_ls:
                                                mat = mat_name = None
                                        
-                                       for f in data.faces:
+                                       for f, uf in zip(data.faces, data.active_uv_texture.data):
                                                if mat_ls:
-                                                       mat_index = f.mat
+                                                       mat_index = f.material_index
+#                                                      mat_index = f.mat
                                                        if mat_index >= mat_ls_len:
                                                                mat_index = f.mat = 0
                                                        mat = mat_ls[mat_index]
@@ -924,7 +994,8 @@ def save_3ds(filename):
                                                        else:   mat_name = None
                                                # else there alredy set to none
                                                        
-                                               img = f.image
+                                               img = uf.image
+#                                              img = f.image
                                                if img: img_name = img.name
                                                else:   img_name = None
                                                
@@ -938,11 +1009,17 @@ def save_3ds(filename):
                                        
                                        # Why 0 Why!
                                        for f in data.faces:
-                                               if f.mat >= mat_ls_len:
-                                                       f.mat = 0 
+                                               if f.material_index >= mat_ls_len:
+#                                              if f.mat >= mat_ls_len:
+                                                       f.material_index = 0
+                                                       # f.mat = 0
+
+               if free:
+                       free_derived_objects(ob)
+
        
        # Make material chunks for all materials used in the meshes:
-       for mat_and_image in materialDict.itervalues():
+       for mat_and_image in materialDict.values():
                object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1]))
        
        # Give all objects a unique ID and build a dictionary from object name to object id:
@@ -971,7 +1048,10 @@ def save_3ds(filename):
                # make a kf object node for the object:
                kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id))
                '''
-               blender_mesh.verts = None
+#              if not blender_mesh.users:
+               bpy.data.remove_mesh(blender_mesh)
+#              blender_mesh.verts = None
+
                i+=i
 
        # Create chunks for all empties:
@@ -1004,16 +1084,47 @@ def save_3ds(filename):
        file.close()
        
        # Debugging only: report the exporting time:
-       Blender.Window.WaitCursor(0)
-       print "3ds export time: %.2f" % (Blender.sys.time() - time1)
+#      Blender.Window.WaitCursor(0)
+       print("3ds export time: %.2f" % (time.clock() - time1))
+#      print("3ds export time: %.2f" % (Blender.sys.time() - time1))
        
        # Debugging only: dump the chunk hierarchy:
        #primary.dump()
 
 
-if __name__=='__main__':
-    if struct:
-        Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds'))
-    else:
-        Blender.Draw.PupMenu("Error%t|This script requires a full python installation")
-# save_3ds('/test_b.3ds')
+# if __name__=='__main__':
+#     if struct:
+#         Blender.Window.FileSelector(save_3ds, "Export 3DS", Blender.sys.makename(ext='.3ds'))
+#     else:
+#         Blender.Draw.PupMenu("Error%t|This script requires a full python installation")
+# # save_3ds('/test_b.3ds')
+
+class EXPORT_OT_3ds(bpy.types.Operator):
+       '''
+       3DS Exporter
+       '''
+       __idname__ = "export.3ds"
+       __label__ = 'Export 3DS'
+       
+       # List of operator properties, the attributes will be assigned
+       # to the class instance from the operator settings before calling.
+
+       __props__ = [
+               # bpy.props.StringProperty(attr="filename", name="File Name", description="File name used for exporting the 3DS file", maxlen= 1024, default= ""),
+               bpy.props.StringProperty(attr="path", name="File Path", description="File path used for exporting the 3DS file", maxlen= 1024, default= ""),
+       ]
+       
+       def execute(self, context):
+               save_3ds(self.path, context)
+               return ('FINISHED',)
+       
+       def invoke(self, context, event):
+               wm = context.manager
+               wm.add_fileselect(self.__operator__)
+               return ('RUNNING_MODAL',)
+       
+       def poll(self, context): # Poll isnt working yet
+               print("Poll")
+               return context.active_object != None
+
+bpy.ops.add(EXPORT_OT_3ds)
index 50357cbfa754d063f97edd8f5fd108f1f2342a39..21b1388ebfe622c53550762e7de4fdc556f41475 100644 (file)
@@ -36,11 +36,16 @@ http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx
 # ***** END GPL LICENCE BLOCK *****
 # --------------------------------------------------------------------------
 
-try:
-       import time
-       # import os # only needed for batch export, nbot used yet
-except:
-       time = None # use this to check if they have python modules installed
+import os
+import time
+import math # math.pi
+import shutil # for file copying
+
+# try:
+#      import time
+#      # import os # only needed for batch export, nbot used yet
+# except:
+#      time = None # use this to check if they have python modules installed
 
 # for python 2.3 support
 try:
@@ -51,20 +56,21 @@ except:
        except:
                set = None # so it complains you dont have a !
 
-# os is only needed for batch 'own dir' option
-try:
-       import os
-except:
-       os = None
+# os is only needed for batch 'own dir' option
+try:
+#      import os
+except:
+#      os = None
 
-import Blender
+import Blender
 import bpy
-from Blender.Mathutils import Matrix, Vector, RotationMatrix
+import Mathutils
+# from Blender.Mathutils import Matrix, Vector, RotationMatrix
 
-import BPyObject
-import BPyMesh
-import BPySys
-import BPyMessages
+import BPyObject
+import BPyMesh
+import BPySys
+import BPyMessages
 
 ## This was used to make V, but faster not to do all that
 ##valid = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_,.()[]{}'
@@ -75,7 +81,7 @@ invalid = ''.join([chr(i) for i in v])
 def cleanName(name):
        for ch in invalid:      name = name.replace(ch, '_')
        return name
-del v, i
+del v, i
 
 
 def copy_file(source, dest):
@@ -88,9 +94,10 @@ def copy_file(source, dest):
        file.close()
 
 
+# XXX not used anymore, images are copied one at a time
 def copy_images(dest_dir, textures):
-       if not dest_dir.endswith(Blender.sys.sep):
-               dest_dir += Blender.sys.sep
+       if not dest_dir.endswith(os.sep):
+               dest_dir += os.sep
        
        image_paths = set()
        for tex in textures:
@@ -103,19 +110,30 @@ def copy_images(dest_dir, textures):
                        # Make a name for the target path.
                        dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
                        if not Blender.sys.exists(dest_image_path): # Image isnt alredy there
-                               print '\tCopying "%s" > "%s"' % (image_path, dest_image_path)
+                               print('\tCopying "%s" > "%s"' % (image_path, dest_image_path))
                                try:
                                        copy_file(image_path, dest_image_path)
                                        copyCount+=1
                                except:
-                                       print '\t\tWarning, file failed to copy, skipping.'
+                                       print('\t\tWarning, file failed to copy, skipping.')
        
-       print '\tCopied %d images' % copyCount
+       print('\tCopied %d images' % copyCount)
+
+# I guess FBX uses degrees instead of radians (Arystan).
+# Call this function just before writing to FBX.
+def eulerRadToDeg(eul):
+       ret = Mathutils.Euler()
 
-mtx4_identity = Matrix()
+       ret.x = 180 / math.pi * eul[0]
+       ret.y = 180 / math.pi * eul[1]
+       ret.z = 180 / math.pi * eul[2]
+
+       return ret
+
+mtx4_identity = Mathutils.Matrix()
 
 # testing
-mtx_x90                = RotationMatrix( 90, 3, 'x') # used
+mtx_x90                = Mathutils.RotationMatrix( math.pi/2, 3, 'x') # used
 #mtx_x90n      = RotationMatrix(-90, 3, 'x')
 #mtx_y90       = RotationMatrix( 90, 3, 'y')
 #mtx_y90n      = RotationMatrix(-90, 3, 'y')
@@ -123,14 +141,14 @@ mtx_x90           = RotationMatrix( 90, 3, 'x') # used
 #mtx_z90n      = RotationMatrix(-90, 3, 'z')
 
 #mtx4_x90      = RotationMatrix( 90, 4, 'x')
-mtx4_x90n      = RotationMatrix(-90, 4, 'x') # used
+mtx4_x90n      = Mathutils.RotationMatrix(-math.pi/2, 4, 'x') # used
 #mtx4_y90      = RotationMatrix( 90, 4, 'y')
-mtx4_y90n      = RotationMatrix(-90, 4, 'y') # used
-mtx4_z90       = RotationMatrix( 90, 4, 'z') # used
-mtx4_z90n      = RotationMatrix(-90, 4, 'z') # used
+mtx4_y90n      = Mathutils.RotationMatrix(-math.pi/2, 4, 'y') # used
+mtx4_z90       = Mathutils.RotationMatrix( math.pi/2, 4, 'z') # used
+mtx4_z90n      = Mathutils.RotationMatrix(-math.pi/2, 4, 'z') # used
 
-def strip_path(p):
-       return p.split('\\')[-1].split('/')[-1]
+def strip_path(p):
+#      return p.split('\\')[-1].split('/')[-1]
 
 # Used to add the scene name into the filename without using odd chars 
 sane_name_mapping_ob = {}
@@ -186,7 +204,7 @@ def sane_name(data, dct):
                #name = BPySys.cleanName(name)
                name = cleanName(name) # use our own
        
-       while name in dct.itervalues(): name = increment_string(name)
+       while name in iter(dct.values()):       name = increment_string(name)
        
        if use_other: # even if other is None - orig_name_other will be a string or None
                dct[orig_name, orig_name_other] = name
@@ -201,27 +219,70 @@ def sane_texname(data):           return sane_name(data, sane_name_mapping_tex)
 def sane_takename(data):       return sane_name(data, sane_name_mapping_take)
 def sane_groupname(data):      return sane_name(data, sane_name_mapping_group)
 
-def derived_paths(fname_orig, basepath, FORCE_CWD=False):
-       '''
-       fname_orig - blender path, can be relative
-       basepath - fname_rel will be relative to this
-       FORCE_CWD - dont use the basepath, just add a ./ to the filename.
-               use when we know the file will be in the basepath.
-       '''
-       fname = Blender.sys.expandpath(fname_orig)
-       fname_strip = strip_path(fname)
-       if FORCE_CWD:   fname_rel = '.' + Blender.sys.sep + fname_strip
-       else:                           fname_rel = Blender.sys.relpath(fname, basepath)
-       if fname_rel.startswith('//'): fname_rel = '.' + Blender.sys.sep + fname_rel[2:]
-       return fname, fname_strip, fname_rel
+# def derived_paths(fname_orig, basepath, FORCE_CWD=False):
+#      '''
+#      fname_orig - blender path, can be relative
+#      basepath - fname_rel will be relative to this
+#      FORCE_CWD - dont use the basepath, just add a ./ to the filename.
+#              use when we know the file will be in the basepath.
+#      '''
+#      fname = bpy.sys.expandpath(fname_orig)
+# #    fname = Blender.sys.expandpath(fname_orig)
+#      fname_strip = os.path.basename(fname)
+# #    fname_strip = strip_path(fname)
+#      if FORCE_CWD:
+#              fname_rel = '.' + os.sep + fname_strip
+#      else:
+#              fname_rel = bpy.sys.relpath(fname, basepath)
+# #            fname_rel = Blender.sys.relpath(fname, basepath)
+#      if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:]
+#      return fname, fname_strip, fname_rel
 
 
 def mat4x4str(mat):
        return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ])
 
+# XXX not used
+# duplicated in OBJ exporter
+def getVertsFromGroup(me, group_index):
+       ret = []
+
+       for i, v in enumerate(me.verts):
+               for g in v.groups:
+                       if g.group == group_index:
+                               ret.append((i, g.weight))
+
+               return ret
+
+# ob must be OB_MESH
+def BPyMesh_meshWeight2List(ob):
+       ''' Takes a mesh and return its group names and a list of lists, one list per vertex.
+       aligning the each vert list with the group names, each list contains float value for the weight.
+       These 2 lists can be modified and then used with list2MeshWeight to apply the changes.
+       '''
+
+       me = ob.data
+
+       # Clear the vert group.
+       groupNames= [g.name for g in ob.vertex_groups]
+       len_groupNames= len(groupNames)
+       
+       if not len_groupNames:
+               # no verts? return a vert aligned empty list
+               return [[] for i in range(len(me.verts))], []
+       else:
+               vWeightList= [[0.0]*len_groupNames for i in range(len(me.verts))]
+
+       for i, v in enumerate(me.verts):
+               for g in v.groups:
+                       vWeightList[i][g.group] = g.weight
+
+       return groupNames, vWeightList
+
 def meshNormalizedWeights(me):
        try: # account for old bad BPyMesh
-               groupNames, vWeightList = BPyMesh.meshWeight2List(me)
+               groupNames, vWeightList = BPyMesh_meshWeight2List(me)
+#              groupNames, vWeightList = BPyMesh.meshWeight2List(me)
        except:
                return [],[]
        
@@ -249,23 +310,23 @@ header_comment = \
 
 # This func can be called with just the filename
 def write(filename, batch_objects = None, \
+               context = None,
                EXP_OBS_SELECTED =                      True,
                EXP_MESH =                                      True,
                EXP_MESH_APPLY_MOD =            True,
-               EXP_MESH_HQ_NORMALS =           False,
+#              EXP_MESH_HQ_NORMALS =           False,
                EXP_ARMATURE =                          True,
                EXP_LAMP =                                      True,
                EXP_CAMERA =                            True,
                EXP_EMPTY =                                     True,
                EXP_IMAGE_COPY =                        False,
-               GLOBAL_MATRIX =                         Matrix(),
+               GLOBAL_MATRIX =                         Mathutils.Matrix(),
                ANIM_ENABLE =                           True,
                ANIM_OPTIMIZE =                         True,
                ANIM_OPTIMIZE_PRECISSION =      6,
                ANIM_ACTION_ALL =                       False,
                BATCH_ENABLE =                          False,
                BATCH_GROUP =                           True,
-               BATCH_SCENE =                           False,
                BATCH_FILE_PREFIX =                     '',
                BATCH_OWN_DIR =                         False
        ):
@@ -277,23 +338,31 @@ def write(filename, batch_objects = None, \
                fbxpath = filename
                
                # get the path component of filename
-               tmp_exists = Blender.sys.exists(fbxpath)
+               tmp_exists = bpy.sys.exists(fbxpath)
+#              tmp_exists = Blender.sys.exists(fbxpath)
                
                if tmp_exists != 2: # a file, we want a path
-                       while fbxpath and fbxpath[-1] not in ('/', '\\'):
-                               fbxpath = fbxpath[:-1]
-                       if not filename:
-                               Draw.PupMenu('Error%t|Directory does not exist!')
+                       fbxpath = os.path.dirname(fbxpath)
+#                      while fbxpath and fbxpath[-1] not in ('/', '\\'):
+#                              fbxpath = fbxpath[:-1]
+                       if not fbxpath:
+#                      if not filename:
+                               # XXX
+                               print('Error%t|Directory does not exist!')
+#                              Draw.PupMenu('Error%t|Directory does not exist!')
                                return
-                       
-                       tmp_exists = Blender.sys.exists(fbxpath)
+
+                       tmp_exists = bpy.sys.exists(fbxpath)
+#                      tmp_exists = Blender.sys.exists(fbxpath)
                
                if tmp_exists != 2:
-                       Draw.PupMenu('Error%t|Directory does not exist!')
+                       # XXX
+                       print('Error%t|Directory does not exist!')
+#                      Draw.PupMenu('Error%t|Directory does not exist!')
                        return
                
-               if not fbxpath.endswith(Blender.sys.sep):
-                       fbxpath += Blender.sys.sep
+               if not fbxpath.endswith(os.sep):
+                       fbxpath += os.sep
                del tmp_exists
                
                
@@ -303,27 +372,31 @@ def write(filename, batch_objects = None, \
                        data_seq = bpy.data.scenes
                
                # call this function within a loop with BATCH_ENABLE == False
-               orig_sce = bpy.data.scenes.active
+               orig_sce = context.scene
+#              orig_sce = bpy.data.scenes.active
                
                
                new_fbxpath = fbxpath # own dir option modifies, we need to keep an original
                for data in data_seq: # scene or group
-                       newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name)
+                       newname = BATCH_FILE_PREFIX + cleanName(data.name)
+#                      newname = BATCH_FILE_PREFIX + BPySys.cleanName(data.name)
                        
                        
                        if BATCH_OWN_DIR:
-                               new_fbxpath = fbxpath + newname + Blender.sys.sep
+                               new_fbxpath = fbxpath + newname + os.sep
                                # path may alredy exist
                                # TODO - might exist but be a file. unlikely but should probably account for it.
-                               
-                               if Blender.sys.exists(new_fbxpath) == 0:
+
+                               if bpy.sys.exists(new_fbxpath) == 0:
+#                              if Blender.sys.exists(new_fbxpath) == 0:
                                        os.mkdir(new_fbxpath)
                                
                        
                        filename = new_fbxpath + newname + '.fbx'
                        
-                       print '\nBatch exporting %s as...\n\t"%s"' % (data, filename)
-                       
+                       print('\nBatch exporting %s as...\n\t"%s"' % (data, filename))
+
+                       # XXX don't know what to do with this, probably do the same? (Arystan)
                        if BATCH_GROUP: #group
                                # group, so objects update properly, add a dummy scene.
                                sce = bpy.data.scenes.new()
@@ -345,10 +418,11 @@ def write(filename, batch_objects = None, \
                        # Call self with modified args
                        # Dont pass batch options since we alredy usedt them
                        write(filename, data.objects,
+                               context,
                                False,
                                EXP_MESH,
                                EXP_MESH_APPLY_MOD,
-                               EXP_MESH_HQ_NORMALS,
+#                              EXP_MESH_HQ_NORMALS,
                                EXP_ARMATURE,
                                EXP_LAMP,
                                EXP_CAMERA,
@@ -363,7 +437,8 @@ def write(filename, batch_objects = None, \
                        
                        if BATCH_GROUP:
                                # remove temp group scene
-                               bpy.data.scenes.unlink(sce)
+                               bpy.data.remove_scene(sce)
+#                              bpy.data.scenes.unlink(sce)
                
                bpy.data.scenes.active = orig_sce
                
@@ -372,7 +447,9 @@ def write(filename, batch_objects = None, \
        # end batch support
        
        # Use this for working out paths relative to the export location
-       basepath = Blender.sys.dirname(filename)
+       basepath = os.path.dirname(filename) or '.'
+       basepath += os.sep
+#      basepath = Blender.sys.dirname(filename)
        
        # ----------------------------------------------
        # storage classes
@@ -398,7 +475,8 @@ def write(filename, batch_objects = None, \
                        self.blenBone =                 blenBone
                        self.blenMeshes =               {}                                      # fbxMeshObName : mesh
                        self.fbxArm =                   fbxArm
-                       self.restMatrix =               blenBone.matrix['ARMATURESPACE']
+                       self.restMatrix =               blenBone.armature_matrix
+#                      self.restMatrix =               blenBone.matrix['ARMATURESPACE']
                        
                        # not used yet
                        # self.restMatrixInv =  self.restMatrix.copy().invert()
@@ -407,8 +485,10 @@ def write(filename, batch_objects = None, \
                        self.parent =                   None
                        
                        # not public
-                       pose = fbxArm.blenObject.getPose()
-                       self.__pose_bone =              pose.bones[self.blenName]
+                       pose = fbxArm.blenObject.pose
+#                      pose = fbxArm.blenObject.getPose()
+                       self.__pose_bone =              pose.pose_channels[self.blenName]
+#                      self.__pose_bone =              pose.bones[self.blenName]
                        
                        # store a list if matricies here, (poseMatrix, head, tail)
                        # {frame:posematrix, frame:posematrix, ...}
@@ -431,8 +511,9 @@ def write(filename, batch_objects = None, \
                                self.__pose_bone.head.copy(),\
                                self.__pose_bone.tail.copy() )
                        '''
-                       
-                       self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy()
+
+                       self.__anim_poselist[f] = self.__pose_bone.pose_matrix.copy()
+#                      self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy()
                
                # get pose from frame.
                def getPoseMatrix(self, f):# ----------------------------------------------
@@ -473,7 +554,8 @@ def write(filename, batch_objects = None, \
                        self.fbxGroupNames = []
                        self.fbxParent = None # set later on IF the parent is in the selection.
                        if matrixWorld:         self.matrixWorld = matrixWorld * GLOBAL_MATRIX
-                       else:                           self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX
+                       else:                           self.matrixWorld = ob.matrix * GLOBAL_MATRIX
+#                      else:                           self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX
                        self.__anim_poselist = {} # we should only access this
                
                def parRelMatrix(self):
@@ -483,7 +565,8 @@ def write(filename, batch_objects = None, \
                                return self.matrixWorld
                
                def setPoseFrame(self, f):
-                       self.__anim_poselist[f] =  self.blenObject.matrixWorld.copy()
+                       self.__anim_poselist[f] =  self.blenObject.matrix.copy()
+#                      self.__anim_poselist[f] =  self.blenObject.matrixWorld.copy()
                
                def getAnimParRelMatrix(self, frame):
                        if self.fbxParent:
@@ -500,11 +583,12 @@ def write(filename, batch_objects = None, \
                                matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotationPart()
                        
                        # Lamps need to be rotated
-                       if type =='Lamp':
+                       if type =='LAMP':
                                matrix_rot = mtx_x90 * matrix_rot
-                       elif ob and type =='Camera':
-                               y = Vector(0,1,0) * matrix_rot
-                               matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y)
+                       elif type =='CAMERA':
+#                      elif ob and type =='Camera':
+                               y = Mathutils.Vector(0,1,0) * matrix_rot
+                               matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y)
                        
                        return matrix_rot
                        
@@ -514,14 +598,16 @@ def write(filename, batch_objects = None, \
        
        
        
-       print '\nFBX export starting...', filename
-       start_time = Blender.sys.time()
+       print('\nFBX export starting...', filename)
+       start_time = time.clock()
+#      start_time = Blender.sys.time()
        try:
                file = open(filename, 'w')
        except:
                return False
-       
-       sce = bpy.data.scenes.active
+
+       sce = context.scene
+#      sce = bpy.data.scenes.active
        world = sce.world
        
        
@@ -553,7 +639,8 @@ def write(filename, batch_objects = None, \
 }''' % (curtime))
        
        file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime)
-       file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version'))
+       file.write('\nCreator: "Blender3D version 2.5"')
+#      file.write('\nCreator: "Blender3D version %.2f"' % Blender.Get('version'))
        
        pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way
        
@@ -562,16 +649,19 @@ def write(filename, batch_objects = None, \
                '''
                Matrix mod is so armature objects can modify their bone matricies
                '''
-               if isinstance(ob, Blender.Types.BoneType):
+               if isinstance(ob, bpy.types.Bone):
+#              if isinstance(ob, Blender.Types.BoneType):
                        
                        # we know we have a matrix
                        # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod)
-                       matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
+                       matrix = mtx4_z90 * ob.armature_matrix # dont apply armature matrix anymore
+#                      matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
                        
                        parent = ob.parent
                        if parent:
                                #par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod)
-                               par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
+                               par_matrix = mtx4_z90 * parent.armature_matrix # dont apply armature matrix anymore
+#                              par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
                                matrix = matrix * par_matrix.copy().invert()
                                
                        matrix_rot =    matrix.rotationPart()
@@ -583,7 +673,7 @@ def write(filename, batch_objects = None, \
                else:
                        # This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore
                        #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX
-                       if ob and not matrix: raise "error: this should never happen!"
+                       if ob and not matrix: raise Exception("error: this should never happen!")
                        
                        matrix_rot = matrix
                        #if matrix:
@@ -599,8 +689,8 @@ def write(filename, batch_objects = None, \
                                        matrix_rot = mtx_x90 * matrix_rot
                                        rot = tuple(matrix_rot.toEuler())
                                elif ob and ob.type =='Camera':
-                                       y = Vector(0,1,0) * matrix_rot
-                                       matrix_rot = matrix_rot * RotationMatrix(90, 3, 'r', y)
+                                       y = Mathutils.Vector(0,1,0) * matrix_rot
+                                       matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, 'r', y)
                                        rot = tuple(matrix_rot.toEuler())
                                else:
                                        rot = tuple(matrix_rot.toEuler())
@@ -621,7 +711,8 @@ def write(filename, batch_objects = None, \
                loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod)
                
                file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc)
-               file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot)
+               file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % tuple(eulerRadToDeg(rot)))
+#              file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot)
                file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale)
                return loc, rot, scale, matrix, matrix_rot
        
@@ -708,7 +799,8 @@ def write(filename, batch_objects = None, \
                        Property: "Show", "bool", "",1
                        Property: "NegativePercentShapeSupport", "bool", "",1
                        Property: "DefaultAttributeIndex", "int", "",0''')
-               if ob and type(ob) != Blender.Types.BoneType:
+               if ob and not isinstance(ob, bpy.types.Bone):
+#              if ob and type(ob) != Blender.Types.BoneType:
                        # Only mesh objects have color 
                        file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
                        file.write('\n\t\t\tProperty: "Size", "double", "",100')
@@ -738,8 +830,9 @@ def write(filename, batch_objects = None, \
                        ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length)
                """
                
-               file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\
-                       (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length)
+               file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %
+                                  (my_bone.blenBone.armature_head - my_bone.blenBone.armature_tail).length)
+#                      (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length)
                
                #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1')
                file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8')
@@ -878,9 +971,12 @@ def write(filename, batch_objects = None, \
                '''
                Write a blender camera
                '''
-               render = sce.render
-               width   = render.sizeX
-               height  = render.sizeY
+               render = sce.render_data
+               width   = render.resolution_x
+               height  = render.resolution_y
+#              render = sce.render
+#              width   = render.sizeX
+#              height  = render.sizeY
                aspect  = float(width)/height
                
                data = my_cam.blenObject.data
@@ -894,8 +990,10 @@ def write(filename, batch_objects = None, \
                file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1')
                file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1')
                file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026')
-               file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units?
-               file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto 
+               file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shift_x) # not sure if this is in the correct units?
+#              file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shiftX) # not sure if this is in the correct units?
+               file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shift_y) # ditto 
+#              file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shiftY) # ditto 
                file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0')
                file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0')
                file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1')
@@ -927,8 +1025,10 @@ def write(filename, batch_objects = None, \
                file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0')
                file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1')
                file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0')
-               file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart)
-               file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart)
+               file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clip_start)
+#              file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clipStart)
+               file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clip_end)
+#              file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clipStart)
                file.write('\n\t\t\tProperty: "FilmWidth", "double", "",1.0')
                file.write('\n\t\t\tProperty: "FilmHeight", "double", "",1.0')
                file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",%.6f' % aspect)
@@ -975,8 +1075,8 @@ def write(filename, batch_objects = None, \
                file.write('\n\t\tTypeFlags: "Camera"')
                file.write('\n\t\tGeometryVersion: 124')
                file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc)
-               file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Vector(0,1,0) * matrix_rot) )
-               file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Vector(0,0,-1)*matrix_rot) )
+               file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,1,0) * matrix_rot) )
+               file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,0,-1)*matrix_rot) )
                
                #file.write('\n\t\tUp: 0,0,0' )
                #file.write('\n\t\tLookAt: 0,0,0' )
@@ -1001,16 +1101,20 @@ def write(filename, batch_objects = None, \
                #ePOINT, 
                #eDIRECTIONAL
                #eSPOT
-               light_type = light.type
+               light_type_items = {'POINT': 0, 'SUN': 1, 'SPOT': 2, 'HEMI': 3, 'AREA': 4}
+               light_type = light_type_items[light.type]
+#              light_type = light.type
                if light_type > 2: light_type = 1 # hemi and area lights become directional
-               
-               mode = light.mode
-               if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows:
+
+#              mode = light.mode
+               if light.shadow_method == 'RAY_SHADOW' or light.shadow_method == 'BUFFER_SHADOW':
+#              if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows:
                        do_shadow = 1
                else:
                        do_shadow = 0
-               
-               if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular):
+
+               if light.only_shadow or (not light.diffuse and not light.specular):
+#              if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular):
                        do_light = 0
                else:
                        do_light = 1
@@ -1025,11 +1129,16 @@ def write(filename, batch_objects = None, \
                file.write('\n\t\t\tProperty: "GoboProperty", "object", ""')
                file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1')
                file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200
-               file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale))
+               if light.type == 'SPOT':
+                       file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spot_size * scale))
+#              file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale))
                file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50')
-               file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col))
+               file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.color))
+#              file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.col))
                file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200
-               file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale))
+# 
+               # duplication? see ^ (Arystan)
+#              file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % (light.spotSize * scale))
                file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50')
                file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type)
                file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light)
@@ -1038,7 +1147,8 @@ def write(filename, batch_objects = None, \
                file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1')
                file.write('\n\t\t\tProperty: "GoboProperty", "object", ""')
                file.write('\n\t\t\tProperty: "DecayType", "enum", "",0')
-               file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist)
+               file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.distance)
+#              file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.dist)
                file.write('\n\t\t\tProperty: "EnableNearAttenuation", "bool", "",0')
                file.write('\n\t\t\tProperty: "NearAttenuationStart", "double", "",0')
                file.write('\n\t\t\tProperty: "NearAttenuationEnd", "double", "",0')
@@ -1084,7 +1194,8 @@ def write(filename, batch_objects = None, \
        }''')
        
        # Material Settings
-       if world:       world_amb = world.getAmb()
+       if world:       world_amb = tuple(world.ambient_color)
+#      if world:       world_amb = world.getAmb()
        else:           world_amb = (0,0,0) # Default value
        
        def write_material(matname, mat):
@@ -1092,22 +1203,31 @@ def write(filename, batch_objects = None, \
                
                # Todo, add more material Properties.
                if mat:
-                       mat_cold = tuple(mat.rgbCol)
-                       mat_cols = tuple(mat.specCol)
+                       mat_cold = tuple(mat.diffuse_color)
+#                      mat_cold = tuple(mat.rgbCol)
+                       mat_cols = tuple(mat.specular_color)
+#                      mat_cols = tuple(mat.specCol)
                        #mat_colm = tuple(mat.mirCol) # we wont use the mirror color
-                       mat_colamb = tuple([c for c in world_amb])
-                       
-                       mat_dif = mat.ref
-                       mat_amb = mat.amb
-                       mat_hard = (float(mat.hard)-1)/5.10
-                       mat_spec = mat.spec/2.0
+                       mat_colamb = world_amb
+#                      mat_colamb = tuple([c for c in world_amb])
+
+                       mat_dif = mat.diffuse_intensity
+#                      mat_dif = mat.ref
+                       mat_amb = mat.ambient
+#                      mat_amb = mat.amb
+                       mat_hard = (float(mat.specular_hardness)-1)/5.10
+#                      mat_hard = (float(mat.hard)-1)/5.10
+                       mat_spec = mat.specular_intensity/2.0
+#                      mat_spec = mat.spec/2.0
                        mat_alpha = mat.alpha
                        mat_emit = mat.emit
-                       mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS
+                       mat_shadeless = mat.shadeless
+#                      mat_shadeless = mat.mode & Blender.Material.Modes.SHADELESS
                        if mat_shadeless:
                                mat_shader = 'Lambert'
                        else:
-                               if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT:
+                               if mat.diffuse_shader == 'LAMBERT':
+#                              if mat.diffuseShader == Blender.Material.Shaders.DIFFUSE_LAMBERT:
                                        mat_shader = 'Lambert'
                                else:
                                        mat_shader = 'Phong'
@@ -1159,7 +1279,20 @@ def write(filename, batch_objects = None, \
 
                file.write('\n\t\t}')
                file.write('\n\t}')
-       
+
+       def copy_image(image):
+
+               rel = image.get_export_path(basepath, True)
+               base = os.path.basename(rel)
+
+               if EXP_IMAGE_COPY:
+                       absp = image.get_export_path(basepath, False)
+                       if not os.path.exists(absp):
+                               shutil.copy(image.get_abs_filename(), absp)
+
+               return (rel, base)
+
+       # tex is an Image (Arystan)
        def write_video(texname, tex):
                # Same as texture really!
                file.write('\n\tVideo: "Video::%s", "Clip" {' % texname)
@@ -1172,7 +1305,8 @@ def write(filename, batch_objects = None, \
                        Property: "Width", "int", "",0
                        Property: "Height", "int", "",0''')
                if tex:
-                       fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
+                       fname_rel, fname_strip = copy_image(tex)
+#                      fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
                else:
                        fname = fname_strip = fname_rel = ''
                
@@ -1221,9 +1355,11 @@ def write(filename, batch_objects = None, \
                        Property: "UseMipMap", "bool", "",0
                        Property: "CurrentMappingType", "enum", "",0
                        Property: "UVSwap", "bool", "",0''')
-               
-               file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX)
-               file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY)
+
+               file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clamp_x)
+#              file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.clampX)
+               file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clamp_y)
+#              file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.clampY)
                
                file.write('''
                        Property: "TextureRotationPivot", "Vector3D", "",0,0,0
@@ -1234,7 +1370,8 @@ def write(filename, batch_objects = None, \
                file.write('\n\t\tMedia: "Video::%s"' % texname)
                
                if tex:
-                       fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
+                       fname_rel, fname_strip = copy_image(tex)
+#                      fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
                else:
                        fname = fname_strip = fname_rel = ''
                
@@ -1290,7 +1427,7 @@ def write(filename, batch_objects = None, \
                                # TODO - this is a bit lazy, we could have a simple write loop
                                # for this case because all weights are 1.0 but for now this is ok
                                # Parent Bones arent used all that much anyway.
-                               vgroup_data = [(j, 1.0) for j in xrange(len(my_mesh.blenData.verts))]
+                               vgroup_data = [(j, 1.0) for j in range(len(my_mesh.blenData.verts))]
                        else:
                                # This bone is not a parent of this mesh object, no weights
                                vgroup_data = []
@@ -1358,7 +1495,8 @@ def write(filename, batch_objects = None, \
                if my_mesh.blenTextures:        do_textures = True
                else:                                           do_textures = False     
                
-               do_uvs = me.faceUV
+               do_uvs = len(me.uv_textures) > 0
+#              do_uvs = me.faceUV
                
                
                file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName)
@@ -1390,20 +1528,25 @@ def write(filename, batch_objects = None, \
                file.write('\n\t\tPolygonVertexIndex: ')
                i=-1
                for f in me.faces:
-                       fi = [v.index for v in f]
+                       fi = f.verts
+                       # fi = [v_index for j, v_index in enumerate(f.verts) if v_index != 0 or j != 3]
+#                      fi = [v.index for v in f]
+
                        # flip the last index, odd but it looks like
                        # this is how fbx tells one face from another
                        fi[-1] = -(fi[-1]+1)
                        fi = tuple(fi)
                        if i==-1:
-                               if len(f) == 3:         file.write('%i,%i,%i' % fi )
+                               if len(fi) == 3:        file.write('%i,%i,%i' % fi )
+#                              if len(f) == 3:         file.write('%i,%i,%i' % fi )
                                else:                           file.write('%i,%i,%i,%i' % fi )
                                i=0
                        else:
                                if i==13:
                                        file.write('\n\t\t')
                                        i=0
-                               if len(f) == 3:         file.write(',%i,%i,%i' % fi )
+                               if len(fi) == 3:        file.write(',%i,%i,%i' % fi )
+#                              if len(f) == 3:         file.write(',%i,%i,%i' % fi )
                                else:                           file.write(',%i,%i,%i,%i' % fi )
                        i+=1
                
@@ -1411,13 +1554,15 @@ def write(filename, batch_objects = None, \
                i=-1
                for ed in me.edges:
                                if i==-1:
-                                       file.write('%i,%i' % (ed.v1.index, ed.v2.index))
+                                       file.write('%i,%i' % (ed.verts[0], ed.verts[1]))
+#                                      file.write('%i,%i' % (ed.v1.index, ed.v2.index))
                                        i=0
                                else:
                                        if i==13:
                                                file.write('\n\t\t')
                                                i=0
-                                       file.write(',%i,%i' % (ed.v1.index, ed.v2.index))
+                                       file.write(',%i,%i' % (ed.verts[0], ed.verts[1]))
+#                                      file.write(',%i,%i' % (ed.v1.index, ed.v2.index))
                                i+=1
                
                file.write('\n\t\tGeometryVersion: 124')
@@ -1433,11 +1578,13 @@ def write(filename, batch_objects = None, \
                i=-1
                for v in me.verts:
                        if i==-1:
-                               file.write('%.15f,%.15f,%.15f' % tuple(v.no));  i=0
+                               file.write('%.15f,%.15f,%.15f' % tuple(v.normal));      i=0
+#                              file.write('%.15f,%.15f,%.15f' % tuple(v.no));  i=0
                        else:
                                if i==2:
                                        file.write('\n                   ');    i=0
-                               file.write(',%.15f,%.15f,%.15f' % tuple(v.no))
+                               file.write(',%.15f,%.15f,%.15f' % tuple(v.normal))
+#                              file.write(',%.15f,%.15f,%.15f' % tuple(v.no))
                        i+=1
                file.write('\n\t\t}')
                
@@ -1464,39 +1611,53 @@ def write(filename, batch_objects = None, \
                
                # Write Edge Smoothing
                file.write('''
-               LayerElementSmoothing: 1 {
+               LayerElementSmoothing: 0 {
                        Version: 101
                        Name: ""
                        MappingInformationType: "ByEdge"
                        ReferenceInformationType: "Direct"
                        Smoothing: ''')
                
-               SHARP = Blender.Mesh.EdgeFlags.SHARP
+#              SHARP = Blender.Mesh.EdgeFlags.SHARP
                i=-1
                for ed in me.edges:
                        if i==-1:
-                               file.write('%i' % ((ed.flag&SHARP)!=0));        i=0
+                               file.write('%i' % (ed.sharp));  i=0
+#                              file.write('%i' % ((ed.flag&SHARP)!=0));        i=0
                        else:
                                if i==54:
                                        file.write('\n                   ');    i=0
-                               file.write(',%i' % ((ed.flag&SHARP)!=0))
+                               file.write(',%i' % (ed.sharp))
+#                              file.write(',%i' % ((ed.flag&SHARP)!=0))
                        i+=1
                
                file.write('\n\t\t}')
-               del SHARP
-               
+#              del SHARP
+
+               # small utility function
+               # returns a slice of data depending on number of face verts
+               # data is either a MeshTextureFace or MeshColor
+               def face_data(data, face):
+                       totvert = len(f.verts)
+                                               
+                       return data[:totvert]
+
                
                # Write VertexColor Layers
                # note, no programs seem to use this info :/
                collayers = []
-               if me.vertexColors:
-                       collayers = me.getColorLayerNames()
-                       collayer_orig = me.activeColorLayer
+               if len(me.vertex_colors):
+#              if me.vertexColors:
+                       collayers = me.vertex_colors
+#                      collayers = me.getColorLayerNames()
+                       collayer_orig = me.active_vertex_color
+#                      collayer_orig = me.activeColorLayer
                        for colindex, collayer in enumerate(collayers):
-                               me.activeColorLayer = collayer
+#                              me.activeColorLayer = collayer
                                file.write('\n\t\tLayerElementColor: %i {' % colindex)
                                file.write('\n\t\t\tVersion: 101')
-                               file.write('\n\t\t\tName: "%s"' % collayer)
+                               file.write('\n\t\t\tName: "%s"' % collayer.name)
+#                              file.write('\n\t\t\tName: "%s"' % collayer)
                                
                                file.write('''
                        MappingInformationType: "ByPolygonVertex"
@@ -1505,23 +1666,41 @@ def write(filename, batch_objects = None, \
                        
                                i = -1
                                ii = 0 # Count how many Colors we write
-                               
-                               for f in me.faces:
-                                       for col in f.col:
+
+                               for f, cf in zip(me.faces, collayer.data):
+                                       colors = [cf.color1, cf.color2, cf.color3, cf.color4]
+
+                                       # determine number of verts
+                                       colors = face_data(colors, f)
+
+                                       for col in colors:
                                                if i==-1:
-                                                       file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0))
+                                                       file.write('%.4f,%.4f,%.4f,1' % tuple(col))
                                                        i=0
                                                else:
                                                        if i==7:
                                                                file.write('\n\t\t\t\t')
                                                                i=0
-                                                       file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0))
+                                                       file.write(',%.4f,%.4f,%.4f,1' % tuple(col))
                                                i+=1
                                                ii+=1 # One more Color
+
+#                              for f in me.faces:
+#                                      for col in f.col:
+#                                              if i==-1:
+#                                                      file.write('%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0))
+#                                                      i=0
+#                                              else:
+#                                                      if i==7:
+#                                                              file.write('\n\t\t\t\t')
+#                                                              i=0
+#                                                      file.write(',%.4f,%.4f,%.4f,1' % (col[0]/255.0, col[1]/255.0, col[2]/255.0))
+#                                              i+=1
+#                                              ii+=1 # One more Color
                                
                                file.write('\n\t\t\tColorIndex: ')
                                i = -1
-                               for j in xrange(ii):
+                               for j in range(ii):
                                        if i == -1:
                                                file.write('%i' % j)
                                                i=0
@@ -1539,13 +1718,17 @@ def write(filename, batch_objects = None, \
                # Write UV and texture layers.
                uvlayers = []
                if do_uvs:
-                       uvlayers = me.getUVLayerNames()
-                       uvlayer_orig = me.activeUVLayer
-                       for uvindex, uvlayer in enumerate(uvlayers):
-                               me.activeUVLayer = uvlayer
+                       uvlayers = me.uv_textures
+#                      uvlayers = me.getUVLayerNames()
+                       uvlayer_orig = me.active_uv_texture
+#                      uvlayer_orig = me.activeUVLayer
+                       for uvindex, uvlayer in enumerate(me.uv_textures):
+#                      for uvindex, uvlayer in enumerate(uvlayers):
+#                              me.activeUVLayer = uvlayer
                                file.write('\n\t\tLayerElementUV: %i {' % uvindex)
                                file.write('\n\t\t\tVersion: 101')
-                               file.write('\n\t\t\tName: "%s"' % uvlayer)
+                               file.write('\n\t\t\tName: "%s"' % uvlayer.name)
+#                              file.write('\n\t\t\tName: "%s"' % uvlayer)
                                
                                file.write('''
                        MappingInformationType: "ByPolygonVertex"
@@ -1555,8 +1738,10 @@ def write(filename, batch_objects = None, \
                                i = -1
                                ii = 0 # Count how many UVs we write
                                
-                               for f in me.faces:
-                                       for uv in f.uv:
+                               for uf in uvlayer.data:
+#                              for f in me.faces:
+                                       for uv in uf.uv:
+#                                      for uv in f.uv:
                                                if i==-1:
                                                        file.write('%.6f,%.6f' % tuple(uv))
                                                        i=0
@@ -1570,7 +1755,7 @@ def write(filename, batch_objects = None, \
                                
                                file.write('\n\t\t\tUVIndex: ')
                                i = -1
-                               for j in xrange(ii):
+                               for j in range(ii):
                                        if i == -1:
                                                file.write('%i'  % j)
                                                i=0
@@ -1586,7 +1771,8 @@ def write(filename, batch_objects = None, \
                                if do_textures:
                                        file.write('\n\t\tLayerElementTexture: %i {' % uvindex)
                                        file.write('\n\t\t\tVersion: 101')
-                                       file.write('\n\t\t\tName: "%s"' % uvlayer)
+                                       file.write('\n\t\t\tName: "%s"' % uvlayer.name)
+#                                      file.write('\n\t\t\tName: "%s"' % uvlayer)
                                        
                                        if len(my_mesh.blenTextures) == 1:
                                                file.write('\n\t\t\tMappingInformationType: "AllSame"')
@@ -1610,7 +1796,8 @@ def write(filename, batch_objects = None, \
                                                                i+=1
                                                
                                                i=-1
-                                               for f in me.faces:
+                                               for f in uvlayer.data:
+#                                              for f in me.faces:
                                                        img_key = f.image
                                                        
                                                        if i==-1:
@@ -1636,7 +1823,7 @@ def write(filename, batch_objects = None, \
                        TextureId: ''')
                                file.write('\n\t\t}')
                        
-                       me.activeUVLayer = uvlayer_orig
+#                      me.activeUVLayer = uvlayer_orig
                        
                # Done with UV/textures.
                
@@ -1665,13 +1852,21 @@ def write(filename, batch_objects = None, \
                                len_material_mapping_local = len(material_mapping_local)
                                
                                mats = my_mesh.blenMaterialList
+
+                               if me.active_uv_texture:
+                                       uv_faces = me.active_uv_texture.data
+                               else:
+                                       uv_faces = [None] * len(me.faces)
                                
                                i=-1
-                               for f in me.faces:
-                                       try:    mat = mats[f.mat]
+                               for f, uf in zip(me.faces, uv_faces):
+#                              for f in me.faces:
+                                       try:    mat = mats[f.material_index]
+#                                      try:    mat = mats[f.mat]
                                        except:mat = None
                                        
-                                       if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/
+                                       if do_uvs: tex = uf.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/
+#                                      if do_uvs: tex = f.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/
                                        else: tex = None
                                        
                                        if i==-1:
@@ -1710,7 +1905,8 @@ def write(filename, batch_objects = None, \
                                TypedIndex: 0
                        }''')
                
-               if me.vertexColors:
+               if me.vertex_colors:
+#              if me.vertexColors:
                        file.write('''
                        LayerElement:  {
                                Type: "LayerElementColor"
@@ -1728,7 +1924,7 @@ def write(filename, batch_objects = None, \
                file.write('\n\t\t}')
                
                if len(uvlayers) > 1:
-                       for i in xrange(1, len(uvlayers)):
+                       for i in range(1, len(uvlayers)):
                                
                                file.write('\n\t\tLayer: %i {' % i)
                                file.write('\n\t\t\tVersion: 100')
@@ -1756,7 +1952,7 @@ def write(filename, batch_objects = None, \
                        layer_offset = 0
                        if uvlayers: layer_offset = len(uvlayers)-1
                        
-                       for i in xrange(layer_offset, len(collayers)+layer_offset):
+                       for i in range(layer_offset, len(collayers)+layer_offset):
                                file.write('\n\t\tLayer: %i {' % i)
                                file.write('\n\t\t\tVersion: 100')
                                
@@ -1806,7 +2002,8 @@ def write(filename, batch_objects = None, \
        
        # if EXP_OBS_SELECTED is false, use sceens objects
        if not batch_objects:
-               if EXP_OBS_SELECTED:    tmp_objects = sce.objects.context
+               if EXP_OBS_SELECTED:    tmp_objects = context.selected_objects
+#              if EXP_OBS_SELECTED:    tmp_objects = sce.objects.context
                else:                                   tmp_objects = sce.objects
        else:
                tmp_objects = batch_objects
@@ -1815,43 +2012,63 @@ def write(filename, batch_objects = None, \
                # This is needed so applying modifiers dosnt apply the armature deformation, its also needed
                # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes.
                # set every armature to its rest, backup the original values so we done mess up the scene
-               ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures]
+               ob_arms_orig_rest = [arm.rest_position for arm in bpy.data.armatures]
+#              ob_arms_orig_rest = [arm.restPosition for arm in bpy.data.armatures]
                
                for arm in bpy.data.armatures:
-                       arm.restPosition = True
+                       arm.rest_position = True
+#                      arm.restPosition = True
                
                if ob_arms_orig_rest:
                        for ob_base in bpy.data.objects:
                                #if ob_base.type == 'Armature':
-                               ob_base.makeDisplayList()
+                               ob_base.make_display_list()
+#                              ob_base.makeDisplayList()
                                        
                        # This causes the makeDisplayList command to effect the mesh
-                       Blender.Set('curframe', Blender.Get('curframe'))
+                       sce.set_frame(sce.current_frame)
+#                      Blender.Set('curframe', Blender.Get('curframe'))
                        
        
        for ob_base in tmp_objects:
-               for ob, mtx in BPyObject.getDerivedObjects(ob_base):
-                       #for ob in [ob_base,]:
+
+               # ignore dupli children
+               if ob_base.parent and ob_base.parent.dupli_type != 'NONE':
+                       continue
+
+               obs = [(ob_base, ob_base.matrix)]
+               if ob_base.dupli_type != 'NONE':
+                       ob_base.create_dupli_list()
+                       obs = [(dob.object, dob.matrix) for dob in ob_base.dupli_list]
+
+               for ob, mtx in obs:
+#              for ob, mtx in BPyObject.getDerivedObjects(ob_base):
                        tmp_ob_type = ob.type
-                       if tmp_ob_type == 'Camera':
+                       if tmp_ob_type == 'CAMERA':
+#                      if tmp_ob_type == 'Camera':
                                if EXP_CAMERA:
                                        ob_cameras.append(my_object_generic(ob, mtx))
-                       elif tmp_ob_type == 'Lamp':
+                       elif tmp_ob_type == 'LAMP':
+#                      elif tmp_ob_type == 'Lamp':
                                if EXP_LAMP:
                                        ob_lights.append(my_object_generic(ob, mtx))
-                       elif tmp_ob_type == 'Armature':
+                       elif tmp_ob_type == 'ARMATURE':
+#                      elif tmp_ob_type == 'Armature':
                                if EXP_ARMATURE:
                                        # TODO - armatures dont work in dupligroups!
                                        if ob not in ob_arms: ob_arms.append(ob)
                                        # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)"
-                       elif tmp_ob_type == 'Empty':
+                       elif tmp_ob_type == 'EMPTY':
+#                      elif tmp_ob_type == 'Empty':
                                if EXP_EMPTY:
                                        ob_null.append(my_object_generic(ob, mtx))
                        elif EXP_MESH:
                                origData = True
-                               if tmp_ob_type != 'Mesh':
-                                       me = bpy.data.meshes.new()
-                                       try:    me.getFromObject(ob)
+                               if tmp_ob_type != 'MESH':
+#                              if tmp_ob_type != 'Mesh':
+#                                      me = bpy.data.meshes.new()
+                                       try:    me = ob.create_mesh(True, 'PREVIEW')
+#                                      try:    me.getFromObject(ob)
                                        except: me = None
                                        if me:
                                                meshes_to_clear.append( me )
@@ -1860,63 +2077,71 @@ def write(filename, batch_objects = None, \
                                else:
                                        # Mesh Type!
                                        if EXP_MESH_APPLY_MOD:
-                                               me = bpy.data.meshes.new()
-                                               me.getFromObject(ob)
+#                                              me = bpy.data.meshes.new()
+                                               me = ob.create_mesh(True, 'PREVIEW')
+#                                              me.getFromObject(ob)
                                                
                                                # so we keep the vert groups
-                                               if EXP_ARMATURE:
-                                                       orig_mesh = ob.getData(mesh=1)
-                                                       if orig_mesh.getVertGroupNames():
-                                                               ob.copy().link(me)
-                                                               # If new mesh has no vgroups we can try add if verts are teh same
-                                                               if not me.getVertGroupNames(): # vgroups were not kept by the modifier
-                                                                       if len(me.verts) == len(orig_mesh.verts):
-                                                                               groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh)
-                                                                               BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
+#                                              if EXP_ARMATURE:
+#                                                      orig_mesh = ob.getData(mesh=1)
+#                                                      if orig_mesh.getVertGroupNames():
+#                                                              ob.copy().link(me)
+#                                                              # If new mesh has no vgroups we can try add if verts are teh same
+#                                                              if not me.getVertGroupNames(): # vgroups were not kept by the modifier
+#                                                                      if len(me.verts) == len(orig_mesh.verts):
+#                                                                              groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh)
+#                                                                              BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
                                                
                                                # print ob, me, me.getVertGroupNames()
                                                meshes_to_clear.append( me )
                                                origData = False
                                                mats = me.materials
                                        else:
-                                               me = ob.getData(mesh=1)
+                                               me = ob.data
+#                                              me = ob.getData(mesh=1)
                                                mats = me.materials
                                                
-                                               # Support object colors
-                                               tmp_colbits = ob.colbits
-                                               if tmp_colbits:
-                                                       tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too.
-                                                       for i in xrange(16):
-                                                               if tmp_colbits & (1<<i):
-                                                                       mats[i] = tmp_ob_mats[i]
-                                                       del tmp_ob_mats
-                                               del tmp_colbits
+#                                              # Support object colors
+#                                              tmp_colbits = ob.colbits
+#                                              if tmp_colbits:
+#                                                      tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too.
+#                                                      for i in xrange(16):
+#                                                              if tmp_colbits & (1<<i):
+#                                                                      mats[i] = tmp_ob_mats[i]
+#                                                      del tmp_ob_mats
+#                                              del tmp_colbits
                                                        
                                        
                                if me:
-                                       # This WILL modify meshes in blender if EXP_MESH_APPLY_MOD is disabled.
-                                       # so strictly this is bad. but only in rare cases would it have negative results
-                                       # say with dupliverts the objects would rotate a bit differently
-                                       if EXP_MESH_HQ_NORMALS:
-                                               BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
+#                                      # This WILL modify meshes in blender if EXP_MESH_APPLY_MOD is disabled.
+#                                      # so strictly this is bad. but only in rare cases would it have negative results
+#                                      # say with dupliverts the objects would rotate a bit differently
+#                                      if EXP_MESH_HQ_NORMALS:
+#                                              BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
                                        
                                        texture_mapping_local = {}
                                        material_mapping_local = {}
-                                       if me.faceUV:
-                                               uvlayer_orig = me.activeUVLayer
-                                               for uvlayer in me.getUVLayerNames():
-                                                       me.activeUVLayer = uvlayer
-                                                       for f in me.faces:
-                                                               tex = f.image
+                                       if len(me.uv_textures) > 0:
+#                                      if me.faceUV:
+                                               uvlayer_orig = me.active_uv_texture
+#                                              uvlayer_orig = me.activeUVLayer
+                                               for uvlayer in me.uv_textures:
+#                                              for uvlayer in me.getUVLayerNames():
+#                                                      me.activeUVLayer = uvlayer
+                                                       for f, uf in zip(me.faces, uvlayer.data):
+#                                                      for f in me.faces:
+                                                               tex = uf.image
+#                                                              tex = f.image
                                                                textures[tex] = texture_mapping_local[tex] = None
                                                                
-                                                               try: mat = mats[f.mat]
+                                                               try: mat = mats[f.material_index]
+#                                                              try: mat = mats[f.mat]
                                                                except: mat = None
                                                                
                                                                materials[mat, tex] = material_mapping_local[mat, tex] = None # should use sets, wait for blender 2.5
                                                                        
                                                        
-                                                       me.activeUVLayer = uvlayer_orig
+#                                                      me.activeUVLayer = uvlayer_orig
                                        else:
                                                for mat in mats:
                                                        # 2.44 use mat.lib too for uniqueness
@@ -1925,13 +2150,16 @@ def write(filename, batch_objects = None, \
                                                        materials[None, None] = None
                                        
                                        if EXP_ARMATURE:
-                                               armob = BPyObject.getObjectArmature(ob)
+                                               armob = ob.find_armature()
                                                blenParentBoneName = None
                                                
                                                # parent bone - special case
-                                               if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.BONE:
+                                               if (not armob) and ob.parent and ob.parent.type == 'ARMATURE' and \
+                                                               ob.parent_type == 'BONE':
+#                                              if (not armob) and ob.parent and ob.parent.type == 'Armature' and ob.parentType == Blender.Object.ParentTypes.BONE:
                                                        armob = ob.parent
-                                                       blenParentBoneName = ob.parentbonename
+                                                       blenParentBoneName = ob.parent_bone
+#                                                      blenParentBoneName = ob.parentbonename
                                                
                                                        
                                                if armob and armob not in ob_arms:
@@ -1943,9 +2171,9 @@ def write(filename, batch_objects = None, \
                                        my_mesh = my_object_generic(ob, mtx)
                                        my_mesh.blenData =              me
                                        my_mesh.origData =              origData
-                                       my_mesh.blenMaterials = material_mapping_local.keys()
+                                       my_mesh.blenMaterials = list(material_mapping_local.keys())
                                        my_mesh.blenMaterialList = mats
-                                       my_mesh.blenTextures =  texture_mapping_local.keys()
+                                       my_mesh.blenTextures =  list(texture_mapping_local.keys())
                                        
                                        # if only 1 null texture then empty the list
                                        if len(my_mesh.blenTextures) == 1 and my_mesh.blenTextures[0] == None:
@@ -1955,18 +2183,26 @@ def write(filename, batch_objects = None, \
                                        my_mesh.fbxBoneParent = blenParentBoneName      # replace with my_bone instance later
                                        
                                        ob_meshes.append( my_mesh )
-       
+
+               # not forgetting to free dupli_list
+               if ob_base.dupli_list: ob_base.free_dupli_list()
+
+
        if EXP_ARMATURE:
                # now we have the meshes, restore the rest arm position
                for i, arm in enumerate(bpy.data.armatures):
-                       arm.restPosition = ob_arms_orig_rest[i]
+                       arm.rest_position = ob_arms_orig_rest[i]
+#                      arm.restPosition = ob_arms_orig_rest[i]
                        
                if ob_arms_orig_rest:
                        for ob_base in bpy.data.objects:
-                               if ob_base.type == 'Armature':
-                                       ob_base.makeDisplayList()
+                               if ob_base.type == 'ARMATURE':
+#                              if ob_base.type == 'Armature':
+                                       ob_base.make_display_list()
+#                                      ob_base.makeDisplayList()
                        # This causes the makeDisplayList command to effect the mesh
-                       Blender.Set('curframe', Blender.Get('curframe'))
+                       sce.set_frame(sce.current_frame)
+#                      Blender.Set('curframe', Blender.Get('curframe'))
        
        del tmp_ob_type, tmp_objects
        
@@ -1977,13 +2213,18 @@ def write(filename, batch_objects = None, \
                
                my_arm.fbxBones =               []
                my_arm.blenData =               ob.data
-               my_arm.blenAction =             ob.action
+               if ob.animation_data:
+                       my_arm.blenAction =     ob.animation_data.action
+               else:
+                       my_arm.blenAction = None
+#              my_arm.blenAction =             ob.action
                my_arm.blenActionList = []
                
                # fbxName, blenderObject, my_bones, blenderActions
                #ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, [])
                
-               for bone in my_arm.blenData.bones.values():
+               for bone in my_arm.blenData.bones:
+#              for bone in my_arm.blenData.bones.values():
                        my_bone = my_bone_class(bone, my_arm)
                        my_arm.fbxBones.append( my_bone )
                        ob_bones.append( my_bone )
@@ -2032,18 +2273,25 @@ def write(filename, batch_objects = None, \
        
        # Build blenObject -> fbxObject mapping
        # this is needed for groups as well as fbxParenting
-       bpy.data.objects.tag = False
+#      for ob in bpy.data.objects:     ob.tag = False
+#      bpy.data.objects.tag = False
+
+       # using a list of object names for tagging (Arystan)
+       tagged_objects = []
+
        tmp_obmapping = {}
        for ob_generic in ob_all_typegroups:
                for ob_base in ob_generic:
-                       ob_base.blenObject.tag = True
+                       tagged_objects.append(ob_base.blenObject.name)
+#                      ob_base.blenObject.tag = True
                        tmp_obmapping[ob_base.blenObject] = ob_base
        
        # Build Groups from objects we export
        for blenGroup in bpy.data.groups:
                fbxGroupName = None
                for ob in blenGroup.objects:
-                       if ob.tag:
+                       if ob.name in tagged_objects:
+#                      if ob.tag:
                                if fbxGroupName == None:
                                        fbxGroupName = sane_groupname(blenGroup)
                                        groups.append((fbxGroupName, blenGroup))
@@ -2056,7 +2304,8 @@ def write(filename, batch_objects = None, \
        for ob_generic in ob_all_typegroups:
                for my_ob in ob_generic:
                        parent = my_ob.blenObject.parent
-                       if parent and parent.tag: # does it exist and is it in the mapping
+                       if parent and parent.name in tagged_objects: # does it exist and is it in the mapping
+#                      if parent and parent.tag: # does it exist and is it in the mapping
                                my_ob.fbxParent = tmp_obmapping[parent]
        
        
@@ -2064,8 +2313,8 @@ def write(filename, batch_objects = None, \
        # Finished finding groups we use
        
        
-       materials =     [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.iterkeys()]
-       textures =      [(sane_texname(tex), tex) for tex in textures.iterkeys()  if tex]
+       materials =     [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.keys()]
+       textures =      [(sane_texname(tex), tex) for tex in textures.keys()  if tex]
        materials.sort() # sort by name
        textures.sort()
        
@@ -2220,11 +2469,12 @@ Objects:  {''')
                        if my_mesh.fbxBoneParent:
                                weights = None
                        else:
-                               weights = meshNormalizedWeights(my_mesh.blenData)
+                               weights = meshNormalizedWeights(my_mesh.blenObject)
+#                              weights = meshNormalizedWeights(my_mesh.blenData)
                        
                        #for bonename, bone, obname, bone_mesh, armob in ob_bones:
                        for my_bone in ob_bones:
-                               if me in my_bone.blenMeshes.itervalues():
+                               if me in iter(my_bone.blenMeshes.values()):
                                        write_sub_deformer_skin(my_mesh, my_bone, weights)
        
        # Write pose's really weired, only needed when an armature and mesh are used together
@@ -2426,7 +2676,8 @@ Connections:  {''')
        
        
        # Needed for scene footer as well as animation
-       render = sce.render
+       render = sce.render_data
+#      render = sce.render
        
        # from the FBX sdk
        #define KTIME_ONE_SECOND        KTime (K_LONGLONG(46186158000))
@@ -2435,8 +2686,10 @@ Connections:  {''')
                return int(0.5 + ((t/fps) * 46186158000))
        
        fps = float(render.fps) 
-       start = render.sFrame
-       end =   render.eFrame
+       start = sce.start_frame
+#      start = render.sFrame
+       end =   sce.end_frame
+#      end =   render.eFrame
        if end < start: start, end = end, start
        if start==end: ANIM_ENABLE = False
        
@@ -2445,7 +2698,8 @@ Connections:  {''')
        
        if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]:
                
-               frame_orig = Blender.Get('curframe')
+               frame_orig = sce.current_frame
+#              frame_orig = Blender.Get('curframe')
                
                if ANIM_OPTIMIZE:
                        ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION
@@ -2454,9 +2708,12 @@ Connections:  {''')
                tmp_actions = [None] # None is the default action
                blenActionDefault = None
                action_lastcompat = None
+
+               # instead of tagging
+               tagged_actions = []
                
                if ANIM_ACTION_ALL:
-                       bpy.data.actions.tag = False
+#                      bpy.data.actions.tag = False
                        tmp_actions = list(bpy.data.actions)
                        
                        
@@ -2472,12 +2729,14 @@ Connections:  {''')
                                arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones])
                                
                                for action in tmp_actions:
-                                       
-                                       action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) )
+
+                                       action_chan_names = arm_bone_names.intersection( set([g.name for g in action.groups]) )
+#                                      action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) )
                                        
                                        if action_chan_names: # at least one channel matches.
                                                my_arm.blenActionList.append(action)
-                                               action.tag = True
+                                               tagged_actions.append(action.name)
+#                                              action.tag = True
                                                tmp_act_count += 1
                                                
                                                # incase there is no actions applied to armatures
@@ -2504,10 +2763,11 @@ Takes:  {''')
                for blenAction in tmp_actions:
                        # we have tagged all actious that are used be selected armatures
                        if blenAction:
-                               if blenAction.tag:
-                                       print '\taction: "%s" exporting...' % blenAction.name
+                               if blenAction.name in tagged_actions:
+#                              if blenAction.tag:
+                                       print('\taction: "%s" exporting...' % blenAction.name)
                                else:
-                                       print '\taction: "%s" has no armature using it, skipping' % blenAction.name
+                                       print('\taction: "%s" has no armature using it, skipping' % blenAction.name)
                                        continue
                        
                        if blenAction == None:
@@ -2521,17 +2781,18 @@ Takes:  {''')
                                        file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name])
                                else:
                                        file.write('\n\tTake: "%s" {' % sane_takename(blenAction))
-                                       
-                               tmp = blenAction.getFrameNumbers()
-                               if tmp:
-                                       act_start =     min(tmp)
-                                       act_end =       max(tmp)
-                                       del tmp
-                               else:
-                                       # Fallback on this, theres not much else we can do? :/
-                                       # when an action has no length
-                                       act_start =     start
-                                       act_end =       end
+
+                               act_start, act_end = blenAction.get_frame_range()
+#                              tmp = blenAction.getFrameNumbers()
+#                              if tmp:
+#                                      act_start =     min(tmp)
+#                                      act_end =       max(tmp)
+#                                      del tmp
+#                              else:
+#                                      # Fallback on this, theres not much else we can do? :/
+#                                      # when an action has no length
+#                                      act_start =     start
+#                                      act_end =       end
                                
                                # Set the action active
                                for my_bone in ob_arms:
@@ -2558,7 +2819,8 @@ Takes:  {''')
                        '''
                        i = act_start
                        while i <= act_end:
-                               Blender.Set('curframe', i)
+                               sce.set_frame(i)
+#                              Blender.Set('curframe', i)
                                for ob_generic in ob_anim_lists:
                                        for my_ob in ob_generic:
                                                #Blender.Window.RedrawAll()
@@ -2585,7 +2847,7 @@ Takes:  {''')
                                                file.write('\n\t\t\tVersion: 1.1')
                                                file.write('\n\t\t\tChannel: "Transform" {')
                                                
-                                               context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in xrange(act_start, act_end+1) ]
+                                               context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in range(act_start, act_end+1) ]
                                                
                                                # ----------------
                                                # ----------------
@@ -2603,11 +2865,12 @@ Takes:  {''')
                                                                for mtx in context_bone_anim_mats:
                                                                        if prev_eul:    prev_eul = mtx[1].toEuler(prev_eul)
                                                                        else:                   prev_eul = mtx[1].toEuler()
-                                                                       context_bone_anim_vecs.append(prev_eul)
+                                                                       context_bone_anim_vecs.append(eulerRadToDeg(prev_eul))
+#                                                                      context_bone_anim_vecs.append(prev_eul)
                                                        
                                                        file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation
                                                        
-                                                       for i in xrange(3):
+                                                       for i in range(3):
                                                                # Loop on each axis of the bone
                                                                file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation
                                                                file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] )
@@ -2694,8 +2957,9 @@ Takes:  {''')
                                my_bone.blenObject.action = my_bone.blenAction
                
                file.write('\n}')
-               
-               Blender.Set('curframe', frame_orig)
+
+               sce.set_frame(frame_orig)
+#              Blender.Set('curframe', frame_orig)
                
        else:
                # no animation
@@ -2713,15 +2977,21 @@ Takes:  {''')
        
        # Clear mesh data Only when writing with modifiers applied
        for me in meshes_to_clear:
-               me.verts = None
-       
-       
+               bpy.data.remove_mesh(me)
+#              me.verts = None
        
        # --------------------------- Footer
        if world:
-               has_mist = world.mode & 1
-               mist_intense, mist_start, mist_end, mist_height = world.mist
-               world_hor = world.hor
+               m = world.mist
+               has_mist = m.enabled
+#              has_mist = world.mode & 1
+               mist_intense = m.intensity
+               mist_start = m.start
+               mist_end = m.depth
+               mist_height = m.height
+#              mist_intense, mist_start, mist_end, mist_height = world.mist
+               world_hor = world.horizon_color
+#              world_hor = world.hor
        else:
                has_mist = mist_intense = mist_start = mist_end = mist_height = 0
                world_hor = 0,0,0
@@ -2771,17 +3041,19 @@ Takes:  {''')
        
        
        # copy images if enabled
-       if EXP_IMAGE_COPY:
-               copy_images( basepath,  [ tex[1] for tex in textures if tex[1] != None ])       
+#      if EXP_IMAGE_COPY:
+# #            copy_images( basepath,  [ tex[1] for tex in textures if tex[1] != None ])
+#              bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath)       
        
-       print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time)
+       print('export finished in %.4f sec.' % (time.clock() - start_time))
+#      print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time)
        return True
        
 
 # --------------------------------------------
 # UI Function - not a part of the exporter.
 # this is to seperate the user interface from the rest of the exporter.
-from Blender import Draw, Window
+from Blender import Draw, Window
 EVENT_NONE = 0
 EVENT_EXIT = 1
 EVENT_REDRAW = 2
@@ -2804,11 +3076,6 @@ def do_obs_sce(e,v):
        GLOBALS['EXP_OBS_SCENE'].val = 1
        GLOBALS['EXP_OBS_SELECTED'].val = 0
 
-def do_obs_sce(e,v):
-       GLOBALS['EVENT'] = e
-       GLOBALS['EXP_OBS_SCENE'].val = 1
-       GLOBALS['EXP_OBS_SELECTED'].val = 0
-
 def do_batch_type_grp(e,v):
        GLOBALS['EVENT'] = e
        GLOBALS['BATCH_GROUP'].val = 1
@@ -2837,21 +3104,21 @@ def fbx_ui_exit(e,v):
 
 def do_help(e,v):
     url = 'http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx'
-    print 'Trying to open web browser with documentation at this address...'
-    print '\t' + url
+    print('Trying to open web browser with documentation at this address...')
+    print('\t' + url)
     
     try:
         import webbrowser
         webbrowser.open(url)
     except:
         Blender.Draw.PupMenu("Error%t|Opening a webbrowser requires a full python installation")
-        print '...could not open a browser window.'
+        print('...could not open a browser window.')
 
        
 
 # run when export is pressed
 #def fbx_ui_write(e,v):
-def fbx_ui_write(filename):
+def fbx_ui_write(filename, context):
        
        # Dont allow overwriting files when saving normally
        if not GLOBALS['BATCH_ENABLE'].val:
@@ -2874,6 +3141,7 @@ def fbx_ui_write(filename):
        
        ret = write(\
                filename, None,\
+               context,
                GLOBALS['EXP_OBS_SELECTED'].val,\
                GLOBALS['EXP_MESH'].val,\
                GLOBALS['EXP_MESH_APPLY_MOD'].val,\
@@ -3071,14 +3339,115 @@ def write_ui():
        
        
        # GLOBALS.clear()
-#test = [write_ui]
-if __name__ == '__main__':
-       # Cant call the file selector first because of a bug in the interface that crashes it.
-       # Blender.Window.FileSelector(write_ui, 'Export FBX', Blender.sys.makename(ext='.fbx'))
-       #write('/scratch/test.fbx')
-       #write_ui('/scratch/test.fbx')
-       
-       if not set:
-               Draw.PupMenu('Error%t|A full install of python2.3 or python 2.4+ is needed to run this script.')
-       else:
-               write_ui()
+
+class EXPORT_OT_fbx(bpy.types.Operator):
+       '''
+       Operator documentation text, will be used for the operator tooltip and python docs.
+       '''
+       __idname__ = "export.fbx"
+       __label__ = "Export FBX"
+       
+       # List of operator properties, the attributes will be assigned
+       # to the class instance from the operator settings before calling.
+       
+       __props__ = [
+               bpy.props.StringProperty(attr="path", name="File Path", description="File path used for exporting the FBX file", maxlen= 1024, default= ""),
+               
+               bpy.props.BoolProperty(attr="EXP_OBS_SELECTED", name="Selected Objects", description="Export selected objects on visible layers", default=True),
+#              bpy.props.BoolProperty(attr="EXP_OBS_SCENE", name="Scene Objects", description="Export all objects in this scene", default=True),
+               bpy.props.FloatProperty(attr="_SCALE", name="Scale", description="Scale all data, (Note! some imports dont support scaled armatures)", min=0.01, max=1000.0, soft_min=0.01, soft_max=1000.0, default=1.0),
+               bpy.props.BoolProperty(attr="_XROT90", name="Rot X90", description="Rotate all objects 90 degrese about the X axis", default=True),
+               bpy.props.BoolProperty(attr="_YROT90", name="Rot Y90", description="Rotate all objects 90 degrese about the Y axis", default=False),
+               bpy.props.BoolProperty(attr="_ZROT90", name="Rot Z90", description="Rotate all objects 90 degrese about the Z axis", default=False),
+               bpy.props.BoolProperty(attr="EXP_EMPTY", name="Empties", description="Export empty objects", default=True),
+               bpy.props.BoolProperty(attr="EXP_CAMERA", name="Cameras", description="Export camera objects", default=True),
+               bpy.props.BoolProperty(attr="EXP_LAMP", name="Lamps", description="Export lamp objects", default=True),
+               bpy.props.BoolProperty(attr="EXP_ARMATURE", name="Armatures", description="Export armature objects", default=True),
+               bpy.props.BoolProperty(attr="EXP_MESH", name="Meshes", description="Export mesh objects", default=True),
+               bpy.props.BoolProperty(attr="EXP_MESH_APPLY_MOD", name="Modifiers", description="Apply modifiers to mesh objects", default=True),
+               bpy.props.BoolProperty(attr="EXP_MESH_HQ_NORMALS", name="HQ Normals", description="Generate high quality normals", default=True),
+               bpy.props.BoolProperty(attr="EXP_IMAGE_COPY", name="Copy Image Files", description="Copy image files to the destination path", default=False),
+               # armature animation
+               bpy.props.BoolProperty(attr="ANIM_ENABLE", name="Enable Animation", description="Export keyframe animation", default=True),
+               bpy.props.BoolProperty(attr="ANIM_OPTIMIZE", name="Optimize Keyframes", description="Remove double keyframes", default=True),
+               bpy.props.FloatProperty(attr="ANIM_OPTIMIZE_PRECISSION", name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0),
+#              bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True),
+               bpy.props.BoolProperty(attr="ANIM_ACTION_ALL", name="All Actions", description="Use all actions for armatures, if false, use current action", default=False),
+               # batch
+               bpy.props.BoolProperty(attr="BATCH_ENABLE", name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False),
+               bpy.props.BoolProperty(attr="BATCH_GROUP", name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False),
+               bpy.props.BoolProperty(attr="BATCH_OWN_DIR", name="Own Dir", description="Create a dir for each exported file", default=True),
+               bpy.props.StringProperty(attr="BATCH_FILE_PREFIX", name="Prefix", description="Prefix each file with this name", maxlen= 1024, default=""),
+       ]
+       
+       def poll(self, context):
+               print("Poll")
+               return context.active_object != None
+       
+       def execute(self, context):
+               if not self.path:
+                       raise Exception("path not set")
+
+               GLOBAL_MATRIX = mtx4_identity
+               GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self._SCALE
+               if self._XROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n
+               if self._YROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n
+               if self._ZROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n
+                       
+               write(self.path,
+                         None, # XXX
+                         context,
+                         self.EXP_OBS_SELECTED,
+                         self.EXP_MESH,
+                         self.EXP_MESH_APPLY_MOD,
+#                        self.EXP_MESH_HQ_NORMALS,
+                         self.EXP_ARMATURE,
+                         self.EXP_LAMP,
+                         self.EXP_CAMERA,
+                         self.EXP_EMPTY,
+                         self.EXP_IMAGE_COPY,
+                         GLOBAL_MATRIX,
+                         self.ANIM_ENABLE,
+                         self.ANIM_OPTIMIZE,
+                         self.ANIM_OPTIMIZE_PRECISSION,
+                         self.ANIM_ACTION_ALL,
+                         self.BATCH_ENABLE,
+                         self.BATCH_GROUP,
+                         self.BATCH_FILE_PREFIX,
+                         self.BATCH_OWN_DIR)           
+
+               return ('FINISHED',)
+       
+       def invoke(self, context, event):       
+               wm = context.manager
+               wm.add_fileselect(self.__operator__)
+               return ('RUNNING_MODAL',)
+
+
+bpy.ops.add(EXPORT_OT_fbx)
+
+# if __name__ == "__main__":
+#      bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply")
+
+
+# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts)
+# - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print
+# - get rid of cleanName somehow
+# + fixed: isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565
+# + get rid of BPyObject_getObjectArmature, move it in RNA?
+# - BATCH_ENABLE and BATCH_GROUP options: line 327
+# - implement all BPyMesh_* used here with RNA
+# - getDerivedObjects is not fully replicated with .dupli* funcs
+# - talk to Campbell, this code won't work? lines 1867-1875
+# - don't know what those colbits are, do we need them? they're said to be deprecated in DNA_object_types.h: 1886-1893
+# - no hq normals: 1900-1901
+
+# TODO
+
+# - bpy.data.remove_scene: line 366
+# - bpy.sys.time move to bpy.sys.util?
+# - new scene creation, activation: lines 327-342, 368
+# - uses bpy.sys.expandpath, *.relpath - replace at least relpath
+
+# SMALL or COSMETICAL
+# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version')
index 7dffb5d204812cc1647325acb8696e58e00c5962..83b400816e35d2a8026b33a1eeb1724b76886bb3 100644 (file)
@@ -2,14 +2,14 @@
 
 """
 Name: 'Wavefront (.obj)...'
-Blender: 249
+Blender: 248
 Group: 'Export'
 Tooltip: 'Save a Wavefront OBJ File'
 """
 
 __author__ = "Campbell Barton, Jiri Hnidek, Paolo Ciccone"
 __url__ = ['http://wiki.blender.org/index.php/Scripts/Manual/Export/wavefront_obj', 'www.blender.org', 'blenderartists.org']
-__version__ = "1.22"
+__version__ = "1.21"
 
 __bpydoc__ = """\
 This script is an exporter to OBJ file format.
@@ -23,11 +23,11 @@ will be exported as mesh data.
 """
 
 
+# --------------------------------------------------------------------------
+# OBJ Export v1.1 by Campbell Barton (AKA Ideasman)
+# --------------------------------------------------------------------------
 # ***** BEGIN GPL LICENSE BLOCK *****
 #
-# Script copyright (C) Campbell J Barton 2007-2009
-# - V1.22- bspline import/export added (funded by PolyDimensions GmbH)
-#
 # 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
@@ -35,26 +35,27 @@ will be exported as mesh data.
 #
 # 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
+# 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.
+# Inc., 59 Temple Place - Suite 330, Boston, MA         02111-1307, USA.
 #
 # ***** END GPL LICENCE BLOCK *****
 # --------------------------------------------------------------------------
 
+# import math and other in functions that use them for the sake of fast Blender startup
+# import math
+import os
+import time
+
+import bpy
+import Mathutils
 
-import Blender
-from Blender import Mesh, Scene, Window, sys, Image, Draw
-import BPyMesh
-import BPyObject
-import BPySys
-import BPyMessages
 
 # Returns a tuple - path,extension.
-# 'hello.obj' >  ('hello', '.obj')
+# 'hello.obj' >         ('hello', '.obj')
 def splitExt(path):
        dotidx = path.rfind('.')
        if dotidx == -1:
@@ -68,23 +69,47 @@ def fixName(name):
        else:
                return name.replace(' ', '_')
 
+
+# this used to be in BPySys module
+# frankly, I don't understand how it works
+def BPySys_cleanName(name):
+
+       v = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,58,59,60,61,62,63,64,91,92,93,94,96,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254]
+
+       invalid = ''.join([chr(i) for i in v])
+
+       for ch in invalid:
+               name = name.replace(ch, '_')
+       return name
+
 # A Dict of Materials
 # (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
-MTL_DICT = {} 
+MTL_DICT = {}  
+
+def write_mtl(scene, filename, copy_images):
+
+       world = scene.world
+       worldAmb = world.ambient_color
+
+       dest_dir = os.path.dirname(filename)
+
+       def copy_image(image):
+               rel = image.get_export_path(dest_dir, True)
+
+               if copy_images:
+                       abspath = image.get_export_path(dest_dir, False)
+                       if not os.path.exists(abs_path):
+                               shutil.copy(image.get_abs_filename(), abs_path)
+
+               return rel
+
 
-def write_mtl(filename):
-       
-       world = Blender.World.GetCurrent()
-       if world:
-               worldAmb = world.getAmb()
-       else:
-               worldAmb = (0,0,0) # Default value
-       
        file = open(filename, "w")
-       file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1])
+       # XXX
+#      file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1])
        file.write('# Material Count: %i\n' % len(MTL_DICT))
        # Write material/image combinations we have used.
-       for key, (mtl_mat_name, mat, img) in MTL_DICT.iteritems():
+       for key, (mtl_mat_name, mat, img) in MTL_DICT.items():
                
                # Get the Blender data for the material and the image.
                # Having an image named None will make a bug, dont do it :)
@@ -92,17 +117,20 @@ def write_mtl(filename):
                file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname
                
                if mat:
-                       file.write('Ns %.6f\n' % ((mat.getHardness()-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's 
-                       file.write('Ka %.6f %.6f %.6f\n' %  tuple([c*mat.amb for c in worldAmb])  ) # Ambient, uses mirror colour,
-                       file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.ref for c in mat.rgbCol]) ) # Diffuse
-                       file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.spec for c in mat.specCol]) ) # Specular
-                       file.write('Ni %.6f\n' % mat.IOR) # Refraction index
+                       file.write('Ns %.6f\n' % ((mat.specular_hardness-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's
+                       file.write('Ka %.6f %.6f %.6f\n' %      tuple([c*mat.ambient for c in worldAmb])  ) # Ambient, uses mirror colour,
+                       file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.diffuse_intensity for c in mat.diffuse_color]) ) # Diffuse
+                       file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.specular_intensity for c in mat.specular_color]) ) # Specular
+                       if hasattr(mat, "ior"):
+                               file.write('Ni %.6f\n' % mat.ior) # Refraction index
+                       else:
+                               file.write('Ni %.6f\n' % 1.0)
                        file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve)
-                       
+
                        # 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
-                       if mat.getMode() & Blender.Material.Modes['SHADELESS']:
+                       if mat.shadeless:
                                file.write('illum 0\n') # ignore lighting
-                       elif mat.getSpec() == 0:
+                       elif mat.specular_intensity == 0:
                                file.write('illum 1\n') # no specular.
                        else:
                                file.write('illum 2\n') # light normaly 
@@ -110,21 +138,25 @@ def write_mtl(filename):
                else:
                        #write a dummy material here?
                        file.write('Ns 0\n')
-                       file.write('Ka %.6f %.6f %.6f\n' %  tuple([c for c in worldAmb])  ) # Ambient, uses mirror colour,
+                       file.write('Ka %.6f %.6f %.6f\n' %      tuple([c for c in worldAmb])  ) # Ambient, uses mirror colour,
                        file.write('Kd 0.8 0.8 0.8\n')
                        file.write('Ks 0.8 0.8 0.8\n')
                        file.write('d 1\n') # No alpha
                        file.write('illum 2\n') # light normaly
                
                # Write images!
-               if img:  # We have an image on the face!
-                       file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image                 
+               if img:  # We have an image on the face!
+                       # write relative image path
+                       rel = copy_image(img)
+                       file.write('map_Kd %s\n' % rel) # Diffuse mapping image
+#                      file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image                 
                
                elif mat: # No face image. if we havea material search for MTex image.
-                       for mtex in mat.getTextures():
-                               if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
+                       for mtex in mat.textures:
+                               if mtex and mtex.texture.type == 'IMAGE':
                                        try:
-                                               filename = mtex.tex.image.filename.split('\\')[-1].split('/')[-1]
+                                               filename = copy_image(mtex.texture.image)
+#                                              filename = mtex.texture.image.filename.split('\\')[-1].split('/')[-1]
                                                file.write('map_Kd %s\n' % filename) # Diffuse mapping image
                                                break
                                        except:
@@ -135,6 +167,7 @@ def write_mtl(filename):
        
        file.close()
 
+# XXX not used
 def copy_file(source, dest):
        file = open(source, 'rb')
        data = file.read()
@@ -145,22 +178,25 @@ def copy_file(source, dest):
        file.close()
 
 
+# XXX not used
 def copy_images(dest_dir):
-       if dest_dir[-1] != sys.sep:
-               dest_dir += sys.sep
+       if dest_dir[-1] != os.sep:
+               dest_dir += os.sep
+#      if dest_dir[-1] != sys.sep:
+#              dest_dir += sys.sep
        
        # Get unique image names
        uniqueImages = {}
-       for matname, mat, image in MTL_DICT.itervalues(): # Only use image name
+       for matname, mat, image in MTL_DICT.values(): # Only use image name
                # Get Texface images
                if image:
                        uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default.
                
                # Get MTex images
                if mat:
-                       for mtex in mat.getTextures():
-                               if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
-                                       image_tex = mtex.tex.image
+                       for mtex in mat.textures:
+                               if mtex and mtex.texture.type == 'IMAGE':
+                                       image_tex = mtex.texture.image
                                        if image_tex:
                                                try:
                                                        uniqueImages[image_tex] = image_tex
@@ -170,18 +206,22 @@ def copy_images(dest_dir):
        # Now copy images
        copyCount = 0
        
-       for bImage in uniqueImages.itervalues():
-               image_path = sys.expandpath(bImage.filename)
-               if sys.exists(image_path):
-                       # Make a name for the target path.
-                       dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
-                       if not sys.exists(dest_image_path): # Image isnt alredy there
-                               print '\tCopying "%s" > "%s"' % (image_path, dest_image_path)
-                               copy_file(image_path, dest_image_path)
-                               copyCount+=1
-       print '\tCopied %d images' % copyCount
+#      for bImage in uniqueImages.values():
+#              image_path = bpy.sys.expandpath(bImage.filename)
+#              if bpy.sys.exists(image_path):
+#                      # Make a name for the target path.
+#                      dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
+#                      if not bpy.sys.exists(dest_image_path): # Image isnt alredy there
+#                              print('\tCopying "%s" > "%s"' % (image_path, dest_image_path))
+#                              copy_file(image_path, dest_image_path)
+#                              copyCount+=1
+
+#      paths= bpy.util.copy_images(uniqueImages.values(), dest_dir)
 
+       print('\tCopied %d images' % copyCount)
+#      print('\tCopied %d images' % copyCount)
 
+# XXX not converted
 def test_nurbs_compat(ob):
        if ob.type != 'Curve':
                return False
@@ -192,6 +232,8 @@ def test_nurbs_compat(ob):
        
        return False
 
+
+# XXX not converted
 def write_nurb(file, ob, ob_mat):
        tot_verts = 0
        cu = ob.data
@@ -204,15 +246,15 @@ def write_nurb(file, ob, ob_mat):
                else:                           DEG_ORDER_U = nu.orderU-1  # Tested to be correct
                
                if nu.type==1:
-                       print "\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported"
+                       print("\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported")
                        continue
                
                if nu.knotsV:
-                       print "\tWarning, surface:", ob.name, "only poly and nurbs curves supported"
+                       print("\tWarning, surface:", ob.name, "only poly and nurbs curves supported")
                        continue
                
                if len(nu) <= DEG_ORDER_U:
-                       print "\tWarning, orderU is lower then vert count, skipping:", ob.name
+                       print("\tWarning, orderU is lower then vert count, skipping:", ob.name)
                        continue
                
                pt_num = 0
@@ -229,7 +271,7 @@ def write_nurb(file, ob, ob_mat):
                file.write('cstype bspline\n') # not ideal, hard coded
                file.write('deg %d\n' % DEG_ORDER_U) # not used for curves but most files have it still
                
-               curve_ls = [-(i+1) for i in xrange(pt_num)]
+               curve_ls = [-(i+1) for i in range(pt_num)]
                
                # 'curv' keyword
                if do_closed:
@@ -245,10 +287,10 @@ def write_nurb(file, ob, ob_mat):
                # 'parm' keyword
                tot_parm = (DEG_ORDER_U + 1) + pt_num
                tot_parm_div = float(tot_parm-1)
-               parm_ls = [(i/tot_parm_div) for i in xrange(tot_parm)]
+               parm_ls = [(i/tot_parm_div) for i in range(tot_parm)]
                
                if do_endpoints: # end points, force param
-                       for i in xrange(DEG_ORDER_U+1):
+                       for i in range(DEG_ORDER_U+1):
                                parm_ls[i] = 0.0
                                parm_ls[-(1+i)] = 1.0
                
@@ -258,24 +300,38 @@ def write_nurb(file, ob, ob_mat):
        
        return tot_verts
 
-def write(filename, objects,\
-EXPORT_TRI=False,  EXPORT_EDGES=False,  EXPORT_NORMALS=False,  EXPORT_NORMALS_HQ=False,\
-EXPORT_UV=True,  EXPORT_MTL=True,  EXPORT_COPY_IMAGES=False,\
-EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\
-EXPORT_GROUP_BY_OB=False,  EXPORT_GROUP_BY_MAT=False, EXPORT_KEEP_VERT_ORDER=False,\
-EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
+def write(filename, objects, scene,
+                 EXPORT_TRI=False,
+                 EXPORT_EDGES=False,
+                 EXPORT_NORMALS=False,
+                 EXPORT_NORMALS_HQ=False,
+                 EXPORT_UV=True,
+                 EXPORT_MTL=True,
+                 EXPORT_COPY_IMAGES=False,
+                 EXPORT_APPLY_MODIFIERS=True,
+                 EXPORT_ROTX90=True,
+                 EXPORT_BLEN_OBS=True,
+                 EXPORT_GROUP_BY_OB=False,
+                 EXPORT_GROUP_BY_MAT=False,
+                 EXPORT_KEEP_VERT_ORDER=False,
+                 EXPORT_POLYGROUPS=False,
+                 EXPORT_CURVE_AS_NURBS=True):
        '''
        Basic write function. The context and options must be alredy set
        This can be accessed externaly
        eg.
        write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
        '''
+
+       # XXX
+       import math
        
        def veckey3d(v):
                return round(v.x, 6), round(v.y, 6), round(v.z, 6)
                
        def veckey2d(v):
-               return round(v.x, 6), round(v.y, 6)
+               return round(v[0], 6), round(v[1], 6)
+               # return round(v.x, 6), round(v.y, 6)
        
        def findVertexGroupName(face, vWeightMap):
                """
@@ -287,29 +343,44 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                of vertices is the face's group 
                """
                weightDict = {}
-               for vert in face:
-                       vWeights = vWeightMap[vert.index]
+               for vert_index in face.verts:
+#              for vert in face:
+                       vWeights = vWeightMap[vert_index]
+#                      vWeights = vWeightMap[vert]
                        for vGroupName, weight in vWeights:
                                weightDict[vGroupName] = weightDict.get(vGroupName, 0) + weight
                
                if weightDict:
-                       alist = [(weight,vGroupName) for vGroupName, weight in weightDict.iteritems()] # sort least to greatest amount of weight
+                       alist = [(weight,vGroupName) for vGroupName, weight in weightDict.items()] # sort least to greatest amount of weight
                        alist.sort()
                        return(alist[-1][1]) # highest value last
                else:
                        return '(null)'
 
+       # TODO: implement this in C? dunno how it should be called...
+       def getVertsFromGroup(me, group_index):
+               ret = []
+
+               for i, v in enumerate(me.verts):
+                       for g in v.groups:
+                               if g.group == group_index:
+                                       ret.append((i, g.weight))
+
+               return ret
 
-       print 'OBJ Export path: "%s"' % filename
+
+       print('OBJ Export path: "%s"' % filename)
        temp_mesh_name = '~tmp-mesh'
 
-       time1 = sys.time()
-       scn = Scene.GetCurrent()
+       time1 = time.clock()
+#      time1 = sys.time()
+#      scn = Scene.GetCurrent()
 
        file = open(filename, "w")
-       
+
        # Write Header
-       file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
+       version = "2.5"
+       file.write('# Blender3D v%s OBJ File: %s\n' % (version, bpy.data.filename.split('/')[-1].split('\\')[-1] ))
        file.write('# www.blender3d.org\n')
 
        # Tell the obj file what material file to use.
@@ -317,107 +388,125 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
                file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
        
-       # Get the container mesh. - used for applying modifiers and non mesh objects.
-       containerMesh = meshName = tempMesh = None
-       for meshName in Blender.NMesh.GetNames():
-               if meshName.startswith(temp_mesh_name):
-                       tempMesh = Mesh.Get(meshName)
-                       if not tempMesh.users:
-                               containerMesh = tempMesh
-       if not containerMesh:
-               containerMesh = Mesh.New(temp_mesh_name)
-       
        if EXPORT_ROTX90:
-               mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
+               mat_xrot90= Mathutils.RotationMatrix(-math.pi/2, 4, 'x')
                
-       del meshName
-       del tempMesh
-       
        # Initialize totals, these are updated each object
        totverts = totuvco = totno = 1
        
        face_vert_index = 1
        
        globalNormals = {}
-       
+
        # Get all meshes
        for ob_main in objects:
-               for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
+
+               # ignore dupli children
+               if ob_main.parent and ob_main.parent.dupli_type != 'NONE':
+                       # XXX
+                       print(ob_main.name, 'is a dupli child - ignoring')
+                       continue
+
+               obs = []
+               if ob_main.dupli_type != 'NONE':
+                       # XXX
+                       print('creating dupli_list on', ob_main.name)
+                       ob_main.create_dupli_list()
                        
-                       # Nurbs curve support
-                       if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob):
-                               if EXPORT_ROTX90:
-                                       ob_mat = ob_mat * mat_xrot90
+                       obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list]
+
+                       # XXX debug print
+                       print(ob_main.name, 'has', len(obs), 'dupli children')
+               else:
+                       obs = [(ob_main, ob_main.matrix)]
+
+               for ob, ob_mat in obs:
+
+                       # XXX postponed
+#                      # Nurbs curve support
+#                      if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob):
+#                              if EXPORT_ROTX90:
+#                                      ob_mat = ob_mat * mat_xrot90
                                
-                               totverts += write_nurb(file, ob, ob_mat)
+#                              totverts += write_nurb(file, ob, ob_mat)
                                
+#                              continue
+#                      end nurbs
+
+                       if ob.type != 'MESH':
                                continue
-                       # end nurbs
-                       
-                       # Will work for non meshes now! :)
-                       # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None)
-                       me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn)
-                       if not me:
-                               continue
-                       
+
+                       me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW')
+
+                       if EXPORT_ROTX90:
+                               me.transform(ob_mat * mat_xrot90)
+                       else:
+                               me.transform(ob_mat)
+
+#                      # Will work for non meshes now! :)
+#                      me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn)
+#                      if not me:
+#                              continue
+
                        if EXPORT_UV:
-                               faceuv= me.faceUV
+                               faceuv = len(me.uv_textures) > 0
                        else:
                                faceuv = False
-                       
+
+                       # XXX - todo, find a better way to do triangulation
+                       # ...removed convert_to_triface because it relies on editmesh
+                       '''
                        # We have a valid mesh
                        if EXPORT_TRI and me.faces:
                                # Add a dummy object to it.
                                has_quads = False
                                for f in me.faces:
-                                       if len(f) == 4:
+                                       if f.verts[3] != 0:
                                                has_quads = True
                                                break
                                
                                if has_quads:
-                                       oldmode = Mesh.Mode()
-                                       Mesh.Mode(Mesh.SelectModes['FACE'])
-                                       
-                                       me.sel = True
-                                       tempob = scn.objects.new(me)
-                                       me.quadToTriangle(0) # more=0 shortest length
-                                       oldmode = Mesh.Mode(oldmode)
-                                       scn.objects.unlink(tempob)
-                                       
-                                       Mesh.Mode(oldmode)
+                                       newob = bpy.data.add_object('MESH', 'temp_object')
+                                       newob.data = me
+                                       # if we forget to set Object.data - crash
+                                       scene.add_object(newob)
+                                       newob.convert_to_triface(scene)
+                                       # mesh will still be there
+                                       scene.remove_object(newob)
+                       '''
                        
                        # Make our own list so it can be sorted to reduce context switching
-                       faces = [ f for f in me.faces ]
+                       face_index_pairs = [ (face, index) for index, face in enumerate(me.faces)]
+                       # faces = [ f for f in me.faces ]
                        
                        if EXPORT_EDGES:
                                edges = me.edges
                        else:
                                edges = []
-                       
-                       if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write
+
+                       if not (len(face_index_pairs)+len(edges)+len(me.verts)): # Make sure there is somthing to write                         
+
+                               # clean up
+                               bpy.data.remove_mesh(me)
+
                                continue # dont bother with this mesh.
                        
-                       if EXPORT_ROTX90:
-                               me.transform(ob_mat*mat_xrot90)
-                       else:
-                               me.transform(ob_mat)
-                       
+                       # XXX
                        # High Quality Normals
-                       if EXPORT_NORMALS and faces:
-                               if EXPORT_NORMALS_HQ:
-                                       BPyMesh.meshCalcNormals(me)
-                               else:
-                                       # transforming normals is incorrect
-                                       # when the matrix is scaled,
-                                       # better to recalculate them
-                                       me.calcNormals()
+                       if EXPORT_NORMALS and face_index_pairs:
+                               me.calc_normals()
+#                              if EXPORT_NORMALS_HQ:
+#                                      BPyMesh.meshCalcNormals(me)
+#                              else:
+#                                      # transforming normals is incorrect
+#                                      # when the matrix is scaled,
+#                                      # better to recalculate them
+#                                      me.calcNormals()
                        
-                       # # Crash Blender
-                       #materials = me.getMaterials(1) # 1 == will return None in the list.
                        materials = me.materials
                        
                        materialNames = []
-                       materialItems = materials[:]
+                       materialItems = [m for m in materials]
                        if materials:
                                for mat in materials:
                                        if mat: # !=None
@@ -437,15 +526,41 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                        if EXPORT_KEEP_VERT_ORDER:
                                pass
                        elif faceuv:
-                               try:    faces.sort(key = lambda a: (a.mat, a.image, a.smooth))
-                               except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
+                               # XXX update
+                               tface = me.active_uv_texture.data
+
+                               # exception only raised if Python 2.3 or lower...
+                               try:
+                                       face_index_pairs.sort(key = lambda a: (a[0].material_index, tface[a[1]].image, a[0].smooth))
+                               except:
+                                       face_index_pairs.sort(lambda a,b: cmp((a[0].material_index, tface[a[1]].image, a[0].smooth),
+                                                                                                                         (b[0].material_index, tface[b[1]].image, b[0].smooth)))
                        elif len(materials) > 1:
-                               try:    faces.sort(key = lambda a: (a.mat, a.smooth))
-                               except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
+                               try:
+                                       face_index_pairs.sort(key = lambda a: (a[0].material_index, a[0].smooth))
+                               except:
+                                       face_index_pairs.sort(lambda a,b: cmp((a[0].material_index, a[0].smooth),
+                                                                                                                         (b[0].material_index, b[0].smooth)))
                        else:
                                # no materials
-                               try:    faces.sort(key = lambda a: a.smooth)
-                               except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth))
+                               try:
+                                       face_index_pairs.sort(key = lambda a: a[0].smooth)
+                               except:
+                                       face_index_pairs.sort(lambda a,b: cmp(a[0].smooth, b[0].smooth))
+#                      if EXPORT_KEEP_VERT_ORDER:
+#                              pass
+#                      elif faceuv:
+#                              try:    faces.sort(key = lambda a: (a.mat, a.image, a.smooth))
+#                              except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
+#                      elif len(materials) > 1:
+#                              try:    faces.sort(key = lambda a: (a.mat, a.smooth))
+#                              except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
+#                      else:
+#                              # no materials
+#                              try:    faces.sort(key = lambda a: a.smooth)
+#                              except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth))
+
+                       faces = [pair[0] for pair in face_index_pairs]
                        
                        # Set the default mat to no material and no image.
                        contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
@@ -453,7 +568,7 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                        
                        if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB:
                                name1 = ob.name
-                               name2 = ob.getData(1)
+                               name2 = ob.data.name
                                if name1 == name2:
                                        obnamestring = fixName(name1)
                                else:
@@ -472,20 +587,41 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                        # UV
                        if faceuv:
                                uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/
-                               
+
                                uv_dict = {} # could use a set() here
-                               for f_index, f in enumerate(faces):
-                                       
-                                       for uv_index, uv in enumerate(f.uv):
+                               uv_layer = me.active_uv_texture
+                               for f, f_index in face_index_pairs:
+
+                                       tface = uv_layer.data[f_index]
+
+                                       uvs = tface.uv
+                                       # uvs = [tface.uv1, tface.uv2, tface.uv3]
+
+                                       # # add another UV if it's a quad
+                                       # if len(f.verts) == 4:
+                                       #       uvs.append(tface.uv4)
+
+                                       for uv_index, uv in enumerate(uvs):
                                                uvkey = veckey2d(uv)
                                                try:
                                                        uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
                                                except:
                                                        uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
                                                        file.write('vt %.6f %.6f\n' % tuple(uv))
+
+#                              uv_dict = {} # could use a set() here
+#                              for f_index, f in enumerate(faces):
+                                       
+#                                      for uv_index, uv in enumerate(f.uv):
+#                                              uvkey = veckey2d(uv)
+#                                              try:
+#                                                      uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
+#                                              except:
+#                                                      uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
+#                                                      file.write('vt %.6f %.6f\n' % tuple(uv))
                                
                                uv_unique_count = len(uv_dict)
-                               del uv, uvkey, uv_dict, f_index, uv_index
+#                              del uv, uvkey, uv_dict, f_index, uv_index
                                # Only need uv_unique_count and uv_face_mapping
                        
                        # NORMAL, Smooth/Non smoothed.
@@ -493,55 +629,81 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                                for f in faces:
                                        if f.smooth:
                                                for v in f:
-                                                       noKey = veckey3d(v.no)
-                                                       if not globalNormals.has_key( noKey ):
+                                                       noKey = veckey3d(v.normal)
+                                                       if noKey not in globalNormals:
                                                                globalNormals[noKey] = totno
                                                                totno +=1
                                                                file.write('vn %.6f %.6f %.6f\n' % noKey)
                                        else:
                                                # Hard, 1 normal from the face.
-                                               noKey = veckey3d(f.no)
-                                               if not globalNormals.has_key( noKey ):
+                                               noKey = veckey3d(f.normal)
+                                               if noKey not in globalNormals:
                                                        globalNormals[noKey] = totno
                                                        totno +=1
                                                        file.write('vn %.6f %.6f %.6f\n' % noKey)
                        
                        if not faceuv:
                                f_image = None
-                       
+
+                       # XXX
                        if EXPORT_POLYGROUPS:
                                # Retrieve the list of vertex groups
-                               vertGroupNames = me.getVertGroupNames()
+#                              vertGroupNames = me.getVertGroupNames()
 
                                currentVGroup = ''
                                # Create a dictionary keyed by face id and listing, for each vertex, the vertex groups it belongs to
-                               vgroupsMap = [[] for _i in xrange(len(me.verts))]
-                               for vertexGroupName in vertGroupNames:
-                                       for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1):
-                                               vgroupsMap[vIdx].append((vertexGroupName, vWeight))
+                               vgroupsMap = [[] for _i in range(len(me.verts))]
+#                              vgroupsMap = [[] for _i in xrange(len(me.verts))]
+                               for g in ob.vertex_groups:
+#                              for vertexGroupName in vertGroupNames:
+                                       for vIdx, vWeight in getVertsFromGroup(me, g.index):
+#                                      for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1):
+                                               vgroupsMap[vIdx].append((g.name, vWeight))
 
                        for f_index, f in enumerate(faces):
-                               f_v= f.v
+                               f_v = [{"index": index, "vertex": me.verts[index]} for index in f.verts]
+
+                               # if f.verts[3] == 0:
+                               #       f_v.pop()
+
+#                              f_v= f.v
                                f_smooth= f.smooth
-                               f_mat = min(f.mat, len(materialNames)-1)
+                               f_mat = min(f.material_index, len(materialNames)-1)
+#                              f_mat = min(f.mat, len(materialNames)-1)
                                if faceuv:
-                                       f_image = f.image
-                                       f_uv= f.uv
+
+                                       tface = me.active_uv_texture.data[face_index_pairs[f_index][1]]
+
+                                       f_image = tface.image
+                                       f_uv = tface.uv
+                                       # f_uv= [tface.uv1, tface.uv2, tface.uv3]
+                                       # if len(f.verts) == 4:
+                                       #       f_uv.append(tface.uv4)
+#                                      f_image = f.image
+#                                      f_uv= f.uv
                                
                                # MAKE KEY
                                if faceuv and f_image: # Object is always true.
-                                       key = materialNames[f_mat],  f_image.name
+                                       key = materialNames[f_mat],      f_image.name
                                else:
-                                       key = materialNames[f_mat],  None # No image, use None instead.
-                               
+                                       key = materialNames[f_mat],      None # No image, use None instead.
+
                                # Write the vertex group
                                if EXPORT_POLYGROUPS:
-                                       if vertGroupNames:
+                                       if len(ob.vertex_groups):
                                                # find what vertext group the face belongs to
                                                theVGroup = findVertexGroupName(f,vgroupsMap)
                                                if      theVGroup != currentVGroup:
                                                        currentVGroup = theVGroup
                                                        file.write('g %s\n' % theVGroup)
+#                              # Write the vertex group
+#                              if EXPORT_POLYGROUPS:
+#                                      if vertGroupNames:
+#                                              # find what vertext group the face belongs to
+#                                              theVGroup = findVertexGroupName(f,vgroupsMap)
+#                                              if      theVGroup != currentVGroup:
+#                                                      currentVGroup = theVGroup
+#                                                      file.write('g %s\n' % theVGroup)
 
                                # CHECK FOR CONTEXT SWITCH
                                if key == contextMat:
@@ -550,7 +712,8 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                                        if key[0] == None and key[1] == None:
                                                # Write a null material, since we know the context has changed.
                                                if EXPORT_GROUP_BY_MAT:
-                                                       file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null)
+                                                       # can be mat_image or (null)
+                                                       file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.data.name)) ) # can be mat_image or (null)
                                                file.write('usemtl (null)\n') # mat, image
                                                
                                        else:
@@ -569,7 +732,7 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                                                                mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image
                                                
                                                if EXPORT_GROUP_BY_MAT:
-                                                       file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null)
+                                                       file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.data.name), mat_data[0]) ) # can be mat_image or (null)
 
                                                file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null)
                                        
@@ -587,23 +750,22 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                                        if EXPORT_NORMALS:
                                                if f_smooth: # Smoothed, use vertex normals
                                                        for vi, v in enumerate(f_v):
-                                                               file.write( ' %d/%d/%d' % (\
-                                                                 v.index+totverts,\
-                                                                 totuvco + uv_face_mapping[f_index][vi],\
-                                                                 globalNormals[ veckey3d(v.no) ])) # vert, uv, normal
+                                                               file.write( ' %d/%d/%d' % \
+                                                                                               (v["index"] + totverts,
+                                                                                                totuvco + uv_face_mapping[f_index][vi],
+                                                                                                globalNormals[ veckey3d(v["vertex"].normal) ]) ) # vert, uv, normal
                                                        
                                                else: # No smoothing, face normals
-                                                       no = globalNormals[ veckey3d(f.no) ]
+                                                       no = globalNormals[ veckey3d(f.normal) ]
                                                        for vi, v in enumerate(f_v):
-                                                               file.write( ' %d/%d/%d' % (\
-                                                                 v.index+totverts,\
-                                                                 totuvco + uv_face_mapping[f_index][vi],\
-                                                                 no)) # vert, uv, normal
-                                       
+                                                               file.write( ' %d/%d/%d' % \
+                                                                                               (v["index"] + totverts,
+                                                                                                totuvco + uv_face_mapping[f_index][vi],
+                                                                                                no) ) # vert, uv, normal
                                        else: # No Normals
                                                for vi, v in enumerate(f_v):
                                                        file.write( ' %d/%d' % (\
-                                                         v.index+totverts,\
+                                                         v["index"] + totverts,\
                                                          totuvco + uv_face_mapping[f_index][vi])) # vert, uv
                                        
                                        face_vert_index += len(f_v)
@@ -612,290 +774,105 @@ EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
                                        if EXPORT_NORMALS:
                                                if f_smooth: # Smoothed, use vertex normals
                                                        for v in f_v:
-                                                               file.write( ' %d//%d' % (\
-                                                                 v.index+totverts,\
-                                                                 globalNormals[ veckey3d(v.no) ]))
+                                                               file.write( ' %d//%d' %
+                                                                                       (v["index"] + totverts, globalNormals[ veckey3d(v["vertex"].normal) ]) )
                                                else: # No smoothing, face normals
-                                                       no = globalNormals[ veckey3d(f.no) ]
+                                                       no = globalNormals[ veckey3d(f.normal) ]
                                                        for v in f_v:
-                                                               file.write( ' %d//%d' % (\
-                                                                 v.index+totverts,\
-                                                                 no))
+                                                               file.write( ' %d//%d' % (v["index"] + totverts, no) )
                                        else: # No Normals
                                                for v in f_v:
-                                                       file.write( ' %d' % (\
-                                                         v.index+totverts))
+                                                       file.write( ' %d' % (v["index"] + totverts) )
                                                
                                file.write('\n')
                        
                        # Write edges.
                        if EXPORT_EDGES:
-                               LOOSE= Mesh.EdgeFlags.LOOSE
                                for ed in edges:
-                                       if ed.flag & LOOSE:
-                                               file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts))
+                                       if ed.loose:
+                                               file.write('f %d %d\n' % (ed.verts[0] + totverts, ed.verts[1] + totverts))
                                
                        # Make the indicies global rather then per mesh
                        totverts += len(me.verts)
                        if faceuv:
                                totuvco += uv_unique_count
-                       me.verts= None
+
+                       # clean up
+                       bpy.data.remove_mesh(me)
+
+               if ob_main.dupli_type != 'NONE':
+                       ob_main.free_dupli_list()
+
        file.close()
        
        
        # Now we have all our materials, save them
        if EXPORT_MTL:
-               write_mtl(mtlfilename)
-       if EXPORT_COPY_IMAGES:
-               dest_dir = filename
-               # Remove chars until we are just the path.
-               while dest_dir and dest_dir[-1] not in '\\/':
-                       dest_dir = dest_dir[:-1]
-               if dest_dir:
-                       copy_images(dest_dir)
-               else:
-                       print '\tError: "%s" could not be used as a base for an image path.' % filename
-       
-       print "OBJ Export time: %.2f" % (sys.time() - time1)
-       
-       
-
-def write_ui(filename):
-       
-       if not filename.lower().endswith('.obj'):
-               filename += '.obj'
-       
-       if not BPyMessages.Warning_SaveOver(filename):
-               return
-       
-       global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\
-               EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\
-               EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\
-               EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\
-               EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\
-               EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS
-       
-       EXPORT_APPLY_MODIFIERS = Draw.Create(0)
-       EXPORT_ROTX90 = Draw.Create(1)
-       EXPORT_TRI = Draw.Create(0)
-       EXPORT_EDGES = Draw.Create(1)
-       EXPORT_NORMALS = Draw.Create(0)
-       EXPORT_NORMALS_HQ = Draw.Create(0)
-       EXPORT_UV = Draw.Create(1)
-       EXPORT_MTL = Draw.Create(1)
-       EXPORT_SEL_ONLY = Draw.Create(1)
-       EXPORT_ALL_SCENES = Draw.Create(0)
-       EXPORT_ANIMATION = Draw.Create(0)
-       EXPORT_COPY_IMAGES = Draw.Create(0)
-       EXPORT_BLEN_OBS = Draw.Create(0)
-       EXPORT_GROUP_BY_OB = Draw.Create(0)
-       EXPORT_GROUP_BY_MAT = Draw.Create(0)
-       EXPORT_KEEP_VERT_ORDER = Draw.Create(1)
-       EXPORT_POLYGROUPS = Draw.Create(0)
-       EXPORT_CURVE_AS_NURBS = Draw.Create(1)
-       
-       
-       # Old UI
-       '''
-       # removed too many options are bad!
-       
-       # Get USER Options
-       pup_block = [\
-       ('Context...'),\
-       ('Selection Only', EXPORT_SEL_ONLY, 'Only export objects in visible selection. Else export whole scene.'),\
-       ('All Scenes', EXPORT_ALL_SCENES, 'Each scene as a separate OBJ file.'),\
-       ('Animation', EXPORT_ANIMATION, 'Each frame as a numbered OBJ file.'),\
-       ('Object Prefs...'),\
-       ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data from each object. May break vert order for morph targets.'),\
-       ('Rotate X90', EXPORT_ROTX90 , 'Rotate on export so Blenders UP is translated into OBJs UP'),\
-       ('Keep Vert Order', EXPORT_KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\
-       ('Extra Data...'),\
-       ('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\
-       ('Normals', EXPORT_NORMALS, 'Export vertex normal data (Ignored on import).'),\
-       ('High Quality Normals', EXPORT_NORMALS_HQ, 'Calculate high quality normals for rendering.'),\
-       ('UVs', EXPORT_UV, 'Export texface UV coords.'),\
-       ('Materials', EXPORT_MTL, 'Write a separate MTL file with the OBJ.'),\
-       ('Copy Images', EXPORT_COPY_IMAGES, 'Copy image files to the export directory, never overwrite.'),\
-       ('Triangulate', EXPORT_TRI, 'Triangulate quads.'),\
-       ('Grouping...'),\
-       ('Objects', EXPORT_BLEN_OBS, 'Export blender objects as "OBJ objects".'),\
-       ('Object Groups', EXPORT_GROUP_BY_OB, 'Export blender objects as "OBJ Groups".'),\
-       ('Material Groups', EXPORT_GROUP_BY_MAT, 'Group by materials.'),\
-       ]
-       
-       if not Draw.PupBlock('Export...', pup_block):
-               return
-       '''
-       
-       # BEGIN ALTERNATIVE UI *******************
-       if True: 
-               
-               EVENT_NONE = 0
-               EVENT_EXIT = 1
-               EVENT_REDRAW = 2
-               EVENT_EXPORT = 3
-               
-               GLOBALS = {}
-               GLOBALS['EVENT'] = EVENT_REDRAW
-               #GLOBALS['MOUSE'] = Window.GetMouseCoords()
-               GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()]
-               
-               def obj_ui_set_event(e,v):
-                       GLOBALS['EVENT'] = e
-               
-               def do_split(e,v):
-                       global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER, EXPORT_POLYGROUPS
-                       if EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val:
-                               EXPORT_KEEP_VERT_ORDER.val = 0
-                       else:
-                               EXPORT_KEEP_VERT_ORDER.val = 1
-                       
-               def do_vertorder(e,v):
-                       global EXPORT_BLEN_OBS, EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_APPLY_MODIFIERS, KEEP_VERT_ORDER
-                       if EXPORT_KEEP_VERT_ORDER.val:
-                               EXPORT_BLEN_OBS.val = EXPORT_GROUP_BY_OB.val = EXPORT_GROUP_BY_MAT.val = EXPORT_APPLY_MODIFIERS.val = 0
-                       else:
-                               if not (EXPORT_BLEN_OBS.val or EXPORT_GROUP_BY_OB.val or EXPORT_GROUP_BY_MAT.val or EXPORT_APPLY_MODIFIERS.val):
-                                       EXPORT_KEEP_VERT_ORDER.val = 1
-                       
-                       
-               def do_help(e,v):
-                       url = __url__[0]
-                       print 'Trying to open web browser with documentation at this address...'
-                       print '\t' + url
-                       
-                       try:
-                               import webbrowser
-                               webbrowser.open(url)
-                       except:
-                               print '...could not open a browser window.'
-               
-               def obj_ui():
-                       ui_x, ui_y = GLOBALS['MOUSE']
-                       
-                       # Center based on overall pup size
-                       ui_x -= 165
-                       ui_y -= 140
-                       
-                       global EXPORT_APPLY_MODIFIERS, EXPORT_ROTX90, EXPORT_TRI, EXPORT_EDGES,\
-                               EXPORT_NORMALS, EXPORT_NORMALS_HQ, EXPORT_UV,\
-                               EXPORT_MTL, EXPORT_SEL_ONLY, EXPORT_ALL_SCENES,\
-                               EXPORT_ANIMATION, EXPORT_COPY_IMAGES, EXPORT_BLEN_OBS,\
-                               EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\
-                               EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS
-
-                       Draw.Label('Context...', ui_x+9, ui_y+239, 220, 20)
-                       Draw.BeginAlign()
-                       EXPORT_SEL_ONLY = Draw.Toggle('Selection Only', EVENT_NONE, ui_x+9, ui_y+219, 110, 20, EXPORT_SEL_ONLY.val, 'Only export objects in visible selection. Else export whole scene.')
-                       EXPORT_ALL_SCENES = Draw.Toggle('All Scenes', EVENT_NONE, ui_x+119, ui_y+219, 110, 20, EXPORT_ALL_SCENES.val, 'Each scene as a separate OBJ file.')
-                       EXPORT_ANIMATION = Draw.Toggle('Animation', EVENT_NONE, ui_x+229, ui_y+219, 110, 20, EXPORT_ANIMATION.val, 'Each frame as a numbered OBJ file.')
-                       Draw.EndAlign()
-                       
-                       
-                       Draw.Label('Output Options...', ui_x+9, ui_y+189, 220, 20)
-                       Draw.BeginAlign()
-                       EXPORT_APPLY_MODIFIERS = Draw.Toggle('Apply Modifiers', EVENT_REDRAW, ui_x+9, ui_y+170, 110, 20, EXPORT_APPLY_MODIFIERS.val, 'Use transformed mesh data from each object. May break vert order for morph targets.', do_split)
-                       EXPORT_ROTX90 = Draw.Toggle('Rotate X90', EVENT_NONE, ui_x+119, ui_y+170, 110, 20, EXPORT_ROTX90.val, 'Rotate on export so Blenders UP is translated into OBJs UP')
-                       EXPORT_COPY_IMAGES = Draw.Toggle('Copy Images', EVENT_NONE, ui_x+229, ui_y+170, 110, 20, EXPORT_COPY_IMAGES.val, 'Copy image files to the export directory, never overwrite.')
-                       Draw.EndAlign()
-                       
-                       
-                       Draw.Label('Export...', ui_x+9, ui_y+139, 220, 20)
-                       Draw.BeginAlign()
-                       EXPORT_EDGES = Draw.Toggle('Edges', EVENT_NONE, ui_x+9, ui_y+120, 50, 20, EXPORT_EDGES.val, 'Edges not connected to faces.')
-                       EXPORT_TRI = Draw.Toggle('Triangulate', EVENT_NONE, ui_x+59, ui_y+120, 70, 20, EXPORT_TRI.val, 'Triangulate quads.')
-                       Draw.EndAlign()
-                       Draw.BeginAlign()
-                       EXPORT_MTL = Draw.Toggle('Materials', EVENT_NONE, ui_x+139, ui_y+120, 70, 20, EXPORT_MTL.val, 'Write a separate MTL file with the OBJ.')
-                       EXPORT_UV = Draw.Toggle('UVs', EVENT_NONE, ui_x+209, ui_y+120, 31, 20, EXPORT_UV.val, 'Export texface UV coords.')
-                       Draw.EndAlign()
-                       Draw.BeginAlign()
-                       EXPORT_NORMALS = Draw.Toggle('Normals', EVENT_NONE, ui_x+250, ui_y+120, 59, 20, EXPORT_NORMALS.val, 'Export vertex normal data (Ignored on import).')
-                       EXPORT_NORMALS_HQ = Draw.Toggle('HQ', EVENT_NONE, ui_x+309, ui_y+120, 31, 20, EXPORT_NORMALS_HQ.val, 'Calculate high quality normals for rendering.')
-                       Draw.EndAlign()
-                       EXPORT_POLYGROUPS = Draw.Toggle('Polygroups', EVENT_REDRAW, ui_x+9, ui_y+95, 120, 20, EXPORT_POLYGROUPS.val, 'Export vertex groups as OBJ groups (one group per face approximation).')
-                       
-                       EXPORT_CURVE_AS_NURBS = Draw.Toggle('Nurbs', EVENT_NONE, ui_x+139, ui_y+95, 100, 20, EXPORT_CURVE_AS_NURBS.val, 'Export 3D nurbs curves and polylines as OBJ curves, (bezier not supported).')
-                       
-                       
-                       Draw.Label('Blender Objects as OBJ:', ui_x+9, ui_y+59, 220, 20)
-                       Draw.BeginAlign()
-                       EXPORT_BLEN_OBS = Draw.Toggle('Objects', EVENT_REDRAW, ui_x+9, ui_y+39, 60, 20, EXPORT_BLEN_OBS.val, 'Export blender objects as "OBJ objects".', do_split)
-                       EXPORT_GROUP_BY_OB = Draw.Toggle('Groups', EVENT_REDRAW, ui_x+69, ui_y+39, 60, 20, EXPORT_GROUP_BY_OB.val, 'Export blender objects as "OBJ Groups".', do_split)
-                       EXPORT_GROUP_BY_MAT = Draw.Toggle('Material Groups', EVENT_REDRAW, ui_x+129, ui_y+39, 100, 20, EXPORT_GROUP_BY_MAT.val, 'Group by materials.', do_split)
-                       Draw.EndAlign()
-                       
-                       EXPORT_KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+239, ui_y+39, 100, 20, EXPORT_KEEP_VERT_ORDER.val, 'Keep vert and face order, disables some other options. Use for morph targets.', do_vertorder)
-                       
-                       Draw.BeginAlign()
-                       Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 20, 'Load the wiki page for this script', do_help)
-                       Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 20, '', obj_ui_set_event)
-                       Draw.PushButton('Export', EVENT_EXPORT, ui_x+229, ui_y+9, 110, 20, 'Export with these settings', obj_ui_set_event)
-                       Draw.EndAlign()
+               write_mtl(scene, mtlfilename, EXPORT_COPY_IMAGES)
+#      if EXPORT_COPY_IMAGES:
+#              dest_dir = os.path.basename(filename)
+# #            dest_dir = filename
+# #            # Remove chars until we are just the path.
+# #            while dest_dir and dest_dir[-1] not in '\\/':
+# #                    dest_dir = dest_dir[:-1]
+#              if dest_dir:
+#                      copy_images(dest_dir)
+#              else:
+#                      print('\tError: "%s" could not be used as a base for an image path.' % filename)
+
+       print("OBJ Export time: %.2f" % (time.clock() - time1))
+#      print "OBJ Export time: %.2f" % (sys.time() - time1)
+
+def do_export(filename, context, 
+                         EXPORT_APPLY_MODIFIERS = True, # not used
+                         EXPORT_ROTX90 = True, # wrong
+                         EXPORT_TRI = False, # ok
+                         EXPORT_EDGES = False,
+                         EXPORT_NORMALS = False, # not yet
+                         EXPORT_NORMALS_HQ = False, # not yet
+                         EXPORT_UV = True, # ok
+                         EXPORT_MTL = True,
+                         EXPORT_SEL_ONLY = True, # ok
+                         EXPORT_ALL_SCENES = False, # XXX not working atm
+                         EXPORT_ANIMATION = False,
+                         EXPORT_COPY_IMAGES = False,
+                         EXPORT_BLEN_OBS = True,
+                         EXPORT_GROUP_BY_OB = False,
+                         EXPORT_GROUP_BY_MAT = False,
+                         EXPORT_KEEP_VERT_ORDER = False,
+                         EXPORT_POLYGROUPS = False,
+                         EXPORT_CURVE_AS_NURBS = True):
+       #       Window.EditMode(0)
+       #       Window.WaitCursor(1)
 
-               
-               # hack so the toggle buttons redraw. this is not nice at all
-               while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_EXPORT):
-                       Draw.UIBlock(obj_ui, 0)
-               
-               if GLOBALS['EVENT'] != EVENT_EXPORT:
-                       return
-               
-       # END ALTERNATIVE UI *********************
-       
-       
-       if EXPORT_KEEP_VERT_ORDER.val:
-               EXPORT_BLEN_OBS.val = False
-               EXPORT_GROUP_BY_OB.val = False
-               EXPORT_GROUP_BY_MAT.val = False
-               EXPORT_APPLY_MODIFIERS.val = False
-       
-       Window.EditMode(0)
-       Window.WaitCursor(1)
-       
-       EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val
-       EXPORT_ROTX90 = EXPORT_ROTX90.val
-       EXPORT_TRI = EXPORT_TRI.val
-       EXPORT_EDGES = EXPORT_EDGES.val
-       EXPORT_NORMALS = EXPORT_NORMALS.val
-       EXPORT_NORMALS_HQ = EXPORT_NORMALS_HQ.val
-       EXPORT_UV = EXPORT_UV.val
-       EXPORT_MTL = EXPORT_MTL.val
-       EXPORT_SEL_ONLY = EXPORT_SEL_ONLY.val
-       EXPORT_ALL_SCENES = EXPORT_ALL_SCENES.val
-       EXPORT_ANIMATION = EXPORT_ANIMATION.val
-       EXPORT_COPY_IMAGES = EXPORT_COPY_IMAGES.val
-       EXPORT_BLEN_OBS = EXPORT_BLEN_OBS.val
-       EXPORT_GROUP_BY_OB = EXPORT_GROUP_BY_OB.val
-       EXPORT_GROUP_BY_MAT = EXPORT_GROUP_BY_MAT.val
-       EXPORT_KEEP_VERT_ORDER = EXPORT_KEEP_VERT_ORDER.val
-       EXPORT_POLYGROUPS = EXPORT_POLYGROUPS.val
-       EXPORT_CURVE_AS_NURBS = EXPORT_CURVE_AS_NURBS.val
-       
-       
        base_name, ext = splitExt(filename)
-       context_name = [base_name, '', '', ext] # basename, scene_name, framenumber, extension
-       
-       # Use the options to export the data using write()
-       # def write(filename, objects, EXPORT_EDGES=False, EXPORT_NORMALS=False, EXPORT_MTL=True, EXPORT_COPY_IMAGES=False, EXPORT_APPLY_MODIFIERS=True):
-       orig_scene = Scene.GetCurrent()
-       if EXPORT_ALL_SCENES:
-               export_scenes = Scene.Get()
-       else:
-               export_scenes = [orig_scene]
+       context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension
        
+       orig_scene = context.scene
+
+#      if EXPORT_ALL_SCENES:
+#              export_scenes = bpy.data.scenes
+#      else:
+#              export_scenes = [orig_scene]
+
+       # XXX only exporting one scene atm since changing 
+       # current scene is not possible.
+       # Brecht says that ideally in 2.5 we won't need such a function,
+       # allowing multiple scenes open at once.
+       export_scenes = [orig_scene]
+
        # Export all scenes.
        for scn in export_scenes:
-               scn.makeCurrent() # If alredy current, this is not slow.
-               context = scn.getRenderingContext()
-               orig_frame = Blender.Get('curframe')
+               #               scn.makeCurrent() # If already current, this is not slow.
+               #               context = scn.getRenderingContext()
+               orig_frame = scn.current_frame
                
                if EXPORT_ALL_SCENES: # Add scene name into the context_name
-                       context_name[1] = '_%s' % BPySys.cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
+                       context_name[1] = '_%s' % BPySys_cleanName(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
                
                # Export an animation?
                if EXPORT_ANIMATION:
-                       scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame.
+                       scene_frames = range(scn.start_frame, context.end_frame+1) # Up to and including the end frame.
                else:
                        scene_frames = [orig_frame] # Dont export an animation.
                
@@ -904,9 +881,9 @@ def write_ui(filename):
                        if EXPORT_ANIMATION: # Add frame to the filename.
                                context_name[2] = '_%.6d' % frame
                        
-                       Blender.Set('curframe', frame)
+                       scn.current_frame = frame
                        if EXPORT_SEL_ONLY:
-                               export_objects = scn.objects.context
+                               export_objects = context.selected_objects
                        else:   
                                export_objects = scn.objects
                        
@@ -914,20 +891,106 @@ def write_ui(filename):
                        
                        # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad.
                        # EXPORT THE FILE.
-                       write(full_path, export_objects,\
-                       EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\
-                       EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\
-                       EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\
-                       EXPORT_ROTX90, EXPORT_BLEN_OBS,\
-                       EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,\
-                       EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS)
+                       write(full_path, export_objects, scn,
+                                 EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,
+                                 EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,
+                                 EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,
+                                 EXPORT_ROTX90, EXPORT_BLEN_OBS,
+                                 EXPORT_GROUP_BY_OB, EXPORT_GROUP_BY_MAT, EXPORT_KEEP_VERT_ORDER,
+                                 EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS)
+
                
-               Blender.Set('curframe', orig_frame)
+               scn.current_frame = orig_frame
        
        # Restore old active scene.
-       orig_scene.makeCurrent()
-       Window.WaitCursor(0)
+#      orig_scene.makeCurrent()
+#      Window.WaitCursor(0)
 
 
-if __name__ == '__main__':
-       Window.FileSelector(write_ui, 'Export Wavefront OBJ', sys.makename(ext='.obj'))
+class EXPORT_OT_obj(bpy.types.Operator):
+       '''
+       Currently the exporter lacks these features:
+       * nurbs
+       * multiple scene export (only active scene is written)
+       * particles
+       '''
+       __idname__ = "export.obj"
+       __label__ = 'Export OBJ'
+       
+       # List of operator properties, the attributes will be assigned
+       # to the class instance from the operator settings before calling.
+
+       __props__ = [
+               bpy.props.StringProperty(attr="path", name="File Path", description="File path used for exporting the OBJ file", maxlen= 1024, default= ""),
+
+               # context group
+               bpy.props.BoolProperty(attr="use_selection", name="Selection Only", description="", default= False),
+               bpy.props.BoolProperty(attr="use_all_scenes", name="All Scenes", description="", default= False),
+               bpy.props.BoolProperty(attr="use_animation", name="All Animation", description="", default= False),
+
+               # object group
+               bpy.props.BoolProperty(attr="use_modifiers", name="Apply Modifiers", description="", default= True),
+               bpy.props.BoolProperty(attr="use_rotate90", name="Rotate X90", description="", default= True),
+
+               # extra data group
+               bpy.props.BoolProperty(attr="use_edges", name="Edges", description="", default= True),
+               bpy.props.BoolProperty(attr="use_normals", name="Normals", description="", default= False),
+               bpy.props.BoolProperty(attr="use_hq_normals", name="High Quality Normals", description="", default= True),
+               bpy.props.BoolProperty(attr="use_uvs", name="UVs", description="", default= True),
+               bpy.props.BoolProperty(attr="use_materials", name="Materials", description="", default= True),
+               bpy.props.BoolProperty(attr="copy_images", name="Copy Images", description="", default= False),
+               bpy.props.BoolProperty(attr="use_triangles", name="Triangulate", description="", default= False),
+               bpy.props.BoolProperty(attr="use_vertex_groups", name="Polygroups", description="", default= False),
+               bpy.props.BoolProperty(attr="use_nurbs", name="Nurbs", description="", default= False),
+
+               # grouping group
+               bpy.props.BoolProperty(attr="use_blen_objects", name="Objects as OBJ Objects", description="", default= True),
+               bpy.props.BoolProperty(attr="group_by_object", name="Objects as OBJ Groups ", description="", default= False),
+               bpy.props.BoolProperty(attr="group_by_material", name="Material Groups", description="", default= False),
+               bpy.props.BoolProperty(attr="keep_vertex_order", name="Keep Vertex Order", description="", default= False)
+       ]
+       
+       def execute(self, context):
+
+               do_export(self.path, context,
+                                 EXPORT_TRI=self.use_triangles,
+                                 EXPORT_EDGES=self.use_edges,
+                                 EXPORT_NORMALS=self.use_normals,
+                                 EXPORT_NORMALS_HQ=self.use_hq_normals,
+                                 EXPORT_UV=self.use_uvs,
+                                 EXPORT_MTL=self.use_materials,
+                                 EXPORT_COPY_IMAGES=self.copy_images,
+                                 EXPORT_APPLY_MODIFIERS=self.use_modifiers,
+                                 EXPORT_ROTX90=self.use_rotate90,
+                                 EXPORT_BLEN_OBS=self.use_blen_objects,
+                                 EXPORT_GROUP_BY_OB=self.group_by_object,
+                                 EXPORT_GROUP_BY_MAT=self.group_by_material,
+                                 EXPORT_KEEP_VERT_ORDER=self.keep_vertex_order,
+                                 EXPORT_POLYGROUPS=self.use_vertex_groups,
+                                 EXPORT_CURVE_AS_NURBS=self.use_nurbs,
+                                 EXPORT_SEL_ONLY=self.use_selection,
+                                 EXPORT_ALL_SCENES=self.use_all_scenes)
+
+               return ('FINISHED',)
+       
+       def invoke(self, context, event):
+               wm = context.manager
+               wm.add_fileselect(self.__operator__)
+               return ('RUNNING_MODAL',)
+       
+       def poll(self, context): # Poll isnt working yet
+               print("Poll")
+               return context.active_object != None
+
+bpy.ops.add(EXPORT_OT_obj)
+
+if __name__ == "__main__":
+       bpy.ops.EXPORT_OT_obj(filename="/tmp/test.obj")
+
+# CONVERSION ISSUES
+# - matrix problem
+# - duplis - only tested dupliverts
+# - NURBS - needs API additions
+# - all scenes export
+# + normals calculation
+# - get rid of cleanName somehow
index 46d080503028a5967944eb60c18f14b645454b92..8e79c3741bb5717dbcfa08c9dc34be1cd7515ef6 100644 (file)
@@ -1,16 +1,4 @@
-#!BPY
-
-"""
-Name: 'Stanford PLY (*.ply)...'
-Blender: 241
-Group: 'Export'
-Tooltip: 'Export active object to Stanford PLY format'
-"""
-
 import bpy
-import Blender
-from Blender import Mesh, Scene, Window, sys, Image, Draw
-import BPyMesh
 
 __author__ = "Bruce Merry"
 __version__ = "0.93"
@@ -62,84 +50,105 @@ Only one mesh can be exported at a time.
 def rvec3d(v): return round(v[0], 6), round(v[1], 6), round(v[2], 6)
 def rvec2d(v): return round(v[0], 6), round(v[1], 6)
 
-def file_callback(filename):
+def write(filename, scene, ob, \
+               EXPORT_APPLY_MODIFIERS= True,\
+               EXPORT_NORMALS= True,\
+               EXPORT_UV= True,\
+               EXPORT_COLORS= True\
+       ):
        
        if not filename.lower().endswith('.ply'):
                filename += '.ply'
        
-       scn= bpy.data.scenes.active
-       ob= scn.objects.active
        if not ob:
-               Blender.Draw.PupMenu('Error%t|Select 1 active object')
+               raise Exception("Error, Select 1 active object")
                return
        
-       file = open(filename, 'wb')
+       file = open(filename, 'w')
        
-       EXPORT_APPLY_MODIFIERS = Draw.Create(1)
-       EXPORT_NORMALS = Draw.Create(1)
-       EXPORT_UV = Draw.Create(1)
-       EXPORT_COLORS = Draw.Create(1)
-       #EXPORT_EDGES = Draw.Create(0)
-       
-       pup_block = [\
-       ('Apply Modifiers', EXPORT_APPLY_MODIFIERS, 'Use transformed mesh data.'),\
-       ('Normals', EXPORT_NORMALS, 'Export vertex normal data.'),\
-       ('UVs', EXPORT_UV, 'Export texface UV coords.'),\
-       ('Colors', EXPORT_COLORS, 'Export vertex Colors.'),\
-       #('Edges', EXPORT_EDGES, 'Edges not connected to faces.'),\
-       ]
-       
-       if not Draw.PupBlock('Export...', pup_block):
-               return
        
+       #EXPORT_EDGES = Draw.Create(0)
+       """
        is_editmode = Blender.Window.EditMode()
        if is_editmode:
                Blender.Window.EditMode(0, '', 0)
        
        Window.WaitCursor(1)
+       """
        
-       EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val
-       EXPORT_NORMALS = EXPORT_NORMALS.val
-       EXPORT_UV = EXPORT_UV.val
-       EXPORT_COLORS = EXPORT_COLORS.val
-       #EXPORT_EDGES = EXPORT_EDGES.val
-       
-       mesh = BPyMesh.getMeshFromObject(ob, None, EXPORT_APPLY_MODIFIERS, False, scn)
+       #mesh = BPyMesh.getMeshFromObject(ob, None, EXPORT_APPLY_MODIFIERS, False, scn) # XXX
+       if EXPORT_APPLY_MODIFIERS:
+               mesh = ob.create_mesh(True, 'PREVIEW')
+       else:
+               mesh = ob.data
        
        if not mesh:
-               Blender.Draw.PupMenu('Error%t|Could not get mesh data from active object')
+               raise ("Error, could not get mesh data from active object")
                return
        
-       mesh.transform(ob.matrixWorld)
+       # mesh.transform(ob.matrixWorld) # XXX
        
-       faceUV = mesh.faceUV
-       vertexUV = mesh.vertexUV
-       vertexColors = mesh.vertexColors
+       faceUV = len(mesh.uv_textures) > 0
+       vertexUV = len(mesh.sticky) > 0
+       vertexColors = len(mesh.vertex_colors) > 0
        
-       if (not faceUV) and (not vertexUV):             EXPORT_UV = False
+       if (not faceUV) and (not vertexUV):     EXPORT_UV = False
        if not vertexColors:                                    EXPORT_COLORS = False
        
        if not EXPORT_UV:                                               faceUV = vertexUV = False
        if not EXPORT_COLORS:                                   vertexColors = False
+               
+       if faceUV:
+               active_uv_layer = None
+               for lay in mesh.uv_textures:
+                       if lay.active:
+                               active_uv_layer= lay.data
+                               break
+               if not active_uv_layer:
+                       EXPORT_UV = False
+                       faceUV = None
+       
+       if vertexColors:
+               active_col_layer = None
+               for lay in mesh.vertex_colors:
+                       if lay.active:
+                               active_col_layer= lay.data
+               if not active_col_layer:
+                       EXPORT_COLORS = False
+                       vertexColors = None
        
        # incase
        color = uvcoord = uvcoord_key = normal = normal_key = None
        
-       verts = [] # list of dictionaries
+       mesh_verts = mesh.verts # save a lookup
+       ply_verts = [] # list of dictionaries
        # vdict = {} # (index, normal, uv) -> new index
-       vdict = [{} for i in xrange(len(mesh.verts))]
+       vdict = [{} for i in range(len(mesh_verts))]
+       ply_faces = [[] for f in range(len(mesh.faces))]
        vert_count = 0
        for i, f in enumerate(mesh.faces):
+               
+               
                smooth = f.smooth
                if not smooth:
-                       normal = tuple(f.no)
+                       normal = tuple(f.normal)
                        normal_key = rvec3d(normal)
+               
+               if faceUV:
+                       uv = active_uv_layer[i]
+                       uv = uv.uv1, uv.uv2, uv.uv3, uv.uv4 # XXX - crufty :/
+               if vertexColors:
+                       col = active_col_layer[i]
+                       col = col.color1, col.color2, col.color3, col.color4
+               
+               f_verts= f.verts
+               
+               pf= ply_faces[i]
+               for j, vidx in enumerate(f_verts):
+                       v = mesh_verts[vidx]
                        
-               if faceUV:                      uv = f.uv
-               if vertexColors:        col = f.col
-               for j, v in enumerate(f):
                        if smooth:
-                               normal=         tuple(v.no)
+                               normal=         tuple(v.normal)
                                normal_key = rvec3d(normal)
                        
                        if faceUV:
@@ -149,33 +158,41 @@ def file_callback(filename):
                                uvcoord=        v.uvco[0], 1.0-v.uvco[1]
                                uvcoord_key = rvec2d(uvcoord)
                        
-                       if vertexColors:        color=          col[j].r, col[j].g, col[j].b
+                       if vertexColors:
+                               color=          col[j]
+                               color= int(color[0]*255.0), int(color[1]*255.0), int(color[2]*255.0)
                        
                        
                        key = normal_key, uvcoord_key, color
                        
-                       vdict_local = vdict[v.index]
+                       vdict_local = vdict[vidx]
+                       pf_vidx = vdict_local.get(key) # Will be None initially
                        
-                       if (not vdict_local) or (not vdict_local.has_key(key)):
-                               vdict_local[key] = vert_count;
-                               verts.append( (tuple(v.co), normal, uvcoord, color) )
+                       if pf_vidx == None: # same as vdict_local.has_key(key)
+                               pf_vidx = vdict_local[key] = vert_count;
+                               ply_verts.append((vidx, normal, uvcoord, color))
                                vert_count += 1
-       
+                       
+                       pf.append(pf_vidx)
        
        file.write('ply\n')
        file.write('format ascii 1.0\n')
-       file.write('comment Created by Blender3D %s - www.blender.org, source file: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
+       version = "2.5" # Blender.Get('version')
+       file.write('comment Created by Blender3D %s - www.blender.org, source file: %s\n' % (version, bpy.data.filename.split('/')[-1].split('\\')[-1] ))
        
-       file.write('element vertex %d\n' % len(verts))
+       file.write('element vertex %d\n' % len(ply_verts))
        
        file.write('property float x\n')
        file.write('property float y\n')
        file.write('property float z\n')
+       
+       # XXX 
+       """
        if EXPORT_NORMALS:
                file.write('property float nx\n')
                file.write('property float ny\n')
                file.write('property float nz\n')
-       
+       """
        if EXPORT_UV:
                file.write('property float s\n')
                file.write('property float t\n')
@@ -188,41 +205,75 @@ def file_callback(filename):
        file.write('property list uchar uint vertex_indices\n')
        file.write('end_header\n')
 
-       for i, v in enumerate(verts):
-               file.write('%.6f %.6f %.6f ' % v[0]) # co
+       for i, v in enumerate(ply_verts):
+               file.write('%.6f %.6f %.6f ' % tuple(mesh_verts[v[0]].co)) # co
+               """
                if EXPORT_NORMALS:
                        file.write('%.6f %.6f %.6f ' % v[1]) # no
-               
-               if EXPORT_UV:
-                       file.write('%.6f %.6f ' % v[2]) # uv
-               if EXPORT_COLORS:
-                       file.write('%u %u %u' % v[3]) # col
+               """
+               if EXPORT_UV:                   file.write('%.6f %.6f ' % v[2]) # uv
+               if EXPORT_COLORS:               file.write('%u %u %u' % v[3]) # col
                file.write('\n')
        
-       for (i, f) in enumerate(mesh.faces):
-               file.write('%d ' % len(f))
-               smooth = f.smooth
-               if not smooth: no = rvec3d(f.no)
-               
-               if faceUV:                      uv = f.uv
-               if vertexColors:        col = f.col
-               for j, v in enumerate(f):
-                       if f.smooth:            normal=         rvec3d(v.no)
-                       else:                           normal=         no
-                       if faceUV:                      uvcoord=        rvec2d((uv[j][0], 1.0-uv[j][1]))
-                       elif vertexUV:          uvcoord=        rvec2d((v.uvco[0], 1.0-v.uvco[1]))
-                       if vertexColors:        color=          col[j].r, col[j].g, col[j].b
-                       
-                       file.write('%d ' % vdict[v.index][normal, uvcoord, color])
-                       
-               file.write('\n')
+       for pf in ply_faces:
+               if len(pf)==3:          file.write('3 %d %d %d\n' % tuple(pf))
+               else:                           file.write('4 %d %d %d %d\n' % tuple(pf))
+       
        file.close()
+       print("writing", filename, "done")
+       
+       if EXPORT_APPLY_MODIFIERS:
+               bpy.data.remove_mesh(mesh)
        
+       # XXX
+       """
        if is_editmode:
                Blender.Window.EditMode(1, '', 0)
+       """
+
+class EXPORT_OT_ply(bpy.types.Operator):
+       '''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
+       __idname__ = "export.ply"
+       __label__ = "Export PLY"
+       
+       # List of operator properties, the attributes will be assigned
+       # to the class instance from the operator settings before calling.
+       
+       __props__ = [
+               bpy.props.StringProperty(attr="path", name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= ""),
+               bpy.props.BoolProperty(attr="use_modifiers", name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default= True),
+               bpy.props.BoolProperty(attr="use_normals", name="Export Normals", description="Export Normals for smooth and hard shaded faces", default= True),
+               bpy.props.BoolProperty(attr="use_uvs", name="Export UVs", description="Exort the active UV layer", default= True),
+               bpy.props.BoolProperty(attr="use_colors", name="Export Vertex Colors", description="Exort the active vertex color layer", default= True)
+       ]
+       
+       def poll(self, context):
+               return context.active_object != None
+       
+       def execute(self, context):
+               # print("Selected: " + context.active_object.name)
+
+               if not self.path:
+                       raise Exception("filename not set")
+                       
+               write(self.path, context.scene, context.active_object,\
+                       EXPORT_APPLY_MODIFIERS = self.use_modifiers,
+                       EXPORT_NORMALS = self.use_normals,
+                       EXPORT_UV = self.use_uvs,
+                       EXPORT_COLORS = self.use_colors,
+               )
+
+               return ('FINISHED',)
+       
+       def invoke(self, context, event):       
+               wm = context.manager
+               wm.add_fileselect(self.__operator__)
+               return ('RUNNING_MODAL',)
+
+
+bpy.ops.add(EXPORT_OT_ply)
+
+if __name__ == "__main__":
+       bpy.ops.EXPORT_OT_ply(path="/tmp/test.ply")
 
-def main():
-       Blender.Window.FileSelector(file_callback, 'PLY Export', Blender.sys.makename(ext='.ply'))
 
-if __name__=='__main__':
-       main()
index b12ff67d8a606842d8851cfbce7c506900c910aa..db29afc7d6dfb40274dfde4bc92712dcb59133c3 100644 (file)
@@ -53,22 +53,30 @@ Known issues:<br>
 # Library dependancies
 ####################################
 
-import Blender
-from Blender import Object, Lamp, Draw, Image, Text, sys, Mesh
-from Blender.Scene import Render
 import math
-import BPyObject
-import BPyMesh
+import os
+
+import bpy
+import Mathutils
+
+from export_3ds import create_derived_objects, free_derived_objects
+
+# import Blender
+# from Blender import Object, Lamp, Draw, Image, Text, sys, Mesh
+# from Blender.Scene import Render
+# import BPyObject
+# import BPyMesh
 
 # 
 DEG2RAD=0.017453292519943295
-MATWORLD= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
+MATWORLD= Mathutils.RotationMatrix(-90, 4, 'x')
 
 ####################################
 # Global Variables
 ####################################
 
-filename = Blender.Get('filename')
+filename = ""
+# filename = Blender.Get('filename')
 _safeOverwrite = True
 
 extension = ''
@@ -109,7 +117,7 @@ class x3d_class:
                                import gzip
                                self.file = gzip.open(filename, "w")                            
                        except:
-                               print "failed to import compression modules, exporting uncompressed"
+                               print("failed to import compression modules, exporting uncompressed")
                                self.filename = filename[:-1] # remove trailing z
                
                if self.file == None:
@@ -161,8 +169,10 @@ class x3d_class:
                self.file.write("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n")
                self.file.write("<X3D version=\"3.0\" profile=\"Immersive\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\">\n")
                self.file.write("<head>\n")
-               self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % sys.basename(bfile))
-               self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % Blender.Get('version'))
+               self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % os.path.basename(bfile))
+               # self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % sys.basename(bfile))
+               self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % '2.5')
+               # self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % Blender.Get('version'))
                self.file.write("\t<meta name=\"translator\" content=\"X3D exporter v1.55 (2006/01/17)\" />\n")
                self.file.write("</head>\n")
                self.file.write("<Scene>\n")
@@ -206,9 +216,12 @@ class x3d_class:
        '''
        
        def writeViewpoint(self, ob, mat, scene):
-               context = scene.render
-               ratio = float(context.imageSizeY())/float(context.imageSizeX())
-               lens = (360* (math.atan(ratio *16 / ob.data.getLens()) / math.pi))*(math.pi/180)
+               context = scene.render_data
+               # context = scene.render
+               ratio = float(context.resolution_x)/float(context.resolution_y)
+               # ratio = float(context.imageSizeY())/float(context.imageSizeX())
+               lens = (360* (math.atan(ratio *16 / ob.data.lens) / math.pi))*(math.pi/180)
+               # lens = (360* (math.atan(ratio *16 / ob.data.getLens()) / math.pi))*(math.pi/180)
                lens = min(lens, math.pi) 
                
                # get the camera location, subtract 90 degress from X to orient like X3D does
@@ -216,7 +229,8 @@ class x3d_class:
                
                loc = self.rotatePointForVRML(mat.translationPart())
                rot = mat.toEuler()
-               rot = (((rot[0]-90)*DEG2RAD), rot[1]*DEG2RAD, rot[2]*DEG2RAD)
+               rot = (((rot[0]-90)), rot[1], rot[2])
+               # rot = (((rot[0]-90)*DEG2RAD), rot[1]*DEG2RAD, rot[2]*DEG2RAD)
                nRot = self.rotatePointForVRML( rot )
                # convert to Quaternion and to Angle Axis
                Q  = self.eulerToQuaternions(nRot[0], nRot[1], nRot[2])
@@ -232,13 +246,18 @@ class x3d_class:
 
        def writeFog(self, world):
                if world:
-                       mtype = world.getMistype()
-                       mparam = world.getMist()
-                       grd = world.getHor()
+                       mtype = world.mist.falloff
+                       # mtype = world.getMistype()
+                       mparam = world.mist
+                       # mparam = world.getMist()
+                       grd = world.horizon_color
+                       # grd = world.getHor()
                        grd0, grd1, grd2 = grd[0], grd[1], grd[2]
                else:
                        return
-               if (mtype == 1 or mtype == 2):
+               if (mtype == 'LINEAR' or mtype == 'INVERSE_QUADRATIC'):
+                       mtype = 1 if mtype == 'LINEAR' else 2
+               # if (mtype == 1 or mtype == 2):
                        self.file.write("<Fog fogType=\"%s\" " % self.namesFog[mtype])                                          
                        self.file.write("color=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
                        self.file.write("visibilityRange=\"%s\" />\n\n" % round(mparam[2],self.cp))
@@ -251,7 +270,8 @@ class x3d_class:
        def writeSpotLight(self, ob, mtx, lamp, world):
                safeName = self.cleanStr(ob.name)
                if world:
-                       ambi = world.amb
+                       ambi = world.ambient_color
+                       # ambi = world.amb
                        ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
                else:
                        ambi = 0
@@ -259,7 +279,8 @@ class x3d_class:
 
                # compute cutoff and beamwidth
                intensity=min(lamp.energy/1.75,1.0)
-               beamWidth=((lamp.spotSize*math.pi)/180.0)*.37;
+               beamWidth=((lamp.spot_size*math.pi)/180.0)*.37;
+               # beamWidth=((lamp.spotSize*math.pi)/180.0)*.37;
                cutOffAngle=beamWidth*1.3
 
                dx,dy,dz=self.computeDirection(mtx)
@@ -270,12 +291,14 @@ class x3d_class:
                #location=(ob.matrixWorld*MATWORLD).translationPart() # now passed
                location=(mtx*MATWORLD).translationPart()
                
-               radius = lamp.dist*math.cos(beamWidth)
+               radius = lamp.distance*math.cos(beamWidth)
+               # radius = lamp.dist*math.cos(beamWidth)
                self.file.write("<SpotLight DEF=\"%s\" " % safeName)
                self.file.write("radius=\"%s\" " % (round(radius,self.cp)))
                self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp)))
                self.file.write("intensity=\"%s\" " % (round(intensity,self.cp)))
-               self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp)))
+               self.file.write("color=\"%s %s %s\" " % (round(lamp.color[0],self.cp), round(lamp.color[1],self.cp), round(lamp.color[2],self.cp)))
+               # self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp)))
                self.file.write("beamWidth=\"%s\" " % (round(beamWidth,self.cp)))
                self.file.write("cutOffAngle=\"%s\" " % (round(cutOffAngle,self.cp)))
                self.file.write("direction=\"%s %s %s\" " % (round(dx,3),round(dy,3),round(dz,3)))
@@ -285,7 +308,8 @@ class x3d_class:
        def writeDirectionalLight(self, ob, mtx, lamp, world):
                safeName = self.cleanStr(ob.name)
                if world:
-                       ambi = world.amb
+                       ambi = world.ambient_color
+                       # ambi = world.amb
                        ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
                else:
                        ambi = 0
@@ -295,14 +319,16 @@ class x3d_class:
                (dx,dy,dz)=self.computeDirection(mtx)
                self.file.write("<DirectionalLight DEF=\"%s\" " % safeName)
                self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp)))
-               self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp)))
+               self.file.write("color=\"%s %s %s\" " % (round(lamp.color[0],self.cp), round(lamp.color[1],self.cp), round(lamp.color[2],self.cp)))
+               # self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp)))
                self.file.write("intensity=\"%s\" " % (round(intensity,self.cp)))
                self.file.write("direction=\"%s %s %s\" />\n\n" % (round(dx,4),round(dy,4),round(dz,4)))
 
        def writePointLight(self, ob, mtx, lamp, world):
                safeName = self.cleanStr(ob.name)
                if world:
-                       ambi = world.amb
+                       ambi = world.ambient_color
+                       # ambi = world.amb
                        ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
                else:
                        ambi = 0
@@ -313,9 +339,11 @@ class x3d_class:
                
                self.file.write("<PointLight DEF=\"%s\" " % safeName)
                self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp)))
-               self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp)))
+               self.file.write("color=\"%s %s %s\" " % (round(lamp.color[0],self.cp), round(lamp.color[1],self.cp), round(lamp.color[2],self.cp)))
+               # self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp)))
                self.file.write("intensity=\"%s\" " % (round( min(lamp.energy/1.75,1.0) ,self.cp)))
-               self.file.write("radius=\"%s\" " % lamp.dist )
+               self.file.write("radius=\"%s\" " % lamp.distance )
+               # self.file.write("radius=\"%s\" " % lamp.dist )
                self.file.write("location=\"%s %s %s\" />\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3)))
        '''
        def writeNode(self, ob, mtx):
@@ -357,24 +385,41 @@ class x3d_class:
                vColors={}      # 'multi':1
                meshName = self.cleanStr(ob.name)
                
-               meshME = self.cleanStr(ob.getData(mesh=1).name) # We dont care if its the mesh name or not
+               meshME = self.cleanStr(ob.data.name) # We dont care if its the mesh name or not
+               # meshME = self.cleanStr(ob.getData(mesh=1).name) # We dont care if its the mesh name or not
                if len(mesh.faces) == 0: return
-               mode = 0
-               if mesh.faceUV:
-                       for face in mesh.faces:
-                               mode |= face.mode 
+               mode = []
+               # mode = 0
+               if mesh.active_uv_texture:
+               # if mesh.faceUV:
+                       for face in mesh.active_uv_texture.data:
+                       # for face in mesh.faces:
+                               if face.halo and 'HALO' not in mode:
+                                       mode += ['HALO']
+                               if face.billboard and 'BILLBOARD' not in mode:
+                                       mode += ['BILLBOARD']
+                               if face.object_color and 'OBJECT_COLOR' not in mode:
+                                       mode += ['OBJECT_COLOR']
+                               if face.collision and 'COLLISION' not in mode:
+                                       mode += ['COLLISION']
+                               # mode |= face.mode 
                
-               if mode & Mesh.FaceModes.HALO and self.halonode == 0:
+               if 'HALO' in mode and self.halonode == 0:
+               # if mode & Mesh.FaceModes.HALO and self.halonode == 0:
                        self.writeIndented("<Billboard axisOfRotation=\"0 0 0\">\n",1)
                        self.halonode = 1
-               elif mode & Mesh.FaceModes.BILLBOARD and self.billnode == 0:
+               elif 'BILLBOARD' in mode and self.billnode == 0:
+               # elif mode & Mesh.FaceModes.BILLBOARD and self.billnode == 0:
                        self.writeIndented("<Billboard axisOfRotation=\"0 1 0\">\n",1)
                        self.billnode = 1
-               elif mode & Mesh.FaceModes.OBCOL and self.matonly == 0:
+               elif 'OBJECT_COLOR' in mode and self.matonly == 0:
+               # elif mode & Mesh.FaceModes.OBCOL and self.matonly == 0:
                        self.matonly = 1
-               elif mode & Mesh.FaceModes.TILES and self.tilenode == 0:
-                       self.tilenode = 1
-               elif not mode & Mesh.FaceModes.DYNAMIC and self.collnode == 0:
+               # TF_TILES is marked as deprecated in DNA_meshdata_types.h
+               # elif mode & Mesh.FaceModes.TILES and self.tilenode == 0:
+               #       self.tilenode = 1
+               elif 'COLLISION' not in mode and self.collnode == 0:
+               # elif not mode & Mesh.FaceModes.DYNAMIC and self.collnode == 0:
                        self.writeIndented("<Collision enabled=\"false\">\n",1)
                        self.collnode = 1
                
@@ -383,7 +428,7 @@ class x3d_class:
                if nIFSCnt > 1:
                        self.writeIndented("<Group DEF=\"%s%s\">\n" % ("G_", meshName),1)
                
-               if sided.has_key('two') and sided['two'] > 0:
+               if 'two' in sided and sided['two'] > 0:
                        bTwoSided=1
                else:
                        bTwoSided=0
@@ -396,34 +441,44 @@ class x3d_class:
                quat = mtx.toQuat()
                rot= quat.axis
 
-               # self.writeIndented('<Transform rotation="%.6f %.6f %.6f %.6f">\n' % (rot[0], rot[1], rot[2], rot[3]))
                self.writeIndented('<Transform DEF="%s" translation="%.6f %.6f %.6f" scale="%.6f %.6f %.6f" rotation="%.6f %.6f %.6f %.6f">\n' % \
-                 (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle*DEG2RAD) )
+                                                  (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle) )
+               # self.writeIndented('<Transform DEF="%s" translation="%.6f %.6f %.6f" scale="%.6f %.6f %.6f" rotation="%.6f %.6f %.6f %.6f">\n' % \
+               #   (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle*DEG2RAD) )
 
                self.writeIndented("<Shape>\n",1)
                maters=mesh.materials
                hasImageTexture=0
                issmooth=0
 
-               if len(maters) > 0 or mesh.faceUV:
+               if len(maters) > 0 or mesh.active_uv_texture:
+               # if len(maters) > 0 or mesh.faceUV:
                        self.writeIndented("<Appearance>\n", 1)
                        # right now this script can only handle a single material per mesh.
                        if len(maters) >= 1:
                                mat=maters[0]
-                               matFlags = mat.getMode()
-                               if not matFlags & Blender.Material.Modes['TEXFACE']:
-                                       self.writeMaterial(mat, self.cleanStr(maters[0].name,''), world)
+                               # matFlags = mat.getMode()
+                               if not mat.face_texture:
+                               # if not matFlags & Blender.Material.Modes['TEXFACE']:
+                                       self.writeMaterial(mat, self.cleanStr(mat.name,''), world)
+                                       # self.writeMaterial(mat, self.cleanStr(maters[0].name,''), world)
                                        if len(maters) > 1:
-                                               print "Warning: mesh named %s has multiple materials" % meshName
-                                               print "Warning: only one material per object handled"
+                                               print("Warning: mesh named %s has multiple materials" % meshName)
+                                               print("Warning: only one material per object handled")
                        
                                #-- textures
-                               if mesh.faceUV:
-                                       for face in mesh.faces:
-                                               if (hasImageTexture == 0) and (face.image):
+                               face = None
+                               if mesh.active_uv_texture:
+                               # if mesh.faceUV:
+                                       for face in mesh.active_uv_texture.data:
+                                       # for face in mesh.faces:
+                                               if face.image:
+                                               # if (hasImageTexture == 0) and (face.image):
                                                        self.writeImageTexture(face.image)
-                                                       hasImageTexture=1  # keep track of face texture
-                               if self.tilenode == 1:
+                                                       # hasImageTexture=1  # keep track of face texture
+                                                       break
+                               if self.tilenode == 1 and face and face.image:
+                               # if self.tilenode == 1:
                                        self.writeIndented("<TextureTransform   scale=\"%s %s\" />\n" % (face.image.xrep, face.image.yrep))
                                        self.tilenode = 0
                                self.writeIndented("</Appearance>\n", -1)
@@ -433,7 +488,7 @@ class x3d_class:
                # user selected BOUNDS=1, SOLID=3, SHARED=4, or TEXTURE=5
                ifStyle="IndexedFaceSet"
                # look up mesh name, use it if available
-               if self.meshNames.has_key(meshME):
+               if meshME in self.meshNames:
                        self.writeIndented("<%s USE=\"ME_%s\">" % (ifStyle, meshME), 1)
                        self.meshNames[meshME]+=1
                else:
@@ -453,11 +508,13 @@ class x3d_class:
                                         issmooth=1
                                         break
                        if issmooth==1:
-                               creaseAngle=(mesh.degr)*(math.pi/180.0)
+                               creaseAngle=(mesh.autosmooth_angle)*(math.pi/180.0)
+                               # creaseAngle=(mesh.degr)*(math.pi/180.0)
                                self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp)))
 
                        #--- output textureCoordinates if UV texture used
-                       if mesh.faceUV:
+                       if mesh.active_uv_texture:
+                       # if mesh.faceUV:
                                if self.matonly == 1 and self.share == 1:
                                        self.writeFaceColors(mesh)
                                elif hasImageTexture == 1:
@@ -471,7 +528,8 @@ class x3d_class:
                        self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI)
                        
                        #--- output textureCoordinates if UV texture used
-                       if mesh.faceUV:
+                       if mesh.active_uv_texture:
+                       # if mesh.faceUV:
                                if hasImageTexture == 1:
                                        self.writeTextureCoordinates(mesh)
                                elif self.matonly == 1 and self.share == 1:
@@ -511,16 +569,22 @@ class x3d_class:
                if self.writingcoords == 0:
                        self.file.write('coordIndex="')
                        for face in mesh.faces:
-                               fv = face.v
+                               fv = face.verts
+                               # fv = face.v
                                
-                               if len(face)==3:
-                                               self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index))
+                               if len(fv)==3:
+                               # if len(face)==3:
+                                       self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2]))
+                                       # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index))
                                else:
                                        if EXPORT_TRI:
-                                               self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index))
-                                               self.file.write("%i %i %i -1, " % (fv[0].index, fv[2].index, fv[3].index))
+                                               self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2]))
+                                               # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index))
+                                               self.file.write("%i %i %i -1, " % (fv[0], fv[2], fv[3]))
+                                               # self.file.write("%i %i %i -1, " % (fv[0].index, fv[2].index, fv[3].index))
                                        else:
-                                               self.file.write("%i %i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index, fv[3].index))
+                                               self.file.write("%i %i %i %i -1, " % (fv[0], fv[1], fv[2], fv[3]))
+                                               # self.file.write("%i %i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index, fv[3].index))
                        
                        self.file.write("\">\n")
                else:
@@ -538,8 +602,13 @@ class x3d_class:
                texIndexList=[]
                j=0
 
-               for face in mesh.faces:
-                       for uv in face.uv:
+               for face in mesh.active_uv_texture.data:
+               # for face in mesh.faces:
+                       uvs = face.uv
+                       # uvs = [face.uv1, face.uv2, face.uv3, face.uv4] if face.verts[3] else [face.uv1, face.uv2, face.uv3]
+
+                       for uv in uvs:
+                       # for uv in face.uv:
                                texIndexList.append(j)
                                texCoordList.append(uv)
                                j=j+1
@@ -547,7 +616,7 @@ class x3d_class:
                if self.writingtexture == 0:
                        self.file.write("\n\t\t\ttexCoordIndex=\"")
                        texIndxStr=""
-                       for i in xrange(len(texIndexList)):
+                       for i in range(len(texIndexList)):
                                texIndxStr = texIndxStr + "%d, " % texIndexList[i]
                                if texIndexList[i]==-1:
                                        self.file.write(texIndxStr)
@@ -555,7 +624,7 @@ class x3d_class:
                        self.file.write("\"\n\t\t\t")
                else:
                        self.writeIndented("<TextureCoordinate point=\"", 1)
-                       for i in xrange(len(texCoordList)):
+                       for i in range(len(texCoordList)):
                                self.file.write("%s %s, " % (round(texCoordList[i][0],self.tp), round(texCoordList[i][1],self.tp)))
                        self.file.write("\" />")
                        self.writeIndented("\n", -1)
@@ -563,43 +632,61 @@ class x3d_class:
        def writeFaceColors(self, mesh):
                if self.writingcolor == 0:
                        self.file.write("colorPerVertex=\"false\" ")
-               else:
+               elif mesh.active_vertex_color:
+               # else:
                        self.writeIndented("<Color color=\"", 1)
-                       for face in mesh.faces:
-                               if face.col:
-                                       c=face.col[0]
-                                       if self.verbose > 2:
-                                               print "Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b)
-                                       aColor = self.rgbToFS(c)
-                                       self.file.write("%s, " % aColor)
+                       for face in mesh.active_vertex_color.data:
+                               c = face.color1
+                               if self.verbose > 2:
+                                       print("Debug: face.col r=%d g=%d b=%d" % (c[0], c[1], c[2]))
+                                       # print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b))
+                               aColor = self.rgbToFS(c)
+                               self.file.write("%s, " % aColor)
+
+                       # for face in mesh.faces:
+                       #       if face.col:
+                       #               c=face.col[0]
+                       #               if self.verbose > 2:
+                       #                       print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b))
+                       #               aColor = self.rgbToFS(c)
+                       #               self.file.write("%s, " % aColor)
                        self.file.write("\" />")
                        self.writeIndented("\n",-1)
        
        def writeMaterial(self, mat, matName, world):
                # look up material name, use it if available
-               if self.matNames.has_key(matName):
+               if matName in self.matNames:
                        self.writeIndented("<Material USE=\"MA_%s\" />\n" % matName)
                        self.matNames[matName]+=1
                        return;
 
                self.matNames[matName]=1
 
-               ambient = mat.amb/3
-               diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2]
+               ambient = mat.ambient/3
+               # ambient = mat.amb/3
+               diffuseR, diffuseG, diffuseB = tuple(mat.diffuse_color)
+               # diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2]
                if world:
-                       ambi = world.getAmb()
-                       ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2
+                       ambi = world.ambient_color
+                       # ambi = world.getAmb()
+                       ambi0, ambi1, ambi2 = (ambi[0]*mat.ambient)*2, (ambi[1]*mat.ambient)*2, (ambi[2]*mat.ambient)*2
+                       # ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2
                else:
                        ambi0, ambi1, ambi2 = 0, 0, 0
                emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/2, (diffuseG*mat.emit+ambi1)/2, (diffuseB*mat.emit+ambi2)/2
 
-               shininess = mat.hard/512.0
-               specR = (mat.specCol[0]+0.001)/(1.25/(mat.spec+0.001))
-               specG = (mat.specCol[1]+0.001)/(1.25/(mat.spec+0.001))
-               specB = (mat.specCol[2]+0.001)/(1.25/(mat.spec+0.001))
+               shininess = mat.specular_hardness/512.0
+               # shininess = mat.hard/512.0
+               specR = (mat.specular_color[0]+0.001)/(1.25/(mat.specular_intensity+0.001))
+               # specR = (mat.specCol[0]+0.001)/(1.25/(mat.spec+0.001))
+               specG = (mat.specular_color[1]+0.001)/(1.25/(mat.specular_intensity+0.001))
+               # specG = (mat.specCol[1]+0.001)/(1.25/(mat.spec+0.001))
+               specB = (mat.specular_color[2]+0.001)/(1.25/(mat.specular_intensity+0.001))
+               # specB = (mat.specCol[2]+0.001)/(1.25/(mat.spec+0.001))
                transp = 1-mat.alpha
-               matFlags = mat.getMode()
-               if matFlags & Blender.Material.Modes['SHADELESS']:
+               # matFlags = mat.getMode()
+               if mat.shadeless:
+               # if matFlags & Blender.Material.Modes['SHADELESS']:
                  ambient = 1
                  shine = 1
                  specR = emitR = diffuseR
@@ -617,7 +704,7 @@ class x3d_class:
        def writeImageTexture(self, image):
                name = image.name
                filename = image.filename.split('/')[-1].split('\\')[-1]
-               if self.texNames.has_key(name):
+               if name in self.texNames:
                        self.writeIndented("<ImageTexture USE=\"%s\" />\n" % self.cleanStr(name))
                        self.texNames[name] += 1
                        return
@@ -630,10 +717,13 @@ class x3d_class:
        def writeBackground(self, world, alltextures):
                if world:       worldname = world.name
                else:           return
-               blending = world.getSkytype()   
-               grd = world.getHor()
+               blending = (world.blend_sky, world.paper_sky, world.real_sky)
+               # blending = world.getSkytype() 
+               grd = world.horizon_color
+               # grd = world.getHor()
                grd0, grd1, grd2 = grd[0], grd[1], grd[2]
-               sky = world.getZen()
+               sky = world.zenith_color
+               # sky = world.getZen()
                sky0, sky1, sky2 = sky[0], sky[1], sky[2]
                mix0, mix1, mix2 = grd[0]+sky[0], grd[1]+sky[1], grd[2]+sky[2]
                mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2
@@ -641,27 +731,32 @@ class x3d_class:
                if worldname not in self.namesStandard:
                        self.file.write("DEF=\"%s\" " % self.secureName(worldname))
                # No Skytype - just Hor color
-               if blending == 0:
+               if blending == (0, 0, 0):
+               # if blending == 0:
                        self.file.write("groundColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
                        self.file.write("skyColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
                # Blend Gradient
-               elif blending == 1:
+               elif blending == (1, 0, 0):
+               # elif blending == 1:
                        self.file.write("groundColor=\"%s %s %s, " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
                        self.file.write("%s %s %s\" groundAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp)))
                        self.file.write("skyColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
                        self.file.write("%s %s %s\" skyAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp)))
                # Blend+Real Gradient Inverse
-               elif blending == 3:
+               elif blending == (1, 0, 1):
+               # elif blending == 3:
                        self.file.write("groundColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
                        self.file.write("%s %s %s\" groundAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp)))
                        self.file.write("skyColor=\"%s %s %s, " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
                        self.file.write("%s %s %s\" skyAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp)))
                # Paper - just Zen Color
-               elif blending == 4:
+               elif blending == (0, 0, 1):
+               # elif blending == 4:
                        self.file.write("groundColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
                        self.file.write("skyColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
                # Blend+Real+Paper - komplex gradient
-               elif blending == 7:
+               elif blending == (1, 1, 1):
+               # elif blending == 7:
                        self.writeIndented("groundColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
                        self.writeIndented("%s %s %s\" groundAngle=\"1.57, 1.57\" " %(round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
                        self.writeIndented("skyColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
@@ -670,22 +765,43 @@ class x3d_class:
                else:
                        self.file.write("groundColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
                        self.file.write("skyColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
+
                alltexture = len(alltextures)
-               for i in xrange(alltexture):
-                       namemat = alltextures[i].name
-                       pic = alltextures[i].getImage()
+
+               for i in range(alltexture):
+                       tex = alltextures[i]
+
+                       if tex.type != 'IMAGE' or tex.image == None:
+                               continue
+
+                       namemat = tex.name
+                       # namemat = alltextures[i].name
+
+                       pic = tex.image
+
+                       # using .expandpath just in case, os.path may not expect //
+                       basename = os.path.basename(pic.get_abs_filename())
+
+                       pic = alltextures[i].image
+                       # pic = alltextures[i].getImage()
                        if (namemat == "back") and (pic != None):
-                               self.file.write("\n\tbackUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+                               self.file.write("\n\tbackUrl=\"%s\" " % basename)
+                               # self.file.write("\n\tbackUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
                        elif (namemat == "bottom") and (pic != None):
-                               self.writeIndented("bottomUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+                               self.writeIndented("bottomUrl=\"%s\" " % basename)
+                               # self.writeIndented("bottomUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
                        elif (namemat == "front") and (pic != None):
-                               self.writeIndented("frontUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+                               self.writeIndented("frontUrl=\"%s\" " % basename)
+                               # self.writeIndented("frontUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
                        elif (namemat == "left") and (pic != None):
-                               self.writeIndented("leftUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+                               self.writeIndented("leftUrl=\"%s\" " % basename)
+                               # self.writeIndented("leftUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
                        elif (namemat == "right") and (pic != None):
-                               self.writeIndented("rightUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+                               self.writeIndented("rightUrl=\"%s\" " % basename)
+                               # self.writeIndented("rightUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
                        elif (namemat == "top") and (pic != None):
-                               self.writeIndented("topUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+                               self.writeIndented("topUrl=\"%s\" " % basename)
+                               # self.writeIndented("topUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
                self.writeIndented("/>\n\n")
 
 ##########################################################
@@ -697,7 +813,7 @@ class x3d_class:
                        EXPORT_TRI=                             False,\
                ):
                
-               print "Info: starting X3D export to " + self.filename + "..."
+               print("Info: starting X3D export to " + self.filename + "...")
                self.writeHeader()
                # self.writeScript()
                self.writeNavigationInfo(scene)
@@ -706,44 +822,65 @@ class x3d_class:
                self.proto = 0
                
                
-               # COPIED FROM OBJ EXPORTER
-               if EXPORT_APPLY_MODIFIERS:
-                       temp_mesh_name = '~tmp-mesh'
+               # COPIED FROM OBJ EXPORTER
+               if EXPORT_APPLY_MODIFIERS:
+               #       temp_mesh_name = '~tmp-mesh'
                
-                       # Get the container mesh. - used for applying modifiers and non mesh objects.
-                       containerMesh = meshName = tempMesh = None
-                       for meshName in Blender.NMesh.GetNames():
-                               if meshName.startswith(temp_mesh_name):
-                                       tempMesh = Mesh.Get(meshName)
-                                       if not tempMesh.users:
-                                               containerMesh = tempMesh
-                       if not containerMesh:
-                               containerMesh = Mesh.New(temp_mesh_name)
+               #       # Get the container mesh. - used for applying modifiers and non mesh objects.
+               #       containerMesh = meshName = tempMesh = None
+               #       for meshName in Blender.NMesh.GetNames():
+               #               if meshName.startswith(temp_mesh_name):
+               #                       tempMesh = Mesh.Get(meshName)
+               #                       if not tempMesh.users:
+               #                               containerMesh = tempMesh
+               #       if not containerMesh:
+               #               containerMesh = Mesh.New(temp_mesh_name)
                # -------------------------- 
                
                
-               for ob_main in scene.objects.context:
-                       for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
+               for ob_main in [o for o in scene.objects if o.is_visible()]:
+               # for ob_main in scene.objects.context:
+
+                       free, derived = create_derived_objects(ob_main)
+
+                       if derived == None: continue
+
+                       for ob, ob_mat in derived:
+                       # for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
                                objType=ob.type
                                objName=ob.name
                                self.matonly = 0
-                               if objType == "Camera":
+                               if objType == "CAMERA":
+                               # if objType == "Camera":
                                        self.writeViewpoint(ob, ob_mat, scene)
-                               elif objType in ("Mesh", "Curve", "Surf", "Text") :
-                                       if  EXPORT_APPLY_MODIFIERS or objType != 'Mesh':
-                                               me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene)
+                               elif objType in ("MESH", "CURVE", "SURF", "TEXT") :
+                               # elif objType in ("Mesh", "Curve", "Surf", "Text") :                           
+                                       if EXPORT_APPLY_MODIFIERS or objType != 'MESH':
+                                       # if  EXPORT_APPLY_MODIFIERS or objType != 'Mesh':
+                                               me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW')
+                                               # me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene)
                                        else:
-                                               me = ob.getData(mesh=1)
+                                               me = ob.data
+                                               # me = ob.getData(mesh=1)
                                        
                                        self.writeIndexedFaceSet(ob, me, ob_mat, world, EXPORT_TRI = EXPORT_TRI)
-                               elif objType == "Lamp":
+
+                                       # free mesh created with create_mesh()
+                                       if me != ob.data:
+                                               bpy.data.remove_mesh(me)
+
+                               elif objType == "LAMP":
+                               # elif objType == "Lamp":
                                        data= ob.data
                                        datatype=data.type
-                                       if datatype == Lamp.Types.Lamp:
+                                       if datatype == 'POINT':
+                                       # if datatype == Lamp.Types.Lamp:
                                                self.writePointLight(ob, ob_mat, data, world)
-                                       elif datatype == Lamp.Types.Spot:
+                                       elif datatype == 'SPOT':
+                                       # elif datatype == Lamp.Types.Spot:
                                                self.writeSpotLight(ob, ob_mat, data, world)
-                                       elif datatype == Lamp.Types.Sun:
+                                       elif datatype == 'SUN':
+                                       # elif datatype == Lamp.Types.Sun:
                                                self.writeDirectionalLight(ob, ob_mat, data, world)
                                        else:
                                                self.writeDirectionalLight(ob, ob_mat, data, world)
@@ -753,12 +890,15 @@ class x3d_class:
                                else:
                                        #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType)
                                        pass
-               
+                               
+                       if free:
+                               free_derived_objects(ob_main)
+                       
                self.file.write("\n</Scene>\n</X3D>")
                
-               if EXPORT_APPLY_MODIFIERS:
-                       if containerMesh:
-                               containerMesh.verts = None
+               if EXPORT_APPLY_MODIFIERS:
+               #       if containerMesh:
+               #               containerMesh.verts = None
                
                self.cleanup()
                
@@ -771,7 +911,7 @@ class x3d_class:
                self.texNames={}
                self.matNames={}
                self.indentLevel=0
-               print "Info: finished X3D export to %s\n" % self.filename
+               print("Info: finished X3D export to %s\n" % self.filename)
 
        def cleanStr(self, name, prefix='rsvd_'):
                """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name"""
@@ -807,15 +947,18 @@ class x3d_class:
                faceMap={}
                nFaceIndx=0
                
-               if mesh.faceUV:
-                       for face in mesh.faces:
+               if mesh.active_uv_texture:
+               # if mesh.faceUV:
+                       for face in mesh.active_uv_texture.data:
+                       # for face in mesh.faces:
                                sidename='';
-                               if  face.mode & Mesh.FaceModes.TWOSIDE:
+                               if face.twoside:
+                               # if  face.mode & Mesh.FaceModes.TWOSIDE:
                                        sidename='two'
                                else:
                                        sidename='one'
                                
-                               if sided.has_key(sidename):
+                               if sidename in sided:
                                        sided[sidename]+=1
                                else:
                                        sided[sidename]=1
@@ -829,56 +972,63 @@ class x3d_class:
                                                imageMap[faceName]=[face.image.name,sidename,face]
 
                        if self.verbose > 2:
-                               for faceName in imageMap.iterkeys():
+                               for faceName in imageMap.keys():
                                        ifs=imageMap[faceName]
-                                       print "Debug: faceName=%s image=%s, solid=%s facecnt=%d" % \
-                                                 (faceName, ifs[0], ifs[1], len(ifs)-2)
+                                       print("Debug: faceName=%s image=%s, solid=%s facecnt=%d" % \
+                                                 (faceName, ifs[0], ifs[1], len(ifs)-2))
 
                return len(imageMap)
        
        def faceToString(self,face):
 
-               print "Debug: face.flag=0x%x (bitflags)" % face.flag
+               print