--- /dev/null
+# io_import_off.py Stefan Huber\r
+#\r
+# Import DEC Object File Format (*.off)\r
+\r
+\r
+bl_addon_info = {\r
+ "name": "Import DEC Object File Format (.off)",\r
+ "author": "Stefan Huber (shuber)",\r
+ "version": (0,7),\r
+ "blender": (2, 5, 3),\r
+ "api": 31667,\r
+ "location": "File > Import > Import DEC Object File Format (.off)",\r
+ "description": "Import DEC Object File Format (.off) files",\r
+ "warning": "",\r
+ "category": "Import/Export"\r
+ }\r
+\r
+\r
+\r
+__author__ = "Stefan Huber"\r
+#__url__ = ("blender", "blenderartists.org", "Author's homepage, http://www.redrival.com/scorpius")\r
+#__version__ = "Part of IOSuite 0.5"\r
+\r
+__bpydoc__ = """\\r
+This script imports DEC Object File Format files to Blender.\r
+\r
+The DEC (Digital Equipment Corporation) OFF format is very old and\r
+almost identical to Wavefront's OBJ. I wrote this so I could get my huge\r
+meshes into Moonlight Atelier. (DXF can also be used but the file size\r
+is five times larger than OFF!) Blender/Moonlight users might find this\r
+script to be very useful.\r
+\r
+Usage:<br>\r
+ Execute this script from the "File->Import" menu and choose an OFF file to\r
+open.\r
+\r
+Notes:<br>\r
+ Port to blender 2.5 beta 2. - shuber\r
+ UV Coordinate support has been added. - Scorpius\r
+ FGON support has been added. - Cam\r
+ New Mesh module now used. - Cam\r
+"""\r
+\r
+import bpy\r
+from bpy.props import *\r
+\r
+\r
+\r
+def isComment(line):\r
+ """Is this line a comment line?"""\r
+ line = line.strip()\r
+ if len(line) == 0:\r
+ return False\r
+ if line[0] == "#":\r
+ return True\r
+ return False\r
+\r
+\r
+def getNextLine(f):\r
+ """Read next line from file 'f' and ignore comments"""\r
+ line = f.readline().strip()\r
+ while isComment(line):\r
+ line = f.readline().strip()\r
+ return line\r
+\r
+\r
+\r
+def unpack_vertices( vertices ):\r
+ l = []\r
+ for t in vertices:\r
+ l.extend(t)\r
+ return l\r
+\r
+\r
+def unpack_faces(faces):\r
+\r
+ l = []\r
+ for face in faces:\r
+\r
+ # Build triangle fans\r
+ for k in range(1, len(face)-1):\r
+\r
+ tri = [face[0], face[k], face[k+1]]\r
+\r
+ # Rotate triangle, such that last index is not zero\r
+ if tri[2] == 0:\r
+ tri = [ tri[2], tri[0], tri[1] ]\r
+ \r
+ l.extend(tri)\r
+ l.extend([0])\r
+\r
+ return l\r
+\r
+\r
+def importFile(filepath, context):\r
+\r
+ # List of vertices, a vertex is a 3-tuple (x,y,z)\r
+ vertices = [] \r
+ # List of faces, a face is a list of indices within vertices\r
+ faces = []\r
+\r
+ try:\r
+\r
+ f = open(filepath, "r")\r
+\r
+ # Get the header line\r
+ line = getNextLine(f)\r
+ if line != "OFF":\r
+ print("Error: header line does not start with 'OFF'.")\r
+ print(line)\r
+ return False\r
+\r
+ #Get number of vertices, faces and edges\r
+ line = getNextLine(f).split()\r
+ if len(line) < 2:\r
+ print("Error: Line of number of vertices, faces and edges is invalid.")\r
+ return False\r
+ [numVertices, numFaces] = map(int, line[0:2])\r
+\r
+ if numVertices < 0:\r
+ print("Error: Number of vertices is negative!")\r
+ return False\r
+ if numFaces < 0:\r
+ print("Error: Number of faces is negative!")\r
+ return False\r
+\r
+ # Get all vertices\r
+ for n in range(numVertices):\r
+ line = getNextLine(f).split()\r
+ if len(line) < 3:\r
+ print("Error: to few coordinates for vertex", n)\r
+\r
+ # Add the vertex\r
+ vertices += [ list(map(float, line[0:3])) ]\r
+\r
+ # Get all faces\r
+ for n in range(numFaces):\r
+ line = getNextLine(f).split()\r
+ \r
+ # Get number of vertices\r
+ lenFace = int(line[0])\r
+ line = line[1:]\r
+ if len(line) < lenFace:\r
+ print("Error: to few vertices for face", n)\r
+\r
+ # Add the face\r
+ faces += [ list(map(int, line[0:lenFace])) ]\r
+\r
+ print("Finish reading file. Got %d vertices, %d faces." % \\r
+ (len(vertices), len(faces)) )\r
+\r
+ # Add a mesh\r
+ me = bpy.data.meshes.new("Mesh")\r
+\r
+ vertexdata = unpack_vertices(vertices)\r
+ facedata = unpack_faces(faces)\r
+\r
+ # Add given number of vertices and faces\r
+ me.vertices.add( len(vertexdata)//3 )\r
+ me.faces.add( len(facedata)//4 )\r
+ me.vertices.foreach_set("co", vertexdata)\r
+ me.faces.foreach_set("vertices_raw", facedata)\r
+ me.update()\r
+\r
+ ob = bpy.data.objects.new("Mesh", me)\r
+ ob.data = me\r
+ scene = context.scene\r
+\r
+ scene.objects.link(ob)\r
+ scene.objects.active = ob\r
+\r
+ except Exception as e:\r
+ print("Error reading .off file")\r
+ print(e)\r
+ return False\r
+ \r
+\r
+\r
+class ImportOffFile(bpy.types.Operator):\r
+ '''Import DEC object file format (.off) files as specified by\r
+http://shape.cs.princeton.edu/benchmark/documentation/off_format.html'''\r
+\r
+ bl_idname = "import.off_files"\r
+ bl_label = "Import DEC Object File Format (.off)"\r
+ bl_description = "Imports DEC object file format (.off)"\r
+ bl_options = {'REGISTER'}\r
+\r
+ filepath = StringProperty(name="File Path",\r
+ description="Filepath used for importing the file",\r
+ maxlen=1024,\r
+ default="" )\r
+\r
+ extEnum = [\r
+ ('*', 'All image formats', 'Import all know image (or movie) formats.'),\r
+ ('off', 'OFF (.off)', 'Object File Format') ]\r
+\r
+ extension = EnumProperty(name="Extension",\r
+ description="Only import files of this type.",\r
+ items=extEnum )\r
+\r
+ def execute(self, context):\r
+\r
+ # File Path\r
+ filepath = self.properties.filepath\r
+ # Call Main Function\r
+ importFile(filepath, context)\r
+\r
+ return {'FINISHED'}\r
+\r
+ def invoke(self, context, event):\r
+ wm = bpy.context.window_manager\r
+ wm.add_fileselect(self)\r
+\r
+ return {'RUNNING_MODAL'}\r
+\r
+\r
+# Registering / Unregister\r
+def menu_func(self, context):\r
+ self.layout.operator(ImportOffFile.bl_idname, \\r
+ text="DEC Object File Format (.off)", icon='PLUGIN')\r
+\r
+def register():\r
+ bpy.types.INFO_MT_file_import.append(menu_func)\r
+\r
+def unregister():\r
+ bpy.types.INFO_MT_file_import.remove(menu_func)\r
+\r
+\r
+if __name__ == "__main__":\r
+ register()\r