solstice_material.c (22158B)
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.h" 18 #include "solstice_c.h" 19 20 #include <rsys/double33.h> 21 #include <rsys/image.h> 22 #include <solstice/ssol.h> 23 24 struct dielectric_param { 25 struct ssol_image* normal_map; 26 }; 27 28 struct matte_param { 29 struct ssol_data reflectivity; 30 struct ssol_image* normal_map; 31 }; 32 33 struct mirror_param { 34 struct ssol_data reflectivity; 35 struct ssol_data roughness; 36 struct ssol_image* normal_map; 37 }; 38 39 struct thin_dielectric_param { 40 struct ssol_image* normal_map; 41 }; 42 43 /******************************************************************************* 44 * Helper functions 45 ******************************************************************************/ 46 static void 47 perturb_normal 48 (const struct ssol_surface_fragment* frag, 49 const struct ssol_image* normal_map, 50 double normal[3]) 51 { 52 double basis[9]; 53 double N[3]; 54 ASSERT(frag && normal_map && normal); 55 56 SSOL(image_sample(normal_map, SSOL_FILTER_LINEAR, SSOL_ADDRESS_CLAMP, 57 SSOL_ADDRESS_CLAMP, frag->uv, N)); 58 59 d3_set(basis+0, frag->dPdu); 60 d3_set(basis+3, frag->dPdv); 61 d3_set(basis+6, frag->Ns); 62 d3_normalize(basis + 0, basis + 0); 63 d3_normalize(basis + 3, basis + 3); 64 65 d3_subd(N, d3_muld(N, N, 2), 1); 66 d33_muld3(N, basis, N); 67 d3_normalize(normal, N); 68 } 69 70 static enum ssol_microfacet_distribution 71 solparser_to_ssol_ufacet_distrib 72 (const enum solparser_microfacet_distribution distrib) 73 { 74 enum ssol_microfacet_distribution ufacet_distrib; 75 switch(distrib) { 76 case SOLPARSER_MICROFACET_BECKMANN: 77 ufacet_distrib = SSOL_MICROFACET_BECKMANN; 78 break; 79 case SOLPARSER_MICROFACET_PILLBOX: 80 ufacet_distrib = SSOL_MICROFACET_PILLBOX; 81 break; 82 default: FATAL("Unreachable code.\n"); break; 83 } 84 return ufacet_distrib; 85 } 86 87 static void 88 mtl_get_normal 89 (struct ssol_device* dev, 90 struct ssol_param_buffer* buf, 91 const double wavelength, 92 const struct ssol_surface_fragment* frag, 93 double* val) 94 { 95 (void)dev, (void)buf, (void)wavelength; 96 d3_set(val, frag->Ns); 97 } 98 99 static void 100 dielectric_get_normal 101 (struct ssol_device* dev, 102 struct ssol_param_buffer* buf, 103 const double wavelength, 104 const struct ssol_surface_fragment* frag, 105 double* val) 106 { 107 const struct dielectric_param* param = ssol_param_buffer_get(buf); 108 (void)dev, (void)buf, (void)wavelength; 109 perturb_normal(frag, param->normal_map, val); 110 } 111 112 static void 113 dielectric_param_release(void* mem) 114 { 115 struct dielectric_param* param = mem; 116 ASSERT(param); 117 if(param->normal_map) SSOL(image_ref_put(param->normal_map)); 118 } 119 120 static void 121 matte_get_reflectivity 122 (struct ssol_device* dev, 123 struct ssol_param_buffer* buf, 124 const double wavelength, 125 const struct ssol_surface_fragment* frag, 126 double* val) 127 { 128 const struct matte_param* param = ssol_param_buffer_get(buf); 129 (void)dev, (void)wavelength, (void)frag; 130 *val = ssol_data_get_value(¶m->reflectivity, wavelength); 131 } 132 133 static void 134 matte_get_normal 135 (struct ssol_device* dev, 136 struct ssol_param_buffer* buf, 137 const double wavelength, 138 const struct ssol_surface_fragment* frag, 139 double* val) 140 { 141 const struct matte_param* param = ssol_param_buffer_get(buf); 142 (void)dev, (void)wavelength; 143 perturb_normal(frag, param->normal_map, val); 144 } 145 146 static void 147 matte_param_release(void* mem) 148 { 149 struct matte_param* param = mem; 150 ASSERT(param); 151 if(param->normal_map) SSOL(image_ref_put(param->normal_map)); 152 ssol_data_clear(¶m->reflectivity); 153 } 154 155 static void 156 mirror_get_reflectivity 157 (struct ssol_device* dev, 158 struct ssol_param_buffer* buf, 159 const double wavelength, 160 const struct ssol_surface_fragment* frag, 161 double* val) 162 { 163 const struct mirror_param* param = ssol_param_buffer_get(buf); 164 (void)dev, (void)wavelength, (void)frag; 165 *val = ssol_data_get_value(¶m->reflectivity, wavelength); 166 } 167 168 static void 169 mirror_get_roughness 170 (struct ssol_device* dev, 171 struct ssol_param_buffer* buf, 172 const double wavelength, 173 const struct ssol_surface_fragment* frag, 174 double* val) 175 { 176 const struct mirror_param* param = ssol_param_buffer_get(buf); 177 (void)dev, (void)wavelength, (void)frag; 178 *val = ssol_data_get_value(¶m->roughness, wavelength); 179 } 180 181 static void 182 mirror_get_normal 183 (struct ssol_device* dev, 184 struct ssol_param_buffer* buf, 185 const double wavelength, 186 const struct ssol_surface_fragment* frag, 187 double* val) 188 { 189 const struct mirror_param* param = ssol_param_buffer_get(buf); 190 (void)dev, (void)wavelength; 191 perturb_normal(frag, param->normal_map, val); 192 } 193 194 static void 195 mirror_param_release(void* mem) 196 { 197 struct mirror_param* param = mem; 198 ASSERT(param); 199 if(param->normal_map) SSOL(image_ref_put(param->normal_map)); 200 ssol_data_clear(¶m->reflectivity); 201 ssol_data_clear(¶m->roughness); 202 } 203 204 static void 205 thin_dielectric_get_normal 206 (struct ssol_device* dev, 207 struct ssol_param_buffer* buf, 208 const double wavelength, 209 const struct ssol_surface_fragment* frag, 210 double* val) 211 { 212 const struct thin_dielectric_param* param = ssol_param_buffer_get(buf); 213 (void)dev, (void)buf, (void)wavelength; 214 perturb_normal(frag, param->normal_map, val); 215 } 216 217 static void 218 thin_dielectric_param_release(void* mem) 219 { 220 struct thin_dielectric_param* param = mem; 221 ASSERT(param); 222 if(param->normal_map) SSOL(image_ref_put(param->normal_map)); 223 } 224 225 static res_T 226 load_image 227 (struct solstice* solstice, 228 const char* filename, 229 struct ssol_image** out_ssol_img) 230 { 231 struct ssol_image* ssol_img = NULL; 232 struct ssol_image_layout layout; 233 struct image img; 234 char* mem; 235 size_t x, y; 236 res_T res = RES_OK; 237 ASSERT(solstice && filename && out_ssol_img); 238 239 image_init(solstice->allocator, &img); 240 241 res = image_read_ppm(&img, filename); 242 if(res != RES_OK) { 243 fprintf(stderr, "Could not load the PPM image `%s'.\n", filename); 244 goto error; 245 } 246 247 res = ssol_image_create(solstice->ssol, &ssol_img); 248 if(res != RES_OK) { 249 fprintf(stderr, "Could not create the Solstice Solver image.\n"); 250 goto error; 251 } 252 253 res = ssol_image_setup(ssol_img, img.width, img.height, SSOL_PIXEL_DOUBLE3); 254 if(res != RES_OK) { 255 fprintf(stderr, "Could not setup the Solstice Solver image.\n"); 256 goto error; 257 } 258 259 SSOL(image_get_layout(ssol_img, &layout)); 260 SSOL(image_map(ssol_img, &mem)); 261 262 FOR_EACH(y, 0, layout.height) { 263 char* dst_row = mem + layout.offset + y * layout.row_pitch; 264 const char* src_row = img.pixels + y * img.pitch; 265 266 FOR_EACH(x, 0, layout.width) { 267 char* dst = dst_row + x*ssol_sizeof_pixel_format(layout.pixel_format); 268 const char* src = src_row + x*sizeof_image_format(img.format); 269 switch(img.format) { 270 case IMAGE_RGB8: 271 ((double*)dst)[0] = ((double)((uint8_t*)src)[0] + 0.5) / UINT8_MAX; 272 ((double*)dst)[1] = ((double)((uint8_t*)src)[1] + 0.5) / UINT8_MAX; 273 ((double*)dst)[2] = ((double)((uint8_t*)src)[2] + 0.5) / UINT8_MAX; 274 break; 275 case IMAGE_RGB16: 276 ((double*)dst)[0] = ((double)((uint16_t*)src)[0] + 0.5) / UINT16_MAX; 277 ((double*)dst)[1] = ((double)((uint16_t*)src)[1] + 0.5) / UINT16_MAX; 278 ((double*)dst)[2] = ((double)((uint16_t*)src)[2] + 0.5) / UINT16_MAX; 279 break; 280 default: FATAL("Unreachable code.\n"); break; 281 } 282 } 283 } 284 285 exit: 286 image_release(&img); 287 *out_ssol_img = ssol_img; 288 return res; 289 error: 290 if(ssol_img) SSOL(image_ref_put(ssol_img)); 291 goto exit; 292 } 293 294 static res_T 295 create_material_dielectric 296 (struct solstice* solstice, 297 const struct solparser_material_dielectric* dielectric, 298 struct ssol_material** out_mtl) 299 { 300 const struct solparser_medium* medium_i; 301 const struct solparser_medium* medium_t; 302 struct ssol_medium ssol_medium_i = SSOL_MEDIUM_VACUUM; 303 struct ssol_medium ssol_medium_t = SSOL_MEDIUM_VACUUM; 304 struct ssol_dielectric_shader shader = SSOL_DIELECTRIC_SHADER_NULL; 305 struct ssol_image* img = NULL; 306 struct ssol_material* mtl = NULL; 307 struct ssol_param_buffer* pbuf = NULL; 308 res_T res = RES_OK; 309 ASSERT(solstice && dielectric && out_mtl); 310 311 res = ssol_material_create_dielectric(solstice->ssol, &mtl); 312 if(res != RES_OK) { 313 fprintf(stderr, 314 "Could not allocate the Solstice Solver dielectric material.\n"); 315 goto error; 316 } 317 318 medium_i = solparser_get_medium(solstice->parser, dielectric->medium_i); 319 medium_t = solparser_get_medium(solstice->parser, dielectric->medium_t); 320 321 if(!SOLPARSER_ID_IS_VALID(dielectric->normal_map)) { 322 shader.normal = mtl_get_normal; 323 } else { 324 const struct solparser_image* image; 325 struct dielectric_param* param = NULL; 326 327 image = solparser_get_image(solstice->parser, dielectric->normal_map); 328 res = load_image(solstice, str_cget(&image->filename), &img); 329 if(res != RES_OK) goto error; 330 331 res = ssol_param_buffer_create 332 (solstice->ssol, sizeof(struct dielectric_param), &pbuf); 333 if(res != RES_OK) { 334 fprintf(stderr, "Could not create the Solstice Solver parameter buffer.\n"); 335 goto error; 336 } 337 338 param = ssol_param_buffer_allocate(pbuf, sizeof(struct dielectric_param), 339 ALIGNOF(struct dielectric_param), dielectric_param_release); 340 if(!param) { 341 fprintf(stderr, "Could not allocate the dielectric parameter.\n"); 342 res = RES_MEM_ERR; 343 goto error; 344 } 345 param->normal_map = img; 346 shader.normal = dielectric_get_normal; 347 SSOL(material_set_param_buffer(mtl, pbuf)); 348 } 349 350 #define SET_SSOL_DATA(Medium, Name) { \ 351 res = mtl_to_ssol_data(solstice, &Medium->Name, &ssol_## Medium.Name); \ 352 if(res != RES_OK) goto error; \ 353 } (void)0 354 SET_SSOL_DATA(medium_i, refractive_index); 355 SET_SSOL_DATA(medium_t, refractive_index); 356 SET_SSOL_DATA(medium_i, extinction); 357 SET_SSOL_DATA(medium_t, extinction); 358 #undef SET_SSOL_DATA 359 SSOL(dielectric_setup(mtl, &shader, &ssol_medium_i, &ssol_medium_t)); 360 361 exit: 362 ssol_medium_clear(&ssol_medium_i); 363 ssol_medium_clear(&ssol_medium_t); 364 if(pbuf) SSOL(param_buffer_ref_put(pbuf)); 365 *out_mtl = mtl; 366 return res; 367 error: 368 if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; 369 if(img) SSOL(image_ref_put(img)); 370 goto exit; 371 } 372 373 static res_T 374 create_material_matte 375 (struct solstice* solstice, 376 const struct solparser_material_matte* matte, 377 struct ssol_material** out_mtl) 378 { 379 struct ssol_matte_shader shader = SSOL_MATTE_SHADER_NULL; 380 struct ssol_image* img = NULL; 381 struct ssol_material* mtl = NULL; 382 struct ssol_param_buffer* pbuf = NULL; 383 struct matte_param* param; 384 res_T res = RES_OK; 385 ASSERT(solstice && matte && out_mtl); 386 387 res = ssol_material_create_matte(solstice->ssol, &mtl); 388 if(res != RES_OK) { 389 fprintf(stderr, "Could not create the Solstice Solver matte material.\n"); 390 goto error; 391 } 392 393 res = ssol_param_buffer_create 394 (solstice->ssol, sizeof(struct matte_param), &pbuf); 395 if(res != RES_OK) { 396 fprintf(stderr, "Could not create the Solstice Solver parameter buffer.\n"); 397 goto error; 398 } 399 400 param = ssol_param_buffer_allocate(pbuf, sizeof(struct matte_param), 401 ALIGNOF(struct matte_param), matte_param_release); 402 if(!param) { 403 fprintf(stderr, "Could not allocate the matte parameter.\n"); 404 res = RES_MEM_ERR; 405 goto error; 406 } 407 memset(param, 0, sizeof(struct matte_param)); 408 409 res = mtl_to_ssol_data(solstice, &matte->reflectivity, ¶m->reflectivity); 410 if(res != RES_OK) goto error; 411 412 if(!SOLPARSER_ID_IS_VALID(matte->normal_map)) { 413 shader.normal = mtl_get_normal; 414 } else { 415 const struct solparser_image* image; 416 image = solparser_get_image(solstice->parser, matte->normal_map); 417 res = load_image(solstice, str_cget(&image->filename), &img); 418 if(res != RES_OK) goto error; 419 param->normal_map = img; 420 shader.normal = matte_get_normal; 421 } 422 423 shader.reflectivity = matte_get_reflectivity; 424 SSOL(matte_setup(mtl, &shader)); 425 SSOL(material_set_param_buffer(mtl, pbuf)); 426 427 exit: 428 if(pbuf) SSOL(param_buffer_ref_put(pbuf)); 429 *out_mtl = mtl; 430 return res; 431 error: 432 if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; 433 if(img) SSOL(image_ref_put(img)); 434 goto exit; 435 } 436 437 static res_T 438 create_material_mirror 439 (struct solstice* solstice, 440 const struct solparser_material_mirror* mirror, 441 struct ssol_material** out_mtl) 442 { 443 struct ssol_image* img = NULL; 444 struct ssol_mirror_shader shader = SSOL_MIRROR_SHADER_NULL; 445 struct ssol_material* mtl = NULL; 446 struct ssol_param_buffer* pbuf = NULL; 447 struct mirror_param* param; 448 enum ssol_microfacet_distribution ufacet_distrib; 449 res_T res = RES_OK; 450 ASSERT(solstice && mirror && out_mtl); 451 452 res = ssol_material_create_mirror(solstice->ssol, &mtl); 453 if(res != RES_OK) { 454 fprintf(stderr, "Could not create the Solstice Solver mirror material.\n"); 455 goto error; 456 } 457 458 res = ssol_param_buffer_create 459 (solstice->ssol, sizeof(struct mirror_param), &pbuf); 460 if(res != RES_OK) { 461 fprintf(stderr, "Could not create the Solstice Solver parameter buffer.\n"); 462 goto error; 463 } 464 465 param = ssol_param_buffer_allocate(pbuf, sizeof(struct mirror_param), 466 ALIGNOF(struct mirror_param), mirror_param_release); 467 if(!param) { 468 fprintf(stderr, "Could not allocate the mirror parameters.\n"); 469 res = RES_MEM_ERR; 470 goto error; 471 } 472 memset(param, 0, sizeof(struct mirror_param)); 473 474 res = mtl_to_ssol_data(solstice, &mirror->reflectivity, ¶m->reflectivity); 475 if(res != RES_OK) goto error; 476 477 switch(mirror->ufacet_distrib) { 478 case SOLPARSER_MICROFACET_BECKMANN: 479 /* For the beckmann distribution, convert the slope error to the 480 * corresponding beckmann rougness by multiplying it by sqrt(2) */ 481 res = scaled_mtl_to_ssol_data 482 (solstice, &mirror->slope_error, sqrt(2), ¶m->roughness); 483 break; 484 case SOLPARSER_MICROFACET_PILLBOX: 485 /* Direct correspondance between the solver roughness parameter and the 486 * provided slope error */ 487 res = mtl_to_ssol_data(solstice, &mirror->slope_error, ¶m->roughness); 488 break; 489 default: FATAL("Unreachable code.\n"); break; 490 } 491 492 if(!SOLPARSER_ID_IS_VALID(mirror->normal_map)) { 493 shader.normal = mtl_get_normal; 494 } else { 495 const struct solparser_image* image; 496 image = solparser_get_image(solstice->parser, mirror->normal_map); 497 res = load_image(solstice, str_cget(&image->filename), &img); 498 if(res != RES_OK) goto error; 499 param->normal_map = img; 500 shader.normal = mirror_get_normal; 501 } 502 503 shader.reflectivity = mirror_get_reflectivity; 504 shader.roughness = mirror_get_roughness; 505 506 ufacet_distrib = solparser_to_ssol_ufacet_distrib(mirror->ufacet_distrib); 507 SSOL(mirror_setup(mtl, &shader, ufacet_distrib)); 508 SSOL(material_set_param_buffer(mtl, pbuf)); 509 510 exit: 511 if(pbuf) SSOL(param_buffer_ref_put(pbuf)); 512 *out_mtl = mtl; 513 return res; 514 error: 515 if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; 516 if(img) SSOL(image_ref_put(img)); 517 goto exit; 518 } 519 520 static res_T 521 create_material_thin_dielectric 522 (struct solstice* solstice, 523 const struct solparser_material_thin_dielectric* thin, 524 struct ssol_material** out_mtl) 525 { 526 struct ssol_image* img = NULL; 527 struct ssol_thin_dielectric_shader shader = SSOL_THIN_DIELECTRIC_SHADER_NULL; 528 const struct solparser_medium* medium_i = NULL; 529 const struct solparser_medium* medium_t = NULL; 530 struct ssol_medium ssol_medium_i = SSOL_MEDIUM_VACUUM; 531 struct ssol_medium ssol_medium_t = SSOL_MEDIUM_VACUUM; 532 struct ssol_material* mtl = NULL; 533 struct ssol_param_buffer* pbuf = NULL; 534 res_T res = RES_OK; 535 ASSERT(solstice && thin && out_mtl); 536 537 res = ssol_material_create_thin_dielectric(solstice->ssol, &mtl); 538 if(res != RES_OK) { 539 fprintf(stderr, 540 "Could not allocate the Solstice Solver thin dielectric material.\n"); 541 goto error; 542 } 543 544 medium_i = solparser_get_medium(solstice->parser, thin->medium_i); 545 medium_t = solparser_get_medium(solstice->parser, thin->medium_t); 546 547 if(!SOLPARSER_ID_IS_VALID(thin->normal_map)) { 548 shader.normal = mtl_get_normal; 549 } else { 550 const struct solparser_image* image; 551 struct dielectric_param* param = NULL; 552 553 image = solparser_get_image(solstice->parser, thin->normal_map); 554 res = load_image(solstice, str_cget(&image->filename), &img); 555 if(res != RES_OK) goto error; 556 557 res = ssol_param_buffer_create 558 (solstice->ssol, sizeof(struct thin_dielectric_param), &pbuf); 559 if(res != RES_OK) { 560 fprintf(stderr, "Could not create the Solsitce Solver parameter buffer.\n"); 561 goto error; 562 } 563 564 param = ssol_param_buffer_allocate(pbuf, 565 sizeof(struct thin_dielectric_param), 566 ALIGNOF(struct thin_dielectric_param), 567 thin_dielectric_param_release); 568 if(!param) { 569 fprintf(stderr, "Could not allocate the thin dielectric parameter.\n"); 570 res = RES_MEM_ERR; 571 goto error; 572 } 573 param->normal_map = img; 574 shader.normal = thin_dielectric_get_normal; 575 SSOL(material_set_param_buffer(mtl, pbuf)); 576 } 577 578 #define SET_SSOL_DATA(Medium, Name) { \ 579 res = mtl_to_ssol_data(solstice, &Medium->Name, &ssol_## Medium.Name); \ 580 if(res != RES_OK) goto error; \ 581 } (void)0 582 SET_SSOL_DATA(medium_i, refractive_index); 583 SET_SSOL_DATA(medium_t, refractive_index); 584 SET_SSOL_DATA(medium_i, extinction); 585 SET_SSOL_DATA(medium_t, extinction); 586 #undef SET_SSOL_DATA 587 SSOL(thin_dielectric_setup 588 (mtl, &shader, &ssol_medium_i, &ssol_medium_t, thin->thickness)); 589 590 exit: 591 ssol_medium_clear(&ssol_medium_i); 592 ssol_medium_clear(&ssol_medium_t); 593 if(pbuf) SSOL(param_buffer_ref_put(pbuf)); 594 *out_mtl = mtl; 595 return res; 596 error: 597 if(mtl) SSOL(material_ref_put(mtl)), mtl = NULL; 598 if(img) SSOL(image_ref_put(img)); 599 goto exit; 600 } 601 602 /******************************************************************************* 603 * Local functions 604 ******************************************************************************/ 605 res_T 606 scaled_mtl_to_ssol_data 607 (struct solstice* solstice, 608 const struct solparser_mtl_data* mtl_data, 609 const double scale_factor, 610 struct ssol_data* data) 611 { 612 struct ssol_spectrum* spectrum = NULL; 613 res_T res = RES_OK; 614 ASSERT(mtl_data && data); 615 616 ssol_data_clear(data); 617 switch(mtl_data->type) { 618 case SOLPARSER_MTL_DATA_REAL: 619 ssol_data_set_real(data, mtl_data->value.real*scale_factor); 620 break; 621 case SOLPARSER_MTL_DATA_SPECTRUM: 622 res = solstice_create_scaled_ssol_spectrum 623 (solstice, mtl_data->value.spectrum, scale_factor, &spectrum); 624 if(res != RES_OK) goto error; 625 ssol_data_set_spectrum(data, spectrum); 626 break; 627 default: FATAL("Unreachable code.\n"); break; 628 } 629 630 exit: 631 if(spectrum) SSOL(spectrum_ref_put(spectrum)); 632 return res; 633 error: 634 ssol_data_clear(data); 635 goto exit; 636 } 637 638 extern LOCAL_SYM res_T 639 mtl_to_ssol_data 640 (struct solstice* solstice, 641 const struct solparser_mtl_data* mtl_data, 642 struct ssol_data* data) 643 { 644 return scaled_mtl_to_ssol_data(solstice, mtl_data, 1.0, data); 645 } 646 647 res_T 648 solstice_create_ssol_material 649 (struct solstice* solstice, 650 const struct solparser_material_id mtl_id, 651 struct ssol_material** out_ssol_mtl) 652 { 653 const struct solparser_material* mtl; 654 struct ssol_material* ssol_mtl = NULL; 655 struct ssol_material** pssol_mtl = NULL; 656 res_T res = RES_OK; 657 ASSERT(solstice); 658 659 mtl = solparser_get_material(solstice->parser, mtl_id); 660 ASSERT(mtl); 661 662 if(mtl->type == SOLPARSER_MATERIAL_VIRTUAL) { 663 /* Use the global solstice virtual material */ 664 ssol_mtl = solstice->mtl_virtual; 665 } else { 666 pssol_mtl = htable_material_find(&solstice->materials, &mtl_id.i); 667 if(pssol_mtl) { 668 ssol_mtl = *pssol_mtl; 669 } else { 670 const struct solparser_material_dielectric* dielectric; 671 const struct solparser_material_matte* matte; 672 const struct solparser_material_mirror* mirror; 673 const struct solparser_material_thin_dielectric* thin_dielectric; 674 675 switch(mtl->type) { 676 case SOLPARSER_MATERIAL_DIELECTRIC: 677 dielectric = solparser_get_material_dielectric 678 (solstice->parser, mtl->data.dielectric); 679 res = create_material_dielectric(solstice, dielectric, &ssol_mtl); 680 break; 681 case SOLPARSER_MATERIAL_MATTE: 682 matte = solparser_get_material_matte 683 (solstice->parser, mtl->data.matte); 684 res = create_material_matte(solstice, matte, &ssol_mtl); 685 break; 686 case SOLPARSER_MATERIAL_MIRROR: 687 mirror = solparser_get_material_mirror 688 (solstice->parser, mtl->data.mirror); 689 res = create_material_mirror(solstice, mirror, &ssol_mtl); 690 break; 691 case SOLPARSER_MATERIAL_THIN_DIELECTRIC: 692 thin_dielectric = solparser_get_material_thin_dielectric 693 (solstice->parser, mtl->data.thin_dielectric); 694 res = create_material_thin_dielectric 695 (solstice, thin_dielectric, &ssol_mtl); 696 break; 697 default: FATAL("Unreachable code.\n"); break; 698 } 699 if(res != RES_OK) goto error; 700 701 /* Cache the created material for future use. */ 702 res = htable_material_set(&solstice->materials, &mtl_id.i, &ssol_mtl); 703 if(res != RES_OK) { 704 fprintf(stderr, "Could not register the material into solstice.\n"); 705 goto error; 706 } 707 } 708 } 709 710 /* Get an additional reference onto the material in order to give to the 711 * caller an ownership onto the returned material. */ 712 SSOL(material_ref_get(ssol_mtl)); 713 714 exit: 715 *out_ssol_mtl = ssol_mtl; 716 return res; 717 error: 718 if(ssol_mtl) SSOL(material_ref_put(ssol_mtl)); 719 goto exit; 720 } 721