1 | |
---|
2 | # |
---|
3 | # TODO: |
---|
4 | # parse vertex colors and UV coordinates |
---|
5 | # remove faces with the hole material |
---|
6 | # |
---|
7 | |
---|
8 | from erlang_ext import * |
---|
9 | import types |
---|
10 | import pprint |
---|
11 | |
---|
12 | import mesh |
---|
13 | |
---|
14 | try: |
---|
15 | import Image |
---|
16 | except: |
---|
17 | pass |
---|
18 | |
---|
19 | def safe_append(ctr, key, value): |
---|
20 | if ctr.has_key(key): |
---|
21 | ctr[key].append(value) |
---|
22 | else: |
---|
23 | ctr[key] = [value] |
---|
24 | |
---|
25 | class wings_reader: |
---|
26 | |
---|
27 | dump = __name__ == '__main__' |
---|
28 | |
---|
29 | def __init__(self, raw_data, writeImages, keepRotation): |
---|
30 | self.data = raw_data |
---|
31 | self.writeImages = writeImages |
---|
32 | self.keepRotation = keepRotation |
---|
33 | # read and check |
---|
34 | a, self.ver, wingsdata = self.data |
---|
35 | if a != erlang_atom("wings") or self.ver != 2: |
---|
36 | raise IOError("Unknown wings version") |
---|
37 | |
---|
38 | #if self.dump: |
---|
39 | # pp = pprint.PrettyPrinter(indent=4,width=78) |
---|
40 | # pp.pprint(wingsdata) |
---|
41 | |
---|
42 | self.raw_objects, self.raw_materials, self.raw_props = wingsdata |
---|
43 | |
---|
44 | def parse(self): |
---|
45 | return self.parse_2() |
---|
46 | |
---|
47 | def parse_2(self): |
---|
48 | scene = mesh.Mesh() |
---|
49 | scene.name = "wings_object" |
---|
50 | self.materials = scene.materials |
---|
51 | self.mat_images = {} |
---|
52 | for raw_mat in self.raw_materials: |
---|
53 | wmat = self.parse_2_material(raw_mat) |
---|
54 | scene.materials.append(wmat) |
---|
55 | self.parse_2_images() |
---|
56 | for raw_obj in self.raw_objects: |
---|
57 | wobj = self.parse_2_object(raw_obj) |
---|
58 | scene.merge(wobj) |
---|
59 | self.postprocess(scene) |
---|
60 | return scene |
---|
61 | |
---|
62 | def parse_2_image(self, index, raw_image): |
---|
63 | w, h, spp = 0, 0, 0 |
---|
64 | pixels = None |
---|
65 | filename = None |
---|
66 | for elem in raw_image: |
---|
67 | if elem[0] == erlang_atom("width"): |
---|
68 | w = elem[1] |
---|
69 | if elem[0] == erlang_atom("height"): |
---|
70 | h = elem[1] |
---|
71 | if elem[0] == erlang_atom("samples_per_pixel"): |
---|
72 | spp = elem[1] |
---|
73 | if elem[0] == erlang_atom("pixels"): |
---|
74 | pixels = elem[1] |
---|
75 | |
---|
76 | if not pixels: |
---|
77 | return None |
---|
78 | |
---|
79 | if spp == 3: mode = 'RGB' |
---|
80 | else: mode = 'L' |
---|
81 | im = Image.new(mode, (w, h)) |
---|
82 | |
---|
83 | print "processing image" |
---|
84 | print mode, spp, w, h, len(pixels) |
---|
85 | |
---|
86 | pixels = map(lambda x: ord(x), pixels) |
---|
87 | for x in range(w): |
---|
88 | for y in range(h): |
---|
89 | i = (x + y * w) * 3 |
---|
90 | yy = h - 1 - y # huh? |
---|
91 | im.putpixel((x, yy), tuple(pixels[i:i+3])) |
---|
92 | #bands = [tuple(pixels[i*3:i*3+3]) for i in range(w * h)] |
---|
93 | |
---|
94 | #print pixels |
---|
95 | #print bands |
---|
96 | |
---|
97 | #im.putdata(bands) |
---|
98 | |
---|
99 | if self.mat_images.has_key(index): |
---|
100 | filename = self.mat_images[index] |
---|
101 | im.save(filename) |
---|
102 | return im |
---|
103 | |
---|
104 | def parse_2_images(self): |
---|
105 | if not self.writeImages: |
---|
106 | return |
---|
107 | images = [] |
---|
108 | if self.raw_props: |
---|
109 | for elem in self.raw_props: |
---|
110 | if elem[0] == erlang_atom('images'): |
---|
111 | images = elem[1] |
---|
112 | |
---|
113 | for raw_im_data in images: |
---|
114 | index, raw_im = raw_im_data[:2] |
---|
115 | self.parse_2_image(index, raw_im) |
---|
116 | |
---|
117 | def parse_2_material(self, raw_mat): |
---|
118 | |
---|
119 | atom, data = raw_mat |
---|
120 | |
---|
121 | #pp = pprint.PrettyPrinter(indent=4,width=78) |
---|
122 | #pp.pprint(data) |
---|
123 | |
---|
124 | #raw_maps, raw_gl = data[:2] |
---|
125 | |
---|
126 | mat = mesh.Material(str(atom)) |
---|
127 | |
---|
128 | for tag in data: |
---|
129 | a, elem_data = tag |
---|
130 | if a == erlang_atom('openg'): |
---|
131 | for elem in elem_data: |
---|
132 | if elem[0] == erlang_atom('ambient'): |
---|
133 | mat.ambient = elem[1] |
---|
134 | if elem[0] == erlang_atom('diffuse'): |
---|
135 | mat.diffuse = elem[1] |
---|
136 | if elem[0] == erlang_atom('specular'): |
---|
137 | mat.specular = elem[1] |
---|
138 | if elem[0] == erlang_atom('shininess'): |
---|
139 | mat.shininess = elem[1] |
---|
140 | elif a == erlang_atom('maps') and elem_data: |
---|
141 | filename = str(atom) + '.png' |
---|
142 | mat.textures.append(filename) |
---|
143 | self.mat_images[elem_data[0][1]] = filename |
---|
144 | |
---|
145 | return mat |
---|
146 | |
---|
147 | |
---|
148 | def check_atom(self, atom, name): |
---|
149 | if atom != erlang_atom(name): |
---|
150 | raise IOError("Unexpected atom: %s expected, %s found" % |
---|
151 | (erlang_atom(name), atom)) |
---|
152 | |
---|
153 | def parse_2_edges(self, wobj, raw_edges, hard_edges): |
---|
154 | faces = {} |
---|
155 | for edge_index in range(len(raw_edges)): |
---|
156 | raw_edge = raw_edges[edge_index] |
---|
157 | LSp, LEp = None, None |
---|
158 | for elem in raw_edge: |
---|
159 | |
---|
160 | if elem[0] == erlang_atom('edge'): |
---|
161 | edgedata = elem |
---|
162 | |
---|
163 | # |
---|
164 | # the color data for the face on the sides of this |
---|
165 | # edge, rgb1/uv1 is for Lf:Sv, rgb2/uv2 is for Rf:Ev |
---|
166 | # |
---|
167 | if elem[0] == erlang_atom('uv'): |
---|
168 | uvdata = struct.unpack('>dddd', elem[1]) |
---|
169 | u1, v1, u2, v2 = uvdata |
---|
170 | LSp = mesh.ColorProp((u1, v1)) |
---|
171 | LEp = mesh.ColorProp((u2, v2)) |
---|
172 | |
---|
173 | # new UV packing for Wings3D 0.98.16b? |
---|
174 | # I leave the old code in for older mesh files |
---|
175 | if elem[0] == erlang_atom('uv_lt'): |
---|
176 | uvdata = struct.unpack('>dd', elem[1]) |
---|
177 | u1, v1 = uvdata |
---|
178 | LSp = mesh.ColorProp((u1, v1)) |
---|
179 | |
---|
180 | if elem[0] == erlang_atom('uv_rt'): |
---|
181 | uvdata = struct.unpack('>dd', elem[1]) |
---|
182 | u2, v2 = uvdata |
---|
183 | LEp = mesh.ColorProp((u2, v2)) |
---|
184 | |
---|
185 | if elem[0] == erlang_atom('color'): |
---|
186 | colordata = struct.unpack('>dddddd', elem[1]) |
---|
187 | r1, g1, b1, r2, g2, b2 = colordata |
---|
188 | LSp = mesh.ColorProp((r1, g1, b1, 1)) |
---|
189 | LEp = mesh.ColorProp((r2, g2, b2, 1)) |
---|
190 | |
---|
191 | # read winged data |
---|
192 | a, Sv, Ev, Lf, Rf, LP, LS, RP, RS = edgedata |
---|
193 | self.check_atom(a, "edge") |
---|
194 | |
---|
195 | minf, maxf = min(Lf, Rf), max(Lf, Rf) |
---|
196 | wobj.edges.append((minf, maxf, Sv, Ev)) |
---|
197 | |
---|
198 | # store color info here if any |
---|
199 | if LSp and LEp: |
---|
200 | if wobj.face_vert_colors.has_key((Lf, Sv)) or \ |
---|
201 | wobj.face_vert_colors.has_key((Rf, Ev)): |
---|
202 | print "hey!" |
---|
203 | wobj.face_vert_colors[(Lf, Sv)] = LSp |
---|
204 | wobj.face_vert_colors[(Rf, Ev)] = LEp |
---|
205 | |
---|
206 | # store hardness info |
---|
207 | if edge_index in hard_edges: |
---|
208 | wobj.hard_edges.append((minf, maxf)) |
---|
209 | |
---|
210 | # store left and right face |
---|
211 | safe_append(faces, Lf, (Sv, Ev)) |
---|
212 | safe_append(faces, Rf, (Ev, Sv)) |
---|
213 | |
---|
214 | # === put edges (Sv & Ev) in correct order === |
---|
215 | # === faces{} now contains a sorted list of edges (Sv & Ev) for each face |
---|
216 | for i in range(len(faces)): |
---|
217 | face = faces[i] |
---|
218 | swaps = 1 |
---|
219 | while swaps: |
---|
220 | swaps = 0 |
---|
221 | for j in range(len(face)-2): |
---|
222 | if face[j][1] != face[j+1][0]: |
---|
223 | face[j+1], face[j+2] = face[j+2], face[j+1] # swap them |
---|
224 | swaps = 1 |
---|
225 | |
---|
226 | # replace tuples with vertex indices, also convert the map to sequence |
---|
227 | # s is a sequence of edges, e is an edge |
---|
228 | wobj.faces = map(lambda s: map(lambda e: e[0], s), faces.values()) |
---|
229 | |
---|
230 | if self.dump: |
---|
231 | print "*** Edges parsed" |
---|
232 | pp = pprint.PrettyPrinter(indent=4,width=78) |
---|
233 | pp.pprint(wobj.faces) |
---|
234 | pp.pprint(wobj.face_vert_colors) |
---|
235 | pp.pprint(wobj.hard_edges) |
---|
236 | |
---|
237 | def parse_2_faces(self, wobj, raw_faces): |
---|
238 | |
---|
239 | for face in range(len(raw_faces)): |
---|
240 | raw_face = raw_faces[face] |
---|
241 | if raw_face: |
---|
242 | for elem in raw_face: |
---|
243 | if elem[0] == erlang_atom('material'): |
---|
244 | mat_name = str(elem[1]) |
---|
245 | mat_id = wobj.find_material(mat_name) |
---|
246 | else: |
---|
247 | try: |
---|
248 | mat_id = wobj.find_material("default") |
---|
249 | except: |
---|
250 | mat_id = 0 |
---|
251 | wobj.face_materials.append(mat_id) |
---|
252 | |
---|
253 | if self.dump: |
---|
254 | print "*** Faces parsed" |
---|
255 | pp = pprint.PrettyPrinter(indent=4,width=78) |
---|
256 | pp.pprint(wobj.face_materials) |
---|
257 | |
---|
258 | |
---|
259 | def parse_2_verts(self, wobj, raw_verts): |
---|
260 | wobj.verts = [] |
---|
261 | |
---|
262 | for vertdata in raw_verts: |
---|
263 | x, y, z = struct.unpack(">ddd", vertdata[0]) # double precision |
---|
264 | if self.keepRotation: |
---|
265 | wobj.verts.append((x, -z, y)) |
---|
266 | else: |
---|
267 | wobj.verts.append((x, y, z)) |
---|
268 | |
---|
269 | def parse_2_object(self, obj): |
---|
270 | a, name, winged, mode = obj |
---|
271 | self.check_atom(a, "object") |
---|
272 | |
---|
273 | # if mode is invisible, skip this |
---|
274 | |
---|
275 | a, raw_edges, raw_faces, raw_verts, raw_edge_htable = winged |
---|
276 | self.check_atom(a, "winged") |
---|
277 | |
---|
278 | print "reading object '%s' (%d faces, %d edges, %d vertices)" % (name, |
---|
279 | len(raw_faces), len(raw_edges), len(raw_verts)) |
---|
280 | |
---|
281 | # raw_edge_htable lists hard edges |
---|
282 | # (edges are soft by default, so this table may be empty, thus None) |
---|
283 | if raw_edge_htable == None: raw_edge_htable = [] |
---|
284 | |
---|
285 | if type(raw_edge_htable) == types.StringType: |
---|
286 | raw_edge_htable = map(ord, raw_edge_htable) |
---|
287 | #print raw_edge_htable |
---|
288 | |
---|
289 | wobj = mesh.Mesh() |
---|
290 | wobj.materials = self.materials |
---|
291 | wobj.name = name |
---|
292 | self.parse_2_edges(wobj, raw_edges, raw_edge_htable) |
---|
293 | self.parse_2_faces(wobj, raw_faces) |
---|
294 | self.parse_2_verts(wobj, raw_verts) |
---|
295 | |
---|
296 | return wobj |
---|
297 | |
---|
298 | def postprocess(self, wobj): |
---|
299 | wobj.make_face_normals() |
---|
300 | wobj.make_vert_normals(1) |
---|
301 | wobj.flatten() |
---|
302 | wobj.triangulate() |
---|
303 | wobj.submeshize() |
---|
304 | |
---|
305 | if self.dump: |
---|
306 | wobj.dump() |
---|
307 | |
---|
308 | def read_wings(filename, writeImages, keepRotation): |
---|
309 | e = erlang_ext_reader(filename) |
---|
310 | raw_data = e.read() |
---|
311 | |
---|
312 | ob = wings_reader(raw_data, writeImages, keepRotation) |
---|
313 | scene = ob.parse() |
---|
314 | |
---|
315 | return scene |
---|
316 | |
---|
317 | if __name__ == '__main__': |
---|
318 | try: |
---|
319 | e = erlang_ext_reader("C:/projects/3d/erpy/uv-cube.wings") |
---|
320 | #e = erlang_ext_reader("C:/projects/3d/erpy/mycar.wings") |
---|
321 | #e = erlang_ext_reader("/home/attis/src/erpy/cube-colored.wings") |
---|
322 | #e = erlang_ext_reader("/home/attis/src/erpy/tank1w.wings") |
---|
323 | raw_data = e.read() |
---|
324 | |
---|
325 | print "read" |
---|
326 | |
---|
327 | ob = wings_reader(raw_data) |
---|
328 | ob.parse() |
---|
329 | |
---|
330 | print "done" |
---|
331 | |
---|
332 | #pp = pprint.PrettyPrinter(indent=4,width=78) |
---|
333 | #file = open("log1.txt", "w") |
---|
334 | #file.write(pp.pformat(raw_data)) |
---|
335 | #file.write('\n') |
---|
336 | |
---|
337 | print "ok" |
---|
338 | |
---|
339 | finally: |
---|
340 | pp = pprint.PrettyPrinter(indent=4,width=78) |
---|
341 | pp.pprint(raw_data) |
---|
342 | |
---|