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