Initial import
[aof2obj.git] / aof2obj.py
1 #!/usr/bin/env python
2 #
3 # aof2obj - convert Artlantis Object Format files to Wavefront OBJ
4 #
5 # Copyright (C) 2012  Antonio Ospite <ospite@studenti.unina.it>
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 import os
21 import sys
22 from lxml import etree
23 import binascii
24
25
26 def usage(name):
27     sys.stdout.write("usage: %s <aof file>\n" % name)
28
29
30 def aof2obj(aof_filename, obj_filename, basename):
31
32     f = open(aof_filename, "r")
33
34     # Use recover mode, because the xml format is ill-specified:
35     # there is at least one element with the name starting with a number
36     # <3D.Paths>, in violation to the XML spec.
37     # And there is some elements with the UUID attribute specified multiple
38     # times...
39     parser = etree.XMLParser(recover=True)
40     tree = etree.parse(f, parser)
41
42     # The preview image could be some bitmap format, don't know yet
43     preview = tree.find("Preview.Image")
44     if preview is not None:
45         heximage = preview.text.rstrip("\t\n")
46
47         preview_file = open(basename + ".prw", "w")
48         preview_file.write(binascii.unhexlify(heximage))
49         preview_file.close()
50
51     obj_file = open(obj_filename, "w")
52
53     obj_file.write("# obj file created with aof2obj\n")
54     obj_file.write("# by Antonio Ospite\n\n")
55
56     # Vertices
57     points = tree.find('Points')
58     points_data = points.text.strip("\t\n").split("\n")
59
60     for p in points_data[1:]:
61         obj_file.write("v %s\n" % p.rstrip(' '))
62
63     obj_file.write("# %d vertices\n\n" % int(points_data[0]))
64
65     # Faces
66     polygons = tree.find('Polygons')
67     polygons_data = polygons.text.strip("\t\n").split("\n")
68
69     current_object = -1
70
71     for p in polygons_data[1:]:
72         ptype, pdata = p.split("\t")
73         if ptype != 'o' and ptype != 'p':
74             sys.stderr.write("Unsupported polygon type")
75             sys.exit(1)
76
77         # If there is a M in pdata discard the line
78         # don't know how to handle that
79         if 'M' in pdata:
80             sys.stdout.write("Warning, ignored M element\n")
81             continue
82
83         # Don't know what the 'I' stands for yet, for now just ignore it
84         pdata = pdata.replace(' I ', ' ').strip(' ')
85
86         pdata_list = pdata.split(' ')
87
88         obj_number = int(pdata_list[0])
89         num_verts = int(pdata_list[1])
90
91         # Vert indices start from 1 in .obj files
92         verts_data = " ".join([str(int(i) + 1) for i in pdata_list[2:]])
93
94         if obj_number != current_object:
95             obj_file.write("\n# defining Object_%d\n" % obj_number)
96             obj_file.write("g Object_%d\n" % obj_number)
97             current_object = obj_number
98
99         obj_file.write("f %s\n" % verts_data)
100
101     obj_file.write("# %d faces\n\n" % int(polygons_data[0]))
102
103     obj_file.close()
104
105
106 if __name__ == "__main__":
107
108     if len(sys.argv) < 2:
109         usage(sys.argv[0])
110         sys.exit(1)
111
112     aof_filename = sys.argv[1]
113     basename_no_ext = os.path.splitext(aof_filename)[0]
114     obj_filename = basename_no_ext + ".obj"
115
116     aof2obj(aof_filename, obj_filename, basename_no_ext)
117
118     sys.exit(0)