fix for blender 2.56 beta
[io_import_off.git] / io_import_off.py
1 # io_import_off.py Stefan Huber
2 #
3 # Import DEC Object File Format (*.off)
4
5
6 bl_addon_info = {
7 "name": "Import DEC Object File Format (.off)",
8 "author": "Stefan Huber (shuber)",
9 "version": (0,7),
10 "blender": (2, 5, 3),
11 "api": 31667,
12 "location": "File > Import > Import DEC Object File Format (.off)",
13 "description": "Import DEC Object File Format (.off) files",
14 "warning": "",
15 "category": "Import/Export"
16 }
17
18
19
20 __author__ = "Stefan Huber"
21 #__url__ = ("blender", "blenderartists.org", "Author's homepage, http://www.redrival.com/scorpius")
22 #__version__ = "Part of IOSuite 0.5"
23
24 __bpydoc__ = """\
25 This script imports DEC Object File Format files to Blender.
26
27 The DEC (Digital Equipment Corporation) OFF format is very old and
28 almost identical to Wavefront's OBJ. I wrote this so I could get my huge
29 meshes into Moonlight Atelier. (DXF can also be used but the file size
30 is five times larger than OFF!) Blender/Moonlight users might find this
31 script to be very useful.
32
33 Usage:<br>
34 Execute this script from the "File->Import" menu and choose an OFF file to
35 open.
36
37 Notes:<br>
38 Port to blender 2.5 beta 2. - shuber
39 UV Coordinate support has been added. - Scorpius
40 FGON support has been added. - Cam
41 New Mesh module now used. - Cam
42 """
43
44 import bpy
45 from bpy.props import *
46
47
48
49 def isComment(line):
50 """Is this line a comment line?"""
51 line = line.strip()
52 if len(line) == 0:
53 return False
54 if line[0] == "#":
55 return True
56 return False
57
58
59 def getNextLine(f):
60 """Read next line from file 'f' and ignore comments"""
61 line = f.readline().strip()
62 while isComment(line):
63 line = f.readline().strip()
64 return line
65
66
67
68 def unpack_vertices( vertices ):
69 l = []
70 for t in vertices:
71 l.extend(t)
72 return l
73
74
75 def unpack_faces(faces):
76
77 l = []
78 for face in faces:
79
80 # Build triangle fans
81 for k in range(1, len(face)-1):
82
83 tri = [face[0], face[k], face[k+1]]
84
85 # Rotate triangle, such that last index is not zero
86 if tri[2] == 0:
87 tri = [ tri[2], tri[0], tri[1] ]
88
89 l.extend(tri)
90 l.extend([0])
91
92 return l
93
94
95 def importFile(filepath, context):
96
97 # List of vertices, a vertex is a 3-tuple (x,y,z)
98 vertices = []
99 # List of faces, a face is a list of indices within vertices
100 faces = []
101
102 try:
103
104 f = open(filepath, "r")
105
106 # Get the header line
107 line = getNextLine(f)
108 if line != "OFF":
109 print("Error: header line does not start with 'OFF'.")
110 print(line)
111 return False
112
113 #Get number of vertices, faces and edges
114 line = getNextLine(f).split()
115 if len(line) < 2:
116 print("Error: Line of number of vertices, faces and edges is invalid.")
117 return False
118 [numVertices, numFaces] = map(int, line[0:2])
119
120 if numVertices < 0:
121 print("Error: Number of vertices is negative!")
122 return False
123 if numFaces < 0:
124 print("Error: Number of faces is negative!")
125 return False
126
127 # Get all vertices
128 for n in range(numVertices):
129 line = getNextLine(f).split()
130 if len(line) < 3:
131 print("Error: to few coordinates for vertex", n)
132
133 # Add the vertex
134 vertices += [ list(map(float, line[0:3])) ]
135
136 # Get all faces
137 for n in range(numFaces):
138 line = getNextLine(f).split()
139
140 # Get number of vertices
141 lenFace = int(line[0])
142 line = line[1:]
143 if len(line) < lenFace:
144 print("Error: to few vertices for face", n)
145
146 # Add the face
147 faces += [ list(map(int, line[0:lenFace])) ]
148
149 print("Finish reading file. Got %d vertices, %d faces." % \
150 (len(vertices), len(faces)) )
151
152 # Add a mesh
153 me = bpy.data.meshes.new("Mesh")
154
155 vertexdata = unpack_vertices(vertices)
156 facedata = unpack_faces(faces)
157
158 # Add given number of vertices and faces
159 me.vertices.add( len(vertexdata)//3 )
160 me.faces.add( len(facedata)//4 )
161 me.vertices.foreach_set("co", vertexdata)
162 me.faces.foreach_set("vertices_raw", facedata)
163 me.update()
164
165 ob = bpy.data.objects.new("Mesh", me)
166 ob.data = me
167 scene = context.scene
168
169 scene.objects.link(ob)
170 scene.objects.active = ob
171
172 except Exception as e:
173 print("Error reading .off file")
174 print(e)
175 return False
176
177
178
179 class ImportOffFile(bpy.types.Operator):
180 '''Import DEC object file format (.off) files as specified by
181 http://shape.cs.princeton.edu/benchmark/documentation/off_format.html'''
182
183 bl_idname = "import.off_files"
184 bl_label = "Import DEC Object File Format (.off)"
185 bl_description = "Imports DEC object file format (.off)"
186 bl_options = {'REGISTER'}
187
188 filepath = StringProperty(name="File Path",
189 description="Filepath used for importing the file",
190 maxlen=1024,
191 default="" )
192
193 extEnum = [
194 ('*', 'All image formats', 'Import all know image (or movie) formats.'),
195 ('off', 'OFF (.off)', 'Object File Format') ]
196
197 extension = EnumProperty(name="Extension",
198 description="Only import files of this type.",
199 items=extEnum )
200
201 def execute(self, context):
202
203 # File Path
204 filepath = self.properties.filepath
205 # Call Main Function
206 importFile(filepath, context)
207
208 return {'FINISHED'}
209
210 def invoke(self, context, event):
211 wm = bpy.context.window_manager
212 wm.fileselect_add(self)
213
214 return {'RUNNING_MODAL'}
215
216
217 # Registering / Unregister
218 def menu_func(self, context):
219 self.layout.operator(ImportOffFile.bl_idname, \
220 text="DEC Object File Format (.off)", icon='PLUGIN')
221
222 def register():
223 bpy.types.INFO_MT_file_import.append(menu_func)
224
225 def unregister():
226 bpy.types.INFO_MT_file_import.remove(menu_func)
227
228
229 if __name__ == "__main__":
230 register()