mrumtl.c (18838B)
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 #define _POSIX_C_SOURCE 200112L /* strtok_r support */ 17 18 #include "mrumtl.h" 19 #include "mrumtl_c.h" 20 #include "mrumtl_log.h" 21 22 #include <rsys/algorithm.h> 23 #include <rsys/cstr.h> 24 #include <rsys/text_reader.h> 25 26 #include <string.h> 27 28 /******************************************************************************* 29 * Helper functions 30 ******************************************************************************/ 31 static INLINE res_T 32 check_mrumtl_create_args(const struct mrumtl_create_args* args) 33 { 34 /* Nothing to check. Only return RES_BAD_ARG if args is NULL */ 35 return args ? RES_OK : RES_BAD_ARG; 36 } 37 38 static res_T 39 parse_brdf_lambertian 40 (struct mrumtl* mrumtl, 41 struct txtrdr* txtrdr, 42 char** tk_ctx, 43 struct brdf_lambertian* brdf) 44 { 45 char* tk = NULL; 46 res_T res = RES_OK; 47 ASSERT(mrumtl && txtrdr && tk_ctx && brdf); 48 49 tk = strtok_r(NULL, " \t", tk_ctx); 50 if(!tk) { 51 log_err(mrumtl, "%s:%lu: missing lambertian reflectivity.\n", 52 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 53 res = RES_BAD_ARG; 54 goto error; 55 } 56 57 res = cstr_to_double(tk, &brdf->reflectivity); 58 if(res != RES_OK) { 59 log_err(mrumtl, "%s:%lu: invalid lambertian reflectivity `%s'.\n", 60 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 61 res = RES_BAD_ARG; 62 goto error; 63 } 64 65 if(brdf->reflectivity < 0 || brdf->reflectivity > 1) { 66 log_err(mrumtl, "%s:%lu: the lambertian reflectivity must be in [0, 1] " 67 "while the submitted value is %g.\n", 68 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 69 brdf->reflectivity); 70 res = RES_BAD_ARG; 71 goto error; 72 } 73 74 tk = strtok_r(NULL, " \t", tk_ctx); 75 if(tk) { 76 log_warn(mrumtl, "%s:%lu: unexpected text `%s'.\n", 77 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 78 } 79 80 exit: 81 return res; 82 error: 83 goto exit; 84 } 85 86 static res_T 87 parse_brdf_specular 88 (struct mrumtl* mrumtl, 89 struct txtrdr* txtrdr, 90 char** tk_ctx, 91 struct brdf_specular* brdf) 92 { 93 char* tk = NULL; 94 res_T res = RES_OK; 95 ASSERT(mrumtl && txtrdr && tk_ctx && brdf); 96 97 tk = strtok_r(NULL, " \t", tk_ctx); 98 if(!tk) { 99 log_err(mrumtl, "%s:%lu: missing specular reflectivity.\n", 100 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 101 res = RES_BAD_ARG; 102 goto error; 103 } 104 105 res = cstr_to_double(tk, &brdf->reflectivity); 106 if(res != RES_OK) { 107 log_err(mrumtl, "%s:%lu: invalid specular reflectivity `%s'.\n", 108 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 109 res = RES_BAD_ARG; 110 goto error; 111 } 112 113 if(brdf->reflectivity < 0 || brdf->reflectivity > 1) { 114 log_err(mrumtl, "%s:%lu: the specular reflectivity must be in [0, 1] " 115 "while the submitted value is %g.\n", 116 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 117 brdf->reflectivity); 118 res = RES_BAD_ARG; 119 goto error; 120 } 121 122 tk = strtok_r(NULL, " \t", tk_ctx); 123 if(tk) { 124 log_warn(mrumtl, "%s:%lu: unexpected text `%s'.\n", 125 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 126 } 127 128 exit: 129 return res; 130 error: 131 goto exit; 132 } 133 134 static res_T 135 parse_brdf 136 (struct mrumtl* mrumtl, 137 struct txtrdr* txtrdr, 138 char** tk_ctx, 139 struct mrumtl_brdf* brdf) 140 { 141 char* tk = NULL; 142 res_T res = RES_OK; 143 ASSERT(mrumtl && txtrdr && tk_ctx && brdf); 144 145 tk = strtok_r(NULL, " \t", tk_ctx); 146 if(!tk) { 147 log_err(mrumtl, "%s:%lu: missing BRDF type.\n", 148 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 149 res = RES_BAD_ARG; 150 goto error; 151 } 152 153 if(!strcmp(tk, "lambertian")) { 154 brdf->type = MRUMTL_BRDF_LAMBERTIAN; 155 res = parse_brdf_lambertian(mrumtl, txtrdr, tk_ctx, &brdf->param.lambertian); 156 if(res != RES_OK) goto error; 157 158 } else if(!strcmp(tk, "specular")) { 159 brdf->type = MRUMTL_BRDF_SPECULAR; 160 res = parse_brdf_specular(mrumtl, txtrdr, tk_ctx, &brdf->param.specular); 161 if(res != RES_OK) goto error; 162 163 } else { 164 log_err(mrumtl, "%s:%lu: invalid BRDF type `%s'.\n", 165 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 166 res = RES_BAD_ARG; 167 goto error; 168 } 169 170 exit: 171 return res; 172 error: 173 goto exit; 174 } 175 176 static res_T 177 parse_wlen_brdf 178 (struct mrumtl* mrumtl, 179 struct txtrdr* txtrdr, 180 struct mrumtl_brdf* brdf) 181 { 182 char* tk = NULL; 183 char* tk_ctx = NULL; 184 double wlen = 0; 185 res_T res = RES_OK; 186 ASSERT(mrumtl && txtrdr && brdf); 187 188 res = txtrdr_read_line(txtrdr); 189 if(res != RES_OK) { 190 log_err(mrumtl, "%s: could not read the line `%lu' -- %s.\n", 191 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 192 res_to_cstr(res)); 193 goto error; 194 } 195 196 if(!txtrdr_get_cline(txtrdr)) { 197 const size_t nexpect = darray_brdf_size_get(&mrumtl->brdfs); 198 const size_t nparsed = (size_t) 199 (brdf - darray_brdf_cdata_get(&mrumtl->brdfs)); 200 log_err(mrumtl, 201 "%s:%lu: missing BRDF. " 202 "Expecting %lu BRDF%swhile %lu %s parsed.\n", 203 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 204 (unsigned long)nexpect, nexpect == 1 ? " " : "s ", 205 (unsigned long)nparsed, nparsed > 1 ? "were" : "was"); 206 res = RES_BAD_ARG; 207 goto error; 208 } 209 210 tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); 211 ASSERT(tk); 212 213 res = cstr_to_double(tk, &wlen); 214 if(res == RES_OK && wlen < 0) res = RES_BAD_ARG; 215 if(res != RES_OK) { 216 log_err(mrumtl, "%s:%lu: invalid wavelength `%s'.\n", 217 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 218 goto error; 219 } 220 brdf->wlen[0] = wlen; 221 brdf->wlen[1] = wlen; 222 223 res = parse_brdf(mrumtl, txtrdr, &tk_ctx, brdf); 224 if(res != RES_OK) goto error; 225 226 exit: 227 return res; 228 error: 229 goto exit; 230 } 231 232 static res_T 233 parse_band_brdf 234 (struct mrumtl* mrumtl, 235 struct txtrdr* txtrdr, 236 struct mrumtl_brdf* brdf) 237 { 238 char* tk = NULL; 239 char* tk_ctx = NULL; 240 res_T res = RES_OK; 241 ASSERT(mrumtl && txtrdr && brdf); 242 243 res = txtrdr_read_line(txtrdr); 244 if(res != RES_OK) { 245 log_err(mrumtl, "%s: could not read the line `%lu' -- %s.\n", 246 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 247 res_to_cstr(res)); 248 goto error; 249 } 250 251 if(!txtrdr_get_cline(txtrdr)) { 252 const size_t nexpect = darray_brdf_size_get(&mrumtl->brdfs); 253 const size_t nparsed = (size_t) 254 (brdf - darray_brdf_cdata_get(&mrumtl->brdfs)); 255 log_err(mrumtl, 256 "%s:%lu: missing BRDF. " 257 "Expecting %lu BRDF%swhile %lu %s parsed.\n", 258 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 259 (unsigned long)nexpect, nexpect == 1 ? " " : "s ", 260 (unsigned long)nparsed, nparsed > 1 ? "were" : "was"); 261 res = RES_BAD_ARG; 262 goto error; 263 } 264 265 tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); 266 ASSERT(tk); 267 268 res = cstr_to_double(tk, &brdf->wlen[0]); 269 if(res == RES_OK && brdf->wlen[0] < 0) res = RES_BAD_ARG; 270 if(res != RES_OK) { 271 log_err(mrumtl, "%s:%lu: invalid band min boundary `%s'.\n", 272 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 273 goto error; 274 } 275 276 tk = strtok_r(NULL, " \t", &tk_ctx); 277 if(!tk) { 278 log_err(mrumtl, "%s:%lu: missing band max boundary.\n", 279 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 280 res = RES_BAD_ARG; 281 goto error; 282 } 283 284 res = cstr_to_double(tk, &brdf->wlen[1]); 285 if(res == RES_OK && brdf->wlen[1] < 0) res = RES_BAD_ARG; 286 if(res != RES_OK) { 287 log_err(mrumtl, "%s:%lu: invalid band max boundary `%s'.\n", 288 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 289 goto error; 290 } 291 292 if(brdf->wlen[0] > brdf->wlen[1]) { 293 log_err(mrumtl, "%s:%lu: band boundaries are degenerated -- [%g, %g].\n", 294 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 295 brdf->wlen[0], brdf->wlen[1]); 296 res = RES_BAD_ARG; 297 goto error; 298 } 299 300 res = parse_brdf(mrumtl, txtrdr, &tk_ctx, brdf); 301 if(res != RES_OK) goto error; 302 303 exit: 304 return res; 305 error: 306 goto exit; 307 } 308 309 static res_T 310 parse_per_wlen_brdf(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) 311 { 312 char* tk = NULL; 313 unsigned long count = 0; 314 unsigned long i; 315 res_T res = RES_OK; 316 ASSERT(mrumtl && txtrdr && tk_ctx); 317 318 tk = strtok_r(NULL, " \t", tk_ctx); 319 if(!tk) { 320 log_err(mrumtl, "%s:%lu: the number of wavelengths is missing.\n", 321 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 322 res = RES_BAD_ARG; 323 goto error; 324 } 325 326 res = cstr_to_ulong(tk, &count); 327 if(res != RES_OK) { 328 log_err(mrumtl, "%s:%lu: invalid number of wavelengths `%s'.\n", 329 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 330 res = RES_BAD_ARG; 331 goto error; 332 } 333 334 tk = strtok_r(NULL, " \t", tk_ctx); 335 if(tk) { 336 log_warn(mrumtl, "%s:%lu: unexpected text `%s'.\n", 337 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 338 } 339 340 res = darray_brdf_resize(&mrumtl->brdfs, count); 341 if(res != RES_OK) { 342 log_err(mrumtl, 343 "%s:%lu: could not allocate the list of BRDFs -- %s.\n", 344 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 345 res_to_cstr(res)); 346 goto error; 347 } 348 349 FOR_EACH(i, 0, count) { 350 struct mrumtl_brdf* brdf = NULL; 351 352 brdf = darray_brdf_data_get(&mrumtl->brdfs) + i; 353 354 res = parse_wlen_brdf(mrumtl, txtrdr, brdf); 355 if(res != RES_OK) goto error; 356 ASSERT(brdf->wlen[0] == brdf->wlen[1]); 357 358 if(i > 0 && brdf[0].wlen[0] <= brdf[-1].wlen[0]) { 359 log_err(mrumtl, 360 "%s:%lu: the BRDFs must be sorted un ascending order of wavelengths " 361 "(brdf %lu at %g nm; brdf %lu at %g nm).\n", 362 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 363 (unsigned long)(i-1), brdf[-1].wlen[0], 364 (unsigned long)(i), brdf[ 0].wlen[0]); 365 res = RES_BAD_ARG; 366 goto error; 367 } 368 } 369 370 exit: 371 return res; 372 error: 373 darray_brdf_clear(&mrumtl->brdfs); 374 goto exit; 375 } 376 377 static res_T 378 parse_per_band_brdf(struct mrumtl* mrumtl, struct txtrdr* txtrdr, char** tk_ctx) 379 { 380 char* tk = NULL; 381 unsigned long count = 0; 382 unsigned long i = 0; 383 res_T res = RES_OK; 384 ASSERT(mrumtl && txtrdr && tk_ctx); 385 386 tk = strtok_r(NULL, " \t", tk_ctx); 387 if(!tk) { 388 log_err(mrumtl, "%s:%lu: the number of bands is missing.\n", 389 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr)); 390 res = RES_BAD_ARG; 391 goto error; 392 } 393 394 res = cstr_to_ulong(tk, &count); 395 if(res != RES_OK) { 396 log_err(mrumtl, "%s:%lu: invalid number of bands `%s'.\n", 397 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 398 res = RES_BAD_ARG; 399 goto error; 400 } 401 402 tk = strtok_r(NULL, " \t", tk_ctx); 403 if(tk) { 404 log_warn(mrumtl, "%s:%lu: unexpected text `%s'.\n", 405 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 406 } 407 408 res = darray_brdf_resize(&mrumtl->brdfs, count); 409 if(res != RES_OK) { 410 log_err(mrumtl, 411 "%s:%lu: could not allocate the list of BRDFs -- %s.\n", 412 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 413 res_to_cstr(res)); 414 goto error; 415 } 416 417 FOR_EACH(i, 0, count) { 418 struct mrumtl_brdf* brdf = NULL; 419 420 brdf = darray_brdf_data_get(&mrumtl->brdfs) + i; 421 422 res = parse_band_brdf(mrumtl, txtrdr, brdf); 423 if(res != RES_OK) goto error; 424 425 if(i > 0) { 426 if(brdf[0].wlen[0] < brdf[-1].wlen[1] 427 || brdf[0].wlen[0] == brdf[-1].wlen[0]) { 428 log_err(mrumtl, 429 "%s:%lu: the BRDFs must be sorted in ascending order " 430 "of bands and must not overlap (BRDF %lu in [%g, %g] nm; " 431 "BRDF %lu in [%g %g] nm)\n", 432 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 433 (unsigned long)(i-1), brdf[-1].wlen[0], brdf[-1].wlen[1], 434 (unsigned long)(i), brdf[ 0].wlen[0], brdf[ 0].wlen[1]); 435 res = RES_BAD_ARG; 436 goto error; 437 } 438 } 439 } 440 441 exit: 442 return res; 443 error: 444 darray_brdf_clear(&mrumtl->brdfs); 445 goto exit; 446 } 447 448 static INLINE void 449 clear_mrumtl(struct mrumtl* mrumtl) 450 { 451 ASSERT(mrumtl); 452 str_clear(&mrumtl->name); 453 darray_brdf_clear(&mrumtl->brdfs); 454 } 455 456 static res_T 457 load_stream 458 (struct mrumtl* mrumtl, 459 FILE* stream, 460 const char* stream_name) 461 { 462 char* tk = NULL; 463 char* tk_ctx = NULL; 464 struct txtrdr* txtrdr = NULL; 465 res_T res = RES_OK; 466 ASSERT(mrumtl && stream && stream_name); 467 468 clear_mrumtl(mrumtl); 469 470 res = txtrdr_stream(mrumtl->allocator, stream, stream_name, '#', &txtrdr); 471 if(res != RES_OK) { 472 log_err(mrumtl, "Could not create the text reader to parse `%s' -- %s.\n", 473 stream_name, res_to_cstr(res)); 474 goto error; 475 } 476 477 res = txtrdr_read_line(txtrdr); 478 if(res != RES_OK) { 479 log_err(mrumtl, "%s: could not read the line `%lu' -- %s.\n", 480 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), 481 res_to_cstr(res)); 482 goto error; 483 } 484 485 res = str_set(&mrumtl->name, stream_name); 486 if(res != RES_OK) { 487 log_err(mrumtl, "Could not copy the stream name `%s' -- %s.\n", 488 stream_name, res_to_cstr(res)); 489 goto error; 490 } 491 492 if(!txtrdr_get_cline(txtrdr)) goto exit; /* No line to parse */ 493 494 tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx); 495 ASSERT(tk); 496 497 if(!strcmp(tk, "wavelengths")) { 498 res = parse_per_wlen_brdf(mrumtl, txtrdr, &tk_ctx); 499 if(res != RES_BAD_ARG) goto error; 500 } else if(!strcmp(tk, "bands")) { 501 res = parse_per_band_brdf(mrumtl, txtrdr, &tk_ctx); 502 if(res != RES_BAD_ARG) goto error; 503 } else { 504 log_err(mrumtl, "%s:%lu: invalid directive `%s'.\n", 505 txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk); 506 res = RES_BAD_ARG; 507 goto error; 508 } 509 510 exit: 511 if(txtrdr) txtrdr_ref_put(txtrdr); 512 return res; 513 error: 514 goto exit; 515 } 516 517 static void 518 release_mrumtl(ref_T* ref) 519 { 520 struct mrumtl* mrumtl; 521 ASSERT(ref); 522 mrumtl = CONTAINER_OF(ref, struct mrumtl, ref); 523 524 darray_brdf_release(&mrumtl->brdfs); 525 str_release(&mrumtl->name); 526 527 /* First release the programs that uses the libs array */ 528 if(mrumtl->logger == &mrumtl->logger__) logger_release(&mrumtl->logger__); 529 MEM_RM(mrumtl->allocator, mrumtl); 530 } 531 532 /******************************************************************************* 533 * Exported functions 534 ******************************************************************************/ 535 res_T 536 mrumtl_create 537 (const struct mrumtl_create_args* args, 538 struct mrumtl** out_mrumtl) 539 { 540 struct mrumtl* mrumtl = NULL; 541 struct mem_allocator* allocator = NULL; 542 res_T res = RES_OK; 543 544 if(!out_mrumtl) { res = RES_BAD_ARG; goto error; } 545 res = check_mrumtl_create_args(args); 546 if(res != RES_OK) goto error; 547 548 allocator = args->allocator ? args->allocator : &mem_default_allocator; 549 mrumtl = MEM_CALLOC(allocator, 1, sizeof(*mrumtl)); 550 if(!mrumtl) { 551 if(args->verbose) { 552 #define ERR_STR "Could not allocate the MruMtl handler.\n" 553 if(args->logger) { 554 logger_print(args->logger, LOG_ERROR, ERR_STR); 555 } else { 556 fprintf(stderr, MSG_ERROR_PREFIX ERR_STR); 557 } 558 #undef ERR_STR 559 } 560 res = RES_MEM_ERR; 561 goto error; 562 } 563 ref_init(&mrumtl->ref); 564 mrumtl->allocator = allocator; 565 mrumtl->verbose = args->verbose; 566 darray_brdf_init(mrumtl->allocator, &mrumtl->brdfs); 567 str_init(mrumtl->allocator, &mrumtl->name); 568 569 if(args->logger) { 570 mrumtl->logger = args->logger; 571 } else { 572 res = setup_log_default(mrumtl); 573 if(res != RES_OK) { 574 if(args->verbose) { 575 fprintf(stderr, MSG_ERROR_PREFIX 576 "Could not setup the MruMtl logger.\n"); 577 } 578 goto error; 579 } 580 mrumtl->logger = &mrumtl->logger__; 581 } 582 583 exit: 584 if(out_mrumtl) *out_mrumtl = mrumtl; 585 return res; 586 error: 587 if(mrumtl) { 588 MRUMTL(ref_put(mrumtl)); 589 mrumtl = NULL; 590 } 591 goto exit; 592 } 593 594 res_T 595 mrumtl_ref_get(struct mrumtl* mrumtl) 596 { 597 if(!mrumtl) return RES_BAD_ARG; 598 ref_get(&mrumtl->ref); 599 return RES_OK; 600 } 601 602 res_T 603 mrumtl_ref_put(struct mrumtl* mrumtl) 604 { 605 if(!mrumtl) return RES_BAD_ARG; 606 ref_put(&mrumtl->ref, release_mrumtl); 607 return RES_OK; 608 } 609 610 res_T 611 mrumtl_load(struct mrumtl* mrumtl, const char* filename) 612 { 613 FILE* fp = NULL; 614 res_T res = RES_OK; 615 616 if(!mrumtl || !filename) { 617 res = RES_BAD_ARG; 618 goto error; 619 } 620 621 fp = fopen(filename, "r"); 622 if(!fp) { 623 log_err(mrumtl, "%s: error opening file `%s' -- %s.\n", 624 FUNC_NAME, filename, strerror(errno)); 625 res = RES_IO_ERR; 626 goto error; 627 } 628 629 res = load_stream(mrumtl, fp, filename); 630 if(res != RES_OK) goto error; 631 632 exit: 633 if(fp) fclose(fp); 634 return res; 635 error: 636 goto exit; 637 } 638 639 res_T 640 mrumtl_load_stream 641 (struct mrumtl* mrumtl, 642 FILE* stream, 643 const char* stream_name) 644 { 645 res_T res = RES_OK; 646 647 if(!mrumtl || !stream) { 648 res = RES_BAD_ARG; 649 goto error; 650 } 651 652 res = load_stream(mrumtl, stream, stream_name ? stream_name : "<stream>"); 653 if(res != RES_OK) goto error; 654 655 exit: 656 return res; 657 error: 658 goto exit; 659 } 660 661 size_t 662 mrumtl_get_brdfs_count(const struct mrumtl* mrumtl) 663 { 664 ASSERT(mrumtl); 665 return darray_brdf_size_get(&mrumtl->brdfs); 666 } 667 668 const struct mrumtl_brdf* 669 mrumtl_get_brdf(const struct mrumtl* mrumtl, const size_t ibrdf) 670 { 671 ASSERT(mrumtl && ibrdf < mrumtl_get_brdfs_count(mrumtl)); 672 return darray_brdf_cdata_get(&mrumtl->brdfs) + ibrdf; 673 } 674 675 enum mrumtl_brdf_type 676 mrumtl_brdf_get_type(const struct mrumtl_brdf* brdf) 677 { 678 ASSERT(brdf); 679 return brdf->type; 680 } 681 682 res_T 683 mrumtl_brdf_get_lambertian 684 (const struct mrumtl_brdf* brdf, 685 struct mrumtl_brdf_lambertian* lambertian) 686 { 687 if(!brdf || !lambertian) return RES_BAD_ARG; 688 if(brdf->type != MRUMTL_BRDF_LAMBERTIAN) return RES_BAD_ARG; 689 lambertian->wavelengths[0] = brdf->wlen[0]; 690 lambertian->wavelengths[1] = brdf->wlen[1]; 691 lambertian->reflectivity = brdf->param.lambertian.reflectivity; 692 return RES_OK; 693 } 694 695 res_T 696 mrumtl_brdf_get_specular 697 (const struct mrumtl_brdf* brdf, 698 struct mrumtl_brdf_specular* specular) 699 { 700 if(!brdf || !specular) return RES_BAD_ARG; 701 if(brdf->type != MRUMTL_BRDF_SPECULAR) return RES_BAD_ARG; 702 specular->wavelengths[0] = brdf->wlen[0]; 703 specular->wavelengths[1] = brdf->wlen[1]; 704 specular->reflectivity = brdf->param.specular.reflectivity; 705 return RES_OK; 706 } 707