star-geometry-3d

Clean and decorate 3D geometries
git clone git://git.meso-star.fr/star-geometry-3d.git
Log | Files | Refs | README | LICENSE

sg3d.h (16758B)


      1 /* Copyright (C) 2019, 2020, 2023, 2024 |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 #ifndef STAR_GEOMETRY3D_H__
     17 #define STAR_GEOMETRY3D_H__
     18 
     19 #include <rsys/rsys.h>
     20 #include <rsys/dynamic_array_uint.h>
     21 
     22 #include <limits.h>
     23 
     24 /* Library symbol management */
     25 #if defined(SG3D_SHARED_BUILD)
     26   #define SG3D_API extern EXPORT_SYM
     27 #elif defined(SG3D_STATIC_BUILD)
     28   #define SG3D_API extern LOCAL_SYM
     29 #else /* Use shared library */
     30   #define SG3D_API extern IMPORT_SYM
     31 #endif
     32 
     33 /* Helper macro that asserts if the invocation of the star-geometry-3d function
     34  * `Func' returns an error. One should use this macro on star-geometry-3d
     35  * function calls for which no explicit error checking is performed. */
     36 #ifndef NDEBUG
     37 #define SG3D(Func) ASSERT(sg3d_ ## Func == RES_OK)
     38 #else
     39 #define SG3D(Func) sg3d_ ## Func
     40 #endif
     41 
     42 /* Forward declaration of external opaque data types */
     43 struct logger;
     44 struct mem_allocator;
     45 struct senc_scene;
     46 
     47 /* Forward declaration of the star-geometry-3d opaque data types. These data
     48  * types are ref counted. Once created the caller implicitly owns the created
     49  * data, i.e. its reference counter is set to 1. The sg3d_<TYPE>_ref_<get|put>
     50  * functions get or release a reference on the data, i.e. they increment or
     51  * decrement the reference counter, respectively. When this counter reaches 0,
     52  * the object is silently destroyed and cannot be used anymore. */
     53 struct sg3d_device;
     54 struct sg3d_geometry;
     55 
     56 /******************************************************************************
     57  * The dimension of the geometry used in the library.
     58  *****************************************************************************/
     59 #define SG3D_GEOMETRY_DIMENSION 3
     60 
     61 /******************************************************************************
     62  * A type to list the different user properties attached to triangles.
     63  *****************************************************************************/
     64 enum sg3d_property_type {
     65   SG3D_FRONT,
     66   SG3D_BACK,
     67   SG3D_INTFACE,
     68   SG3D_PROP_TYPES_COUNT__
     69 };
     70 
     71 /******************************************************************************
     72  * A type to list the different possible partitions of triangles.
     73  *****************************************************************************/
     74 enum sg3d_obj_dump_content {
     75   SG3D_OBJ_DUMP_MERGE_CONFLICTS = BIT(0),
     76   SG3D_OBJ_DUMP_PROPERTY_CONFLICTS = BIT(1),
     77   SG3D_OBJ_DUMP_VALID_PRIMITIVE = BIT(2),
     78   SG3D_OBJ_DUMP_ALL =
     79      SG3D_OBJ_DUMP_MERGE_CONFLICTS
     80    | SG3D_OBJ_DUMP_PROPERTY_CONFLICTS
     81    | SG3D_OBJ_DUMP_VALID_PRIMITIVE
     82 };
     83 
     84 /******************************************************************************
     85  * A type to list the different qualifiers of C code variable output.
     86  *****************************************************************************/
     87 enum sg3d_c_dump_qualifiers {
     88   SG3D_C_DUMP_CONST = BIT(0),
     89   SG3D_C_DUMP_STATIC = BIT(1)
     90 };
     91 
     92 /******************************************************************************
     93  * The value that should be used for properties attached to triangles (i.e.
     94  * media or interface) when let unspecified.
     95  * SG3D_UNSPECIFIED_PROPERTY can be used for a property that has already been
     96  * defined; in this case the previous value will remain.
     97  *****************************************************************************/
     98 #define SG3D_UNSPECIFIED_PROPERTY UINT_MAX
     99 
    100 /*****************************************************************************
    101  * A type to hold callbacks for sg3d_geometry_add.
    102  ****************************************************************************/
    103 struct sg3d_geometry_add_callbacks {
    104   /* User function that provides vertices ids for added triangles */
    105   void(*get_indices)
    106     (const unsigned itri,
    107      unsigned ids[SG3D_GEOMETRY_DIMENSION],
    108      void* context);
    109   /* User function that provides properties for added triangles */
    110   void(*get_properties) /* Can be NULL <=> SG3D_UNSPECIFIED_PROPERTY used */
    111     (const unsigned itri,
    112      /* It is OK to have side and interface properties sharing the same IDs,
    113       * i.e. side and interface IDs both starting from 0 */
    114      unsigned properties[SG3D_PROP_TYPES_COUNT__],
    115      void* context);
    116   /* User function that provides coordinates for added vertices */
    117   void(*get_position)
    118     (const unsigned ivert, double pos[SG3D_GEOMETRY_DIMENSION], void* context);
    119   /* Called if the itri_th triangle of the current sg3d_geometry_add is a new
    120    * triangle (i.e. not a duplicate) so that the client app can manage its own
    121    * triangle data/properties/attributes.
    122    * If return is not RES_OK, sg3d_geometry_add stops immediately and returns
    123    * whatever value add_triangle returned. */
    124   res_T(*add_triangle) /* Can be NULL */
    125     (const unsigned unique_id, const unsigned itri, void* context);
    126   /* Called if the itri_th triangle of the current sg3d_geometry_add is a
    127    * duplicate of the unique_id_th unique triangle so that the client app can
    128    * merge its own triangle data, rule merge validity, and possibly change the
    129    * recorded properties.
    130    * The reversed_triangle arg indicates if the triangle vertices' order is
    131    * the same it was when the triangle was first added.
    132    * The merge_conflict_status argument can be set to any value. Any non-0
    133    * value is accounted for a conflict and is kept as-is in dumps, allowing
    134    * different shades of conflict.
    135    * The triangle_properties and merged_properties args contain the involved
    136    * properties. */
    137   res_T(*merge_triangle) /* Can be NULL */
    138     (const unsigned unique_id,
    139      const unsigned itri,
    140      const int reversed_triangle,
    141      unsigned triangle_properties[SG3D_PROP_TYPES_COUNT__],
    142      const unsigned merged_properties[SG3D_PROP_TYPES_COUNT__],
    143      void* context,
    144      int* merge_conflict_status);
    145   /* Called if the itri_th triangle is degenerated. According to the value
    146    * of abort, sg3d_geometry_add will stop and return RES_BAD_ARG or continue
    147    * silently. */
    148   res_T(*degenerated_triangle) /* Can be NULL <=> Drop triangle, don't abort */
    149     (const unsigned itri, void* context, int* abort);
    150 };
    151 #define SG3D_ADD_CALLBACKS_NULL__ { NULL, NULL, NULL, NULL, NULL, NULL }
    152 
    153 BEGIN_DECLS
    154 
    155 /******************************************************************************
    156  * A helper function on properties compatibility.
    157  *****************************************************************************/
    158 static INLINE int
    159 sg3d_compatible_property
    160   (const unsigned p1,
    161    const unsigned p2)
    162 {
    163   if(p1 == SG3D_UNSPECIFIED_PROPERTY || p2 == SG3D_UNSPECIFIED_PROPERTY)
    164     return 1;
    165   return (p1 == p2);
    166 }
    167 
    168 /******************************************************************************
    169  * star-geometry-3d device. It is an handle toward the star-geometry-3d
    170  * library. It manages the star-geometry-3d resources.
    171  *****************************************************************************/
    172 SG3D_API res_T
    173 sg3d_device_create
    174   (struct logger* logger, /* Can be NULL <=> use default logger */
    175    struct mem_allocator* allocator, /* Can be NULL <=> use default allocator */
    176    const int verbose, /* Verbosity level */
    177    struct sg3d_device** dev);
    178 
    179 SG3D_API res_T
    180 sg3d_device_ref_get
    181   (struct sg3d_device* dev);
    182 
    183 SG3D_API res_T
    184 sg3d_device_ref_put
    185   (struct sg3d_device* dev);
    186 
    187 /******************************************************************************
    188  * star-geometry-3d geometry.
    189  * It stores decorated geometry accumulated through calls to sg3d_geometry_add,
    190  * information related to this geometry and its creation process, including
    191  * merge conflicts.
    192  *****************************************************************************/
    193 /* Create a geometry that can be used to accumulate vertices and triangles
    194  * decorated with properties. */
    195 SG3D_API res_T
    196 sg3d_geometry_create
    197   (struct sg3d_device* dev,
    198    struct sg3d_geometry** geometry);
    199 
    200 /* Reserve memory according to anticipated geometry size. */
    201 SG3D_API res_T
    202 sg3d_geometry_reserve
    203   (struct sg3d_geometry* geometry,
    204    const unsigned vertices_count,
    205    const unsigned triangles_count,
    206    const unsigned properties_count);
    207 
    208 /* Add a new set of 3D vertices and triangles to the geometry; triangles can
    209  * be decorated with 3 properties (front and back media and interface) that can
    210  * be let unspecified using the SG3D_UNSPECIFIED_PROPERTY special value.
    211  * Vertices can be duplicates and are silently deduplicated, always valid.
    212  * Triangles can be duplicates, but this can be ruled invalid due to property
    213  * inconsistency. Triangle duplicates are silently deduplicated, even if
    214  * invalid. Consistency is to be understood as the consistency of the
    215  * successive values for the same property across calls of sg3d_geometry_add,
    216  * not as the consistency of the values of the 3 properties of a triangle at
    217  * some given time (this question has its own callback (validate) in the
    218  * sg3d_geometry_validate_properties API call).
    219  * Duplicate triangles validity is either ruled by the user-provided
    220  * merge_triangle callback, or is just a matter of properties consistency if no
    221  * callback is provided. In either case, sg3d_geometry_add never stops
    222  * prematurely nor returns an error code due to a merge conflict.
    223  * - if provided, the callback must return the consistency status using the
    224  *   merge_conflict_status int* paramater (0 for consistent; any other value
    225  *   for inconsistent, this value being recorded); regardless of
    226  *   merge_conflict_status, the callback can change the properties of the
    227  *   triangle before the SG3D_UNSPECIFIED_PROPERTY overwriting step;
    228  * - if not, a non-SG3D_UNSPECIFIED_PROPERTY is only consistent with itself and
    229  *   with SG3D_UNSPECIFIED_PROPERTY (if inconsistent, merge_conflict_status is
    230  *   set to 1 and recorded) ; regardless of merge_conflict_status, a
    231  *   non-SG3D_UNSPECIFIED_PROPERTY property is never overridden.
    232  * When deduplicating triangles, the first occurence remains (with its
    233  * original index in user world). After consistency being computed, a final
    234  * step consists in rewriting SG3D_UNSPECIFIED_PROPERTY properties if the
    235  * merged property is defined. */
    236 SG3D_API res_T
    237 sg3d_geometry_add
    238   (struct sg3d_geometry* geometry,
    239    const unsigned vertices_count,
    240    const unsigned triangles_count,
    241    const struct sg3d_geometry_add_callbacks* callbacks,
    242    void* context); /* Can be NULL */
    243 
    244 /* Apply a validation callback on each triangle included in this geometry that
    245  * is not already flagged with a merge error. If validate returns a non-RES_OK
    246  * value, the validation stops and returns the same error value; on the other
    247  * hand, validation goes to the end regardless of properties conflicts.
    248  * The properties_conflict_status argument can be set to any value. Any non-0
    249  * value is accounted for a conflict and is kept as-is in dumps, allowing
    250  * different shades of conflict.
    251  * If validation is processed again, the properties conflict count is reset,
    252  * as well as the properties_conflict_status status of the triangles. */
    253 SG3D_API res_T
    254 sg3d_geometry_validate_properties
    255   (struct sg3d_geometry* geometry,
    256    res_T(*validate)
    257      (const unsigned itri,
    258       const unsigned properties[SG3D_PROP_TYPES_COUNT__],
    259       void* context,
    260       int* properties_conflict_status),
    261    void* context); /* Can be NULL */
    262 
    263 /* Get the number of unique vertices. */
    264 SG3D_API res_T
    265 sg3d_geometry_get_unique_vertices_count
    266   (const struct sg3d_geometry* geometry,
    267    unsigned* count);
    268 
    269 /* Get the ivtx_th vertex. */
    270 SG3D_API res_T
    271 sg3d_geometry_get_unique_vertex
    272   (const struct sg3d_geometry* geometry,
    273    const unsigned ivtx,
    274    double coord[SG3D_GEOMETRY_DIMENSION]);
    275 
    276 /* Get the number of triangles added to the geometry, regardless of unicity. */
    277 SG3D_API res_T
    278 sg3d_geometry_get_added_triangles_count
    279   (const struct sg3d_geometry* geometry,
    280    unsigned* count);
    281 
    282 /* Get the number of unique triangles. */
    283 SG3D_API res_T
    284 sg3d_geometry_get_unique_triangles_count
    285   (const struct sg3d_geometry* geometry,
    286    unsigned* count);
    287 
    288 /* Get the vertex indices of the itri_th unique triangle. */
    289 SG3D_API res_T
    290 sg3d_geometry_get_unique_triangle_vertices
    291   (const struct sg3d_geometry* geometry,
    292    const unsigned itri,
    293    unsigned indices[SG3D_GEOMETRY_DIMENSION]);
    294 
    295 /* Get the properties of the itri_th unique triangle. */
    296 SG3D_API res_T
    297 sg3d_geometry_get_unique_triangle_properties
    298   (const struct sg3d_geometry* geometry,
    299    const unsigned itri,
    300    unsigned properties[SG3D_PROP_TYPES_COUNT__]);
    301 
    302 /* Get the user ID of the itri_th unique triangle, that is the user world's
    303  * index of the triangle that first created this unique triangle.
    304  * User world index starts at 0 and increases for every triangle that is
    305  * submitted to sg3d_geometry_add calls, regardless of duplication or
    306  * sg3d_geometry_add failures (non-RES_OK return value). */
    307 SG3D_API res_T
    308 sg3d_geometry_get_unique_triangle_user_id
    309   (const struct sg3d_geometry* geometry,
    310    const unsigned itri,
    311    unsigned* user_id);
    312 
    313 /* Get the number of triangles with (at least) one unspecified side. */
    314 SG3D_API res_T
    315 sg3d_geometry_get_unique_triangles_with_unspecified_side_count
    316   (const struct sg3d_geometry* geometry,
    317    unsigned* count);
    318 
    319 /* Get the number of triangles with unspecified interface. */
    320 SG3D_API res_T
    321 sg3d_geometry_get_unique_triangles_with_unspecified_interface_count
    322   (const struct sg3d_geometry* geometry,
    323    unsigned* count);
    324 
    325 /* Get the number of triangles flagged with a merge conflict. */
    326 SG3D_API res_T
    327 sg3d_geometry_get_unique_triangles_with_merge_conflict_count
    328   (const struct sg3d_geometry* geometry,
    329    unsigned* count);
    330 
    331 /* Get the number of triangles flagged with a property conflict. Only
    332  * meaningful after sg3d_geometry_validate_properties has been called. */
    333 SG3D_API res_T
    334 sg3d_geometry_get_unique_triangles_with_properties_conflict_count
    335   (const struct sg3d_geometry* geometry,
    336    unsigned* count);
    337 
    338 /* Dump a geometry in the provided stream in the OBJ format.
    339  * The geometry can include conflicts, but cannot be empty.
    340  * The dump is made of the vertices and some triangles, without their
    341  * properties. The dumped triangles are defined by the flags argument, that
    342  * must be ORed enum sg3d_obj_dump_content values.
    343  * The dumped triangles are partitioned in the following groups:
    344  * - Valid_triangles
    345  * - Merge_conflicts
    346  * - Property_conflict */
    347 SG3D_API res_T
    348 sg3d_geometry_dump_as_obj
    349   (const struct sg3d_geometry* geometry,
    350    FILE* stream,
    351    int flags);
    352 
    353 /* Dump a geometry in the provided stream in the VTK ascii format.
    354  * The geometry can include conflicts, but cannot be empty.
    355  * The dump is made of the vertices and triangles, with most of their
    356  * properties:
    357  * - Front_medium (medium ID of the front side, INT_MAX for both unspecified
    358  *   and conflicted)
    359  * - Back_medium (medium ID of the back side, INT_MAX for both unspecified and
    360  *   conflicted)
    361  * - Interface (interface ID, INT_MAX for both unspecified and conflicted)
    362  * - Merge_conflict (merge conflict status)
    363  * - Property_conflict (property conflict status)
    364  * - Created_at_sg3d_geometry_add (rank of the sg3d_geometry_add that created
    365  *   the triangle) */
    366 SG3D_API res_T
    367 sg3d_geometry_dump_as_vtk
    368   (const struct sg3d_geometry* geometry,
    369    FILE* stream);
    370 
    371 /* Dump the geometry as C code.
    372  * The geometry cannot be empty and must be conflict-free.
    373  * The C code defines the 3 variables:
    374  * - [static] [const] unsigned <name_prefix>_vertices_count = N1;
    375  * - [static] [const] double <name_prefix>_vertices[<N1>] = { .... };
    376  * - [static] [const] unsigned <name_prefix>_triangles_count = N2;
    377  * - [static] [const] unsigned <name_prefix>_triangles[<N2>] = { .... };
    378  * - [static] [const] unsigned <name_prefix>_properties[<N2>] = { .... };
    379  * Where <N1> is 3 * vertices_count and <N2> is 3 * triangles_count.
    380  * The two qualifiers static and const are output or not according to flags;
    381  * flags must be ORed enum sg3d_c_dump_qualifiers values. */
    382 SG3D_API res_T
    383 sg3d_geometry_dump_as_c_code
    384   (const struct sg3d_geometry* geometry,
    385    FILE* stream,
    386    const char* name_prefix, /* Can be NULL or "" */
    387    const int flags);
    388 
    389 SG3D_API res_T
    390 sg3d_geometry_ref_get
    391   (struct sg3d_geometry* geometry);
    392 
    393 SG3D_API res_T
    394 sg3d_geometry_ref_put
    395   (struct sg3d_geometry* geometry);
    396 
    397 END_DECLS
    398 
    399 #endif /* STAR_GEOMETRY3D_H__ */