star-uvm

Spatial structuring of unstructured volumetric meshes
git clone git://git.meso-star.fr/star-uvm.git
Log | Files | Refs | README | LICENSE

suvm_volume.h (7809B)


      1 /* Copyright (C) 2020-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 SUVM_VOLUME_H
     17 #define SUVM_VOLUME_H
     18 
     19 #include "suvm_backend.h"
     20 
     21 #include <rsys/dynamic_array_u32.h>
     22 #include <rsys/dynamic_array_float.h>
     23 #include <rsys/float3.h>
     24 #include <rsys/ref_count.h>
     25 
     26 /*
     27  * Tetrahedron geometric layout
     28  *
     29  *        3 (top vertex)  facet 0 = {0,1,2}
     30  *        +               facet 1 = {0,3,1}
     31  *       /|`.             facet 2 = {1,3,2}
     32  *      / |  `.           facet 3 = {2,3,0}
     33  *     /  |    `.
     34  *    /   |      `.
     35  * 0 +....|.........+ 2
     36  *    `.  |    _,-'
     37  *      `,|_,-'
     38  *        +
     39  *        1
     40  */
     41 
     42 /* Forward declarations */
     43 struct suvm_device;
     44 struct mem_allocator;
     45 
     46 struct buffer {
     47   void* mem; /* Raw memory block storing the data */
     48   size_t elmt_size; /* Size in bytes of one data */
     49   size_t elmt_stride; /* Size in bytes between two consecutive data */
     50   size_t elmt_alignment; /* Data alignment */
     51   size_t size; /* #data */
     52   struct mem_allocator* allocator;
     53 };
     54 static const struct buffer BUFFER_NULL;
     55 
     56 enum node_type { NODE_INNER, NODE_LEAF };
     57 
     58 /* Generic node */
     59 struct node {
     60   enum node_type type;
     61 };
     62 
     63 /* Generate the dynamic array of BVH node */
     64 #define DARRAY_NAME node
     65 #define DARRAY_DATA struct node*
     66 #include <rsys/dynamic_array.h>
     67 
     68 /* Inner node */
     69 struct ALIGN(16) node_inner {
     70   float low[2][3];
     71   float upp[2][3];
     72   struct node* children[2];
     73   struct node node;
     74 };
     75 
     76 /* Leaf node */
     77 struct ALIGN(16) node_leaf {
     78   float low[3];
     79   uint32_t geom_id;
     80   float upp[3];
     81   uint32_t prim_id;
     82   struct node node;
     83 };
     84 
     85 struct suvm_volume {
     86   struct darray_u32 indices; /* List of uint32_t[4] */
     87   struct darray_float positions; /* List of float[3] */
     88   struct darray_float normals; /* List of per tetrahedron facet normals */
     89   struct buffer prim_data; /* Per primitive data */
     90   struct buffer vert_data; /* Per vertex data */
     91 
     92   int has_prim_data;
     93   int has_vert_data;
     94 
     95   float low[3], upp[3]; /* Volume AABB */
     96 
     97   RTCBVH bvh;
     98   struct node* bvh_root;
     99 
    100   struct suvm_device* dev;
    101   ref_T ref;
    102 };
    103 
    104 static FINLINE size_t
    105 volume_get_primitives_count(const struct suvm_volume* vol)
    106 {
    107   size_t sz = 0;
    108   ASSERT(vol);
    109   sz = darray_u32_size_get(&vol->indices);
    110   ASSERT(sz % 4/*#vertices per tetrahedron*/ == 0);
    111   return sz / 4;
    112 }
    113 
    114 static FINLINE size_t
    115 volume_get_vertices_count(const struct suvm_volume* vol)
    116 {
    117   size_t sz = 0;
    118   ASSERT(vol);
    119   sz = darray_float_size_get(&vol->positions);
    120   ASSERT(sz % 3/*#coords per vertex*/ == 0);
    121   return sz / 3;
    122 }
    123 
    124 static FINLINE size_t*
    125 volume_primitive_get_indices
    126   (const struct suvm_volume* vol,
    127    const size_t iprim,
    128    size_t indices[4])
    129 {
    130   const uint32_t* ids;
    131   ASSERT(vol && indices && iprim < volume_get_primitives_count(vol));
    132   ids = darray_u32_cdata_get(&vol->indices) + iprim*4/*#vertices per tetra*/;
    133   indices[0] = (size_t)ids[0];
    134   indices[1] = (size_t)ids[1];
    135   indices[2] = (size_t)ids[2];
    136   indices[3] = (size_t)ids[3];
    137   return indices;
    138 }
    139 
    140 static FINLINE float*
    141 volume_primitive_get_vertex_position
    142   (const struct suvm_volume* vol,
    143    const size_t iprim,
    144    const size_t ivert, /* In [0, 3] */
    145    float pos[3])
    146 {
    147   const uint32_t* ids;
    148   ASSERT(vol && iprim < volume_get_primitives_count(vol) && pos && ivert < 4);
    149   ids = darray_u32_cdata_get(&vol->indices) + iprim*4/*#vertex per tetra*/;
    150   pos[0] = darray_float_cdata_get(&vol->positions)[ids[ivert]*3 + 0];
    151   pos[1] = darray_float_cdata_get(&vol->positions)[ids[ivert]*3 + 1];
    152   pos[2] = darray_float_cdata_get(&vol->positions)[ids[ivert]*3 + 2];
    153   return pos;
    154 }
    155 
    156 static INLINE float*
    157 volume_primitive_compute_facet_normal
    158   (const struct suvm_volume* vol,
    159    const size_t iprim,
    160    const int ifacet/*In [0,3]*/,
    161    float normal[3])
    162 {
    163   const uint32_t* ids;
    164   const float* v0;
    165   const float* v1;
    166   const float* v2;
    167 
    168   float E0[3], E1[3];
    169 
    170   /* Facet indices, Ensure CCW ordering */
    171   const int facet[4][3] = {{0,1,2}, {0,3,1}, {1,3,2}, {2,3,0}};
    172 
    173   ASSERT(vol && iprim < volume_get_primitives_count(vol) && normal);
    174   ASSERT(ifacet < 4);
    175 
    176   /* Fetch tetrahedron indices */
    177   ids = darray_u32_cdata_get(&vol->indices) + iprim*4;
    178 
    179   /* Fetch facet vertices */
    180   v0 = darray_float_cdata_get(&vol->positions) + ids[facet[ifacet][0]]*3;
    181   v1 = darray_float_cdata_get(&vol->positions) + ids[facet[ifacet][1]]*3;
    182   v2 = darray_float_cdata_get(&vol->positions) + ids[facet[ifacet][2]]*3;
    183 
    184   /* Compute the normal */
    185   f3_sub(E0, v1, v0);
    186   f3_sub(E1, v2, v0);
    187   f3_cross(normal, E0, E1);
    188   f3_normalize(normal, normal);
    189 
    190   return normal;
    191 }
    192 
    193 static FINLINE float*
    194 volume_primitive_get_facet_normal
    195   (const struct suvm_volume* vol,
    196    const size_t iprim,
    197    const int ifacet, /* In [0, 3] */
    198    float normal[3])
    199 {
    200   ASSERT(vol && iprim < volume_get_primitives_count(vol) && normal);
    201   ASSERT(ifacet < 4);
    202 
    203   if(!darray_float_size_get(&vol->normals)) {
    204     volume_primitive_compute_facet_normal(vol, iprim, ifacet, normal);
    205   } else {
    206     const size_t id =
    207       (iprim*4/*#facets per tetra*/ + (size_t)ifacet)*3/*#coords per normal*/;
    208     ASSERT(id + 3 <= darray_float_size_get(&vol->normals));
    209     normal[0] = darray_float_cdata_get(&vol->normals)[id+0];
    210     normal[1] = darray_float_cdata_get(&vol->normals)[id+1];
    211     normal[2] = darray_float_cdata_get(&vol->normals)[id+2];
    212   }
    213   return normal;
    214 }
    215 
    216 static INLINE const void*
    217 buffer_at(const struct buffer* buf, const size_t i)
    218 {
    219   void* data;
    220   ASSERT(buf && i < buf->size);
    221   data = (char*)buf->mem + i * buf->elmt_stride;
    222   ASSERT(IS_ALIGNED(data, buf->elmt_alignment));
    223   return data;
    224 }
    225 
    226 static INLINE const void*
    227 volume_primitive_get_data(const struct suvm_volume* vol, const size_t iprim)
    228 {
    229   ASSERT(vol && vol->has_prim_data && iprim < volume_get_primitives_count(vol));
    230   return buffer_at(&vol->prim_data, iprim);
    231 }
    232 
    233 static INLINE const void*
    234 volume_primitive_get_vertex_data
    235   (const struct suvm_volume* vol,
    236    const size_t iprim,
    237    const size_t ivert /* In [0, 3] */)
    238 {
    239   const uint32_t* ids;
    240   ASSERT(vol && vol->has_vert_data && iprim < volume_get_primitives_count(vol));
    241   ASSERT(ivert < 4);
    242   ids = darray_u32_cdata_get(&vol->indices) + iprim*4/*#vertex per tetra*/;
    243   return buffer_at(&vol->vert_data, ids[ivert]);
    244 }
    245 
    246 static INLINE void
    247 volume_primitive_setup
    248   (const struct suvm_volume* vol,
    249    const size_t iprim,
    250    struct suvm_primitive* prim)
    251 {
    252   ASSERT(vol && prim && iprim < volume_get_primitives_count(vol));
    253   prim->nvertices = 4;
    254   prim->iprim = iprim;
    255   prim->volume__ = vol;
    256   volume_primitive_get_indices(vol, prim->iprim, prim->indices);
    257   if(vol->has_prim_data) {
    258     prim->data = volume_primitive_get_data(vol, prim->iprim);
    259   }
    260   if(vol->has_vert_data) {
    261     prim->vertex_data[0] = volume_primitive_get_vertex_data(vol, iprim, 0);
    262     prim->vertex_data[1] = volume_primitive_get_vertex_data(vol, iprim, 1);
    263     prim->vertex_data[2] = volume_primitive_get_vertex_data(vol, iprim, 2);
    264     prim->vertex_data[3] = volume_primitive_get_vertex_data(vol, iprim, 3);
    265   }
    266 }
    267 
    268 extern LOCAL_SYM void
    269 tetrahedron_setup
    270   (const struct suvm_volume* vol,
    271    const float low[3], /* NULL <=> compute on the fly */
    272    const float upp[3], /* NULL <=> compute on the fly */
    273    const size_t iprim,
    274    struct suvm_polyhedron* polyhedron);
    275 
    276 #endif /* SUVM_VOLUME_H */
    277