Blender V4.3
io_ply_importer_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "testing/testing.h"
6
7#include "BLI_fileops.hh"
8#include "BLI_hash_mm2a.hh"
9
10#include "ply_import.hh"
11#include "ply_import_buffer.hh"
12#include "ply_import_data.hh"
13
14namespace blender::io::ply {
15
24
25class PLYImportTest : public testing::Test {
26 public:
27 void import_and_check(const char *path, const Expectation &exp)
28 {
29 std::string ply_path = blender::tests::flags_test_asset_dir() +
30 SEP_STR "io_tests" SEP_STR "ply" SEP_STR + path;
31
32 /* Use a small read buffer size for better coverage of buffer refilling behavior. */
33 PlyReadBuffer infile(ply_path.c_str(), 128);
34 PlyHeader header;
35 const char *header_err = read_header(infile, header);
36 if (header_err != nullptr) {
37 ADD_FAILURE();
38 return;
39 }
40 std::unique_ptr<PlyData> data = import_ply_data(infile, header);
41 if (!data->error.empty()) {
42 fprintf(stderr, "%s\n", data->error.c_str());
43 ASSERT_EQ(0, exp.totvert);
44 ASSERT_EQ(0, exp.faces_num);
45 return;
46 }
47
48 /* Test expected amount of vertices, edges, and faces. */
49 ASSERT_EQ(data->vertices.size(), exp.totvert);
50 ASSERT_EQ(data->edges.size(), exp.totedge);
51 ASSERT_EQ(data->face_sizes.size(), exp.faces_num);
52 ASSERT_EQ(data->face_vertices.size(), exp.totindex);
53
54 /* Test hash of face and edge index data. */
57 uint32_t offset = 0;
58 for (uint32_t face_size : data->face_sizes) {
59 BLI_hash_mm2a_add(&hash, (const uchar *)&data->face_vertices[offset], face_size * 4);
60 offset += face_size;
61 }
62 uint16_t face_hash = BLI_hash_mm2a_end(&hash);
63 if (!data->face_vertices.is_empty()) {
64 ASSERT_EQ(face_hash, exp.polyhash);
65 }
66
67 if (!data->edges.is_empty()) {
68 uint16_t edge_hash = BLI_hash_mm2(
69 (const uchar *)data->edges.data(), data->edges.size() * sizeof(data->edges[0]), 0);
70 ASSERT_EQ(edge_hash, exp.edgehash);
71 }
72
73 /* Test if first and last vertices match. */
74 EXPECT_V3_NEAR(data->vertices.first(), exp.vert_first, 0.0001f);
75 EXPECT_V3_NEAR(data->vertices.last(), exp.vert_last, 0.0001f);
76
77 /* Check if first normal matches. */
78 float3 got_normal = data->vertex_normals.is_empty() ? float3(0, 0, 0) :
79 data->vertex_normals.first();
80 EXPECT_V3_NEAR(got_normal, exp.normal_first, 0.0001f);
81
82 /* Check if first UV matches. */
83 float2 got_uv = data->uv_coordinates.is_empty() ? float2(0, 0) : data->uv_coordinates.first();
84 EXPECT_V2_NEAR(got_uv, exp.uv_first, 0.0001f);
85
86 /* Check if first color matches. */
87 float4 got_color = data->vertex_colors.is_empty() ? float4(-1, -1, -1, -1) :
88 data->vertex_colors.first();
89 EXPECT_V4_NEAR(got_color, exp.color_first, 0.0001f);
90 }
91};
92
93TEST_F(PLYImportTest, PLYImportCube)
94{
95 Expectation expect = {24,
96 6,
97 24,
98 0,
99 26429,
100 0,
101 float3(1, 1, -1),
102 float3(-1, 1, 1),
103 float3(0, 0, -1),
104 float2(0.979336, 0.844958),
105 float4(1, 0.8470, 0, 1)};
106 import_and_check("cube_ascii.ply", expect);
107}
108
109TEST_F(PLYImportTest, PLYImportWireframeCube)
110{
111 Expectation expect = {8, 0, 0, 12, 0, 31435, float3(-1, -1, -1), float3(1, 1, 1)};
112 import_and_check("ASCII_wireframe_cube.ply", expect);
113 import_and_check("wireframe_cube.ply", expect);
114}
115
116TEST_F(PLYImportTest, PlyImportBinaryDataStartsWithLF)
117{
118 Expectation expect = {4, 1, 4, 0, 37235, 0, float3(-1, -1, 0), float3(-1, 1, 0)};
119 import_and_check("bin_data_starts_with_lf.ply", expect);
120 import_and_check("bin_data_starts_with_lf_header_crlf.ply", expect);
121}
122
123TEST_F(PLYImportTest, PLYImportBunny)
124{
125 Expectation expect = {1623,
126 1000,
127 3000,
128 0,
129 62556,
130 0,
131 float3(0.0380425, 0.109755, 0.0161689),
132 float3(-0.0722821, 0.143895, -0.0129091)};
133 import_and_check("bunny2.ply", expect);
134}
135
136TEST_F(PLYImportTest, PlyImportManySmallHoles)
137{
138 Expectation expect = {2004,
139 3524,
140 10572,
141 0,
142 15143,
143 0,
144 float3(-0.0131592, -0.0598382, 1.58958),
145 float3(-0.0177622, 0.0105153, 1.61977),
146 float3(0, 0, 0),
147 float2(0, 0),
148 float4(0.7215, 0.6784, 0.6627, 1)};
149 import_and_check("many_small_holes.ply", expect);
150}
151
152TEST_F(PLYImportTest, PlyImportColorNotFull)
153{
154 Expectation expect = {4, 1, 4, 0, 37235, 0, float3(1, 0, 1), float3(-1, 0, 1)};
155 import_and_check("color_not_full_a.ply", expect);
156 import_and_check("color_not_full_b.ply", expect);
157}
158
159TEST_F(PLYImportTest, PlyImportCustomDataElements)
160{
161 Expectation expect = {600,
162 0,
163 0,
164 0,
165 0,
166 0,
167 float3(-0.78193f, 0.40659f, -1),
168 float3(-0.75537f, 1, -0.24777f),
169 float3(0, 0, 0),
170 float2(0, 0),
171 float4(0.31373f, 0, 0, 1)};
172 import_and_check("custom_data_elements.ply", expect);
173}
174
175TEST_F(PLYImportTest, PlyImportDoubleXYZ)
176{
177 Expectation expect = {4,
178 1,
179 4,
180 0,
181 37235,
182 0,
183 float3(1, 0, 1),
184 float3(-1, 0, 1),
185 float3(0, 0, 0),
186 float2(0, 0),
187 float4(1, 0, 0, 1)};
188 import_and_check("double_xyz_a.ply", expect);
189 import_and_check("double_xyz_b.ply", expect);
190}
191
192TEST_F(PLYImportTest, PlyImportFaceIndicesNotFirstProp)
193{
194 Expectation expect = {4, 2, 6, 0, 4136, 0, float3(1, 0, 1), float3(-1, 0, 1)};
195 import_and_check("face_indices_not_first_prop_a.ply", expect);
196 import_and_check("face_indices_not_first_prop_b.ply", expect);
197}
198
199TEST_F(PLYImportTest, PlyImportFaceIndicesPrecededByList)
200{
201 Expectation expect = {4, 2, 6, 0, 4136, 0, float3(1, 0, 1), float3(-1, 0, 1)};
202 import_and_check("face_indices_preceded_by_list_a.ply", expect);
203 import_and_check("face_indices_preceded_by_list_b.ply", expect);
204}
205
206TEST_F(PLYImportTest, PlyImportFaceUVsColors)
207{
208 Expectation expect = {4, 1, 4, 0, 37235, 0, float3(1, 0, 1), float3(-1, 0, 1)};
209 import_and_check("face_uvs_colors_a.ply", expect);
210 import_and_check("face_uvs_colors_b.ply", expect);
211}
212
213TEST_F(PLYImportTest, PlyImportFacesFirst)
214{
215 Expectation expect = {4,
216 1,
217 4,
218 0,
219 37235,
220 0,
221 float3(1, 0, 1),
222 float3(-1, 0, 1),
223 float3(0, 0, 0),
224 float2(0, 0),
225 float4(1, 0, 0, 1)};
226 import_and_check("faces_first_a.ply", expect);
227 import_and_check("faces_first_b.ply", expect);
228}
229
230TEST_F(PLYImportTest, PlyImportFloatFormats)
231{
232 Expectation expect = {4,
233 1,
234 4,
235 0,
236 37235,
237 0,
238 float3(1, 0, 1),
239 float3(-1, 0, 1),
240 float3(0, 0, 0),
241 float2(0, 0),
242 float4(0.5f, 0, 0.25f, 1)};
243 import_and_check("float_formats_a.ply", expect);
244 import_and_check("float_formats_b.ply", expect);
245}
246
247TEST_F(PLYImportTest, PlyImportPositionNotFull)
248{
249 Expectation expect = {0, 0, 0, 0};
250 import_and_check("position_not_full_a.ply", expect);
251 import_and_check("position_not_full_b.ply", expect);
252}
253
254TEST_F(PLYImportTest, PlyImportTristrips)
255{
256 Expectation expect = {6, 4, 12, 0, 3404, 0, float3(1, 0, 1), float3(-3, 0, 1)};
257 import_and_check("tristrips_a.ply", expect);
258 import_and_check("tristrips_b.ply", expect);
259}
260
261TEST_F(PLYImportTest, PlyImportTypeAliases)
262{
263 Expectation expect = {4,
264 1,
265 4,
266 0,
267 37235,
268 0,
269 float3(1, 0, 1),
270 float3(-1, 0, 1),
271 float3(0, 0, 0),
272 float2(0, 0),
273 float4(220 / 255.0f, 20 / 255.0f, 20 / 255.0f, 1)};
274 import_and_check("type_aliases_a.ply", expect);
275 import_and_check("type_aliases_b.ply", expect);
276 import_and_check("type_aliases_be_b.ply", expect);
277}
278
279TEST_F(PLYImportTest, PlyImportVertexCompOrder)
280{
281 Expectation expect = {4,
282 1,
283 4,
284 0,
285 37235,
286 0,
287 float3(1, 0, 1),
288 float3(-1, 0, 1),
289 float3(0, 0, 0),
290 float2(0, 0),
291 float4(0.8f, 0.2f, 0, 1)};
292 import_and_check("vertex_comp_order_a.ply", expect);
293 import_and_check("vertex_comp_order_b.ply", expect);
294}
295
296//@TODO: test with vertex element having list properties
297//@TODO: test with edges starting with non-vertex index properties
298//@TODO: test various malformed headers
299//@TODO: UVs with: s,t; u,v; texture_u,texture_v; texture_s,texture_t (from miniply)
300//@TODO: colors with: r,g,b in addition to red,green,blue (from miniply)
301//@TODO: importing bunny2 with old importer results in smooth shading; flat shading with new one
302
303} // namespace blender::io::ply
File and directory operations.
void BLI_hash_mm2a_init(BLI_HashMurmur2A *mm2, uint32_t seed)
Definition hash_mm2a.cc:62
void BLI_hash_mm2a_add(BLI_HashMurmur2A *mm2, const unsigned char *data, size_t len)
Definition hash_mm2a.cc:70
uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2)
Definition hash_mm2a.cc:90
uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed)
Definition hash_mm2a.cc:100
unsigned char uchar
void import_and_check(const char *path, const Expectation &exp)
ccl_device_inline float3 exp(float3 v)
std::unique_ptr< PlyData > import_ply_data(PlyReadBuffer &file, PlyHeader &header)
const char * read_header(PlyReadBuffer &file, PlyHeader &r_header)
Definition ply_import.cc:98
TEST_F(PLYExportTest, WriteHeaderAscii)
VecBase< float, 4 > float4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
#define hash
Definition noise.c:154
unsigned short uint16_t
Definition stdint.h:79
unsigned int uint32_t
Definition stdint.h:80
#define SEP_STR
Definition unit.cc:39