FBX exporter conversion almost done.
Unit tests: - add a check that BKE_copy_images produces NULL filepath for images having type other than IMA_TYPE_IMAGE - also expect NULL filepath for images having empty filename Enhanced BKE_copy_images so the tests pass.
This commit is contained in:
@@ -297,6 +297,29 @@ def BPyMesh_meshWeight2List(ob):
|
|||||||
return groupNames, vWeightList
|
return groupNames, vWeightList
|
||||||
|
|
||||||
|
|
||||||
|
def BPyMesh_meshWeight2Dict(me, ob):
|
||||||
|
''' Takes a mesh and return its group names and a list of dicts, one dict per vertex.
|
||||||
|
using the group as a key and a float value for the weight.
|
||||||
|
These 2 lists can be modified and then used with dict2MeshWeight to apply the changes.
|
||||||
|
'''
|
||||||
|
|
||||||
|
vWeightDict= [dict() for i in xrange(len(me.verts))] # Sync with vertlist.
|
||||||
|
|
||||||
|
# Clear the vert group.
|
||||||
|
groupNames= [g.name for g in ob.vertex_groups]
|
||||||
|
# groupNames= me.getVertGroupNames()
|
||||||
|
|
||||||
|
for group in groupNames:
|
||||||
|
for vert_index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples.
|
||||||
|
vWeightDict[vert_index][group]= weight
|
||||||
|
|
||||||
|
# removed this because me may be copying teh vertex groups.
|
||||||
|
#for group in groupNames:
|
||||||
|
# me.removeVertGroup(group)
|
||||||
|
|
||||||
|
return groupNames, vWeightDict
|
||||||
|
|
||||||
|
|
||||||
def meshNormalizedWeights(me):
|
def meshNormalizedWeights(me):
|
||||||
try: # account for old bad BPyMesh
|
try: # account for old bad BPyMesh
|
||||||
groupNames, vWeightList = BPyMesh_meshWeight2List(me)
|
groupNames, vWeightList = BPyMesh_meshWeight2List(me)
|
||||||
@@ -1498,7 +1521,7 @@ def write(filename, batch_objects = None, \
|
|||||||
if my_mesh.blenTextures: do_textures = True
|
if my_mesh.blenTextures: do_textures = True
|
||||||
else: do_textures = False
|
else: do_textures = False
|
||||||
|
|
||||||
do_uvs = len(me.uv_layers) > 0
|
do_uvs = len(me.uv_textures) > 0
|
||||||
# do_uvs = me.faceUV
|
# do_uvs = me.faceUV
|
||||||
|
|
||||||
|
|
||||||
@@ -2073,8 +2096,9 @@ def write(filename, batch_objects = None, \
|
|||||||
origData = True
|
origData = True
|
||||||
if tmp_ob_type != 'MESH':
|
if tmp_ob_type != 'MESH':
|
||||||
# if tmp_ob_type != 'Mesh':
|
# if tmp_ob_type != 'Mesh':
|
||||||
me = bpy.data.meshes.new()
|
# me = bpy.data.meshes.new()
|
||||||
try: me.getFromObject(ob)
|
try: me = ob.create_mesh(True, 'PREVIEW')
|
||||||
|
# try: me.getFromObject(ob)
|
||||||
except: me = None
|
except: me = None
|
||||||
if me:
|
if me:
|
||||||
meshes_to_clear.append( me )
|
meshes_to_clear.append( me )
|
||||||
@@ -2084,65 +2108,70 @@ def write(filename, batch_objects = None, \
|
|||||||
# Mesh Type!
|
# Mesh Type!
|
||||||
if EXP_MESH_APPLY_MOD:
|
if EXP_MESH_APPLY_MOD:
|
||||||
# me = bpy.data.meshes.new()
|
# me = bpy.data.meshes.new()
|
||||||
me = ob.create_mesh('PREVIEW')
|
me = ob.create_mesh(True, 'PREVIEW')
|
||||||
# me.getFromObject(ob)
|
# me.getFromObject(ob)
|
||||||
|
|
||||||
# so we keep the vert groups
|
# so we keep the vert groups
|
||||||
if EXP_ARMATURE:
|
# if EXP_ARMATURE:
|
||||||
orig_mesh = ob.data
|
|
||||||
# orig_mesh = ob.getData(mesh=1)
|
# orig_mesh = ob.getData(mesh=1)
|
||||||
if len(ob.vertex_groups):
|
|
||||||
# if orig_mesh.getVertGroupNames():
|
# if orig_mesh.getVertGroupNames():
|
||||||
ob.copy().link(me)
|
# ob.copy().link(me)
|
||||||
# If new mesh has no vgroups we can try add if verts are teh same
|
# # 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 not me.getVertGroupNames(): # vgroups were not kept by the modifier
|
||||||
if len(me.verts) == len(orig_mesh.verts):
|
# if len(me.verts) == len(orig_mesh.verts):
|
||||||
groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh)
|
# groupNames, vWeightDict = BPyMesh.meshWeight2Dict(orig_mesh)
|
||||||
BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
|
# BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
|
||||||
|
|
||||||
# print ob, me, me.getVertGroupNames()
|
# print ob, me, me.getVertGroupNames()
|
||||||
meshes_to_clear.append( me )
|
meshes_to_clear.append( me )
|
||||||
origData = False
|
origData = False
|
||||||
mats = me.materials
|
mats = me.materials
|
||||||
else:
|
else:
|
||||||
me = ob.getData(mesh=1)
|
me = ob.data
|
||||||
|
# me = ob.getData(mesh=1)
|
||||||
mats = me.materials
|
mats = me.materials
|
||||||
|
|
||||||
# Support object colors
|
# # Support object colors
|
||||||
tmp_colbits = ob.colbits
|
# tmp_colbits = ob.colbits
|
||||||
if tmp_colbits:
|
# if tmp_colbits:
|
||||||
tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too.
|
# tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too.
|
||||||
for i in xrange(16):
|
# for i in xrange(16):
|
||||||
if tmp_colbits & (1<<i):
|
# if tmp_colbits & (1<<i):
|
||||||
mats[i] = tmp_ob_mats[i]
|
# mats[i] = tmp_ob_mats[i]
|
||||||
del tmp_ob_mats
|
# del tmp_ob_mats
|
||||||
del tmp_colbits
|
# del tmp_colbits
|
||||||
|
|
||||||
|
|
||||||
if me:
|
if me:
|
||||||
# This WILL modify meshes in blender if EXP_MESH_APPLY_MOD is disabled.
|
# # 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
|
# # 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
|
# # say with dupliverts the objects would rotate a bit differently
|
||||||
if EXP_MESH_HQ_NORMALS:
|
# if EXP_MESH_HQ_NORMALS:
|
||||||
BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
|
# BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
|
||||||
|
|
||||||
texture_mapping_local = {}
|
texture_mapping_local = {}
|
||||||
material_mapping_local = {}
|
material_mapping_local = {}
|
||||||
if me.faceUV:
|
if len(me.uv_textures) > 0:
|
||||||
uvlayer_orig = me.activeUVLayer
|
# if me.faceUV:
|
||||||
for uvlayer in me.getUVLayerNames():
|
uvlayer_orig = me.active_uv_texture
|
||||||
me.activeUVLayer = uvlayer
|
# uvlayer_orig = me.activeUVLayer
|
||||||
for f in me.faces:
|
for uvlayer in me.uv_textures:
|
||||||
tex = f.image
|
# 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
|
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
|
except: mat = None
|
||||||
|
|
||||||
materials[mat, tex] = material_mapping_local[mat, tex] = None # should use sets, wait for blender 2.5
|
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:
|
else:
|
||||||
for mat in mats:
|
for mat in mats:
|
||||||
# 2.44 use mat.lib too for uniqueness
|
# 2.44 use mat.lib too for uniqueness
|
||||||
@@ -2155,9 +2184,12 @@ def write(filename, batch_objects = None, \
|
|||||||
blenParentBoneName = None
|
blenParentBoneName = None
|
||||||
|
|
||||||
# parent bone - special case
|
# 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
|
armob = ob.parent
|
||||||
blenParentBoneName = ob.parentbonename
|
blenParentBoneName = ob.parent_bone
|
||||||
|
# blenParentBoneName = ob.parentbonename
|
||||||
|
|
||||||
|
|
||||||
if armob and armob not in ob_arms:
|
if armob and armob not in ob_arms:
|
||||||
@@ -2181,7 +2213,11 @@ def write(filename, batch_objects = None, \
|
|||||||
my_mesh.fbxBoneParent = blenParentBoneName # replace with my_bone instance later
|
my_mesh.fbxBoneParent = blenParentBoneName # replace with my_bone instance later
|
||||||
|
|
||||||
ob_meshes.append( my_mesh )
|
ob_meshes.append( my_mesh )
|
||||||
|
|
||||||
|
# not forgetting to free dupli_list
|
||||||
|
if ob_base.dupli_list: ob_base.free_dupli_list()
|
||||||
|
|
||||||
|
|
||||||
if EXP_ARMATURE:
|
if EXP_ARMATURE:
|
||||||
# now we have the meshes, restore the rest arm position
|
# now we have the meshes, restore the rest arm position
|
||||||
for i, arm in enumerate(bpy.data.armatures):
|
for i, arm in enumerate(bpy.data.armatures):
|
||||||
@@ -2217,7 +2253,8 @@ def write(filename, batch_objects = None, \
|
|||||||
# fbxName, blenderObject, my_bones, blenderActions
|
# fbxName, blenderObject, my_bones, blenderActions
|
||||||
#ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, [])
|
#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_bone = my_bone_class(bone, my_arm)
|
||||||
my_arm.fbxBones.append( my_bone )
|
my_arm.fbxBones.append( my_bone )
|
||||||
ob_bones.append( my_bone )
|
ob_bones.append( my_bone )
|
||||||
@@ -2662,7 +2699,8 @@ Connections: {''')
|
|||||||
|
|
||||||
|
|
||||||
# Needed for scene footer as well as animation
|
# Needed for scene footer as well as animation
|
||||||
render = sce.render
|
render = sce.render_data
|
||||||
|
# render = sce.render
|
||||||
|
|
||||||
# from the FBX sdk
|
# from the FBX sdk
|
||||||
#define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000))
|
#define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000))
|
||||||
@@ -2671,8 +2709,10 @@ Connections: {''')
|
|||||||
return int(0.5 + ((t/fps) * 46186158000))
|
return int(0.5 + ((t/fps) * 46186158000))
|
||||||
|
|
||||||
fps = float(render.fps)
|
fps = float(render.fps)
|
||||||
start = render.sFrame
|
start = sce.start_frame
|
||||||
end = render.eFrame
|
# start = render.sFrame
|
||||||
|
end = sce.end_frame
|
||||||
|
# end = render.eFrame
|
||||||
if end < start: start, end = end, start
|
if end < start: start, end = end, start
|
||||||
if start==end: ANIM_ENABLE = False
|
if start==end: ANIM_ENABLE = False
|
||||||
|
|
||||||
@@ -2959,8 +2999,6 @@ Takes: {''')
|
|||||||
bpy.data.remove_mesh(me)
|
bpy.data.remove_mesh(me)
|
||||||
# me.verts = None
|
# me.verts = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------- Footer
|
# --------------------------- Footer
|
||||||
if world:
|
if world:
|
||||||
m = world.mist
|
m = world.mist
|
||||||
@@ -3025,7 +3063,8 @@ Takes: {''')
|
|||||||
if EXP_IMAGE_COPY:
|
if EXP_IMAGE_COPY:
|
||||||
copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ])
|
copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ])
|
||||||
|
|
||||||
print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time)
|
print 'export finished in %.4f sec.' % (bpy.sys.time() - start_time)
|
||||||
|
# print 'export finished in %.4f sec.' % (Blender.sys.time() - start_time)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -3338,11 +3377,14 @@ if __name__ == '__main__':
|
|||||||
# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts)
|
# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts)
|
||||||
# - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print
|
# - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print
|
||||||
# - get rid of cleanName somehow
|
# - get rid of cleanName somehow
|
||||||
# - isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565
|
# + fixed: isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565
|
||||||
# - get rid of BPyObject_getObjectArmature, move it in RNA?
|
# - get rid of BPyObject_getObjectArmature, move it in RNA?
|
||||||
# - BATCH_ENABLE and BATCH_GROUP options: line 327
|
# - BATCH_ENABLE and BATCH_GROUP options: line 327
|
||||||
# - implement all BPyMesh_* used here with RNA
|
# - implement all BPyMesh_* used here with RNA
|
||||||
# - getDerivedObjects is not fully replicated with .dupli* funcs
|
# - 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
|
# TODO
|
||||||
|
|
||||||
|
|||||||
@@ -2120,6 +2120,7 @@ void BKE_image_user_calc_imanr(ImageUser *iuser, int cfra, int fieldnr)
|
|||||||
Copy list of images to dest_dir.
|
Copy list of images to dest_dir.
|
||||||
|
|
||||||
paths is optional, if given, image paths for each image will be written in it.
|
paths is optional, if given, image paths for each image will be written in it.
|
||||||
|
It will also contain NULLs for images that cannot be copied.
|
||||||
If an image file doesn't exist, NULL is added in paths.
|
If an image file doesn't exist, NULL is added in paths.
|
||||||
|
|
||||||
Logic:
|
Logic:
|
||||||
@@ -2161,6 +2162,13 @@ void BKE_copy_images(ListBase *images, char *dest_dir, ListBase *paths)
|
|||||||
while (link) {
|
while (link) {
|
||||||
im= link->data;
|
im= link->data;
|
||||||
|
|
||||||
|
LinkData *ld = MEM_callocN(sizeof(LinkData), "PathLinkData");
|
||||||
|
ld->data= NULL;
|
||||||
|
BLI_addtail(paths, ld);
|
||||||
|
|
||||||
|
if (!strcmp(im->name, "") || im->type != IMA_TYPE_IMAGE)
|
||||||
|
goto next;
|
||||||
|
|
||||||
BLI_strncpy(path, im->name, sizeof(path));
|
BLI_strncpy(path, im->name, sizeof(path));
|
||||||
|
|
||||||
/* expand "//" in filename and get absolute path */
|
/* expand "//" in filename and get absolute path */
|
||||||
@@ -2169,16 +2177,8 @@ void BKE_copy_images(ListBase *images, char *dest_dir, ListBase *paths)
|
|||||||
/* in unit tests, we don't want to modify the filesystem */
|
/* in unit tests, we don't want to modify the filesystem */
|
||||||
#ifndef WITH_UNIT_TEST
|
#ifndef WITH_UNIT_TEST
|
||||||
/* proceed only if image file exists */
|
/* proceed only if image file exists */
|
||||||
if (!BLI_exists(path)) {
|
if (!BLI_exists(path))
|
||||||
|
goto next;
|
||||||
if (paths) {
|
|
||||||
LinkData *ld = MEM_callocN(sizeof(LinkData), "PathLinkData");
|
|
||||||
ld->data= NULL;
|
|
||||||
BLI_addtail(paths, ld);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* get the directory part */
|
/* get the directory part */
|
||||||
@@ -2219,17 +2219,17 @@ void BKE_copy_images(ListBase *images, char *dest_dir, ListBase *paths)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WITH_UNIT_TEST
|
#ifndef WITH_UNIT_TEST
|
||||||
BLI_copy_fileops(path, dest_path);
|
if (BLI_copy_fileops(path, dest_path) != 0)
|
||||||
|
goto next;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (paths) {
|
if (paths) {
|
||||||
LinkData *ld = MEM_callocN(sizeof(LinkData), "PathLinkData");
|
|
||||||
len= strlen(dest_path) + 1;
|
len= strlen(dest_path) + 1;
|
||||||
ld->data= MEM_callocN(len, "PathLinkData");
|
ld->data= MEM_callocN(len, "PathLinkData");
|
||||||
BLI_strncpy(ld->data, dest_path, len);
|
BLI_strncpy(ld->data, dest_path, len);
|
||||||
BLI_addtail(paths, ld);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next:
|
||||||
link= link->next;
|
link= link->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ void RNA_api_object(StructRNA *srna)
|
|||||||
RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
|
RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
|
||||||
RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers.");
|
RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers.");
|
||||||
RNA_def_property_flag(parm, PROP_REQUIRED);
|
RNA_def_property_flag(parm, PROP_REQUIRED);
|
||||||
parm= RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Mesh settings to apply.");
|
parm= RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply.");
|
||||||
RNA_def_property_flag(parm, PROP_REQUIRED);
|
RNA_def_property_flag(parm, PROP_REQUIRED);
|
||||||
parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export.");
|
parm= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export.");
|
||||||
RNA_def_function_return(func, parm);
|
RNA_def_function_return(func, parm);
|
||||||
|
|||||||
@@ -583,9 +583,8 @@ static PyObject *bpy_util_copy_images(PyObject *self, PyObject *args)
|
|||||||
|
|
||||||
/* convert filenames */
|
/* convert filenames */
|
||||||
ret= PyList_New(0);
|
ret= PyList_New(0);
|
||||||
len= BLI_countlist(paths);
|
|
||||||
|
|
||||||
for(link= paths->first, i= 0; link; link++, i++) {
|
for(link= paths->first; link; link= link->next) {
|
||||||
if (link->data) {
|
if (link->data) {
|
||||||
item= PyUnicode_FromString(link->data);
|
item= PyUnicode_FromString(link->data);
|
||||||
PyList_Append(ret, item);
|
PyList_Append(ret, item);
|
||||||
|
|||||||
Reference in New Issue
Block a user