solstice_object.c (22059B)
1 /* Copyright (C) 2018-2026 |Meso|Star> (contact@meso-star.com) 2 * Copyright (C) 2016-2018 CNRS 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #include "solstice_c.h" 18 19 #include <solstice/ssol.h> 20 21 #include <rsys/double33.h> 22 #include <rsys/float3.h> 23 24 #include <star/s3dut.h> 25 #include <star/sstl.h> 26 27 #include <limits.h> 28 29 #define MAX_POLYCLIPS 16 30 31 struct mesh_ctx_s3dut { 32 struct s3dut_mesh_data data; 33 double transform[12]; 34 }; 35 36 struct mesh_ctx_sstl { 37 struct sstl_desc desc; 38 const double *transform; 39 }; 40 41 /******************************************************************************* 42 * Helper functions 43 ******************************************************************************/ 44 static void 45 mesh_ctx_s3dut_get_ids(const unsigned itri, unsigned ids[3], void* ctx) 46 { 47 const struct mesh_ctx_s3dut* mesh = ctx; 48 ASSERT(ids && ctx && itri < mesh->data.nprimitives); 49 ASSERT(mesh->data.indices[itri*3+0] <= UINT_MAX); 50 ASSERT(mesh->data.indices[itri*3+1] <= UINT_MAX); 51 ASSERT(mesh->data.indices[itri*3+2] <= UINT_MAX); 52 ids[0] = (unsigned)mesh->data.indices[itri*3+0]; 53 ids[1] = (unsigned)mesh->data.indices[itri*3+1]; 54 ids[2] = (unsigned)mesh->data.indices[itri*3+2]; 55 } 56 57 static void 58 mesh_ctx_s3dut_get_pos(const unsigned ivert, float pos[3], void* ctx) 59 { 60 const struct mesh_ctx_s3dut* mesh = ctx; 61 double tmp[3]; 62 ASSERT(pos && ctx && ivert < mesh->data.nvertices); 63 d3_set(tmp, mesh->data.positions + ivert*3); 64 d33_muld3(tmp, mesh->transform, tmp); 65 d3_add(tmp, mesh->transform+9, tmp); 66 f3_set_d3(pos, tmp); 67 } 68 69 static void 70 mesh_ctx_sstl_get_ids(const unsigned itri, unsigned ids[3], void* ctx) 71 { 72 const struct mesh_ctx_sstl* mesh = ctx; 73 ASSERT(ids && ctx && itri < mesh->desc.triangles_count); 74 ASSERT(mesh->desc.indices[itri*3+0] <= UINT_MAX); 75 ASSERT(mesh->desc.indices[itri*3+1] <= UINT_MAX); 76 ASSERT(mesh->desc.indices[itri*3+2] <= UINT_MAX); 77 ids[0] = mesh->desc.indices[itri*3+0]; 78 ids[1] = mesh->desc.indices[itri*3+1]; 79 ids[2] = mesh->desc.indices[itri*3+2]; 80 } 81 82 static void 83 mesh_ctx_sstl_get_pos(const unsigned ivert, float pos[3], void* ctx) 84 { 85 const struct mesh_ctx_sstl* mesh = ctx; 86 double tmp[3]; 87 ASSERT(pos && ctx && ivert < mesh->desc.vertices_count); 88 d3_set_f3(tmp, mesh->desc.vertices + ivert * 3); 89 d33_muld3(tmp, mesh->transform, tmp); 90 d3_add(tmp, mesh->transform + 9, tmp); 91 f3_set_d3(pos, tmp); 92 } 93 94 static void 95 get_carving_pos(const size_t ivert, double pos[2], void* ctx) 96 { 97 const struct solparser_polyclip* polyclip = ctx; 98 ASSERT(pos && ctx); 99 solparser_polyclip_get_vertex(polyclip, ivert, pos); 100 } 101 102 static INLINE enum ssol_clipping_op 103 solparser_to_ssol_clip_op(const enum solparser_clip_op op) 104 { 105 switch(op) { 106 case SOLPARSER_CLIP_OP_SUB: return SSOL_SUB; 107 case SOLPARSER_CLIP_OP_AND: return SSOL_AND; 108 default: FATAL("Unreachable code.\n"); 109 } 110 } 111 112 static void 113 get_circular(const size_t ivert, double position[2], void* ctx) 114 { 115 struct solparser_circleclip* data = (struct solparser_circleclip*)ctx; 116 const double a = (double)ivert * 2 * PI / (double)data->segments; 117 ASSERT(ivert < (size_t)data->segments); 118 position[0] = data->center[0] + data->radius * cos(a); 119 position[1] = data->center[1] + data->radius * sin(a); 120 } 121 122 static res_T 123 create_ssol_shape_mesh 124 (struct solstice* solstice, 125 const double transform[12], 126 const struct s3dut_mesh* mesh, 127 struct ssol_shape** out_ssol_shape) 128 { 129 struct mesh_ctx_s3dut mesh_ctx; 130 struct ssol_vertex_data vertex_data = SSOL_VERTEX_DATA_NULL; 131 struct ssol_shape* ssol_shape = NULL; 132 res_T res = RES_OK; 133 ASSERT(solstice && mesh && out_ssol_shape); 134 135 S3DUT(mesh_get_data(mesh, &mesh_ctx.data)); 136 ASSERT(mesh_ctx.data.nprimitives <= UINT_MAX); 137 ASSERT(mesh_ctx.data.nvertices <= UINT_MAX); 138 d33_set(mesh_ctx.transform, transform); 139 d3_set(mesh_ctx.transform+9, transform+9); 140 141 res = ssol_shape_create_mesh(solstice->ssol, &ssol_shape); 142 if(res != RES_OK) { 143 fprintf(stderr, "Could not create a Solstice Solver mesh shape.\n"); 144 goto error; 145 } 146 147 vertex_data.usage = SSOL_POSITION; 148 vertex_data.get = mesh_ctx_s3dut_get_pos; 149 res = ssol_mesh_setup(ssol_shape, (unsigned)mesh_ctx.data.nprimitives, 150 mesh_ctx_s3dut_get_ids, (unsigned)mesh_ctx.data.nvertices, &vertex_data, 1, 151 &mesh_ctx); 152 if(res != RES_OK) { 153 fprintf(stderr, "Could not setup a Solstice Solver mesh shape.\n"); 154 goto error; 155 } 156 157 exit: 158 *out_ssol_shape = ssol_shape; 159 return res; 160 error: 161 if(ssol_shape) { 162 SSOL(shape_ref_put(ssol_shape)); 163 ssol_shape = NULL; 164 } 165 goto exit; 166 } 167 168 static res_T 169 create_cuboid 170 (struct solstice* solstice, 171 const double transform[12], 172 const struct solparser_shape_cuboid_id cuboid_id, 173 struct ssol_shape** out_ssol_shape) 174 { 175 const struct solparser_shape_cuboid* cuboid; 176 struct s3dut_mesh* mesh = NULL; 177 struct ssol_shape* ssol_shape = NULL; 178 res_T res = RES_OK; 179 ASSERT(solstice && out_ssol_shape); 180 181 cuboid = solparser_get_shape_cuboid(solstice->parser, cuboid_id); 182 res = s3dut_create_cuboid(solstice->allocator, cuboid->size[0], 183 cuboid->size[1], cuboid->size[2], &mesh); 184 if(res != RES_OK) { 185 fprintf(stderr, "Could not create the cuboid 3D data.\n"); 186 goto error; 187 } 188 189 res = create_ssol_shape_mesh(solstice, transform, mesh, &ssol_shape); 190 if(res != RES_OK) goto error; 191 192 exit: 193 if(mesh) S3DUT(mesh_ref_put(mesh)); 194 *out_ssol_shape = ssol_shape; 195 return res; 196 error: 197 if(ssol_shape) { 198 SSOL(shape_ref_put(ssol_shape)); 199 ssol_shape = NULL; 200 } 201 goto exit; 202 } 203 204 205 static res_T 206 create_cylinder 207 (struct solstice* solstice, 208 const double transform[12], 209 const struct solparser_shape_cylinder_id cylinder_id, 210 struct ssol_shape** out_ssol_shape) 211 { 212 const struct solparser_shape_cylinder* cylinder; 213 struct s3dut_mesh* mesh = NULL; 214 struct ssol_shape* ssol_shape = NULL; 215 res_T res = RES_OK; 216 ASSERT(solstice && out_ssol_shape); 217 218 cylinder = solparser_get_shape_cylinder(solstice->parser, cylinder_id); 219 ASSERT(cylinder->nslices > 0 && cylinder->nslices < UINT_MAX); 220 res = s3dut_create_cylinder(solstice->allocator, cylinder->radius, 221 cylinder->height, (unsigned)cylinder->nslices, (unsigned)cylinder->nstacks, 222 &mesh); 223 if(res != RES_OK) { 224 fprintf(stderr, "Could not create the cylinder 3D data.\n"); 225 goto error; 226 } 227 228 res = create_ssol_shape_mesh(solstice, transform, mesh, &ssol_shape); 229 if(res != RES_OK) goto error; 230 231 exit: 232 if(mesh) S3DUT(mesh_ref_put(mesh)); 233 *out_ssol_shape = ssol_shape; 234 return res; 235 error: 236 if(ssol_shape) { 237 SSOL(shape_ref_put(ssol_shape)); 238 ssol_shape = NULL; 239 } 240 goto exit; 241 } 242 243 static res_T 244 create_sphere 245 (struct solstice* solstice, 246 const double transform[12], 247 const struct solparser_shape_sphere_id sphere_id, 248 struct ssol_shape** out_ssol_shape) 249 { 250 const struct solparser_shape_sphere* sphere; 251 struct s3dut_mesh* mesh = NULL; 252 struct ssol_shape* ssol_shape = NULL; 253 res_T res = RES_OK; 254 ASSERT(solstice && out_ssol_shape); 255 256 sphere = solparser_get_shape_sphere(solstice->parser, sphere_id); 257 ASSERT(sphere->nslices > 0 && sphere->nslices < UINT_MAX); 258 res = s3dut_create_sphere(solstice->allocator, sphere->radius, 259 (unsigned)sphere->nslices, (unsigned)(sphere->nslices / 2), &mesh); 260 if(res != RES_OK) { 261 fprintf(stderr, "Could not create the sphere 3D data.\n"); 262 goto error; 263 } 264 265 res = create_ssol_shape_mesh(solstice, transform, mesh, &ssol_shape); 266 if(res != RES_OK) goto error; 267 268 exit: 269 if(mesh) S3DUT(mesh_ref_put(mesh)); 270 *out_ssol_shape = ssol_shape; 271 return res; 272 error: 273 if(ssol_shape) { 274 SSOL(shape_ref_put(ssol_shape)); 275 ssol_shape = NULL; 276 } 277 goto exit; 278 } 279 280 static res_T 281 create_stl 282 (struct solstice* solstice, 283 const double transform[12], 284 const struct solparser_shape_imported_geometry_id stl_id, 285 struct ssol_shape** out_stl) 286 { 287 const struct solparser_shape_imported_geometry* stl; 288 struct ssol_shape* ssol_shape = NULL; 289 struct sstl* tmp_stl; 290 struct sstl_desc tmp_desc; 291 struct mesh_ctx_sstl mesh_ctx; 292 struct ssol_vertex_data vertex_data = SSOL_VERTEX_DATA_NULL; 293 res_T res = RES_OK; 294 ASSERT(solstice && out_stl); 295 296 stl = solparser_get_shape_stl(solstice->parser, stl_id); 297 ASSERT(str_cget(&stl->filename)); 298 299 res = sstl_create(NULL, solstice->allocator, 1, &tmp_stl); 300 if(res != RES_OK) { 301 fprintf(stderr, "Could not create a Solstice Solver STL shape.\n"); 302 goto error; 303 } 304 res = sstl_load(tmp_stl, str_cget(&stl->filename)); 305 if(res != RES_OK) goto error; 306 res = sstl_get_desc(tmp_stl, &tmp_desc); 307 if(res != RES_OK) goto error; 308 ASSERT(tmp_desc.triangles_count <= UINT_MAX); 309 ASSERT(tmp_desc.vertices_count <= UINT_MAX); 310 mesh_ctx.transform = transform; 311 mesh_ctx.desc = tmp_desc; 312 313 res = ssol_shape_create_mesh(solstice->ssol, &ssol_shape); 314 if(res != RES_OK) { 315 fprintf(stderr, "Could not create the STL mesh shape.\n"); 316 goto error; 317 } 318 319 vertex_data.usage = SSOL_POSITION; 320 vertex_data.get = mesh_ctx_sstl_get_pos; 321 res = ssol_mesh_setup(ssol_shape, (unsigned)tmp_desc.triangles_count, 322 mesh_ctx_sstl_get_ids, (unsigned)tmp_desc.vertices_count, &vertex_data, 1, 323 &mesh_ctx); 324 if(res != RES_OK) { 325 fprintf(stderr, "Could not setup STL mesh.\n"); 326 goto error; 327 } 328 329 exit: 330 if(tmp_stl) SSTL(ref_put(tmp_stl)); 331 *out_stl = ssol_shape; 332 return res; 333 error: 334 if(ssol_shape) { 335 SSOL(shape_ref_put(ssol_shape)); 336 ssol_shape = NULL; 337 } 338 goto exit; 339 } 340 341 static res_T 342 create_ssol_shape_punched_surface 343 (struct solstice* solstice, 344 const struct darray_polyclip* clips, 345 struct ssol_quadric* quadric, 346 struct ssol_shape** out_ssol_shape) 347 { 348 struct ssol_shape* ssol_shape = NULL; 349 struct ssol_carving carvings[MAX_POLYCLIPS]; 350 struct ssol_punched_surface punched_surf = SSOL_PUNCHED_SURFACE_NULL; 351 size_t iclip, nclips; 352 res_T res = RES_OK; 353 ASSERT(solstice && quadric && out_ssol_shape); 354 355 nclips = darray_polyclip_size_get(clips); 356 if(nclips > MAX_POLYCLIPS) { 357 fprintf(stderr, "Too many clipping polygons. " 358 "%lu are submitted while at most %lu can be defined.\n", 359 (unsigned long)nclips, (unsigned long)MAX_POLYCLIPS); 360 res = RES_BAD_ARG; 361 goto error; 362 } 363 364 FOR_EACH(iclip, 0, nclips) { 365 const struct solparser_polyclip* clip; 366 clip = darray_polyclip_cdata_get(clips) + iclip; 367 368 switch(clip->contour_type) { 369 case SOLPARSER_CLIP_CONTOUR_POLY: 370 carvings[iclip].get = get_carving_pos; 371 carvings[iclip].nb_vertices = solparser_polyclip_get_vertices_count(clip); 372 carvings[iclip].operation = solparser_to_ssol_clip_op(clip->op); 373 carvings[iclip].context = (void*)clip; 374 break; 375 case SOLPARSER_CLIP_CONTOUR_CIRCLE: 376 carvings[iclip].get = get_circular; 377 carvings[iclip].nb_vertices = (size_t)clip->circle.segments; 378 carvings[iclip].operation = solparser_to_ssol_clip_op(clip->op); 379 carvings[iclip].context = (void*)&clip->circle; 380 break; 381 default: FATAL("Unreachable code.\n"); 382 } 383 } 384 385 punched_surf.quadric = quadric; 386 punched_surf.carvings = carvings; 387 punched_surf.nb_carvings = nclips; 388 389 res = ssol_shape_create_punched_surface(solstice->ssol, &ssol_shape); 390 if(res != RES_OK) { 391 fprintf(stderr, "Could not create a Solstice Solver punched surface.\n"); 392 goto error; 393 } 394 395 res = ssol_punched_surface_setup(ssol_shape, &punched_surf); 396 if(res != RES_OK) { 397 fprintf(stderr, "Could not setup the Solstice Solver punched surface.\n"); 398 goto error; 399 } 400 exit: 401 *out_ssol_shape = ssol_shape; 402 return res; 403 error: 404 if(ssol_shape) { 405 SSOL(shape_ref_put(ssol_shape)); 406 ssol_shape = NULL; 407 } 408 goto exit; 409 410 } 411 412 static res_T 413 create_parabol 414 (struct solstice* solstice, 415 const double transform[12], 416 const struct solparser_shape_paraboloid_id id, 417 struct ssol_shape** out_ssol_shape) 418 { 419 const struct solparser_shape_paraboloid* paraboloid; 420 struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; 421 ASSERT(solstice); 422 423 paraboloid = solparser_get_shape_parabol(solstice->parser, id); 424 425 quadric.type = SSOL_QUADRIC_PARABOL; 426 quadric.data.parabol.focal = paraboloid->focal; 427 d33_set(quadric.transform, transform); 428 d3_set(quadric.transform+9, transform+9); 429 if(paraboloid->nslices > 0) { /* nslices is set */ 430 quadric.slices_count_hint = (size_t)paraboloid->nslices; 431 } 432 return create_ssol_shape_punched_surface 433 (solstice, ¶boloid->polyclips, &quadric, out_ssol_shape); 434 } 435 436 static res_T 437 create_parabolic_cylinder 438 (struct solstice* solstice, 439 const double transform[12], 440 const struct solparser_shape_paraboloid_id id, 441 struct ssol_shape** out_ssol_shape) 442 { 443 const struct solparser_shape_paraboloid* paraboloid; 444 struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; 445 ASSERT(solstice); 446 447 paraboloid = solparser_get_shape_parabolic_cylinder(solstice->parser, id); 448 449 quadric.type = SSOL_QUADRIC_PARABOLIC_CYLINDER; 450 quadric.data.parabolic_cylinder.focal = paraboloid->focal; 451 d33_set(quadric.transform, transform); 452 d3_set(quadric.transform+9, transform+9); 453 if(paraboloid->nslices > 0) { /* nslices is set */ 454 quadric.slices_count_hint = (size_t)paraboloid->nslices; 455 } 456 457 return create_ssol_shape_punched_surface 458 (solstice, ¶boloid->polyclips, &quadric, out_ssol_shape); 459 } 460 461 static res_T 462 create_hyperbol 463 (struct solstice* solstice, 464 const double transform[12], 465 const struct solparser_shape_hyperboloid_id id, 466 struct ssol_shape** out_ssol_shape) 467 { 468 const struct solparser_shape_hyperboloid* hyperboloid; 469 struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; 470 ASSERT(solstice); 471 472 hyperboloid = solparser_get_shape_hyperbol(solstice->parser, id); 473 474 quadric.type = SSOL_QUADRIC_HYPERBOL; 475 quadric.data.hyperbol.real_focal = hyperboloid->focals.real; 476 quadric.data.hyperbol.img_focal = hyperboloid->focals.image; 477 d33_set(quadric.transform, transform); 478 d3_set(quadric.transform + 9, transform + 9); 479 if(hyperboloid->nslices > 0) { /* nslices is set */ 480 quadric.slices_count_hint = (size_t)hyperboloid->nslices; 481 } 482 483 return create_ssol_shape_punched_surface 484 (solstice, &hyperboloid->polyclips, &quadric, out_ssol_shape); 485 } 486 487 static res_T 488 create_hemisphere 489 (struct solstice* solstice, 490 const double transform[12], 491 const struct solparser_shape_hemisphere_id id, 492 struct ssol_shape** out_ssol_shape) 493 { 494 const struct solparser_shape_hemisphere* hemisphere; 495 struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; 496 ASSERT(solstice); 497 498 hemisphere = solparser_get_shape_hemisphere(solstice->parser, id); 499 500 quadric.type = SSOL_QUADRIC_HEMISPHERE; 501 quadric.data.hemisphere.radius = hemisphere->radius; 502 d33_set(quadric.transform, transform); 503 d3_set(quadric.transform + 9, transform + 9); 504 if(hemisphere->nslices > 0) { /* nslices is set */ 505 quadric.slices_count_hint = (size_t)hemisphere->nslices; 506 } 507 508 return create_ssol_shape_punched_surface 509 (solstice, &hemisphere->polyclips, &quadric, out_ssol_shape); 510 } 511 512 static res_T 513 create_plane 514 (struct solstice* solstice, 515 const double transform[12], 516 const struct solparser_shape_plane_id id, 517 struct ssol_shape** out_ssol_shape) 518 { 519 const struct solparser_shape_plane* plane; 520 struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; 521 ASSERT(solstice); 522 523 plane = solparser_get_shape_plane(solstice->parser, id); 524 ASSERT(plane->nslices > 0); 525 526 quadric.type = SSOL_QUADRIC_PLANE; 527 quadric.slices_count_hint = (size_t)plane->nslices; 528 d33_set(quadric.transform, transform); 529 d3_set(quadric.transform+9, transform+9); 530 531 return create_ssol_shape_punched_surface 532 (solstice, &plane->polyclips, &quadric, out_ssol_shape); 533 } 534 535 static res_T 536 create_shaded_shape 537 (struct solstice* solstice, 538 const struct solparser_object_id obj_id, 539 struct ssol_material** ssol_front, 540 struct ssol_material** ssol_back, 541 struct ssol_shape** ssol_shape) 542 { 543 const struct solparser_material_double_sided* mtl2; 544 const struct solparser_object* obj; 545 const struct solparser_shape* shape; 546 double transform[12]; 547 double rotation[3]; 548 res_T res = RES_OK; 549 ASSERT(solstice && ssol_front && ssol_back && ssol_shape); 550 551 *ssol_front = NULL; 552 *ssol_back = NULL; 553 *ssol_shape = NULL; 554 555 obj = solparser_get_object(solstice->parser, obj_id); 556 557 mtl2 = solparser_get_material_double_sided(solstice->parser, obj->mtl2); 558 res = solstice_create_ssol_material(solstice, mtl2->front, ssol_front); 559 if(res != RES_OK) goto error; 560 res = solstice_create_ssol_material(solstice, mtl2->back, ssol_back); 561 if(res != RES_OK) goto error; 562 563 /* Define the shape transformation */ 564 rotation[0] = MDEG2RAD(obj->rotation[0]); 565 rotation[1] = MDEG2RAD(obj->rotation[1]); 566 rotation[2] = MDEG2RAD(obj->rotation[2]); 567 d33_rotation(transform, rotation[0], rotation[1], rotation[2]); 568 d3_set(transform+9, obj->translation); 569 570 shape = solparser_get_shape(solstice->parser, obj->shape); 571 switch(shape->type) { 572 case SOLPARSER_SHAPE_CUBOID: 573 res = create_cuboid(solstice, transform, shape->data.cuboid, ssol_shape); 574 break; 575 case SOLPARSER_SHAPE_CYLINDER: 576 res = create_cylinder 577 (solstice, transform, shape->data.cylinder, ssol_shape); 578 break; 579 case SOLPARSER_SHAPE_OBJ: 580 fprintf(stderr, "`obj' shapes are not supported yet.\n"); 581 res = RES_BAD_ARG; 582 break; 583 case SOLPARSER_SHAPE_PARABOL: 584 res = create_parabol(solstice, transform, shape->data.parabol, ssol_shape); 585 break; 586 case SOLPARSER_SHAPE_PARABOLIC_CYLINDER: 587 res = create_parabolic_cylinder 588 (solstice, transform, shape->data.parabol, ssol_shape); 589 break; 590 case SOLPARSER_SHAPE_HYPERBOL: 591 res = create_hyperbol(solstice, transform, shape->data.hyperbol, ssol_shape); 592 break; 593 case SOLPARSER_SHAPE_HEMISPHERE: 594 res = create_hemisphere 595 (solstice, transform, shape->data.hemisphere, ssol_shape); 596 break; 597 case SOLPARSER_SHAPE_PLANE: 598 res = create_plane(solstice, transform, shape->data.plane, ssol_shape); 599 break; 600 case SOLPARSER_SHAPE_SPHERE: 601 res = create_sphere(solstice, transform, shape->data.sphere, ssol_shape); 602 break; 603 case SOLPARSER_SHAPE_STL: 604 res = create_stl(solstice, transform, shape->data.stl, ssol_shape); 605 break; 606 default: FATAL("Unreachable code.\n"); break; 607 } 608 if(res != RES_OK) goto error; 609 610 exit: 611 return res; 612 error: 613 if(*ssol_front) SSOL(material_ref_put(*ssol_front)), *ssol_front = NULL; 614 if(*ssol_back) SSOL(material_ref_put(*ssol_back)), *ssol_back = NULL; 615 if(*ssol_shape) SSOL(shape_ref_put(*ssol_shape)), *ssol_shape = NULL; 616 goto exit; 617 } 618 619 /******************************************************************************* 620 * Local functions 621 ******************************************************************************/ 622 res_T 623 solstice_instantiate_geometry 624 (struct solstice* solstice, 625 const struct solparser_geometry_id geom_id, 626 struct ssol_instance** out_inst) 627 { 628 struct ssol_instance* inst = NULL; 629 struct ssol_material* front = NULL; 630 struct ssol_material* back = NULL; 631 struct ssol_object** pssol_obj = NULL; 632 struct ssol_object* ssol_obj = NULL; 633 struct ssol_object* ssol_obj_new = NULL; 634 struct ssol_shape* shape = NULL; 635 int is_attached_to_scn = 0; 636 int is_registered = 0; 637 res_T res = RES_OK; 638 ASSERT(solstice && out_inst); 639 640 pssol_obj = htable_object_find(&solstice->objects, &geom_id.i); 641 if(pssol_obj) { 642 ssol_obj = *pssol_obj; 643 } else { 644 const struct solparser_geometry* geom; 645 size_t iobj, nobjs; 646 647 res = ssol_object_create(solstice->ssol, &ssol_obj_new); 648 if(res != RES_OK) { 649 fprintf(stderr, "Could not create a Solstice Solver object.\n"); 650 goto error; 651 } 652 ssol_obj = ssol_obj_new; 653 654 geom = solparser_get_geometry(solstice->parser, geom_id); 655 nobjs = solparser_geometry_get_objects_count(geom); 656 FOR_EACH(iobj, 0, nobjs) { 657 struct solparser_object_id obj_id; 658 659 obj_id = solparser_geometry_get_object(geom, iobj); 660 res = create_shaded_shape(solstice, obj_id, &front, &back, &shape); 661 if(res != RES_OK) goto error; 662 663 res = ssol_object_add_shaded_shape(ssol_obj, shape, front, back); 664 if(res != RES_OK) { 665 fprintf(stderr, 666 "Could not add a shaded shape to a Solstice Solver object.\n"); 667 goto error; 668 } 669 670 /* Release the shape and its double sided material since they are now own 671 * by the object */ 672 SSOL(shape_ref_put(shape)); 673 SSOL(material_ref_put(front)); 674 SSOL(material_ref_put(back)); 675 shape = NULL; 676 front = NULL; 677 back = NULL; 678 } 679 } 680 681 res = ssol_object_instantiate(ssol_obj, &inst); 682 if(res != RES_OK) { 683 fprintf(stderr, "Could not instantiate a Solstice Solver object.\n"); 684 goto error; 685 } 686 687 res = ssol_scene_attach_instance(solstice->scene, inst); 688 if(res != RES_OK) { 689 fprintf(stderr, 690 "Could not attach the instance against the Solstice Solver scene.\n"); 691 goto error; 692 } 693 is_attached_to_scn = 1; 694 695 res = htable_object_set(&solstice->objects, &geom_id.i, &ssol_obj); 696 if(res != RES_OK) { 697 fprintf(stderr, "Could not register a Solstice Solver object.\n"); 698 goto error; 699 } 700 is_registered = 1; 701 702 exit: 703 *out_inst = inst; 704 return res; 705 error: 706 if(is_attached_to_scn) SSOL(scene_detach_instance(solstice->scene, inst)); 707 if(is_registered) htable_object_erase(&solstice->objects, &geom_id.i); 708 if(inst) SSOL(instance_ref_put(inst)), inst = NULL; 709 if(ssol_obj_new) SSOL(object_ref_put(ssol_obj_new)); 710 if(shape) SSOL(shape_ref_put(shape)); 711 if(front) SSOL(material_ref_put(front)); 712 if(back) SSOL(material_ref_put(back)); 713 goto exit; 714 } 715