test_sstl_load_binary.c (14716B)
1 /* Copyright (C) 2015, 2016, 2019, 2021, 2023, 2025 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU Lesser General Public License for more details. 12 * 13 * You should have received a copy of the GNU Lesser General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #define _POSIX_C_SOURCE 200112L /* fork */ 17 18 #include "sstl.h" 19 20 #include <rsys/float3.h> 21 #include <rsys/mem_allocator.h> 22 23 #include <string.h> 24 #include <unistd.h> /* fork, pipe */ 25 26 /******************************************************************************* 27 * Helper functions 28 ******************************************************************************/ 29 static void 30 check_api(struct sstl* sstl) 31 { 32 const char header[80] = {0}; 33 const uint32_t ntris = 0; 34 const char* filename = "test.stl"; 35 FILE* fp = NULL; 36 struct sstl_desc desc = SSTL_DESC_NULL; 37 38 CHK((fp = fopen(filename, "w+")) != NULL); 39 rewind(fp); 40 41 CHK(sstl_load_binary(sstl, NULL) == RES_BAD_ARG); 42 CHK(sstl_load_binary(NULL, filename) == RES_BAD_ARG); 43 CHK(sstl_load_binary(sstl, "none.stl") == RES_IO_ERR); 44 /* A binary cannot be empty */ 45 CHK(sstl_load_binary(sstl, filename) == RES_BAD_ARG); 46 47 CHK(sstl_load_stream_binary(NULL, fp, filename) == RES_BAD_ARG); 48 CHK(sstl_load_stream_binary(sstl, NULL, filename) == RES_BAD_ARG); 49 CHK(sstl_load_stream_binary(sstl, fp, NULL) == RES_BAD_ARG); 50 /* A binary cannot be empty */ 51 CHK(sstl_load_stream_binary(sstl, fp, filename) == RES_BAD_ARG); 52 53 /* Write the minimum data required by a binary StL */ 54 CHK(fwrite(header, sizeof(header), 1, fp) == 1); 55 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 56 rewind(fp); 57 58 CHK(sstl_load_binary(sstl, filename) == RES_OK); 59 CHK(sstl_get_desc(sstl, &desc) == RES_OK); 60 CHK(desc.type == SSTL_BINARY); 61 CHK(!strcmp(desc.filename, filename)); 62 CHK(desc.solid_name == NULL); 63 CHK(desc.vertices_count == 0); 64 CHK(desc.triangles_count == 0); 65 66 CHK(sstl_load_stream_binary(sstl, fp, filename) == RES_OK); 67 CHK(sstl_get_desc(sstl, &desc) == RES_OK); 68 CHK(desc.type == SSTL_BINARY); 69 CHK(!strcmp(desc.filename, filename)); 70 CHK(desc.solid_name == NULL); 71 CHK(desc.vertices_count == 0); 72 CHK(desc.triangles_count == 0); 73 74 CHK(fclose(fp) == 0); 75 } 76 77 static void 78 check_1_triangle(struct sstl* sstl) 79 { 80 char header[80] = {0}; 81 const uint32_t ntris = 1; 82 const float normal[3] = {0.f, -1.f, 0.f}; 83 const float verts[9] = { 84 0.f, 0.f, 0.f, 85 1.f, 0.f, 0.f, 86 0.f, 0.f, 1.f 87 }; 88 const uint16_t nattrs = 0; 89 const char* filename = "1_triangle.stl"; 90 FILE* fp = NULL; 91 float v[3] = {0,0,0}; 92 struct sstl_desc desc = SSTL_DESC_NULL; 93 94 CHK(sstl); 95 96 CHK((fp = fopen(filename, "w")) != NULL); 97 CHK(fwrite(header, sizeof(header), 1, fp) == 1); 98 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 99 CHK(fwrite(normal, sizeof(normal), 1, fp) == 1); 100 CHK(fwrite(verts, sizeof(verts), 1, fp) == 1); 101 CHK(fwrite(&nattrs, sizeof(nattrs), 1, fp) == 1); 102 CHK(fclose(fp) == 0); 103 104 CHK(sstl_load(sstl, filename) == RES_OK); 105 CHK(sstl_get_desc(sstl, &desc) == RES_OK); 106 107 CHK(desc.type == SSTL_BINARY); 108 CHK(!strcmp(desc.filename, filename)); 109 CHK(desc.solid_name == NULL); 110 CHK(desc.vertices_count == 3); 111 CHK(desc.triangles_count == 1); 112 CHK(desc.indices[0] == 0); 113 CHK(desc.indices[1] == 1); 114 CHK(desc.indices[2] == 2); 115 CHK(f3_eq(desc.vertices + 0*3, f3(v, 0.f, 0.f, 0.f)) == 1); 116 CHK(f3_eq(desc.vertices + 1*3, f3(v, 1.f, 0.f, 0.f)) == 1); 117 CHK(f3_eq(desc.vertices + 2*3, f3(v, 0.f, 0.f, 1.f)) == 1); 118 CHK(f3_eq(desc.normals, f3(v, 0.f, -1.f, 0.f)) == 1); 119 } 120 121 static void 122 check_1_triangle_no_normal(struct sstl* sstl) 123 { 124 char header[80] = {0}; 125 const uint32_t ntris = 1; 126 const float normal[3] = {0.f, 0.f, 0.f}; 127 const float verts[9] = { 128 0.f, 0.f, 0.f, 129 -1.f, 0.f, 0.f, 130 0.f, 0.f,-1.f 131 }; 132 const uint16_t nattrs = 0; 133 const char* filename = "1_triangle_no_normal.stl"; 134 FILE* fp = NULL; 135 float v[3] = {0,0,0}; 136 struct sstl_desc desc = SSTL_DESC_NULL; 137 138 CHK((fp = fopen(filename, "w+")) != NULL); 139 CHK(fwrite(header, sizeof(header), 1, fp) == 1); 140 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 141 CHK(fwrite(normal, sizeof(normal), 1, fp) == 1); 142 CHK(fwrite(verts, sizeof(verts), 1, fp) == 1); 143 CHK(fwrite(&nattrs, sizeof(nattrs), 1, fp) == 1); 144 rewind(fp); 145 146 CHK(sstl_load_stream(sstl, fp, filename) == RES_OK); 147 148 CHK(sstl_get_desc(sstl, &desc) == RES_OK); 149 CHK(desc.type == SSTL_BINARY); 150 CHK(!strcmp(desc.filename, filename)); 151 CHK(desc.solid_name == NULL); 152 CHK(desc.vertices_count == 3); 153 CHK(desc.triangles_count == 1); 154 CHK(desc.indices[0] == 0); 155 CHK(desc.indices[1] == 1); 156 CHK(desc.indices[2] == 2); 157 CHK(f3_eq(desc.vertices + 0*3, f3(v, 0.f, 0.f, 0.f)) == 1); 158 CHK(f3_eq(desc.vertices + 1*3, f3(v,-1.f, 0.f, 0.f)) == 1); 159 CHK(f3_eq(desc.vertices + 2*3, f3(v, 0.f, 0.f,-1.f)) == 1); 160 161 /* Normal is automatically calculated */ 162 CHK(f3_eq(desc.normals, f3(v, 0.f, -1.f, 0.f)) == 1); 163 164 CHK(fclose(fp) == 0); 165 } 166 167 static void 168 check_invalid_file(struct sstl* sstl) 169 { 170 const char header[80] = {0}; 171 const uint32_t ntris = 1; 172 const float N[3] = {0,0,0}; 173 const float v0[3] = {0,0,0}; 174 const float v1[3] = {1,0,0}; 175 const float v2[3] = {0,0,1}; 176 const uint16_t nattrs = 0; 177 FILE* fp = NULL; 178 float v[3] = {0,0,0}; 179 struct sstl_desc desc = SSTL_DESC_NULL; 180 181 /* First, check that the file should be OK if all the data has been correctly 182 * written, to make sure that the tests really check what we expect, i.e. a 183 * bad formatting and not a faulty data set */ 184 CHK((fp = tmpfile()) != NULL); 185 CHK(fwrite(&header, sizeof(char), sizeof(header), fp) == sizeof(header)); 186 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 187 CHK(fwrite(N, sizeof(N), 1, fp) == 1); 188 CHK(fwrite(v0, sizeof(v0), 1, fp) == 1); 189 CHK(fwrite(v1, sizeof(v1), 1, fp) == 1); 190 CHK(fwrite(v2, sizeof(v2), 1, fp) == 1); 191 CHK(fwrite(&nattrs, sizeof(nattrs), 1, fp) == 1); 192 rewind(fp); 193 CHK(sstl_load_stream(sstl, fp, "Valid StL") == RES_OK); 194 CHK(fclose(fp) == 0); 195 196 CHK(sstl_get_desc(sstl, &desc) == RES_OK); 197 CHK(desc.type == SSTL_BINARY); 198 CHK(!strcmp(desc.filename, "Valid StL")); 199 CHK(desc.vertices_count == 3); 200 CHK(desc.triangles_count == 1); 201 CHK(desc.indices[0] == 0); 202 CHK(desc.indices[1] == 1); 203 CHK(desc.indices[2] == 2); 204 CHK(f3_eq(desc.vertices + 0*3, f3(v, 0.f, 0.f, 0.f)) == 1); 205 CHK(f3_eq(desc.vertices + 1*3, f3(v, 1.f, 0.f, 0.f)) == 1); 206 CHK(f3_eq(desc.vertices + 2*3, f3(v, 0.f, 0.f, 1.f)) == 1); 207 CHK(f3_eq(desc.normals, f3(v, 0.f, -1.f, 0.f)) == 1); 208 209 /* Header is too small */ 210 CHK((fp = tmpfile()) != NULL); 211 CHK(fwrite(&header, sizeof(char), sizeof(header)-1, fp) == sizeof(header)-1); 212 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 213 rewind(fp); 214 CHK(sstl_load_stream(sstl, fp, "Invalid StL") == RES_BAD_ARG); 215 CHK(fclose(fp) == 0); 216 217 /* Triangle is missing */ 218 CHK((fp = tmpfile()) != NULL); 219 CHK(fwrite(&header, sizeof(char), sizeof(header), fp) == sizeof(header)); 220 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 221 rewind(fp); 222 CHK(sstl_load_stream(sstl, fp, "Invalid StL") == RES_BAD_ARG); 223 CHK(fclose(fp) == 0); 224 225 /* Triangle normal is missing */ 226 CHK((fp = tmpfile()) != NULL); 227 CHK(fwrite(&header, sizeof(char), sizeof(header), fp) == sizeof(header)); 228 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 229 CHK(fwrite(v0, sizeof(v0), 1, fp) == 1); 230 CHK(fwrite(v1, sizeof(v1), 1, fp) == 1); 231 CHK(fwrite(v2, sizeof(v2), 1, fp) == 1); 232 CHK(fwrite(&nattrs, sizeof(nattrs), 1, fp) == 1); 233 rewind(fp); 234 CHK(sstl_load_stream_binary(sstl, fp, "Invalid StL") == RES_BAD_ARG); 235 CHK(fclose(fp) == 0); 236 237 /* One vertex of the triangle is wrongly written */ 238 CHK((fp = tmpfile()) != NULL); 239 CHK(fwrite(&header, sizeof(char), sizeof(header), fp) == sizeof(header)); 240 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 241 CHK(fwrite(N, sizeof(N), 1, fp) == 1); 242 CHK(fwrite(v0, sizeof(v0), 1, fp) == 1); 243 CHK(fwrite(v1, sizeof(v1)-1/*One byte is missing*/, 1, fp) == 1); 244 CHK(fwrite(v2, sizeof(v2), 1, fp) == 1); 245 CHK(fwrite(&nattrs, sizeof(nattrs), 1, fp) == 1); 246 rewind(fp); 247 CHK(sstl_load_stream(sstl, fp, "Invalid StL") == RES_BAD_ARG); 248 CHK(fclose(fp) == 0); 249 250 /* The #attribs is missing */ 251 CHK((fp = tmpfile()) != NULL); 252 CHK(fwrite(&header, sizeof(char), sizeof(header), fp) == sizeof(header)); 253 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 254 CHK(fwrite(N, sizeof(N), 1, fp) == 1); 255 CHK(fwrite(v0, sizeof(v0), 1, fp) == 1); 256 CHK(fwrite(v1, sizeof(v1), 1, fp) == 1); 257 CHK(fwrite(v2, sizeof(v2), 1, fp) == 1); 258 rewind(fp); 259 CHK(sstl_load_stream(sstl, fp, "Invalid StL") == RES_BAD_ARG); 260 CHK(fclose(fp) == 0); 261 } 262 263 static void 264 check_tetrahedron(struct sstl* sstl) 265 { 266 const char header[80] = {0}; 267 float v[3] = {0,0,0}; 268 const uint32_t ntris = 4; 269 const uint16_t nattrs = 0; 270 FILE* fp = NULL; 271 struct sstl_desc desc = SSTL_DESC_NULL; 272 273 CHK(sstl != NULL); 274 275 CHK((fp = tmpfile()) != NULL); 276 CHK(fwrite(header, sizeof(header), 1, fp) == 1); 277 CHK(fwrite(&ntris, sizeof(ntris), 1, fp) == 1); 278 279 CHK(fwrite(f3(v, 0.0f,-1.0f, 0.0f), sizeof(v), 1, fp) == 1); 280 CHK(fwrite(f3(v, 0.0f, 0.0f, 0.0f), sizeof(v), 1, fp) == 1); 281 CHK(fwrite(f3(v, 0.1f, 0.0f, 0.0f), sizeof(v), 1, fp) == 1); 282 CHK(fwrite(f3(v, 0.0f, 0.0f, 0.1f), sizeof(v), 1, fp) == 1); 283 CHK(fwrite(&nattrs, sizeof(nattrs), 1, fp) == 1); 284 285 CHK(fwrite(f3(v, 0.0f, 0.0f,-1.f), sizeof(v), 1, fp) == 1); 286 CHK(fwrite(f3(v, 0.0f, 0.0f, 0.0f), sizeof(v), 1, fp) == 1); 287 CHK(fwrite(f3(v, 0.0f, 0.1f, 0.0f), sizeof(v), 1, fp) == 1); 288 CHK(fwrite(f3(v, 0.1f, 0.0f, 0.0f), sizeof(v), 1, fp) == 1); 289 CHK(fwrite(&nattrs, sizeof(nattrs), 1, fp) == 1); 290 291 CHK(fwrite(f3(v,-1.0f, 0.0f, 0.0f), sizeof(v), 1, fp) == 1); 292 CHK(fwrite(f3(v, 0.0f, 0.0f, 0.0f), sizeof(v), 1, fp) == 1); 293 CHK(fwrite(f3(v, 0.0f, 0.0f, 0.1f), sizeof(v), 1, fp) == 1); 294 CHK(fwrite(f3(v, 0.0f, 0.1f, 0.0f), sizeof(v), 1, fp) == 1); 295 CHK(fwrite(&nattrs, sizeof(nattrs), 1, fp) == 1); 296 297 CHK(fwrite(f3(v, 0.577f, 0.577f, 0.577f), sizeof(v), 1, fp) == 1); 298 CHK(fwrite(f3(v, 0.1f, 0.0f, 0.0f), sizeof(v), 1, fp) == 1); 299 CHK(fwrite(f3(v, 0.0f, 0.1f, 0.0f), sizeof(v), 1, fp) == 1); 300 CHK(fwrite(f3(v, 0.0f, 0.0f, 0.1f), sizeof(v), 1, fp) == 1); 301 CHK(fwrite(&nattrs, sizeof(nattrs), 1, fp) == 1); 302 303 rewind(fp); 304 305 CHK(sstl_load_stream(sstl, fp, "Tetrahedron") == RES_OK); 306 CHK(fclose(fp) == 0); 307 308 CHK(sstl_get_desc(sstl, &desc) == RES_OK); 309 CHK(desc.type == SSTL_BINARY); 310 CHK(!strcmp(desc.filename, "Tetrahedron")); 311 CHK(desc.solid_name == NULL); 312 CHK(desc.vertices_count == 4); 313 CHK(desc.triangles_count == 4); 314 315 CHK(f3_eq(desc.vertices + desc.indices[0]*3, f3(v, 0.0f, 0.0f, 0.0f)) == 1); 316 CHK(f3_eq(desc.vertices + desc.indices[1]*3, f3(v, 0.1f, 0.0f, 0.0f)) == 1); 317 CHK(f3_eq(desc.vertices + desc.indices[2]*3, f3(v, 0.0f, 0.0f, 0.1f)) == 1); 318 CHK(f3_eq(desc.vertices + desc.indices[3]*3, f3(v, 0.0f, 0.0f, 0.0f)) == 1); 319 CHK(f3_eq(desc.vertices + desc.indices[4]*3, f3(v, 0.0f, 0.1f, 0.0f)) == 1); 320 CHK(f3_eq(desc.vertices + desc.indices[5]*3, f3(v, 0.1f, 0.0f, 0.0f)) == 1); 321 CHK(f3_eq(desc.vertices + desc.indices[6]*3, f3(v, 0.0f, 0.0f, 0.0f)) == 1); 322 CHK(f3_eq(desc.vertices + desc.indices[7]*3, f3(v, 0.0f, 0.0f, 0.1f)) == 1); 323 CHK(f3_eq(desc.vertices + desc.indices[8]*3, f3(v, 0.0f, 0.1f, 0.0f)) == 1); 324 CHK(f3_eq(desc.vertices + desc.indices[9]*3, f3(v, 0.1f, 0.0f, 0.0f)) == 1); 325 CHK(f3_eq(desc.vertices + desc.indices[10]*3, f3(v, 0.0f, 0.1f, 0.0f)) == 1); 326 CHK(f3_eq(desc.vertices + desc.indices[11]*3, f3(v, 0.0f, 0.0f, 0.1f)) == 1); 327 328 CHK(f3_eq(desc.normals + 0*3, f3(v, 0.f,-1.f, 0.f)) == 1); 329 CHK(f3_eq(desc.normals + 1*3, f3(v, 0.f, 0.f,-1.f)) == 1); 330 CHK(f3_eq(desc.normals + 2*3, f3(v,-1.f, 0.f, 0.f)) == 1); 331 f3_normalize(v, f3(v, 1.f, 1.f, 1.f)); 332 CHK(f3_eq_eps(desc.normals + 3*3, v, 1.e-6f) == 1); 333 } 334 335 static void 336 check_no_seekable_file(struct sstl* sstl) 337 { 338 float v[3] = {0,0,0}; 339 int fd[2] = {0,0}; 340 pid_t pid = 0; 341 342 CHK(pipe(fd) == 0); 343 CHK((pid = fork()) != -1); 344 345 if(pid == 0) { /* Child process */ 346 const char header[80] = {0}; 347 const uint32_t ntris = 1; 348 const uint16_t nattrs = 0; 349 350 CHK(close(fd[0]) == 0); /* Close the unused input stream */ 351 CHK(sstl_ref_put(sstl) == RES_OK); /* Release the unused sstl */ 352 353 /* Write the binary StL */ 354 CHK(write(fd[1], header, sizeof(header)) == sizeof(header)); 355 CHK(write(fd[1], &ntris, sizeof(ntris)) == sizeof(ntris)); 356 CHK(write(fd[1], f3(v, 0.f,-1.f, 0.f), sizeof(v)) == sizeof(v)); 357 CHK(write(fd[1], f3(v, 1.f, 0.f, 0.f), sizeof(v)) == sizeof(v)); 358 CHK(write(fd[1], f3(v, 0.f, 0.f, 1.f), sizeof(v)) == sizeof(v)); 359 CHK(write(fd[1], f3(v, 0.f, 0.f, 0.f), sizeof(v)) == sizeof(v)); 360 CHK(write(fd[1], &nattrs, sizeof(nattrs)) == sizeof(nattrs)); 361 362 CHK(close(fd[1]) == 0); 363 exit(0); 364 365 } else { /* Parent process */ 366 struct sstl_desc desc = SSTL_DESC_NULL; 367 FILE* fp = NULL; 368 CHK(close(fd[1]) == 0); /* Close the unused output stream */ 369 370 CHK(fp = fdopen(fd[0], "r")); 371 CHK(sstl_load_stream(sstl, fp, "Piped StL") == RES_BAD_ARG); 372 CHK(sstl_load_stream_binary(sstl, fp, "Piped StL") == RES_OK); 373 CHK(fclose(fp) == 0); 374 375 CHK(sstl_get_desc(sstl, &desc) == RES_OK); 376 CHK(desc.type == SSTL_BINARY); 377 CHK(!strcmp(desc.filename, "Piped StL")); 378 CHK(desc.solid_name == NULL); 379 CHK(desc.vertices_count == 3); 380 CHK(desc.triangles_count == 1); 381 CHK(desc.indices[0] == 0); 382 CHK(desc.indices[1] == 1); 383 CHK(desc.indices[2] == 2); 384 CHK(f3_eq(desc.vertices + 0*3, f3(v, 1.f, 0.f, 0.f)) == 1); 385 CHK(f3_eq(desc.vertices + 1*3, f3(v, 0.f, 0.f, 1.f)) == 1); 386 CHK(f3_eq(desc.vertices + 2*3, f3(v, 0.f, 0.f, 0.f)) == 1); 387 CHK(f3_eq(desc.normals, f3(v, 0.f, -1.f, 0.f)) == 1); 388 } 389 } 390 391 392 /******************************************************************************* 393 * The test 394 ******************************************************************************/ 395 int 396 main(int argc, char** argv) 397 { 398 struct sstl* sstl = NULL; 399 (void)argc, (void)argv; 400 401 CHK(sstl_create(NULL, NULL, 3, &sstl) == RES_OK); 402 403 check_api(sstl); 404 check_1_triangle(sstl); 405 check_1_triangle_no_normal(sstl); 406 check_invalid_file(sstl); 407 check_tetrahedron(sstl); 408 check_no_seekable_file(sstl); 409 410 CHK(sstl_ref_put(sstl) == RES_OK); 411 CHK(mem_allocated_size() == 0); 412 return 0; 413 }