Scripts:
[blender.git] / release / scripts / lightwave_import.py
1 #!BPY
2
3 """
4 Name: 'LightWave (.lwo)...'
5 Blender: 232
6 Group: 'Import'
7 Tooltip: 'Import LightWave Object File Format (.lwo)'
8 """
9
10 __author__ = "Anthony D'Agostino (Scorpius)"
11 __url__ = ("blender", "elysiun",
12 "Author's homepage, http://www.redrival.com/scorpius")
13 __version__ = "Part of IOSuite 0.5"
14
15 __bpydoc__ = """\
16 This script imports LightWave files to Blender.
17
18 LightWave is a full-featured commercial modeling and rendering
19 application. The lwo file format is composed of 'chunks,' is well
20 defined, and easy to read and write. It is similar in structure to the
21 trueSpace cob format.
22
23 Usage:<br>
24         Execute this script from the "File->Import" menu and choose a LightWave
25 file to open.
26
27 Supported:<br>
28         Meshes only.
29
30 Missing:<br>
31     Materials, UV Coordinates, and Vertex Color info will be ignored.
32
33 Known issues:<br>
34         Triangulation of convex polygons works fine, and uses a very simple
35 fanning algorithm. Convex polygons (i.e., shaped like the letter "U")
36 require a different algorithm, and will be triagulated incorrectly.
37
38 Notes:<br>
39         Also reads lwo files in the old LW v5.5 format.
40 """
41
42 # $Id$
43 #
44 # +---------------------------------------------------------+
45 # | Copyright (c) 2002 Anthony D'Agostino                   |
46 # | http://www.redrival.com/scorpius                        |
47 # | scorpius@netzero.com                                    |
48 # | April 21, 2002                                          |
49 # | Released under the Blender Artistic Licence (BAL)       |
50 # | Import Export Suite v0.5                                |
51 # +---------------------------------------------------------+
52 # | Read and write LightWave Object File Format (*.lwo)     |
53 # +---------------------------------------------------------+
54
55 import Blender, mod_meshtools
56 import struct, chunk, os, cStringIO, time, operator
57
58 # =============================
59 # === Read LightWave Format ===
60 # =============================
61 def read(filename):
62         start = time.clock()
63         file = open(filename, "rb")
64
65         # === LWO header ===
66         form_id, form_size, form_type = struct.unpack(">4s1L4s",  file.read(12))
67         if (form_type != "LWOB") and (form_type != "LWO2"):
68                 print "Can't read a file with the form_type:", form_type
69                 return
70
71         objname = os.path.splitext(os.path.basename(filename))[0]
72
73         while 1:
74                 try:
75                         lwochunk = chunk.Chunk(file)
76                 except EOFError:
77                         break
78                 if lwochunk.chunkname == "LAYR":
79                         objname = read_layr(lwochunk)
80                 elif lwochunk.chunkname == "PNTS":                         # Verts
81                         verts = read_verts(lwochunk)
82                 elif lwochunk.chunkname == "POLS" and form_type == "LWO2": # Faces v6.0
83                         faces = read_faces_6(lwochunk)
84                         mod_meshtools.create_mesh(verts, faces, objname)
85                 elif lwochunk.chunkname == "POLS" and form_type == "LWOB": # Faces v5.5
86                         faces = read_faces_5(lwochunk)
87                         mod_meshtools.create_mesh(verts, faces, objname)
88                 else:                                                                                                      # Misc Chunks
89                         lwochunk.skip()
90
91         Blender.Window.DrawProgressBar(1.0, "")    # clear progressbar
92         file.close()
93         end = time.clock()
94         seconds = " in %.2f %s" % (end-start, "seconds")
95         if form_type == "LWO2": fmt = " (v6.0 Format)"
96         if form_type == "LWOB": fmt = " (v5.5 Format)"
97         message = "Successfully imported " + os.path.basename(filename) + fmt + seconds
98         mod_meshtools.print_boxed(message)
99
100 # ==================
101 # === Read Verts ===
102 # ==================
103 def read_verts(lwochunk):
104         data = cStringIO.StringIO(lwochunk.read())
105         numverts = lwochunk.chunksize/12
106         #$verts = []
107         verts = [None] * numverts
108         for i in range(numverts):
109                 if not i%100 and mod_meshtools.show_progress:
110                         Blender.Window.DrawProgressBar(float(i)/numverts, "Reading Verts")
111                 x, y, z = struct.unpack(">fff", data.read(12))
112                 #$verts.append((x, z, y))
113                 verts[i] = (x, z, y)
114         return verts
115
116 # =================
117 # === Read Name ===
118 # =================
119 def read_name(file):
120         name = ""
121         while 1:
122                 char = file.read(1)
123                 if char == "\0": break
124                 else: name += char
125         return name
126
127 # ==================
128 # === Read Layer ===
129 # ==================
130 def read_layr(lwochunk):
131         data = cStringIO.StringIO(lwochunk.read())
132         idx, flags = struct.unpack(">hh", data.read(4))
133         pivot = struct.unpack(">fff", data.read(12))
134         layer_name = read_name(data)
135         if not layer_name: layer_name = "No Name"
136         return layer_name
137
138 # ======================
139 # === Read Faces 5.5 ===
140 # ======================
141 def read_faces_5(lwochunk):
142         data = cStringIO.StringIO(lwochunk.read())
143         faces = []
144         i = 0
145         while i < lwochunk.chunksize:
146                 if not i%100 and mod_meshtools.show_progress:
147                    Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces")
148                 facev = []
149                 numfaceverts, = struct.unpack(">H", data.read(2))
150                 for j in range(numfaceverts):
151                         index, = struct.unpack(">H", data.read(2))
152                         facev.append(index)
153                 facev.reverse()
154                 faces.append(facev)
155                 surfaceindex, = struct.unpack(">H", data.read(2))
156                 if surfaceindex < 0:
157                         print "detail polygons follow, error."
158                         return
159                 i += (4+numfaceverts*2)
160         return faces
161
162 # ==================================
163 # === Read Variable-Length Index ===
164 # ==================================
165 def read_vx(data):
166         byte1, = struct.unpack(">B", data.read(1))
167         if byte1 != 0xFF:       # 2-byte index
168                 byte2, = struct.unpack(">B", data.read(1))
169                 index = byte1*256 + byte2
170                 index_size = 2
171         else:                           # 4-byte index
172                 byte2, byte3, byte4 = struct.unpack(">3B", data.read(3))
173                 index = byte2*65536 + byte3*256 + byte4
174                 index_size = 4
175         return index, index_size
176
177 # ======================
178 # === Read Faces 6.0 ===
179 # ======================
180 def read_faces_6(lwochunk):
181         data = cStringIO.StringIO(lwochunk.read())
182         faces = []
183         polygon_type = data.read(4)
184         if polygon_type != "FACE":
185                 print "No Faces Were Found. Polygon Type:", polygon_type
186                 return ""
187         i = 0
188         while(i < lwochunk.chunksize-4):
189                 if not i%100 and mod_meshtools.show_progress:
190                    Blender.Window.DrawProgressBar(float(i)/lwochunk.chunksize, "Reading Faces")
191                 facev = []
192                 numfaceverts, = struct.unpack(">H", data.read(2))
193                 i += 2
194
195                 for j in range(numfaceverts):
196                         index, index_size = read_vx(data)
197                         i += index_size
198                         facev.append(index)
199                 facev.reverse()
200                 faces.append(facev)
201         return faces
202
203 def fs_callback(filename):
204         read(filename)
205
206 Blender.Window.FileSelector(fs_callback, "Import LWO")