Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2009-09-29 19:27:00 +0400
committerCampbell Barton <ideasman42@gmail.com>2009-09-29 19:27:00 +0400
commit7f5dc4644f72ffb56d23db79cc3208dbca2d5eab (patch)
tree587310833d8914a73cc27bb290f03233193d9567
parentf93ca02443645ad571081c3f02c970abbc05095e (diff)
adding back changes from soc-2009-kaz branch.
-rw-r--r--release/scripts/io/export_3ds.py323
-rw-r--r--release/scripts/io/export_fbx.py967
-rw-r--r--release/scripts/io/export_obj.py959
-rw-r--r--release/scripts/io/export_ply.py231
-rw-r--r--release/scripts/io/export_x3d.py553
-rw-r--r--release/scripts/io/import_3ds.py1068
-rw-r--r--release/scripts/io/import_obj.py752
7 files changed, 3100 insertions, 1753 deletions
diff --git a/release/scripts/io/export_3ds.py b/release/scripts/io/export_3ds.py
index 87680bce1b0..2c1999c3d45 100644
--- a/release/scripts/io/export_3ds.py
+++ b/release/scripts/io/export_3ds.py
@@ -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)
diff --git a/release/scripts/io/export_fbx.py b/release/scripts/io/export_fbx.py
index 50357cbfa75..21b1388ebfe 100644
--- a/release/scripts/io/export_fbx.py
+++ b/release/scripts/io/export_fbx.py
@@ -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')
diff --git a/release/scripts/io/export_obj.py b/release/scripts/io/export_obj.py
index 7dffb5d2048..83b400816e3 100644
--- a/release/scripts/io/export_obj.py
+++ b/release/scripts/io/export_obj.py
@@ -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
diff --git a/release/scripts/io/export_ply.py b/release/scripts/io/export_ply.py
index 46d08050302..8e79c3741bb 100644
--- a/release/scripts/io/export_ply.py
+++ b/release/scripts/io/export_ply.py
@@ -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()
diff --git a/release/scripts/io/export_x3d.py b/release/scripts/io/export_x3d.py
index b12ff67d8a6..db29afc7d6d 100644
--- a/release/scripts/io/export_x3d.py
+++ b/release/scripts/io/export_x3d.py
@@ -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("Debug: face.flag=0x%x (bitflags)" % face.flag)
if face.sel:
- print "Debug: face.sel=true"
+ print("Debug: face.sel=true")
- print "Debug: face.mode=0x%x (bitflags)" % face.mode
+ print("Debug: face.mode=0x%x (bitflags)" % face.mode)
if face.mode & Mesh.FaceModes.TWOSIDE:
- print "Debug: face.mode twosided"
+ print("Debug: face.mode twosided")
- print "Debug: face.transp=0x%x (enum)" % face.transp
+ print("Debug: face.transp=0x%x (enum)" % face.transp)
if face.transp == Mesh.FaceTranspModes.SOLID:
- print "Debug: face.transp.SOLID"
+ print("Debug: face.transp.SOLID")
if face.image:
- print "Debug: face.image=%s" % face.image.name
- print "Debug: face.materialIndex=%d" % face.materialIndex
-
- def getVertexColorByIndx(self, mesh, indx):
- c = None
- for face in mesh.faces:
- j=0
- for vertex in face.v:
- if vertex.index == indx:
- c=face.col[j]
- break
- j=j+1
- if c: break
- return c
+ print("Debug: face.image=%s" % face.image.name)
+ print("Debug: face.materialIndex=%d" % face.materialIndex)
+
+ # XXX not used
+ # def getVertexColorByIndx(self, mesh, indx):
+ # c = None
+ # for face in mesh.faces:
+ # j=0
+ # for vertex in face.v:
+ # if vertex.index == indx:
+ # c=face.col[j]
+ # break
+ # j=j+1
+ # if c: break
+ # return c
def meshToString(self,mesh):
- print "Debug: mesh.hasVertexUV=%d" % mesh.vertexColors
- print "Debug: mesh.faceUV=%d" % mesh.faceUV
- print "Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours()
- print "Debug: mesh.verts=%d" % len(mesh.verts)
- print "Debug: mesh.faces=%d" % len(mesh.faces)
- print "Debug: mesh.materials=%d" % len(mesh.materials)
+ # print("Debug: mesh.hasVertexUV=%d" % mesh.vertexColors)
+ print("Debug: mesh.faceUV=%d" % (len(mesh.uv_textures) > 0))
+ # print("Debug: mesh.faceUV=%d" % mesh.faceUV)
+ print("Debug: mesh.hasVertexColours=%d" % (len(mesh.vertex_colors) > 0))
+ # print("Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours())
+ print("Debug: mesh.verts=%d" % len(mesh.verts))
+ print("Debug: mesh.faces=%d" % len(mesh.faces))
+ print("Debug: mesh.materials=%d" % len(mesh.materials))
def rgbToFS(self, c):
- s="%s %s %s" % (
- round(c.r/255.0,self.cp),
- round(c.g/255.0,self.cp),
- round(c.b/255.0,self.cp))
+ s="%s %s %s" % (round(c[0]/255.0,self.cp),
+ round(c[1]/255.0,self.cp),
+ round(c[2]/255.0,self.cp))
+
+ # s="%s %s %s" % (
+ # round(c.r/255.0,self.cp),
+ # round(c.g/255.0,self.cp),
+ # round(c.b/255.0,self.cp))
return s
def computeDirection(self, mtx):
@@ -886,9 +1036,10 @@ class x3d_class:
ax,ay,az = (mtx*MATWORLD).toEuler()
- ax *= DEG2RAD
- ay *= DEG2RAD
- az *= DEG2RAD
+ # ax *= DEG2RAD
+ # ay *= DEG2RAD
+ # az *= DEG2RAD
+
# rot X
x1=x
y1=y*math.cos(ax)-z*math.sin(ax)
@@ -924,7 +1075,7 @@ class x3d_class:
self.indentLevel = self.indentLevel + inc
spaces=""
- for x in xrange(self.indentLevel):
+ for x in range(self.indentLevel):
spaces = spaces + "\t"
self.file.write(spaces + s)
@@ -975,11 +1126,11 @@ class x3d_class:
# Callbacks, needed before Main
##########################################################
-def x3d_export(filename, \
- EXPORT_APPLY_MODIFIERS= False,\
- EXPORT_TRI= False,\
- EXPORT_GZIP= False,\
- ):
+def x3d_export(filename,
+ context,
+ EXPORT_APPLY_MODIFIERS=False,
+ EXPORT_TRI=False,
+ EXPORT_GZIP=False):
if EXPORT_GZIP:
if not filename.lower().endswith('.x3dz'):
@@ -989,9 +1140,13 @@ def x3d_export(filename, \
filename = '.'.join(filename.split('.')[:-1]) + '.x3d'
- scene = Blender.Scene.GetCurrent()
+ scene = context.scene
+ # scene = Blender.Scene.GetCurrent()
world = scene.world
- alltextures = Blender.Texture.Get()
+
+ # XXX these are global textures while .Get() returned only scene's?
+ alltextures = bpy.data.textures
+ # alltextures = Blender.Texture.Get()
wrlexport=x3d_class(filename)
wrlexport.export(\
@@ -1045,7 +1200,41 @@ def x3d_export_ui(filename):
#########################################################
-if __name__ == '__main__':
- Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d'))
+# if __name__ == '__main__':
+# Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d'))
+
+class EXPORT_OT_x3d(bpy.types.Operator):
+ '''
+ X3D Exporter
+ '''
+ __idname__ = "export.x3d"
+ __label__ = 'Export X3D'
+
+ # 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 X3D file", maxlen= 1024, default= ""),
+
+ bpy.props.BoolProperty(attr="apply_modifiers", name="Apply Modifiers", description="Use transformed mesh data from each object.", default=True),
+ bpy.props.BoolProperty(attr="triangulate", name="Triangulate", description="Triangulate quads.", default=False),
+ bpy.props.BoolProperty(attr="compress", name="Compress", description="GZip the resulting file, requires a full python install.", default=False),
+ ]
+
+ def execute(self, context):
+ x3d_export(self.path, context, self.apply_modifiers, self.triangulate, self.compress)
+ 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_x3d)
+# NOTES
+# - blender version is hardcoded
diff --git a/release/scripts/io/import_3ds.py b/release/scripts/io/import_3ds.py
index bcde82c4869..339fac839ea 100644
--- a/release/scripts/io/import_3ds.py
+++ b/release/scripts/io/import_3ds.py
@@ -125,28 +125,36 @@ Loader is based on 3ds loader from www.gametutorials.com (Thanks DigiBen).
# Importing modules
-import Blender
+import os
+import time
+import struct
+
+from import_obj import unpack_face_list, load_image
+
import bpy
-from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils
-from Blender.Mathutils import Vector
-import BPyImage
+import Mathutils
+
+# import Blender
+# from Blender import Mesh, Object, Material, Image, Texture, Lamp, Mathutils
+# from Blender.Mathutils import Vector
+# import BPyImage
-import BPyMessages
+# import BPyMessages
-try:
- from struct import calcsize, unpack
-except:
- calcsize= unpack= None
+# try:
+# from struct import calcsize, unpack
+# except:
+# calcsize= unpack= None
-# If python version is less than 2.4, try to get set stuff from module
-try:
- set
-except:
- from sets import Set as set
+# # If python version is less than 2.4, try to get set stuff from module
+# try:
+# set
+# except:
+# from sets import Set as set
-BOUNDS_3DS= []
+BOUNDS_3DS = []
#this script imports uvcoords as sticky vertex coords
@@ -154,9 +162,9 @@ BOUNDS_3DS= []
#which shold be more useful.
def createBlenderTexture(material, name, image):
- texture= bpy.data.textures.new(name)
+ texture = bpy.data.textures.new(name)
texture.setType('Image')
- texture.image= image
+ texture.image = image
material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL)
@@ -167,189 +175,201 @@ def createBlenderTexture(material, name, image):
#Some of the chunks that we will see
#----- 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
-EDITKEYFRAME= 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
+EDITKEYFRAME= 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...
+MATERIAL = 45055 #0xAFFF // This stored the texture info
+OBJECT = 16384 #0x4000 // This stores the faces, vertices, etc...
#>------ sub defines of MATERIAL
#------ sub defines of MATERIAL_BLOCK
-MAT_NAME = long('0xA000',16) # This holds the material name
-MAT_AMBIENT = long('0xA010',16) # Ambient color of the object/material
-MAT_DIFFUSE = long('0xA020',16) # This holds the color of the object/material
-MAT_SPECULAR = long('0xA030',16) # SPecular color of the object/material
-MAT_SHINESS = long('0xA040',16) # ??
-MAT_TRANSPARENCY= long('0xA050',16) # Transparency value of material
-MAT_SELF_ILLUM = long('0xA080',16) # Self Illumination value of material
-MAT_WIRE = long('0xA085',16) # Only render's wireframe
-
-MAT_TEXTURE_MAP = long('0xA200',16) # This is a header for a new texture map
-MAT_SPECULAR_MAP= long('0xA204',16) # This is a header for a new specular map
-MAT_OPACITY_MAP = long('0xA210',16) # This is a header for a new opacity map
-MAT_REFLECTION_MAP= long('0xA220',16) # This is a header for a new reflection map
-MAT_BUMP_MAP = long('0xA230',16) # This is a header for a new bump map
-MAT_MAP_FILENAME = long('0xA300',16) # This holds the file name of the texture
-
-MAT_FLOAT_COLOR = long ('0x0010', 16) #color defined as 3 floats
-MAT_24BIT_COLOR = long ('0x0011', 16) #color defined as 3 bytes
+MAT_NAME = int('0xA000',16) # This holds the material name
+MAT_AMBIENT = int('0xA010',16) # Ambient color of the object/material
+MAT_DIFFUSE = int('0xA020',16) # This holds the color of the object/material
+MAT_SPECULAR = int('0xA030',16) # SPecular color of the object/material
+MAT_SHINESS = int('0xA040',16) # ??
+MAT_TRANSPARENCY= int('0xA050',16) # Transparency value of material
+MAT_SELF_ILLUM = int('0xA080',16) # Self Illumination value of material
+MAT_WIRE = int('0xA085',16) # Only render's wireframe
+
+MAT_TEXTURE_MAP = int('0xA200',16) # This is a header for a new texture map
+MAT_SPECULAR_MAP= int('0xA204',16) # This is a header for a new specular map
+MAT_OPACITY_MAP = int('0xA210',16) # This is a header for a new opacity map
+MAT_REFLECTION_MAP= int('0xA220',16) # This is a header for a new reflection map
+MAT_BUMP_MAP = int('0xA230',16) # This is a header for a new bump map
+MAT_MAP_FILENAME = int('0xA300',16) # This holds the file name of the texture
+
+MAT_FLOAT_COLOR = int ('0x0010', 16) #color defined as 3 floats
+MAT_24BIT_COLOR = int ('0x0011', 16) #color defined as 3 bytes
#>------ sub defines of OBJECT
-OBJECT_MESH = long('0x4100',16); # This lets us know that we are reading a new object
-OBJECT_LAMP = long('0x4600',16); # This lets un know we are reading a light object
-OBJECT_LAMP_SPOT = long('0x4610',16); # The light is a spotloght.
-OBJECT_LAMP_OFF = long('0x4620',16); # The light off.
-OBJECT_LAMP_ATTENUATE = long('0x4625',16);
-OBJECT_LAMP_RAYSHADE = long('0x4627',16);
-OBJECT_LAMP_SHADOWED = long('0x4630',16);
-OBJECT_LAMP_LOCAL_SHADOW = long('0x4640',16);
-OBJECT_LAMP_LOCAL_SHADOW2 = long('0x4641',16);
-OBJECT_LAMP_SEE_CONE = long('0x4650',16);
-OBJECT_LAMP_SPOT_RECTANGULAR= long('0x4651',16);
-OBJECT_LAMP_SPOT_OVERSHOOT= long('0x4652',16);
-OBJECT_LAMP_SPOT_PROJECTOR= long('0x4653',16);
-OBJECT_LAMP_EXCLUDE= long('0x4654',16);
-OBJECT_LAMP_RANGE= long('0x4655',16);
-OBJECT_LAMP_ROLL= long('0x4656',16);
-OBJECT_LAMP_SPOT_ASPECT= long('0x4657',16);
-OBJECT_LAMP_RAY_BIAS= long('0x4658',16);
-OBJECT_LAMP_INNER_RANGE= long('0x4659',16);
-OBJECT_LAMP_OUTER_RANGE= long('0x465A',16);
-OBJECT_LAMP_MULTIPLIER = long('0x465B',16);
-OBJECT_LAMP_AMBIENT_LIGHT = long('0x4680',16);
-
-
-
-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_LAMP = int('0x4600',16); # This lets un know we are reading a light object
+OBJECT_LAMP_SPOT = int('0x4610',16); # The light is a spotloght.
+OBJECT_LAMP_OFF = int('0x4620',16); # The light off.
+OBJECT_LAMP_ATTENUATE = int('0x4625',16);
+OBJECT_LAMP_RAYSHADE = int('0x4627',16);
+OBJECT_LAMP_SHADOWED = int('0x4630',16);
+OBJECT_LAMP_LOCAL_SHADOW = int('0x4640',16);
+OBJECT_LAMP_LOCAL_SHADOW2 = int('0x4641',16);
+OBJECT_LAMP_SEE_CONE = int('0x4650',16);
+OBJECT_LAMP_SPOT_RECTANGULAR = int('0x4651',16);
+OBJECT_LAMP_SPOT_OVERSHOOT = int('0x4652',16);
+OBJECT_LAMP_SPOT_PROJECTOR = int('0x4653',16);
+OBJECT_LAMP_EXCLUDE = int('0x4654',16);
+OBJECT_LAMP_RANGE = int('0x4655',16);
+OBJECT_LAMP_ROLL = int('0x4656',16);
+OBJECT_LAMP_SPOT_ASPECT = int('0x4657',16);
+OBJECT_LAMP_RAY_BIAS = int('0x4658',16);
+OBJECT_LAMP_INNER_RANGE = int('0x4659',16);
+OBJECT_LAMP_OUTER_RANGE = int('0x465A',16);
+OBJECT_LAMP_MULTIPLIER = int('0x465B',16);
+OBJECT_LAMP_AMBIENT_LIGHT = int('0x4680',16);
+
+
+
+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
global scn
-scn= None
+scn = None
#the chunk class
class chunk:
- ID=0
- length=0
- bytes_read=0
+ ID = 0
+ length = 0
+ bytes_read = 0
#we don't read in the bytes_read, we compute that
binary_format='<HI'
def __init__(self):
- self.ID=0
- self.length=0
- self.bytes_read=0
+ self.ID = 0
+ self.length = 0
+ self.bytes_read = 0
def dump(self):
- print 'ID: ', self.ID
- print 'ID in hex: ', hex(self.ID)
- print 'length: ', self.length
- print 'bytes_read: ', self.bytes_read
+ print('ID: ', self.ID)
+ print('ID in hex: ', hex(self.ID))
+ print('length: ', self.length)
+ print('bytes_read: ', self.bytes_read)
def read_chunk(file, chunk):
- temp_data=file.read(calcsize(chunk.binary_format))
- data=unpack(chunk.binary_format, temp_data)
- chunk.ID=data[0]
- chunk.length=data[1]
+ temp_data = file.read(struct.calcsize(chunk.binary_format))
+ data = struct.unpack(chunk.binary_format, temp_data)
+ chunk.ID = data[0]
+ chunk.length = data[1]
#update the bytes read function
- chunk.bytes_read=6
+ chunk.bytes_read = 6
#if debugging
#chunk.dump()
def read_string(file):
#read in the characters till we get a null character
- s=''
- while not s.endswith('\x00'):
- s+=unpack( '<c', file.read(1) )[0]
+ s = b''
+# s = ''
+ while not s.endswith(b'\x00'):
+# while not s.endswith('\x00'):
+ s += struct.unpack('<c', file.read(1))[0]
+# s += struct.unpack( '<c', file.read(1) )[0]
#print 'string: ',s
-
+
+ s = str(s[:-1], 'ASCII')
+# print("read string", s)
+
#remove the null character from the string
- return s[:-1]
+ return s
+# return s[:-1]
######################################################
# IMPORT
######################################################
def process_next_object_chunk(file, previous_chunk):
- new_chunk=chunk()
- temp_chunk=chunk()
+ new_chunk = chunk()
+ temp_chunk = chunk()
- while (previous_chunk.bytes_read<previous_chunk.length):
+ while (previous_chunk.bytes_read < previous_chunk.length):
#read the next chunk
read_chunk(file, new_chunk)
def skip_to_end(file, skip_chunk):
- buffer_size=skip_chunk.length-skip_chunk.bytes_read
+ buffer_size = skip_chunk.length - skip_chunk.bytes_read
binary_format='%ic' % buffer_size
- temp_data=file.read(calcsize(binary_format))
- skip_chunk.bytes_read+=buffer_size
+ temp_data = file.read(struct.calcsize(binary_format))
+ skip_chunk.bytes_read += buffer_size
def add_texture_to_material(image, texture, material, mapto):
- if mapto=='DIFFUSE':
- map=Texture.MapTo.COL
- elif mapto=='SPECULAR':
- map=Texture.MapTo.SPEC
- elif mapto=='OPACITY':
- map=Texture.MapTo.ALPHA
- elif mapto=='BUMP':
- map=Texture.MapTo.NOR
- else:
- print '/tError: Cannot map to "%s"\n\tassuming diffuse color. modify material "%s" later.' % (mapto, material.name)
- map=Texture.MapTo.COL
-
- if image: texture.setImage(image) # double check its an image.
- free_tex_slots= [i for i, tex in enumerate( material.getTextures() ) if tex==None]
- if not free_tex_slots:
- print '/tError: Cannot add "%s" map. 10 Texture slots alredy used.' % mapto
- else:
- material.setTexture(free_tex_slots[0],texture,Texture.TexCo.UV,map)
+# if mapto=='DIFFUSE':
+# map = Texture.MapTo.COL
+# elif mapto=='SPECULAR':
+# map = Texture.MapTo.SPEC
+# elif mapto=='OPACITY':
+# map = Texture.MapTo.ALPHA
+# elif mapto=='BUMP':
+# map = Texture.MapTo.NOR
+# else:
+ if mapto not in ("COLOR", "SPECULARITY", "ALPHA", "NORMAL"):
+ print('/tError: Cannot map to "%s"\n\tassuming diffuse color. modify material "%s" later.' % (mapto, material.name))
+ mapto = "COLOR"
+# map = Texture.MapTo.COL
+
+ if image: texture.image = image
+# if image: texture.setImage(image) # double check its an image.
+
+ material.add_texture(texture, "UV", mapto)
+# free_tex_slots = [i for i, tex in enumerate( material.getTextures() ) if tex == None]
+# if not free_tex_slots:
+# print('/tError: Cannot add "%s" map. 10 Texture slots alredy used.' % mapto)
+# else:
+# material.setTexture(free_tex_slots[0],texture,Texture.TexCo.UV,map)
def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
#print previous_chunk.bytes_read, 'BYTES READ'
- contextObName= None
- contextLamp= [None, None] # object, Data
- contextMaterial= None
- contextMatrix_rot= None # Blender.Mathutils.Matrix(); contextMatrix.identity()
- #contextMatrix_tx= None # Blender.Mathutils.Matrix(); contextMatrix.identity()
- contextMesh_vertls= None
- contextMesh_facels= None
- contextMeshMaterials= {} # matname:[face_idxs]
- contextMeshUV= None
-
- TEXTURE_DICT={}
- MATDICT={}
- TEXMODE= Mesh.FaceModes['TEX']
+ contextObName = None
+ contextLamp = [None, None] # object, Data
+ contextMaterial = None
+ contextMatrix_rot = None # Blender.Mathutils.Matrix(); contextMatrix.identity()
+ #contextMatrix_tx = None # Blender.Mathutils.Matrix(); contextMatrix.identity()
+ contextMesh_vertls = None
+ contextMesh_facels = None
+ contextMeshMaterials = {} # matname:[face_idxs]
+ contextMeshUV = None
+
+ TEXTURE_DICT = {}
+ MATDICT = {}
+# TEXMODE = Mesh.FaceModes['TEX']
# Localspace variable names, faster.
- STRUCT_SIZE_1CHAR= calcsize('c')
- STRUCT_SIZE_2FLOAT= calcsize('2f')
- STRUCT_SIZE_3FLOAT= calcsize('3f')
- STRUCT_SIZE_UNSIGNED_SHORT= calcsize('H')
- STRUCT_SIZE_4UNSIGNED_SHORT= calcsize('4H')
- STRUCT_SIZE_4x3MAT= calcsize('ffffffffffff')
- _STRUCT_SIZE_4x3MAT= calcsize('fffffffffffff')
- # STRUCT_SIZE_4x3MAT= calcsize('ffffffffffff')
+ STRUCT_SIZE_1CHAR = struct.calcsize('c')
+ STRUCT_SIZE_2FLOAT = struct.calcsize('2f')
+ STRUCT_SIZE_3FLOAT = struct.calcsize('3f')
+ STRUCT_SIZE_UNSIGNED_SHORT = struct.calcsize('H')
+ STRUCT_SIZE_4UNSIGNED_SHORT = struct.calcsize('4H')
+ STRUCT_SIZE_4x3MAT = struct.calcsize('ffffffffffff')
+ _STRUCT_SIZE_4x3MAT = struct.calcsize('fffffffffffff')
+ # STRUCT_SIZE_4x3MAT = calcsize('ffffffffffff')
# print STRUCT_SIZE_4x3MAT, ' STRUCT_SIZE_4x3MAT'
def putContextMesh(myContextMesh_vertls, myContextMesh_facels, myContextMeshMaterials):
- materialFaces= set() # faces that have a material. Can optimize?
+ materialFaces = set() # faces that have a material. Can optimize?
# Now make copies with assigned materils.
@@ -360,13 +380,13 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
'''
faceVertUsers = [False] * len(myContextMesh_vertls)
- ok=0
+ ok = 0
for fIdx in faces:
for vindex in myContextMesh_facels[fIdx]:
faceVertUsers[vindex] = True
if matName != None: # if matName is none then this is a set(), meaning we are using the untextured faces and do not need to store textured faces.
materialFaces.add(fIdx)
- ok=1
+ ok = 1
if not ok:
return
@@ -374,374 +394,465 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
myVertMapping = {}
vertMappingIndex = 0
- vertsToUse = [i for i in xrange(len(myContextMesh_vertls)) if faceVertUsers[i]]
+ vertsToUse = [i for i in range(len(myContextMesh_vertls)) if faceVertUsers[i]]
myVertMapping = dict( [ (ii, i) for i, ii in enumerate(vertsToUse) ] )
tempName= '%s_%s' % (contextObName, matName) # matName may be None.
- bmesh = bpy.data.meshes.new(tempName)
+ bmesh = bpy.data.add_mesh(tempName)
+# bmesh = bpy.data.meshes.new(tempName)
if matName == None:
- img= None
+ img = None
else:
bmat = MATDICT[matName][1]
- bmesh.materials= [bmat]
- try: img= TEXTURE_DICT[bmat.name]
- except: img= None
+ bmesh.add_material(bmat)
+# bmesh.materials = [bmat]
+ try: img = TEXTURE_DICT[bmat.name]
+ except: img = None
- bmesh_verts = bmesh.verts
- bmesh_verts.extend( [Vector()] )
- bmesh_verts.extend( [myContextMesh_vertls[i] for i in vertsToUse] )
- # +1 because of DUMMYVERT
- face_mapping= bmesh.faces.extend( [ [ bmesh_verts[ myVertMapping[vindex]+1] for vindex in myContextMesh_facels[fIdx]] for fIdx in faces ], indexList=True )
-
- if bmesh.faces and (contextMeshUV or img):
- bmesh.faceUV= 1
- for ii, i in enumerate(faces):
-
- # Mapped index- faces may have not been added- if so, then map to the correct index
- # BUGGY API - face_mapping is not always the right length
- map_index= face_mapping[ii]
-
- if map_index != None:
- targetFace= bmesh.faces[map_index]
- if contextMeshUV:
- # v.index-1 because of the DUMMYVERT
- targetFace.uv= [contextMeshUV[vindex] for vindex in myContextMesh_facels[i]]
- if img:
- targetFace.image= img
+# bmesh_verts = bmesh.verts
+ if len(vertsToUse):
+ bmesh.add_geometry(len(vertsToUse), 0, len(faces))
+
+ # XXX why add extra vertex?
+# bmesh_verts.extend( [Vector()] )
+ bmesh.verts.foreach_set("co", [x for tup in [myContextMesh_vertls[i] for i in vertsToUse] for x in tup])
+# bmesh_verts.extend( [myContextMesh_vertls[i] for i in vertsToUse] )
+
+ # +1 because of DUMMYVERT
+ bmesh.faces.foreach_set("verts_raw", unpack_face_list([[myVertMapping[vindex] for vindex in myContextMesh_facels[fIdx]] for fIdx in faces]))
+# face_mapping = bmesh.faces.extend( [ [ bmesh_verts[ myVertMapping[vindex]+1] for vindex in myContextMesh_facels[fIdx]] for fIdx in faces ], indexList=True )
+
+ if bmesh.faces and (contextMeshUV or img):
+ bmesh.add_uv_texture()
+# bmesh.faceUV = 1
+ for ii, i in enumerate(faces):
+
+ # Mapped index- faces may have not been added- if so, then map to the correct index
+ # BUGGY API - face_mapping is not always the right length
+# map_index = face_mapping[ii]
+
+ if 1:
+# if map_index != None:
+ targetFace = bmesh.faces[ii]
+# targetFace = bmesh.faces[map_index]
+
+ uf = bmesh.active_uv_texture.data[ii]
+
+ if contextMeshUV:
+ # v.index-1 because of the DUMMYVERT
+ uvs = [contextMeshUV[vindex] for vindex in myContextMesh_facels[i]]
+
+ if len(myContextMesh_facels[i]) == 3:
+ uf.uv1, uf.uv2, uf.uv3, uf.uv4 = uvs + [(0.0, 0.0)]
+ else:
+ uf.uv1, uf.uv2, uf.uv3, uf.uv4 = uvs
+# targetFace.uv = [contextMeshUV[vindex] for vindex in myContextMesh_facels[i]]
+ if img:
+ uf.image = img
+# targetFace.image = img
# bmesh.transform(contextMatrix)
- ob = SCN_OBJECTS.new(bmesh, tempName)
+ ob = bpy.data.add_object("MESH", tempName)
+ ob.data = bmesh
+ SCN.add_object(ob)
+# ob = SCN_OBJECTS.new(bmesh, tempName)
'''
if contextMatrix_tx:
ob.setMatrix(contextMatrix_tx)
'''
if contextMatrix_rot:
- ob.setMatrix(contextMatrix_rot)
+ # ob.matrix = [x for row in contextMatrix_rot for x in row]
+ ob.matrix = contextMatrix_rot
+# ob.setMatrix(contextMatrix_rot)
importedObjects.append(ob)
- bmesh.calcNormals()
+ bmesh.update()
+# bmesh.calcNormals()
- for matName, faces in myContextMeshMaterials.iteritems():
+ for matName, faces in myContextMeshMaterials.items():
makeMeshMaterialCopy(matName, faces)
- if len(materialFaces)!=len(myContextMesh_facels):
+ if len(materialFaces) != len(myContextMesh_facels):
# Invert material faces.
makeMeshMaterialCopy(None, set(range(len( myContextMesh_facels ))) - materialFaces)
#raise 'Some UnMaterialed faces', len(contextMesh.faces)
#a spare chunk
- new_chunk= chunk()
- temp_chunk= chunk()
+ new_chunk = chunk()
+ temp_chunk = chunk()
CreateBlenderObject = False
+ def read_float_color(temp_chunk):
+ temp_data = file.read(struct.calcsize('3f'))
+ temp_chunk.bytes_read += 12
+ return [float(col) for col in struct.unpack('<3f', temp_data)]
+
+ def read_byte_color(temp_chunk):
+ temp_data = file.read(struct.calcsize('3B'))
+ temp_chunk.bytes_read += 3
+ return [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
+
+ def read_texture(new_chunk, temp_chunk, name, mapto):
+ new_texture = bpy.data.add_texture('Diffuse')
+ new_texture.type = 'IMAGE'
+
+ img = None
+ while (new_chunk.bytes_read < new_chunk.length):
+ #print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
+ read_chunk(file, temp_chunk)
+
+ if (temp_chunk.ID == MAT_MAP_FILENAME):
+ texture_name = read_string(file)
+ img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
+ new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
+
+ else:
+ skip_to_end(file, temp_chunk)
+
+ new_chunk.bytes_read += temp_chunk.bytes_read
+
+ # add the map to the material in the right channel
+ if img:
+ add_texture_to_material(img, new_texture, contextMaterial, mapto)
+
+ dirname = os.path.dirname(FILENAME)
+
#loop through all the data for this chunk (previous chunk) and see what it is
- while (previous_chunk.bytes_read<previous_chunk.length):
+ while (previous_chunk.bytes_read < previous_chunk.length):
#print '\t', previous_chunk.bytes_read, 'keep going'
#read the next chunk
#print 'reading a chunk'
read_chunk(file, new_chunk)
#is it a Version chunk?
- if (new_chunk.ID==VERSION):
- #print 'if (new_chunk.ID==VERSION):'
+ if (new_chunk.ID == VERSION):
+ #print 'if (new_chunk.ID == VERSION):'
#print 'found a VERSION chunk'
#read in the version of the file
#it's an unsigned short (H)
- temp_data= file.read(calcsize('I'))
- version = unpack('<I', temp_data)[0]
- new_chunk.bytes_read+= 4 #read the 4 bytes for the version number
+ temp_data = file.read(struct.calcsize('I'))
+ version = struct.unpack('<I', temp_data)[0]
+ new_chunk.bytes_read += 4 #read the 4 bytes for the version number
#this loader works with version 3 and below, but may not with 4 and above
- if (version>3):
- print '\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version
+ if (version > 3):
+ print('\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version)
#is it an object info chunk?
- elif (new_chunk.ID==OBJECTINFO):
- #print 'elif (new_chunk.ID==OBJECTINFO):'
+ elif (new_chunk.ID == OBJECTINFO):
+ #print 'elif (new_chunk.ID == OBJECTINFO):'
# print 'found an OBJECTINFO chunk'
process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH)
#keep track of how much we read in the main chunk
- new_chunk.bytes_read+=temp_chunk.bytes_read
+ new_chunk.bytes_read += temp_chunk.bytes_read
#is it an object chunk?
- elif (new_chunk.ID==OBJECT):
+ elif (new_chunk.ID == OBJECT):
if CreateBlenderObject:
putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
- contextMesh_vertls= []; contextMesh_facels= []
+ contextMesh_vertls = []; contextMesh_facels = []
## preparando para receber o proximo objeto
- contextMeshMaterials= {} # matname:[face_idxs]
- contextMeshUV= None
- #contextMesh.vertexUV= 1 # Make sticky coords.
+ contextMeshMaterials = {} # matname:[face_idxs]
+ contextMeshUV = None
+ #contextMesh.vertexUV = 1 # Make sticky coords.
# Reset matrix
- contextMatrix_rot= None
- #contextMatrix_tx= None
+ contextMatrix_rot = None
+ #contextMatrix_tx = None
- CreateBlenderObject= True
- tempName= read_string(file)
- contextObName= tempName
+ CreateBlenderObject = True
+ tempName = read_string(file)
+ contextObName = tempName
new_chunk.bytes_read += len(tempName)+1
#is it a material chunk?
- elif (new_chunk.ID==MATERIAL):
- #print 'elif (new_chunk.ID==MATERIAL):'
- contextMaterial= bpy.data.materials.new('Material')
+ elif (new_chunk.ID == MATERIAL):
+
+# print("read material")
+
+ #print 'elif (new_chunk.ID == MATERIAL):'
+ contextMaterial = bpy.data.add_material('Material')
+# contextMaterial = bpy.data.materials.new('Material')
- elif (new_chunk.ID==MAT_NAME):
- #print 'elif (new_chunk.ID==MAT_NAME):'
- material_name= read_string(file)
+ elif (new_chunk.ID == MAT_NAME):
+ #print 'elif (new_chunk.ID == MAT_NAME):'
+ material_name = read_string(file)
+
+# print("material name", material_name)
#plus one for the null character that ended the string
- new_chunk.bytes_read+= len(material_name)+1
+ new_chunk.bytes_read += len(material_name)+1
- contextMaterial.name= material_name.rstrip() # remove trailing whitespace
+ contextMaterial.name = material_name.rstrip() # remove trailing whitespace
MATDICT[material_name]= (contextMaterial.name, contextMaterial)
- elif (new_chunk.ID==MAT_AMBIENT):
- #print 'elif (new_chunk.ID==MAT_AMBIENT):'
+ elif (new_chunk.ID == MAT_AMBIENT):
+ #print 'elif (new_chunk.ID == MAT_AMBIENT):'
read_chunk(file, temp_chunk)
- if (temp_chunk.ID==MAT_FLOAT_COLOR):
- temp_data=file.read(calcsize('3f'))
- temp_chunk.bytes_read+=12
- contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)]
- elif (temp_chunk.ID==MAT_24BIT_COLOR):
- temp_data=file.read(calcsize('3B'))
- temp_chunk.bytes_read+= 3
- contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb
+ if (temp_chunk.ID == MAT_FLOAT_COLOR):
+ contextMaterial.mirror_color = read_float_color(temp_chunk)
+# temp_data = file.read(struct.calcsize('3f'))
+# temp_chunk.bytes_read += 12
+# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)]
+ elif (temp_chunk.ID == MAT_24BIT_COLOR):
+ contextMaterial.mirror_color = read_byte_color(temp_chunk)
+# temp_data = file.read(struct.calcsize('3B'))
+# temp_chunk.bytes_read += 3
+# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
else:
skip_to_end(file, temp_chunk)
- new_chunk.bytes_read+= temp_chunk.bytes_read
+ new_chunk.bytes_read += temp_chunk.bytes_read
- elif (new_chunk.ID==MAT_DIFFUSE):
- #print 'elif (new_chunk.ID==MAT_DIFFUSE):'
+ elif (new_chunk.ID == MAT_DIFFUSE):
+ #print 'elif (new_chunk.ID == MAT_DIFFUSE):'
read_chunk(file, temp_chunk)
- if (temp_chunk.ID==MAT_FLOAT_COLOR):
- temp_data=file.read(calcsize('3f'))
- temp_chunk.bytes_read+=12
- contextMaterial.rgbCol=[float(col) for col in unpack('<3f', temp_data)]
- elif (temp_chunk.ID==MAT_24BIT_COLOR):
- temp_data=file.read(calcsize('3B'))
- temp_chunk.bytes_read+= 3
- contextMaterial.rgbCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb
+ if (temp_chunk.ID == MAT_FLOAT_COLOR):
+ contextMaterial.diffuse_color = read_float_color(temp_chunk)
+# temp_data = file.read(struct.calcsize('3f'))
+# temp_chunk.bytes_read += 12
+# contextMaterial.rgbCol = [float(col) for col in struct.unpack('<3f', temp_data)]
+ elif (temp_chunk.ID == MAT_24BIT_COLOR):
+ contextMaterial.diffuse_color = read_byte_color(temp_chunk)
+# temp_data = file.read(struct.calcsize('3B'))
+# temp_chunk.bytes_read += 3
+# contextMaterial.rgbCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
else:
skip_to_end(file, temp_chunk)
- new_chunk.bytes_read+= temp_chunk.bytes_read
- elif (new_chunk.ID==MAT_SPECULAR):
- #print 'elif (new_chunk.ID==MAT_SPECULAR):'
+# print("read material diffuse color", contextMaterial.diffuse_color)
+
+ new_chunk.bytes_read += temp_chunk.bytes_read
+
+ elif (new_chunk.ID == MAT_SPECULAR):
+ #print 'elif (new_chunk.ID == MAT_SPECULAR):'
read_chunk(file, temp_chunk)
- if (temp_chunk.ID==MAT_FLOAT_COLOR):
- temp_data=file.read(calcsize('3f'))
- temp_chunk.bytes_read+=12
- contextMaterial.mirCol=[float(col) for col in unpack('<3f', temp_data)]
- elif (temp_chunk.ID==MAT_24BIT_COLOR):
- temp_data=file.read(calcsize('3B'))
- temp_chunk.bytes_read+= 3
- contextMaterial.mirCol= [float(col)/255 for col in unpack('<3B', temp_data)] # data [0,1,2] == rgb
+ if (temp_chunk.ID == MAT_FLOAT_COLOR):
+ contextMaterial.specular_color = read_float_color(temp_chunk)
+# temp_data = file.read(struct.calcsize('3f'))
+# temp_chunk.bytes_read += 12
+# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)]
+ elif (temp_chunk.ID == MAT_24BIT_COLOR):
+ contextMaterial.specular_color = read_byte_color(temp_chunk)
+# temp_data = file.read(struct.calcsize('3B'))
+# temp_chunk.bytes_read += 3
+# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
else:
skip_to_end(file, temp_chunk)
- new_chunk.bytes_read+= temp_chunk.bytes_read
-
- elif (new_chunk.ID==MAT_TEXTURE_MAP):
- #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):'
- new_texture= bpy.data.textures.new('Diffuse')
- new_texture.setType('Image')
- img = None
- while (new_chunk.bytes_read<new_chunk.length):
- #print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
- read_chunk(file, temp_chunk)
+ new_chunk.bytes_read += temp_chunk.bytes_read
+
+ elif (new_chunk.ID == MAT_TEXTURE_MAP):
+ read_texture(new_chunk, temp_chunk, "Diffuse", "COLOR")
+# #print 'elif (new_chunk.ID==MAT_TEXTURE_MAP):'
+# new_texture= bpy.data.textures.new('Diffuse')
+# new_texture.setType('Image')
+# img = None
+# while (new_chunk.bytes_read<new_chunk.length):
+# #print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
+# read_chunk(file, temp_chunk)
- if (temp_chunk.ID==MAT_MAP_FILENAME):
- texture_name=read_string(file)
- #img= TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
- img= TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
- new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
+# if (temp_chunk.ID==MAT_MAP_FILENAME):
+# texture_name=read_string(file)
+# #img= TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
+# img= TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
+# new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
- else:
- skip_to_end(file, temp_chunk)
+# else:
+# skip_to_end(file, temp_chunk)
- new_chunk.bytes_read+= temp_chunk.bytes_read
-
- #add the map to the material in the right channel
- if img:
- add_texture_to_material(img, new_texture, contextMaterial, 'DIFFUSE')
-
- elif (new_chunk.ID==MAT_SPECULAR_MAP):
- #print 'elif (new_chunk.ID==MAT_SPECULAR_MAP):'
- new_texture= bpy.data.textures.new('Specular')
- new_texture.setType('Image')
- img = None
- while (new_chunk.bytes_read<new_chunk.length):
- read_chunk(file, temp_chunk)
+# new_chunk.bytes_read+= temp_chunk.bytes_read
+
+# #add the map to the material in the right channel
+# if img:
+# add_texture_to_material(img, new_texture, contextMaterial, 'DIFFUSE')
+
+ elif (new_chunk.ID == MAT_SPECULAR_MAP):
+ read_texture(new_chunk, temp_chunk, "Specular", "SPECULARITY")
+# #print 'elif (new_chunk.ID == MAT_SPECULAR_MAP):'
+# new_texture = bpy.data.textures.new('Specular')
+# new_texture.setType('Image')
+# img = None
+# while (new_chunk.bytes_read < new_chunk.length):
+# read_chunk(file, temp_chunk)
- if (temp_chunk.ID==MAT_MAP_FILENAME):
- texture_name= read_string(file)
- #img= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
- img= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
- new_chunk.bytes_read+= (len(texture_name)+1) #plus one for the null character that gets removed
- else:
- skip_to_end(file, temp_chunk)
+# if (temp_chunk.ID == MAT_MAP_FILENAME):
+# texture_name = read_string(file)
+# #img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
+# img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
+# new_chunk.bytes_read+= (len(texture_name)+1) #plus one for the null character that gets removed
+# else:
+# skip_to_end(file, temp_chunk)
- new_chunk.bytes_read+= temp_chunk.bytes_read
+# new_chunk.bytes_read += temp_chunk.bytes_read
- #add the map to the material in the right channel
- if img:
- add_texture_to_material(img, new_texture, contextMaterial, 'SPECULAR')
-
- elif (new_chunk.ID==MAT_OPACITY_MAP):
- #print 'new_texture=Blender.Texture.New('Opacity')'
- new_texture= bpy.data.textures.new('Opacity')
- new_texture.setType('Image')
- img = None
- while (new_chunk.bytes_read<new_chunk.length):
- read_chunk(file, temp_chunk)
+# #add the map to the material in the right channel
+# if img:
+# add_texture_to_material(img, new_texture, contextMaterial, 'SPECULAR')
+
+ elif (new_chunk.ID == MAT_OPACITY_MAP):
+ read_texture(new_chunk, temp_chunk, "Opacity", "ALPHA")
+# #print 'new_texture = Blender.Texture.New('Opacity')'
+# new_texture = bpy.data.textures.new('Opacity')
+# new_texture.setType('Image')
+# img = None
+# while (new_chunk.bytes_read < new_chunk.length):
+# read_chunk(file, temp_chunk)
- if (temp_chunk.ID==MAT_MAP_FILENAME):
- texture_name= read_string(file)
- #img= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
- img= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
- new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
- else:
- skip_to_end(file, temp_chunk)
+# if (temp_chunk.ID == MAT_MAP_FILENAME):
+# texture_name = read_string(file)
+# #img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
+# img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
+# new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
+# else:
+# skip_to_end(file, temp_chunk)
- new_chunk.bytes_read+= temp_chunk.bytes_read
- #add the map to the material in the right channel
- if img:
- add_texture_to_material(img, new_texture, contextMaterial, 'OPACITY')
-
- elif (new_chunk.ID==MAT_BUMP_MAP):
- #print 'elif (new_chunk.ID==MAT_BUMP_MAP):'
- new_texture= bpy.data.textures.new('Bump')
- new_texture.setType('Image')
- img = None
- while (new_chunk.bytes_read<new_chunk.length):
- read_chunk(file, temp_chunk)
+# new_chunk.bytes_read += temp_chunk.bytes_read
+# #add the map to the material in the right channel
+# if img:
+# add_texture_to_material(img, new_texture, contextMaterial, 'OPACITY')
+
+ elif (new_chunk.ID == MAT_BUMP_MAP):
+ read_texture(new_chunk, temp_chunk, "Bump", "NORMAL")
+# #print 'elif (new_chunk.ID == MAT_BUMP_MAP):'
+# new_texture = bpy.data.textures.new('Bump')
+# new_texture.setType('Image')
+# img = None
+# while (new_chunk.bytes_read < new_chunk.length):
+# read_chunk(file, temp_chunk)
- if (temp_chunk.ID==MAT_MAP_FILENAME):
- texture_name= read_string(file)
- #img= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
- img= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
- new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
- else:
- skip_to_end(file, temp_chunk)
+# if (temp_chunk.ID == MAT_MAP_FILENAME):
+# texture_name = read_string(file)
+# #img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
+# img = BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
+# new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
+# else:
+# skip_to_end(file, temp_chunk)
- new_chunk.bytes_read+=temp_chunk.bytes_read
+# new_chunk.bytes_read += temp_chunk.bytes_read
- #add the map to the material in the right channel
- if img:
- add_texture_to_material(img, new_texture, contextMaterial, 'BUMP')
+# #add the map to the material in the right channel
+# if img:
+# add_texture_to_material(img, new_texture, contextMaterial, 'BUMP')
- elif (new_chunk.ID==MAT_TRANSPARENCY):
- #print 'elif (new_chunk.ID==MAT_TRANSPARENCY):'
+ elif (new_chunk.ID == MAT_TRANSPARENCY):
+ #print 'elif (new_chunk.ID == MAT_TRANSPARENCY):'
read_chunk(file, temp_chunk)
- temp_data=file.read(STRUCT_SIZE_UNSIGNED_SHORT)
+ temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- temp_chunk.bytes_read+=2
- contextMaterial.alpha= 1-(float(unpack('<H', temp_data)[0])/100)
- new_chunk.bytes_read+=temp_chunk.bytes_read
+ temp_chunk.bytes_read += 2
+ contextMaterial.alpha = 1-(float(struct.unpack('<H', temp_data)[0])/100)
+ new_chunk.bytes_read += temp_chunk.bytes_read
- elif (new_chunk.ID==OBJECT_LAMP): # Basic lamp support.
+ elif (new_chunk.ID == OBJECT_LAMP): # Basic lamp support.
- temp_data=file.read(STRUCT_SIZE_3FLOAT)
+ temp_data = file.read(STRUCT_SIZE_3FLOAT)
- x,y,z=unpack('<3f', temp_data)
- new_chunk.bytes_read+=STRUCT_SIZE_3FLOAT
+ x,y,z = struct.unpack('<3f', temp_data)
+ new_chunk.bytes_read += STRUCT_SIZE_3FLOAT
+
+ ob = bpy.data.add_object("LAMP", "Lamp")
+ ob.data = bpy.data.add_lamp("Lamp")
+ SCN.add_object(ob)
- contextLamp[1]= bpy.data.lamps.new()
- contextLamp[0]= SCN_OBJECTS.new(contextLamp[1])
+ contextLamp[1]= ob.data
+# contextLamp[1]= bpy.data.lamps.new()
+ contextLamp[0]= ob
+# contextLamp[0]= SCN_OBJECTS.new(contextLamp[1])
importedObjects.append(contextLamp[0])
#print 'number of faces: ', num_faces
#print x,y,z
- contextLamp[0].setLocation(x,y,z)
+ contextLamp[0].location = (x, y, z)
+# contextLamp[0].setLocation(x,y,z)
# Reset matrix
- contextMatrix_rot= None
- #contextMatrix_tx= None
+ contextMatrix_rot = None
+ #contextMatrix_tx = None
#print contextLamp.name,
- elif (new_chunk.ID==OBJECT_MESH):
+ elif (new_chunk.ID == OBJECT_MESH):
# print 'Found an OBJECT_MESH chunk'
pass
- elif (new_chunk.ID==OBJECT_VERTICES):
+ elif (new_chunk.ID == OBJECT_VERTICES):
'''
Worldspace vertex locations
'''
- # print 'elif (new_chunk.ID==OBJECT_VERTICES):'
- temp_data=file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- num_verts=unpack('<H', temp_data)[0]
- new_chunk.bytes_read+=2
+ # print 'elif (new_chunk.ID == OBJECT_VERTICES):'
+ temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
+ num_verts = struct.unpack('<H', temp_data)[0]
+ new_chunk.bytes_read += 2
# print 'number of verts: ', num_verts
def getvert():
- temp_data= unpack('<3f', file.read(STRUCT_SIZE_3FLOAT))
+ temp_data = struct.unpack('<3f', file.read(STRUCT_SIZE_3FLOAT))
new_chunk.bytes_read += STRUCT_SIZE_3FLOAT #12: 3 floats x 4 bytes each
return temp_data
#contextMesh.verts.extend( [Vector(),] ) # DUMMYVERT! - remove when blenders internals are fixed.
- contextMesh_vertls= [getvert() for i in xrange(num_verts)]
+ contextMesh_vertls = [getvert() for i in range(num_verts)]
#print 'object verts: bytes read: ', new_chunk.bytes_read
- elif (new_chunk.ID==OBJECT_FACES):
- # print 'elif (new_chunk.ID==OBJECT_FACES):'
- temp_data= file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- num_faces= unpack('<H', temp_data)[0]
- new_chunk.bytes_read+= 2
+ elif (new_chunk.ID == OBJECT_FACES):
+ # print 'elif (new_chunk.ID == OBJECT_FACES):'
+ temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
+ num_faces = struct.unpack('<H', temp_data)[0]
+ new_chunk.bytes_read += 2
#print 'number of faces: ', num_faces
def getface():
# print '\ngetting a face'
- temp_data= file.read(STRUCT_SIZE_4UNSIGNED_SHORT)
- new_chunk.bytes_read+= STRUCT_SIZE_4UNSIGNED_SHORT #4 short ints x 2 bytes each
- v1,v2,v3,dummy= unpack('<4H', temp_data)
+ temp_data = file.read(STRUCT_SIZE_4UNSIGNED_SHORT)
+ new_chunk.bytes_read += STRUCT_SIZE_4UNSIGNED_SHORT #4 short ints x 2 bytes each
+ v1,v2,v3,dummy = struct.unpack('<4H', temp_data)
return v1, v2, v3
- contextMesh_facels= [ getface() for i in xrange(num_faces) ]
+ contextMesh_facels = [ getface() for i in range(num_faces) ]
- elif (new_chunk.ID==OBJECT_MATERIAL):
- # print 'elif (new_chunk.ID==OBJECT_MATERIAL):'
- material_name= read_string(file)
+ elif (new_chunk.ID == OBJECT_MATERIAL):
+ # print 'elif (new_chunk.ID == OBJECT_MATERIAL):'
+ material_name = read_string(file)
new_chunk.bytes_read += len(material_name)+1 # remove 1 null character.
- temp_data=file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- num_faces_using_mat = unpack('<H', temp_data)[0]
+ temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
+ num_faces_using_mat = struct.unpack('<H', temp_data)[0]
new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
def getmat():
- temp_data= file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- new_chunk.bytes_read+= STRUCT_SIZE_UNSIGNED_SHORT
- return unpack('<H', temp_data)[0]
+ temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
+ new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
+ return struct.unpack('<H', temp_data)[0]
- contextMeshMaterials[material_name]= [ getmat() for i in xrange(num_faces_using_mat) ]
+ contextMeshMaterials[material_name]= [ getmat() for i in range(num_faces_using_mat) ]
#look up the material in all the materials
- elif (new_chunk.ID==OBJECT_UV):
- temp_data=file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- num_uv=unpack('<H', temp_data)[0]
- new_chunk.bytes_read+= 2
+ elif (new_chunk.ID == OBJECT_UV):
+ temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
+ num_uv = struct.unpack('<H', temp_data)[0]
+ new_chunk.bytes_read += 2
def getuv():
- temp_data=file.read(STRUCT_SIZE_2FLOAT)
+ temp_data = file.read(STRUCT_SIZE_2FLOAT)
new_chunk.bytes_read += STRUCT_SIZE_2FLOAT #2 float x 4 bytes each
- return Vector( unpack('<2f', temp_data) )
+ return Mathutils.Vector( struct.unpack('<2f', temp_data) )
+# return Vector( struct.unpack('<2f', temp_data) )
- contextMeshUV= [ getuv() for i in xrange(num_uv) ]
+ contextMeshUV = [ getuv() for i in range(num_uv) ]
- elif (new_chunk.ID== OBJECT_TRANS_MATRIX):
+ elif (new_chunk.ID == OBJECT_TRANS_MATRIX):
# How do we know the matrix size? 54 == 4x4 48 == 4x3
- temp_data=file.read(STRUCT_SIZE_4x3MAT)
- data= list( unpack('<ffffffffffff', temp_data) )
+ temp_data = file.read(STRUCT_SIZE_4x3MAT)
+ data = list( struct.unpack('<ffffffffffff', temp_data) )
new_chunk.bytes_read += STRUCT_SIZE_4x3MAT
- contextMatrix_rot= Blender.Mathutils.Matrix(\
+ contextMatrix_rot = Mathutils.Matrix(\
+# contextMatrix_rot = Blender.Mathutils.Matrix(\
data[:3] + [0],\
data[3:6] + [0],\
data[6:9] + [0],\
@@ -749,7 +860,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
'''
- contextMatrix_rot= Blender.Mathutils.Matrix(\
+ contextMatrix_rot = Blender.Mathutils.Matrix(\
data[:3] + [0],\
data[3:6] + [0],\
data[6:9] + [0],\
@@ -757,7 +868,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
'''
'''
- contextMatrix_rot= Blender.Mathutils.Matrix(\
+ contextMatrix_rot = Blender.Mathutils.Matrix(\
data[:3] ,\
data[3:6],\
data[6:9])
@@ -769,7 +880,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
for j in xrange(4):
for i in xrange(3):
contextMatrix_rot[j][i] = data[m]
- m+=1
+ m += 1
contextMatrix_rot[0][3]=0;
contextMatrix_rot[1][3]=0;
@@ -790,82 +901,87 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
#contextMatrix = contextMatrix * tx
#contextMatrix = contextMatrix *tx
- elif (new_chunk.ID==MAT_MAP_FILENAME):
- texture_name=read_string(file)
+ elif (new_chunk.ID == MAT_MAP_FILENAME):
+ texture_name = read_string(file)
try:
TEXTURE_DICT[contextMaterial.name]
except:
- #img= TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
- img= TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
+ #img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
+ img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
+# img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
- new_chunk.bytes_read+= len(texture_name)+1 #plus one for the null character that gets removed
+ new_chunk.bytes_read += len(texture_name)+1 #plus one for the null character that gets removed
else: #(new_chunk.ID!=VERSION or new_chunk.ID!=OBJECTINFO or new_chunk.ID!=OBJECT or new_chunk.ID!=MATERIAL):
# print 'skipping to end of this chunk'
- buffer_size=new_chunk.length-new_chunk.bytes_read
+ buffer_size = new_chunk.length - new_chunk.bytes_read
binary_format='%ic' % buffer_size
- temp_data=file.read(calcsize(binary_format))
- new_chunk.bytes_read+=buffer_size
+ temp_data = file.read(struct.calcsize(binary_format))
+ new_chunk.bytes_read += buffer_size
#update the previous chunk bytes read
# print 'previous_chunk.bytes_read += new_chunk.bytes_read'
# print previous_chunk.bytes_read, new_chunk.bytes_read
previous_chunk.bytes_read += new_chunk.bytes_read
- ## print 'Bytes left in this chunk: ', previous_chunk.length-previous_chunk.bytes_read
+ ## print 'Bytes left in this chunk: ', previous_chunk.length - previous_chunk.bytes_read
# FINISHED LOOP
# There will be a number of objects still not added
if contextMesh_facels != None:
putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
-def load_3ds(filename, PREF_UI= True):
- global FILENAME, SCN_OBJECTS
-
- if BPyMessages.Error_NoFile(filename):
- return
-
- print '\n\nImporting 3DS: "%s"' % (Blender.sys.expandpath(filename))
+def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True, APPLY_MATRIX=False):
+ global FILENAME, SCN
+# global FILENAME, SCN_OBJECTS
+
+ # XXX
+# if BPyMessages.Error_NoFile(filename):
+# return
- time1= Blender.sys.time()
+ print('\n\nImporting 3DS: "%s"' % (filename))
+# print('\n\nImporting 3DS: "%s"' % (Blender.sys.expandpath(filename)))
+
+ time1 = time.clock()
+# time1 = Blender.sys.time()
- FILENAME=filename
- current_chunk=chunk()
+ FILENAME = filename
+ current_chunk = chunk()
- file=open(filename,'rb')
+ file = open(filename,'rb')
#here we go!
# print 'reading the first chunk'
read_chunk(file, current_chunk)
if (current_chunk.ID!=PRIMARY):
- print '\tFatal Error: Not a valid 3ds file: ', filename
+ print('\tFatal Error: Not a valid 3ds file: ', filename)
file.close()
return
- # IMPORT_AS_INSTANCE= Blender.Draw.Create(0)
- IMPORT_CONSTRAIN_BOUNDS= Blender.Draw.Create(10.0)
- IMAGE_SEARCH= Blender.Draw.Create(1)
- APPLY_MATRIX= Blender.Draw.Create(0)
+ # IMPORT_AS_INSTANCE = Blender.Draw.Create(0)
+# IMPORT_CONSTRAIN_BOUNDS = Blender.Draw.Create(10.0)
+# IMAGE_SEARCH = Blender.Draw.Create(1)
+# APPLY_MATRIX = Blender.Draw.Create(0)
# Get USER Options
- pup_block= [\
- ('Size Constraint:', IMPORT_CONSTRAIN_BOUNDS, 0.0, 1000.0, 'Scale the model by 10 until it reacehs the size constraint. Zero Disables.'),\
- ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\
- ('Transform Fix', APPLY_MATRIX, 'Workaround for object transformations importing incorrectly'),\
- #('Group Instance', IMPORT_AS_INSTANCE, 'Import objects into a new scene and group, creating an instance in the current scene.'),\
- ]
+# pup_block = [\
+# ('Size Constraint:', IMPORT_CONSTRAIN_BOUNDS, 0.0, 1000.0, 'Scale the model by 10 until it reacehs the size constraint. Zero Disables.'),\
+# ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\
+# ('Transform Fix', APPLY_MATRIX, 'Workaround for object transformations importing incorrectly'),\
+# #('Group Instance', IMPORT_AS_INSTANCE, 'Import objects into a new scene and group, creating an instance in the current scene.'),\
+# ]
- if PREF_UI:
- if not Blender.Draw.PupBlock('Import 3DS...', pup_block):
- return
+# if PREF_UI:
+# if not Blender.Draw.PupBlock('Import 3DS...', pup_block):
+# return
- Blender.Window.WaitCursor(1)
+# Blender.Window.WaitCursor(1)
- IMPORT_CONSTRAIN_BOUNDS= IMPORT_CONSTRAIN_BOUNDS.val
- # IMPORT_AS_INSTANCE= IMPORT_AS_INSTANCE.val
- IMAGE_SEARCH = IMAGE_SEARCH.val
- APPLY_MATRIX = APPLY_MATRIX.val
+# IMPORT_CONSTRAIN_BOUNDS = IMPORT_CONSTRAIN_BOUNDS.val
+# # IMPORT_AS_INSTANCE = IMPORT_AS_INSTANCE.val
+# IMAGE_SEARCH = IMAGE_SEARCH.val
+# APPLY_MATRIX = APPLY_MATRIX.val
if IMPORT_CONSTRAIN_BOUNDS:
BOUNDS_3DS[:]= [1<<30, 1<<30, 1<<30, -1<<30, -1<<30, -1<<30]
@@ -874,96 +990,103 @@ def load_3ds(filename, PREF_UI= True):
##IMAGE_SEARCH
- scn= bpy.data.scenes.active
- SCN_OBJECTS = scn.objects
- SCN_OBJECTS.selected = [] # de select all
+ scn = context.scene
+# scn = bpy.data.scenes.active
+ SCN = scn
+# SCN_OBJECTS = scn.objects
+# SCN_OBJECTS.selected = [] # de select all
- importedObjects= [] # Fill this list with objects
+ importedObjects = [] # Fill this list with objects
process_next_chunk(file, current_chunk, importedObjects, IMAGE_SEARCH)
# Link the objects into this scene.
- # Layers= scn.Layers
+ # Layers = scn.Layers
# REMOVE DUMMYVERT, - remove this in the next release when blenders internal are fixed.
- for ob in importedObjects:
- if ob.type=='Mesh':
- me= ob.getData(mesh=1)
- me.verts.delete([me.verts[0],])
- if not APPLY_MATRIX:
- me.transform(ob.matrixWorld.copy().invert())
+# for ob in importedObjects:
+# if ob.type == 'MESH':
+# # if ob.type=='Mesh':
+# me = ob.getData(mesh=1)
+# me.verts.delete([me.verts[0],])
+# if not APPLY_MATRIX:
+# me.transform(ob.matrixWorld.copy().invert())
# Done DUMMYVERT
"""
if IMPORT_AS_INSTANCE:
- name= filename.split('\\')[-1].split('/')[-1]
+ name = filename.split('\\')[-1].split('/')[-1]
# Create a group for this import.
- group_scn= Scene.New(name)
+ group_scn = Scene.New(name)
for ob in importedObjects:
group_scn.link(ob) # dont worry about the layers
- grp= Blender.Group.New(name)
- grp.objects= importedObjects
+ grp = Blender.Group.New(name)
+ grp.objects = importedObjects
- grp_ob= Object.New('Empty', name)
- grp_ob.enableDupGroup= True
- grp_ob.DupGroup= grp
+ grp_ob = Object.New('Empty', name)
+ grp_ob.enableDupGroup = True
+ grp_ob.DupGroup = grp
scn.link(grp_ob)
- grp_ob.Layers= Layers
- grp_ob.sel= 1
+ grp_ob.Layers = Layers
+ grp_ob.sel = 1
else:
# Select all imported objects.
for ob in importedObjects:
scn.link(ob)
- ob.Layers= Layers
- ob.sel= 1
+ ob.Layers = Layers
+ ob.sel = 1
"""
- if IMPORT_CONSTRAIN_BOUNDS!=0.0:
+ if 0:
+# if IMPORT_CONSTRAIN_BOUNDS!=0.0:
# Set bounds from objecyt bounding box
for ob in importedObjects:
- if ob.type=='Mesh':
+ if ob.type == 'MESH':
+# if ob.type=='Mesh':
ob.makeDisplayList() # Why dosnt this update the bounds?
for v in ob.getBoundBox():
for i in (0,1,2):
if v[i] < BOUNDS_3DS[i]:
BOUNDS_3DS[i]= v[i] # min
- if v[i] > BOUNDS_3DS[i+3]:
- BOUNDS_3DS[i+3]= v[i] # min
+ if v[i] > BOUNDS_3DS[i + 3]:
+ BOUNDS_3DS[i + 3]= v[i] # min
# Get the max axis x/y/z
- max_axis= max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2])
+ max_axis = max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2])
# print max_axis
- if max_axis < 1<<30: # Should never be false but just make sure.
+ if max_axis < 1 << 30: # Should never be false but just make sure.
# Get a new scale factor if set as an option
- SCALE=1.0
- while (max_axis*SCALE) > IMPORT_CONSTRAIN_BOUNDS:
+ SCALE = 1.0
+ while (max_axis * SCALE) > IMPORT_CONSTRAIN_BOUNDS:
SCALE/=10
# SCALE Matrix
- SCALE_MAT= Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
+ SCALE_MAT = Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
+# SCALE_MAT = Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
for ob in importedObjects:
- ob.setMatrix(ob.matrixWorld*SCALE_MAT)
+ ob.setMatrix(ob.matrixWorld * SCALE_MAT)
# Done constraining to bounds.
# Select all new objects.
- print 'finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1))
+ print('finished importing: "%s" in %.4f sec.' % (filename, (time.clock()-time1)))
+# print('finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1)))
file.close()
- Blender.Window.WaitCursor(0)
+# Blender.Window.WaitCursor(0)
-DEBUG= False
-if __name__=='__main__' and not DEBUG:
- if calcsize==None:
- Blender.Draw.PupMenu('Error%t|a full python installation not found')
- else:
- Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds')
+DEBUG = False
+# if __name__=='__main__' and not DEBUG:
+# if calcsize == None:
+# Blender.Draw.PupMenu('Error%t|a full python installation not found')
+# else:
+# Blender.Window.FileSelector(load_3ds, 'Import 3DS', '*.3ds')
# For testing compatibility
#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False)
@@ -973,14 +1096,14 @@ if __name__=='__main__' and not DEBUG:
else:
import os
# DEBUG ONLY
- TIME= Blender.sys.time()
+ TIME = Blender.sys.time()
import os
print 'Searching for files'
os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list')
# os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list')
print '...Done'
- file= open('/tmp/temp3ds_list', 'r')
- lines= file.readlines()
+ file = open('/tmp/temp3ds_list', 'r')
+ lines = file.readlines()
file.close()
# sort by filesize for faster testing
lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines]
@@ -998,10 +1121,47 @@ else:
#_3ds= _3ds[:-1]
print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines)
_3ds_file= _3ds.split('/')[-1].split('\\')[-1]
- newScn= Blender.Scene.New(_3ds_file)
+ newScn = Blender.Scene.New(_3ds_file)
newScn.makeCurrent()
load_3ds(_3ds, False)
print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
'''
+
+class IMPORT_OT_3ds(bpy.types.Operator):
+ '''
+ 3DS Importer
+ '''
+ __idname__ = "import.3ds"
+ __label__ = 'Import 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="path", name="File Path", description="File path used for importing the 3DS file", maxlen= 1024, default= ""),
+
+# bpy.props.FloatProperty(attr="size_constraint", name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0),
+# bpy.props.BoolProperty(attr="search_images", name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True),
+# bpy.props.BoolProperty(attr="apply_matrix", name="Transform Fix", description="Workaround for object transformations importing incorrectly", default=False),
+ ]
+
+ def execute(self, context):
+ load_3ds(self.path, context, 0.0, False, False)
+ return ('FINISHED',)
+
+ def invoke(self, context, event):
+ wm = context.manager
+ wm.add_fileselect(self.__operator__)
+ return ('RUNNING_MODAL',)
+ '''
+ def poll(self, context):
+ print("Poll")
+ return context.active_object != None'''
+
+bpy.ops.add(IMPORT_OT_3ds)
+
+# NOTES:
+# why add 1 extra vertex? and remove it when done?
+# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time)
diff --git a/release/scripts/io/import_obj.py b/release/scripts/io/import_obj.py
index 81230bfcf03..a762005ae7d 100644
--- a/release/scripts/io/import_obj.py
+++ b/release/scripts/io/import_obj.py
@@ -9,7 +9,7 @@ Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.'
__author__= "Campbell Barton", "Jiri Hnidek", "Paolo Ciccone"
__url__= ['http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj', 'blender.org', 'blenderartists.org']
-__version__= "2.13"
+__version__= "2.11"
__bpydoc__= """\
This script imports a Wavefront OBJ files to Blender.
@@ -21,8 +21,7 @@ Note, This loads mesh objects and materials only, nurbs and curves are not suppo
# ***** BEGIN GPL LICENSE BLOCK *****
#
-# Script copyright (C) Campbell J Barton 2007-2009
-# - V2.12- bspline import/export added (funded by PolyDimensions GmbH)
+# Script copyright (C) Campbell J Barton 2007
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -41,14 +40,19 @@ Note, This loads mesh objects and materials only, nurbs and curves are not suppo
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
-from Blender import Mesh, Draw, Window, Texture, Material, sys
+import os
+import time
import bpy
-import BPyMesh
-import BPyImage
-import BPyMessages
+import Mathutils
+import Geometry
-try: import os
-except: os= False
+# from Blender import Mesh, Draw, Window, Texture, Material, sys
+# # import BPyMesh
+# import BPyImage
+# import BPyMessages
+
+# try: import os
+# except: os= False
# Generic path functions
def stripFile(path):
@@ -56,7 +60,8 @@ def stripFile(path):
lastSlash= max(path.rfind('\\'), path.rfind('/'))
if lastSlash != -1:
path= path[:lastSlash]
- return '%s%s' % (path, sys.sep)
+ return '%s%s' % (path, os.sep)
+# return '%s%s' % (path, sys.sep)
def stripPath(path):
'''Strips the slashes from the back of a string'''
@@ -71,7 +76,215 @@ def stripExt(name): # name is a string
return name
# end path funcs
+def unpack_list(list_of_tuples):
+ l = []
+ for t in list_of_tuples:
+ l.extend(t)
+ return l
+
+# same as above except that it adds 0 for triangle faces
+def unpack_face_list(list_of_tuples):
+ l = []
+ for t in list_of_tuples:
+ face = [i for i in t]
+ if len(face) != 3 and len(face) != 4:
+ raise RuntimeError("{0} vertices in face.".format(len(face)))
+
+ # rotate indices if the 4th is 0
+ if len(face) == 4 and face[3] == 0:
+ face = [face[3], face[0], face[1], face[2]]
+
+ if len(face) == 3:
+ face.append(0)
+
+ l.extend(face)
+
+ return l
+
+def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
+ '''
+ Takes a polyline of indices (fgon)
+ and returns a list of face indicie lists.
+ Designed to be used for importers that need indices for an fgon to create from existing verts.
+
+ from_data: either a mesh, or a list/tuple of vectors.
+ indices: a list of indicies to use this list is the ordered closed polyline to fill, and can be a subset of the data given.
+ PREF_FIX_LOOPS: If this is enabled polylines that use loops to make multiple polylines are delt with correctly.
+ '''
+
+ if not set: # Need sets for this, otherwise do a normal fill.
+ PREF_FIX_LOOPS= False
+
+ Vector= Mathutils.Vector
+ if not indices:
+ return []
+
+ # return []
+ def rvec(co): return round(co.x, 6), round(co.y, 6), round(co.z, 6)
+ def mlen(co): return abs(co[0])+abs(co[1])+abs(co[2]) # manhatten length of a vector, faster then length
+
+ def vert_treplet(v, i):
+ return v, rvec(v), i, mlen(v)
+
+ def ed_key_mlen(v1, v2):
+ if v1[3] > v2[3]:
+ return v2[1], v1[1]
+ else:
+ return v1[1], v2[1]
+
+
+ if not PREF_FIX_LOOPS:
+ '''
+ Normal single concave loop filling
+ '''
+ if type(from_data) in (tuple, list):
+ verts= [Vector(from_data[i]) for ii, i in enumerate(indices)]
+ else:
+ verts= [from_data.verts[i].co for ii, i in enumerate(indices)]
+
+ for i in range(len(verts)-1, 0, -1): # same as reversed(xrange(1, len(verts))):
+ if verts[i][1]==verts[i-1][0]:
+ verts.pop(i-1)
+
+ fill= Geometry.PolyFill([verts])
+
+ else:
+ '''
+ Seperate this loop into multiple loops be finding edges that are used twice
+ This is used by lightwave LWO files a lot
+ '''
+
+ if type(from_data) in (tuple, list):
+ verts= [vert_treplet(Vector(from_data[i]), ii) for ii, i in enumerate(indices)]
+ else:
+ verts= [vert_treplet(from_data.verts[i].co, ii) for ii, i in enumerate(indices)]
+
+ edges= [(i, i-1) for i in range(len(verts))]
+ if edges:
+ edges[0]= (0,len(verts)-1)
+
+ if not verts:
+ return []
+
+
+ edges_used= set()
+ edges_doubles= set()
+ # We need to check if any edges are used twice location based.
+ for ed in edges:
+ edkey= ed_key_mlen(verts[ed[0]], verts[ed[1]])
+ if edkey in edges_used:
+ edges_doubles.add(edkey)
+ else:
+ edges_used.add(edkey)
+
+ # Store a list of unconnected loop segments split by double edges.
+ # will join later
+ loop_segments= []
+
+ v_prev= verts[0]
+ context_loop= [v_prev]
+ loop_segments= [context_loop]
+
+ for v in verts:
+ if v!=v_prev:
+ # Are we crossing an edge we removed?
+ if ed_key_mlen(v, v_prev) in edges_doubles:
+ context_loop= [v]
+ loop_segments.append(context_loop)
+ else:
+ if context_loop and context_loop[-1][1]==v[1]:
+ #raise "as"
+ pass
+ else:
+ context_loop.append(v)
+
+ v_prev= v
+ # Now join loop segments
+
+ def join_seg(s1,s2):
+ if s2[-1][1]==s1[0][1]: #
+ s1,s2= s2,s1
+ elif s1[-1][1]==s2[0][1]:
+ pass
+ else:
+ return False
+
+ # If were stuill here s1 and s2 are 2 segments in the same polyline
+ s1.pop() # remove the last vert from s1
+ s1.extend(s2) # add segment 2 to segment 1
+
+ if s1[0][1]==s1[-1][1]: # remove endpoints double
+ s1.pop()
+
+ s2[:]= [] # Empty this segment s2 so we dont use it again.
+ return True
+
+ joining_segments= True
+ while joining_segments:
+ joining_segments= False
+ segcount= len(loop_segments)
+
+ for j in range(segcount-1, -1, -1): #reversed(range(segcount)):
+ seg_j= loop_segments[j]
+ if seg_j:
+ for k in range(j-1, -1, -1): # reversed(range(j)):
+ if not seg_j:
+ break
+ seg_k= loop_segments[k]
+
+ if seg_k and join_seg(seg_j, seg_k):
+ joining_segments= True
+
+ loop_list= loop_segments
+
+ for verts in loop_list:
+ while verts and verts[0][1]==verts[-1][1]:
+ verts.pop()
+
+ loop_list= [verts for verts in loop_list if len(verts)>2]
+ # DONE DEALING WITH LOOP FIXING
+
+
+ # vert mapping
+ vert_map= [None]*len(indices)
+ ii=0
+ for verts in loop_list:
+ if len(verts)>2:
+ for i, vert in enumerate(verts):
+ vert_map[i+ii]= vert[2]
+ ii+=len(verts)
+
+ fill= Geometry.PolyFill([ [v[0] for v in loop] for loop in loop_list ])
+ #draw_loops(loop_list)
+ #raise 'done loop'
+ # map to original indicies
+ fill= [[vert_map[i] for i in reversed(f)] for f in fill]
+
+
+ if not fill:
+ print('Warning Cannot scanfill, fallback on a triangle fan.')
+ fill= [ [0, i-1, i] for i in range(2, len(indices)) ]
+ else:
+ # Use real scanfill.
+ # See if its flipped the wrong way.
+ flip= None
+ for fi in fill:
+ if flip != None:
+ break
+ for i, vi in enumerate(fi):
+ if vi==0 and fi[i-1]==1:
+ flip= False
+ break
+ elif vi==1 and fi[i-1]==0:
+ flip= True
+ break
+
+ if not flip:
+ for i, fi in enumerate(fill):
+ fill[i]= tuple([ii for ii in reversed(fi)])
+
+ return fill
def line_value(line_split):
'''
@@ -88,22 +301,47 @@ def line_value(line_split):
elif length > 2:
return ' '.join( line_split[1:] )
+# limited replacement for BPyImage.comprehensiveImageLoad
+def load_image(imagepath, dirname):
+
+ if os.path.exists(imagepath):
+ return bpy.data.add_image(imagepath)
+
+ variants = [os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
+
+ for path in variants:
+ if os.path.exists(path):
+ return bpy.data.add_image(path)
+ else:
+ print(path, "doesn't exist")
+
+ # TODO comprehensiveImageLoad also searched in bpy.config.textureDir
+ return None
+
def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
- '''
- Mainly uses comprehensiveImageLoad
- but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores.
- '''
-
+
if '_' in imagepath:
- image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
- if image: return image
- # Did the exporter rename the image?
- image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
+ image= load_image(imagepath.replace('_', ' '), DIR)
if image: return image
-
- # Return an image, placeholder if it dosnt exist
- image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH)
- return image
+
+ return load_image(imagepath, DIR)
+
+# def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
+# '''
+# Mainly uses comprehensiveImageLoad
+# but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores.
+# '''
+
+# if '_' in imagepath:
+# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
+# if image: return image
+# # Did the exporter rename the image?
+# image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
+# if image: return image
+
+# # Return an image, placeholder if it dosnt exist
+# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH)
+# return image
def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH):
@@ -117,69 +355,82 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
# This function sets textures defined in .mtl file #
#==================================================================================#
def load_material_image(blender_material, context_material_name, imagepath, type):
-
- texture= bpy.data.textures.new(type)
- texture.setType('Image')
+
+ texture= bpy.data.add_texture(type)
+ texture.type= 'IMAGE'
+# texture= bpy.data.textures.new(type)
+# texture.setType('Image')
# Absolute path - c:\.. etc would work here
image= obj_image_load(imagepath, DIR, IMAGE_SEARCH)
- has_data = image.has_data
- texture.image = image
+ has_data = image.has_data if image else False
- if not has_data:
- try:
- # first time using this image. We need to load it first
- image.glLoad()
- except:
- # probably the image is crashed
- pass
- else:
- has_data = image.has_data
+ if image:
+ texture.image = image
# Adds textures for materials (rendering)
if type == 'Kd':
if has_data and image.depth == 32:
# Image has alpha
- blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA)
- texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha')
- blender_material.mode |= Material.Modes.ZTRANSP
+
+ # XXX bitmask won't work?
+ blender_material.add_texture(texture, "UV", ("COLOR", "ALPHA"))
+ texture.mipmap = True
+ texture.interpolation = True
+ texture.use_alpha = True
+ blender_material.z_transparency = True
blender_material.alpha = 0.0
+
+# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL | Texture.MapTo.ALPHA)
+# texture.setImageFlags('MipMap', 'InterPol', 'UseAlpha')
+# blender_material.mode |= Material.Modes.ZTRANSP
+# blender_material.alpha = 0.0
else:
- blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL)
+ blender_material.add_texture(texture, "UV", "COLOR")
+# blender_material.setTexture(0, texture, Texture.TexCo.UV, Texture.MapTo.COL)
# adds textures to faces (Textured/Alt-Z mode)
# Only apply the diffuse texture to the face if the image has not been set with the inline usemat func.
unique_material_images[context_material_name]= image, has_data # set the texface image
elif type == 'Ka':
- blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API
+ blender_material.add_texture(texture, "UV", "AMBIENT")
+# blender_material.setTexture(1, texture, Texture.TexCo.UV, Texture.MapTo.CMIR) # TODO- Add AMB to BPY API
elif type == 'Ks':
- blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC)
+ blender_material.add_texture(texture, "UV", "SPECULARITY")
+# blender_material.setTexture(2, texture, Texture.TexCo.UV, Texture.MapTo.SPEC)
elif type == 'Bump':
- blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR)
+ blender_material.add_texture(texture, "UV", "NORMAL")
+# blender_material.setTexture(3, texture, Texture.TexCo.UV, Texture.MapTo.NOR)
elif type == 'D':
- blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA)
- blender_material.mode |= Material.Modes.ZTRANSP
+ blender_material.add_texture(texture, "UV", "ALPHA")
+ blender_material.z_transparency = True
blender_material.alpha = 0.0
+# blender_material.setTexture(4, texture, Texture.TexCo.UV, Texture.MapTo.ALPHA)
+# blender_material.mode |= Material.Modes.ZTRANSP
+# blender_material.alpha = 0.0
# Todo, unset deffuse material alpha if it has an alpha channel
elif type == 'refl':
- blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF)
+ blender_material.add_texture(texture, "UV", "REFLECTION")
+# blender_material.setTexture(5, texture, Texture.TexCo.UV, Texture.MapTo.REF)
# Add an MTL with the same name as the obj if no MTLs are spesified.
temp_mtl= stripExt(stripPath(filepath))+ '.mtl'
-
- if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs:
- material_libs.append( temp_mtl )
+
+ if os.path.exists(DIR + temp_mtl) and temp_mtl not in material_libs:
+# if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs:
+ material_libs.append( temp_mtl )
del temp_mtl
#Create new materials
for name in unique_materials: # .keys()
if name != None:
- unique_materials[name]= bpy.data.materials.new(name)
+ unique_materials[name]= bpy.data.add_material(name)
+# unique_materials[name]= bpy.data.materials.new(name)
unique_material_images[name]= None, False # assign None to all material images to start with, add to later.
unique_materials[None]= None
@@ -187,7 +438,8 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
for libname in material_libs:
mtlpath= DIR + libname
- if not sys.exists(mtlpath):
+ if not os.path.exists(mtlpath):
+# if not sys.exists(mtlpath):
#print '\tError Missing MTL: "%s"' % mtlpath
pass
else:
@@ -197,7 +449,7 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
for line in mtl: #.xreadlines():
if line.startswith('newmtl'):
context_material_name= line_value(line.split())
- if unique_materials.has_key(context_material_name):
+ if context_material_name in unique_materials:
context_material = unique_materials[ context_material_name ]
else:
context_material = None
@@ -207,18 +459,23 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
line_split= line.split()
line_lower= line.lower().lstrip()
if line_lower.startswith('ka'):
- context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
+ context_material.mirror_color = (float(line_split[1]), float(line_split[2]), float(line_split[3]))
+# context_material.setMirCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
elif line_lower.startswith('kd'):
- context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
+ context_material.diffuse_color = (float(line_split[1]), float(line_split[2]), float(line_split[3]))
+# context_material.setRGBCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
elif line_lower.startswith('ks'):
- context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
+ context_material.specular_color = (float(line_split[1]), float(line_split[2]), float(line_split[3]))
+# context_material.setSpecCol((float(line_split[1]), float(line_split[2]), float(line_split[3])))
elif line_lower.startswith('ns'):
- context_material.setHardness( int((float(line_split[1])*0.51)) )
+ context_material.specular_hardness = int((float(line_split[1])*0.51))
+# context_material.setHardness( int((float(line_split[1])*0.51)) )
elif line_lower.startswith('ni'): # Refraction index
- context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3
+ context_material.ior = max(1, min(float(line_split[1]), 3))
+# context_material.setIOR( max(1, min(float(line_split[1]), 3))) # Between 1 and 3
elif line_lower.startswith('d') or line_lower.startswith('tr'):
- context_material.setAlpha(float(line_split[1]))
- context_material.mode |= Material.Modes.ZTRANSP
+ context_material.alpha = float(line_split[1])
+# context_material.setAlpha(float(line_split[1]))
elif line_lower.startswith('map_ka'):
img_filepath= line_value(line.split())
if img_filepath:
@@ -322,14 +579,14 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP,
face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index
matname= face[2]
- if matname and not unique_materials_split.has_key(matname):
+ if matname and matname not in unique_materials_split:
unique_materials_split[matname] = unique_materials[matname]
faces_split.append(face)
# remove one of the itemas and reorder
- return [(value[0], value[1], value[2], key_to_name(key)) for key, value in face_split_dict.iteritems()]
+ return [(value[0], value[1], value[2], key_to_name(key)) for key, value in list(face_split_dict.items())]
def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname):
@@ -342,7 +599,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if unique_smooth_groups:
sharp_edges= {}
- smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in unique_smooth_groups.iterkeys() ])
+ smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in list(unique_smooth_groups.keys()) ])
context_smooth_group_old= -1
# Split fgons into tri's
@@ -353,7 +610,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
context_object= None
# reverse loop through face indicies
- for f_idx in xrange(len(faces)-1, -1, -1):
+ for f_idx in range(len(faces)-1, -1, -1):
face_vert_loc_indicies,\
face_vert_tex_indicies,\
@@ -370,7 +627,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if CREATE_EDGES:
# generators are better in python 2.4+ but can't be used in 2.3
# edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) )
- edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1)] )
+ edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in range(len_face_vert_loc_indicies-1)] )
faces.pop(f_idx)
else:
@@ -382,7 +639,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
edge_dict= smooth_group_users[context_smooth_group]
context_smooth_group_old= context_smooth_group
- for i in xrange(len_face_vert_loc_indicies):
+ for i in range(len_face_vert_loc_indicies):
i1= face_vert_loc_indicies[i]
i2= face_vert_loc_indicies[i-1]
if i1>i2: i1,i2= i2,i1
@@ -395,7 +652,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
# FGons into triangles
if has_ngons and len_face_vert_loc_indicies > 4:
- ngon_face_indices= BPyMesh.ngon(verts_loc, face_vert_loc_indicies)
+ ngon_face_indices= BPyMesh_ngon(verts_loc, face_vert_loc_indicies)
faces.extend(\
[(\
[face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],\
@@ -420,7 +677,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
except KeyError:
edge_users[i1,i2]= 1
- for key, users in edge_users.iteritems():
+ for key, users in edge_users.items():
if users>1:
fgon_edges[key]= None
@@ -430,8 +687,8 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
# Build sharp edges
if unique_smooth_groups:
- for edge_dict in smooth_group_users.itervalues():
- for key, users in edge_dict.iteritems():
+ for edge_dict in list(smooth_group_users.values()):
+ for key, users in list(edge_dict.items()):
if users==1: # This edge is on the boundry of a group
sharp_edges[key]= None
@@ -441,25 +698,39 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
materials= [None] * len(unique_materials)
- for name, index in material_mapping.iteritems():
+ for name, index in list(material_mapping.items()):
materials[index]= unique_materials[name]
-
- me= bpy.data.meshes.new(dataname)
-
- me.materials= materials[0:16] # make sure the list isnt too big.
+
+ me= bpy.data.add_mesh(dataname)
+# me= bpy.data.meshes.new(dataname)
+
+ # make sure the list isnt too big
+ for material in materials[0:16]:
+ me.add_material(material)
+# me.materials= materials[0:16] # make sure the list isnt too big.
#me.verts.extend([(0,0,0)]) # dummy vert
- me.verts.extend(verts_loc)
-
- face_mapping= me.faces.extend([f[0] for f in faces], indexList=True)
+
+ me.add_geometry(len(verts_loc), 0, len(faces))
+
+ # verts_loc is a list of (x, y, z) tuples
+ me.verts.foreach_set("co", unpack_list(verts_loc))
+# me.verts.extend(verts_loc)
+
+ # faces is a list of (vert_indices, texco_indices, ...) tuples
+ # XXX faces should contain either 3 or 4 verts
+ # XXX no check for valid face indices
+ me.faces.foreach_set("verts_raw", unpack_face_list([f[0] for f in faces]))
+# face_mapping= me.faces.extend([f[0] for f in faces], indexList=True)
if verts_tex and me.faces:
- me.faceUV= 1
+ me.add_uv_texture()
+# me.faceUV= 1
# TEXMODE= Mesh.FaceModes['TEX']
context_material_old= -1 # avoid a dict lookup
mat= 0 # rare case it may be un-initialized.
me_faces= me.faces
- ALPHA= Mesh.FaceTranspModes.ALPHA
+# ALPHA= Mesh.FaceTranspModes.ALPHA
for i, face in enumerate(faces):
if len(face[0]) < 2:
@@ -468,9 +739,14 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if CREATE_EDGES:
edges.append(face[0])
else:
- face_index_map= face_mapping[i]
- if face_index_map!=None: # None means the face wasnt added
- blender_face= me_faces[face_index_map]
+# face_index_map= face_mapping[i]
+
+ # since we use foreach_set to add faces, all of them are added
+ if 1:
+# if face_index_map!=None: # None means the face wasnt added
+
+ blender_face = me.faces[i]
+# blender_face= me_faces[face_index_map]
face_vert_loc_indicies,\
face_vert_tex_indicies,\
@@ -489,17 +765,24 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if mat>15:
mat= 15
context_material_old= context_material
-
- blender_face.mat= mat
+
+ blender_face.material_index= mat
+# blender_face.mat= mat
- if verts_tex:
+ if verts_tex:
+
+ blender_tface= me.uv_textures[0].data[i]
+
if context_material:
image, has_data= unique_material_images[context_material]
if image: # Can be none if the material dosnt have an image.
- blender_face.image= image
- if has_data and image.depth == 32:
- blender_face.transp |= ALPHA
+ blender_tface.image= image
+# blender_face.image= image
+ if has_data:
+# if has_data and image.depth == 32:
+ blender_tface.transp = 'ALPHA'
+# blender_face.transp |= ALPHA
# BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled.
if len(face_vert_loc_indicies)==4:
@@ -511,43 +794,80 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
# END EEEKADOODLE FIX
# assign material, uv's and image
- for ii, uv in enumerate(blender_face.uv):
- uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]]
+ blender_tface.uv1= verts_tex[face_vert_tex_indicies[0]]
+ blender_tface.uv2= verts_tex[face_vert_tex_indicies[1]]
+ blender_tface.uv3= verts_tex[face_vert_tex_indicies[2]]
+
+ if blender_face.verts[3] != 0:
+ blender_tface.uv4= verts_tex[face_vert_tex_indicies[3]]
+
+# for ii, uv in enumerate(blender_face.uv):
+# uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]]
del me_faces
- del ALPHA
-
- # Add edge faces.
- me_edges= me.edges
- if CREATE_FGONS and fgon_edges:
- FGON= Mesh.EdgeFlags.FGON
- for ed in me.findEdges( fgon_edges.keys() ):
- if ed!=None:
- me_edges[ed].flag |= FGON
- del FGON
-
- if unique_smooth_groups and sharp_edges:
- SHARP= Mesh.EdgeFlags.SHARP
- for ed in me.findEdges( sharp_edges.keys() ):
- if ed!=None:
- me_edges[ed].flag |= SHARP
- del SHARP
-
+# del ALPHA
+
if CREATE_EDGES:
- me_edges.extend( edges )
+
+ me.add_geometry(0, len(edges), 0)
+
+ # edges should be a list of (a, b) tuples
+ me.edges.foreach_set("verts", unpack_list(edges))
+# me_edges.extend( edges )
- del me_edges
+# del me_edges
- me.calcNormals()
+ # Add edge faces.
+# me_edges= me.edges
+
+ def edges_match(e1, e2):
+ return (e1[0] == e2[0] and e1[1] == e2[1]) or (e1[0] == e2[1] and e1[1] == e2[0])
+
+ # XXX slow
+# if CREATE_FGONS and fgon_edges:
+# for fgon_edge in fgon_edges.keys():
+# for ed in me.edges:
+# if edges_match(fgon_edge, ed.verts):
+# ed.fgon = True
+
+# if CREATE_FGONS and fgon_edges:
+# FGON= Mesh.EdgeFlags.FGON
+# for ed in me.findEdges( fgon_edges.keys() ):
+# if ed!=None:
+# me_edges[ed].flag |= FGON
+# del FGON
+
+ # XXX slow
+# if unique_smooth_groups and sharp_edges:
+# for sharp_edge in sharp_edges.keys():
+# for ed in me.edges:
+# if edges_match(sharp_edge, ed.verts):
+# ed.sharp = True
+
+# if unique_smooth_groups and sharp_edges:
+# SHARP= Mesh.EdgeFlags.SHARP
+# for ed in me.findEdges( sharp_edges.keys() ):
+# if ed!=None:
+# me_edges[ed].flag |= SHARP
+# del SHARP
+
+ me.update()
+# me.calcNormals()
- ob= scn.objects.new(me)
+ ob= bpy.data.add_object("MESH", "Mesh")
+ ob.data= me
+ scn.add_object(ob)
+# ob= scn.objects.new(me)
new_objects.append(ob)
# Create the vertex groups. No need to have the flag passed here since we test for the
# content of the vertex_groups. If the user selects to NOT have vertex groups saved then
# the following test will never run
- for group_name, group_indicies in vertex_groups.iteritems():
- me.addVertGroup(group_name)
- me.assignVertsToGroup(group_name, group_indicies,1.00, Mesh.AssignModes.REPLACE)
+ for group_name, group_indicies in vertex_groups.items():
+ group= ob.add_vertex_group(group_name)
+# me.addVertGroup(group_name)
+ for vertex_index in group_indicies:
+ ob.add_vertex_to_group(vertex_index, group, 1.0, 'REPLACE')
+# me.assignVertsToGroup(group_name, group_indicies, 1.00, Mesh.AssignModes.REPLACE)
def create_nurbs(scn, context_nurbs, vert_loc, new_objects):
@@ -563,16 +883,16 @@ def create_nurbs(scn, context_nurbs, vert_loc, new_objects):
cstype = context_nurbs.get('cstype', None)
if cstype == None:
- print '\tWarning, cstype not found'
+ print('\tWarning, cstype not found')
return
if cstype != 'bspline':
- print '\tWarning, cstype is not supported (only bspline)'
+ print('\tWarning, cstype is not supported (only bspline)')
return
if not curv_idx:
- print '\tWarning, curv argument empty or not set'
+ print('\tWarning, curv argument empty or not set')
return
if len(deg) > 1 or parm_v:
- print '\tWarning, surfaces not supported'
+ print('\tWarning, surfaces not supported')
return
cu = bpy.data.curves.new(name, 'Curve')
@@ -594,7 +914,7 @@ def create_nurbs(scn, context_nurbs, vert_loc, new_objects):
# get for endpoint flag from the weighting
if curv_range and len(parm_u) > deg[0]+1:
do_endpoints = True
- for i in xrange(deg[0]+1):
+ for i in range(deg[0]+1):
if abs(parm_u[i]-curv_range[0]) > 0.0001:
do_endpoints = False
@@ -659,28 +979,30 @@ def get_float_func(filepath):
return float
def load_obj(filepath,
- CLAMP_SIZE= 0.0,
- CREATE_FGONS= True,
- CREATE_SMOOTH_GROUPS= True,
- CREATE_EDGES= True,
- SPLIT_OBJECTS= True,
- SPLIT_GROUPS= True,
- SPLIT_MATERIALS= True,
- ROTATE_X90= True,
- IMAGE_SEARCH=True,
- POLYGROUPS=False):
+ context,
+ CLAMP_SIZE= 0.0,
+ CREATE_FGONS= True,
+ CREATE_SMOOTH_GROUPS= True,
+ CREATE_EDGES= True,
+ SPLIT_OBJECTS= True,
+ SPLIT_GROUPS= True,
+ SPLIT_MATERIALS= True,
+ ROTATE_X90= True,
+ IMAGE_SEARCH=True,
+ POLYGROUPS=False):
'''
Called by the user interface or another script.
load_obj(path) - should give acceptable results.
This function passes the file and sends the data off
to be split into objects and then converted into mesh objects
'''
- print '\nimporting obj "%s"' % filepath
+ print('\nimporting obj "%s"' % filepath)
if SPLIT_OBJECTS or SPLIT_GROUPS or SPLIT_MATERIALS:
POLYGROUPS = False
-
- time_main= sys.time()
+
+ time_main= time.time()
+# time_main= sys.time()
verts_loc= []
verts_tex= []
@@ -717,8 +1039,9 @@ def load_obj(filepath,
# so we need to know weather
context_multi_line= ''
- print '\tparsing obj file "%s"...' % filepath,
- time_sub= sys.time()
+ print('\tparsing obj file "%s"...' % filepath)
+ time_sub= time.time()
+# time_sub= sys.time()
file= open(filepath, 'rU')
for line in file: #.xreadlines():
@@ -926,70 +1249,77 @@ def load_obj(filepath,
'''
file.close()
- time_new= sys.time()
- print '%.4f sec' % (time_new-time_sub)
+ time_new= time.time()
+# time_new= sys.time()
+ print('%.4f sec' % (time_new-time_sub))
time_sub= time_new
- print '\tloading materials and images...',
+ print('\tloading materials and images...')
create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH)
-
- time_new= sys.time()
- print '%.4f sec' % (time_new-time_sub)
+
+ time_new= time.time()
+# time_new= sys.time()
+ print('%.4f sec' % (time_new-time_sub))
time_sub= time_new
if not ROTATE_X90:
verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc]
# deselect all
- scn = bpy.data.scenes.active
- scn.objects.selected = []
+# if context.selected_objects:
+# bpy.ops.OBJECT_OT_select_all_toggle()
+
+ scene = context.scene
+# scn = bpy.data.scenes.active
+# scn.objects.selected = []
new_objects= [] # put new objects here
- print '\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ),
+ print('\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ))
# Split the mesh by objects/materials, may
if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True
else: SPLIT_OB_OR_GROUP = False
for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP, SPLIT_MATERIALS):
# Create meshes from the data, warning 'vertex_groups' wont support splitting
- create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname)
+ create_mesh(scene, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname)
# nurbs support
- for context_nurbs in nurbs:
- create_nurbs(scn, context_nurbs, verts_loc, new_objects)
+# for context_nurbs in nurbs:
+# create_nurbs(scn, context_nurbs, verts_loc, new_objects)
axis_min= [ 1000000000]*3
axis_max= [-1000000000]*3
- if CLAMP_SIZE:
- # Get all object bounds
- for ob in new_objects:
- for v in ob.getBoundBox():
- for axis, value in enumerate(v):
- if axis_min[axis] > value: axis_min[axis]= value
- if axis_max[axis] < value: axis_max[axis]= value
+# if CLAMP_SIZE:
+# # Get all object bounds
+# for ob in new_objects:
+# for v in ob.getBoundBox():
+# for axis, value in enumerate(v):
+# if axis_min[axis] > value: axis_min[axis]= value
+# if axis_max[axis] < value: axis_max[axis]= value
- # Scale objects
- max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2])
- scale= 1.0
+# # Scale objects
+# max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2])
+# scale= 1.0
- while CLAMP_SIZE < max_axis * scale:
- scale= scale/10.0
+# while CLAMP_SIZE < max_axis * scale:
+# scale= scale/10.0
- for ob in new_objects:
- ob.setSize(scale, scale, scale)
+# for ob in new_objects:
+# ob.setSize(scale, scale, scale)
# Better rotate the vert locations
#if not ROTATE_X90:
# for ob in new_objects:
# ob.RotX = -1.570796326794896558
+
+ time_new= time.time()
+# time_new= sys.time()
- time_new= sys.time()
-
- print '%.4f sec' % (time_new-time_sub)
- print 'finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main))
+ print('%.4f sec' % (time_new-time_sub))
+ print('finished importing: "%s" in %.4f sec.' % (filepath, (time_new-time_main)))
DEBUG= True
@@ -1082,14 +1412,14 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
def do_help(e,v):
url = __url__[0]
- 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:
- print '...could not open a browser window.'
+ print('...could not open a browser window.')
def obj_ui():
ui_x, ui_y = GLOBALS['MOUSE']
@@ -1199,11 +1529,11 @@ def load_obj_ui_batch(file):
DEBUG= False
-if __name__=='__main__' and not DEBUG:
- if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT:
- Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '')
- else:
- Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj')
+# if __name__=='__main__' and not DEBUG:
+# if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT:
+# Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '')
+# else:
+# Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj')
# For testing compatibility
'''
@@ -1232,3 +1562,77 @@ else:
'''
#load_obj('/test.obj')
#load_obj('/fe/obj/mba1.obj')
+
+
+
+class IMPORT_OT_obj(bpy.types.Operator):
+ '''
+ Operator documentation text, will be used for the operator tooltip and python docs.
+ '''
+ __idname__ = "import.obj"
+ __label__ = "Import 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 importing the OBJ file", maxlen= 1024, default= ""),
+
+ bpy.props.BoolProperty(attr="CREATE_SMOOTH_GROUPS", name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True),
+ bpy.props.BoolProperty(attr="CREATE_FGONS", name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True),
+ bpy.props.BoolProperty(attr="CREATE_EDGES", name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True),
+ bpy.props.BoolProperty(attr="SPLIT_OBJECTS", name="Object", description="Import OBJ Objects into Blender Objects", default= True),
+ bpy.props.BoolProperty(attr="SPLIT_GROUPS", name="Group", description="Import OBJ Groups into Blender Objects", default= True),
+ bpy.props.BoolProperty(attr="SPLIT_MATERIALS", name="Material", description="Import each material into a seperate mesh (Avoids > 16 per mesh error)", default= True),
+ # old comment: only used for user feedback
+ # disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj
+ # bpy.props.BoolProperty(attr="KEEP_VERT_ORDER", name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True),
+ bpy.props.BoolProperty(attr="ROTATE_X90", name="-X90", description="Rotate X 90.", default= True),
+ bpy.props.FloatProperty(attr="CLAMP_SIZE", name="Clamp Scale", description="Clamp the size to this maximum (Zero to Disable)", min=0.01, max=1000.0, soft_min=0.0, soft_max=1000.0, default=0.0),
+ bpy.props.BoolProperty(attr="POLYGROUPS", name="Poly Groups", description="Import OBJ groups as vertex groups.", default= True),
+ bpy.props.BoolProperty(attr="IMAGE_SEARCH", name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True),
+ ]
+
+ '''
+ def poll(self, context):
+ return True '''
+
+ def execute(self, context):
+ # print("Selected: " + context.active_object.name)
+
+ load_obj(self.path,
+ context,
+ self.CLAMP_SIZE,
+ self.CREATE_FGONS,
+ self.CREATE_SMOOTH_GROUPS,
+ self.CREATE_EDGES,
+ self.SPLIT_OBJECTS,
+ self.SPLIT_GROUPS,
+ self.SPLIT_MATERIALS,
+ self.ROTATE_X90,
+ self.IMAGE_SEARCH,
+ self.POLYGROUPS)
+
+ return ('FINISHED',)
+
+ def invoke(self, context, event):
+ wm = context.manager
+ wm.add_fileselect(self.__operator__)
+ return ('RUNNING_MODAL',)
+
+
+bpy.ops.add(IMPORT_OT_obj)
+
+
+# NOTES (all line numbers refer to 2.4x import_obj.py, not this file)
+# check later: line 489
+# can convert now: edge flags, edges: lines 508-528
+# ngon (uses python module BPyMesh): 384-414
+# nurbs: 947-
+# NEXT clamp size: get bound box with RNA
+# get back to l 140 (here)
+# search image in bpy.config.textureDir - load_image
+# replaced BPyImage.comprehensiveImageLoad with a simplified version that only checks additional directory specified, but doesn't search dirs recursively (obj_image_load)
+# bitmask won't work? - 132
+# uses operator bpy.ops.OBJECT_OT_select_all_toggle() to deselect all (not necessary?)
+# uses bpy.sys.time()