star-3dstl

Create star-3d geometries from StL files
git clone git://git.meso-star.fr/star-3dstl.git
Log | Files | Refs | README | LICENSE

s3dstl.c (6651B)


      1 /* Copyright (C) 2016, 2018, 2021, 2023 |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 "s3dstl.h"
     17 
     18 #include <rsys/float3.h>
     19 #include <rsys/logger.h>
     20 #include <rsys/mem_allocator.h>
     21 #include <rsys/ref_count.h>
     22 
     23 #include <star/s3d.h>
     24 #include <star/sstl.h>
     25 
     26 struct s3dstl {
     27   struct s3d_device* s3d;
     28   struct s3d_shape* shape;
     29 
     30   struct sstl* sstl;
     31   struct logger* logger;
     32   struct mem_allocator* allocator;
     33   int verbose;
     34   ref_T ref;
     35 };
     36 
     37 /*******************************************************************************
     38  * Helper functions
     39  ******************************************************************************/
     40 static void
     41 get_position(const unsigned ivert, float pos[3], void* ctx)
     42 {
     43   const struct sstl_desc* desc = ctx;
     44   ASSERT(ctx && pos && ivert < desc->vertices_count);
     45   f3_set(pos, desc->vertices + ivert * 3);
     46 }
     47 
     48 static void
     49 get_indices(const unsigned itri, unsigned ids[3], void* ctx)
     50 {
     51   const struct sstl_desc* desc = ctx;
     52   const unsigned* indices;
     53   ASSERT(ctx && ids && itri < desc->triangles_count);
     54   indices = desc->indices + itri*3;
     55   /* Note that in the Star-STL loader, front faces are CCW ordered while in to
     56    * the Star-3D library front faces are CW ordered. Flip the vertex index in
     57    * order to ensure that the 3D and the STL front faces are the same */
     58   ids[0] = indices[2];
     59   ids[1] = indices[1];
     60   ids[2] = indices[0];
     61 }
     62 
     63 static void
     64 log_error(const struct s3dstl* s3dstl, const char* msg, ...)
     65 {
     66   va_list vargs_list;
     67   ASSERT(s3dstl && msg);
     68   if(s3dstl->verbose) {
     69     res_T res; (void)res;
     70     va_start(vargs_list, msg);
     71     res = logger_vprint(s3dstl->logger, LOG_ERROR, msg, vargs_list);
     72     ASSERT(res == RES_OK);
     73     va_end(vargs_list);
     74   }
     75 }
     76 
     77 static res_T
     78 shape_create(struct s3dstl* s3dstl, const char* filename)
     79 {
     80   struct s3d_vertex_data vertex_data;
     81   struct s3d_shape* shape = NULL;
     82   struct sstl_desc desc;
     83   res_T res = RES_OK;
     84   ASSERT(s3dstl && filename);
     85 
     86   res = sstl_get_desc(s3dstl->sstl, &desc);
     87   if(res != RES_OK) {
     88     log_error(s3dstl, "%s: couldn't retrieve the STL descriptor.\n", filename);
     89     goto error;
     90   }
     91 
     92   if(!desc.triangles_count) goto exit;
     93 
     94   res = s3d_shape_create_mesh(s3dstl->s3d, &shape);
     95   if(res != RES_OK) {
     96     log_error(s3dstl, "%s: couldn't create the Star-3D shape.\n", filename);
     97     goto error;
     98   }
     99 
    100   vertex_data.usage = S3D_POSITION;
    101   vertex_data.type = S3D_FLOAT3;
    102   vertex_data.get = get_position;
    103 
    104   res = s3d_mesh_setup_indexed_vertices(shape, (unsigned)desc.triangles_count,
    105     get_indices, (unsigned)desc.vertices_count, &vertex_data, 1, &desc);
    106   if(res != RES_OK) {
    107     log_error(s3dstl, "%s: couldn't setup the data of the Star-3D shape.\n",
    108       filename);
    109     goto error;
    110   }
    111 
    112   if(s3dstl->shape) S3D(shape_ref_put(s3dstl->shape));
    113   s3dstl->shape = shape;
    114 
    115 exit:
    116   return res;
    117 error:
    118   if(shape) S3D(shape_ref_put(shape));
    119   goto exit;
    120 }
    121 
    122 static void
    123 release_s3dstl(ref_T* ref)
    124 {
    125   struct s3dstl* s3dstl;
    126   ASSERT(ref);
    127 
    128   s3dstl = CONTAINER_OF(ref, struct s3dstl, ref);
    129   if(s3dstl->sstl) SSTL(ref_put(s3dstl->sstl));
    130   if(s3dstl->s3d) S3D(device_ref_put(s3dstl->s3d));
    131   if(s3dstl->shape) S3D(shape_ref_put(s3dstl->shape));
    132 
    133   MEM_RM(s3dstl->allocator, s3dstl);
    134 }
    135 
    136 /*******************************************************************************
    137  * Exported functions
    138  ******************************************************************************/
    139 res_T
    140 s3dstl_create
    141   (struct logger* log,
    142    struct mem_allocator* allocator,
    143    struct sstl* sstl,
    144    struct s3d_device* s3d,
    145    const int verbose,
    146    struct s3dstl** out_s3dstl)
    147 {
    148   struct s3dstl* s3dstl = NULL;
    149   struct mem_allocator* mem_allocator;
    150   struct logger* logger = NULL;
    151   res_T res = RES_OK;
    152 
    153   if(!s3d || !out_s3dstl) {
    154     res = RES_BAD_ARG;
    155     goto error;
    156   }
    157 
    158   mem_allocator = allocator ? allocator :  &mem_default_allocator;
    159   logger = log ? log : LOGGER_DEFAULT;
    160 
    161   s3dstl = MEM_CALLOC(mem_allocator, 1, sizeof(struct s3dstl));
    162   if(!s3dstl) {
    163     if(verbose) {
    164       logger_print(logger, LOG_ERROR,
    165         "Couldn't allocate the Star-3DSTL device.\n");
    166     }
    167     res = RES_MEM_ERR;
    168     goto error;
    169   }
    170   ref_init(&s3dstl->ref);
    171   s3dstl->allocator = mem_allocator;
    172   s3dstl->logger = logger;
    173   s3dstl->verbose = verbose;
    174   S3D(device_ref_get(s3d));
    175   s3dstl->s3d = s3d;
    176 
    177   if(sstl) {
    178     SSTL(ref_get(sstl));
    179     s3dstl->sstl = sstl;
    180   } else {
    181     res = sstl_create(logger, allocator, verbose, &s3dstl->sstl);
    182     if(res != RES_OK) {
    183       if(verbose) {
    184         logger_print(logger, LOG_ERROR,
    185           "Couldn't create the loader of the STL fileformat.\n");
    186       }
    187       goto error;
    188     }
    189   }
    190 
    191 exit:
    192   if(out_s3dstl) *out_s3dstl = s3dstl;
    193   return res;
    194 error:
    195   if(s3dstl) {
    196     S3DSTL(ref_put(s3dstl));
    197     s3dstl = NULL;
    198   }
    199   goto exit;
    200 }
    201 
    202 res_T
    203 s3dstl_ref_get(struct s3dstl* s3dstl)
    204 {
    205   if(!s3dstl) return RES_BAD_ARG;
    206   ref_get(&s3dstl->ref);
    207   return RES_OK;
    208 }
    209 
    210 res_T
    211 s3dstl_ref_put(struct s3dstl* s3dstl)
    212 {
    213   if(!s3dstl) return RES_BAD_ARG;
    214   ref_put(&s3dstl->ref, release_s3dstl);
    215   return RES_OK;
    216 }
    217 
    218 res_T
    219 s3dstl_get_sstl(struct s3dstl* s3dstl, struct sstl** sstl)
    220 {
    221   if(!s3dstl || !sstl) return RES_BAD_ARG;
    222   *sstl = s3dstl->sstl;
    223   return RES_OK;
    224 }
    225 
    226 res_T
    227 s3dstl_load(struct s3dstl* s3dstl, const char* filename)
    228 {
    229   res_T res;
    230   if(!s3dstl || !filename) return RES_BAD_ARG;
    231   res = sstl_load(s3dstl->sstl, filename);
    232   if(res != RES_OK) return res;
    233   return shape_create(s3dstl, filename);
    234 }
    235 
    236 res_T
    237 s3dstl_load_stream(struct s3dstl* s3dstl, FILE* stream)
    238 {
    239   res_T res;
    240   if(!s3dstl || !stream) return RES_BAD_ARG;
    241   res = sstl_load_stream(s3dstl->sstl, stream);
    242   if(res != RES_OK) return res;
    243   return shape_create(s3dstl, "STREAM");
    244 }
    245 
    246 res_T
    247 s3dstl_clear(struct s3dstl* s3dstl)
    248 {
    249   if(!s3dstl) return RES_BAD_ARG;
    250   if(s3dstl->shape) {
    251     S3D(shape_ref_put(s3dstl->shape));
    252     s3dstl->shape = NULL;
    253   }
    254   return RES_OK;
    255 }
    256 
    257 res_T
    258 s3dstl_get_shape(struct s3dstl* s3dstl, struct s3d_shape** shape)
    259 {
    260   if(!s3dstl || !shape) return RES_BAD_ARG;
    261   *shape = s3dstl->shape;
    262   return RES_OK;
    263 }
    264