From faff1cf46b1c12401f4f2a604cc3d464abe9fc2b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 4 Feb 2006 03:44:21 +0000 Subject: Fixed bug where a extra vert was duplicated. - (Thanks Brandedo) Face indicies spanning over 1 line are now supported (had a freak obj that did this) Small optimization @% overall speedup. - Last release before move to Mesh over NMesh. --- release/scripts/obj_import.py | 337 ++++++++++-------------------------------- 1 file changed, 74 insertions(+), 263 deletions(-) (limited to 'release') diff --git a/release/scripts/obj_import.py b/release/scripts/obj_import.py index f2bcaf853e7..08b4429a1f9 100644 --- a/release/scripts/obj_import.py +++ b/release/scripts/obj_import.py @@ -71,21 +71,7 @@ def stripExt(name): # name is a string from Blender import * - - - -# Adds a slash to the end of a path if its not there. -def addSlash(path): - if path.endswith('\\') or path.endswith('/'): - return path - return path + sys.sep - - -def getExt(name): - index = name.rfind('.') - if index != -1: - return name[index+1:] - return name +import BPyImage try: import os @@ -94,189 +80,6 @@ except: print 'Module "os" not found, install python to enable comprehensive image finding and batch loading.' os = None -#===========================================================================# -# Comprehansive image loader, will search and find the image # -# Will return a blender image or none if the image is missing # -#===========================================================================# -def comprehansiveImageLoad(imagePath, filePath): - - # When we have the file load it with this. try/except niceness. - def imageLoad(path): - try: - img = Image.Load(path) - print '\t\tImage loaded "%s"' % path - return img - except: - print '\t\tImage failed loading "%s", mabe its not a format blender can read.' % (path) - return None - - # Image formats blender can read - IMAGE_EXT = ['jpg', 'jpeg', 'png', 'tga', 'bmp', 'rgb', 'sgi', 'bw', 'iff', 'lbm', # Blender Internal - 'gif', 'psd', 'tif', 'tiff', 'pct', 'pict', 'pntg', 'qtif'] # Quacktime, worth a try. - - - - - print '\tAttempting to load "%s"' % imagePath - if sys.exists(imagePath): - print '\t\tFile found where expected.' - return imageLoad(imagePath) - - imageFileName = stripPath(imagePath) # image path only - imageFileName_lower = imageFileName.lower() # image path only - imageFileName_noext = stripExt(imageFileName) # With no extension. - imageFileName_noext_lower = stripExt(imageFileName_lower) # With no extension. - imageFilePath = stripFile(imagePath) - - # Remove relative path from image path - if imageFilePath.startswith('./') or imageFilePath.startswith('.\\'): - imageFilePath = imageFilePath[2:] - - - # Attempt to load from obj path. - tmpPath = stripFile(filePath) + stripFile(imageFilePath) - if sys.exists(tmpPath): - print '\t\tFile found in obj dir.' - return imageLoad(imagePath) - - # OS NEEDED IF WE GO ANY FURTHER. - if not os: - return - - - # We have os. - # GATHER PATHS. - paths = {} # Store possible paths we may use, dict for no doubles. - tmpPath = addSlash(sys.expandpath('//')) # Blenders path - if sys.exists(tmpPath): - print '\t\tSearching in %s' % tmpPath - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - - tmpPath = imageFilePath - if sys.exists(tmpPath): - print '\t\tSearching in %s' % tmpPath - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - - tmpPath = stripFile(filePath) - if sys.exists(tmpPath): - print '\t\tSearching in %s' % tmpPath - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - - tmpPath = addSlash(Get('texturesdir')) - if tmpPath and sys.exists(tmpPath): - print '\t\tSearching in %s' % tmpPath - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - - # Add path if relative image patrh was given. - for k in paths.iterkeys(): - tmpPath = k + imageFilePath - if sys.exists(tmpPath): - paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading - paths[tmpPath].append([f.lower() for f in paths[tmpPath][0]]) # Lower case list. - paths[tmpPath].append([stripExt(f) for f in paths[tmpPath][1]]) # Lower case no ext - # DONE - - - # - for path, files in paths.iteritems(): - - if sys.exists(path + imageFileName): - return imageLoad(path + imageFileName) - - # If the files not there then well do a case insensitive seek. - filesOrigCase = files[0] - filesLower = files[1] - filesLowerNoExt = files[2] - - # We are going to try in index the file directly, if its not there just keep on - index = None - try: - # Is it just a case mismatch? - index = filesLower.index(imageFileName_lower) - except: - try: - # Have the extensions changed? - index = filesLowerNoExt.index(imageFileName_noext_lower) - - ext = getExt( filesLower[index] ) # Get the extension of the file that matches all but ext. - - # Check that the ext is useable eg- not a 3ds file :) - if ext.lower() not in IMAGE_EXT: - index = None - - except: - index = None - - if index != None: - tmpPath = path + filesOrigCase[index] - img = imageLoad( tmpPath ) - if img != None: - print '\t\tImage Found "%s"' % tmpPath - return img - - - # IMAGE NOT FOUND IN ANY OF THE DIRS!, DO A RECURSIVE SEARCH. - print '\t\tImage Not Found in any of the dirs, doing a recusrive search' - for path in paths.iterkeys(): - # Were not going to use files - - - #------------------ - # finds the file starting at the root. - # def findImage(findRoot, imagePath): - #W--------------- - - # ROOT, DIRS, FILES - pathWalk = os.walk(path) - pathList = [True] - - matchList = [] # Store a list of (match, size), choose the biggest. - while True: - try: - pathList = pathWalk.next() - except: - break - - for file in pathList[2]: - file_lower = file.lower() - # FOUND A MATCH - if (file_lower == imageFileName_lower) or\ - (stripExt(file_lower) == imageFileName_noext_lower and getExt(file_lower) in IMAGE_EXT): - name = pathList[0] + sys.sep + file - size = os.path.getsize(name) - print '\t\t\tfound:', name - matchList.append( (name, size) ) - - if matchList: - # Sort by file size - matchList.sort(lambda A, B: cmp(B[1], A[1]) ) - - print '\t\tFound "%s"' % matchList[0][0] - - # Loop through all we have found - img = None - for match in matchList: - img = imageLoad(match[0]) # 0 - first, 0 - pathname - if img != None: - break - return img - - # No go. - print '\t\tImage Not Found "%s"' % imagePath - return None - - - - - #==================================================================================# # This function sets textures defined in .mtl file # #==================================================================================# @@ -292,7 +95,7 @@ def loadMaterialImage(mat, img_fileName, type, meshDict, dir): texture.setType('Image') # Absolute path - c:\.. etc would work here - image = comprehansiveImageLoad(img_fileName, dir) + image = BPyImage.comprehansiveImageLoad(img_fileName, dir) if image: texture.image = image @@ -483,9 +286,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): #==================================================================================# # Load all verts first (texture verts too) # #==================================================================================# - print '\tfile length: %d' % len(fileLines) - # Ignore normals and comments. fileLines = [lsplit for l in fileLines if not l.startswith('vn') if not l.startswith('#') for lsplit in (l.split(),) if lsplit] Vert = NMesh.Vert @@ -496,7 +297,6 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): print '\tvert:%i texverts:%i smoothgroups:%i materials:%s' % (len(vertList), len(uvMapList), len(smoothingGroups), len(materialDict)) # Replace filelines, Excluding v excludes "v ", "vn " and "vt " - # Remove any variables we may have created. try: del _dummy except: pass @@ -510,6 +310,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): except: pass del Vert + # With negative values this is used a lot. make faster access. len_uvMapList = len(uvMapList) len_vertList = len(vertList) @@ -525,7 +326,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): # Make a list of all unused vert indicies that we can copy from - VERT_USED_LIST = [0]*len_vertList + VERT_USED_LIST = [-1]*len_vertList # Here we store a boolean list of which verts are used or not # no we know weather to add them to the current mesh @@ -552,7 +353,6 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): currentUsedVertListSmoothGroup = VERT_USED_LIST[:] currentUsedVertList= {currentSmoothGroup: currentUsedVertListSmoothGroup } - # 0:NMesh, 1:SmoothGroups[UsedVerts[0,0,0,0]], 2:materialMapping['matname':matIndexForThisNMesh] meshDict = {currentObjectName: (currentMesh, currentUsedVertList, currentMaterialMeshMapping) } @@ -570,12 +370,10 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): #==================================================================================# # Load all faces into objects, main loop # #==================================================================================# - #lIdx = 0 - # Face and Object loading LOOP - #while lIdx < len(fileLines): - # l = fileLines[lIdx] - #for lIdx - for l in fileLines: + lIdx = 0 + while lIdx < len(fileLines): + l = fileLines[lIdx] + #for l in fileLines: if len(l) == 0: continue # FACE @@ -602,47 +400,63 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): fHasUV = len_uvMapList # Assume the face has a UV until it sho it dosent, if there are no UV coords then this will start as 0. - for v in l[1:]: - # OBJ files can have // or / to seperate vert/texVert/normal - # this is a bit of a pain but we must deal with it. - objVert = v.split('/') - - # Vert Index - OBJ supports negative index assignment (like python) - index = int(objVert[0])-1 - # Account for negative indicies. - if index < 0: - index = len_vertList+index+1 - - vIdxLs.append(index) - if fHasUV: - # UV - index = 0 # Dummy var - if len(objVert) == 1: - index = vIdxLs[-1] - elif objVert[1]: # != '' # Its possible that theres no texture vert just he vert and normal eg 1//2 - index = int(objVert[1])-1 - if index < 0: - index = len_uvMapList+index+1 - - if len_uvMapList > index: - vtIdxLs.append(index) # Seperate UV coords - else: - # BAD FILE, I have found this so I account for it. - # INVALID UV COORD - # Could ignore this- only happens with 1 in 1000 files. - badObjFaceTexCo +=1 - vtIdxLs.append(1) - - fHasUV = 0 - - # Dont add a UV to the face if its larger then the UV coord list - # The OBJ file would have to be corrupt or badly written for thi to happen - # but account for it anyway. - if len(vtIdxLs) > 0: - if vtIdxLs[-1] > len_uvMapList: - fHasUV = 0 + + # Support stupid multiline faces + # not an obj spec but some objs exist that do this. + # f 1 2 3 \ + # 4 5 6 \ + # ..... instead of the more common and sane. + # f 1 2 3 4 5 6 + # + # later lines are not modified, just skepped by advancing "lIdx" + while l[-1] == '\\': + l.pop() + lIdx+=1 + l.extend(fileLines[lIdx]) + # Done supporting crappy obj faces over multiple lines. + + for v in l: + if v is not 'f': # Only the first v will be f, any better ways to skip it? + # OBJ files can have // or / to seperate vert/texVert/normal + # this is a bit of a pain but we must deal with it. + objVert = v.split('/') + + # Vert Index - OBJ supports negative index assignment (like python) + index = int(objVert[0])-1 + # Account for negative indicies. + if index < 0: + index = len_vertList+index+1 + + vIdxLs.append(index) + if fHasUV: + # UV + index = 0 # Dummy var + if len(objVert) == 1: + index = vIdxLs[-1] + elif objVert[1]: # != '' # Its possible that theres no texture vert just he vert and normal eg 1//2 + index = int(objVert[1])-1 + if index < 0: + index = len_uvMapList+index+1 + + if len_uvMapList > index: + vtIdxLs.append(index) # Seperate UV coords + else: + # BAD FILE, I have found this so I account for it. + # INVALID UV COORD + # Could ignore this- only happens with 1 in 1000 files. + badObjFaceTexCo +=1 + vtIdxLs.append(1) - badObjUvs +=1 # ERROR, Cont + fHasUV = 0 + + # Dont add a UV to the face if its larger then the UV coord list + # The OBJ file would have to be corrupt or badly written for thi to happen + # but account for it anyway. + if len(vtIdxLs) > 0: + if vtIdxLs[-1] > len_uvMapList: + fHasUV = 0 + + badObjUvs +=1 # ERROR, Cont # Quads only, we could import quads using the method below but it polite to import a quad as a quad. #print lIdx, len(vIdxLs), len(currentUsedVertListSmoothGroup) #print fileLines[lIdx] @@ -650,7 +464,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): if IMPORT_EDGES: # Edge for i in (0,1): - if currentUsedVertListSmoothGroup[vIdxLs[i]] == 0: + if currentUsedVertListSmoothGroup[vIdxLs[i]] == -1: faceQuadVList[i] = vertList[vIdxLs[i]] currentMesh.verts.append(faceQuadVList[i]) currentUsedVertListSmoothGroup[vIdxLs[i]] = len(currentMesh.verts)-1 @@ -671,7 +485,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): badObjFaceVerts+=1 else: for i in quadList: # quadList == [0,1,2,3] - if currentUsedVertListSmoothGroup[vIdxLs[i]] == 0: + if currentUsedVertListSmoothGroup[vIdxLs[i]] == -1: faceQuadVList[i] = vertList[vIdxLs[i]] currentMesh.verts.append(faceQuadVList[i]) currentUsedVertListSmoothGroup[vIdxLs[i]] = len(currentMesh.verts)-1 @@ -699,7 +513,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): badObjFaceVerts+=1 else: for k, j in [(0,0), (1,i+1), (2,i+2)]: - if currentUsedVertListSmoothGroup[vIdxLs[j]] == 0: + if currentUsedVertListSmoothGroup[vIdxLs[j]] == -1: faceTriVList[k] = vertList[vIdxLs[j]] currentMesh.verts.append(faceTriVList[k]) currentUsedVertListSmoothGroup[vIdxLs[j]] = len(currentMesh.verts)-1 @@ -827,17 +641,15 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): except KeyError: # Not in dict, add for first time. # Image has not been added, Try and load the image - currentImg = comprehansiveImageLoad(newImgName, DIR) # Use join in case of spaces + currentImg = BPyImage.comprehansiveImageLoad(newImgName, DIR) # Use join in case of spaces imageDict[newImgName] = currentImg # These may be None, thats okay. - - # MATERIAL FILE elif l[0] == 'mtllib': mtl_fileName.append(' '.join(l[1:]) ) # SHOULD SUPPORT MULTIPLE MTL? - #lIdx+=1 - + lIdx+=1 + # Applies material properties to materials alredy on the mesh as well as Textures. if IMPORT_MTL: for mtl in mtl_fileName: @@ -851,7 +663,6 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): # Ignore no vert meshes. if not nme.verts: # == [] continue - name = getUniqueName(mk) ob = NMesh.PutRaw(nme, name) ob.name = name @@ -938,12 +749,12 @@ def load_obj_ui(file): if count > 1: print 'Total obj import "%s" dir: %.2f' % (obj_dir, sys.time() - time) - + def main(): Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ') - - if __name__ == '__main__': - main() \ No newline at end of file + main() + +#load_obj('/cube.obj') \ No newline at end of file -- cgit v1.2.3