[6] | 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 | |
---|