From c0ced3637002dea456559ac809513d455e2b4856 Mon Sep 17 00:00:00 2001 From: Thomas FORGIONE Date: Tue, 17 Jan 2017 17:16:10 +0100 Subject: [PATCH] Added binary little endian ply support --- assets/models/cube/cube.mtl | 3 + assets/models/cube/cube.obj | 3 + d3/model/basemodel.py | 14 +- d3/model/formats/ply.py | 252 +++++++++++++++++++++++++++++++++--- d3/model/mesh.py | 1 + 5 files changed, 251 insertions(+), 22 deletions(-) diff --git a/assets/models/cube/cube.mtl b/assets/models/cube/cube.mtl index 5a4b37f..5473cb4 100644 --- a/assets/models/cube/cube.mtl +++ b/assets/models/cube/cube.mtl @@ -8,3 +8,6 @@ Ka 0.5 0.5 0. Kd 0.9 0.9 0.9 Ks 0.0 0.0 0.0 map_Kd cube.png + +newmtl fuckyou +Ka 1 1 1 diff --git a/assets/models/cube/cube.obj b/assets/models/cube/cube.obj index 778151b..d105fe8 100644 --- a/assets/models/cube/cube.obj +++ b/assets/models/cube/cube.obj @@ -29,3 +29,6 @@ f 6/1/1 5/3/1 7/4/1 8/2/1 f 5/1/6 1/3/6 3/4/6 7/2/6 f 4/1/2 8/3/2 7/4/2 3/2/2 f 2/1/5 1/3/5 5/4/5 6/2/5 + +usemtl fuckyou + diff --git a/d3/model/basemodel.py b/d3/model/basemodel.py index c64c386..35db913 100644 --- a/d3/model/basemodel.py +++ b/d3/model/basemodel.py @@ -134,8 +134,18 @@ class ModelParser: self.current_part.add_face(face) - def parse_bytes(self, bytes): - pass + def parse_file(self, path, chunk_size = 512): + """Sets the path of the model and parse bytes by chunk + """ + self.path = path + byte_counter = 0 + with open(path, 'rb') as f: + while True: + bytes = f.read(chunk_size) + if bytes == b'': + return + self.parse_bytes(bytes, byte_counter) + byte_counter += chunk_size def draw(self): """Draws each part of the model with OpenGL diff --git a/d3/model/formats/ply.py b/d3/model/formats/ply.py index 22e840a..5db202f 100644 --- a/d3/model/formats/ply.py +++ b/d3/model/formats/ply.py @@ -1,11 +1,65 @@ import os +import sys import PIL +import struct from ..basemodel import ModelParser, TextModelParser, Exporter, Vertex, Face, FaceVertex, TexCoord, Material +class UnkownTypeError(Exception): + def __init__(self, message): + self.message = message + def is_ply(filename): return filename[-4:] == '.ply' -class PLYParser(TextModelParser): +# List won't work with this function +def _ply_type_size(type): + if type == 'char' or type == 'uchar': + return 1 + elif type == 'short' or type == 'ushort': + return 2 + elif type == 'int' or type == 'uint': + return 4 + elif type == 'float': + return 4 + elif type == 'double': + return 8 + else: + raise UnkownTypeError('Type ' + type + ' is unknown') + +def ply_type_size(type): + split = type.split() + + if len(split) == 1: + return [_ply_type_size(type)] + else: + if split[0] != 'list': + print('You have multiple types but it\'s not a list...', file=sys.stderr) + sys.exit(-1) + else: + return list(map(lambda a: _ply_type_size(a), split[1:])) + + +def bytes_to_element(type, bytes, byteorder = 'little'): + if type == 'char': + return ord(struct.unpack(' len(bytes): + self.previous_bytes = bytes[beginning_byte_index:] + # self.current_byte -= len(self.previous_bytes) + return + + if len(size) == 1: + + size = size[0] + + current_property_bytes = bytes[current_byte_index:current_byte_index+size] + property_values.append(bytes_to_element(property[1], current_property_bytes)) + current_byte_index += size + # self.current_byte += size + + elif len(size) == 2: + + types = property[1].split()[1:] + current_property_bytes = bytes[current_byte_index:current_byte_index+size[0]] + number_of_elements = bytes_to_element(types[0], current_property_bytes) + current_byte_index += size[0] + # self.current_byte += size[0] + + property_values.append([]) + + # Parse list + for i in range(number_of_elements): + + if current_byte_index + size[1] > len(bytes): + + self.previous_bytes = bytes[beginning_byte_index:] + # self.current_byte -= len(self.previous_bytes) + return + + current_property_bytes = bytes[current_byte_index:current_byte_index+size[1]] + property_values[-1].append(bytes_to_element(types[1], current_property_bytes)) + current_byte_index += size[1] + # self.current_byte += size[1] + + + else: + print('I have not idea what this means', file=sys.stderr) + + # Add element + if self.current_element.name == 'vertex': + self.parent.add_vertex(Vertex().from_array(property_values)) + + + elif self.current_element.name == 'face': + + # Create texture coords + for i in range(0,6,2): + tex_coord = TexCoord(*property_values[1][i:i+2]) + self.parent.add_tex_coord(tex_coord) + + face = Face(\ + FaceVertex(property_values[0][0], len(self.parent.tex_coords)-3), \ + FaceVertex(property_values[0][1], len(self.parent.tex_coords)-2), \ + FaceVertex(property_values[0][2], len(self.parent.tex_coords)-1)) + + face.material = self.parent.materials[property_values[2]] + + self.parent.add_face(face) + + pass + + self.counter += 1 + + if self.counter == self.current_element.number: + self.next_element() + + def next_element(self): + self.counter = 0 + self.element_index += 1 + if self.element_index < len(self.parent.elements): + self.current_element = self.parent.elements[self.element_index] + + + +class PLYBigEndianContentParser(PLYLittleEndianContentParser): + def __init__(self, parent): + super().__init__(self, parent) + + def parse_bytes(self, bytes): + # Reverse bytes, and then + super().parse_bytes(self, bytes) + class PLYExporter(Exporter): def __init__(self, model): super().__init__(model) @@ -132,7 +344,7 @@ class PLYExporter(Exporter): # Types : vertices string += "element vertex " + str(len(self.model.vertices)) +"\n" - string += "property float32 x\nproperty float32 y\nproperty float32 z\n" + string += "property float x\nproperty float y\nproperty float z\n" # Types : faces string += "element face " + str(len(faces)) + "\n" diff --git a/d3/model/mesh.py b/d3/model/mesh.py index c9c32cc..54d6ff3 100644 --- a/d3/model/mesh.py +++ b/d3/model/mesh.py @@ -24,6 +24,7 @@ class Material: try: ix, iy, image = self.map_Kd.size[0], self.map_Kd.size[1], self.map_Kd.tobytes("raw", "RGBA", 0, -1) except: + print('Humm') ix, iy, image = self.map_Kd.size[0], self.map_Kd.size[1], self.map_Kd.tobytes("raw", "RGBX", 0, -1) self.id = gl.glGenTextures(1)