153 lines
4.8 KiB
Python
153 lines
4.8 KiB
Python
import os
|
|
import PIL
|
|
from ..basemodel import ModelParser, TextModelParser, Exporter, Vertex, Face, FaceVertex, TexCoord, Material
|
|
|
|
def is_ply(filename):
|
|
return filename[-4:] == '.ply'
|
|
|
|
class PLYParser(TextModelParser):
|
|
|
|
def __init__(self, up_conversion = None):
|
|
super().__init__(up_conversion)
|
|
self.counter = 0
|
|
self.elements = []
|
|
self.materials = []
|
|
self.inner_parser = PLYHeaderParser(self)
|
|
|
|
def parse_line(self, string):
|
|
self.inner_parser.parse_line(string)
|
|
|
|
class PLYHeaderParser:
|
|
def __init__(self, parent):
|
|
self.current_element = None
|
|
self.parent = parent
|
|
|
|
def parse_line(self, string):
|
|
split = string.split()
|
|
if string == 'ply':
|
|
return
|
|
|
|
elif split[0] == 'format':
|
|
if split[1] != 'ascii' or split[2] != '1.0':
|
|
print('Only ascii 1.0 format is supported', file=sys.stderr)
|
|
sys.exit(-1)
|
|
|
|
elif split[0] == 'element':
|
|
self.current_element = PLYElement(split[1], int(split[2]))
|
|
self.parent.elements.append(self.current_element)
|
|
|
|
elif split[0] == 'property':
|
|
self.current_element.add_property(split[-1], (split[1:][:-1]))
|
|
|
|
elif split[0] == 'end_header':
|
|
self.parent.inner_parser = PLYContentParser(self.parent)
|
|
|
|
elif split[0] == 'comment' and split[1] == 'TextureFile':
|
|
material = Material('mat' + str(len(self.parent.materials)))
|
|
self.parent.materials.append(material)
|
|
|
|
try:
|
|
material.map_Kd = PIL.Image.open(os.path.join(os.path.dirname(self.parent.path), split[2]))
|
|
except:
|
|
pass
|
|
|
|
|
|
|
|
class PLYElement:
|
|
def __init__(self, name, number):
|
|
self.name = name
|
|
self.number = number
|
|
self.properties = []
|
|
|
|
def add_property(self, name, type):
|
|
self.properties.append((name, type))
|
|
|
|
class PLYVertex(Vertex):
|
|
def __init__(self, string):
|
|
pass
|
|
|
|
def add_to_parser(self, parser):
|
|
pass
|
|
|
|
class PLYContentParser:
|
|
def __init__(self, parent):
|
|
self.parent = parent
|
|
self.element_index = 0
|
|
self.counter = 0
|
|
self.current_element = self.parent.elements[0]
|
|
|
|
def parse_line(self, string):
|
|
|
|
split = string.split()
|
|
|
|
if self.current_element.name == 'vertex':
|
|
self.parent.add_vertex(Vertex().from_array(split))
|
|
elif self.current_element.name == 'face':
|
|
|
|
faceVertexArray = []
|
|
current_material = None
|
|
|
|
# Analyse element
|
|
offset = 0
|
|
for property in self.current_element.properties:
|
|
if property[0] == 'vertex_indices':
|
|
for i in range(int(split[offset])):
|
|
faceVertexArray.append(FaceVertex(int(split[i+offset+1])))
|
|
offset += int(split[0]) + 1
|
|
elif property[0] == 'texcoord':
|
|
offset += 1
|
|
for i in range(3):
|
|
# Create corresponding tex_coords
|
|
tex_coord = TexCoord().from_array(split[offset:offset+2])
|
|
offset += 2
|
|
self.parent.add_tex_coord(tex_coord)
|
|
faceVertexArray[i].tex_coord = len(self.parent.tex_coords) - 1
|
|
elif property[0] == 'texnumber':
|
|
current_material = self.parent.materials[int(split[offset])]
|
|
|
|
face = Face(*faceVertexArray)
|
|
face.material = current_material
|
|
self.parent.add_face(face)
|
|
|
|
self.counter += 1
|
|
|
|
if self.counter == self.current_element.number:
|
|
self.next_element()
|
|
|
|
def next_element(self):
|
|
self.element_index += 1
|
|
if self.element_index < len(self.parent.elements):
|
|
self.current_element = self.parent.elements[self.element_index]
|
|
|
|
class PLYExporter(Exporter):
|
|
def __init__(self, model):
|
|
super().__init__(model)
|
|
|
|
def __str__(self):
|
|
|
|
faces = sum([part.faces for part in self.model.parts], [])
|
|
|
|
# Header
|
|
string = "ply\nformat ascii 1.0\ncomment Automatically gnerated by model-converter\n"
|
|
|
|
# Types : vertices
|
|
string += "element vertex " + str(len(self.model.vertices)) +"\n"
|
|
string += "property float32 x\nproperty float32 y\nproperty float32 z\n"
|
|
|
|
# Types : faces
|
|
string += "element face " + str(len(faces)) + "\n"
|
|
string += "property list uint8 int32 vertex_indices\n"
|
|
|
|
# End header
|
|
string += "end_header\n"
|
|
|
|
# Content of the model
|
|
for vertex in self.model.vertices:
|
|
string += str(vertex.x) + " " + str(vertex.y) + " " + str(vertex.z) + "\n"
|
|
|
|
for face in faces:
|
|
string += "3 " + str(face.a.vertex) + " " + str(face.b.vertex) + " " + str(face.c.vertex) + "\n"
|
|
|
|
return string
|
|
|