star-stl

Load STereo Lithography (StL) file format
git clone git://git.meso-star.fr/star-stl.git
Log | Files | Refs | README | LICENSE

commit 857156284196db738b01e51802a6d28aca66a805
parent 11f0d828ac3672c80966170930831f18a702b18e
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  6 Jan 2016 12:31:39 +0100

Refactor and finalise a first version of the load functions

Diffstat:
Msrc/sstl.c | 357++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/sstl.h | 2+-
Msrc/test_sstl.c | 2+-
3 files changed, 237 insertions(+), 124 deletions(-)

diff --git a/src/sstl.c b/src/sstl.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2015 (contact@meso-star.com) +/* 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, @@ -44,8 +44,6 @@ struct solid { }; static const struct solid SOLID_NULL = { NULL, NULL, NULL, NULL }; -struct vertex { float xyz[3]; }; - struct streamer { FILE* stream; const char* name; @@ -53,12 +51,15 @@ struct streamer { char* buf; }; +struct vertex { float xyz[3]; }; + static INLINE char eq_vertex(const struct vertex* a, const struct vertex* b) { return f3_eq(a->xyz, b->xyz); } +/* Declare the hash table that map a vertex to its index */ #define HTABLE_NAME vertex #define HTABLE_DATA size_t #define HTABLE_KEY struct vertex @@ -68,7 +69,7 @@ eq_vertex(const struct vertex* a, const struct vertex* b) struct sstl { int verbose; struct htable_vertex vertex2id; - struct solid* solids; + struct solid solid; struct logger* logger; struct mem_allocator* allocator; @@ -132,6 +133,15 @@ solid_clear(struct solid* solid) } static void +clear(struct sstl* sstl) +{ + ASSERT(sstl); + solid_clear(&sstl->solid); + sstl->solid = SOLID_NULL; + htable_vertex_clear(&sstl->vertex2id); +} + +static void print_log (const struct sstl* sstl, const enum log_type type, const char* msg, ...) { @@ -176,13 +186,155 @@ parse_float3 tk = strtok(NULL, " \t"); } tk = strtok(NULL, "\0"); - if(tk) { + if(tk) { /* Unexpected remaining chars */ print_log(sstl, LOG_WARNING, "%s:%lu: unexpected directive \"%s\".\n", filename, (unsigned long)iline, tk); } return RES_OK; } +static INLINE res_T +parse_solid_name + (struct sstl* sstl, + struct solid* solid, + char* line, + const char* filename, + const size_t iline) +{ + char* tk; + res_T res = RES_OK; + ASSERT(sstl && solid && !solid->name); + + if(!line || strcmp(strtok(line, " \t"), "solid")) { + print_log(sstl, LOG_ERROR, + "%s:%lu: missing the \"solid [NAME]\" directive.\n", + filename, (unsigned long)iline); + res = RES_BAD_ARG; + goto error; + } + + tk = strtok(NULL, " \t"); + if(!tk) { + solid->name = sa_add(solid->name, strlen(tk)+1/*NULL char*/); + if(!solid->name) { + print_log(sstl, LOG_ERROR, + "%s:%lu: not enough memory: couldn't allocate the name of the solid.\n", + filename, (unsigned long)iline); + res = RES_MEM_ERR; + goto error; + } + strcpy(solid->name, tk); + + if((tk = strtok(NULL, "\0")) && strcspn(tk, " \t")) { /* Trailing chars */ + print_log(sstl, LOG_WARNING, + "%s:%lu: malformed \"solid [NAME]\" directive.\n"); + } + } + +exit: + return res; +error: + if(solid->name) sa_release(solid->name); + goto exit; +} + +static INLINE res_T +parse_solid_vertex + (struct sstl* sstl, + struct solid* solid, + size_t* index, + char* line, + const char* filename, + const size_t iline) +{ + struct vertex vertex; + res_T res = RES_OK; + ASSERT(sstl && solid && index); + + 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); + return RES_BAD_ARG; + } + + res = parse_float3(sstl, strtok(NULL, "\0"), vertex.xyz, filename, iline); + if(res != RES_OK) return res; + + /* Look for an already registered vertex position */ + index = htable_vertex_find(&sstl->vertex2id, &vertex); + + if(!index) { + /* Add a new vertex */ + *index = sa_size(solid->indices); + res = htable_vertex_set(&sstl->vertex2id, &vertex, index); + if(res != RES_OK) { + print_log(sstl, LOG_ERROR, + "%s:%lu: couldn't register a vertex position.\n", + filename, (unsigned long)iline); + } + f3_set(sa_add(solid->vertices, 3), vertex.xyz); + } + return RES_OK; +} + +static INLINE res_T +parse_outer_loop + (struct sstl* sstl, + char* line, + const char* filename, + const size_t iline) +{ + char* tk; + ASSERT(sstl); + + if(!line + || strcmp(strtok(line, " \t"), "outer") + || !(tk = strtok(NULL, " \t")) + || strcmp(tk, "loop")) { + print_log(sstl, LOG_ERROR, + "%s:%lu: missing the \"outer loop\" directive.\n", + filename, (unsigned long)iline); + return RES_BAD_ARG; + } + + tk = strtok(NULL, "\0"); + if(tk && strcspn(tk, " \t")) { /* Invalid remaining chars */ + print_log(sstl, LOG_WARNING, + "%s:%lu: malformed \"outer loop\" directive.\n", + filename, (unsigned long)iline); + } + return RES_OK; +} + +static INLINE res_T +parse_directive + (struct sstl* sstl, + const char* directive, + char* line, + const char* filename, + const size_t iline) +{ + char* tk; + ASSERT(sstl && directive); + + if(!line || strcmp(strtok(line, " \t"), directive)) { + print_log(sstl, LOG_ERROR, + "%s:%lu: missing the \"%s\" directive.\n", + filename, (unsigned long)iline, directive); + return RES_BAD_ARG; + } + + tk = strtok(NULL, " \0"); + if(tk && strcspn(tk, " \t")) { /* Invalid remaining chars */ + print_log(sstl, LOG_WARNING, + "%s:%lu: malformed \"%s\" directive.\n", + filename, (unsigned long)iline, directive); + } + + return RES_OK; +} + static res_T load_stream(struct sstl* sstl, FILE* stream, const char* stream_name) { @@ -191,155 +343,115 @@ load_stream(struct sstl* sstl, FILE* stream, const char* stream_name) struct solid solid = SOLID_NULL; char* line = NULL; char* tk; - size_t* id; ASSERT(sstl && stream); streamer_init(&streamer, stream, stream_name); + clear(sstl); if(!sstl || !stream) { res = RES_BAD_ARG; goto error; } - while((line = streamer_read_line(&streamer))) { + line = streamer_read_line(&streamer); + res = parse_solid_name(sstl, &solid, line, streamer.name, streamer.iline); + if(res != RES_OK) goto error; - /* Parse the solid name */ - if(strcmp(strtok(line, " \t"), "solid")) { - print_log(sstl, LOG_ERROR, - "%s:%lu: missing the \"solid NAME\" directive.\n", - streamer.name, (unsigned long)streamer.iline); + for(;;) { /* Parse the solid facets */ + float normal[3], v0[3], v1[3], N[3], len; + size_t facet[3]; + int ivertex; + + solid = SOLID_NULL; + + line = streamer_read_line(&streamer); + if(!(line = streamer_read_line(&streamer))) { + print_log(sstl, LOG_ERROR, "%s:%lu: missing directive.\n", + streamer.name, (unsigned long)streamer.iline); res = RES_BAD_ARG; goto error; } - tk = strtok(NULL, "\0"); - solid.name = sa_add(solid.name, strlen(tk)+1/*NULL char*/); - if(!solid.name) { + + tk = strtok(line, " \t"); + + /* Stop on "endsolid" directive */ + if(!strcmp(tk, "endsolid")) + break; + + /* Parse the facet normal directive */ + if(strcmp(tk, "facet") + || !(tk = strtok(NULL, " \t")) + || strcmp(tk, "normal")) { print_log(sstl, LOG_ERROR, - "Not enough memory: couldn't allocate the name of the solid.\n"); - res = RES_MEM_ERR; + "%s:%lu: missing the \"facet normal X Y Z\" directive.\n", + streamer.name, (unsigned long)streamer.iline); + res = RES_BAD_ARG; goto error; } + res = parse_float3 + (sstl, strtok(NULL, "\0"), normal, streamer.name, streamer.iline); + if(res != RES_OK) goto error; - for(;;) { /* Parse the solid facets */ - float normal[3]; - size_t facet[3]; - int ivertex; - - solid = SOLID_NULL; + /* Parse the Outer loop directive */ + line = streamer_read_line(&streamer); + res = parse_outer_loop(sstl, line, streamer.name, streamer.iline); + if(res != RES_OK) goto error; + /* Parse the facet vertices. Assume that only 3 vertices are submitted */ + FOR_EACH(ivertex, 0, 3) { line = streamer_read_line(&streamer); - if(!(line = streamer_read_line(&streamer))) { - print_log(sstl, LOG_ERROR, "%s:%lu: missing directive.\n", - streamer.name, (unsigned long)streamer.iline); - res = RES_BAD_ARG; - goto error; - } - - tk = strtok(line, " \t"); - - /* Stop on "endsolid" directive */ - if(!strcmp(tk, "endsolid")) - break; - - /* Parse the facet normal directive */ - if(strcmp(tk, "facet") || strcmp(strtok(NULL, " \t"), "normal")) { - print_log(sstl, LOG_ERROR, - "%s:%lu: missing the \"facet normal X Y Z\" directive.\n", - streamer.name, (unsigned long)streamer.iline); - res = RES_BAD_ARG; - goto error; - } - res = parse_float3 - (sstl, strtok(NULL, "\0"), normal, streamer.name, streamer.iline); + res = parse_solid_vertex + (sstl, &solid, facet+ivertex, line, streamer.name, streamer.iline); if(res != RES_OK) goto error; + } - /* Parse the Outer loop directive */ - if(!(line = streamer_read_line(&streamer)) - || strcmp(strtok(line, " \t"), "outer") - || strcmp(strtok(NULL, " \t"), "loop")) { - print_log(sstl, LOG_ERROR, - "%s:%lu: missing the \"outer loop\" directive.\n", - streamer.name, (unsigned long)streamer.iline); - res = RES_BAD_ARG; - goto error; - } - if(strcspn(strtok(NULL, " \0"), " \t")) { /* Invalid remaining chars */ - print_log(sstl, LOG_WARNING, - "%s:%lu: malformed \"outer loop\" directive.\n", - streamer.name, (unsigned long)streamer.iline); - res = RES_BAD_ARG; - goto error; - } - - /* Parse the facet vertices. Assume that only 3 vertices are submitted */ - FOR_EACH(ivertex, 0, 3) { - struct vertex pos; - line = streamer_read_line(&streamer); - if(!line || !strcmp(strtok(line, " \t"), "vertex")) { - print_log(sstl, LOG_ERROR, - "%s:%lu: missing a \"vertex X Y Z\" directive.\n", - streamer.name, (unsigned long)streamer.iline); - res = RES_BAD_ARG; - goto error; - } - res = parse_float3 - (sstl, strtok(NULL, "\0"), pos.xyz, streamer.name, streamer.iline); - if(res != RES_OK) goto error; - - id = htable_vertex_find(&sstl->vertex2id, &pos); - if(id) { - facet[ivertex] = *id; - } else { - facet[ivertex] = sa_size(solid.indices); - res = htable_vertex_set(&sstl->vertex2id, &pos, facet + ivertex); - if(res != RES_OK) { - print_log(sstl, LOG_ERROR, - "%s:%lu: couldn't register a vertex position.\n", - streamer.name, (unsigned long)streamer.iline); - } - f3_set(sa_add(solid.vertices, 3), pos.xyz); - } - } - - if(!f3_is_normalized(normal)) { /* Compute normal from facet vertices */ - float v0[3], v1[3]; - 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); + /* 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); - id = sa_add(solid.indices, 3); - id[0] = facet[0]; - id[1] = facet[1]; - id[2] = facet[2]; - - streamer_read_line(&streamer); - if(!line || strcmp(strtok(line, " \t"), "endloop")) { - print_log(sstl, LOG_ERROR, - "%s:%lu: missing the \"endloop\" directive.\n", - streamer.name, (unsigned long)streamer.iline); - res = RES_BAD_ARG; - goto error; - } - if(strcspn(strtok(NULL, " \0"), " \t")) { /* Invalid remaining chars */ - print_log(sstl, LOG_WARNING, - "%s:%lu: malformed \"endloop\" directive.\n", - streamer.name, (unsigned long)streamer.iline); - } + sa_push(solid.indices, facet[0]); + sa_push(solid.indices, facet[1]); + sa_push(solid.indices, facet[2]); } - if(strcmp(strtok(NULL, "\0"), streamer.name)) { + line = streamer_read_line(&streamer); + res = parse_directive(sstl, "endloop", line, streamer.name, streamer.iline); + if(res != RES_OK) goto error; + + line = streamer_read_line(&streamer); + res = parse_directive(sstl, "endfacet", line, streamer.name, streamer.iline); + if(res != RES_OK) goto error; + } + + if(solid.name) { /* Parse "name" of the endsolid directive */ + tk = strtok(NULL, " \t"); + if(tk && strcmp(tk, solid.name)) { print_log(sstl, LOG_WARNING, - "%s:%lu: inconsistent \"endsolid\" name.\n", + "%s:%lu: missing or inconsistent \"endsolid\" name.\n", streamer.name, (unsigned long)streamer.iline); } - solid_clear(&solid); /* FIXME register the solid against sstl */ } + + if((tk = strtok(NULL, " \0")) && strcspn(tk, " \t")) { /* Invalid chars */ + print_log(sstl, LOG_WARNING, + "%s:%lu: malformed \"endsolid\" directive\n", + streamer.name, streamer.iline); + } + + /* Register the solid */ + sstl->solid = solid; + exit: streamer_release(&streamer); return res; error: + solid_clear(&solid); goto exit; } @@ -349,6 +461,8 @@ sstl_release(ref_T* ref) struct sstl* sstl; ASSERT(ref); sstl = CONTAINER_OF(ref, struct sstl, ref); + clear(sstl); + htable_vertex_release(&sstl->vertex2id); MEM_RM(sstl->allocator, sstl); } @@ -445,4 +559,3 @@ sstl_load_stream(struct sstl* sstl, FILE* stream) return load_stream(sstl, stream, "STREAM"); } - diff --git a/src/sstl.h b/src/sstl.h @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2015 (contact@meso-star.com) +/* 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, diff --git a/src/test_sstl.c b/src/test_sstl.c @@ -1,4 +1,4 @@ -/* Copyright (C) |Meso|Star> 2015 (contact@meso-star.com) +/* 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,