star-2d

Contour structuring for efficient 2D geometric queries
git clone git://git.meso-star.fr/star-2d.git
Log | Files | Refs | README | LICENSE

s2d.h (16901B)


      1 /* Copyright (C) 2016-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 #ifndef S2D_H
     17 #define S2D_H
     18 
     19 #include <rsys/rsys.h>
     20 #include <float.h>
     21 
     22 /* Library symbol management */
     23 #if defined(S2D_SHARED_BUILD) /* Build shared library */
     24   #define S2D_API extern EXPORT_SYM
     25 #elif defined(S2D_STATIC) /* Use/build static library */
     26   #define S2D_API extern LOCAL_SYM
     27 #else /* Use shared library */
     28   #define S2D_API extern IMPORT_SYM
     29 #endif
     30 
     31 /* Helper macro that asserts if the invocation of the s2d function `Func'
     32  * returns an error. One should use this macro on s2d function calls for which
     33  * no explicit error checking is performed */
     34 #ifndef NDEBUG
     35   #define S2D(Func) ASSERT(s2d_ ## Func == RES_OK)
     36 #else
     37   #define S2D(Func) s2d_ ## Func
     38 #endif
     39 
     40 /* Syntactic sugar use during the setup of the shape. Setting a vertex data
     41  * functor to S2D_KEEP means that this vertex data will not be updated */
     42 #define S2D_KEEP NULL
     43 
     44 #define S2D_INVALID_ID ((unsigned)-1) /* Value of an invalid identifer */
     45 
     46 enum s2d_attrib_usage {
     47   S2D_POSITION, /* World space position */
     48   S2D_ATTRIB_0, /* Generic attrib 0 */
     49   S2D_ATTRIB_1, /* Generic attrib 1 */
     50   S2D_ATTRIB_2, /* Generic attrib 2 */
     51   S2D_ATTRIB_3, /* Generic attrib 3 */
     52   S2D_ATTRIBS_COUNT__,
     53   /* Unormalized world space face normal. For line segments, the outward
     54    * orientation is defined with respect to the Clock Wise vertex ordering */
     55   S2D_GEOMETRY_NORMAL
     56 };
     57 
     58 enum s2d_type {
     59   S2D_FLOAT,
     60   S2D_FLOAT2,
     61   S2D_FLOAT3
     62 };
     63 
     64 /* Primitive descriptor. The geom indentifier covers a compact ranges of value.
     65  * They can be used in conjunction with a dynamic array to map from s2d
     66  * geometry to application geometry */
     67 struct s2d_primitive {
     68   unsigned prim_id; /* Primitive identifier */
     69   unsigned geom_id; /* Geometry identifier */
     70   unsigned scene_prim_id; /* Identifier of the primitive in the scene */
     71   /* Internal data. Should not be accessed  */
     72   void* mesh__;
     73 };
     74 
     75 #define S2D_PRIMITIVE_NULL__ {                                                 \
     76   S2D_INVALID_ID, S2D_INVALID_ID, S2D_INVALID_ID, NULL                         \
     77 }
     78 static const struct s2d_primitive S2D_PRIMITIVE_NULL = S2D_PRIMITIVE_NULL__;
     79 
     80 /* Helper macro that defines whether or not 2 primitives are equal */
     81 #define S2D_PRIMITIVE_EQ(Prim0, Prim1)                                         \
     82   (  (Prim0)->prim_id == (Prim1)->prim_id                                      \
     83   && (Prim0)->geom_id == (Prim1)->geom_id)
     84 
     85 /* Untyped vertex attribute */
     86 struct s2d_attrib {
     87   float value[3];
     88   enum s2d_type type;
     89   enum s2d_attrib_usage usage;
     90 };
     91 
     92 /* Describe a per vertex data */
     93 struct s2d_vertex_data {
     94   /* Semantic of the data. Note that the S2D_GEOMETRY_NORMAL is not a valid
     95    * vertex usage */
     96   enum s2d_attrib_usage usage;
     97   enum s2d_type type;
     98   /* Retreive the vertex data value of `ivert'. Set it to S2D_KEEP, to keep the
     99    * previously set data */
    100   void (*get)
    101     (const unsigned ivert, /* Index of the vertex */
    102      float* value, /* Retrieved attrib value */
    103      void* ctx); /* Pointer to user data */
    104 };
    105 
    106 /* Invalid vertex data */
    107 #define S2D_VERTEX_DATA_NULL__ { S2D_ATTRIBS_COUNT__, S2D_FLOAT, NULL }
    108 static const struct s2d_vertex_data S2D_VERTEX_DATA_NULL = S2D_VERTEX_DATA_NULL__;
    109 
    110 /* Intersection point */
    111 struct s2d_hit {
    112   struct s2d_primitive prim; /* Intersected primitive */
    113   float normal[2]; /* Unormalized geometry normal (left hand convention) */
    114   float u; /* Barycentric coordinates onto `prim'. pos = (1 - u)*v0 + u*v1 */
    115   float distance; /* Hit distance from the ray origin */
    116 };
    117 
    118 /* Constant defining a NULL intersection. Should be used to initialize a hit */
    119 #define S2D_HIT_NULL__ {                                                       \
    120   S2D_PRIMITIVE_NULL__,                                                        \
    121   { 0.f, 0.f },                                                                \
    122   0.f,                                                                         \
    123   FLT_MAX                                                                      \
    124 }
    125 static const struct s2d_hit S2D_HIT_NULL = S2D_HIT_NULL__;
    126 
    127 /* Helper macro that defines whether or not the hit is valid, i.e. the ray
    128  * intersects a shape or not */
    129 #define S2D_HIT_NONE(Hit) ((Hit)->distance >= FLT_MAX)
    130 
    131 enum s2d_scene_view_flag {
    132   S2D_TRACE = BIT(0),
    133   S2D_SAMPLE = BIT(1),
    134   S2D_GET_PRIMITIVE = BIT(2)
    135 };
    136 
    137 /* Filter function data type. One can define such function to discard
    138  * intersections along a ray or the result of a closest point query with
    139  * respect to user defined criteria, e.g.: masked/transparent primitive, etc.
    140  * Return 0 if the intersection is not discarded and a value not equal to zero
    141  * otherwise. */
    142 typedef int
    143 (*s2d_hit_filter_function_T)
    144   (const struct s2d_hit* hit,
    145    const float ray_org[2],
    146    const float ray_dir[],
    147    const float ray_range[2],
    148    void* ray_data, /* User data submitted on trace ray(s) invocation */
    149    void* filter_data); /* Data defined on the setup of the filter function */
    150 
    151 /* Forward declaration of s2d opaque data types */
    152 struct s2d_device;
    153 struct s2d_scene;
    154 struct s2d_scene_view;
    155 struct s2d_shape;
    156 
    157 /* Forward declaration of external data types */
    158 struct logger;
    159 struct mem_allocator;
    160 
    161 BEGIN_DECLS
    162 
    163 /*******************************************************************************
    164  * Device API - entry point of the s2d library
    165  ******************************************************************************/
    166 S2D_API res_T
    167 s2d_device_create
    168   (struct logger* logger, /* May be NULL <=> use default logger */
    169    struct mem_allocator* allocator, /* May be NULL <=> use default allocator */
    170    const int verbose, /* Define the level of verbosity */
    171    struct s2d_device** dev);
    172 
    173 S2D_API res_T
    174 s2d_device_ref_get
    175   (struct s2d_device* dev);
    176 
    177 S2D_API res_T
    178 s2d_device_ref_put
    179   (struct s2d_device* dev);
    180 
    181 /*******************************************************************************
    182  * Scene API - collection of shapes
    183  ******************************************************************************/
    184 S2D_API res_T
    185 s2d_scene_create
    186   (struct s2d_device* dev,
    187    struct s2d_scene** scn);
    188 
    189 S2D_API res_T
    190 s2d_scene_ref_get
    191   (struct s2d_scene* scn);
    192 
    193 S2D_API res_T
    194 s2d_scene_ref_put
    195   (struct s2d_scene* scn);
    196 
    197 /* Attach the shape to the scene. On success, the scene gets a reference onto
    198  * the attached shape */
    199 S2D_API res_T
    200 s2d_scene_attach_shape
    201   (struct s2d_scene* scn,
    202    struct s2d_shape* shape);
    203 
    204 /* Remove the shape from the scene. After its detachment, the scene
    205  * release its reference on the shape */
    206 S2D_API res_T
    207 s2d_scene_detach_shape
    208   (struct s2d_scene* scn,
    209    struct s2d_shape* shape);
    210 
    211 /* Detach all the shapes from the scene and release the reference that the
    212  * scene takes onto them */
    213 S2D_API res_T
    214 s2d_scene_clear
    215   (struct s2d_scene* scn);
    216 
    217 /* Retrieve the device from which the scene was created */
    218 S2D_API res_T
    219 s2d_scene_get_device
    220   (struct s2d_scene* scn,
    221    struct s2d_device** dev);
    222 
    223 S2D_API res_T
    224 s2d_scene_get_shapes_count
    225   (struct s2d_scene* scn,
    226    size_t* nshapes);
    227 
    228 /*******************************************************************************
    229  * Scene view API - State of the scene geometry
    230  ******************************************************************************/
    231 S2D_API res_T
    232 s2d_scene_view_create
    233   (struct s2d_scene* scn,
    234    const int mask, /* Combination of s2d_scene_view_flag */
    235    struct s2d_scene_view** scnview);
    236 
    237 S2D_API res_T
    238 s2d_scene_view_ref_get
    239   (struct s2d_scene_view* scnview);
    240 
    241 S2D_API res_T
    242 s2d_scene_view_ref_put
    243   (struct s2d_scene_view* scnview);
    244 
    245 S2D_API res_T
    246 s2d_scene_view_get_mask
    247   (struct s2d_scene_view* scnview,
    248    int* mask);
    249 
    250 /* Trace a ray into the `scn' and return the closest intersection. The ray is
    251  * defined by `origin' + t*`direction' = 0 with t in [`range[0]', `range[1]').
    252  * Note that if range is degenerated (i.e. `range[0]' >= `range[1]') then the
    253  * ray is not traced and `hit' is set to S2D_HIT_NULL. Can be called only if
    254  * the scnview was created with the S2D_TRACE flag. */
    255 S2D_API res_T
    256 s2d_scene_view_trace_ray
    257   (struct s2d_scene_view* scnview,
    258    const float origin[2], /* Ray origin */
    259    const float direction[2], /* Ray direction. Must be normalized */
    260    const float range[2], /* In [0, INF)^2 */
    261    void* ray_data, /* User ray data sent to the hit filter func. May be NULL */
    262    struct s2d_hit* hit);
    263 
    264 /* Trace a 3D ray into `scn' and return the closest intersection. The third
    265  * dimension of the scene primitives is assumed to be infinite, i.e. the
    266  * contours are extruded to the infinity in Z. The ray is defined by `origin' +
    267  * t*`direction' = 0 with t in [`range[0]', `range[1]'). The ray range as well
    268  * as the potential hit distance are expressed with respect to the 3D
    269  * direction. Note that if range is degenerated (i.e.  `range[0]' >=
    270  * `range[1]') then the ray is not traced and `hit' is set to S2D_HIT_NULL. Can
    271  * be called only if te scnview was created with the S2D_TRACE flag. */
    272 S2D_API res_T
    273 s2d_scene_view_trace_ray_3d
    274   (struct s2d_scene_view* scnview,
    275    const float origin[2],
    276    const float dir[3],
    277    const float range[2],
    278    void* ray_data,
    279    struct s2d_hit* hit);
    280 
    281 /* Return the point onto the scene segments that is the closest of the
    282  * submitted `pos'. Note that even though only one point is returned, several
    283  * position can have the same minimal distance to the queried position. The
    284  * `radius' parameter defines the maximum search distance around `pos'. Each
    285  * candidate position are internally filtered by the hit_filter_function
    286  * attached to the corresponding shape; the user can thus reject a candidate
    287  * position according to its own criteria.  This function can be called only if
    288  * the scnview was created with the S2D_TRACE flag which is actually the flag
    289  * used to tell Star-2D to internally build an acceleration structure on which
    290  * this function relies. */
    291 S2D_API res_T
    292 s2d_scene_view_closest_point
    293   (struct s2d_scene_view* scnview,
    294    const float pos[2], /* Position to query */
    295    const float radius, /* Search distance in [0, radius[ */
    296    void* query_data, /* User data sent to the hit filter func. May be NULL */
    297    struct s2d_hit* hit);
    298 
    299 /* Uniformly sample the scene and returned the sampled primitive and its sample
    300  * position. Can be called only if the scnview was created with the
    301  * S2D_SAMPLE flag */
    302 S2D_API res_T
    303 s2d_scene_view_sample
    304   (struct s2d_scene_view* scnview,
    305    const float u, const float v, /* Random numbers in [0, 1) */
    306    struct s2d_primitive* primitive, /* Sampled primitive */
    307    float* s); /* Sampled parametric coordinates on the primitive */
    308 
    309 /* Retrieve a primitive from the scene. Can be called only if the scnview was
    310  * created with the S2D_GET_PRIMITIVE flag */
    311 S2D_API res_T
    312 s2d_scene_view_get_primitive
    313   (struct s2d_scene_view* scnview,
    314    const unsigned iprim, /* in [0, #prims) */
    315    struct s2d_primitive* prim);
    316 
    317 /* Retrieve the number of scene primitives. Can be called only if the scnview
    318  * was created with the S2D_GET_PRIMITIVE flag */
    319 S2D_API res_T
    320 s2d_scene_view_primitives_count
    321   (struct s2d_scene_view* scnview,
    322    size_t* primitives_count);
    323 
    324 /* Compute the overall length of the shape contours */
    325 S2D_API res_T
    326 s2d_scene_view_compute_contour_length
    327   (struct s2d_scene_view* scnview,
    328    float* length);
    329 
    330 /* This function assumes that the scene defines a closed polygon and that the
    331  * normals point into the polygon. */
    332 S2D_API res_T
    333 s2d_scene_view_compute_area
    334   (struct s2d_scene_view* scnview,
    335    float* area);
    336 
    337 /* Retrieve the Axis Aligned Bounding Box of the scene. */
    338 S2D_API res_T
    339 s2d_scene_view_get_aabb
    340   (struct s2d_scene_view* scnview,
    341    float lower[2], /* AABB lower bound */
    342    float upper[2]); /* AABB upper bound */
    343 
    344 /*******************************************************************************
    345  * Shape API - define a 2D contour that can be attached to a scene.
    346  ******************************************************************************/
    347 S2D_API res_T
    348 s2d_shape_create_line_segments
    349   (struct s2d_device* dev,
    350    struct s2d_shape** shape);
    351 
    352 S2D_API res_T
    353 s2d_shape_ref_get
    354   (struct s2d_shape* shape);
    355 
    356 S2D_API res_T
    357 s2d_shape_ref_put
    358   (struct s2d_shape* shape);
    359 
    360 /* Retrieve the id of the shape. This id covers a compact range of value.
    361  * Consequently, it can be used to map from the s2d shapes to the geometry
    362  * representation of the caller with a simple dynamic array */
    363 S2D_API res_T
    364 s2d_shape_get_id
    365   (const struct s2d_shape* shape,
    366    unsigned* id);
    367 
    368 /* Enable/disable the shape, i.e. it cannot be hit when its associated scene is
    369  * ray-traced or sampled */
    370 S2D_API res_T
    371 s2d_shape_enable
    372   (struct s2d_shape* shape,
    373    const char enable);
    374 
    375 /* Return whether or not the shape is enabled, i.e. ray-traced or sampled.
    376  * Default is 1 */
    377 S2D_API res_T
    378 s2d_shape_is_enabled
    379   (const struct s2d_shape* shape,
    380    char* is_enabled);
    381 
    382 /* Define whether the shape is attached or not */
    383 S2D_API res_T
    384 s2d_shape_is_attached
    385   (const struct s2d_shape* shape,
    386    char* is_attached);
    387 
    388 /* Flip the contour orientation, i.e. flip the normal of the contour */
    389 S2D_API res_T
    390 s2d_shape_flip_contour
    391   (struct s2d_shape* shape);
    392 
    393 /*******************************************************************************
    394  * Primitive API - Define a geometric primitive of a shape
    395  ******************************************************************************/
    396 /* Retrieve the attribute of the shape primitive `iprim' at the barycentric
    397  * coordinates `uv' */
    398 S2D_API res_T
    399 s2d_primitive_get_attrib
    400   (const struct s2d_primitive* prim,
    401    const enum s2d_attrib_usage attr, /* Attribute to retrieve */
    402    const float s, /* Parametric coordinates of `attr' on `prim' */
    403    struct s2d_attrib* attrib); /* Resulting attrib */
    404 
    405 /* Uniform sampling of the primitive */
    406 S2D_API res_T
    407 s2d_primitive_sample
    408   (const struct s2d_primitive* prim,
    409    const float u, /* Random numbers in [0, 1) */
    410    float* s); /* Sampled parametric coordinates on prim */
    411 
    412 S2D_API res_T
    413 s2d_primitive_compute_length
    414   (const struct s2d_primitive* prim,
    415    float* area);
    416 
    417 S2D_API res_T
    418 s2d_segment_get_vertex_attrib
    419   (const struct s2d_primitive* prim,
    420    const size_t ivertex, /* in [0..2[ */
    421    const enum s2d_attrib_usage usage,
    422    struct s2d_attrib* attrib); /* Resulting attrib */
    423 
    424 /*******************************************************************************
    425  * Line Segments API - manage a list of segments. Normal segments point toward
    426  * the semi space whose orientation is clock wise.
    427  ******************************************************************************/
    428 S2D_API res_T
    429 s2d_line_segments_setup_indexed_vertices
    430   (struct s2d_shape* shape,
    431    const unsigned nsegments,
    432    void (*get_indices) /* May be S2D_KEEP, i.e. do not update the indices */
    433     (const unsigned isegment, unsigned ids[2], void* ctx),
    434    const unsigned nverts,
    435    /* List of the shape vertex data. Must have at least an attrib with the
    436     * S2D_POSITION usage. */
    437    struct s2d_vertex_data attribs[],
    438    const unsigned nattribs, /* # attributes in the attribs list */
    439    void* data); /* Client data set as the last param of the callbacks */
    440 
    441 /* Copy the line segments data from `src' to `dst' */
    442 S2D_API res_T
    443 s2d_line_segments_copy
    444   (const struct s2d_shape* src,
    445    struct s2d_shape* dst);
    446 
    447 S2D_API res_T
    448 s2d_line_segments_get_vertices_count
    449   (const struct s2d_shape* shape,
    450    unsigned* nverts);
    451 
    452 S2D_API res_T
    453 s2d_line_segments_get_vertex_attrib
    454   (const struct s2d_shape* shape,
    455    const unsigned ivert,
    456    const enum s2d_attrib_usage usage,
    457    struct s2d_attrib* attrib);
    458 
    459 S2D_API res_T
    460 s2d_line_segments_get_segments_count
    461   (const struct s2d_shape* shape,
    462    unsigned* nsegments);
    463 
    464 S2D_API res_T
    465 s2d_line_segments_get_segment_indices
    466   (const struct s2d_shape* shape,
    467    const unsigned isegment,
    468    unsigned ids[2]);
    469 
    470 /* Define a intersection filter function. The filter function is invoked at
    471  * each intersection found during the s2d_scene_trace_ray calls. If func does
    472  * not return 0, then the intersection is ignored and the ray pursues its
    473  * traversal. */
    474 S2D_API res_T
    475 s2d_line_segments_set_hit_filter_function
    476   (struct s2d_shape* shape,
    477    s2d_hit_filter_function_T func,
    478    void* filter_data);
    479 
    480 S2D_API res_T
    481 s2d_line_segments_get_hit_filter_data
    482   (struct s2d_shape* shape,
    483    void** data);
    484 
    485 END_DECLS
    486 
    487 #endif /* S2D_H */
    488