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:
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,