1 /**
2 Copyright: Copyright (c) 2016-2017 Andrey Penechko.
3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4 Authors: Andrey Penechko.
5 */
6 module voxelman.model.ply;
7 
8 import std.algorithm : startsWith;
9 import std.conv : to, parse;
10 import std..string : lineSplitter, stripLeft;
11 
12 import voxelman.container.buffer : Buffer;
13 import voxelman.model.utils : Faces, unrollFaces;
14 import voxelman.model.mesh : Mesh;
15 
16 enum HEADER_STR = "end_header";
17 enum VERTEX_STR = "element vertex ";
18 enum FACE_STR = "element face ";
19 
20 Vert[] readPlyFile(Vert)(string fileName)
21 {
22 	import std.file : read;
23 	string data = cast(string)read(fileName);
24 	Mesh!Vert mesh = parsePly!Vert(data);
25 	return unrollFaces(mesh.vertices, mesh.faces);
26 }
27 
28 Mesh!Vert parsePly(Vert)(string fileData)
29 {
30 	auto lines = fileData.lineSplitter;
31 
32 	size_t numVertices;
33 	size_t numFaces;
34 
35 	// parse header
36 	while(!lines.empty)
37 	{
38 		auto line = lines.front;
39 
40 		if (line.startsWith(HEADER_STR))
41 		{
42 			lines.popFront;
43 			break;
44 		}
45 		else if (line.startsWith(VERTEX_STR))
46 		{
47 			numVertices = to!size_t(line[VERTEX_STR.length..$]);
48 		}
49 		else if (line.startsWith(FACE_STR))
50 		{
51 			numFaces = to!size_t(line[FACE_STR.length..$]);
52 		}
53 
54 		lines.popFront;
55 	}
56 
57 	Buffer!Vert vertices;
58 
59 	// parse vertices
60 	foreach (i; 0..numVertices)
61 	{
62 		auto line = lines.front;
63 
64 		Vert v;
65 		v.position.x = parse!float(line); line = stripLeft(line);
66 		v.position.y = parse!float(line); line = stripLeft(line);
67 		v.position.z = parse!float(line); line = stripLeft(line);
68 		v.color.r = parse!ubyte(line); line = stripLeft(line);
69 		v.color.g = parse!ubyte(line); line = stripLeft(line);
70 		v.color.b = parse!ubyte(line);
71 
72 		vertices.put(v);
73 
74 		lines.popFront;
75 	}
76 
77 	Buffer!int faceData;
78 	faceData.reserve(numFaces * 4);
79 
80 	// parse faces
81 	foreach (i; 0..numFaces)
82 	{
83 		auto line = lines.front;
84 
85 		int numFaceVertices = parse!int(line);
86 		faceData.put(numFaceVertices);
87 
88 		foreach (j; 0..numFaceVertices)
89 		{
90 			line = stripLeft(line);
91 			faceData.put(parse!int(line));
92 		}
93 
94 		lines.popFront;
95 	}
96 
97 	return Mesh!Vert(
98 		vertices.data,
99 		Faces(faceData.data, numFaces));
100 }