commit 31654a41ee1f27e993ba6a4b4ed063fbb2d2f1a7
parent 4b8f9a09070b0fefd6a6f8f0fe172ae4cf11ab7b
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 18 Nov 2025 15:21:00 +0100
In-depth rewrite
Replace the "ctx" data structure with the "mtool_args" structure and its
associated API, i.e., its initialization from command line arguments.
Its name is more meaningful than "context", which does not mean anything
in particular. Similarly, the names of its member variables are more
explicit than the letter of the command line option that activates the
option. For example, the member variable "reverse_normals" replaces the
variable "r".
This structure does not store the list of transformations to be applied.
Instead, it encodes them in a 3x4 matrix that can then be applied as
affine transformations to the vertices of the mesh.
Add the mtool API, i.e., the command API. In the main function, a
command is initialized from the command line arguments, before being
executed and finally released before exiting the program. Thus,
processing is performed in the mtool command functions, and no longer in
the main function, which simply acts as a link between the command line
interface and the command processing.
Use Star-StL 0.7, which updates its API, particularly for writing the
output file. This output file is now written while the facets of the
input geometry are being transformed. The transformed mesh is therefore
never stored in memory but is streamed to the output file.
Numerous code refactorings to improve the readability of the source
code.
Note that although the source code has been successfully compiled, no
tests have been performed yet.
Diffstat:
| M | Makefile | | | 5 | ++--- |
| M | config.mk | | | 2 | +- |
| M | src/mtool.c | | | 265 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
| A | src/mtool.h | | | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | src/mtool_actions.c | | | 68 | -------------------------------------------------------------------- |
| D | src/mtool_actions.h | | | 68 | -------------------------------------------------------------------- |
| M | src/mtool_args.c | | | 270 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
| A | src/mtool_args.h | | | 62 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/mtool_main.c | | | 44 | ++++++++++++++++++++++++++++++++++++++++++++ |
| D | src/mtool_utils.c | | | 89 | ------------------------------------------------------------------------------- |
| D | src/mtool_utils.h | | | 49 | ------------------------------------------------- |
11 files changed, 491 insertions(+), 479 deletions(-)
diff --git a/Makefile b/Makefile
@@ -25,10 +25,9 @@ all: default
# Library building
################################################################################
SRC =\
- src/mtool.c \
- src/mtool_actions.c\
+ src/mtool.c\
src/mtool_args.c\
- src/mtool_utils.c
+ src/mtool_main.c
OBJ = $(SRC:.c=.o)
DEP = $(SRC:.c=.d)
HDR = src/mtool_version.h
diff --git a/config.mk b/config.mk
@@ -31,7 +31,7 @@ PCFLAGS_STATIC = --static
PCFLAGS = $(PCFLAGS_$(LIB_TYPE))
RSYS_VERSION = 0.14
-SSTL_VERSION = 0.5.1
+SSTL_VERSION = 0.7
INCS = $$($(PKG_CONFIG) $(PCFLAGS) --cflags rsys sstl)
LIBS = $$($(PKG_CONFIG) $(PCFLAGS) --libs rsys sstl) -lm
diff --git a/src/mtool.c b/src/mtool.c
@@ -13,114 +13,219 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#include "mtool_actions.h"
-#include "mtool_utils.h"
+#include "mtool.h"
#include <star/sstl.h>
-#include <rsys/mem_allocator.h>
-#include <rsys/logger.h>
+#include <rsys/cstr.h>
+#include <rsys/double3.h>
+#include <rsys/double33.h>
#include <rsys/float3.h>
-#include <rsys/rsys.h>
-int
-main(int argc, char** argv)
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+print_description(struct sstl_desc* desc)
{
- res_T res = RES_OK;
- struct ctx ctx = CTX_NULL__;
- struct mem_allocator allocator;
- struct logger logger;
- struct sstl* sstl = NULL;
- struct sstl_desc desc;
- struct sstl_write_data data;
+ float low[3], upp[3];
size_t i;
- int allocator_initialized = 0;
- int logger_initialized = 0;
- int wbin;
-
- ERR(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- allocator_initialized = 1;
- ERR(logger_init(&allocator, &logger));
- logger_initialized = 1;
+ ASSERT(desc);
- init_ctx(&allocator, &ctx);
+ /* Calculate the mesh AABB */
+ f3_splat(low, FLT_MAX);
+ f3_splat(upp,-FLT_MAX);
+ FOR_EACH(i, 0, desc->vertices_count) {
+ f3_min(low, low, desc->vertices+3*i);
+ f3_max(upp, upp, desc->vertices+3*i);
+ }
+ /* Display the mesh description */
+ fprintf(stderr,
+ "Type: %s, Vertice count: %ld, Triangle count: %ld\n"
+ "Xrange: [%g %g], Yrange: [%g %g], Zrange: [%g %g]\n",
+ desc->type == SSTL_ASCII ? "ACII" : "BINARY",
+ desc->vertices_count,
+ desc->triangles_count,
+ SPLIT3(low),
+ SPLIT3(upp));
+}
- /* Active loggin for args parsing */
- logger_set_stream(&logger, LOG_ERROR, log_err_fn, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_warn_fn, NULL);
- logger_set_stream(&logger, LOG_OUTPUT, log_prt_fn, NULL);
+static res_T
+create_writer(struct mtool* mtool, struct sstl_writer** out_writer)
+{
+ struct sstl_writer_create_args writer_args = SSTL_WRITER_CREATE_ARGS_DEFAULT;
+ struct sstl_writer* writer = NULL;
+ res_T res = RES_OK;
- ERR(parse_args(argc, argv, &ctx, &logger, &allocator));
+ ASSERT(mtool && out_writer);
- if(ctx.h || ctx.v) {
- if(ctx.v) print_version(stdout);
- if(ctx.h) usage(stdout);
- goto end;
- }
+ if(mtool->args.output) {
+ /* Write StL to the destination file */
+ writer_args.filename = mtool->args.output;
+ writer_args.stream = NULL;
- /* Deactivate some loggin according to the -V arg */
- if(ctx.V < 1)
- logger_set_stream(&logger, LOG_ERROR, NULL, NULL);
- if(ctx.V < 2)
- logger_set_stream(&logger, LOG_WARNING, NULL, NULL);
- if(ctx.V < 3)
- logger_set_stream(&logger, LOG_OUTPUT, NULL, NULL);
-
- /* Create SSTL device and load data */
- ERR(sstl_create(&logger, &allocator, ctx.V, &sstl));
- if(ctx.in != NULL) {
- ERR(sstl_load(sstl, ctx.in));
} else {
- ERR(sstl_load_stream(sstl, stdin));
+ /* Write StL to stdout */
+ writer_args.filename = "stdout";
+ writer_args.stream = stdout;
}
- /* Get access to data */
- ERR(sstl_get_desc(sstl, &desc));
+ /* The output type is the one defined in the command line. Note that this
+ * option can also be used to define the type of input data provided on stdin.
+ * This is confusing, as the option is used for two files: input and output.
+ * TODO: correct this confusion */
+ writer_args.type = mtool->args.type;
+ writer_args.triangles_count = (long)mtool->desc.triangles_count;
+
+ if((res = sstl_writer_create(&writer_args, &writer)) != RES_OK) goto error;
+
+exit:
+ *out_writer = writer;
+ return res;
+error:
+ if(writer) { SSTL(writer_ref_put(writer)); writer = NULL; }
+ goto exit;
+}
+
+static res_T
+load(struct mtool* mtool, const struct mtool_args* args)
+{
+ res_T res = RES_OK;
+ ASSERT(mtool && args);
+
+ res = sstl_create(NULL, NULL, args->verbose, &mtool->sstl);
+ if(res != RES_OK) goto error;
+
+ if(args->input) {
+ /* Load data from the provided input file */
+ if((res = sstl_load(mtool->sstl, args->input)) != RES_OK) goto error;
- /* If description requested, print it and quit */
- if(ctx.d) {
- if(ctx.d) print_description(&desc);
- goto end;
+ } else {
+ /* Data are loaded from stdin. The StL type must be defined because the
+ * standard input is not searchable. */
+ switch(args->type) {
+ case SSTL_ASCII:
+ res = sstl_load_stream_ascii(mtool->sstl, stdin, "stdin (ASCII)");
+ break;
+ case SSTL_BINARY:
+ res = sstl_load_stream_binary(mtool->sstl, stdin, "stdin (binary)");
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ if(res != RES_OK) goto error;
}
- /* Apply specified actions */
- ERR(apply_actions(&ctx, &desc));
+ if((res = sstl_get_desc(mtool->sstl, &mtool->desc)) != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ if(mtool->sstl) { SSTL(ref_put(mtool->sstl)); mtool->sstl = NULL; }
+ goto exit;
+}
- /* Prepare data for writing */
- wbin = (ctx.b ? 1 : (ctx.a ? 0 : desc.read_type == SSTL_BINARY));
- ERR(sstl_pack_write_data(sstl, &data));
+static res_T
+transform_mesh(struct mtool* mtool)
+{
+ struct sstl_writer* writer = NULL;
+ size_t itri = 0;
+ res_T res = RES_OK;
- /* Revert normals if requiered */
- if(ctx.r) {
- for(i = 0; i < desc.triangles_count; i++) {
- SWAP(unsigned, desc.indices[3*i], desc.indices[3*i+1]);
+ if((res = create_writer(mtool, &writer)) != RES_OK) goto error;
+
+ FOR_EACH(itri, 0, mtool->desc.triangles_count) {
+ struct sstl_facet facet = SSTL_FACET_NULL;
+
+ /* Get the facet */
+ res = sstl_desc_get_facet(&mtool->desc, itri, &facet);
+ if(res != RES_OK) goto error;
+
+ /* Multiply the vertices by the transformation matrix constructed from the
+ * transformations submitted on the command line */
+ #define TRANSFORM(Vertex) { \
+ double vec[3] = {0,0,0}; \
+ d3_set_f3(vec, Vertex); \
+ d33_muld3(vec, mtool->args.transform, vec); \
+ d3_add(vec, mtool->args.transform+12, vec); \
+ f3_set_d3(Vertex, vec); \
+ } (void) 0
+ TRANSFORM(facet.vertices[0]);
+ TRANSFORM(facet.vertices[1]);
+ TRANSFORM(facet.vertices[2]);
+ #undef TRANSFORM
+
+ if(mtool->args.reverse_normals) {
+ /* Swap the first two vertices to flip the orientation of the triangle */
+ SWAP(float, facet.vertices[0][0], facet.vertices[1][0]);
+ SWAP(float, facet.vertices[0][1], facet.vertices[1][1]);
+ SWAP(float, facet.vertices[0][2], facet.vertices[1][2]);
+
+ /* Reverse the normal even if, in reality, Star-StL does not provide it:
+ * it will be automatically calculated during writing from the vertices of
+ * the facet. However, this may not always be true, hence the explicit
+ * reversal of this normal, which allows for robustness against possible
+ * future changes without adding significant computational cost */
+ f3_minus(facet.normal, facet.normal);
}
+
+ /* Write the facet */
+ if((res = sstl_write_facet(writer, &facet)) != RES_OK) goto error;
}
- /* Write data */
- if(ctx.in != NULL) {
- ERR(sstl_write(&data, wbin, ctx.out));
+exit:
+ if(writer) SSTL(writer_ref_put(writer));
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+mtool_init(struct mtool* mtool, const struct mtool_args* args)
+{
+ res_T res = RES_OK;
+ ASSERT(mtool && args);
+
+ *mtool = MTOOL_NULL;
+
+ /* Load the StL */
+ if((res = load(mtool, args)) != RES_OK) goto error;
+ mtool->args = *args;
+
+exit:
+ return res;
+error:
+ mtool_release(mtool);
+ goto exit;
+}
+
+void
+mtool_release(struct mtool* mtool)
+{
+ ASSERT(mtool);
+ if(mtool->sstl) SSTL(ref_put(mtool->sstl));
+ mtool_args_release(&mtool->args);
+}
+
+res_T
+mtool_run(struct mtool* mtool)
+{
+ res_T res = RES_OK;
+
+ if(mtool->args.print_desc) {
+ print_description(&mtool->desc);
+
} else {
- ERR(sstl_write_stream(&data, wbin, stdout));
+ res = transform_mesh(mtool);
+ if(res != RES_OK) goto error;
}
-end:
- release_ctx(&ctx);
- if(sstl) sstl_ref_put(sstl);
- if(logger_initialized) logger_release(&logger);
- if(allocator_initialized) {
- if(MEM_ALLOCATED_SIZE(&allocator) != 0) {
- char dump[4096] = { '\0' };
- MEM_DUMP(&allocator, dump, sizeof(dump));
- fprintf(stderr, "%s\n", dump);
- fprintf(stderr, "\nMemory leaks: %lu Bytes\n",
- (unsigned long)MEM_ALLOCATED_SIZE(&allocator));
- }
- mem_shutdown_proxy_allocator(&allocator);
- }
+exit:
return res;
error:
- goto end;
+ goto exit;
}
diff --git a/src/mtool.h b/src/mtool.h
@@ -0,0 +1,48 @@
+/* Copyright (C) 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef MTOOL_H
+#define MTOOL_H
+
+#include "mtool_args.h"
+#include <rsys/rsys.h>
+
+/* Forward declarations */
+struct sstl;
+struct sstl_writer;
+
+struct mtool {
+ struct sstl_desc desc;
+ struct sstl* sstl;
+
+ struct mtool_args args;
+};
+#define MTOOL_NULL__ {SSTL_DESC_NULL, NULL, MTOOL_ARGS_DEFAULT}
+static const struct mtool MTOOL_NULL = MTOOL_NULL__;
+
+extern LOCAL_SYM res_T
+mtool_init
+ (struct mtool* mtool,
+ const struct mtool_args* args);
+
+extern LOCAL_SYM void
+mtool_release
+ (struct mtool* mtool);
+
+extern LOCAL_SYM res_T
+mtool_run
+ (struct mtool* mtool);
+
+#endif /* MTOOL_H */
diff --git a/src/mtool_actions.c b/src/mtool_actions.c
@@ -1,68 +0,0 @@
-/* Copyright (C) 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "mtool_actions.h"
-
-#include <star/sstl.h>
-
-#include <rsys/mem_allocator.h>
-#include <rsys/logger.h>
-#include <rsys/float3.h>
-#include <rsys/rsys.h>
-
-
-void
-init_ctx(struct mem_allocator* allocator, struct ctx* ctx)
-{
- ASSERT(allocator && ctx);
- darray_actions_init(allocator, &ctx->actions);
-}
-
-void
-release_ctx(struct ctx* ctx)
-{
- ASSERT(ctx);
- darray_actions_release(&ctx->actions);
-}
-
-res_T
-apply_actions(const struct ctx* ctx, struct sstl_desc* desc)
-{
- res_T res = RES_OK;
- size_t a;
-
- /* Tanslate if specified */
- for(a = 0; a < darray_actions_size_get(&ctx->actions); a++) {
- const struct actions* action = darray_actions_cdata_get(&ctx->actions) + a;
- size_t i;
- switch(action->type) {
- case SCALE:
- for(i = 0; i < desc->vertices_count; i++) {
- f3_mul(desc->vertices+i*3, action->what.scale, desc->vertices+3*i);
- }
- break;
-
- case TRANSLATION:
- for(i = 0; i < desc->vertices_count; i++) {
- f3_add(desc->vertices+i*3, action->what.translation, desc->vertices+3*i);
- }
- break;
-
- default: FATAL("Invalid type");
- }
- }
-
- return res;
-}
diff --git a/src/mtool_actions.h b/src/mtool_actions.h
@@ -1,68 +0,0 @@
-/* Copyright (C) 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef MTOOL_ACTIONS_H
-#define MTOOL_ACTIONS_H
-
-#include <rsys/dynamic_array.h>
-
-struct mem_allocator;
-struct logger;
-struct sstl_desc;
-
-enum action_type {
- SCALE,
- TRANSLATION
-};
-
-struct actions {
- enum action_type type;
- union {
- float scale[3];
- float translation[3];
- } what;
-};
-
-#define DARRAY_NAME actions
-#define DARRAY_DATA struct actions
-#include <rsys/dynamic_array.h>
-
-struct ctx {
- int a, b, d, h, r, v, V;
- char *in, *out;
- struct darray_actions actions;
-};
-
-#define CTX_NULL__ \
-{ 0, 0, 0, 0, 0, 0, 0, NULL, NULL, {NULL,0,0,NULL} }
-
-res_T
-parse_args
- (const int argc,
- char** argv,
- struct ctx* ctx,
- struct logger* logger,
- struct mem_allocator* allocator);
-
-void
-init_ctx(struct mem_allocator* allocator, struct ctx* ctx);
-
-void
-release_ctx(struct ctx* ctx);
-
-res_T
-apply_actions(const struct ctx* ctx, struct sstl_desc* desc);
-
-#endif /* MTOOL_ACTIONS_H */
diff --git a/src/mtool_args.c b/src/mtool_args.c
@@ -13,144 +13,172 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#include "mtool_actions.h"
-#include "mtool_utils.h"
+#define _POSIX_C_SOURCE 200112L /* getopt support */
+
+#include "mtool_args.h"
+#include "mtool_version.h"
-#include <star/sstl.h>
-#include <rsys/mem_allocator.h>
-#include <rsys/logger.h>
#include <rsys/cstr.h>
-#include <rsys/str.h>
+#include <rsys/double3.h>
-#include <getopt.h>
+#include <unistd.h> /* getopt */
-res_T
-parse_args
- (const int argc,
- char** argv,
- struct ctx* ctx,
- struct logger* logger,
- struct mem_allocator* allocator)
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE void
+usage(FILE* stream)
{
- int opt = 0;
+ fprintf(stream,
+"usage: mesh-tool [-abdhrv] [-i file] [-o file] [-S sx,sy,sz] [-T tx,ty,tz]\n"
+" [-V verbosity_level]\n");
+}
+
+static INLINE void
+version(FILE* stream)
+{
+ fprintf(stream,
+ "mesh-tool version %i.%i.%i\n",
+ MTOOL_VERSION_MAJOR,
+ MTOOL_VERSION_MINOR,
+ MTOOL_VERSION_PATCH);
+}
+
+static res_T
+apply_scale(struct mtool_args* args, const char* str)
+{
+ double scale[3] = {0,0,0};
size_t len = 0;
+ res_T res = RES_OK;
+
+ ASSERT(args && str);
+
+ res = cstr_to_list_double(str, ',', scale, &len, 3);
+ if(res == RES_OK && len != 3) res = RES_BAD_ARG;
+ if(res != RES_OK) goto error;
+
+ /* | A, D G J | | Sx 0 0 0 | | A*Sx D*Sy G*Sz J |
+ * M = | B, E H K | * | 0 Sy 0 0 | = | B*Sx E*Sy H*Sz K |
+ * | C, F I L | | 0 0 Sz 0 | | C*Sx F*Sy I*Sz L |
+ * | 0, 0 0 1 | | 0 0 0 1 | | 0 0 0 1 | */
+ d3_muld(args->transform+0, args->transform+0, scale[0]);
+ d3_muld(args->transform+3, args->transform+3, scale[1]);
+ d3_muld(args->transform+6, args->transform+6, scale[2]);
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+apply_translation(struct mtool_args* args, const char* str)
+{
+ double translation[3] = {0,0,0};
+ double vec[3] = {0,0,0};
+ size_t len = 0;
+ res_T res = RES_OK;
+
+ ASSERT(args && str);
+
+ res = cstr_to_list_double(str, ',', translation, &len, 3);
+ if(res == RES_OK && len != 3) res = RES_BAD_ARG;
+ if(res != RES_OK) goto error;
+
+ /* | A D G J | | 1 0 0 Tx | | A D G (A*Tx + D*Ty + G*Tz + J) |
+ * M = | B E H K | * | 0 1 0 Ty | = | B E H (B*Tx + E*Ty + H*Tz + K) |
+ * | C F I L | | 0 0 1 Tz | | C F I (C*Tx + F*Ty + I*Tz + L) |
+ * | 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 | */
+ d3_muld(vec, args->transform+0, translation[0]);
+ d3_add(vec, vec, d3_muld(vec, args->transform+3, translation[1]));
+ d3_add(vec, vec, d3_muld(vec, args->transform+6, translation[2]));
+ d3_add(vec, vec, args->transform+9);
+ d3_set(args->transform+9, vec);
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_verbosity(struct mtool_args* args, const char* str)
+{
+ unsigned verbosity = 0;
+ res_T res = RES_OK;
+
+ ASSERT(args && str);
+
+ res = cstr_to_uint(str, &verbosity);
+ if(res == RES_OK && verbosity > 3) res = RES_BAD_ARG;
+ if(res != RES_OK) goto error;
+
+ args->verbose = (int)verbosity;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+mtool_args_init
+ (struct mtool_args* args,
+ int argc,
+ char** argv)
+{
const char option_list[] = "abdhi:o:rS:T:vV:";
+ int opt = 0;
res_T res = RES_OK;
- ASSERT(argv && ctx && logger && allocator);
- (void)allocator;
+ ASSERT(args && argc && argv);
+
+ *args = MTOOL_ARGS_DEFAULT;
- opterr = 0; /* No default error messages */
while((opt = getopt(argc, argv, option_list)) != -1) {
switch (opt) {
-
- case '?': /* Unreconised option */
- {
- char* ptr = strchr(option_list, optopt);
- res = RES_BAD_ARG;
- if(ptr && ptr[1] == ':') {
- logger_print(logger, LOG_ERROR,
- "Missing argument for option -%c\n",
- optopt);
- } else {
- logger_print(logger, LOG_ERROR, "Invalid option -%c\n", optopt);
- }
- goto error;
- }
-
- case 'a':
- ctx->a = 1;
- break;
-
- case 'b':
- ctx->b = 1;
- break;
-
- case 'd':
- ctx->d = 1;
- break;
-
+ case 'a': args->type = SSTL_ASCII; break;
+ case 'b': args->type = SSTL_BINARY; break;
+ case 'd': args->print_desc = 1; break;
case 'h':
- ctx->h = 1;
- break;
-
- case 'i':
- ctx->in = optarg;
- break;
-
- case 'o':
- ctx->out = optarg;
- break;
-
- case 'r':
- ctx->r = 1;
- break;
-
- case 'S':
- {
- struct actions action;
- res = cstr_to_list_float(optarg, ',', action.what.scale, &len, 3);
- if(res != RES_OK
- || len != 3)
- {
- logger_print(logger, LOG_ERROR,
- "Error parsing translation: `%s'\n", optarg);
- if(res == RES_OK) res = RES_BAD_ARG;
- goto error;
- }
- action.type = SCALE;
- ERR(darray_actions_push_back(&ctx->actions, &action));
- break;
- }
-
- case 'T':
- {
- struct actions action;
- res = cstr_to_list_float(optarg, ',', action.what.translation, &len, 3);
- if(res != RES_OK
- || len != 3)
- {
- logger_print(logger, LOG_ERROR,
- "Error parsing translation: `%s'\n", optarg);
- if(res == RES_OK) res = RES_BAD_ARG;
- goto error;
- }
- action.type = TRANSLATION;
- ERR(darray_actions_push_back(&ctx->actions, &action));
- break;
- }
-
+ usage(stdout);
+ args->quit = 1;
+ goto exit;
+ case 'i': args->input = optarg; break;
+ case 'o': args->output = optarg; break;
+ case 'r': args->reverse_normals = 1; break;
+ case 'S': res = apply_scale(args, optarg); break;
+ case 'T': res = apply_translation(args, optarg); break;
case 'v':
- ctx->v = 1;
- break;
-
- case 'V':
- res = cstr_to_int(optarg, &ctx->V);
- if(res != RES_OK
- || ctx->V < 0
- || ctx->V > 3)
- {
- logger_print(logger, LOG_ERROR,
- "Invalid verbosity level: `%s'\n", optarg);
- if(res == RES_OK) res = RES_BAD_ARG;
- goto error;
- }
- break;
-
+ version(stdout);
+ args->quit = 1;
+ goto exit;
+ case 'V': res = parse_verbosity(args, optarg); break;
+ default: res = RES_BAD_ARG; break;
+ }
+ if(res != RES_OK) {
+ if(optarg) {
+ fprintf(stderr, "mesh-tool: invalid option argument '%s' -- '%c'\n",
+ optarg, opt);
+ }
+ goto error;
}
}
- /* Check -a and -b not both specified */
- if(ctx->a && ctx->b) {
- logger_print(logger, LOG_ERROR,
- "Cannot specify -a and -b at the same time.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
-end:
+exit:
return res;
error:
- logger_print(logger, LOG_ERROR, "Use option -h to print help.\n");
- goto end;
+ mtool_args_release(args);
+ usage(stderr);
+ goto exit;
+}
+
+void
+mtool_args_release(struct mtool_args* args)
+{
+ ASSERT(args);
+ *args = MTOOL_ARGS_DEFAULT;
}
diff --git a/src/mtool_args.h b/src/mtool_args.h
@@ -0,0 +1,62 @@
+/* Copyright (C) 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef MTOOL_ARGS_H
+#define MTOOL_ARGS_H
+
+#include <star/sstl.h> /* enum sstl_type */
+
+struct mtool_args {
+ /* Transformation matrix storing the list of transformations, applied in the
+ * order in which they are submitted on the command line */
+ double transform[12]; /* 3x4 column major */
+
+ const char* input; /* Input filename. NULL <=> stdin */
+ const char* output; /* Output filename. NULL <=> stdout */
+
+ /* Input/output StL type */
+ enum sstl_type type;
+
+ int reverse_normals;
+ int print_desc;
+ int verbose;
+ int quit;
+};
+#define MTOOL_ARGS_DEFAULT__ { \
+ {1,0,0, 0,1,0, 0,0,1, 0,0,0}, /* Transform */ \
+ \
+ NULL, /* Input */ \
+ NULL, /* Output */ \
+ \
+ SSTL_ASCII, /* Input/output StL type */ \
+ \
+ 0, /* Reverse normals */ \
+ 0, /* Print descriptor */ \
+ 0, /* Verbosity */ \
+ 0 /* Quit */ \
+}
+static const struct mtool_args MTOOL_ARGS_DEFAULT = MTOOL_ARGS_DEFAULT__;
+
+extern LOCAL_SYM res_T
+mtool_args_init
+ (struct mtool_args* args,
+ int argc,
+ char** argv);
+
+extern LOCAL_SYM void
+mtool_args_release
+ (struct mtool_args* args);
+
+#endif /* MTOOL_ARGS_H */
diff --git a/src/mtool_main.c b/src/mtool_main.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "mtool.h"
+#include "mtool_args.h"
+
+#include <rsys/mem_allocator.h>
+
+int
+main(int argc, char** argv)
+{
+ struct mtool_args args = MTOOL_ARGS_DEFAULT;
+ struct mtool cmd = MTOOL_NULL;
+ size_t sz = 0;
+ res_T res = RES_OK;
+
+ if((res = mtool_args_init(&args, argc, argv)) != RES_OK) goto error;
+ if(args.quit) goto exit;
+
+ if((res = mtool_init(&cmd, &args)) != RES_OK) goto error;
+ if((res = mtool_run(&cmd)) != RES_OK) goto error;
+
+exit:
+ mtool_release(&cmd);
+ mtool_args_release(&args);
+ if((sz = mem_allocated_size()) != 0) {
+ fprintf(stderr, "Memory leaks: %lu Bytes\n", (unsigned long)sz);
+ }
+ return res;
+error:
+ goto exit;
+}
diff --git a/src/mtool_utils.c b/src/mtool_utils.c
@@ -1,89 +0,0 @@
-/* Copyright (C) 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include "mtool_utils.h"
-#include "mtool_version.h"
-
-#include <star/sstl.h>
-#include <rsys/mem_allocator.h>
-#include <rsys/logger.h>
-#include <rsys/rsys.h>
-#include <rsys/float3.h>
-
-#include <stdio.h>
-
-void
-log_err_fn
- (const char* msg, void* ctx)
-{
- ASSERT(msg);
- (void)ctx;
- fprintf(stderr, "\x1b[31merror:\x1b[0m %s", msg);
-}
-
-void
-log_warn_fn
- (const char* msg, void* ctx)
-{
- ASSERT(msg);
- (void)ctx;
- fprintf(stderr, "\x1b[33mwarning:\x1b[0m %s", msg);
-}
-
-void
-log_prt_fn
- (const char* msg, void* ctx)
-{
- ASSERT(msg);
- (void)ctx;
- fprintf(stderr, "\x1b[32moutput:\x1b[0m %s", msg);
-}
-
-void
-usage(FILE* stream)
-{
- fprintf(stream, "mesh-tool [-abdhrv] [-i <file>] [-o <file>] [-S sx,sy,sz]] [-T tx,ty,tz] [-V verbosity_level]\n");
-}
-
-void
-print_version
- (FILE* stream)
-{
- ASSERT(stream);
- fprintf(stream,
- "mesh-tool version %i.%i.%i\n",
- MTOOL_VERSION_MAJOR, MTOOL_VERSION_MINOR, MTOOL_VERSION_PATCH);
-}
-
-void
-print_description
- (struct sstl_desc* desc)
-{
- size_t i;
- float minb[3], maxb[3];
- f3_splat(minb, FLT_MAX);
- f3_splat(maxb, -FLT_MAX);
- for(i = 0; i < desc->vertices_count; i++) {
- f3_min(minb, minb, desc->vertices+3*i);
- f3_max(maxb, maxb, desc->vertices+3*i);
- }
- fprintf(stderr,
- "Type: %s, Vertice count: %ld, Triangle count: %ld\n"
- "Xrange: [%g %g], Yrange: [%g %g], Zrange: [%g %g]\n",
- (desc->read_type == SSTL_ASCII ? "ACII" : "BINARY"),
- desc->vertices_count, desc->triangles_count,
- minb[0], maxb[0], minb[1], maxb[1], minb[2], maxb[2]);
-}
-
diff --git a/src/mtool_utils.h b/src/mtool_utils.h
@@ -1,49 +0,0 @@
-/* Copyright (C) 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef MTOOL_UTILS_H
-#define MTOOL_UTILS_H
-
-#include <stdio.h>
-
-struct sstl_desc;
-
-/* Utility macros */
-#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; else (void)0
-
-void
-log_err_fn
- (const char* msg, void* ctx);
-
-void
-log_warn_fn
- (const char* msg, void* ctx);
-
-void
-log_prt_fn
- (const char* msg, void* ctx);
-
-void
-usage(FILE* stream);
-
-void
-print_version
- (FILE* stream);
-
-void
-print_description
- (struct sstl_desc* desc);
-
-#endif /* MTOOL_UTILS_H */