/
example.cpp
172 lines (135 loc) · 8.34 KB
/
example.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// This software is in the public domain. Where that dedication is not
// recognized, you are granted a perpetual, irrevocable license to copy,
// distribute, and modify this file as you see fit.
// https://github.com/ddiakopoulos/tinyply
// Version 2.3
// The purpose of this file is to demonstrate the tinyply API and provide several almost-complete
// functions that can be copied and pasted into your own application or library. Because tinyply
// treats the file format as structured data, it's up to you to copy or move the parsed data
// into your application-specific data structures (e.g. float3, vec3, etc).
#include "tinyply.h"
using namespace tinyply;
#include "example-utils.hpp"
void write_ply_example(const std::string & filename)
{
geometry cube = make_cube_geometry();
std::filebuf fb_binary;
fb_binary.open(filename + "-binary.ply", std::ios::out | std::ios::binary);
std::ostream outstream_binary(&fb_binary);
if (outstream_binary.fail()) throw std::runtime_error("failed to open " + filename);
std::filebuf fb_ascii;
fb_ascii.open(filename + "-ascii.ply", std::ios::out);
std::ostream outstream_ascii(&fb_ascii);
if (outstream_ascii.fail()) throw std::runtime_error("failed to open " + filename);
PlyFile cube_file;
cube_file.add_properties_to_element("vertex", { "x", "y", "z" },
Type::FLOAT32, cube.vertices.size(), reinterpret_cast<uint8_t*>(cube.vertices.data()), Type::INVALID, 0);
cube_file.add_properties_to_element("vertex", { "nx", "ny", "nz" },
Type::FLOAT32, cube.normals.size(), reinterpret_cast<uint8_t*>(cube.normals.data()), Type::INVALID, 0);
cube_file.add_properties_to_element("vertex", { "u", "v" },
Type::FLOAT32, cube.texcoords.size() , reinterpret_cast<uint8_t*>(cube.texcoords.data()), Type::INVALID, 0);
cube_file.add_properties_to_element("face", { "vertex_indices" },
Type::UINT32, cube.triangles.size(), reinterpret_cast<uint8_t*>(cube.triangles.data()), Type::UINT8, 3);
cube_file.get_comments().push_back("generated by tinyply 2.3");
// Write an ASCII file
cube_file.write(outstream_ascii, false);
// Write a binary file
cube_file.write(outstream_binary, true);
}
void read_ply_file(const std::string & filepath, const bool preload_into_memory = true)
{
std::cout << "........................................................................\n";
std::cout << "Now Reading: " << filepath << std::endl;
std::unique_ptr<std::istream> file_stream;
std::vector<uint8_t> byte_buffer;
try
{
// For most files < 1gb, pre-loading the entire file upfront and wrapping it into a
// stream is a net win for parsing speed, about 40% faster.
if (preload_into_memory)
{
byte_buffer = read_file_binary(filepath);
file_stream.reset(new memory_stream((char*)byte_buffer.data(), byte_buffer.size()));
}
else
{
file_stream.reset(new std::ifstream(filepath, std::ios::binary));
}
if (!file_stream || file_stream->fail()) throw std::runtime_error("file_stream failed to open " + filepath);
PlyFile file;
file.parse_header(*file_stream);
std::cout << "\t[ply_header] Type: " << (file.is_binary_file() ? "binary" : "ascii") << std::endl;
for (const auto & c : file.get_comments()) std::cout << "\t[ply_header] Comment: " << c << std::endl;
for (const auto & c : file.get_info()) std::cout << "\t[ply_header] Info: " << c << std::endl;
for (const auto & e : file.get_elements())
{
std::cout << "\t[ply_header] element: " << e.name << " (" << e.size << ")" << std::endl;
for (const auto & p : e.properties)
{
std::cout << "\t[ply_header] \tproperty: " << p.name << " (type=" << tinyply::PropertyTable[p.propertyType].str << ")";
if (p.isList) std::cout << " (list_type=" << tinyply::PropertyTable[p.listType].str << ")";
std::cout << std::endl;
}
}
// Because most people have their own mesh types, tinyply treats parsed data as structured/typed byte buffers.
// See examples below on how to marry your own application-specific data structures with this one.
std::shared_ptr<PlyData> vertices, normals, colors, texcoords, faces, tripstrip;
// The header information can be used to programmatically extract properties on elements
// known to exist in the header prior to reading the data. For brevity of this sample, properties
// like vertex position are hard-coded:
try { vertices = file.request_properties_from_element("vertex", { "x", "y", "z" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }
try { normals = file.request_properties_from_element("vertex", { "nx", "ny", "nz" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }
try { colors = file.request_properties_from_element("vertex", { "red", "green", "blue", "alpha" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }
try { colors = file.request_properties_from_element("vertex", { "r", "g", "b", "a" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }
try { texcoords = file.request_properties_from_element("vertex", { "u", "v" }); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }
// Providing a list size hint (the last argument) is a 2x performance improvement. If you have
// arbitrary ply files, it is best to leave this 0.
try { faces = file.request_properties_from_element("face", { "vertex_indices" }, 3); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }
// Tristrips must always be read with a 0 list size hint (unless you know exactly how many elements
// are specifically in the file, which is unlikely);
try { tripstrip = file.request_properties_from_element("tristrips", { "vertex_indices" }, 0); }
catch (const std::exception & e) { std::cerr << "tinyply exception: " << e.what() << std::endl; }
manual_timer read_timer;
read_timer.start();
file.read(*file_stream);
read_timer.stop();
std::cout << "Reading took " << read_timer.get() / 1000.f << " seconds." << std::endl;
if (vertices) std::cout << "\tRead " << vertices->count << " total vertices "<< std::endl;
if (normals) std::cout << "\tRead " << normals->count << " total vertex normals " << std::endl;
if (colors) std::cout << "\tRead " << colors->count << " total vertex colors " << std::endl;
if (texcoords) std::cout << "\tRead " << texcoords->count << " total vertex texcoords " << std::endl;
if (faces) std::cout << "\tRead " << faces->count << " total faces (triangles) " << std::endl;
if (tripstrip) std::cout << "\tRead " << (tripstrip->buffer.size_bytes() / tinyply::PropertyTable[tripstrip->t].stride) << " total indicies (tristrip) " << std::endl;
// Example One: converting to your own application types
{
const size_t numVerticesBytes = vertices->buffer.size_bytes();
std::vector<float3> verts(vertices->count);
std::memcpy(verts.data(), vertices->buffer.get(), numVerticesBytes);
}
// Example Two: converting to your own application type
{
std::vector<float3> verts_floats;
std::vector<double3> verts_doubles;
if (vertices->t == tinyply::Type::FLOAT32) { /* as floats ... */ }
if (vertices->t == tinyply::Type::FLOAT64) { /* as doubles ... */ }
}
}
catch (const std::exception & e)
{
std::cerr << "Caught tinyply exception: " << e.what() << std::endl;
}
}
int main(int argc, char *argv[])
{
// Circular write-read
write_ply_example("example_cube");
read_ply_file("example_cube-ascii.ply");
read_ply_file("example_cube-binary.ply", true);
return EXIT_SUCCESS;
}