fix for [#17871] PLY file import: blender seems to loose vertex color information
[blender.git] / release / scripts / ply_import.py
index 6b96777102a9f4136b8bcdc242648b32b74d222d..302e21a0a43167e057819af9497eb6092e3f6259 100644 (file)
@@ -2,13 +2,13 @@
 
 """
 Name: 'Stanford PLY (*.ply)...'
-Blender: 241
+Blender: 248
 Group: 'Import'
 Tip: 'Import a Stanford PLY file'
 """
 
 __author__ = 'Bruce Merry'
-__version__ = '0.92'
+__version__ = '0.93'
 __bpydoc__ = """\
 This script imports Stanford PLY files into Blender. It supports per-vertex
 normals, and per-face colours and texture coordinates.
@@ -35,20 +35,20 @@ Run this script from "File->Import" and select the desired PLY file.
 # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 
-# Updated by Campbell Barton AKA Ideasman, 10% faster code.
+# 20th Oct 2008, 0.93 - Updated by Campbell Barton AKA ideasman42, use Mesh rather then NMesh, dont import normals, vcolors work again.
+# Updated by Campbell Barton AKA Ideasman42, 10% faster code.
 
 # Portions of this code are taken from mod_meshtools.py in Blender
 # 2.32.
 
 import Blender
 try:
-       import re, struct, StringIO
+       import re, struct
 except:
        struct= None
 
-class element_spec:
-       name = ''
-       count = 0
+class element_spec(object):
+       __slots__ = 'name', 'count', 'properties'
        def __init__(self, name, count):
                self.name = name
                self.count = count
@@ -64,10 +64,8 @@ class element_spec:
                        if p.name == name: return i
                return -1
 
-class property_spec:
-       name = ''
-       list_type = ''
-       numeric_type = ''
+class property_spec(object):
+       __slots__ = 'name', 'list_type', 'numeric_type'
        def __init__(self, name, list_type, numeric_type):
                self.name = name
                self.list_type = list_type
@@ -117,14 +115,17 @@ class property_spec:
                else:
                        return self.read_format(format, 1, self.numeric_type, stream)[0]
 
-class object_spec:
+class object_spec(object):
+       __slots__ = 'specs'
        'A list of element_specs'
-       specs = []
-
+       def __init__(self):
+               self.specs = []
+       
        def load(self, format, stream):
                return dict([(i.name,[i.load(format, stream) for j in xrange(i.count) ]) for i in self.specs])
                
                '''
+               # Longhand for above LC
                answer = {}
                for i in self.specs:
                        answer[i.name] = []
@@ -176,7 +177,7 @@ def read(filename):
                                if (len(tokens) < 3):
                                        print 'Invalid format line'
                                        return None
-                               if (tokens[1] not in format_specs.keys()):
+                               if (tokens[1] not in format_specs): # .keys()): # keys is implicit
                                        print 'Unknown format', tokens[1]
                                        return None
                                if (tokens[2] != version):
@@ -209,115 +210,132 @@ def read(filename):
        
        return (obj_spec, obj);
 
-
-def add_face(vertices, varr, indices, uvindices, colindices):
-       face = Blender.NMesh.Face([varr[i] for i in indices])
-       for index in indices:
-               vertex = vertices[index];
-               
-               if uvindices:
-                       face.uv.append((vertex[uvindices[0]], 1.0 - vertex[uvindices[1]]))
-                       face.mode &= ~Blender.NMesh.FaceModes.TEX
-               if colindices:
-                       if not uvindices: face.uv.append((0, 0)) # Force faceUV
-                       face.col.append(Blender.NMesh.Col(vertex[colindices[0]], vertex[colindices[1]], vertex[colindices[2]], 255))
-                       face.mode &= ~Blender.NMesh.FaceModes.TEX
-       return face
-
-def filesel_callback(filename):
+def load_ply(filename):
        t = Blender.sys.time()
-       (obj_spec, obj) = read(filename)
+       obj_spec, obj = read(filename)
        if obj == None:
                print 'Invalid file'
                return
-       vmap = {}
-       varr = []
-       uvindices = None
-       noindices = None
-       colindices = None
+       
+       uvindices = colindices = None
+       # noindices = None # Ignore normals
+       
        for el in obj_spec.specs:
                if el.name == 'vertex':
                        vindices = vindices_x, vindices_y, vindices_z = (el.index('x'), el.index('y'), el.index('z'))
-                       if el.index('nx') >= 0 and el.index('ny') >= 0 and el.index('nz') >= 0:
-                               noindices = (el.index('nx'), el.index('ny'), el.index('nz'))
-                       if el.index('s') >= 0 and el.index('t') >= 0:
-                               uvindices = (el.index('s'), el.index('t'))
-                       if el.index('red') >= 0 and el.index('green') and el.index('blue') >= 0:
-                               colindices = (el.index('red'), el.index('green'), el.index('blue'))
+                       # noindices = (el.index('nx'), el.index('ny'), el.index('nz'))
+                       # if -1 in noindices: noindices = None
+                       uvindices = (el.index('s'), el.index('t'))
+                       if -1 in uvindices: uvindices = None
+                       colindices = (el.index('red'), el.index('green'), el.index('blue'))
+                       if -1 in colindices: colindices = None
                elif el.name == 'face':
                        findex = el.index('vertex_indices')
+       
+       mesh_faces = []
+       mesh_uvs = []
+       mesh_colors = []
+       
+       def add_face(vertices, indices, uvindices, colindices):
+               mesh_faces.append(indices)
+               if uvindices:   mesh_uvs.append([ (vertices[index][uvindices[0]], 1.0 - vertices[index][uvindices[1]]) for index in indices])
+               if colindices:  mesh_colors.append([ (vertices[index][colindices[0]], vertices[index][colindices[1]], vertices[index][colindices[2]]) for index in indices])
+       
+       
+       if uvindices or colindices:
+               # If we have Cols or UVs then we need to check the face order.
+               add_face_simple = add_face
                
-
-       mesh = Blender.NMesh.GetRaw()
-       NMVert = Blender.NMesh.Vert
-       for v in obj['vertex']:
-               
-               if noindices > 0:
-                       x,y,z,nx,ny,nz = vkey =\
-                       (v[vindices_x], v[vindices_y], v[vindices_z],\
-                       v[noindices[0]], v[noindices[1]], v[noindices[2]])
-               else:
-                       x,y,z = vkey = (v[vindices_x], v[vindices_y], v[vindices_z])
-               #if not vmap.has_key(vkey):
-               try: # try uses 1 less dict lookup
-                       varr.append(vmap[vkey])
-               except:
-                       nmv = NMVert(vkey[0], vkey[1], vkey[2])
-                       mesh.verts.append(nmv)
-                       if noindices > 0:
-                               nmv.no[0] = vkey[3]
-                               nmv.no[1] = vkey[4]
-                               nmv.no[2] = vkey[5]
-                       vmap[vkey] = nmv
-                       varr.append(vmap[vkey])
+               # EVIL EEKADOODLE - face order annoyance.
+               def add_face(vertices, indices, uvindices, colindices):
+                       if len(indices)==4:
+                               if indices[2]==0 or indices[3]==0:
+                                       indices= indices[2], indices[3], indices[0], indices[1]
+                       elif len(indices)==3:
+                               if indices[2]==0:
+                                       indices= indices[1], indices[2], indices[0]
+                       
+                       add_face_simple(vertices, indices, uvindices, colindices)
        
        verts = obj['vertex']
        
        if 'face' in obj:
                for f in obj['face']:
                        ind = f[findex]
-                       nind = len(ind)
-                       if nind <= 4:
-                               mesh.faces.append(add_face(verts, varr, ind, uvindices, colindices))
+                       len_ind = len(ind)
+                       if len_ind <= 4:
+                               add_face(verts, ind, uvindices, colindices)
                        else:
-                               for j in xrange(nind - 2):
-                                       mesh.faces.append(add_face(verts, varr, (ind[0], ind[j + 1], ind[j + 2]), uvindices, colindices))
-
+                               # Fan fill the face
+                               for j in xrange(len_ind - 2):
+                                       add_face(verts, (ind[0], ind[j + 1], ind[j + 2]), uvindices, colindices)
+       
+       mesh = Blender.Mesh.New()
+       
+       mesh.verts.extend([(v[vindices_x], v[vindices_y], v[vindices_z]) for v in obj['vertex']])
+       
+       if mesh_faces:
+               mesh.faces.extend(mesh_faces, smooth=True, ignoreDups=True)
+               
+               if uvindices or colindices:
+                       if uvindices:   mesh.faceUV = True
+                       if colindices:  mesh.vertexColors = True
+                       
+                       for i, f in enumerate(mesh.faces):
+                               if uvindices:
+                                       ply_uv = mesh_uvs[i]
+                                       for j, uv in enumerate(f.uv):
+                                               uv[:] = ply_uv[j]
+                               
+                               if colindices:
+                                       ply_col = mesh_colors[i]
+                                       for j, col in enumerate(f.col):
+                                               col.r, col.g, col.b = ply_col[j]
        
-       del obj # Reclaim memory
+       mesh.calcNormals()
        
-       '''
-       if noindices:
-               normals = 1
-       else:
-               normals = 0
-       '''
        
        objname = Blender.sys.splitext(Blender.sys.basename(filename))[0]
        scn= Blender.Scene.GetCurrent()
        scn.objects.selected = []
        
        mesh.name= objname
-       scn.objects.new(mesh)
+       scn.objects.active = scn.objects.new(mesh)
        
        Blender.Redraw()
        Blender.Window.DrawProgressBar(1.0, '')
-       print '\nSuccessfully imported ' + Blender.sys.basename(filename) + ' ' + str(Blender.sys.time()-t)
-       
-
-
+       print '\nSuccessfully imported "%s" in %.3f sec' %  (filename, Blender.sys.time()-t)
 
 def main():
        if not struct:
-               Blender.Draw.PupMenu('This importer requires a full python install')
+               msg = 'This importer requires a full python install'
+               if Blender.mode == 'background':        print msg
+               else:   Blender.Draw.PupMenu(msg)
                return
        
-       Blender.Window.FileSelector(filesel_callback, 'Import PLY', '*.ply')
+       Blender.Window.FileSelector(load_ply, 'Import PLY', '*.ply')
 
 if __name__=='__main__':
        main()
 
+'''
+import bpy
+import os
+files = os.popen('find /fe/ply -iname "*.ply"').readlines()
 
 
-
-
+files.sort()
+tot = len(files)
+for i, f in enumerate(files):
+       if i < 26 or i > 1000000:
+               continue
+       #if i != 12686:
+       #       continue
+       
+       f = f.strip()
+       print f, i, tot
+       sce = bpy.data.scenes.new(f.split('/')[-1])
+       bpy.data.scenes.active = sce
+       # Window.
+       load_ply(f)
+'''
\ No newline at end of file