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