#!/usr/bin/env python3 from .basemodel import ModelParser, Exporter, Vertex, TexCoord, Normal, FaceVertex, Face, Material from functools import reduce import os.path import PIL.Image def is_obj(filename): return filename[-4:] == '.obj' class OBJParser(ModelParser): def __init__(self): super().__init__() self.current_material = None def parse_line(self, string): if string == '': return split = string.split() first = split[0] split = split[1:] if first == 'usemtl': self.current_material = split[0] elif first == 'mtllib': path = os.path.join(os.path.dirname(self.path), split[0]) self.mtl = MTLParser(self) self.mtl.parse_file(path) elif first == 'v': self.add_vertex(Vertex().from_array(split)) elif first == 'vn': self.add_normal(Normal().from_array(split)) elif first == 'vt': self.add_tex_coord(TexCoord().from_array(split)) elif first == 'f': splits = list(map(lambda x: x.split('/'), split)) for i in range(len(splits)): for j in range(len(splits[i])): if splits[i][j] is not '': splits[i][j] = int(splits[i][j]) - 1 face = Face().from_array(splits) face.material = self.current_material self.add_face(face) class MTLParser: def __init__(self, parent): self.parent = parent self.materials = [] self.current_mtl = None def parse_line(self, string): if string == '': return split = string.split() first = split[0] split = split[1:] if first == 'newmtl': self.current_mtl = Material(split[0]) self.materials.append(self.current_mtl) elif first == 'Ka': self.current_mtl.Ka = Vertex().from_array(split) elif first == 'Kd': self.current_mtl.Kd = Vertex().from_array(split) elif first == 'Ks': self.current_mtl.Ks = Vertex().from_array(split) elif first == 'map_Kd': self.map_Kd = PIL.Image.open(os.path.join(os.path.dirname(self.parent.path), split[0])) def parse_file(self, path): with open(path) as f: for line in f.readlines(): line = line.rstrip() self.parse_line(line) class OBJExporter(Exporter): def __init__(self, model): super().__init__(model) def __str__(self): string = "" for vertex in self.model.vertices: string += "v " + ' '.join([str(vertex.x), str(vertex.y), str(vertex.z)]) + "\n" string += "\n" if len(self.model.tex_coords) > 0: for tex_coord in self.model.tex_coords: string += "vt " + ' '.join([str(tex_coord.x), str(tex_coord.y)]) + "\n" string += "\n" if len(self.model.normals) > 0: for normal in self.model.normals: string += "vn " + ' '.join([str(normal.x), str(normal.y), str(normal.z)]) + "\n" string += "\n" for face in self.model.faces: string += "f " arr = [] for v in [face.a, face.b, face.c]: sub_arr = [] sub_arr.append(str(v.vertex + 1)) if v.normal is None: if v.texture is not None: sub_arr.append('') sub_arr.append(str(v.texture + 1)) elif v.texture is not None: sub_arr.append(str(v.texture + 1)) if v.normal is not None: sub_arr.append(str(v.normal + 1)) arr.append('/'.join(sub_arr)) string += ' '.join(arr) + '\n' return string