blender/release/scripts/ply_import.py
Campbell Barton e70610ab1e Update to ply export, give nice messages to the user rather then throwing errors at the user.
Export mesh data with modifiers and objects matrix applied. export not only mesh data but text, nurbs etc (thanks to BPYMesh getMeshFromObject)

Small updates to ply import, dont set the TEX of a face (no pink faces anymore)
2006-07-03 03:22:48 +00:00

306 lines
8.5 KiB
Python

#!BPY
"""
Name: 'Stanford PLY (*.ply)...'
Blender: 241
Group: 'Import'
Tip: 'Import a Stanford PLY file'
"""
__author__ = 'Bruce Merry'
__version__ = '0.92'
__bpydoc__ = """\
This script imports Stanford PLY files into Blender. It supports per-vertex
normals, and per-face colours and texture coordinates.
Usage:
Run this script from "File->Import" and select the desired PLY file.
"""
# Copyright (C) 2004, 2005: Bruce Merry, bmerry@cs.uct.ac.za
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Updated by Campbell Barton AKA Ideasman, 10% faster code.
# Portions of this code are taken from mod_meshtools.py in Blender
# 2.32.
import Blender, meshtools
import re, struct, StringIO
class element_spec:
name = ''
count = 0
def __init__(self, name, count):
self.name = name
self.count = count
self.properties = []
def load(self, format, stream):
if format == 'ascii':
stream = re.split('\s+', stream.readline())
return map(lambda x: x.load(format, stream), self.properties)
def index(self, name):
for i, p in enumerate(self.properties):
if p.name == name: return i
return -1
class property_spec:
name = ''
list_type = ''
numeric_type = ''
def __init__(self, name, list_type, numeric_type):
self.name = name
self.list_type = list_type
self.numeric_type = numeric_type
def read_format(self, format, count, num_type, stream):
if format == 'ascii':
if (num_type == 's'):
ans = []
for i in xrange(count):
s = stream[i]
if len(s) < 2 or s[0] != '"' or s[-1] != '"':
print 'Invalid string', s
print 'Note: ply_import.py does not handle whitespace in strings'
return None
ans.append(s[1:-1])
stream[:count] = []
return ans
if (num_type == 'f' or num_type == 'd'):
mapper = float
else:
mapper = int
ans = map(lambda x: mapper(x), stream[:count])
stream[:count] = []
return ans
else:
if (num_type == 's'):
ans = []
for i in xrange(count):
fmt = format + 'i'
data = stream.read(struct.calcsize(fmt))
length = struct.unpack(fmt, data)[0]
fmt = '%s%is' % (format, length)
data = stream.read(struct.calcsize(fmt))
s = struct.unpack(fmt, data)[0]
ans.append(s[:-1]) # strip the NULL
return ans
else:
fmt = '%s%i%s' % (format, count, num_type)
data = stream.read(struct.calcsize(fmt));
return struct.unpack(fmt, data)
def load(self, format, stream):
if (self.list_type != None):
count = int(self.read_format(format, 1, self.list_type, stream)[0])
return self.read_format(format, count, self.numeric_type, stream)
else:
return self.read_format(format, 1, self.numeric_type, stream)[0]
class object_spec:
'A list of element_specs'
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])
'''
answer = {}
for i in self.specs:
answer[i.name] = []
for j in xrange(i.count):
if not j % 100 and meshtools.show_progress:
Blender.Window.DrawProgressBar(float(j) / i.count, 'Loading ' + i.name)
answer[i.name].append(i.load(format, stream))
return answer
'''
def read(filename):
format = ''
version = '1.0'
format_specs = {'binary_little_endian': '<',
'binary_big_endian': '>',
'ascii': 'ascii'}
type_specs = {'char': 'b',
'uchar': 'B',
'int8': 'b',
'uint8': 'B',
'int16': 'h',
'uint16': 'H',
'int': 'i',
'int32': 'i',
'uint': 'I',
'uint32': 'I',
'float': 'f',
'float32': 'f',
'float64': 'd',
'string': 's'}
obj_spec = object_spec()
try:
file = open(filename, 'rb')
signature = file.readline()
if (signature != 'ply\n'):
print 'Signature line was invalid'
return None
while 1:
tokens = re.split(r'[ \n]+', file.readline())
if (len(tokens) == 0):
continue
if (tokens[0] == 'end_header'):
break
elif (tokens[0] == 'comment' or tokens[0] == 'obj_info'):
continue
elif (tokens[0] == 'format'):
if (len(tokens) < 3):
print 'Invalid format line'
return None
if (tokens[1] not in format_specs.keys()):
print 'Unknown format', tokens[1]
return None
if (tokens[2] != version):
print 'Unknown version', tokens[2]
return None
format = tokens[1]
elif (tokens[0] == 'element'):
if (len(tokens) < 3):
print 'Invalid element line'
return None
obj_spec.specs.append(element_spec(tokens[1], int(tokens[2])))
elif (tokens[0] == 'property'):
if (not len(obj_spec.specs)):
print 'Property without element'
return None
if (tokens[1] == 'list'):
obj_spec.specs[-1].properties.append(property_spec(tokens[4], type_specs[tokens[2]], type_specs[tokens[3]]))
else:
obj_spec.specs[-1].properties.append(property_spec(tokens[2], None, type_specs[tokens[1]]))
obj = obj_spec.load(format_specs[format], file)
except IOError, (errno, strerror):
file.close()
return None
file.close()
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):
t = Blender.sys.time()
(obj_spec, obj) = read(filename)
if obj == None:
print 'Invalid file'
return
vmap = {}
varr = []
uvindices = None
noindices = None
colindices = None
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'))
elif el.name == 'face':
findex = el.index('vertex_indices')
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])
verts = obj['vertex']
for f in obj['face']:
ind = f[findex]
nind = len(ind)
if nind <= 4:
mesh.faces.append(add_face(verts, varr, 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))
del obj # Reclaim memory
'''
if noindices:
normals = 1
else:
normals = 0
'''
objname = Blender.sys.splitext(Blender.sys.basename(filename))[0]
scn= Blender.Scene.GetCurrent()
for obj in scn.getChildren():
obj.sel= 0
obj= Blender.Object.New('Mesh', objname)
mesh.name= objname
obj.link(mesh)
scn.link(obj)
obj.sel= 1
obj.Layers= scn.Layers
Blender.Redraw()
Blender.Window.DrawProgressBar(1.0, '')
message = 'Successfully imported ' + Blender.sys.basename(filename) + ' ' + str(Blender.sys.time()-t)
meshtools.print_boxed(message)
Blender.Window.FileSelector(filesel_callback, 'Import PLY', Blender.sys.makename(ext='.ply'))