suvm_volume.c (21975B)
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 #include "suvm.h" 17 #include "suvm_c.h" 18 #include "suvm_device.h" 19 #include "suvm_volume.h" 20 21 #include <rsys/cstr.h> 22 #include <rsys/dynamic_array_double.h> 23 #include <rsys/dynamic_array_size_t.h> 24 #include <rsys/ref_count.h> 25 26 /* Generate the dynamic array of RTCBuildPrimitive */ 27 #define DARRAY_NAME rtc_prim 28 #define DARRAY_DATA struct RTCBuildPrimitive 29 #define DARRAY_ALIGNMENT ALIGNOF(struct RTCBuildPrimitive) 30 #include <rsys/dynamic_array.h> 31 32 /******************************************************************************* 33 * Helper functions 34 ******************************************************************************/ 35 static INLINE int 36 check_tetrahedral_mesh_args(const struct suvm_tetrahedral_mesh_args* args) 37 { 38 return args 39 && args->ntetrahedra 40 && args->nvertices 41 && args->get_indices 42 && args->get_position; 43 } 44 45 static INLINE void 46 buffer_release(struct buffer* buf) 47 { 48 ASSERT(buf); 49 if(buf->mem) MEM_RM(buf->allocator, buf->mem); 50 *buf = BUFFER_NULL; 51 } 52 53 static res_T 54 buffer_init_from_data 55 (struct mem_allocator* mem_allocator, /* May be NULL */ 56 struct buffer* buf, 57 const struct suvm_data* data, 58 const size_t ndata, 59 void* context) 60 { 61 struct mem_allocator* allocator = NULL; 62 size_t idata; 63 res_T res = RES_OK; 64 ASSERT(buf && data && data->get && ndata); 65 66 allocator = mem_allocator ? mem_allocator : &mem_default_allocator; 67 68 *buf = BUFFER_NULL; 69 if(!data->size || !IS_POW2(data->alignment)) { 70 res = RES_BAD_ARG; 71 goto error; 72 } 73 buf->elmt_size = data->size; 74 buf->elmt_alignment = data->alignment; 75 buf->elmt_stride = ALIGN_SIZE(data->size, data->alignment); 76 buf->size = ndata; 77 buf->allocator = allocator; 78 79 /* Allocate the required memory */ 80 buf->mem = MEM_ALLOC_ALIGNED 81 (buf->allocator, buf->elmt_stride*ndata, buf->elmt_alignment); 82 if(!buf->mem) { 83 res = RES_MEM_ERR; 84 goto error; 85 } 86 87 /* Fill the buffer with the submitted data */ 88 FOR_EACH(idata, 0, ndata) { 89 char* elmt = (char*)buf->mem + idata*buf->elmt_stride; 90 data->get(idata, elmt, context); 91 92 /* Clean up padding bytes to initialise them regarding their possible 93 * hashing by the suvm_volume_compute_hash function */ 94 if(buf->elmt_stride != buf->elmt_size) { 95 memset(elmt + buf->elmt_size, 0, buf->elmt_stride - buf->elmt_size); 96 } 97 } 98 99 exit: 100 return res; 101 error: 102 buffer_release(buf); 103 goto exit; 104 } 105 106 static res_T 107 setup_tetrahedral_mesh_indices 108 (struct suvm_volume* vol, const struct suvm_tetrahedral_mesh_args* args) 109 { 110 size_t itetra; 111 res_T res = RES_OK; 112 ASSERT(vol && args); 113 114 res = darray_u32_resize 115 (&vol->indices, args->ntetrahedra*4/*#vertices per tetra*/); 116 if(res != RES_OK) goto error; 117 118 /* Locally copy the indices */ 119 FOR_EACH(itetra, 0, args->ntetrahedra) { 120 size_t tetra[4]; 121 uint32_t* tetra_u32 = darray_u32_data_get(&vol->indices)+itetra*4; 122 args->get_indices(itetra, tetra, args->context); 123 ASSERT(tetra[0] < UINT32_MAX); 124 ASSERT(tetra[1] < UINT32_MAX); 125 ASSERT(tetra[2] < UINT32_MAX); 126 ASSERT(tetra[3] < UINT32_MAX); 127 tetra_u32[0] = (uint32_t)tetra[0]; 128 tetra_u32[1] = (uint32_t)tetra[1]; 129 tetra_u32[2] = (uint32_t)tetra[2]; 130 tetra_u32[3] = (uint32_t)tetra[3]; 131 } 132 133 exit: 134 return res; 135 error: 136 darray_u32_purge(&vol->indices); 137 goto exit; 138 } 139 140 static res_T 141 setup_tetrahedral_mesh_position 142 (struct suvm_volume* vol, const struct suvm_tetrahedral_mesh_args* args) 143 { 144 size_t ivert; 145 res_T res = RES_OK; 146 ASSERT(vol && args); 147 148 res = darray_float_resize 149 (&vol->positions, args->nvertices*3/*#coords per vertex*/); 150 if(res != RES_OK) goto error; 151 152 /* Locally copy the positions */ 153 FOR_EACH(ivert, 0, args->nvertices) { 154 double vertd[3]; 155 float* vertf = darray_float_data_get(&vol->positions)+ivert*3; 156 args->get_position(ivert, vertd, args->context); 157 vertf[0] = (float)vertd[0]; 158 vertf[1] = (float)vertd[1]; 159 vertf[2] = (float)vertd[2]; 160 } 161 162 exit: 163 return res; 164 error: 165 darray_float_purge(&vol->positions); 166 goto exit; 167 } 168 169 static res_T 170 setup_tetrahedral_mesh 171 (struct suvm_volume* vol, const struct suvm_tetrahedral_mesh_args* args) 172 { 173 res_T res = RES_OK; 174 ASSERT(vol && args); 175 176 res = setup_tetrahedral_mesh_indices(vol, args); 177 if(res != RES_OK) goto error; 178 res = setup_tetrahedral_mesh_position(vol, args); 179 if(res != RES_OK) goto error; 180 181 /* Store the per tetrahedron data */ 182 if(args->tetrahedron_data.get) { 183 res = buffer_init_from_data(vol->dev->allocator, &vol->prim_data, 184 &args->tetrahedron_data, args->ntetrahedra, args->context); 185 if(res != RES_OK) goto error; 186 vol->has_prim_data = 1; 187 } 188 189 /* Store the per vertex data */ 190 if(args->vertex_data.get) { 191 res = buffer_init_from_data(vol->dev->allocator, &vol->vert_data, 192 &args->vertex_data, args->nvertices, args->context); 193 if(res != RES_OK) goto error; 194 vol->has_vert_data = 1; 195 } 196 197 exit: 198 return res; 199 error: 200 darray_u32_purge(&vol->indices); 201 darray_float_purge(&vol->positions); 202 darray_float_purge(&vol->normals); 203 buffer_release(&vol->prim_data); 204 buffer_release(&vol->vert_data); 205 goto exit; 206 } 207 208 static INLINE void* 209 rtc_node_inner_create 210 (RTCThreadLocalAllocator allocator, unsigned int nchildren, void* ctx) 211 { 212 struct node_inner* inner = NULL; 213 ASSERT(nchildren == 2); 214 (void)ctx, (void)nchildren; 215 inner = rtcThreadLocalAlloc(allocator, sizeof(*inner), 16); 216 if(!inner) return NULL; 217 inner->node.type = NODE_INNER; 218 return &inner->node; 219 } 220 221 static INLINE void 222 rtc_node_inner_set_children 223 (void* ptr, void* children[2], unsigned nchildren, void* ctx) 224 { 225 struct node_inner* inner = CONTAINER_OF(ptr, struct node_inner, node); 226 struct node* node = ptr; 227 ASSERT(node && node->type == NODE_INNER && children && nchildren == 2); 228 (void)ctx, (void)nchildren, (void)node; 229 inner->children[0] = children[0]; 230 inner->children[1] = children[1]; 231 } 232 233 static INLINE void 234 rtc_node_inner_set_bounds 235 (void* ptr, 236 const struct RTCBounds* bounds[2], 237 unsigned nchildren, 238 void* ctx) 239 { 240 struct node_inner* inner = CONTAINER_OF(ptr, struct node_inner, node); 241 struct node* node = ptr; 242 ASSERT(node && node->type == NODE_INNER && bounds && nchildren == 2); 243 (void)ctx, (void)nchildren, (void)node; 244 245 /* Setup the AABB of the 1st child */ 246 inner->low[0][0] = bounds[0]->lower_x; 247 inner->low[0][1] = bounds[0]->lower_y; 248 inner->low[0][2] = bounds[0]->lower_z; 249 inner->upp[0][0] = bounds[0]->upper_x; 250 inner->upp[0][1] = bounds[0]->upper_y; 251 inner->upp[0][2] = bounds[0]->upper_z; 252 253 /* Setup the AABB of the 2nd child */ 254 inner->low[1][0] = bounds[1]->lower_x; 255 inner->low[1][1] = bounds[1]->lower_y; 256 inner->low[1][2] = bounds[1]->lower_z; 257 inner->upp[1][0] = bounds[1]->upper_x; 258 inner->upp[1][1] = bounds[1]->upper_y; 259 inner->upp[1][2] = bounds[1]->upper_z; 260 } 261 262 static INLINE void* 263 rtc_node_leaf_create 264 (RTCThreadLocalAllocator allocator, 265 const struct RTCBuildPrimitive* prim, 266 size_t nprims, 267 void* ctx) 268 { 269 struct node_leaf* leaf = NULL; 270 ASSERT(prim && nprims == 1); 271 (void)ctx, (void)nprims; 272 273 leaf = rtcThreadLocalAlloc(allocator, sizeof(*leaf), 16); 274 if(!leaf) return NULL; 275 276 leaf->low[0] = prim->lower_x; 277 leaf->low[1] = prim->lower_y; 278 leaf->low[2] = prim->lower_z; 279 leaf->upp[0] = prim->upper_x; 280 leaf->upp[1] = prim->upper_y; 281 leaf->upp[2] = prim->upper_z; 282 leaf->geom_id = prim->geomID; 283 leaf->prim_id = prim->primID; 284 leaf->node.type = NODE_LEAF; 285 return &leaf->node; 286 } 287 288 static res_T 289 build_bvh(struct suvm_volume* vol) 290 { 291 struct darray_rtc_prim rtc_prims; 292 struct RTCBuildArguments args; 293 size_t iprim, nprims; 294 int rtc_prims_is_init = 0; 295 res_T res = RES_OK; 296 ASSERT(vol); 297 298 nprims = volume_get_primitives_count(vol); 299 300 /* Create the BVH */ 301 vol->bvh = rtcNewBVH(vol->dev->rtc); 302 if(!vol->bvh) { 303 const enum RTCError rtc_err = rtcGetDeviceError(vol->dev->rtc); 304 log_err(vol->dev, "Could not create the BVH -- %s.\n", 305 rtc_error_string(rtc_err)); 306 res = rtc_error_to_res_T(rtc_err); 307 goto error; 308 } 309 310 /* Allocate the array of geometric primitives */ 311 darray_rtc_prim_init(vol->dev->allocator, &rtc_prims); 312 rtc_prims_is_init = 1; 313 res = darray_rtc_prim_resize(&rtc_prims, nprims); 314 if(res != RES_OK) goto error; 315 316 /* Setup the primitive array */ 317 FOR_EACH(iprim, 0, nprims) { 318 const uint32_t* ids = darray_u32_cdata_get(&vol->indices) + iprim*4; 319 const float* verts[4]; 320 struct RTCBuildPrimitive* prim = darray_rtc_prim_data_get(&rtc_prims)+iprim; 321 double low[3], upp[3]; 322 323 ASSERT(ids[0] < volume_get_vertices_count(vol)); 324 ASSERT(ids[1] < volume_get_vertices_count(vol)); 325 ASSERT(ids[2] < volume_get_vertices_count(vol)); 326 ASSERT(ids[3] < volume_get_vertices_count(vol)); 327 328 /* Fetch the tetrahedron vertices */ 329 verts[0] = darray_float_cdata_get(&vol->positions) + ids[0]*3/*#coords*/; 330 verts[1] = darray_float_cdata_get(&vol->positions) + ids[1]*3/*#coords*/; 331 verts[2] = darray_float_cdata_get(&vol->positions) + ids[2]*3/*#coords*/; 332 verts[3] = darray_float_cdata_get(&vol->positions) + ids[3]*3/*#coords*/; 333 334 /* Compute the tetrahedron AABB */ 335 low[0] = MMIN(MMIN(verts[0][0],verts[1][0]), MMIN(verts[2][0],verts[3][0])); 336 low[1] = MMIN(MMIN(verts[0][1],verts[1][1]), MMIN(verts[2][1],verts[3][1])); 337 low[2] = MMIN(MMIN(verts[0][2],verts[1][2]), MMIN(verts[2][2],verts[3][2])); 338 upp[0] = MMAX(MMAX(verts[0][0],verts[1][0]), MMAX(verts[2][0],verts[3][0])); 339 upp[1] = MMAX(MMAX(verts[0][1],verts[1][1]), MMAX(verts[2][1],verts[3][1])); 340 upp[2] = MMAX(MMAX(verts[0][2],verts[1][2]), MMAX(verts[2][2],verts[3][2])); 341 342 /* Setup the build primitive */ 343 prim->lower_x = (float)low[0]; 344 prim->lower_y = (float)low[1]; 345 prim->lower_z = (float)low[2]; 346 prim->upper_x = (float)upp[0]; 347 prim->upper_y = (float)upp[1]; 348 prim->upper_z = (float)upp[2]; 349 prim->geomID = 0; 350 prim->primID = (unsigned int)iprim; 351 } 352 353 /* Setup the build arguments */ 354 args = rtcDefaultBuildArguments(); 355 args.byteSize = sizeof(args); 356 args.buildQuality = RTC_BUILD_QUALITY_MEDIUM; 357 args.buildFlags = RTC_BUILD_FLAG_NONE; 358 args.maxBranchingFactor = 2; 359 args.maxDepth = 1024; 360 args.sahBlockSize = 1; 361 args.minLeafSize = 1; 362 args.maxLeafSize = 1; 363 args.traversalCost = 1.f; 364 args.intersectionCost = 10.f; 365 args.bvh = vol->bvh; 366 args.primitives = darray_rtc_prim_data_get(&rtc_prims); 367 args.primitiveCount = nprims; 368 args.primitiveArrayCapacity = darray_rtc_prim_capacity(&rtc_prims); 369 args.createNode = rtc_node_inner_create; 370 args.setNodeChildren = rtc_node_inner_set_children; 371 args.setNodeBounds = rtc_node_inner_set_bounds; 372 args.createLeaf = rtc_node_leaf_create; 373 args.splitPrimitive = NULL; 374 args.buildProgress = NULL; 375 args.userPtr = vol; 376 377 /* Build the BVH */ 378 vol->bvh_root = rtcBuildBVH(&args); 379 if(!vol->bvh_root) { 380 const enum RTCError rtc_err = rtcGetDeviceError(vol->dev->rtc); 381 log_err(vol->dev, "Error building the BVH -- %s.\n", 382 rtc_error_string(rtc_err)); 383 res = rtc_error_to_res_T(rtc_err); 384 goto error; 385 } 386 387 exit: 388 if(rtc_prims_is_init) darray_rtc_prim_release(&rtc_prims); 389 return res; 390 error: 391 if(vol->bvh) { 392 rtcReleaseBVH(vol->bvh); 393 vol->bvh = NULL; 394 } 395 goto exit; 396 } 397 398 static res_T 399 setup_tetrahedra_normals 400 (struct suvm_volume* vol, 401 const int precompute_normals) 402 { 403 size_t itetra, ntetra; 404 int fixup = 0; 405 res_T res = RES_OK; 406 ASSERT(vol); 407 408 ntetra = volume_get_primitives_count(vol); 409 410 if(precompute_normals) { 411 res = darray_float_resize(&vol->normals, 412 ntetra * 4/*#facets per tetrahedron*/ * 3/*#coords per normal*/); 413 if(res != RES_OK) goto error; 414 } 415 416 FOR_EACH(itetra, 0, ntetra) { 417 uint32_t* ids = NULL; 418 const float* vert0 = NULL; 419 const float* vert3 = NULL; 420 float normal0[3]; 421 float v0[3]; 422 int flip = 0; 423 424 /* Fetch tetrahedron indices */ 425 ids = darray_u32_data_get(&vol->indices) + itetra*4; 426 ASSERT(ids[0] < volume_get_vertices_count(vol)); 427 ASSERT(ids[1] < volume_get_vertices_count(vol)); 428 ASSERT(ids[2] < volume_get_vertices_count(vol)); 429 ASSERT(ids[3] < volume_get_vertices_count(vol)); 430 431 /* Fetch the tetrahedron vertices */ 432 vert0 = darray_float_cdata_get(&vol->positions) + ids[0]*3/*#coords*/; 433 vert3 = darray_float_cdata_get(&vol->positions) + ids[3]*3/*#coords*/; 434 435 /* Compute the normal of the 1st facet */ 436 volume_primitive_compute_facet_normal(vol, itetra, 0, normal0); 437 438 /* Check that the normal of the 1st facet looks the fourth vertex */ 439 if(f3_dot(normal0, f3_sub(v0, vert3, vert0)) < 0) { 440 fixup = flip = 1; 441 /* Revert tetrahedron orientation */ 442 SWAP(uint32_t, ids[1], ids[2]); 443 } 444 445 /* Precompute and store the facet the normals */ 446 if(precompute_normals) { 447 float* n0 = darray_float_data_get(&vol->normals) + (itetra*4 + 0)*3; 448 float* n1 = darray_float_data_get(&vol->normals) + (itetra*4 + 1)*3; 449 float* n2 = darray_float_data_get(&vol->normals) + (itetra*4 + 2)*3; 450 float* n3 = darray_float_data_get(&vol->normals) + (itetra*4 + 3)*3; 451 if(!flip) { 452 /* Copy the already computed normal of the facet 0 */ 453 n0[0] = normal0[0]; 454 n0[1] = normal0[1]; 455 n0[2] = normal0[2]; 456 } else { 457 /* We could store the negated normal of the facet 0 but we recompute it 458 * from scratch to ensure strict equivalence if it is not stored; since 459 * tetrahedron vertices were flipped the negated normal and the 460 * recomputed one are not strictly equals */ 461 volume_primitive_compute_facet_normal(vol, itetra, 0, n0); 462 } 463 volume_primitive_compute_facet_normal(vol, itetra, 1, n1); 464 volume_primitive_compute_facet_normal(vol, itetra, 2, n2); 465 volume_primitive_compute_facet_normal(vol, itetra, 3, n3); 466 } 467 468 #ifndef NDEBUG 469 { 470 const float* verts[4]; 471 float normals[4][3]; 472 float pt[3], v1[3]; 473 474 verts[0] = vert0; 475 verts[1] = darray_float_cdata_get(&vol->positions) + ids[1]*3/*#coords*/; 476 verts[2] = darray_float_cdata_get(&vol->positions) + ids[2]*3/*#coords*/; 477 verts[3] = vert3; 478 479 /* Compute the position at the center of the tetrahedron */ 480 pt[0] = (verts[0][0] + verts[1][0] + verts[2][0] + verts[3][0]) * 0.25f; 481 pt[1] = (verts[0][1] + verts[1][1] + verts[2][1] + verts[3][1]) * 0.25f; 482 pt[2] = (verts[0][2] + verts[1][2] + verts[2][2] + verts[3][2]) * 0.25f; 483 484 /* Fetch the tetrahedron normals */ 485 volume_primitive_get_facet_normal(vol, itetra, 0, normals[0]); 486 volume_primitive_get_facet_normal(vol, itetra, 1, normals[1]); 487 volume_primitive_get_facet_normal(vol, itetra, 2, normals[2]); 488 volume_primitive_get_facet_normal(vol, itetra, 3, normals[3]); 489 490 /* Check normals orientation */ 491 f3_sub(v0, pt, verts[0]); 492 f3_sub(v1, pt, verts[3]); 493 ASSERT(f3_dot(normals[0], v0) >= 0); 494 ASSERT(f3_dot(normals[1], v1) >= 0); 495 ASSERT(f3_dot(normals[2], v1) >= 0); 496 ASSERT(f3_dot(normals[3], v1) >= 0); 497 } 498 #endif 499 } 500 501 if(fixup) { 502 log_warn(vol->dev, "Tetrahedra were not correctly oriented regarding the " 503 "Star-UVM convention.\n"); 504 } 505 506 exit: 507 return res; 508 error: 509 darray_float_purge(&vol->normals); 510 goto exit; 511 } 512 513 static void 514 volume_release(ref_T* ref) 515 { 516 struct suvm_volume* vol = NULL; 517 struct suvm_device* dev = NULL; 518 ASSERT(ref); 519 vol = CONTAINER_OF(ref, struct suvm_volume, ref); 520 dev = vol->dev; 521 darray_u32_release(&vol->indices); 522 darray_float_release(&vol->positions); 523 darray_float_release(&vol->normals); 524 buffer_release(&vol->prim_data); 525 buffer_release(&vol->vert_data); 526 if(vol->bvh) rtcReleaseBVH(vol->bvh); 527 MEM_RM(dev->allocator, vol); 528 SUVM(device_ref_put(dev)); 529 } 530 531 /******************************************************************************* 532 * Exported functions 533 ******************************************************************************/ 534 res_T 535 suvm_tetrahedral_mesh_create 536 (struct suvm_device* dev, 537 const struct suvm_tetrahedral_mesh_args* args, 538 struct suvm_volume** out_vol) 539 { 540 struct suvm_volume* vol = NULL; 541 res_T res = RES_OK; 542 543 if(!dev || !check_tetrahedral_mesh_args(args) || !out_vol) { 544 res = RES_BAD_ARG; 545 goto error; 546 } 547 548 vol = MEM_CALLOC(dev->allocator, 1, sizeof(*vol)); 549 if(!vol) { 550 res = RES_MEM_ERR; 551 goto error; 552 } 553 ref_init(&vol->ref); 554 SUVM(device_ref_get(dev)); 555 vol->dev = dev; 556 darray_u32_init(dev->allocator, &vol->indices); 557 darray_float_init(dev->allocator, &vol->positions); 558 darray_float_init(dev->allocator, &vol->normals); 559 560 /* Locally copy the volumetric mesh data */ 561 res = setup_tetrahedral_mesh(vol, args); 562 if(res != RES_OK) goto error; 563 564 /* Ensure that the vertices of the tetrahedra are well ordered regarding the 565 * normal convention and store them if required */ 566 res = setup_tetrahedra_normals(vol, args->precompute_normals); 567 if(res != RES_OK) goto error; 568 569 /* Build the BVH of the volumetric mesh */ 570 res = build_bvh(vol); 571 if(res != RES_OK) goto error; 572 573 /* Setup the volume AABB */ 574 if(vol->bvh_root->type == NODE_LEAF) { 575 const struct node_leaf* leaf = NULL; 576 leaf = CONTAINER_OF(vol->bvh_root, struct node_leaf, node); 577 vol->low[0] = leaf->low[0]; 578 vol->low[1] = leaf->low[1]; 579 vol->low[2] = leaf->low[2]; 580 vol->upp[0] = leaf->upp[0]; 581 vol->upp[1] = leaf->upp[1]; 582 vol->upp[2] = leaf->upp[2]; 583 } else { 584 const struct node_inner* inner = NULL; 585 inner = CONTAINER_OF(vol->bvh_root, struct node_inner, node); 586 vol->low[0] = MMIN(inner->low[0][0], inner->low[1][0]); 587 vol->low[1] = MMIN(inner->low[0][1], inner->low[1][1]); 588 vol->low[2] = MMIN(inner->low[0][2], inner->low[1][2]); 589 vol->upp[0] = MMAX(inner->upp[0][0], inner->upp[1][0]); 590 vol->upp[1] = MMAX(inner->upp[0][1], inner->upp[1][1]); 591 vol->upp[2] = MMAX(inner->upp[0][2], inner->upp[1][2]); 592 } 593 594 exit: 595 if(out_vol) *out_vol = vol; 596 return res; 597 error: 598 if(vol) { SUVM(volume_ref_put(vol)); vol = NULL; } 599 goto exit; 600 } 601 602 res_T 603 suvm_volume_ref_get(struct suvm_volume* vol) 604 { 605 if(!vol) return RES_BAD_ARG; 606 ref_get(&vol->ref); 607 return RES_OK; 608 } 609 610 res_T 611 suvm_volume_ref_put(struct suvm_volume* vol) 612 { 613 if(!vol) return RES_BAD_ARG; 614 ref_put(&vol->ref, volume_release); 615 return RES_OK; 616 } 617 618 res_T 619 suvm_volume_get_aabb 620 (const struct suvm_volume* volume, 621 double lower[3], 622 double upper[3]) 623 { 624 if(!volume || !lower || !upper) return RES_BAD_ARG; 625 lower[0] = volume->low[0]; 626 lower[1] = volume->low[1]; 627 lower[2] = volume->low[2]; 628 upper[0] = volume->upp[0]; 629 upper[1] = volume->upp[1]; 630 upper[2] = volume->upp[2]; 631 return RES_OK; 632 } 633 634 res_T 635 suvm_volume_get_primitives_count(const struct suvm_volume* vol, size_t* nprims) 636 { 637 if(!vol || !nprims) return RES_BAD_ARG; 638 *nprims = volume_get_primitives_count(vol); 639 return RES_OK; 640 } 641 642 res_T 643 suvm_volume_get_primitive 644 (const struct suvm_volume* vol, 645 const size_t iprim, 646 struct suvm_primitive* prim) 647 { 648 if(!vol|| !prim || iprim >= volume_get_primitives_count(vol)) 649 return RES_BAD_ARG; 650 volume_primitive_setup(vol, iprim, prim); 651 return RES_OK; 652 } 653 654 res_T 655 suvm_volume_compute_hash 656 (const struct suvm_volume* vol, 657 const int cpnt_mask, 658 hash256_T hash) 659 { 660 struct sha256_ctx ctx; 661 res_T res = RES_OK; 662 663 if(!vol || !hash) { 664 res = RES_BAD_ARG; 665 goto error; 666 } 667 668 sha256_ctx_init(&ctx); 669 670 if(cpnt_mask & SUVM_POSITIONS) { 671 const float* pos = darray_float_cdata_get(&vol->positions); 672 const size_t n = darray_float_size_get(&vol->positions); 673 sha256_ctx_update(&ctx, (const char*)pos, sizeof(*pos)*n); 674 } 675 if(cpnt_mask & SUVM_INDICES) { 676 const uint32_t* ids = darray_u32_cdata_get(&vol->indices); 677 const size_t n = darray_u32_size_get(&vol->indices); 678 sha256_ctx_update(&ctx, (const char*)ids, sizeof(*ids)*n); 679 } 680 if(cpnt_mask & SUVM_PRIMITIVE_DATA) { 681 const size_t sz = vol->prim_data.size * vol->prim_data.elmt_stride; 682 sha256_ctx_update(&ctx, vol->prim_data.mem, sz); 683 } 684 if(cpnt_mask & SUVM_VERTEX_DATA) { 685 const size_t sz = vol->vert_data.size * vol->vert_data.elmt_stride; 686 sha256_ctx_update(&ctx, vol->vert_data.mem, sz); 687 } 688 689 sha256_ctx_finalize(&ctx, hash); 690 691 exit: 692 return res; 693 error: 694 goto exit; 695 } 696 697 res_T 698 suvm_volume_get_mesh_desc 699 (const struct suvm_volume* vol, 700 struct suvm_mesh_desc* desc) 701 { 702 res_T res = RES_OK; 703 704 if(!vol || !desc) { 705 res = RES_BAD_ARG; 706 goto error; 707 } 708 709 desc->positions = darray_float_cdata_get(&vol->positions); 710 desc->indices = darray_u32_cdata_get(&vol->indices); 711 desc->dvertex = 3; 712 desc->dprimitive = 4; 713 desc->nvertices = darray_float_size_get(&vol->positions) / desc->dvertex; 714 desc->nprimitives = darray_u32_size_get(&vol->indices) / desc->dprimitive; 715 716 exit: 717 return res; 718 error: 719 goto exit; 720 } 721 722 res_T 723 suvm_mesh_desc_compute_hash(const struct suvm_mesh_desc* desc, hash256_T hash) 724 { 725 struct sha256_ctx ctx; 726 727 if(!desc || !hash) return RES_BAD_ARG; 728 729 #define HASH(Var, Nb) \ 730 sha256_ctx_update(&ctx, (const char*)(Var), sizeof(*Var)*(Nb)); 731 732 sha256_ctx_init(&ctx); 733 HASH(desc->positions, desc->nvertices*desc->dvertex); 734 HASH(desc->indices, desc->nprimitives*desc->dprimitive); 735 HASH(&desc->nvertices, 1); 736 HASH(&desc->nprimitives, 1); 737 HASH(&desc->dvertex, 1); 738 HASH(&desc->dprimitive, 1); 739 sha256_ctx_finalize(&ctx, hash); 740 741 #undef HASH 742 743 return RES_OK; 744 }