commit e20bd58ae37440b5293d0b8e20fd2064daba5349
parent 62833bc63bc69a1121d26a5f67f178366470198e
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 6 Jan 2016 11:00:25 +0100
First draft of the load functions
It is neither tested nor finalized.
Diffstat:
2 files changed, 334 insertions(+), 1 deletion(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -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 a computer program whose purpose is to generate files used
# to build the Star-3D library.
@@ -63,6 +63,10 @@ rcmake_prepend_path(SSTL_FILES_DOC ${SSTL_SOURCE_DIR}/../)
add_library(sstl SHARED ${SSTL_FILES_SRC} ${SSTL_FILES_INC} ${SSTL_FILES_INC_API})
target_link_libraries(sstl RSys)
+if(CMAKE_COMPILER_IS_GNUCC)
+ target_link_libraries(sstl m)
+endif()
+
set(VERSION_MAJOR 0)
set(VERSION_MINOR 3)
diff --git a/src/sstl.c b/src/sstl.c
@@ -28,12 +28,48 @@
#include "sstl.h"
+#include <rsys/cstr.h>
+#include <rsys/float3.h>
+#include <rsys/hash_table.h>
#include <rsys/logger.h>
#include <rsys/mem_allocator.h>
#include <rsys/ref_count.h>
+#include <rsys/stretchy_array.h>
+
+struct solid {
+ char* name;
+ size_t* indices;
+ float* vertices;
+ float* normals;
+};
+static const struct solid SOLID_NULL = { NULL, NULL, NULL, NULL };
+
+struct vertex { float xyz[3]; };
+
+struct streamer {
+ FILE* stream;
+ const char* name;
+ size_t iline;
+ char* buf;
+};
+
+static INLINE char
+eq_vertex(const struct vertex* a, const struct vertex* b)
+{
+ return f3_eq(a->xyz, b->xyz);
+}
+
+#define HTABLE_NAME vertex
+#define HTABLE_DATA size_t
+#define HTABLE_KEY struct vertex
+#define HTABLE_KEY_FUNCTOR_EQ eq_vertex
+#include <rsys/hash_table.h>
struct sstl {
int verbose;
+ struct htable_vertex vertex2id;
+ struct solid* solids;
+
struct logger* logger;
struct mem_allocator* allocator;
ref_T ref;
@@ -43,6 +79,271 @@ struct sstl {
* Helper functions
******************************************************************************/
static void
+streamer_init(struct streamer* streamer, FILE* stream, const char* name)
+{
+ ASSERT(streamer && stream && name);
+ memset(streamer, 0, sizeof(struct streamer));
+ streamer->stream = stream;
+ streamer->name = name;
+ streamer->iline = 1;
+}
+
+static void
+streamer_release(struct streamer* streamer)
+{
+ ASSERT(streamer);
+ sa_release(streamer->buf);
+}
+
+static char*
+streamer_read_line(struct streamer* streamer)
+{
+ const size_t buf_chunk = 256;
+ char* line;
+ ASSERT(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);
+ if(!remain) {
+ FATAL("Not enough memory: couldn't resize the stream buffer.\n");
+ }
+ line = streamer->buf;
+ if(!fgets(remain, (int)buf_chunk, streamer->stream)) /* EOF */
+ break;
+ }
+ if(strcspn(streamer->buf, " \t") != 0) /* Not empty line */
+ break;
+ }
+ ++streamer->iline;
+ return line;
+}
+
+static void
+solid_clear(struct solid* solid)
+{
+ ASSERT(solid);
+ sa_release(solid->name);
+ sa_release(solid->vertices);
+ sa_release(solid->indices);
+ sa_release(solid->normals);
+}
+
+static void
+print_log
+ (const struct sstl* sstl, const enum log_type type, const char* msg, ...)
+{
+ va_list vargs_list;
+ ASSERT(sstl && msg);
+ if(sstl->verbose) {
+ res_T res; (void)res;
+ va_start(vargs_list, msg);
+ res = logger_vprint(sstl->logger, type, msg, vargs_list);
+ ASSERT(res == RES_OK);
+ va_end(vargs_list);
+ }
+}
+
+static INLINE res_T
+parse_float3
+ (struct sstl* sstl,
+ char* str,
+ float vert[3],
+ const char* filename,
+ const size_t iline)
+{
+ char* tk;
+ int i;
+ res_T res = RES_OK;
+ ASSERT(str && vert && filename);
+
+ tk = strtok(str, " \t");
+ FOR_EACH(i, 0, 3) {
+ if(!tk) {
+ print_log(sstl, LOG_ERROR, "%s:%lu: expecting 3D coordinates.\n",
+ filename, (unsigned long)iline);
+ return RES_BAD_ARG;
+ }
+
+ res = cstr_to_float(tk, vert + i);
+ if(res != RES_OK) {
+ print_log(sstl, LOG_ERROR, "%s:%lu: invalid coordinate \"%s\".\n",
+ filename, (unsigned long)iline, tk);
+ return res;
+ }
+ tk = strtok(NULL, " \t");
+ }
+ tk = strtok(NULL, "\0");
+ if(tk) {
+ print_log(sstl, LOG_WARNING, "%s:%lu: unexpected directive \"%s\".\n",
+ filename, (unsigned long)iline, tk);
+ }
+ return RES_OK;
+}
+
+static res_T
+load_stream(struct sstl* sstl, FILE* stream, const char* stream_name)
+{
+ res_T res = RES_OK;
+ struct streamer streamer;
+ struct solid solid = SOLID_NULL;
+ char* line = NULL;
+ char* tk;
+ size_t* id;
+
+ ASSERT(sstl && stream);
+ streamer_init(&streamer, stream, stream_name);
+
+ if(!sstl || !stream) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ while((line = streamer_read_line(&streamer))) {
+
+ /* 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);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ tk = strtok(NULL, "\0");
+ solid.name = sa_add(solid.name, strlen(tk)+1/*NULL char*/);
+ if(!solid.name) {
+ print_log(sstl, LOG_ERROR,
+ "Not enough memory: couldn't allocate the name of the solid.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ for(;;) { /* Parse the solid facets */
+ float normal[3];
+ 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(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);
+ 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);
+ }
+ 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);
+ }
+ }
+
+ if(strcmp(strtok(NULL, "\0"), streamer.name)) {
+ print_log(sstl, LOG_WARNING,
+ "%s:%lu: inconsistent \"endsolid\" name.\n",
+ streamer.name, (unsigned long)streamer.iline);
+ }
+ solid_clear(&solid); /* FIXME register the solid against sstl */
+ }
+exit:
+ streamer_release(&streamer);
+ return res;
+error:
+ goto exit;
+}
+
+static void
sstl_release(ref_T* ref)
{
struct sstl* sstl;
@@ -88,6 +389,7 @@ sstl_create
sstl->allocator = allocator;
sstl->logger = logger;
sstl->verbose = verbose;
+ htable_vertex_init(allocator, &sstl->vertex2id);
exit:
if(out_sstl) *out_sstl = sstl;
@@ -117,3 +419,30 @@ sstl_ref_put(struct sstl* sstl)
}
+res_T
+sstl_load(struct sstl* sstl, const char* filename)
+{
+ FILE* file;
+ res_T res = RES_OK;
+
+ if(!sstl || !filename)
+ return RES_BAD_ARG;
+
+ file = fopen(filename, "r");
+ if(!file) {
+ print_log(sstl, LOG_ERROR, "Error opening `%s'.\n", filename);
+ return RES_IO_ERR;
+ }
+ res = load_stream(sstl, file, filename);
+ fclose(file);
+ return res;
+}
+
+res_T
+sstl_load_stream(struct sstl* sstl, FILE* stream)
+{
+ if(!sstl || !stream) return RES_BAD_ARG;
+ return load_stream(sstl, stream, "STREAM");
+}
+
+