star-stl

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

commit 82ac1780944d00f2571856f630f0678a872613cc
parent d47b34f20a96540fa15594a873a0531df5d661be
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 11 Apr 2025 11:34:43 +0200

Write the sstl utility

It loads StL files and prints information about them. It is designed to
check the loading procedure of an arbitrary StL file.

Note that its manual is missing.

Diffstat:
M.gitignore | 19++++++++++---------
MMakefile | 36++++++++++++++++++++++++++++++++----
Asrc/sstl_main.c | 213+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 255 insertions(+), 13 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,13 +1,14 @@ -.gitignore -[Bb]uild* -*.sw[po] -*.[aod] -*.so *~ -test* -!test*.[ch] +*.[aod] +[Bb]uild* .config -.test -tags +.gitignore *.pc +*.so +sstl *.stl +*.sw[po] +tags +.test +test* +!test*.[ch] diff --git a/Makefile b/Makefile @@ -23,7 +23,7 @@ LIBNAME_SHARED = libsstl.so LIBNAME = $(LIBNAME_$(LIB_TYPE)) default: library -all: library tests +all: library tests util ################################################################################ # Library building @@ -68,6 +68,33 @@ libsstl.o: $(OBJ) $(CC) $(CFLAGS_LIB) -c $< -o $@ ################################################################################ +# Utils +################################################################################ +UTIL_SRC = src/sstl_main.c +UTIL_OBJ = $(UTIL_SRC:.c=.o) +UTIL_DEP = $(UTIL_SRC:.c=.d) + +PKG_CONFIG_LOCAL = PKG_CONFIG_PATH="./:$${PKG_CONFIG_PATH}" $(PKG_CONFIG) + +INCS_UTIL = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags rsys sstl-local) +LIBS_UTIL = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs rsys sstl-local) + +CFLAGS_UTIL = -std=c99 $(CFLAGS_EXE) $(INCS_UTIL) +LDFLAGS_UTIL = $(LDFLAGS_EXE) $(LIBS_UTIL) + +util: library $(UTIL_DEP) + @$(MAKE) -fMakefile -f"$(UTIL_DEP)" sstl + +sstl: config.mk sstl-local.pc $(UTIL_OBJ) $(LIBNAME) + $(CC) $(CFLAGS_UTIL) -o $@ $(UTIL_OBJ) $(LDFLAGS_UTIL) + +$(UTIL_DEP): config.mk sstl-local.pc + @$(CC) $(CFLAGS_UTIL) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@ + +$(UTIL_OBJ): config.mk sstl-local.pc + $(CC) $(CFLAGS_UTIL) -c $(@:.o=.c) -o $@ + +################################################################################ # Installation ################################################################################ pkg: @@ -84,20 +111,22 @@ sstl-local.pc: sstl.pc.in -e 's#@RSYS_VERSION@#$(RSYS_VERSION)#g' \ sstl.pc.in > $@ -install: library pkg +install: library util pkg install() { mode="$$1"; prefix="$$2"; shift 2; \ mkdir -p "$${prefix}"; \ cp "$$@" "$${prefix}"; \ chmod "$${mode}" "$$@"; \ }; \ - install 755 "$(DESTDIR)$(LIBPREFIX)/" $(LIBNAME); \ + install 755 "$(DESTDIR)$(LIBPREFIX)" $(LIBNAME); \ install 644 "$(DESTDIR)$(LIBPREFIX)/pkgconfig" sstl.pc; \ + install 755 "$(DESTDIR)$(BINPREFIX)" sstl; \ install 644 "$(DESTDIR)$(INCPREFIX)/star" src/sstl.h; \ install 644 "$(DESTDIR)$(PREFIX)/share/doc/star-stl" COPYING README.md uninstall: rm -f "$(DESTDIR)$(LIBPREFIX)/$(LIBNAME)" rm -f "$(DESTDIR)$(LIBPREFIX)/pkgconfig/sstl.pc" + rm -f "$(DESTDIR)$(BINPREFIX)/sstl" rm -f "$(DESTDIR)$(INCPREFIX)/star/sstl.h" rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-stl/COPYING" rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-stl/README.md" @@ -117,7 +146,6 @@ TEST_OBJ = $(TEST_SRC:.c=.o) TEST_DEP = $(TEST_SRC:.c=.d) TEST_TGT = $(TEST_SRC:.c=.t) -PKG_CONFIG_LOCAL = PKG_CONFIG_PATH="./:$${PKG_CONFIG_PATH}" $(PKG_CONFIG) INCS_TEST = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags rsys sstl-local) LIBS_TEST = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs rsys sstl-local) diff --git a/src/sstl_main.c b/src/sstl_main.c @@ -0,0 +1,213 @@ +/* Copyright (C) 2015, 2016, 2019, 2021, 2023, 2025 |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 /* getopt support */ + +#include "sstl.h" + +#include <rsys/mem_allocator.h> +#include <unistd.h> /* getopt */ + +struct args { + /* List of input meshes. + * Empty list means that a mesh is read from standard */ + char* const* meshes; + unsigned nmeshes; + + enum sstl_read_type read_type; /* Type of input meshes */ + int verbose; /* Verbosity level */ + int quit; +}; +static const struct args ARGS_DEFAULT = {NULL, 0, SSTL_NONE__, 0, 0}; + +struct cmd { + struct args args; + struct sstl* sstl; +}; +static const struct cmd CMD_NULL = {0}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE void +usage(FILE* stream) +{ + fprintf(stream, "usage: sstl [-abhv] [file ...]\n"); +} + +static res_T +args_init(struct args* args, int argc, char** argv) +{ + int opt = 0; + res_T res = RES_OK; + + *args = ARGS_DEFAULT; + + while((opt = getopt(argc, argv, "abhv")) != -1) { + switch(opt) { + case 'a': args->read_type = SSTL_ASCII; break; + case 'b': args->read_type = SSTL_BINARY; break; + case 'h': + usage(stdout); + args->quit = 1; + break; + case 'v': args->verbose += (args->verbose < 3); break; + default: res = RES_BAD_ARG; break; + } + if(res != RES_OK) goto error; + } + + /* Setup the list of meshes */ + args->meshes = argv + optind; + args->nmeshes = (unsigned)(argc - optind); + + if(!args->nmeshes && args->read_type == SSTL_NONE__) { + fprintf(stderr, + "StL type must be defined for reading on stdin " + "-- options '-a' or -b'\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + usage(stderr); + goto exit; +} + +static INLINE void +cmd_release(struct cmd* cmd) +{ + if(cmd->sstl) SSTL(ref_put(cmd->sstl)); +} + +static INLINE res_T +cmd_init(struct cmd* cmd, const struct args* args) +{ + res_T res = RES_OK; + ASSERT(cmd && args); + + cmd->args = *args; + + res = sstl_create(NULL, NULL, args->verbose, &cmd->sstl); + if(res != RES_OK) goto error; + +exit: + return res; +error: + cmd_release(cmd); + goto exit; +} + +static INLINE const char* +read_type_to_cstr(const enum sstl_read_type type) +{ + const char* cstr = NULL; + switch(type) { + case SSTL_ASCII: cstr = "ASCII"; break; + case SSTL_BINARY: cstr = "binary"; break; + default: FATAL("Unreachable code"); break; + } + return cstr; +} + +static INLINE void +print_info(const struct cmd* cmd) +{ + struct sstl_desc desc = SSTL_DESC_NULL; + ASSERT(cmd); + + SSTL(get_desc(cmd->sstl, &desc)); + printf("%s\t%s\t%s\t%lu\t%lu\n", + desc.filename, + read_type_to_cstr(desc.read_type), + desc.solid_name ? desc.solid_name : "NULL", + (unsigned long)desc.triangles_count, + (unsigned long)desc.vertices_count); +} + +static INLINE res_T +cmd_run(const struct cmd* cmd) +{ + res_T res = RES_OK; + ASSERT(cmd); + + /* Read from the standard input */ + if(!cmd->args.nmeshes) { + switch(cmd->args.read_type) { + case SSTL_ASCII: + res = sstl_load_stream_ascii(cmd->sstl, stdin, "stdin (ASCII)"); + break; + case SSTL_BINARY: + res = sstl_load_stream_binary(cmd->sstl, stdin, "stdin (binary)"); + break; + default: FATAL("Unreachable code"); break; + } + if(res != RES_OK) goto error; + print_info(cmd); + + /* Load files */ + } else { + unsigned i; + FOR_EACH(i, 0, cmd->args.nmeshes) { + switch(cmd->args.read_type) { + case SSTL_ASCII: + res = sstl_load_ascii(cmd->sstl, cmd->args.meshes[i]); + break; + case SSTL_BINARY: + res = sstl_load_binary(cmd->sstl, cmd->args.meshes[i]); + break; + case SSTL_NONE__: + res = sstl_load(cmd->sstl, cmd->args.meshes[i]); + break; + default: FATAL("Unreachable code"); break; + } + if(res != RES_OK) goto error; + print_info(cmd); + } + } + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * The program + ******************************************************************************/ +int +main(int argc, char** argv) +{ + struct args args = ARGS_DEFAULT; + struct cmd cmd = CMD_NULL; + int err = 0; + res_T res = RES_OK; + + if((res = args_init(&args, argc, argv)) != RES_OK) goto error; + if(args.quit) goto exit; + + if((res = cmd_init(&cmd, &args)) != RES_OK) goto error; + if((res = cmd_run(&cmd)) != RES_OK) goto error; + +exit: + cmd_release(&cmd); + CHK(mem_allocated_size() == 0); + return err; +error: + err = 1; + goto exit; +}