commit 6004efe0c7a24674ae9e1ceebe77d20ebe8a2ab8
parent 2ece078a8792331f46aab354dc134266fabe6835
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 7 Apr 2025 15:47:15 +0200
Start of a major refactoring of the API and implementation
This commit marks the start of a major overhaul of the Star-STL library.
Its API had become too complicated for its purpose: loading a simple
geometric format. And its implementation had become bloated.
The writing API was completely removed because it was both too
complicated and not designed for streaming output (i.e. on the fly): the
number of triangles would have to be known a priori, whereas this is not
a constraint of the StL format. It needs to be completely rethought.
Removes the API distinction between ASCII and binary files. Both should
be supported by the same set of functions. In any case, the binary
format is currently disabled. Only ASCII files are loaded, with a
loading procedure that has been completely rewritten to rely on the
text_reader API offered by RSys, rather than on a reading procedure
local to the library.
Finally, this commit removes support for the CL compiler.
Diffstat:
| M | Makefile | | | 2 | +- |
| M | src/sstl.c | | | 1028 | ++++++------------------------------------------------------------------------- |
| M | src/sstl.h | | | 66 | +++++------------------------------------------------------------- |
| A | src/sstl_ascii.c | | | 303 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/sstl_c.h | | | 97 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | src/test_sstl_load.c | | | 279 | +++++-------------------------------------------------------------------------- |
6 files changed, 492 insertions(+), 1283 deletions(-)
diff --git a/Makefile b/Makefile
@@ -25,7 +25,7 @@ LIBNAME = $(LIBNAME_$(LIB_TYPE))
################################################################################
# Library building
################################################################################
-SRC = src/sstl.c
+SRC = src/sstl.c src/sstl_ascii.c
OBJ = $(SRC:.c=.o)
DEP = $(SRC:.c=.d)
diff --git a/src/sstl.c b/src/sstl.c
@@ -16,28 +16,14 @@
#define _POSIX_C_SOURCE 200112L /* strtok_r support */
#include "sstl.h"
+#include "sstl_c.h"
#include <rsys/rsys.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>
-#include <string.h>
+#include <errno.h>
#include <stdio.h>
-#include <ctype.h>
-
-#ifdef COMPILER_CL
- #pragma warning(push)
- #pragma warning(disable:4706) /* Assignment within a condition */
-
- #define strtok_r strtok_s
-#endif
-
-#define OK(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0
enum allowed_load_steps {
TRY_READ_ASCII = 1,
@@ -52,888 +38,60 @@ enum read_type {
OK_BINARY = BIT(3)
};
-struct solid {
- char* name;
- unsigned* indices;
- float* vertices;
- float* normals;
- enum read_type read_type;
-};
-static const struct solid SOLID_NULL = { NULL, NULL, NULL, NULL, 0 };
-
-struct streamer {
- FILE* stream;
- const char* name;
- size_t iline;
- char* buf;
-};
-
-struct vertex { float xyz[3]; };
-
-static INLINE char
-eq_vertex(const struct vertex* a, const struct vertex* b)
-{
- return (char)f3_eq(a->xyz, b->xyz);
-}
-
-/* Declare the hash table that map a vertex to its index */
-#define HTABLE_NAME vertex
-#define HTABLE_DATA unsigned
-#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 solid;
-
- struct logger* logger;
- struct mem_allocator* allocator;
- ref_T ref;
-};
-
-/* A type for binary files I/O */
-struct tmp {
- float normal[3];
- union u {
- float vertices[3][3];
- struct vertex vtx[3];
- } u;
- unsigned short attrib, foo;
-};
-
-STATIC_ASSERT(sizeof(struct tmp) == 52, Invalid_struct_size);
-
/*******************************************************************************
* 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 = 0;
- streamer->buf = sa_add(streamer->buf, 128);
- ASSERT(streamer->buf);
-}
-
-static void
-streamer_release(struct streamer* streamer)
-{
- ASSERT(streamer);
- sa_release(streamer->buf);
-}
-
-/* Large enough to read "solid\0" */
-#define CHECK_SOLID_LEN 6
-
-static char*
-streamer_read_line
- (struct streamer* streamer,
- int checking_solid,
- size_t* count)
-{
- const size_t buf_chunk = 256;
- size_t read_sz, read_count = 0;
- char* line;
- ASSERT(streamer && count);
-
- if(checking_solid) {
- size_t current = sa_size(streamer->buf);
- if(current < CHECK_SOLID_LEN) {
- char* remain = sa_add(streamer->buf, CHECK_SOLID_LEN - current);
- if(!remain) {
- FATAL("Not enough memory: couldn't resize the stream buffer.\n");
- }
- }
- read_sz = CHECK_SOLID_LEN;
- } else {
- read_sz = sa_size(streamer->buf);
- }
-
- for(;(line=fgets(streamer->buf, (int)read_sz, streamer->stream));
- ++streamer->iline) {
- size_t l;
-
- /* If checking for a line starting with "solid", stop reading early if the
- * line does not. If no error, ensure that the whole line is read */
- while(!strrchr(line, '\n')) {
- char* remain;
- size_t remain_sz;
- if(checking_solid) {
- if(0 != strncmp("solid", line, 5)) {
- l = strlen(line);
- read_count += l;
- *count = read_count;
- /* Dont read further */
- return line;
- }
- remain = line + 5;
- ASSERT(*remain == '\0');
- remain_sz = sa_size(streamer->buf) - 5;
- } else {
- remain = sa_add(streamer->buf, buf_chunk);
- if(!remain) {
- FATAL("Not enough memory: couldn't resize the stream buffer.\n");
- }
- remain_sz = buf_chunk;
- }
- line = streamer->buf;
- if(!fgets(remain, (int)remain_sz, streamer->stream)) /* EOF */
- break;
-
- read_sz = sa_size(streamer->buf);
- checking_solid = 0;
- }
-
- l = strlen(streamer->buf);
- read_count += l;
- if(strspn(streamer->buf, " \t\r\n") != l) { /* 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;
- *count += read_count;
- 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
-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, ...)
-{
- 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** tok_ctx)
-{
- char* tk;
- int i;
- res_T res = RES_OK;
- ASSERT(str && vert && filename);
-
- FOR_EACH(i, 0, 3) {
- tk = strtok_r(i==0 ? str : NULL, " \t", tok_ctx);
- 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_r(NULL, "\0", tok_ctx);
- 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_name_string
- (struct sstl* sstl,
- char* str,
- char** out_name,
- const char* filename,
- const size_t iline,
- char** tok_ctx)
-{
- char* name = NULL;
- char* tk;
- res_T res = RES_OK;
- ASSERT(sstl && out_name);
-
- if(!str) goto exit;
-
- /* Handle name with spaces */
- for(tk = strtok_r(str, " \t", tok_ctx); tk; tk = strtok_r(NULL, " \t", tok_ctx)) {
- char* remain = NULL;
- if(name) name[strlen(name)] = ' '; /* Replace '\0' by ' ' */
- remain = sa_add(name, strlen(tk) + 1/*NULL char*/);
- if(!remain) {
- 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(remain, tk);
- }
-
-exit:
- *out_name = name;
- return res;
-error:
- if(name) {
- sa_release(name);
- name = NULL;
- }
- goto exit;
-}
-
-static INLINE res_T
-parse_solid_name
- (struct sstl* sstl,
- struct solid* solid,
- char* line,
- const char* filename,
- const size_t iline,
- int allowed,
- char** tok_ctx)
+sstl_release(ref_T* ref)
{
- res_T res = RES_OK;
- ASSERT(sstl && solid && !solid->name);
-
- if(!line || strcmp(strtok_r(line, " \t", tok_ctx), "solid")) {
- enum log_type lt = (allowed & TRY_READ_BINARY) ? LOG_OUTPUT : LOG_ERROR;
- print_log(sstl, lt,
- "%s:%lu: missing the \"solid [NAME]\" directive.\n",
- filename, (unsigned long)iline);
- res = RES_BAD_ARG;
- goto error;
- }
-
- solid->read_type |= STARTED_ASCII;
-
- OK(parse_name_string(sstl, strtok_r(NULL, "\0", tok_ctx), &solid->name,
- filename, iline, tok_ctx));
-
-exit:
- return res;
-error:
- if(solid->name) sa_release(solid->name);
- goto exit;
+ struct sstl* sstl;
+ ASSERT(ref);
+ sstl = CONTAINER_OF(ref, struct sstl, ref);
+ str_release(&sstl->name);
+ htable_vertex_release(&sstl->vertex2id);
+ sa_release(sstl->vertices);
+ sa_release(sstl->normals);
+ sa_release(sstl->indices);
+ MEM_RM(sstl->allocator, sstl);
}
-static INLINE res_T
-parse_solid_vertex
- (struct sstl* sstl,
- struct solid* solid,
- unsigned* const index,
- char* line,
- const char* filename,
- const size_t iline,
- char** tok_ctx)
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+register_vertex(struct sstl* sstl, const float v[3])
{
- struct vertex vertex;
- unsigned* found_id;
+ struct vertex vtx;
+ unsigned* found = NULL;
+ unsigned id = 0;
res_T res = RES_OK;
- ASSERT(sstl && solid && index);
+ ASSERT(sstl && v);
- if(!line || strcmp(strtok_r(line, " \t", tok_ctx), "vertex")) {
- print_log(sstl, LOG_ERROR,
- "%s:%lu: missing a \"vertex X Y Z\" directive.\n",
- filename, (unsigned long)iline);
- return RES_BAD_ARG;
- }
+ /* Check if the input vertex is already registered */
+ f3_set(vtx.xyz, v);
+ found = htable_vertex_find(&sstl->vertex2id, &vtx);
- res = parse_float3(sstl, strtok_r(NULL, "\0", tok_ctx), vertex.xyz, filename, iline, tok_ctx);
- if(res != RES_OK) return res;
+ if(found) { /* The vertex already exists */
+ id = *found;
- /* Look for an already registered vertex position */
- found_id = htable_vertex_find(&sstl->vertex2id, &vertex);
+ } else { /* The vertex is a new one */
+ id = (unsigned)sa_size(sstl->vertices)/3;
+ res = htable_vertex_set(&sstl->vertex2id, &vtx, &id);
+ if(res != RES_OK) goto error;
- if(found_id) {
- *index = *found_id;
- } else {
/* Add a new vertex */
- *index = (unsigned)sa_size(solid->vertices) / 3;
- 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);
- }
- sa_push(solid->indices, *index);
-
- return RES_OK;
-}
-
-static INLINE res_T
-parse_outer_loop
- (struct sstl* sstl,
- char* line,
- const char* filename,
- const size_t iline,
- char** tok_ctx)
-{
- char* tk;
- ASSERT(sstl);
-
- if(!line
- || strcmp(strtok_r(line, " \t", tok_ctx), "outer")
- || !(tk = strtok_r(NULL, " \t", tok_ctx))
- || 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_r(NULL, "\0", tok_ctx);
- 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);
- }
- 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** tok_ctx)
-{
- char* tk;
- ASSERT(sstl && directive);
-
- if(!line || strcmp(strtok_r(line, " \t", tok_ctx), directive)) {
- print_log(sstl, LOG_ERROR,
- "%s:%lu: missing the \"%s\" directive.\n",
- filename, (unsigned long)iline, directive);
- return RES_BAD_ARG;
- }
-
- tk = strtok_r(NULL, " \0", tok_ctx);
- 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);
- }
-
- return RES_OK;
-}
-
-static res_T
-load_ascii_stream
- (struct sstl* sstl,
- FILE* stream,
- const char* stream_name,
- int allowed,
- size_t* count)
-{
- res_T res = RES_OK;
- struct streamer streamer;
- struct solid solid = SOLID_NULL;
- char* line = NULL;
- char* tok_ctx;
- char* tk;
-
- ASSERT(sstl && stream && stream_name && count);
- streamer_init(&streamer, stream, stream_name);
- clear(sstl);
-
- line = streamer_read_line(&streamer, 1, count);
- OK(parse_solid_name(sstl, &solid, line, streamer.name, streamer.iline,
- allowed, &tok_ctx));
-
- for(;;) { /* Parse the solid facets */
- float normal[3];
- unsigned facet[3];
- int ivertex;
-
- line = streamer_read_line(&streamer, 0, count);
- if(!line) {
- print_log(sstl, LOG_ERROR, "%s:%lu: missing directive.\n",
- streamer.name, (unsigned long)streamer.iline);
- res = RES_BAD_ARG;
- goto error;
- }
-
- tk = strtok_r(line, " \t", &tok_ctx);
-
- /* Stop on "endsolid" directive */
- if(!strcmp(tk, "endsolid"))
- break;
-
- /* Parse the facet normal directive */
- if(strcmp(tk, "facet")
- || !(tk = strtok_r(NULL, " \t", &tok_ctx))
- || strcmp(tk, "normal")) {
- print_log(sstl, LOG_ERROR,
- "%s:%lu: missing or malformed \"facet normal X Y Z\" directive.\n",
- streamer.name, (unsigned long)streamer.iline);
- res = RES_BAD_ARG;
- goto error;
- }
- OK(parse_float3(sstl, strtok_r(NULL, "\0", &tok_ctx), normal, streamer.name,
- streamer.iline, &tok_ctx));
-
- /* Parse the Outer loop directive */
- line = streamer_read_line(&streamer, 0, count);
- OK(parse_outer_loop(sstl, line, streamer.name, streamer.iline, &tok_ctx));
-
- /* Parse the facet vertices. Assume that only 3 vertices are submitted */
- FOR_EACH(ivertex, 0, 3) {
- line = streamer_read_line(&streamer, 0, count);
- OK(parse_solid_vertex(sstl, &solid, facet+ivertex, line, streamer.name,
- streamer.iline, &tok_ctx));
- }
-
- 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, 0, count);
- OK(parse_directive(sstl, "endloop", line, streamer.name, streamer.iline, &tok_ctx));
-
- line = streamer_read_line(&streamer, 0, count);
- OK(parse_directive(sstl, "endfacet", line, streamer.name, streamer.iline, &tok_ctx));
+ f3_set(sa_add(sstl->vertices, 3), vtx.xyz);
}
- /* Check the solid/endsolid name consistency */
- if(sstl->verbose && solid.name) {
- char* name = NULL;
- OK(parse_name_string(sstl, strtok_r(NULL, "\0", &tok_ctx), &name,
- streamer.name, streamer.iline, &tok_ctx));
-
- /* Compare the "endsolid" name with the one of the "solid" directive */
- if(name && strcmp(name, solid.name)) {
- print_log(sstl, LOG_WARNING,
- "%s:%lu: inconsistent \"endsolid\" name.\n",
- streamer.name, (unsigned long)streamer.iline);
- }
- sa_release(name);
- }
- if(sstl->verbose) {
- int tmp, non_space = 0;
- size_t i = 0;
- while (EOF != (tmp = fgetc(stream))) {
- i++;
- if(!isspace(tmp)) non_space = 1;
- }
- if(non_space) {
- print_log(sstl, LOG_WARNING,
- "%s: %u unexpected trailing characters.\n",
- stream_name, i);
- }
- }
-
- /* Register the solid */
- solid.read_type |= OK_ASCII;
- sstl->solid = solid;
+ /* Register the vertex index */
+ sa_push(sstl->indices, id);
exit:
- streamer_release(&streamer);
return res;
error:
- solid_clear(&solid);
goto exit;
}
-static res_T
-load_binary_stream
- (struct sstl* sstl,
- FILE* stream,
- const char* stream_name,
- const size_t already_read_count)
-{
- res_T res = RES_OK;
- char header[80];
- unsigned triangles_count;
- struct solid solid = SOLID_NULL;
- unsigned i;
-
- ASSERT(sstl && stream && stream_name && already_read_count <= 80);
- clear(sstl);
-
- /* Read header; the first 80 bytes are meaningless and can be safely
- * (partially) dropped */
- if(1 != fread(header+already_read_count, sizeof(header)-already_read_count, 1,
- stream))
- {
- print_log(sstl, LOG_ERROR, "%s: missing header.\n", stream_name);
- res = RES_BAD_ARG;
- goto error;
- }
-
- solid.read_type |= STARTED_BIN;
-
- if(1 != fread(&triangles_count, 4, 1, stream)) {
- print_log(sstl, LOG_ERROR, "%s: missing triangle count.\n", stream_name);
- res = RES_BAD_ARG;
- goto error;
- }
- for(i = 0; i < triangles_count; i++) {
- struct tmp tmp;
- int n;
- if(1 != fread(&tmp, 50, 1, stream)) {
- print_log(sstl, LOG_ERROR, "%s: missing triangle data.\n", stream_name);
- res = RES_BAD_ARG;
- goto error;
- }
-
- f3_set(sa_add(solid.normals, 3), tmp.normal);
- for(n = 0; n < 3; n++) {
- /* Look for an already registered vertex position */
- unsigned* found_id = htable_vertex_find(&sstl->vertex2id, &tmp.u.vtx[n]);
- unsigned index;
-
- if(found_id) {
- index = *found_id;
- } else {
- /* Add a new vertex */
- index = (unsigned)sa_size(solid.vertices) / 3;
- res = htable_vertex_set(&sstl->vertex2id, &tmp.u.vtx[n], &index);
- if(res != RES_OK) {
- print_log(sstl, LOG_ERROR,
- "%s:%u: couldn't register a vertex position.\n",
- stream_name, i);
- }
- f3_set(sa_add(solid.vertices, 3), tmp.u.vtx[n].xyz);
- }
- sa_push(solid.indices, index);
- }
- }
- if(sstl->verbose) {
- i = 0;
- while (1 == fread(header, 1, 1, stream)) i++;
- if(i) {
- print_log(sstl, LOG_WARNING,
- "%s: %u unexpected trailing bytes.\n",
- stream_name, i);
- }
- }
-
- /* Register the solid */
- solid.read_type |= OK_BINARY;
- sstl->solid = solid;
-
-exit:
- return res;
-error:
- solid_clear(&solid);
- goto exit;
-}
-
-static res_T
-load_stream
- (struct sstl* sstl,
- FILE* stream,
- const char* stream_name,
- int allowed)
-{
- res_T res = RES_OK;
- int log = (allowed == TRY_READ_ALL);
- size_t count = 0;
-
- ASSERT(sstl && stream && allowed);
-
- /* Try reading as an ASCII file; if the file doesn't start with "solid" the
- * file is not read past the first 5 characters, so that we can continue
- * reading as a binary file, exploiting the fact that binary files' first 80
- * characters are meaningless */
- if(allowed & TRY_READ_ASCII) {
- if(log) {
- print_log(sstl, LOG_OUTPUT,
- "%s: attempt to read as ASCII file.\n", stream_name);
- }
- res = load_ascii_stream(sstl, stream, stream_name, allowed, &count);
- if(res == RES_OK) {
- if(log) print_log(sstl, LOG_OUTPUT, "Attempt successful.\n");
- goto exit;
- }
- }
- /* If here the stream could not be read as ASCII */
- if(!(allowed & TRY_READ_BINARY)) goto exit;
- if(sstl->solid.read_type & STARTED_ASCII) {
- /* "solid" was found: was an ill-formed ASCII file */
- return res;
- }
- if(count > 80) {
- /* Don't know if can happen, but further code cannot handle this */
- print_log(sstl, LOG_ERROR,
- "%s: cannot attempt to read as binary file"
- " (too many bytes read while trying ascii read).\n",
- stream_name);
- res = RES_BAD_ARG;
- goto error;
- }
- if(log) {
- print_log(sstl, LOG_OUTPUT,
- "%s: attempt to read as binary file.\n", stream_name);
- }
- res = load_binary_stream(sstl, stream, stream_name, count);
- if(res != RES_OK) goto error;
- if(log) print_log(sstl, LOG_OUTPUT, "Attempt successful.\n");
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-#undef FTELL
-
-static res_T
-load_base(struct sstl* sstl, const char* filename, int allowed)
-{
- FILE* file;
- res_T res = RES_OK;
-
- 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, allowed);
- fclose(file);
- return res;
-}
-
-static res_T
-get_sstl_triangle_normal
- (const unsigned idx,
- const void* data,
- float normal[3])
-{
- res_T res = RES_OK;
- struct sstl* sstl = (struct sstl*)data;
- struct sstl_desc desc;
-
- if(!sstl || !normal) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- OK(sstl_get_desc(sstl, &desc));
- if(idx >= desc.triangles_count) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- ASSERT(3*idx+2 < sa_size(desc.normals));
- f3_set(normal, desc.normals + 3*idx);
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-get_sstl_triangle_vertices
- (const unsigned idx,
- const void* data,
- float vtx[3][3])
-{
- res_T res = RES_OK;
- struct sstl* sstl = (struct sstl*)data;
- struct sstl_desc desc;
- unsigned n;
-
- if(!sstl || !vtx) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- OK(sstl_get_desc(sstl, &desc));
- if(idx >= desc.triangles_count) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- for(n = 0; n < 3; n++) {
- size_t vtx_idx = desc.indices[3*idx + n];
- ASSERT(3*vtx_idx+2 < sa_size(desc.vertices));
- f3_set(vtx[n], desc.vertices + 3*vtx_idx);
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static void
-print_sstl_error_log
- (const void* data,
- const char* msg,
- ...)
-{
- const struct sstl_write_data* sstld = (struct sstl_write_data*)data;
- va_list vargs_list;
- va_start(vargs_list, msg);
- print_log(sstld->data, LOG_ERROR, msg, vargs_list);
- va_end(vargs_list);
-}
-
-res_T
-sstl_pack_write_data
- (const struct sstl* sstl,
- struct sstl_write_data* out)
-{
- size_t sz;
- if(!sstl || !out) return RES_BAD_ARG;
- if(!sstl->solid.indices || !sstl->solid.normals || !sstl->solid.vertices)
- return RES_BAD_ARG;
- sz = sa_size(sstl->solid.indices);
- if(sz % 3 != 0) return RES_BAD_ARG;
- sz /= 3;
- if(sz > UINT_MAX) return RES_BAD_ARG;
- out->name = sstl->solid.name;
- out->data = sstl;
- out->get_triangle_normal = get_sstl_triangle_normal;
- out->get_triangle_vertices = get_sstl_triangle_vertices;
- out->print_error_log = print_sstl_error_log;
- out->triangles_count = (unsigned)sz;
- return RES_OK;
-}
-
-#define OKP(Expr) if((Expr) < 0) { res=RES_IO_ERR; goto error; }
-
-static res_T
-write_stream
- (const struct sstl_write_data* data,
- FILE* stream,
- const char* stream_name,
- const int binary)
-{
- res_T res = RES_OK;
- unsigned i;
-
- ASSERT(data && stream && stream_name);
-
- if(data->get_triangle_normal == NULL) {
- if(data->print_error_log) {
- data->print_error_log(data,
- "%s: no getter defined for triangles' normals.\n", stream_name);
- }
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(data->get_triangle_vertices == NULL) {
- if(data->print_error_log) {
- data->print_error_log(data,
- "%s: no getter defined for triangles' vertices.\n", stream_name);
- }
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(binary) {
- char header[80] = "Binary STL written by the star-stl library";
- if(1 != fwrite(header, sizeof(header), 1, stream)) {
- res = RES_IO_ERR;
- goto error;
- }
- ASSERT(sizeof(data->triangles_count == 4));
- if(1 != fwrite(&data->triangles_count, 4, 1, stream)) {
- res = RES_IO_ERR;
- goto error;
- }
- for(i = 0; i < data->triangles_count; i++) {
- struct tmp tmp;
- res = data->get_triangle_normal(i, data->data, tmp.normal);
- res = data->get_triangle_vertices(i, data->data, tmp.u.vertices);
- tmp.attrib = 0;
- if(1 != fwrite(&tmp, 50, 1, stream)) {
- res = RES_IO_ERR;
- goto error;
- }
- }
- } else {
- if(data->name) {
- OKP(fprintf(stream, "solid %s\n", data->name));
- } else {
- OKP(fprintf(stream, "solid \n"));
- }
- for(i = 0; i < data->triangles_count; i++) {
- float normal[3], vtx[3][3];
- int n;
-
- res = data->get_triangle_normal(i, data->data, normal);
- OKP(fprintf(stream, " facet normal %g %g %g\n", SPLIT3(normal)));
-
- res = data->get_triangle_vertices(i, data->data, vtx);
- OKP(fprintf(stream, " outer loop\n"));
- for(n = 0; n < 3; n++) {
- OKP(fprintf(stream, " vertex %.16g %.16g %.16g\n", SPLIT3(vtx[n])));
- }
- OKP(fprintf(stream, " endloop\n"));
- OKP(fprintf(stream, " endfacet\n"));
- }
- OKP(fprintf(stream, "endsolid \n"));
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-#undef OKP
-
-static void
-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);
-}
-
/*******************************************************************************
* Exported functions
******************************************************************************/
@@ -972,6 +130,7 @@ sstl_create
sstl->logger = logger;
sstl->verbose = verbose;
htable_vertex_init(allocator, &sstl->vertex2id);
+ str_init(allocator, &sstl->name);
exit:
if(out_sstl) *out_sstl = sstl;
@@ -998,107 +157,58 @@ sstl_ref_put(struct sstl* sstl)
if(!sstl) return RES_BAD_ARG;
ref_put(&sstl->ref, sstl_release);
return RES_OK;
-
}
res_T
-sstl_load_ascii(struct sstl* sstl, const char* filename)
+sstl_load(struct sstl* sstl, const char* filename)
{
- if(!sstl || !filename) return RES_BAD_ARG;
- return load_base(sstl, filename, TRY_READ_ASCII);
-}
+ FILE* stream = NULL;
+ res_T res = RES_OK;
-res_T
-sstl_load_binary(struct sstl* sstl, const char* filename)
-{
- if(!sstl || !filename) return RES_BAD_ARG;
- return load_base(sstl, filename, TRY_READ_BINARY);
-}
+ if(!sstl || !filename) { res = RES_BAD_ARG; goto error; }
-res_T
-sstl_load(struct sstl* sstl, const char* filename)
-{
- if(!sstl || !filename) return RES_BAD_ARG;
- return load_base(sstl, filename, TRY_READ_ALL);
-}
+ stream = fopen(filename, "r");
+ if(!stream) {
+ ERROR(sstl, "Error opening file %s -- %s\n", filename, strerror(errno));
+ res = RES_IO_ERR;
+ goto error;
+ }
-res_T
-sstl_load_stream_ascii(struct sstl* sstl, FILE* stream)
-{
- if(!sstl || !stream) return RES_BAD_ARG;
- return load_stream(sstl, stream, "STREAM", TRY_READ_ASCII);
-}
+ res = load_stream_ascii(sstl, stream, filename);
+ if(res != RES_OK) goto error;
-res_T
-sstl_load_stream_binary(struct sstl* sstl, FILE* stream)
-{
- if(!sstl || !stream) return RES_BAD_ARG;
- return load_stream(sstl, stream, "STREAM", TRY_READ_BINARY);
+exit:
+ if(stream) CHK(fclose(stream) == 0);
+ return res;
+error:
+ goto exit;
}
res_T
-sstl_load_stream(struct sstl* sstl, FILE* stream)
+sstl_load_stream
+ (struct sstl* sstl,
+ FILE* stream,
+ const char* stream_name)
{
- if(!sstl || !stream) return RES_BAD_ARG;
- return load_stream(sstl, stream, "STREAM", TRY_READ_ALL);
+ if(!sstl || !stream || !stream_name) return RES_BAD_ARG;
+ return load_stream_ascii(sstl, stream, stream_name);
}
res_T
sstl_get_desc(struct sstl* sstl, struct sstl_desc* desc)
{
- if(!sstl || !desc
- /* OK_ASCII xor OK_BIN */
- || (sstl->solid.read_type & OK_BINARY) == (sstl->solid.read_type & OK_ASCII))
- return RES_BAD_ARG;
- desc->solid_name = sstl->solid.name;
- desc->read_type = (sstl->solid.read_type & OK_ASCII) ? SSTL_ASCII : SSTL_BINARY;
- desc->vertices_count = sa_size(sstl->solid.vertices);
- ASSERT(desc->vertices_count % 3 == 0);
- desc->vertices_count /= 3/* # coords per vertex */;
- desc->triangles_count = sa_size(sstl->solid.indices);
- ASSERT(desc->triangles_count % 3 == 0);
- desc->triangles_count /= 3/* # indices per triange */;
- desc->vertices = sstl->solid.vertices;
- desc->indices = sstl->solid.indices;
- desc->normals = sstl->solid.normals;
- return RES_OK;
-}
-
-res_T
-sstl_write
- (const struct sstl_write_data* data,
- const int binary,
- const char* filename)
-{
- FILE* file;
- res_T res = RES_OK;
+ if(!sstl || !desc) return RES_BAD_ARG;
- if(!data || !filename)
- return RES_BAD_ARG;
+ ASSERT(sa_size(sstl->vertices) % 3 == 0);
+ ASSERT(sa_size(sstl->normals) % 3 == 0);
+ ASSERT(sa_size(sstl->indices) % 3 == 0);
- file = fopen(filename, (binary ? "wb" : "w"));
- if(!file) {
- if(data->print_error_log) {
- data->print_error_log(data, "Error opening `%s'.\n", filename);
- }
- return RES_IO_ERR;
- }
- res = write_stream(data, file, filename, binary);
- fclose(file);
- return res;
-}
-
-res_T
-sstl_write_stream
- (const struct sstl_write_data* data,
- const int binary,
- FILE* stream)
-{
- if(!data || !stream) return RES_BAD_ARG;
- return write_stream(data, stream, "STREAM", binary);
+ desc->solid_name = str_len(&sstl->name) ? str_cget(&sstl->name) : NULL;
+ desc->vertices_count = sa_size(sstl->vertices) / 3/*#coords*/;
+ desc->triangles_count = sa_size(sstl->indices) / 3/*#ids*/;
+ desc->vertices = sstl->vertices;
+ desc->indices = sstl->indices;
+ desc->normals = sstl->normals;
+ desc->read_type = SSTL_ASCII;
+ return RES_OK;
}
-
-#ifdef COMPILER_CL
- #pragma warning(pop)
-#endif
-
diff --git a/src/sstl.h b/src/sstl.h
@@ -48,32 +48,14 @@ struct sstl_desc {
enum sstl_read_type read_type; /* The type of the file */
/* Front faces are CCW ordered and the normals follow the right handed rule */
- float* vertices; /* triangles_count * 3 coordinates */
- unsigned* indices; /* triangles_count * 3 indices */
- float* normals; /* Per triangle normalized normal */
+ const float* vertices; /* triangles_count * 3 coordinates */
+ const unsigned* indices; /* triangles_count * 3 indices */
+ const float* normals; /* Per triangle normalized normal */
size_t triangles_count;
size_t vertices_count;
};
-/* Data descriptor used to write a bunch of triangles to a file in the STL
- * format.
- * - name can be NULL,
- * - print_error_log can be NULL: no log,
- * - data can be NULL if get_triangle_xxx functions do not use it. */
-struct sstl_write_data {
- const char* name;
- const void* data;
- res_T (*get_triangle_vertices)
- (const unsigned idx, const void* data, float vtx[3][3]);
- res_T (*get_triangle_normal)
- (const unsigned idx, const void* data, float normal[3]);
- void (*print_error_log)(const void* data, const char* msg, ...);
- unsigned triangles_count;
-};
-#define SSTL_WRITE_DATA_NULL__ { NULL, NULL, NULL, NULL, NULL, 0 }
-static const struct sstl_write_data SSTL_WRITE_DATA_NULL = SSTL_WRITE_DATA_NULL__;
-
/* Forward declaration of external types */
struct logger;
struct mem_allocator;
@@ -101,26 +83,6 @@ SSTL_API res_T
sstl_ref_put
(struct sstl* sstl);
-SSTL_API res_T
-sstl_load_ascii
- (struct sstl* sstl,
- const char* filename);
-
-SSTL_API res_T
-sstl_load_stream_ascii
- (struct sstl* sstl,
- FILE* stream);
-
-SSTL_API res_T
-sstl_load_binary
- (struct sstl* sstl,
- const char* filename);
-
-SSTL_API res_T
-sstl_load_stream_binary
- (struct sstl* sstl,
- FILE* stream);
-
/* Try first loading as an ASCII file, then as a binary file if ASCII failed.
* Note that a binary file starting with "solid" will be wrongly identified as
* ASCII, thus leading to a failure without trying a binary load.
@@ -137,26 +99,8 @@ sstl_load
SSTL_API res_T
sstl_load_stream
(struct sstl* sstl,
- FILE* stream);
-
-/* Create a sstl_write_data from a sstl.
- * The result is valid as long as the input sstl is valid */
-SSTL_API res_T
-sstl_pack_write_data
- (const struct sstl* sstl,
- struct sstl_write_data* out);
-
-SSTL_API res_T
-sstl_write
- (const struct sstl_write_data* data,
- const int binary,
- const char* filename);
-
-SSTL_API res_T
-sstl_write_stream
- (const struct sstl_write_data* data,
- const int binary,
- FILE* stream);
+ FILE* stream,
+ const char* stream_name);
/* The returned descriptor is valid until a new load process */
SSTL_API res_T
diff --git a/src/sstl_ascii.c b/src/sstl_ascii.c
@@ -0,0 +1,303 @@
+/* Copyright (C) 2015, 2016, 2019, 2021, 2023 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#define _POSIX_C_SOURCE 200112L /* strtok_r support */
+
+#include "sstl_c.h"
+
+#include <rsys/cstr.h>
+#include <rsys/float3.h>
+#include <rsys/hash_table.h>
+#include <rsys/text_reader.h>
+
+#include <string.h>
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static res_T
+parse_float3
+ (struct sstl* sstl,
+ const struct txtrdr* txtrdr,
+ char* str,
+ char** ctx,
+ float vec[3])
+{
+ char* x = NULL;
+ char* y = NULL;
+ char* z = NULL;
+ res_T res = RES_OK;
+ ASSERT(sstl && txtrdr && vec);
+
+ if(!(x = strtok_r(str, " \t", ctx))
+ || !(y = strtok_r(NULL, " \t", ctx))
+ || !(z = strtok_r(NULL, " \t", ctx))) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if((res = cstr_to_float(x, vec+0)) != RES_OK) goto error;
+ if((res = cstr_to_float(y, vec+1)) != RES_OK) goto error;
+ if((res = cstr_to_float(z, vec+2)) != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ ERROR(sstl, "%s:%lu: invalid vector component\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ goto exit;
+}
+
+static res_T
+parse_word
+ (struct sstl* sstl,
+ const struct txtrdr* txtrdr,
+ const char* word,
+ char* str,
+ char** ctx)
+{
+ char* tk = NULL;
+ ASSERT(sstl && txtrdr && ctx);
+
+ tk = strtok_r(str, " \t", ctx);
+ if(!tk || strcmp(tk, word) != 0) {
+ ERROR(sstl, "%s:%lu: expect the \"%s\" keyword\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ word);
+ return RES_BAD_ARG;
+ }
+
+ return RES_OK;
+}
+
+static INLINE res_T
+parse_nothing
+ (struct sstl* sstl,
+ const struct txtrdr* txtrdr,
+ char* str,
+ char** ctx)
+{
+ char* tk = NULL;
+
+ ASSERT(txtrdr && ctx);
+ (void)sstl; /* Avoid "unused variable" warning */
+
+ tk = strtok_r(str, " \t", ctx);
+ if(tk != NULL) {
+ WARN(sstl, "%s:%lu: unexpected text \"%s\"\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ }
+ return RES_OK;
+}
+
+static res_T
+parse_vec3
+ (struct sstl* sstl,
+ struct txtrdr* txtrdr,
+ const char* name,
+ char* str,
+ char** ctx,
+ float vec[3])
+{
+ res_T res = RES_BAD_ARG;
+ ASSERT(sstl && txtrdr && name && ctx);
+
+ if((res = parse_word(sstl, txtrdr, name, str, ctx)) != RES_OK) goto error;
+ if((res = parse_float3(sstl, txtrdr, NULL, ctx, vec)) != RES_OK) goto error;
+ if((res = parse_nothing(sstl, txtrdr, NULL, ctx)) != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_facet(struct sstl* sstl, struct txtrdr* txtrdr, char* normal)
+{
+ float v[3][3] = {0};
+ float* N = NULL;
+ char* line = NULL;
+ char* ctx = NULL;
+ int i = 0;
+ res_T res = RES_OK;
+ ASSERT(sstl && txtrdr && normal);
+
+ N = sa_add(sstl->normals, 3);
+ if((res = parse_vec3(sstl, txtrdr, "normal", normal, &ctx, N)) != RES_OK) goto error;
+
+ #define READ_LINE { \
+ if((res = txtrdr_read_line(txtrdr)) != RES_OK) { \
+ ERROR(sstl, "%s: error reading line -- %s\n", \
+ txtrdr_get_name(txtrdr), res_to_cstr(res)); \
+ goto error; \
+ } \
+ if(!(line = txtrdr_get_line(txtrdr))) { \
+ ERROR(sstl, "%s: unexpected end of file\n", txtrdr_get_name(txtrdr)); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } \
+ } (void)0
+
+ READ_LINE;
+ if((res = parse_word(sstl, txtrdr, "outer", line, &ctx)) != RES_OK) goto error;
+ if((res = parse_word(sstl, txtrdr, "loop", NULL, &ctx)) != RES_OK) goto error;
+ if((res = parse_nothing(sstl, txtrdr, NULL, &ctx)) != RES_OK) goto error;
+
+ FOR_EACH(i, 0, 3) {
+ READ_LINE;
+ res = parse_vec3(sstl, txtrdr, "vertex", line, &ctx, v[i]);
+ if(res != RES_OK) goto error;
+
+ res = register_vertex(sstl, v[i]);
+ if(res != RES_OK) {
+ ERROR(sstl, "%s:%lu: vertex registration error -- %s\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+ }
+
+ READ_LINE;
+ if((res = parse_word(sstl, txtrdr, "endloop", line, &ctx)) != RES_OK) goto error;
+ if((res = parse_nothing(sstl, txtrdr, NULL, &ctx)) != RES_OK) goto error;
+
+ READ_LINE;
+ if((res = parse_word(sstl, txtrdr, "endfacet", line, &ctx)) != RES_OK) goto error;
+ if((res = parse_nothing(sstl, txtrdr, NULL, &ctx)) != RES_OK) goto error;
+
+ #undef READ_LINE
+
+ if(!f3_is_normalized(N)) {
+ /* If necessary, automatically calculate the surface normal.
+ * Vertices are CCW and the normal follows the right handed rule */
+ float E0[3], E1[3];
+ f3_sub(E0, v[1], v[0]);
+ f3_sub(E1, v[2], v[0]);
+ f3_cross(N, E0, E1);
+ f3_normalize(N, N);
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_solid(struct sstl* sstl, struct txtrdr* txtrdr)
+{
+ char* line = NULL;
+ char* tk = NULL;
+ char* tk_ctx = NULL;
+ res_T res = RES_OK;
+ ASSERT(sstl && txtrdr);
+
+ line = txtrdr_get_line(txtrdr);
+ ASSERT(line != NULL);
+
+ tk = strtok_r(line, " \t", &tk_ctx);
+ ASSERT(tk);
+ if(strcmp(tk, "solid")) {
+ ERROR(sstl, "%s:%lu: the \"solid [name]\" directive is missing\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(NULL, "", &tk_ctx);
+ if(tk != NULL && (res = str_set(&sstl->name, tk)) != RES_OK) {
+ ERROR(sstl, "%s:%lu: error duplicating solid name -- %s\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ for(;;) {
+ if((res = txtrdr_read_line(txtrdr)) != RES_OK) {
+ ERROR(sstl, "%s: error reading line -- %s\n",
+ str_cget(&sstl->name), res_to_cstr(res));
+ goto error;
+ }
+
+ if((line = txtrdr_get_line(txtrdr)) == NULL) {
+ ERROR(sstl, "%s: the \"endsolid [name]\" directive is missing\n",
+ txtrdr_get_name(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(line, " \t", &tk_ctx);
+
+ if(!strcmp(tk, "facet")) {
+ res = parse_facet(sstl, txtrdr, strtok_r(NULL, "", &tk_ctx));
+ if(res != RES_OK) goto error;
+
+ } else if(!strcmp(tk, "endsolid")) {
+ break; /* Stop on "endsolid" directive */
+
+ } else {
+ ERROR(sstl, "%s:%lu: invalid directive \"%s\"\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+load_stream_ascii
+ (struct sstl* sstl,
+ FILE* stream,
+ const char* stream_name)
+{
+ struct txtrdr* txtrdr = NULL;
+ res_T res = RES_OK;
+
+ ASSERT(sstl && stream && stream_name);
+
+ clear(sstl);
+
+ res = txtrdr_stream(sstl->allocator, stream, stream_name, '#', &txtrdr);
+ if(res != RES_OK) {
+ ERROR(sstl, "%s: error creating text reader -- %s\n",
+ stream_name, res_to_cstr(res));
+ goto error;
+ }
+
+ if((res = txtrdr_read_line(txtrdr)) != RES_OK) {
+ ERROR(sstl, "%s: error reading line -- %s\n", stream_name, res_to_cstr(res));
+ goto error;
+ }
+
+ if(txtrdr_get_cline(txtrdr) != NULL) { /* File is not empty */
+ if((res = parse_solid(sstl, txtrdr)) != RES_OK) goto error;
+ }
+
+exit:
+ htable_vertex_purge(&sstl->vertex2id); /* Purge the helper structure */
+ if(txtrdr) txtrdr_ref_put(txtrdr);
+ return res;
+error:
+ clear(sstl);
+ goto exit;
+}
diff --git a/src/sstl_c.h b/src/sstl_c.h
@@ -0,0 +1,97 @@
+/* Copyright (C) 2015, 2016, 2019, 2021, 2023 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SSTL_C_H
+#define SSTL_C_H
+
+#include <rsys/hash_table.h>
+#include <rsys/logger.h>
+#include <rsys/ref_count.h>
+#include <rsys/str.h>
+#include <rsys/stretchy_array.h>
+
+/* Helper macros for logging */
+#define LOG__(Dev, Lvl, Type, ...) { \
+ if ((Dev)->verbose >= (Lvl)) \
+ logger_print((Dev)->logger, Type, __VA_ARGS__); \
+} (void)0
+#define ERROR(Dev, ...) LOG__(Dev, 1, LOG_ERROR, "error: "__VA_ARGS__)
+#define WARN(Dev, ...) LOG__(Dev, 2, LOG_WARNING, "warning: "__VA_ARGS__)
+#define INFO(Dev, ...) LOG__(Dev, 3, LOG_OUTPUT, __VA_ARGS__)
+
+struct vertex { float xyz[3]; };
+
+static INLINE char
+eq_vertex(const struct vertex* a, const struct vertex* b)
+{
+ return (char)
+ a->xyz[0] == b->xyz[0]
+ && a->xyz[1] == b->xyz[1]
+ && a->xyz[2] == b->xyz[2];
+}
+
+/* Declare the hash table that map a vertex to its index */
+#define HTABLE_NAME vertex
+#define HTABLE_DATA unsigned
+#define HTABLE_KEY struct vertex
+#define HTABLE_KEY_FUNCTOR_EQ eq_vertex
+#include <rsys/hash_table.h>
+
+/* Forward declarations */
+struct logger;
+struct mem_allocator;
+
+struct sstl {
+ int verbose;
+ struct str name;
+
+ /* Temporary structure used to map a vertex to its id */
+ struct htable_vertex vertex2id;
+
+ float* normals;
+ float* vertices;
+ unsigned* indices;
+
+ struct logger* logger;
+ struct mem_allocator* allocator;
+ ref_T ref;
+};
+
+static INLINE void
+clear(struct sstl* sstl)
+{
+ ASSERT(sstl);
+ str_clear(&sstl->name);
+ sa_release(sstl->indices);
+ sa_release(sstl->vertices);
+ sa_release(sstl->normals);
+ sstl->indices = NULL;
+ sstl->vertices = NULL;
+ sstl->normals = NULL;
+ htable_vertex_clear(&sstl->vertex2id);
+}
+
+extern LOCAL_SYM res_T
+load_stream_ascii
+ (struct sstl* sstl,
+ FILE* stream,
+ const char* stream_name);
+
+extern LOCAL_SYM res_T
+register_vertex
+ (struct sstl* sstl,
+ const float v[3]);
+
+#endif /* SSTL_C_H */
diff --git a/src/test_sstl_load.c b/src/test_sstl_load.c
@@ -129,7 +129,6 @@ test_basic(struct sstl* sstl)
struct sstl_desc desc;
FILE* file;
size_t i;
- struct sstl_write_data wd;
CHK(sstl != NULL);
@@ -138,18 +137,6 @@ test_basic(struct sstl* sstl)
fwrite(test0, sizeof(char), strlen(test0), file);
fclose(file);
- CHK(sstl_load_ascii(NULL, NULL) == RES_BAD_ARG);
- CHK(sstl_load_ascii(sstl, NULL) == RES_BAD_ARG);
- CHK(sstl_load_ascii(NULL, "test_basic.stl") == RES_BAD_ARG);
- CHK(sstl_load_ascii(sstl, "none.stl") == RES_IO_ERR);
- CHK(sstl_load_ascii(sstl, "test_basic.stl") == RES_OK);
-
- CHK(sstl_load_binary(NULL, NULL) == RES_BAD_ARG);
- CHK(sstl_load_binary(sstl, NULL) == RES_BAD_ARG);
- CHK(sstl_load_binary(NULL, "test_basic.stl") == RES_BAD_ARG);
- CHK(sstl_load_binary(sstl, "none.stl") == RES_IO_ERR);
- CHK(sstl_load_binary(sstl, "test_basic.stl") == RES_BAD_ARG);
-
CHK(sstl_load(NULL, NULL) == RES_BAD_ARG);
CHK(sstl_load(sstl, NULL) == RES_BAD_ARG);
CHK(sstl_load(NULL, "test_basic.stl") == RES_BAD_ARG);
@@ -175,59 +162,16 @@ test_basic(struct sstl* sstl)
file = tmpfile();
CHK(file != NULL);
fwrite(test1, sizeof(char), strlen(test1), file);
-
- rewind(file);
- CHK(sstl_load_stream_ascii(NULL, NULL) == RES_BAD_ARG);
- CHK(sstl_load_stream_ascii(sstl, NULL) == RES_BAD_ARG);
- CHK(sstl_load_stream_ascii(NULL, file) == RES_BAD_ARG);
- CHK(sstl_load_stream_ascii(sstl, file) == RES_OK);
-
- rewind(file);
- CHK(sstl_load_stream_binary(NULL, NULL) == RES_BAD_ARG);
- CHK(sstl_load_stream_binary(sstl, NULL) == RES_BAD_ARG);
- CHK(sstl_load_stream_binary(NULL, file) == RES_BAD_ARG);
- CHK(sstl_load_stream_binary(sstl, file) == RES_BAD_ARG);
-
- rewind(file);
- CHK(sstl_load_stream(NULL, NULL) == RES_BAD_ARG);
- CHK(sstl_load_stream(sstl, NULL) == RES_BAD_ARG);
- CHK(sstl_load_stream(NULL, file) == RES_BAD_ARG);
- CHK(sstl_load_stream_ascii(sstl, file) == RES_OK);
- fclose(file);
-
- CHK(sstl_pack_write_data(NULL, &wd) == RES_BAD_ARG);
- CHK(sstl_pack_write_data(sstl, NULL) == RES_BAD_ARG);
- CHK(sstl_pack_write_data(NULL, NULL) == RES_BAD_ARG);
- CHK(sstl_pack_write_data(sstl, &wd) == RES_OK);
- CHK(sstl_write(&wd, 1, "test_basic.stl") == RES_OK);
- CHK(sstl_load_binary(sstl, "test_basic.stl") == RES_OK);
-
- CHK(sstl_pack_write_data(sstl, &wd) == RES_OK);
- wd.data = NULL;
- CHK(sstl_write(&wd, 1, "test_basic.stl") == RES_BAD_ARG);
-
- CHK(sstl_pack_write_data(sstl, &wd) == RES_OK);
- wd.get_triangle_normal = NULL;
- CHK(sstl_write(&wd, 1, "test_basic.stl") == RES_BAD_ARG);
-
- CHK(sstl_pack_write_data(sstl, &wd) == RES_OK);
- wd.get_triangle_vertices = NULL;
- CHK(sstl_write(&wd, 1, "test_basic.stl") == RES_BAD_ARG);
-
- CHK(sstl_pack_write_data(sstl, &wd) == RES_OK);
- wd.triangles_count += 1;
- CHK(sstl_write(&wd, 1, "test_basic.stl") == RES_BAD_ARG);
-
- file = tmpfile();
- CHK(file != NULL);
- CHK(sstl_pack_write_data(sstl, &wd) == RES_OK);
- CHK(sstl_write_stream(&wd, 1, file) == RES_OK);
rewind(file);
- CHK(sstl_load_stream_binary(sstl,file) == RES_OK);
+ CHK(sstl_load_stream(NULL, NULL, "stream") == RES_BAD_ARG);
+ CHK(sstl_load_stream(sstl, NULL, "stream") == RES_BAD_ARG);
+ CHK(sstl_load_stream(NULL, file, "stream") == RES_BAD_ARG);
+ CHK(sstl_load_stream(sstl, file, NULL) == RES_BAD_ARG);
+ CHK(sstl_load_stream(sstl, file, "stream") == RES_OK);
fclose(file);
CHK(sstl_get_desc(sstl, &desc) == RES_OK);
- CHK(desc.solid_name == NULL);
+ CHK(strcmp(desc.solid_name, "my_solid") == 0);
CHK(desc.vertices_count == 3);
CHK(desc.triangles_count == 1);
CHK(desc.indices[0] == 0);
@@ -241,7 +185,7 @@ test_basic(struct sstl* sstl)
file = tmpfile();
fwrite(test2, sizeof(char), strlen(test2), file);
rewind(file);
- CHK(sstl_load_stream(sstl, file) == RES_OK);
+ CHK(sstl_load_stream(sstl, file, "stream") == RES_OK);
fclose(file);
CHK(sstl_get_desc(sstl, &desc) == RES_OK);
@@ -252,70 +196,21 @@ test_basic(struct sstl* sstl)
file = tmpfile();
fwrite(test3, sizeof(char), strlen(test3), file);
rewind(file);
- CHK(sstl_load_stream_binary(sstl, file) == RES_BAD_ARG);
+ CHK(sstl_load_stream(sstl, file, "stream") == RES_OK);
fclose(file);
+ CHK(sstl_get_desc(sstl, &desc) == RES_OK);
+ CHK(desc.vertices_count == 3);
+ CHK(desc.triangles_count == 1);
+ CHK(f3_eq(desc.normals, f3(tmp, 0.f, -1.f, 0.f)) == 1);
+
FOR_EACH(i, 0, nbads) {
file = tmpfile();
fwrite(bad[i], sizeof(char), strlen(bad[i]), file);
rewind(file);
- CHK(sstl_load_stream(sstl, file) == RES_BAD_ARG);
+ CHK(sstl_load_stream(sstl, file, "stream") == RES_BAD_ARG);
fclose(file);
}
-
- CHK(sstl_pack_write_data(NULL, NULL) == RES_BAD_ARG);
- CHK(sstl_pack_write_data(sstl, NULL) == RES_BAD_ARG);
- CHK(sstl_pack_write_data(NULL, &wd) == RES_BAD_ARG);
-
- CHK(sstl_write(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(sstl_write(&wd, 0, NULL) == RES_BAD_ARG);
- CHK(sstl_write(NULL, 0, "test_basic.stl") == RES_BAD_ARG);
- CHK(sstl_write(&wd, 0, "") == RES_IO_ERR);
- CHK(sstl_write(&wd, 1, "") == RES_IO_ERR);
-
- file = fopen("test_basic.stl", "w");
- CHK(file != NULL);
- fwrite(test0, sizeof(char), strlen(test0), file);
- fclose(file);
-
- CHK(sstl_load_ascii(sstl, "test_basic.stl") == RES_OK);
- CHK(sstl_pack_write_data(sstl, &wd) == RES_OK);
- CHK(sstl_write(&wd, 0, "test_basic.stl") == RES_OK);
- CHK(sstl_load(sstl, "test_basic.stl") == RES_OK);
- CHK(sstl_get_desc(sstl, &desc) == RES_OK);
-
- CHK(desc.solid_name == NULL);
- CHK(desc.vertices_count == 3);
- CHK(desc.triangles_count == 1);
- CHK(desc.indices[0] == 0);
- CHK(desc.indices[1] == 1);
- CHK(desc.indices[2] == 2);
- CHK(f3_eq(desc.vertices + 0*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + 1*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + 2*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.normals, f3(tmp, 0.f, -1.f, 0.f)) == 1);
-
- file = fopen("test_basic.stl", "w");
- CHK(file != NULL);
- fwrite(test0, sizeof(char), strlen(test0), file);
- fclose(file);
-
- CHK(sstl_load(sstl, "test_basic.stl") == RES_OK);
- CHK(sstl_pack_write_data(sstl, &wd) == RES_OK);
- CHK(sstl_write(&wd, 1, "test_basic2.stl") == RES_OK);
- CHK(sstl_load(sstl, "test_basic2.stl") == RES_OK);
- CHK(sstl_get_desc(sstl, &desc) == RES_OK);
-
- CHK(desc.solid_name == NULL);
- CHK(desc.vertices_count == 3);
- CHK(desc.triangles_count == 1);
- CHK(desc.indices[0] == 0);
- CHK(desc.indices[1] == 1);
- CHK(desc.indices[2] == 2);
- CHK(f3_eq(desc.vertices + 0*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + 1*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + 2*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.normals, f3(tmp, 0.f, -1.f, 0.f)) == 1);
}
static void
@@ -358,7 +253,6 @@ test_tetrahedron(struct sstl* sstl)
struct sstl_desc desc;
float tmp[3];
size_t i;
- struct sstl_write_data wd;
CHK(sstl != NULL);
@@ -368,36 +262,8 @@ test_tetrahedron(struct sstl* sstl)
fwrite(tetrahedron[i], sizeof(char), strlen(tetrahedron[i]), file);
rewind(file);
- CHK(sstl_load_stream(sstl, file) == RES_OK);
-
- CHK(sstl_get_desc(sstl, &desc) == RES_OK);
- CHK(strcmp(desc.solid_name, "cube_corner") == 0);
- CHK(desc.vertices_count == 4);
- CHK(desc.triangles_count == 4);
-
- CHK(f3_eq(desc.vertices + desc.indices[0]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[1]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[2]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[3]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[4]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[5]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[6]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[7]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[8]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[9]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[10]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[11]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
-
- CHK(f3_eq(desc.normals + 0*3, f3(tmp, 0.f,-1.f, 0.f)) == 1);
- CHK(f3_eq(desc.normals + 1*3, f3(tmp, 0.f, 0.f,-1.f)) == 1);
- CHK(f3_eq(desc.normals + 2*3, f3(tmp,-1.f, 0.f, 0.f)) == 1);
- f3_normalize(tmp, f3(tmp, 1.f, 1.f, 1.f));
- CHK(f3_eq_eps(desc.normals + 3*3, tmp, 1.e-6f) == 1);
-
- rewind(file);
- CHK(sstl_load_stream_binary(sstl, file) == RES_BAD_ARG);
- rewind(file);
- CHK(sstl_load_stream_ascii(sstl, file) == RES_OK);
+ CHK(sstl_load_stream(sstl, file, "stream") == RES_OK);
+ CHK(fclose(file) == 0);
CHK(sstl_get_desc(sstl, &desc) == RES_OK);
CHK(strcmp(desc.solid_name, "cube_corner") == 0);
@@ -422,117 +288,6 @@ test_tetrahedron(struct sstl* sstl)
CHK(f3_eq(desc.normals + 2*3, f3(tmp,-1.f, 0.f, 0.f)) == 1);
f3_normalize(tmp, f3(tmp, 1.f, 1.f, 1.f));
CHK(f3_eq_eps(desc.normals + 3*3, tmp, 1.e-6f) == 1);
-
- CHK(sstl_pack_write_data(sstl, &wd) == RES_OK);
- CHK(sstl_write(&wd, 0, "corner.stl") == RES_OK);
- CHK(sstl_write(&wd, 1, "corner_bin.stl") == RES_OK);
-
- CHK(sstl_load_ascii(sstl, "corner_bin.stl") == RES_BAD_ARG);
- CHK(sstl_load_binary(sstl, "corner.stl") == RES_BAD_ARG);
-
- CHK(sstl_load(sstl, "corner.stl") == RES_OK);
-
- CHK(sstl_get_desc(sstl, &desc) == RES_OK);
- CHK(strcmp(desc.solid_name, "cube_corner") == 0);
- CHK(desc.vertices_count == 4);
- CHK(desc.triangles_count == 4);
-
- CHK(f3_eq(desc.vertices + desc.indices[0]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[1]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[2]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[3]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[4]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[5]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[6]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[7]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[8]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[9]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[10]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[11]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
-
- CHK(f3_eq(desc.normals + 0*3, f3(tmp, 0.f,-1.f, 0.f)) == 1);
- CHK(f3_eq(desc.normals + 1*3, f3(tmp, 0.f, 0.f,-1.f)) == 1);
- CHK(f3_eq(desc.normals + 2*3, f3(tmp,-1.f, 0.f, 0.f)) == 1);
- f3_normalize(tmp, f3(tmp, 1.f, 1.f, 1.f));
- CHK(f3_eq_eps(desc.normals + 3*3, tmp, 1.e-6f) == 1);
-
- CHK(sstl_load_ascii(sstl, "corner.stl") == RES_OK);
-
- CHK(sstl_get_desc(sstl, &desc) == RES_OK);
- CHK(strcmp(desc.solid_name, "cube_corner") == 0);
- CHK(desc.vertices_count == 4);
- CHK(desc.triangles_count == 4);
-
- CHK(f3_eq(desc.vertices + desc.indices[0]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[1]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[2]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[3]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[4]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[5]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[6]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[7]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[8]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[9]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[10]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[11]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
-
- CHK(f3_eq(desc.normals + 0*3, f3(tmp, 0.f,-1.f, 0.f)) == 1);
- CHK(f3_eq(desc.normals + 1*3, f3(tmp, 0.f, 0.f,-1.f)) == 1);
- CHK(f3_eq(desc.normals + 2*3, f3(tmp,-1.f, 0.f, 0.f)) == 1);
- f3_normalize(tmp, f3(tmp, 1.f, 1.f, 1.f));
- CHK(f3_eq_eps(desc.normals + 3*3, tmp, 1.e-6f) == 1);
-
- CHK(sstl_load(sstl, "corner_bin.stl") == RES_OK);
-
- CHK(sstl_get_desc(sstl, &desc) == RES_OK);
- CHK(desc.solid_name == NULL); /* binary files don't store a name */
- CHK(desc.vertices_count == 4);
- CHK(desc.triangles_count == 4);
-
- CHK(f3_eq(desc.vertices + desc.indices[0]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[1]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[2]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[3]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[4]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[5]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[6]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[7]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[8]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[9]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[10]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[11]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
-
- CHK(f3_eq(desc.normals + 0*3, f3(tmp, 0.f,-1.f, 0.f)) == 1);
- CHK(f3_eq(desc.normals + 1*3, f3(tmp, 0.f, 0.f,-1.f)) == 1);
- CHK(f3_eq(desc.normals + 2*3, f3(tmp,-1.f, 0.f, 0.f)) == 1);
- f3_normalize(tmp, f3(tmp, 1.f, 1.f, 1.f));
- CHK(f3_eq_eps(desc.normals + 3*3, tmp, 1.e-6f) == 1);
-
- CHK(sstl_load_binary(sstl, "corner_bin.stl") == RES_OK);
-
- CHK(sstl_get_desc(sstl, &desc) == RES_OK);
- CHK(desc.solid_name == NULL); /* binary files don't store a name */
- CHK(desc.vertices_count == 4);
- CHK(desc.triangles_count == 4);
-
- CHK(f3_eq(desc.vertices + desc.indices[0]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[1]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[2]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[3]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[4]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[5]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[6]*3, f3(tmp, 0.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[7]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[8]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[9]*3, f3(tmp, 1.f, 0.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[10]*3, f3(tmp, 0.f, 1.f, 0.f)) == 1);
- CHK(f3_eq(desc.vertices + desc.indices[11]*3, f3(tmp, 0.f, 0.f, 1.f)) == 1);
-
- CHK(f3_eq(desc.normals + 0*3, f3(tmp, 0.f,-1.f, 0.f)) == 1);
- CHK(f3_eq(desc.normals + 1*3, f3(tmp, 0.f, 0.f,-1.f)) == 1);
- CHK(f3_eq(desc.normals + 2*3, f3(tmp,-1.f, 0.f, 0.f)) == 1);
- f3_normalize(tmp, f3(tmp, 1.f, 1.f, 1.f));
- CHK(f3_eq_eps(desc.normals + 3*3, tmp, 1.e-6f) == 1);
}
int
@@ -545,7 +300,7 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHK(sstl_create(NULL, &allocator, 1, &sstl) == RES_OK);
+ CHK(sstl_create(NULL, &allocator, 3, &sstl) == RES_OK);
test_basic(sstl);
test_tetrahedron(sstl);