star-meshtool

Mesh transformation
git clone git://git.meso-star.fr/star-meshtool.git
Log | Files | Refs | README | LICENSE

mtool.c (6564B)


      1 /* Copyright (C) 2025 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "mtool.h"
     17 
     18 #include <star/sstl.h>
     19 
     20 #include <rsys/cstr.h>
     21 #include <rsys/double3.h>
     22 #include <rsys/double33.h>
     23 #include <rsys/float3.h>
     24 
     25 /*******************************************************************************
     26  * Helper functions
     27  ******************************************************************************/
     28 static void
     29 print_description(struct sstl_desc* desc)
     30 {
     31   float low[3], upp[3];
     32   size_t i;
     33 
     34   ASSERT(desc);
     35 
     36   /* Calculate the mesh AABB */
     37   f3_splat(low, FLT_MAX);
     38   f3_splat(upp,-FLT_MAX);
     39   FOR_EACH(i, 0, desc->vertices_count) {
     40     f3_min(low, low, desc->vertices+3*i);
     41     f3_max(upp, upp, desc->vertices+3*i);
     42   }
     43 
     44   /* Display the mesh description */
     45   fprintf(stderr,
     46     "Type: %s, Vertice count: %ld, Triangle count: %ld\n"
     47     "Xrange: [%g %g], Yrange: [%g %g], Zrange: [%g %g]\n",
     48     desc->type == SSTL_ASCII ? "ACII" : "BINARY",
     49     desc->vertices_count,
     50     desc->triangles_count,
     51     SPLIT3(low),
     52     SPLIT3(upp));
     53 }
     54 
     55 static res_T
     56 create_writer(struct mtool* mtool, struct sstl_writer** out_writer)
     57 {
     58   struct sstl_writer_create_args writer_args = SSTL_WRITER_CREATE_ARGS_DEFAULT;
     59   struct sstl_writer* writer = NULL;
     60   res_T res = RES_OK;
     61 
     62   ASSERT(mtool && out_writer);
     63 
     64   if(mtool->args.output) {
     65     /* Write StL to the destination file */
     66     writer_args.filename = mtool->args.output;
     67     writer_args.stream = NULL;
     68 
     69   } else {
     70     /*  Write StL to stdout */
     71     writer_args.filename = "stdout";
     72     writer_args.stream = stdout;
     73   }
     74 
     75   /* The output type is the one defined in the command line. Note that this
     76    * option can also be used to define the type of input data provided on stdin.
     77    * This is confusing, as the option is used for two files: input and output.
     78    * TODO: correct this confusion */
     79   writer_args.type = mtool->args.type;
     80   writer_args.triangles_count = (long)mtool->desc.triangles_count;
     81 
     82   if((res = sstl_writer_create(&writer_args, &writer)) != RES_OK) goto error;
     83 
     84 exit:
     85   *out_writer = writer;
     86   return res;
     87 error:
     88   if(writer) { SSTL(writer_ref_put(writer)); writer = NULL; }
     89   goto exit;
     90 }
     91 
     92 static res_T
     93 load(struct mtool* mtool, const struct mtool_args* args)
     94 {
     95   res_T res = RES_OK;
     96   ASSERT(mtool && args);
     97 
     98   res = sstl_create(NULL, NULL, args->verbose, &mtool->sstl);
     99   if(res != RES_OK) goto error;
    100 
    101   if(args->input) {
    102     /* Load data from the provided input file */
    103     if((res = sstl_load(mtool->sstl, args->input)) != RES_OK) goto error;
    104 
    105   } else {
    106     /* Data are loaded from stdin. The StL type must be defined because the
    107      * standard input is not searchable. */
    108     switch(args->type) {
    109       case SSTL_ASCII:
    110         res = sstl_load_stream_ascii(mtool->sstl, stdin, "stdin (ASCII)");
    111         break;
    112       case SSTL_BINARY:
    113         res = sstl_load_stream_binary(mtool->sstl, stdin, "stdin (binary)");
    114         break;
    115       default: FATAL("Unreachable code\n"); break;
    116     }
    117     if(res != RES_OK) goto error;
    118   }
    119 
    120   if((res = sstl_get_desc(mtool->sstl, &mtool->desc)) != RES_OK) goto error;
    121 
    122 exit:
    123   return res;
    124 error:
    125   if(mtool->sstl) { SSTL(ref_put(mtool->sstl)); mtool->sstl = NULL; }
    126   goto exit;
    127 }
    128 
    129 static res_T
    130 transform_mesh(struct mtool* mtool)
    131 {
    132   struct sstl_writer* writer = NULL;
    133   size_t itri = 0;
    134   res_T res = RES_OK;
    135 
    136   if((res = create_writer(mtool, &writer)) != RES_OK) goto error;
    137 
    138   FOR_EACH(itri, 0, mtool->desc.triangles_count) {
    139     struct sstl_facet facet = SSTL_FACET_NULL;
    140 
    141     /* Get the facet */
    142     res = sstl_desc_get_facet(&mtool->desc, itri, &facet);
    143     if(res != RES_OK) goto error;
    144 
    145     /* Multiply the vertices by the transformation matrix constructed from the
    146      * transformations submitted on the command line */
    147     #define TRANSFORM(Vertex) { \
    148       double vec[3] = {0,0,0}; \
    149       d3_set_f3(vec, Vertex); \
    150       d33_muld3(vec, mtool->args.transform, vec); \
    151       d3_add(vec, mtool->args.transform+9, vec); \
    152       f3_set_d3(Vertex, vec); \
    153     } (void) 0
    154     TRANSFORM(facet.vertices[0]);
    155     TRANSFORM(facet.vertices[1]);
    156     TRANSFORM(facet.vertices[2]);
    157     #undef TRANSFORM
    158 
    159     if(mtool->args.reverse_normals) {
    160       /* Swap the first two vertices to flip the orientation of the triangle */
    161       SWAP(float, facet.vertices[0][0], facet.vertices[1][0]);
    162       SWAP(float, facet.vertices[0][1], facet.vertices[1][1]);
    163       SWAP(float, facet.vertices[0][2], facet.vertices[1][2]);
    164 
    165       /* Reverse the normal even if, in reality, Star-StL does not provide it:
    166        * it will be automatically calculated during writing from the vertices of
    167        * the facet. However, this may not always be true, hence the explicit
    168        * reversal of this normal, which allows for robustness against possible
    169        * future changes without adding significant computational cost */
    170       f3_minus(facet.normal, facet.normal);
    171     }
    172 
    173     /* Write the facet */
    174     if((res = sstl_write_facet(writer, &facet)) != RES_OK) goto error;
    175   }
    176 
    177 exit:
    178   if(writer) SSTL(writer_ref_put(writer));
    179   return res;
    180 error:
    181   goto exit;
    182 }
    183 
    184 /*******************************************************************************
    185  * Local functions
    186  ******************************************************************************/
    187 res_T
    188 mtool_init(struct mtool* mtool, const struct mtool_args* args)
    189 {
    190   res_T res = RES_OK;
    191   ASSERT(mtool && args);
    192 
    193   *mtool = MTOOL_NULL;
    194 
    195   /* Load the StL */
    196   if((res = load(mtool, args)) != RES_OK) goto error;
    197   mtool->args = *args;
    198 
    199 exit:
    200   return res;
    201 error:
    202   mtool_release(mtool);
    203   goto exit;
    204 }
    205 
    206 void
    207 mtool_release(struct mtool* mtool)
    208 {
    209   ASSERT(mtool);
    210   if(mtool->sstl) SSTL(ref_put(mtool->sstl));
    211   mtool_args_release(&mtool->args);
    212 }
    213 
    214 res_T
    215 mtool_run(struct mtool* mtool)
    216 {
    217   res_T res = RES_OK;
    218 
    219   if(mtool->args.print_desc) {
    220     print_description(&mtool->desc);
    221 
    222   } else {
    223     res = transform_mesh(mtool);
    224     if(res != RES_OK) goto error;
    225   }
    226 
    227 exit:
    228   return res;
    229 error:
    230   goto exit;
    231 }