diff --git a/release/scripts/bpymodules/BPyImage.py b/release/scripts/bpymodules/BPyImage.py index a6e047bae47..5aa3c4c582a 100644 --- a/release/scripts/bpymodules/BPyImage.py +++ b/release/scripts/bpymodules/BPyImage.py @@ -81,7 +81,10 @@ def comprehensiveImageLoad(imagePath, filePath, placeHolder= True, VERBOSE=True) if VERBOSE: print 'img:', imagePath, 'file:', filePath # When we have the file load it with this. try/except niceness. def imageLoad(path): + #if path.endswith('\\') or path.endswith('/'): + # raise 'INVALID PATH' try: + img = Blender.Image.Load(path) if VERBOSE: print '\t\tImage loaded "%s"' % path return img @@ -89,8 +92,8 @@ def comprehensiveImageLoad(imagePath, filePath, placeHolder= True, VERBOSE=True) #raise "Helloo" if VERBOSE: if sys.exists(path): print '\t\tImage failed loading "%s", mabe its not a format blender can read.' % (path) - else: print '\t\tImage not found "%s"' % (path) - if newImage: + else: print '\t\tImage not found, making a place holder "%s"' % (path) + if placeHolder: img= Blender.Image.New(stripPath(path),1,1,24) img.setName(path.split('/')[-1].split('\\')[-1][0:21]) #path.split('/')[-1].split('\\')[-1][0:21] @@ -115,7 +118,7 @@ def comprehensiveImageLoad(imagePath, filePath, placeHolder= True, VERBOSE=True) if VERBOSE: print '\tAttempting to load "%s"' % imagePath if sys.exists(imagePath): - if VERBOSE: print '\t\tFile found where expected.' + if VERBOSE: print '\t\tFile found where expected "%s".' % imagePath return imageLoad(imagePath) @@ -130,14 +133,15 @@ def comprehensiveImageLoad(imagePath, filePath, placeHolder= True, VERBOSE=True) # Attempt to load from obj path. - tmpPath = stripFile(filePath) + stripFile(imageFilePath) + tmpPath = stripFile(filePath) + stripPath(imageFileName) if sys.exists(tmpPath): - if VERBOSE: print '\t\tFile found in path "%s".' % tmpPath + if VERBOSE: print '\t\tFile found in path (1)"%s".' % tmpPath return imageLoad(tmpPath) # os needed if we go any further. if os == None: + if VERBOSE: print '\t\tCreating a placeholder with a face path: "%s".' % imagePath return imageLoad(imagePath) # Will jus treturn a placeholder. @@ -181,7 +185,8 @@ def comprehensiveImageLoad(imagePath, filePath, placeHolder= True, VERBOSE=True) if VERBOSE: print '\tNo Path: "%s"' % tmpPath # Add path if relative image patrh was given. - for k in paths.iterkeys(): + tmp_paths= paths.keys() + for k in tmp_paths: tmpPath = k + imageFilePath if sys.exists(tmpPath): paths[tmpPath] = [os.listdir(tmpPath)] # Orig name for loading @@ -194,8 +199,8 @@ def comprehensiveImageLoad(imagePath, filePath, placeHolder= True, VERBOSE=True) print 'PATHs', paths # for path, files in paths.iteritems(): - if sys.exists(path + imageFileName): + if VERBOSE: print '\tFound image at path: "%s" file" "%s"' % (path, imageFileName) return imageLoad(path + imageFileName) # If the files not there then well do a case insensitive seek. @@ -278,5 +283,10 @@ def comprehensiveImageLoad(imagePath, filePath, placeHolder= True, VERBOSE=True) return img # No go. - if VERBOSE: print '\t\tImage Not Found "%s"' % imagePath - return imageLoad(imagePath) # Will jus treturn a placeholder. \ No newline at end of file + if VERBOSE: print '\t\tImage Not Found after looking everywhere! "%s"' % imagePath + return imageLoad(imagePath) # Will jus treturn a placeholder. + + + + + diff --git a/release/scripts/obj_import.py b/release/scripts/obj_import.py index ddb62bee850..cbf3204003b 100644 --- a/release/scripts/obj_import.py +++ b/release/scripts/obj_import.py @@ -7,11 +7,11 @@ Group: 'Import' Tooltip: 'Load a Wavefront OBJ File, Shift: batch import all dir.' """ -__author__ = "Campbell Barton" -__url__ = ["blender", "elysiun"] -__version__ = "1.0" +__author__= "Campbell Barton" +__url__= ["blender", "elysiun"] +__version__= "1.0" -__bpydoc__ = """\ +__bpydoc__= """\ This script imports OBJ files to Blender. Usage: @@ -48,9 +48,9 @@ Run this script from "File->Import" menu and then load the desired OBJ file. # Return directory, where the file is # #==============================================# def stripFile(path): - lastSlash = max(path.rfind('\\'), path.rfind('/')) + lastSlash= max(path.rfind('\\'), path.rfind('/')) if lastSlash != -1: - path = path[:lastSlash] + path= path[:lastSlash] return '%s%s' % (path, sys.sep) #==============================================# @@ -63,7 +63,7 @@ def stripPath(path): # Strips the prefix off the name before writing # #====================================================# def stripExt(name): # name is a string - index = name.rfind('.') + index= name.rfind('.') if index != -1: return name[ : index ] else: @@ -72,33 +72,115 @@ def stripExt(name): # name is a string from Blender import * import BPyImage +reload(BPyImage) + +# takes a polyline of indicies (fgon) +# and returns a list of face indicie lists. +def ngon(from_mesh, indicies): + if len(indicies) < 4: + return [indicies] + temp_mesh_name= '~NGON_TEMP~' + is_editmode= Window.EditMode() + if is_editmode: + Window.EditMode(0) + try: + temp_mesh = Mesh.Get(temp_mesh_name) + if temp_mesh.users!=0: + temp_mesh = Mesh.New(temp_mesh_name) + except: + temp_mesh = Mesh.New(temp_mesh_name) + + + temp_mesh.verts.extend( [from_mesh.verts[i].co for i in indicies] ) + temp_mesh.edges.extend( [(temp_mesh.verts[i], temp_mesh.verts[i-1]) for i in xrange(len(temp_mesh.verts))] ) + + oldmode = Mesh.Mode() + Mesh.Mode(Mesh.SelectModes['VERTEX']) + for v in temp_mesh.verts: + v.sel= 1 + + # Must link to scene + scn= Scene.GetCurrent() + temp_ob= Object.New('Mesh') + temp_ob.link(temp_mesh) + scn.link(temp_ob) + temp_mesh.fill() + scn.unlink(temp_ob) + Mesh.Mode(oldmode) + + new_indicies= [ [v.index for v in f.v] for f in temp_mesh.faces ] + + if not new_indicies: # JUST DO A FAN, Cant Scanfill + print 'Warning Cannot scanfill!- Fallback on a triangle fan.' + new_indicies = [ [indicies[0], indicies[i-1], indicies[i]] for i in xrange(2, len(indicies)) ] + else: + # Use real scanfill. + # See if its flipped the wrong way. + flip= None + for fi in new_indicies: + 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 fi in new_indicies: + fi.reverse() + + if is_editmode: + Window.EditMode(1) + + # Save some memory and forget about the verts. + # since we cant unlink the mesh. + temp_mesh.verts= None + + return new_indicies + + + +# EG +''' +scn= Scene.GetCurrent() +me = scn.getActiveObject().getData(mesh=1) +ind= [v.index for v in me.verts if v.sel] # Get indicies + +indicies = ngon(me, ind) # fill the ngon. + +# Extand the faces to show what the scanfill looked like. +print len(indicies) +me.faces.extend([[me.verts[ii] for ii in i] for i in indicies]) +''' + + + try: import os except: # So we know if os exists. print 'Module "os" not found, install python to enable comprehensive image finding and batch loading.' - os = None + os= None -#==================================================================================# -# This function sets textures defined in .mtl file # -#==================================================================================# -# ___ Replaced by comprehensive imahge get #==================================================================================# # This function sets textures defined in .mtl file # #==================================================================================# def loadMaterialImage(mat, img_fileName, type, meshDict, dir): - TEX_ON_FLAG = NMesh.FaceModes['TEX'] + TEX_ON_FLAG= NMesh.FaceModes['TEX'] - texture = Texture.New(type) + texture= Texture.New(type) texture.setType('Image') # Absolute path - c:\.. etc would work here - image = BPyImage.comprehensiveImageLoad(img_fileName, dir) + image= BPyImage.comprehensiveImageLoad(img_fileName, dir) if image: - texture.image = image + texture.image= image # 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. @@ -110,7 +192,7 @@ def loadMaterialImage(mat, img_fileName, type, meshDict, dir): # the inline usemat command overides the material Image if not f.image: f.mode |= TEX_ON_FLAG - f.image = image + f.image= image # adds textures for materials (rendering) elif type == 'Ka': @@ -143,12 +225,12 @@ def load_mtl(dir, mtl_file, meshDict, materialDict): #except NameError or KeyError: except: # Better do any exception # Do we realy need to keep the dict up to date?, not realy but keeps consuistant. - materialDict[matName] = Material.New(matName) - return materialDict[matName] + mat= materialDict[matName]= Material.New(matName) + return mat - mtl_file = stripPath(mtl_file) - mtl_fileName = dir + mtl_file + mtl_file= stripPath(mtl_file) + mtl_fileName= dir + mtl_file try: fileLines= open(mtl_fileName, 'r').readlines() @@ -159,13 +241,13 @@ def load_mtl(dir, mtl_file, meshDict, materialDict): try: lIdx=0 while lIdx < len(fileLines): - l = fileLines[lIdx].split() + l= fileLines[lIdx].split() # Detect a line that will be ignored if len(l) == 0 or l[0].startswith('#'): pass elif l[0] == 'newmtl': - currentMat = getMat('_'.join(l[1:]), materialDict) # Material should alredy exist. + currentMat= getMat('_'.join(l[1:]), materialDict) # Material should alredy exist. elif l[0] == 'Ka': currentMat.setMirCol((float(l[1]), float(l[2]), float(l[3]))) elif l[0] == 'Kd': @@ -181,25 +263,25 @@ def load_mtl(dir, mtl_file, meshDict, materialDict): elif l[0] == 'Tr': currentMat.setAlpha(float(l[1])) elif l[0] == 'map_Ka': - img_fileName = ' '.join(l[1:]) + img_fileName= ' '.join(l[1:]) loadMaterialImage(currentMat, img_fileName, 'Ka', meshDict, dir) elif l[0] == 'map_Ks': - img_fileName = ' '.join(l[1:]) + img_fileName= ' '.join(l[1:]) loadMaterialImage(currentMat, img_fileName, 'Ks', meshDict, dir) elif l[0] == 'map_Kd': - img_fileName = ' '.join(l[1:]) + img_fileName= ' '.join(l[1:]) loadMaterialImage(currentMat, img_fileName, 'Kd', meshDict, dir) # new additions elif l[0] == 'map_Bump': # Bumpmap - img_fileName = ' '.join(l[1:]) + img_fileName= ' '.join(l[1:]) loadMaterialImage(currentMat, img_fileName, 'Bump', meshDict, dir) elif l[0] == 'map_D': # Alpha map - Dissolve - img_fileName = ' '.join(l[1:]) + img_fileName= ' '.join(l[1:]) loadMaterialImage(currentMat, img_fileName, 'D', meshDict, dir) elif l[0] == 'refl': # Reflectionmap - img_fileName = ' '.join(l[1:]) + img_fileName= ' '.join(l[1:]) loadMaterialImage(currentMat, img_fileName, 'refl', meshDict, dir) lIdx+=1 @@ -211,23 +293,29 @@ def load_mtl(dir, mtl_file, meshDict, materialDict): # Returns unique name of object/mesh (preserve overwriting existing meshes) # #===========================================================================# def getUniqueName(name): - newName = name[:19] # 19 chars is the longest name. - uniqueInt = 0 + newName= name[:19] # 19 chars is the longest name. + uniqueInt= 0 while newName in getUniqueName.uniqueNames: - newName = '%s.%.3i' % (name[:15], uniqueInt) + newName= '%s.%.3i' % (name[:15], uniqueInt) uniqueInt +=1 getUniqueName.uniqueNames.append(newName) return newName -getUniqueName.uniqueNames = [] +getUniqueName.uniqueNames= [] #==================================================================================# # This loads data from .obj file # #==================================================================================# -def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): +def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGON=1, IMPORT_SMOOTH_GROUPS=0, IMPORT_MTL_SPLIT=0): + global currentMesh,\ + currentUsedVertList,\ + currentUsedVertListSmoothGroup,\ + meshDict,\ + contextMeshMatIdx,\ + currentMaterialMeshMapping print '\nImporting OBJ file: "%s"' % file - time1 = sys.time() + time1= sys.time() getUniqueName.uniqueNames.extend( [ob.name for ob in Object.Get()] ) getUniqueName.uniqueNames.extend( NMesh.GetNames() ) @@ -235,65 +323,68 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): # Deselect all objects in the scene. # do this first so we dont have to bother, with objects we import for ob in Scene.GetCurrent().getChildren(): - ob.sel = 0 + ob.sel= 0 - TEX_OFF_FLAG = ~NMesh.FaceModes['TEX'] + TEX_OFF_FLAG= ~NMesh.FaceModes['TEX'] # Get the file name with no path or .obj - fileName = stripExt( stripPath(file) ) + fileName= stripExt( stripPath(file) ) - mtl_fileName = [] # Support multiple mtl files if needed. + mtl_fileName= [] # Support multiple mtl files if needed. - DIR = stripFile(file) + DIR= stripFile(file) - tempFile = open(file, 'r') - fileLines = tempFile.readlines() + tempFile= open(file, 'r') + fileLines= tempFile.readlines() tempFile.close() del tempFile - uvMapList = [] # store tuple uv pairs here + uvMapList= [] # store tuple uv pairs here # This dummy vert makes life a whole lot easier- # pythons index system then aligns with objs, remove later - vertList = [] # Could havea vert but since this is a placeholder theres no Point + vertList= [] # Could havea vert but since this is a placeholder theres no Point # Store all imported images in a dict, names are key - imageDict = {} + imageDict= {} # This stores the index that the current mesh has for the current material. # if the mesh does not have the material then set -1 - contextMeshMatIdx = -1 + contextMeshMatIdx= -1 # Keep this out of the dict for easy accsess. - nullMat = Material.New('(null)') + nullMat= Material.New('(null)') - currentMat = nullMat # Use this mat. - currentImg = None # Null image is a string, otherwise this should be set to an image object.\ + currentMat= nullMat # Use this mat. + currentImg= None # Null image is a string, otherwise this should be set to an image object.\ if IMPORT_SMOOTH_ALL: - currentSmooth = True + currentSmooth= True else: - currentSmooth = False + currentSmooth= False # Store a list of unnamed names - currentUnnamedGroupIdx = 1 - currentUnnamedObjectIdx = 1 + currentUnnamedGroupIdx= 1 + currentUnnamedObjectIdx= 1 - quadList = (0, 1, 2, 3) + quadList= (0, 1, 2, 3) - faceQuadVList = [None, None, None, None] - faceTriVList = [None, None, None] + faceQuadVList= [None, None, None, None] + faceTriVList= [None, None, None] #==================================================================================# # 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 - vertList = [Vert(float(l[1]), float(l[2]), float(l[3]) ) for l in fileLines if l[0] == 'v'] - uvMapList = [(float(l[1]), float(l[2])) for l in fileLines if l[0] == 'vt'] - smoothingGroups = dict([('_'.join(l[1:]), None) for l in fileLines if l[0] == 's' ]) - materialDict = dict([('_'.join(l[1:]), None) for l in fileLines if l[0] == 'usemtl']) # Store all imported materials as unique dict, names are key + 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 + vertList= [Vert(float(l[1]), float(l[2]), float(l[3]) ) for l in fileLines if l[0] == 'v'] + uvMapList= [(float(l[1]), float(l[2])) for l in fileLines if l[0] == 'vt'] + if IMPORT_SMOOTH_GROUPS: + smoothingGroups= dict([('_'.join(l[1:]), None) for l in fileLines if l[0] == 's' ]) + else: + smoothingGroups= {} + materialDict= dict([('_'.join(l[1:]), None) for l in fileLines if l[0] == 'usemtl']) # Store all imported materials as unique dict, names are key 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 " @@ -312,21 +403,21 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): # With negative values this is used a lot. make faster access. - len_uvMapList = len(uvMapList) - len_vertList = len(vertList) + len_uvMapList= len(uvMapList) + len_vertList= len(vertList) # Only want unique keys anyway - smoothingGroups['(null)'] = None # Make sure we have at least 1. - smoothingGroups = smoothingGroups.keys() + smoothingGroups['(null)']= None # Make sure we have at least 1. + smoothingGroups= smoothingGroups.keys() print '\tfound %d smoothing groups.' % (len(smoothingGroups) -1) # Add materials to Blender for later is in teh OBJ for k in materialDict.iterkeys(): - materialDict[k] = Material.New(k) + materialDict[k]= Material.New(k) # Make a list of all unused vert indicies that we can copy from - VERT_USED_LIST = [-1]*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 @@ -336,30 +427,33 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): # currentObjectName has a char in front of it that determins weather its a group or object. # We ignore it when naming the object. - currentObjectName = 'unnamed_obj_0' # If we cant get one, use this + currentObjectName= 'unnamed_obj_0' # If we cant get one, use this - #meshDict = {} # The 3 variables below are stored in a tuple within this dict for each mesh - currentMesh = NMesh.GetRaw() # The NMesh representation of the OBJ group/Object - #currentUsedVertList = {} # A Dict of smooth groups, each smooth group has a list of used verts and they are generated on demand so as to save memory. - currentMaterialMeshMapping = {} # Used to store material indicies so we dont have to search the mesh for materials every time. + if IMPORT_MTL_SPLIT: + currentObjectName_real= currentObjectName + + #meshDict= {} # The 3 variables below are stored in a tuple within this dict for each mesh + currentMesh= NMesh.GetRaw() # The NMesh representation of the OBJ group/Object + #currentUsedVertList= {} # A Dict of smooth groups, each smooth group has a list of used verts and they are generated on demand so as to save memory. + currentMaterialMeshMapping= {} # Used to store material indicies so we dont have to search the mesh for materials every time. # Every mesh has a null smooth group, this is used if there are no smooth groups in the OBJ file. # and when for faces where no smooth group is used. - currentSmoothGroup = '(null)' # The Name of the current smooth group + currentSmoothGroup= '(null)' # The Name of the current smooth group # For direct accsess to the Current Meshes, Current Smooth Groups- Used verts. # This is of course context based and changes on the fly. # Set the initial '(null)' Smooth group, every mesh has one. - currentUsedVertListSmoothGroup = VERT_USED_LIST[:] + 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) } + meshDict= {currentObjectName: (currentMesh, currentUsedVertList, currentMaterialMeshMapping) } # Only show the bad uv error once - badObjUvs = 0 - badObjFaceVerts = 0 - badObjFaceTexCo = 0 + badObjUvs= 0 + badObjFaceVerts= 0 + badObjFaceTexCo= 0 #currentMesh.verts.append(vertList[0]) # So we can sync with OBJ indicies where 1 is the first item. @@ -367,39 +461,100 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): currentMesh.hasFaceUV(1) # Turn UV's on if we have ANY texture coords in this obj file. + + # Heres the code that gets a mesh, creating a new one if needed. + # may_exist is used to avoid a dict looup. + # if the mesh is unnamed then we generate a new name and dont bother looking + # to see if its alredy there. + def obj_getmesh(may_exist): + global currentMesh,\ + currentUsedVertList,\ + currentUsedVertListSmoothGroup,\ + meshDict,\ + contextMeshMatIdx,\ + currentMaterialMeshMapping + + #print 'getting mesh,', currentObjectName + + # If we havnt written to this mesh before then do so. + # if we have then we'll just keep appending to it, this is required for soem files. + + # If we are new, or we are not yet in the list of added meshes + # then make us new mesh. + if (not may_exist) or (not meshDict.has_key(currentObjectName)): + currentMesh= NMesh.GetRaw() + + currentUsedVertList= {} + + # SmoothGroup is a string + ########currentSmoothGroup= '(null)' # From examplesm changing the g/o shouldent change the smooth group. + currentUsedVertList[currentSmoothGroup]= currentUsedVertListSmoothGroup= VERT_USED_LIST[:] + + currentMaterialMeshMapping= {} + meshDict[currentObjectName]= (currentMesh, currentUsedVertList, currentMaterialMeshMapping) + currentMesh.hasFaceUV(1) + contextMeshMatIdx= -1 + + else: + # Since we have this in Blender then we will check if the current Mesh has the material. + # set the contextMeshMatIdx to the meshs index but only if we have it. + currentMesh, currentUsedVertList, currentMaterialMeshMapping= meshDict[currentObjectName] + #getMeshMaterialIndex(currentMesh, currentMat) + + try: + contextMeshMatIdx= currentMaterialMeshMapping[currentMat.name] #getMeshMaterialIndex(currentMesh, currentMat) + except KeyError: + contextMeshMatIdx -1 + + # For new meshes switch smoothing groups to null + ########currentSmoothGroup= '(null)' # From examplesm changing the g/o shouldent change the smooth group. + try: + currentUsedVertListSmoothGroup= currentUsedVertList[currentSmoothGroup] + except: + currentUsedVertList[currentSmoothGroup]= currentUsedVertListSmoothGroup= VERT_USED_LIST[:] + + + + + + + #==================================================================================# # Load all faces into objects, main loop # #==================================================================================# - lIdx = 0 + lIdx= 0 + EDGE_FGON_FLAG= NMesh.EdgeFlags['FGON'] + EDGE_DRAW_FLAG= NMesh.EdgeFlags['EDGEDRAW'] + while lIdx < len(fileLines): - l = fileLines[lIdx] + l= fileLines[lIdx] #for l in fileLines: if len(l) == 0: continue # FACE - elif l[0] == 'f': + elif l[0] == 'f' or l[0] == 'fo': # Make a face with the correct material. # Add material to mesh if contextMeshMatIdx == -1: - tmpMatLs = currentMesh.materials + tmpMatLs= currentMesh.materials if len(tmpMatLs) == 16: - contextMeshMatIdx = 0 # Use first material + contextMeshMatIdx= 0 # Use first material print 'material overflow, attempting to use > 16 materials. defaulting to first.' else: - contextMeshMatIdx = len(tmpMatLs) - currentMaterialMeshMapping[currentMat.name] = contextMeshMatIdx + contextMeshMatIdx= len(tmpMatLs) + currentMaterialMeshMapping[currentMat.name]= contextMeshMatIdx currentMesh.addMaterial(currentMat) # Set up vIdxLs : Verts # Set up vtIdxLs : UV # Start with a dummy objects so python accepts OBJs 1 is the first index. - vIdxLs = [] - vtIdxLs = [] + vIdxLs= [] + vtIdxLs= [] - 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. + 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. # Support stupid multiline faces # not an obj spec but some objs exist that do this. @@ -419,24 +574,24 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): 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('/') + objVert= v.split('/') # Vert Index - OBJ supports negative index assignment (like python) - index = int(objVert[0])-1 + index= int(objVert[0])-1 # Account for negative indicies. if index < 0: - index = len_vertList+index+1 + index= len_vertList+index+1 vIdxLs.append(index) if fHasUV: # UV - index = 0 # Dummy var + index= 0 # Dummy var if len(objVert) == 1: - index = vIdxLs[-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 + index= int(objVert[1])-1 if index < 0: - index = len_uvMapList+index+1 + index= len_uvMapList+index+1 if len_uvMapList > index: vtIdxLs.append(index) # Seperate UV coords @@ -447,32 +602,42 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): badObjFaceTexCo +=1 vtIdxLs.append(1) - fHasUV = 0 + 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 + 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] - if len(vIdxLs) == 2: - if IMPORT_EDGES: + + # Add all the verts we need, + # dont edd edge verts if were not importing them. + face_vert_count= len(vIdxLs) + if (not IMPORT_EDGES) and face_vert_count == 2: + pass + else: + # Add the verts that arnt alredy added. + for i in vIdxLs: + if currentUsedVertListSmoothGroup[i] == -1: + v= vertList[i] + currentMesh.verts.append(v) + currentUsedVertListSmoothGroup[i]= len(currentMesh.verts)-1 + + if face_vert_count == 2: + if IMPORT_EDGES and vIdxLs[0]!=vIdxLs[1]: # Edge - for i in (0,1): - if currentUsedVertListSmoothGroup[vIdxLs[i]] == -1: - faceQuadVList[i] = vertList[vIdxLs[i]] - currentMesh.verts.append(faceQuadVList[i]) - currentUsedVertListSmoothGroup[vIdxLs[i]] = len(currentMesh.verts)-1 - else: - faceQuadVList[i] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[i]]] - - currentMesh.addEdge(faceQuadVList[0], faceQuadVList[1]) - elif len(vIdxLs) == 4: + currentMesh.addEdge(\ + currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[0]]],\ + currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[0]]]) + + elif face_vert_count == 4: # Have found some files where wach face references the same vert # - This causes a bug and stopts the import so lets check here @@ -485,169 +650,182 @@ 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]] == -1: - faceQuadVList[i] = vertList[vIdxLs[i]] - currentMesh.verts.append(faceQuadVList[i]) - currentUsedVertListSmoothGroup[vIdxLs[i]] = len(currentMesh.verts)-1 - else: - faceQuadVList[i] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[i]]] + faceQuadVList[i]= currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[i]]] - f = NMesh.Face(faceQuadVList) + f= NMesh.Face(faceQuadVList) # UV MAPPING if fHasUV: - f.uv = [uvMapList[ vtIdxLs[0] ],uvMapList[ vtIdxLs[1] ],uvMapList[ vtIdxLs[2] ],uvMapList[ vtIdxLs[3] ]] + f.uv= [uvMapList[ vtIdxLs[0] ],uvMapList[ vtIdxLs[1] ],uvMapList[ vtIdxLs[2] ],uvMapList[ vtIdxLs[3] ]] if currentImg: - f.image = currentImg + f.image= currentImg else: f.mode &= TEX_OFF_FLAG - f.mat = contextMeshMatIdx - f.smooth = currentSmooth + f.mat= contextMeshMatIdx + f.smooth= currentSmooth currentMesh.faces.append(f) # move the face onto the mesh - elif len(vIdxLs) >= 3: # This handles tri's and fans - for i in range(len(vIdxLs)-2): + elif face_vert_count == 3: # This handles tri's and fans, dont use fans anymore. + for i in range(face_vert_count-2): if vIdxLs[0] == vIdxLs[i+1] or\ vIdxLs[0] == vIdxLs[i+2] or\ vIdxLs[i+1] == vIdxLs[i+2]: badObjFaceVerts+=1 else: for k, j in [(0,0), (1,i+1), (2,i+2)]: - if currentUsedVertListSmoothGroup[vIdxLs[j]] == -1: - faceTriVList[k] = vertList[vIdxLs[j]] - currentMesh.verts.append(faceTriVList[k]) - currentUsedVertListSmoothGroup[vIdxLs[j]] = len(currentMesh.verts)-1 - else: - faceTriVList[k] = currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[j]]] + faceTriVList[k]= currentMesh.verts[currentUsedVertListSmoothGroup[vIdxLs[j]]] - f = NMesh.Face(faceTriVList) + f= NMesh.Face(faceTriVList) # UV MAPPING if fHasUV: - f.uv = [uvMapList[vtIdxLs[0]], uvMapList[vtIdxLs[i+1]], uvMapList[vtIdxLs[i+2]]] + f.uv= [uvMapList[vtIdxLs[0]], uvMapList[vtIdxLs[i+1]], uvMapList[vtIdxLs[i+2]]] if currentImg: - f.image = currentImg + f.image= currentImg else: f.mode &= TEX_OFF_FLAG - f.mat = contextMeshMatIdx - f.smooth = currentSmooth + f.mat= contextMeshMatIdx + f.smooth= currentSmooth currentMesh.faces.append(f) # move the face onto the mesh - + + elif face_vert_count > 4: # NGons. + # we need to map indicies to uv coords. + currentMeshRelativeIdxs= [currentUsedVertListSmoothGroup[i] for i in vIdxLs] + + if fHasUV: + vert2UvMapping=dict( [ (currentMeshRelativeIdxs[i],vtIdxLs[i]) for i in xrange(face_vert_count)] ) + + ngon_face_indicies= ngon(currentMesh, currentMeshRelativeIdxs) + + # At the moment scanfill always makes tri's but dont count on it + for fillFace in ngon_face_indicies: + f= NMesh.Face([currentMesh.verts[currentMeshRelativeIdxs[i]] for i in fillFace]) + + if fHasUV: + f.uv= [uvMapList[vert2UvMapping[currentMeshRelativeIdxs[i]]] for i in fillFace] + if currentImg: + f.image= currentImg + else: + f.mode &= TEX_OFF_FLAG + + f.mat= contextMeshMatIdx + f.smooth= currentSmooth + currentMesh.faces.append(f) # move the face onto the mesh + + # Set fgon flag. + if IMPORT_FGON: + edgeUsers={} + for fillFace in ngon_face_indicies: + for i in xrange(len(fillFace)): # Should always be 3 + i1= currentMeshRelativeIdxs[fillFace[i]] + i2= currentMeshRelativeIdxs[fillFace[i-1]] + + # Sort the pair so thet always match. + if i1>i2: i1,i2=i2,i1 + + try: + edgeUsers[i1,i2]+= 1 + except: + edgeUsers[i1,i2]= 0 + + for edgeVerts, users in edgeUsers.iteritems(): + if users: + ed= currentMesh.addEdge(\ + currentMesh.verts[edgeVerts[0]],\ + currentMesh.verts[edgeVerts[1]]) + + ed.flag|= EDGE_FGON_FLAG + # FACE SMOOTHING - elif l[0] == 's': + elif l[0] == 's' and IMPORT_SMOOTH_GROUPS: # No value? then turn on. if len(l) == 1: - currentSmooth = True - currentSmoothGroup = '(null)' + currentSmooth= True + currentSmoothGroup= '(null)' else: if l[1] == 'off': # We all have a null group so dont need to try, will try anyway to avoid code duplication. if not IMPORT_SMOOTH_ALL: - currentSmooth = False - currentSmoothGroup = '(null)' + currentSmooth= False + currentSmoothGroup= '(null)' else: - currentSmooth = True - currentSmoothGroup = '_'.join(l[1:]) + currentSmooth= True + currentSmoothGroup= '_'.join(l[1:]) try: - currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup] + currentUsedVertListSmoothGroup= currentUsedVertList[currentSmoothGroup] except KeyError: - currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup = VERT_USED_LIST[:] + currentUsedVertList[currentSmoothGroup]= currentUsedVertListSmoothGroup= VERT_USED_LIST[:] # OBJECT / GROUP elif l[0] == 'o' or l[0] == 'g': # Forget about the current image - currentImg = None + currentImg= None # This makes sure that if an object and a group have the same name then # they are not put into the same object. # Only make a new group.object name if the verts in the existing object have been used, this is obscure # but some files face groups seperating verts and faces which results in silly things. (no groups have names.) - if len(l) > 1: - currentObjectName = '_'.join(l[1:]) - else: # No name given + if len(l) == 1: # Make a new empty name if l[0] == 'g': # Make a blank group name - currentObjectName = 'unnamed_grp_%.4d' % currentUnnamedGroupIdx + currentObjectName= 'unnamed_grp_%.4d' % currentUnnamedGroupIdx currentUnnamedGroupIdx +=1 else: # is an object. - currentObjectName = 'unnamed_ob_%.4d' % currentUnnamedObjectIdx + currentObjectName= 'unnamed_ob_%.4d' % currentUnnamedObjectIdx currentUnnamedObjectIdx +=1 + may_exist= False # we know the model is new. + else: # No name given + currentObjectName= '_'.join(l[1:]) + may_exist= True + if IMPORT_MTL_SPLIT: + currentObjectName_real= currentObjectName + currentObjectName += '_'+currentMat.name - # If we havnt written to this mesh before then do so. - # if we have then we'll just keep appending to it, this is required for soem files. - - # If we are new, or we are not yet in the list of added meshes - # then make us new mesh. - if len(l) == 1 or (not meshDict.has_key(currentObjectName)): - currentMesh = NMesh.GetRaw() - - currentUsedVertList = {} - - # Sg is a string - ########currentSmoothGroup = '(null)' # From examplesm changing the g/o shouldent change the smooth group. - currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup = VERT_USED_LIST[:] - - currentMaterialMeshMapping = {} - meshDict[currentObjectName] = (currentMesh, currentUsedVertList, currentMaterialMeshMapping) - currentMesh.hasFaceUV(1) - contextMeshMatIdx = -1 - - else: - # Since we have this in Blender then we will check if the current Mesh has the material. - # set the contextMeshMatIdx to the meshs index but only if we have it. - currentMesh, currentUsedVertList, currentMaterialMeshMapping = meshDict[currentObjectName] - #getMeshMaterialIndex(currentMesh, currentMat) - - try: - contextMeshMatIdx = currentMaterialMeshMapping[currentMat.name] #getMeshMaterialIndex(currentMesh, currentMat) - except KeyError: - contextMeshMatIdx -1 - - # For new meshes switch smoothing groups to null - ########currentSmoothGroup = '(null)' # From examplesm changing the g/o shouldent change the smooth group. - try: - currentUsedVertListSmoothGroup = currentUsedVertList[currentSmoothGroup] - except: - currentUsedVertList[currentSmoothGroup] = currentUsedVertListSmoothGroup = VERT_USED_LIST[:] - + obj_getmesh(may_exist) # MATERIAL elif l[0] == 'usemtl': if len(l) == 1 or l[1] == '(null)': - currentMat = nullMat # We know we have a null mat. + currentMat= nullMat # We know we have a null mat. else: - currentMat = materialDict['_'.join(l[1:])] + currentMat= materialDict['_'.join(l[1:])] try: - contextMeshMatIdx = currentMaterialMeshMapping[currentMat.name] + contextMeshMatIdx= currentMaterialMeshMapping[currentMat.name] except KeyError: - contextMeshMatIdx = -1 #getMeshMaterialIndex(currentMesh, currentMat) + contextMeshMatIdx= -1 #getMeshMaterialIndex(currentMesh, currentMat) + + # Check if we are splitting by material. + if IMPORT_MTL_SPLIT: + currentObjectName= currentObjectName_real+'_'+currentMat.name + obj_getmesh(True) + # IMAGE elif l[0] == 'usemat' or l[0] == 'usemap': if len(l) == 1 or l[1] == '(null)' or l[1] == 'off': - currentImg = None + currentImg= None else: # Load an image. - newImgName = stripPath(' '.join(l[1:])) # Use space since its a file name. + newImgName= stripPath(' '.join(l[1:])) # Use space since its a file name. try: # Assume its alredy set in the dict (may or maynot be loaded) - currentImg = imageDict[newImgName] + currentImg= imageDict[newImgName] except KeyError: # Not in dict, add for first time. # Image has not been added, Try and load the image - currentImg = BPyImage.comprehensiveImageLoad(newImgName, DIR) # Use join in case of spaces - imageDict[newImgName] = currentImg + currentImg= BPyImage.comprehensiveImageLoad(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? + elif l[0] == 'mtllib' and IMPORT_MTL and len(l)>1: + mtl_fileName.append(' '.join(l[1:]) ) # Support for multiple MTL's lIdx+=1 # Applies material properties to materials alredy on the mesh as well as Textures. @@ -656,22 +834,22 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): load_mtl(DIR, mtl, meshDict, materialDict) - importedObjects = [] + importedObjects= [] for mk, me in meshDict.iteritems(): - nme = me[0] + nme= me[0] # Ignore no vert meshes. if not nme.verts: # == [] continue - name = getUniqueName(mk) - ob = NMesh.PutRaw(nme, name) - ob.name = name + name= getUniqueName(mk) + ob= NMesh.PutRaw(nme, name) + ob.name= name importedObjects.append(ob) # Select all imported objects. for ob in importedObjects: - ob.sel = 1 + ob.sel= 1 if badObjUvs > 0: print '\tERROR: found %d faces with badly formatted UV coords. everything else went okay.' % badObjUvs @@ -686,61 +864,69 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0): def load_obj_ui(file): - IMPORT_MTL = Draw.Create(1) - IMPORT_DIR = Draw.Create(0) - IMPORT_NEW_SCENE = Draw.Create(0) - IMPORT_EDGES = Draw.Create(1) - IMPORT_SMOOTH_ALL = Draw.Create(0) - + IMPORT_MTL= Draw.Create(1) + IMPORT_DIR= Draw.Create(0) + IMPORT_NEW_SCENE= Draw.Create(0) + IMPORT_EDGES= Draw.Create(1) + IMPORT_SMOOTH_ALL= Draw.Create(1) + IMPORT_FGON= Draw.Create(1) + IMPORT_SMOOTH_GROUPS= Draw.Create(0) + IMPORT_MTL_SPLIT= Draw.Create(0) # Get USER Options - pup_block = [\ + pup_block= [\ ('Material (*.mtl)', IMPORT_MTL, 'Imports material settings and images from the obj\'s .mtl file'),\ ('All *.obj\'s in dir', IMPORT_DIR, 'Import all obj files in this dir (avoid overlapping data with "Create scene")'),\ ('Create scene', IMPORT_NEW_SCENE, 'Imports each obj into its own scene, named from the file'),\ 'Geometry...',\ ('Edges', IMPORT_EDGES, 'Import faces with 2 verts as in edge'),\ ('Smooths all faces', IMPORT_SMOOTH_ALL, 'Smooth all faces even if they are not in a smoothing group'),\ + ('Create FGons', IMPORT_FGON, 'Import faces with more then 4 verts as fgons.'),\ + ('Smooth Groups', IMPORT_SMOOTH_GROUPS, 'Only Share verts within smooth groups. (Warning, Hogs Memory)'),\ + ('Split by Material', IMPORT_MTL_SPLIT, 'Import each material into a seperate mesh (Avoids >16 meterials per mesh problem)'),\ ] if not os: - pup_block.pop(1) # Make sure this is the IMPORT_DIR option that requires OS + pup_block.pop(2) # Make sure this is the IMPORT_DIR option that requires OS if not Draw.PupBlock('Import...', pup_block): return Window.WaitCursor(1) Window.DrawProgressBar(0, '') - time = sys.time() + time= sys.time() - IMPORT_MTL = IMPORT_MTL.val - IMPORT_DIR = IMPORT_DIR.val - IMPORT_NEW_SCENE = IMPORT_NEW_SCENE.val - IMPORT_EDGES = IMPORT_EDGES.val - IMPORT_SMOOTH_ALL = IMPORT_SMOOTH_ALL.val + IMPORT_MTL= IMPORT_MTL.val + IMPORT_DIR= IMPORT_DIR.val + IMPORT_NEW_SCENE= IMPORT_NEW_SCENE.val + IMPORT_EDGES= IMPORT_EDGES.val + IMPORT_SMOOTH_ALL= IMPORT_SMOOTH_ALL.val + IMPORT_FGON= IMPORT_FGON.val + IMPORT_SMOOTH_GROUPS= IMPORT_SMOOTH_GROUPS.val + IMPORT_MTL_SPLIT= IMPORT_MTL_SPLIT.val - #orig_scene = Scene.GetCurrent() + #orig_scene= Scene.GetCurrent() - obj_dir = stripFile(file) + obj_dir= stripFile(file) if IMPORT_DIR: - obj_files = [(obj_dir,f) for f in os.listdir(obj_dir) if f.lower().endswith('obj')] + obj_files= [(obj_dir,f) for f in os.listdir(obj_dir) if f.lower().endswith('obj')] else: - obj_files = [(obj_dir,stripPath(file))] + obj_files= [(obj_dir,stripPath(file))] - obj_len = len(obj_files) - count = 0 + obj_len= len(obj_files) + count= 0 for d, f in obj_files: count+= 1 if not sys.exists(d+f): print 'Error: "%s%s" does not exist' % (d,f) else: if IMPORT_NEW_SCENE: - scn = Scene.New('.'.join(f.split('.')[0:-1])) + scn= Scene.New('.'.join(f.split('.')[0:-1])) scn.makeCurrent() Window.DrawProgressBar((float(count)/obj_len) - 0.01, '%s: %i of %i' % (f, count, obj_len)) - load_obj(d+f, IMPORT_MTL, IMPORT_EDGES, IMPORT_SMOOTH_ALL) + load_obj(d+f, IMPORT_MTL, IMPORT_EDGES, IMPORT_SMOOTH_ALL, IMPORT_FGON, IMPORT_SMOOTH_GROUPS, IMPORT_MTL_SPLIT) #orig_scene.makeCurrent() # We can leave them in there new scene. @@ -756,5 +942,6 @@ def main(): if __name__ == '__main__': main() + pass -#load_obj('/cube.obj') \ No newline at end of file +#load_obj('/1test.obj') \ No newline at end of file