commit 408de0cef4631a5e209dfb2025b598ecec890312
parent 857156284196db738b01e51802a6d28aca66a805
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 6 Jan 2016 16:14:02 +0100
Test and fix the load functions
Diffstat:
3 files changed, 239 insertions(+), 41 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -92,6 +92,11 @@ if(NOT NO_TEST)
add_executable(test_sstl ${SSTL_SOURCE_DIR}/test_sstl.c)
target_link_libraries(test_sstl sstl)
add_test(test_sstl test_sstl)
+
+ add_executable(test_sstl_load ${SSTL_SOURCE_DIR}/test_sstl_load.c)
+ target_link_libraries(test_sstl_load sstl)
+ add_test(test_sstl_load test_sstl)
+
rcmake_set_test_runtime_dirs(test_sstl _runtime_dirs)
endif(NOT NO_TEST)
diff --git a/src/sstl.c b/src/sstl.c
@@ -86,7 +86,9 @@ streamer_init(struct streamer* streamer, FILE* stream, const char* name)
memset(streamer, 0, sizeof(struct streamer));
streamer->stream = stream;
streamer->name = name;
- streamer->iline = 1;
+ streamer->iline = 0;
+ streamer->buf = sa_add(streamer->buf, 128);
+ ASSERT(streamer->buf);
}
static void
@@ -105,6 +107,7 @@ streamer_read_line(struct streamer* streamer)
for(;(line=fgets(streamer->buf, (int)sa_size(streamer->buf), streamer->stream));
++streamer->iline) {
+
/* Ensure that the whole line is read */
while(!strrchr(line, '\n')) {
char* remain = sa_add(streamer->buf, buf_chunk);
@@ -115,8 +118,14 @@ streamer_read_line(struct streamer* streamer)
if(!fgets(remain, (int)buf_chunk, streamer->stream)) /* EOF */
break;
}
- if(strcspn(streamer->buf, " \t") != 0) /* Not empty line */
+
+ if(strspn(streamer->buf, " \t\r\n") != strlen(streamer->buf)) { /* Not empty */
+ /* Remove newline character(s) */
+ size_t last_char = strlen(line);
+ while(last_char-- && (line[last_char]=='\n' || line[last_char]=='\r'));
+ line[last_char + 1] = '\0';
break;
+ }
}
++streamer->iline;
return line;
@@ -169,8 +178,8 @@ parse_float3
res_T res = RES_OK;
ASSERT(str && vert && filename);
- tk = strtok(str, " \t");
FOR_EACH(i, 0, 3) {
+ tk = strtok(i==0 ? str : NULL, " \t");
if(!tk) {
print_log(sstl, LOG_ERROR, "%s:%lu: expecting 3D coordinates.\n",
filename, (unsigned long)iline);
@@ -183,7 +192,6 @@ parse_float3
filename, (unsigned long)iline, tk);
return res;
}
- tk = strtok(NULL, " \t");
}
tk = strtok(NULL, "\0");
if(tk) { /* Unexpected remaining chars */
@@ -214,7 +222,7 @@ parse_solid_name
}
tk = strtok(NULL, " \t");
- if(!tk) {
+ if(tk) {
solid->name = sa_add(solid->name, strlen(tk)+1/*NULL char*/);
if(!solid->name) {
print_log(sstl, LOG_ERROR,
@@ -225,7 +233,7 @@ parse_solid_name
}
strcpy(solid->name, tk);
- if((tk = strtok(NULL, "\0")) && strcspn(tk, " \t")) { /* Trailing chars */
+ if((tk = strtok(NULL, "\0")) && strspn(tk, " \t\r\n") != strlen(tk)) {
print_log(sstl, LOG_WARNING,
"%s:%lu: malformed \"solid [NAME]\" directive.\n");
}
@@ -242,16 +250,17 @@ static INLINE res_T
parse_solid_vertex
(struct sstl* sstl,
struct solid* solid,
- size_t* index,
+ size_t* const index,
char* line,
const char* filename,
const size_t iline)
{
struct vertex vertex;
+ size_t* found_id;
res_T res = RES_OK;
ASSERT(sstl && solid && index);
- if(!line || !strcmp(strtok(line, " \t"), "vertex")) {
+ if(!line || strcmp(strtok(line, " \t"), "vertex")) {
print_log(sstl, LOG_ERROR,
"%s:%lu: missing a \"vertex X Y Z\" directive.\n",
filename, (unsigned long)iline);
@@ -262,9 +271,11 @@ parse_solid_vertex
if(res != RES_OK) return res;
/* Look for an already registered vertex position */
- index = htable_vertex_find(&sstl->vertex2id, &vertex);
+ found_id = htable_vertex_find(&sstl->vertex2id, &vertex);
- if(!index) {
+ if(found_id) {
+ *index = *found_id;
+ } else {
/* Add a new vertex */
*index = sa_size(solid->indices);
res = htable_vertex_set(&sstl->vertex2id, &vertex, index);
@@ -273,8 +284,11 @@ parse_solid_vertex
"%s:%lu: couldn't register a vertex position.\n",
filename, (unsigned long)iline);
}
+
f3_set(sa_add(solid->vertices, 3), vertex.xyz);
}
+ sa_push(solid->indices, *index);
+
return RES_OK;
}
@@ -299,7 +313,7 @@ parse_outer_loop
}
tk = strtok(NULL, "\0");
- if(tk && strcspn(tk, " \t")) { /* Invalid remaining chars */
+ if(tk && strspn(tk, " \t\r\n") != strlen(tk)) { /* Invalid remaining chars */
print_log(sstl, LOG_WARNING,
"%s:%lu: malformed \"outer loop\" directive.\n",
filename, (unsigned long)iline);
@@ -326,7 +340,7 @@ parse_directive
}
tk = strtok(NULL, " \0");
- if(tk && strcspn(tk, " \t")) { /* Invalid remaining chars */
+ if(tk && strspn(tk, " \t\r\n") != strlen(tk)) { /* Invalid remaining chars */
print_log(sstl, LOG_WARNING,
"%s:%lu: malformed \"%s\" directive.\n",
filename, (unsigned long)iline, directive);
@@ -348,26 +362,19 @@ load_stream(struct sstl* sstl, FILE* stream, const char* stream_name)
streamer_init(&streamer, stream, stream_name);
clear(sstl);
- if(!sstl || !stream) {
- res = RES_BAD_ARG;
- goto error;
- }
-
line = streamer_read_line(&streamer);
res = parse_solid_name(sstl, &solid, line, streamer.name, streamer.iline);
if(res != RES_OK) goto error;
for(;;) { /* Parse the solid facets */
- float normal[3], v0[3], v1[3], N[3], len;
+ float normal[3];
size_t facet[3];
int ivertex;
- solid = SOLID_NULL;
-
line = streamer_read_line(&streamer);
- if(!(line = streamer_read_line(&streamer))) {
+ if(!line) {
print_log(sstl, LOG_ERROR, "%s:%lu: missing directive.\n",
- streamer.name, (unsigned long)streamer.iline);
+ streamer.name, (unsigned long)streamer.iline);
res = RES_BAD_ARG;
goto error;
}
@@ -380,11 +387,11 @@ load_stream(struct sstl* sstl, FILE* stream, const char* stream_name)
/* Parse the facet normal directive */
if(strcmp(tk, "facet")
- || !(tk = strtok(NULL, " \t"))
- || strcmp(tk, "normal")) {
+ || !(tk = strtok(NULL, " \t"))
+ || strcmp(tk, "normal")) {
print_log(sstl, LOG_ERROR,
- "%s:%lu: missing the \"facet normal X Y Z\" directive.\n",
- streamer.name, (unsigned long)streamer.iline);
+ "%s:%lu: missing or malformed \"facet normal X Y Z\" directive.\n",
+ streamer.name, (unsigned long)streamer.iline);
res = RES_BAD_ARG;
goto error;
}
@@ -405,20 +412,15 @@ load_stream(struct sstl* sstl, FILE* stream, const char* stream_name)
if(res != RES_OK) goto error;
}
- /* Register the facet if it is not degenerated */
- f3_sub(v0, solid.vertices + facet[1]*3, solid.vertices + facet[0]*3);
- f3_sub(v1, solid.vertices + facet[2]*3, solid.vertices + facet[0]*3);
- f3_cross(N, v0, v1);
- len = f3_dot(N, N);
- if(len != 0.f) { /* triangle is not degenerated */
- if(!f3_is_normalized(normal)) { /* Use geometry normal */
- f3_divf(normal, N, (float)sqrt(len));
- }
- f3_set(sa_add(solid.normals, 3), normal);
- sa_push(solid.indices, facet[0]);
- sa_push(solid.indices, facet[1]);
- sa_push(solid.indices, facet[2]);
+ if(!f3_is_normalized(normal)) { /* Use geometry normal */
+ float v0[3], v1[3];
+ /* Vertices are CCW ordered and the normal follows the right handed rule */
+ f3_sub(v0, solid.vertices + facet[1]*3, solid.vertices + facet[0]*3);
+ f3_sub(v1, solid.vertices + facet[2]*3, solid.vertices + facet[0]*3);
+ f3_cross(normal, v0, v1);
+ f3_normalize(normal, normal);
}
+ f3_set(sa_add(solid.normals, 3), normal);
line = streamer_read_line(&streamer);
res = parse_directive(sstl, "endloop", line, streamer.name, streamer.iline);
@@ -433,12 +435,12 @@ load_stream(struct sstl* sstl, FILE* stream, const char* stream_name)
tk = strtok(NULL, " \t");
if(tk && strcmp(tk, solid.name)) {
print_log(sstl, LOG_WARNING,
- "%s:%lu: missing or inconsistent \"endsolid\" name.\n",
+ "%s:%lu: inconsistent \"endsolid\" name.\n",
streamer.name, (unsigned long)streamer.iline);
}
}
- if((tk = strtok(NULL, " \0")) && strcspn(tk, " \t")) { /* Invalid chars */
+ if((tk = strtok(NULL, " \0")) && strspn(tk, " \t\r\n") != strlen(tk)) {
print_log(sstl, LOG_WARNING,
"%s:%lu: malformed \"endsolid\" directive\n",
streamer.name, streamer.iline);
diff --git a/src/test_sstl_load.c b/src/test_sstl_load.c
@@ -0,0 +1,191 @@
+/* Copyright (C) |Meso|Star> 2015-2016 (contact@meso-star.com)
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software. You can use,
+ * modify and/or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "http://www.cecill.info".
+ *
+ * As a counterpart to the access to the source code and rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty and the software's author, the holder of the
+ * economic rights, and the successive licensors have only limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading, using, modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean that it is complicated to manipulate, and that also
+ * therefore means that it is reserved for developers and experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and, more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms. */
+
+#include "sstl.h"
+#include "test_sstl_utils.h"
+
+#include <rsys/logger.h>
+
+static void
+test_basic(struct sstl* sstl)
+{
+ static const char* test0 =
+ "solid\n"
+ " facet normal 0.0 -1.0 0.0\n"
+ " outer loop\n"
+ " vertex 0.0 0.0 0.0\n"
+ " vertex 1.0 0.0 0.0\n"
+ " vertex 0.0 0.0 1.0\n"
+ " endloop\n"
+ " endfacet\n"
+ "endsolid";
+ static const char* test1 =
+ "solid my_solid\n"
+ "\n"
+ " facet normal 0.0 -1.0 0.0\n"
+ " outer loop hophophophophop\n"
+ " vertex\t 0.0 0.0 0.0\n"
+ " vertex 1.0 0.0 0.0 \taaa\n"
+ " vertex 0.0 0.0 1.0\n"
+ " endloop \n"
+ " endfacet \t\t\t noise\n"
+ "endsolid pouet\n";
+ static const char* test2 =
+ "solid my_solid\n"
+ "endsolid my_solid\n";
+
+ static const char* bad[] = {
+ "solid\n"
+ " facet normal 0.0 -1.0 0.0\n"
+ " outer loop\n"
+ " vertex 0.0 0.0 0.0\n"
+ " vertex 1.0 0.0 0.0\n"
+ " vertex 0.0 0.0 1.0\n"
+ " endloop\n"
+ " endfacet\n"
+ ,
+ " facet normal 0.0 -1.0 0.0\n"
+ " outer loop\n"
+ " vertex 0.0 0.0 0.0\n"
+ " vertex 1.0 0.0 0.0\n"
+ " vertex 0.0 0.0 1.0\n"
+ " endloop\n"
+ " endfacet\n"
+ "endsolid\n"
+ ,
+ "solid\n"
+ " facet 0.0 -1.0 0.0\n"
+ " outer loop\n"
+ " vertex 0.0 0.0 0.0\n"
+ " vertex 1.0 0.0 0.0\n"
+ " vertex 0.0 0.0 1.0\n"
+ " endloop\n"
+ " endfacet\n"
+ "endsolid\n"
+ ,
+ "solid\n"
+ " normal 0.0 -1.0 0.0\n"
+ " outer loop\n"
+ " vertex 0.0 0.0 0.0\n"
+ " vertex 1.0 0.0 0.0\n"
+ " vertex 0.0 0.0 1.0\n"
+ " endloop\n"
+ " endfacet\n"
+ "endsolid\n"
+ ,
+ "solid\n"
+ " facet normal 0.0 -1.0 0.0\n"
+ " outer loop\n"
+ " vertex 0.0 0.0 a.0\n"
+ " vertex 1.0 0.0 0.0\n"
+ " vertex 0.0 0.0 1.0\n"
+ " endloop\n"
+ " endfacet\n"
+ "endsolid\n"
+ ,
+ "solid\n"
+ " facet normal 0.0 -1.0 0.0\n"
+ " outer loop\n"
+ " vertex 1.0 0.0 0.0\n"
+ " vertex 0.0 0.0 1.0\n"
+ " endloop\n"
+ " endfacet\n"
+ "endsolid\n"
+ ,
+ "solid\n"
+ " facet normal 0.0 -1.0 0.0\n"
+ " vertex 0.0 0.0 0.0\n"
+ " vertex 1.0 0.0 0.0\n"
+ " vertex 0.0 0.0 1.0\n"
+ " endfacet\n"
+ "endsolid\n"
+ };
+ const size_t nbads = sizeof(bad)/sizeof(const char*);
+
+ FILE* file;
+ size_t i;
+
+ NCHECK(sstl, NULL);
+
+ file = fopen("test_basic.stl", "w");
+ NCHECK(file, NULL);
+ fwrite(test0, sizeof(char), strlen(test0), file);
+ fclose(file);
+
+ CHECK(sstl_load(NULL, NULL), RES_BAD_ARG);
+ CHECK(sstl_load(sstl, NULL), RES_BAD_ARG);
+ CHECK(sstl_load(NULL, "test_basic.stl"), RES_BAD_ARG);
+ CHECK(sstl_load(sstl, "none.stl"), RES_IO_ERR);
+ CHECK(sstl_load(sstl, "test_basic.stl"), RES_OK);
+
+ file = tmpfile();
+ NCHECK(file, NULL);
+ fwrite(test1, sizeof(char), strlen(test1), file);
+ rewind(file);
+ CHECK(sstl_load_stream(NULL, NULL), RES_BAD_ARG);
+ CHECK(sstl_load_stream(sstl, NULL), RES_BAD_ARG);
+ CHECK(sstl_load_stream(NULL, file), RES_BAD_ARG);
+ CHECK(sstl_load_stream(sstl, file), RES_OK);
+ fclose(file);
+
+ file = tmpfile();
+ fwrite(test2, sizeof(char), strlen(test2), file);
+ rewind(file);
+ CHECK(sstl_load_stream(sstl, file), RES_OK);
+ fclose(file);
+
+ FOR_EACH(i, 0, nbads) {
+ file = tmpfile();
+ fwrite(bad[i], sizeof(char), strlen(bad[i]), file);
+ rewind(file);
+ CHECK(sstl_load_stream(sstl, file), RES_BAD_ARG);
+ fclose(file);
+ }
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct sstl* sstl;
+ (void)argc, (void)argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(sstl_create(NULL, &allocator, 1, &sstl), RES_OK);
+
+ test_basic(sstl);
+
+ CHECK(sstl_ref_put(sstl), RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+ return 0;
+}
+