#!/usr/bin/env python # # aof2obj - convert Artlantis Object Format files to Wavefront OBJ # # Copyright (C) 2012 Antonio Ospite # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import sys from lxml import etree import binascii def usage(name): sys.stdout.write("usage: %s \n" % name) def aof2obj(aof_filename, obj_filename, basename): f = open(aof_filename, "r") # Use recover mode, because the xml format is ill-specified: # there is at least one element with the name starting with a number # <3D.Paths>, in violation to the XML spec. # And there is some elements with the UUID attribute specified multiple # times... parser = etree.XMLParser(recover=True) tree = etree.parse(f, parser) # The preview image could be some bitmap format, don't know yet preview = tree.find("Preview.Image") if preview is not None: heximage = preview.text.rstrip("\t\n") preview_file = open(basename + ".prw", "w") preview_file.write(binascii.unhexlify(heximage)) preview_file.close() obj_file = open(obj_filename, "w") obj_file.write("# obj file created with aof2obj\n") obj_file.write("# by Antonio Ospite\n\n") # Vertices points = tree.find('Points') points_data = points.text.strip("\t\n").split("\n") for p in points_data[1:]: obj_file.write("v %s\n" % p.rstrip(' ')) obj_file.write("# %d vertices\n\n" % int(points_data[0])) # Faces polygons = tree.find('Polygons') polygons_data = polygons.text.strip("\t\n").split("\n") current_object = -1 for p in polygons_data[1:]: ptype, pdata = p.split("\t") if ptype != 'o' and ptype != 'p': sys.stderr.write("Unsupported polygon type") sys.exit(1) # If there is a M in pdata discard the line # don't know how to handle that if 'M' in pdata: sys.stdout.write("Warning, ignored M element\n") continue # Don't know what the 'I' stands for yet, for now just ignore it pdata = pdata.replace(' I ', ' ').strip(' ') pdata_list = pdata.split(' ') obj_number = int(pdata_list[0]) num_verts = int(pdata_list[1]) # Vert indices start from 1 in .obj files verts_data = " ".join([str(int(i) + 1) for i in pdata_list[2:]]) if obj_number != current_object: obj_file.write("\n# defining Object_%d\n" % obj_number) obj_file.write("g Object_%d\n" % obj_number) current_object = obj_number obj_file.write("f %s\n" % verts_data) obj_file.write("# %d faces\n\n" % int(polygons_data[0])) obj_file.close() if __name__ == "__main__": if len(sys.argv) < 2: usage(sys.argv[0]) sys.exit(1) aof_filename = sys.argv[1] basename_no_ext = os.path.splitext(aof_filename)[0] obj_filename = basename_no_ext + ".obj" aof2obj(aof_filename, obj_filename, basename_no_ext) sys.exit(0)