diff --git a/release/scripts/bpymodules/BPyMesh.py b/release/scripts/bpymodules/BPyMesh.py index 9d4a7cdf119..140613ad873 100644 --- a/release/scripts/bpymodules/BPyMesh.py +++ b/release/scripts/bpymodules/BPyMesh.py @@ -32,11 +32,16 @@ def dict2MeshWeight(me, groupNames, vWeightDict): # Clear the vert group. currentGroupNames= me.getVertGroupNames() for group in currentGroupNames: - me.removeVertGroup(group) + if group not in groupNames: + me.removeVertGroup(group) # messes up the active group. + else: + me.removeVertsFromGroup(group) # Add clean unused vert groupNames back + currentGroupNames= me.getVertGroupNames() for group in groupNames: - me.addVertGroup(group) + if group not in currentGroupNames: + me.addVertGroup(group) add_ = Blender.Mesh.AssignModes.ADD @@ -45,7 +50,7 @@ def dict2MeshWeight(me, groupNames, vWeightDict): vertList[0]= i for group, weight in vWeightDict[i].iteritems(): try: - me.assignVertsToGroup(group, vertList, weight, add_) + me.assignVertsToGroup(group, vertList, min(1, max(0, weight)), add_) except: pass # vert group is not used anymore. @@ -125,4 +130,236 @@ def getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=Tru except: print 'Cant assign materials to', type - return mesh \ No newline at end of file + return mesh + +type_tuple= type( (0,) ) +type_list= type( [] ) +def ngon(from_data, indices): + ''' + 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 is either a mesh, or a list/tuple of vectors. + ''' + Mesh= Blender.Mesh + Window= Blender.Window + Scene= Blender.Scene + Object= Blender.Object + + if len(indices) < 4: + return [indices] + 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) + + if type(from_data) in (type_tuple, type_list): + # From a list/tuple of vectors + temp_mesh.verts.extend( [from_data[i] for i in indices] ) + temp_mesh.edges.extend( [(temp_mesh.verts[i], temp_mesh.verts[i-1]) for i in xrange(len(temp_mesh.verts))] ) + else: + # From a mesh + temp_mesh.verts.extend( [from_data.verts[i].co for i in indices] ) + 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_indices= [ [v.index for v in f.v] for f in temp_mesh.faces ] + + if not new_indices: # JUST DO A FAN, Cant Scanfill + print 'Warning Cannot scanfill!- Fallback on a triangle fan.' + new_indices = [ [indices[0], indices[i-1], indices[i]] for i in xrange(2, len(indices)) ] + else: + # Use real scanfill. + # See if its flipped the wrong way. + flip= None + for fi in new_indices: + 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_indices: + 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_indices + + + +# EG +''' +scn= Scene.GetCurrent() +me = scn.getActiveObject().getData(mesh=1) +ind= [v.index for v in me.verts if v.sel] # Get indices + +indices = ngon(me, ind) # fill the ngon. + +# Extand the faces to show what the scanfill looked like. +print len(indices) +me.faces.extend([[me.verts[ii] for ii in i] for i in indices]) +''' + + + + + + + + + + + + + + + + + + + +# NMesh wrapper +Vector= Blender.Mathutils.Vector +class NMesh(object): + __slots__= 'verts', 'faces', 'edges', 'faceUV', 'materials', 'realmesh' + def __init__(self, mesh): + ''' + This is an NMesh wrapper that + mesh is an Mesh as returned by Blender.Mesh.New() + This class wraps NMesh like access into Mesh + + Running NMesh.update() - with this wrapper, + Will update the realmesh. + ''' + self.verts= [] + self.faces= [] + self.edges= [] + self.faceUV= False + self.materials= [] + self.realmesh= mesh + + def addFace(self, nmf): + self.faces.append(nmf) + + def Face(self, v=[]): + return NMFace(v) + def Vert(self, x,y,z): + return NMVert(x,y,z) + + def hasFaceUV(self, flag): + if flag: + self.faceUV= True + else: + self.faceUV= False + + def addMaterial(self, mat): + self.materials.append(mat) + + def update(self, recalc_normals=False): # recalc_normals is dummy + mesh= self.realmesh + mesh.verts= None # Clears the + + # Add in any verts from faces we may have not added. + for nmf in self.faces: + for nmv in nmf.v: + if nmv.index==-1: + nmv.index= len(self.verts) + self.verts.append(nmv) + + + mesh.verts.extend([nmv.co for nmv in self.verts]) + for i, nmv in enumerate(self.verts): + nmv.index= i + mv= mesh.verts[i] + mv.sel= nmv.sel + + good_faces= [nmf for nmf in self.faces if len(nmf.v) in (3,4)] + #print len(good_faces), 'AAA' + + + #mesh.faces.extend([nmf.v for nmf in self.faces]) + mesh.faces.extend([[mesh.verts[nmv.index] for nmv in nmf.v] for nmf in good_faces]) + if len(mesh.faces): + if self.faceUV: + mesh.faceUV= 1 + + #for i, nmf in enumerate(self.faces): + for i, nmf in enumerate(good_faces): + mf= mesh.faces[i] + if self.faceUV: + if len(nmf.uv) == len(mf.v): + mf.uv= [Vector(uv[0], uv[1]) for uv in nmf.uv] + if len(nmf.col) == len(mf.v): + for c, i in enumerate(mf.col): + c.r, c.g, c.b= nmf.col[i].r, nmf.col[i].g, nmf.col[i].b + if nmf.image: + mf.image= nmf.image + + mesh.materials= self.materials[:16] + +class NMVert(object): + __slots__= 'co', 'index', 'no', 'sel', 'uvco' + def __init__(self, x,y,z): + self.co= Vector(x,y,z) + self.index= None # set on appending. + self.no= Vector(0,0,1) # dummy + self.sel= 0 + self.uvco= None +class NMFace(object): + __slots__= 'col', 'flag', 'hide', 'image', 'mat', 'materialIndex', 'mode', 'normal',\ + 'sel', 'smooth', 'transp', 'uv', 'v' + + def __init__(self, v=[]): + self.col= [] + self.flag= 0 + self.hide= 0 + self.image= None + self.mat= 0 # materialIndex needs support too. + self.mode= 0 + self.normal= Vector(0,0,1) + self.uv= [] + self.sel= 0 + self.smooth= 0 + self.transp= 0 + self.uv= [] + self.v= [] # a list of nmverts. + +class NMCol(object): + __slots__ = 'r', 'g', 'b', 'a' + def __init__(self): + self.r= 255 + self.g= 255 + self.b= 255 + self.a= 255 diff --git a/release/scripts/mesh_cleanup.py b/release/scripts/mesh_cleanup.py index 2f3b3c8abd3..2ee3642efe8 100644 --- a/release/scripts/mesh_cleanup.py +++ b/release/scripts/mesh_cleanup.py @@ -179,13 +179,12 @@ def main(): if is_editmode and (not actob.sel): obsel.append(actob) - meshes= [ob.getData(mesh=1) for ob in obsel if ob.getType() == 'Mesh'] - #====================================# # Popup menu to select the functions # #====================================# + CLEAN_ALL_DATA= Draw.Create(0) CLEAN_VERTS_FREE= Draw.Create(1) CLEAN_EDGE_NOFACE= Draw.Create(0) CLEAN_EDGE_SMALL= Draw.Create(0) @@ -213,13 +212,13 @@ def main(): ('Weight Normalize', CLEAN_WEIGHT_NORMALIZE, 'Make the sum total of vertex weights accross vgroups 1.0 for each vertex.'),\ '',\ ('limit: ', limit, 0.001, 1.0, 'Limit used for the area and length tests above (a higher limit will remove more data).'),\ + '',\ + ('All Mesh Data', CLEAN_ALL_DATA, 'Warning! Operate on ALL mesh objects in your Blend file. Use with care'),\ ] - if not Draw.PupBlock('Clean Selected Meshes...', pup_block): return - CLEAN_VERTS_FREE= CLEAN_VERTS_FREE.val CLEAN_EDGE_NOFACE= CLEAN_EDGE_NOFACE.val CLEAN_EDGE_SMALL= CLEAN_EDGE_SMALL.val @@ -230,9 +229,19 @@ def main(): CLEAN_VWEIGHT= CLEAN_VWEIGHT.val CLEAN_WEIGHT_NORMALIZE= CLEAN_WEIGHT_NORMALIZE.val limit= limit.val + CLEAN_ALL_DATA= CLEAN_ALL_DATA.val if is_editmode: Window.EditMode(0) + if CLEAN_ALL_DATA: + if CLEAN_GROUP or CLEAN_VWEIGHT or CLEAN_WEIGHT_NORMALIZE: + # For groups we need the objects linked to the mesh + meshes= [ob.getData(mesh=1) for ob in Object.Get() if ob.getType() == 'Mesh'] + else: + meshes= Mesh.Get() + else: + meshes= [ob.getData(mesh=1) for ob in obsel if ob.getType() == 'Mesh'] + rem_face_count= rem_edge_count= rem_vert_count= rem_material_count= rem_group_count= rem_vweight_count= 0 for me in meshes: diff --git a/release/scripts/obj_export.py b/release/scripts/obj_export.py index b58b1e7ddde..47e4f2bcde7 100644 --- a/release/scripts/obj_export.py +++ b/release/scripts/obj_export.py @@ -167,12 +167,12 @@ def copy_images(dest_dir): # Get MTex images if matname != None: mat= Material.Get(matname) - for mtex in mat.getTextures(): - if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: - try: - uniqueImages[mtex.tex.image.name] = None - except: - pass + for mtex in mat.getTextures(): + if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE: + try: + uniqueImages[mtex.tex.image.name] = None + except: + pass # Now copy images copyCount = 0 @@ -463,6 +463,7 @@ EXPORT_GROUP_BY_OB=False, EXPORT_GROUP_BY_MAT=False): # Make the indicies global rather then per mesh totverts += len(m.verts) + m.verts= None file.close() diff --git a/release/scripts/obj_import.py b/release/scripts/obj_import.py index 12f9d78d833..1ac3c37851f 100644 --- a/release/scripts/obj_import.py +++ b/release/scripts/obj_import.py @@ -73,91 +73,7 @@ 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]) -''' - - - +import BPyMesh try: import os @@ -416,12 +332,12 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO materialDict[k]= Material.New(k) - # Make a list of all unused vert indicies that we can copy from + # Make a list of all unused vert indices that we can copy from 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 - # This is an issue with global vertex indicies being translated to per mesh indicies + # This is an issue with global vertex indices being translated to per mesh indices # like blenders, we start with a dummy just like the vert. # -1 means unused, any other value refers to the local mesh index of the vert. @@ -435,7 +351,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO #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. + currentMaterialMeshMapping= {} # Used to store material indices 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. @@ -456,7 +372,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO badObjFaceTexCo= 0 - #currentMesh.verts.append(vertList[0]) # So we can sync with OBJ indicies where 1 is the first item. + #currentMesh.verts.append(vertList[0]) # So we can sync with OBJ indices where 1 is the first item. if len_uvMapList > 1: currentMesh.hasFaceUV(1) # Turn UV's on if we have ANY texture coords in this obj file. @@ -591,7 +507,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO # Vert Index - OBJ supports negative index assignment (like python) index= int(objVert[0])-1 - # Account for negative indicies. + # Account for negative indices. if index < 0: if IMPORT_RELATIVE_VERTS: # non standard index= VERT_COUNT+index+1 @@ -713,16 +629,17 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO currentMesh.faces.append(f) # move the face onto the mesh elif face_vert_count > 4: # NGons. - # we need to map indicies to uv coords. + # we need to map indices 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) + ngon_face_indices= BPyMesh.ngon(currentMesh, currentMeshRelativeIdxs) + # At the moment scanfill always makes tri's but dont count on it - for fillFace in ngon_face_indicies: + for fillFace in ngon_face_indices: f= NMesh.Face([currentMesh.verts[currentMeshRelativeIdxs[i]] for i in fillFace]) if fHasUV: @@ -739,7 +656,7 @@ def load_obj(file, IMPORT_MTL=1, IMPORT_EDGES=1, IMPORT_SMOOTH_ALL=0, IMPORT_FGO # Set fgon flag. if IMPORT_FGON: edgeUsers={} - for fillFace in ngon_face_indicies: + for fillFace in ngon_face_indices: for i in xrange(len(fillFace)): # Should always be 3 i1= currentMeshRelativeIdxs[fillFace[i]] i2= currentMeshRelativeIdxs[fillFace[i-1]] @@ -908,7 +825,7 @@ def load_obj_ui(file): ('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)'),\ - ('Relative Verts', IMPORT_RELATIVE_VERTS, 'Import non standard OBJs with relative vertex indicies, try if your mesh imports with scrambled faces.'),\ + ('Relative Verts', IMPORT_RELATIVE_VERTS, 'Import non standard OBJs with relative vertex indices, try if your mesh imports with scrambled faces.'),\ ] if not os: