BPyMessages - added "Save over" message for scripts to use, so as not to overwrite files.

import_obj - comments, docstring additions, cleanup.

OBJ export: -renamed export_obj
 faster edge exporting (use edges LOOSE flag rather then finding zero face user edges)
 check for file before overwriting
 use object iterators
This commit is contained in:
Campbell Barton 2006-09-25 05:12:37 +00:00
parent db7c3d3271
commit 7fce181d11
3 changed files with 66 additions and 48 deletions

@ -1,4 +1,4 @@
from Blender import Draw from Blender import Draw, sys
def Error_NoMeshSelected(): def Error_NoMeshSelected():
Draw.PupMenu('ERROR%t|No mesh objects selected') Draw.PupMenu('ERROR%t|No mesh objects selected')
def Error_NoMeshActive(): def Error_NoMeshActive():
@ -8,3 +8,11 @@ def Error_NoMeshUvSelected():
def Error_NoMeshUvActive(): def Error_NoMeshUvActive():
Draw.PupMenu('ERROR%t|Active object is not a mesh with texface') Draw.PupMenu('ERROR%t|Active object is not a mesh with texface')
def Warning_SaveOver(path):
'''Returns - True to save, False dont save'''
if sys.exists(sys.expandpath(path)):
ret= Draw.PupMenu('Save over%t|' + path)
if ret == -1:
return False
return True

@ -16,7 +16,10 @@ This script is an exporter to OBJ file format.
Usage: Usage:
Run this script from "File->Export" menu to export all meshes. Select the objects you wish to export and run this script from "File->Export" menu.
Selecting the default options from the popup box will be good in most cases.
All objects that can be represented as a mesh (mesh, curve, metaball, surface, text3d)
will be exported as mesh data.
""" """
@ -46,6 +49,7 @@ Run this script from "File->Export" menu to export all meshes.
import Blender import Blender
from Blender import Mesh, Scene, Window, sys, Image, Draw from Blender import Mesh, Scene, Window, sys, Image, Draw
import BPyMesh import BPyMesh
import BPyMessages
# Returns a tuple - path,extension. # Returns a tuple - path,extension.
# 'hello.obj' > ('hello', '.obj') # 'hello.obj' > ('hello', '.obj')
@ -68,9 +72,6 @@ def saneFilechars(name):
name = name.replace(ch, '_') name = name.replace(ch, '_')
return name return name
def sortPair(a,b):
return min(a,b), max(a,b)
global MTL_DICT global MTL_DICT
# A Dict of Materials # A Dict of Materials
@ -217,7 +218,7 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False):
file = open(filename, "w") file = open(filename, "w")
# Write Header # Write Header
file.write('# Blender v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )) file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
file.write('# www.blender3d.org\n') file.write('# www.blender3d.org\n')
# Tell the obj file what material file to use. # Tell the obj file what material file to use.
@ -380,7 +381,6 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False):
key = materialNames[min(f.mat,len(materialNames)-1)], None # No image, use None instead. key = materialNames[min(f.mat,len(materialNames)-1)], None # No image, use None instead.
#key = materialNames[f.mat], None # No image, use None instead. #key = materialNames[f.mat], None # No image, use None instead.
# CHECK FOR CONTEXT SWITCH # CHECK FOR CONTEXT SWITCH
if key == contextMat: if key == contextMat:
pass # Context alredy switched, dont do anythoing pass # Context alredy switched, dont do anythoing
@ -468,19 +468,10 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False):
# Write edges. # Write edges.
if EXPORT_EDGES: if EXPORT_EDGES:
edgeUsers = {} LOOSE= Mesh.EdgeFlags.LOOSE
for f in faces:
for i in xrange(len(f_v)):
faceEdgeVKey = sortPair(f_v[i].index, f_v[i-1].index)
# We dont realy need to keep count. Just that a face uses it
# so dont export.
edgeUsers[faceEdgeVKey] = 1
for ed in edges: for ed in edges:
edgeVKey = sortPair(ed.v1.index, ed.v2.index) if ed.flag & LOOSE:
if not edgeUsers.has_key(edgeVKey): # No users? Write the edge. file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts))
file.write('f %d %d\n' % (edgeVKey[0]+totverts, edgeVKey[1]+totverts))
# Make the indicies global rather then per mesh # Make the indicies global rather then per mesh
totverts += len(m.verts) totverts += len(m.verts)
@ -507,9 +498,6 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False):
def write_ui(filename): def write_ui(filename):
for s in Window.GetScreenInfo():
Window.QHandle(s['id'])
EXPORT_APPLY_MODIFIERS = Draw.Create(1) EXPORT_APPLY_MODIFIERS = Draw.Create(1)
EXPORT_ROTX90 = Draw.Create(1) EXPORT_ROTX90 = Draw.Create(1)
EXPORT_TRI = Draw.Create(0) EXPORT_TRI = Draw.Create(0)
@ -552,6 +540,7 @@ def write_ui(filename):
if not Draw.PupBlock('Export...', pup_block): if not Draw.PupBlock('Export...', pup_block):
return return
Window.EditMode(0)
Window.WaitCursor(1) Window.WaitCursor(1)
EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS.val
@ -594,7 +583,7 @@ def write_ui(filename):
# Export an animation? # Export an animation?
if EXPORT_ANIMATION: if EXPORT_ANIMATION:
scene_frames = range(context.startFrame(), context.endFrame()+1) # up to and including the end frame. scene_frames = xrange(context.startFrame(), context.endFrame()+1) # up to and including the end frame.
else: else:
scene_frames = [orig_frame] # Dont export an animation. scene_frames = [orig_frame] # Dont export an animation.
@ -605,12 +594,15 @@ def write_ui(filename):
Blender.Set('curframe', frame) Blender.Set('curframe', frame)
if EXPORT_SEL_ONLY: if EXPORT_SEL_ONLY:
export_objects = Blender.Object.GetSelected() # Export Context export_objects = scn.objects.selected #Blender.Object.GetSelected() # Export Context
else: else:
export_objects = scn.getChildren() export_objects = scn.objects # scn.getChildren()
full_path= ''.join(context_name)
if BPyMessages.Warning_SaveOver(full_path):
# EXPORT THE FILE. # EXPORT THE FILE.
write(''.join(context_name), export_objects,\ write(full_path, export_objects,\
EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\ EXPORT_TRI, EXPORT_EDGES, EXPORT_NORMALS,\
EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\ EXPORT_NORMALS_HQ, EXPORT_UV, EXPORT_MTL,\
EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\ EXPORT_COPY_IMAGES, EXPORT_APPLY_MODIFIERS,\

@ -12,17 +12,19 @@ __url__= ["blender.org", "blenderartists.org"]
__version__= "2.0" __version__= "2.0"
__bpydoc__= """\ __bpydoc__= """\
This script imports OBJ files to Blender. This script imports a Wavefront OBJ files to Blender.
Usage: Usage:
Run this script from "File->Import" menu and then load the desired OBJ file. Run this script from "File->Import" menu and then load the desired OBJ file.
Note, This loads mesh objects and materials only, nurbs and curves are unsupported. Note, This loads mesh objects and materials only, nurbs and curves are not supported.
""" """
from Blender import * from Blender import *
import BPyMesh import BPyMesh
import BPyImage import BPyImage
# Generic path functions
def stripFile(path): def stripFile(path):
'''Return directory, where the file is''' '''Return directory, where the file is'''
lastSlash= max(path.rfind('\\'), path.rfind('/')) lastSlash= max(path.rfind('\\'), path.rfind('/'))
@ -30,9 +32,8 @@ def stripFile(path):
path= path[:lastSlash] path= path[:lastSlash]
return '%s%s' % (path, sys.sep) return '%s%s' % (path, sys.sep)
# Generic path functions
def stripPath(path): def stripPath(path):
# Strips the slashes from the back of a string '''Strips the slashes from the back of a string'''
return path.split('/')[-1].split('\\')[-1] return path.split('/')[-1].split('\\')[-1]
def stripExt(name): # name is a string def stripExt(name): # name is a string
@ -44,8 +45,13 @@ def stripExt(name): # name is a string
return name return name
# end path funcs # end path funcs
def line_value(line_split): def line_value(line_split):
'''Takes removes the first work from the line, None if theres only1 word''' '''
Returns 1 string represneting the value for this line
None will be returned if theres only 1 word
'''
length= len(line_split) length= len(line_split)
if length == 1: if length == 1:
return None return None
@ -75,8 +81,10 @@ def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH): def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH):
'''Create all the used materials in this obj, '''
assign colors and images to the materials from all referenced material libs''' Create all the used materials in this obj,
assign colors and images to the materials from all referenced material libs
'''
DIR= stripFile(filepath) DIR= stripFile(filepath)
#==================================================================================# #==================================================================================#
@ -184,6 +192,12 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
def split_mesh(verts_loc, faces, unique_materials, SPLIT_OBJECTS, SPLIT_MATERIALS): def split_mesh(verts_loc, faces, unique_materials, SPLIT_OBJECTS, SPLIT_MATERIALS):
'''
Takes vert_loc and faces, and seperates into multiple sets of
(verts_loc, faces, unique_materials)
This is done so objects do not overload the 16 material limit.
'''
if not SPLIT_OBJECTS and not SPLIT_MATERIALS: if not SPLIT_OBJECTS and not SPLIT_MATERIALS:
return [(verts_loc, faces, unique_materials)] return [(verts_loc, faces, unique_materials)]
@ -248,8 +262,11 @@ def split_mesh(verts_loc, faces, unique_materials, SPLIT_OBJECTS, SPLIT_MATERIAL
return [(verts_split, faces_split, unique_materials_split) for faces_split, verts_split, unique_materials_split, vert_remap in face_split_dict.itervalues()] return [(verts_split, faces_split, unique_materials_split) for faces_split, verts_split, unique_materials_split, vert_remap in face_split_dict.itervalues()]
def create_meshes(new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups): def create_mesh(new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups):
'''
Takes all the data gathered and generates a mesh, adding the new object to new_objects
deals with fgons, sharp edges and assigning materials
'''
if not has_ngons: if not has_ngons:
CREATE_FGONS= False CREATE_FGONS= False
@ -363,10 +380,6 @@ def create_meshes(new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc,
me.materials= materials[0:16] # make sure the list isnt too big. me.materials= materials[0:16] # make sure the list isnt too big.
#me.verts.extend([(0,0,0)]) # dummy vert #me.verts.extend([(0,0,0)]) # dummy vert
me.verts.extend(verts_loc) me.verts.extend(verts_loc)
for f in faces:
if len(f[0]) not in (3,4):
print len(f[0])
raise "Error"
face_mapping= me.faces.extend([f[0] for f in faces], indexList=True) face_mapping= me.faces.extend([f[0] for f in faces], indexList=True)
@ -472,7 +485,12 @@ def get_float_func(filepath):
return float 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, IMAGE_SEARCH=True): 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, IMAGE_SEARCH=True):
'''
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
time_main= sys.time() time_main= sys.time()
@ -637,7 +655,7 @@ def load_obj(filepath, CLAMP_SIZE= 0.0, CREATE_FGONS= True, CREATE_SMOOTH_GROUPS
# Split the mesh by objects/materials, may # Split the mesh by objects/materials, may
for verts_loc_split, faces_split, unique_materials_split in split_mesh(verts_loc, faces, unique_materials, SPLIT_OBJECTS, SPLIT_MATERIALS): for verts_loc_split, faces_split, unique_materials_split in split_mesh(verts_loc, faces, unique_materials, SPLIT_OBJECTS, SPLIT_MATERIALS):
# Create meshes from the data # Create meshes from the data
create_meshes(new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups) create_mesh(new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups)
axis_min= [ 1000000000]*3 axis_min= [ 1000000000]*3
axis_max= [-1000000000]*3 axis_max= [-1000000000]*3