solstice.c (22729B)
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 #define _POSIX_C_SOURCE 200112L /* close support */ 18 19 #include "solstice.h" 20 #include "solstice_c.h" 21 #include "solstice_args.h" 22 #include "parser/solparser.h" 23 24 #include <rsys/double2.h> 25 26 #include <sys/stat.h> 27 #include <sys/types.h> 28 29 #include <errno.h> 30 #include <stdio.h> 31 #include <fcntl.h> 32 33 #ifdef COMPILER_CL 34 /* Wrap POSIX functions and constants */ 35 #include <io.h> 36 #define open _open 37 #define close _close 38 #define fdopen _fdopen 39 #define S_IRUSR S_IREAD 40 #define S_IWUSR S_IWRITE 41 #else 42 /* open/close functions */ 43 #include <unistd.h> 44 #endif 45 46 #include <solstice/ssol.h> 47 48 /******************************************************************************* 49 * Helper functions 50 ******************************************************************************/ 51 static void 52 log_err(const char* msg, void* ctx) 53 { 54 ASSERT(msg); 55 (void)ctx; 56 #ifdef OS_WINDOWS 57 fprintf(stderr, "error: %s", msg); 58 #else 59 fprintf(stderr, "\x1b[31merror:\x1b[0m %s", msg); 60 #endif 61 } 62 63 static void 64 log_warn(const char* msg, void* ctx) 65 { 66 ASSERT(msg); 67 (void)ctx; 68 #ifdef OS_WINDOWS 69 fprintf(stderr,"warning: %s", msg); 70 #else 71 fprintf(stderr, "\x1b[33mwarning:\x1b[0m %s", msg); 72 #endif 73 } 74 75 static void 76 clear_materials(struct htable_material* materials) 77 { 78 struct htable_material_iterator it, end; 79 ASSERT(materials); 80 81 htable_material_begin(materials, &it); 82 htable_material_end(materials, &end); 83 while(!htable_material_iterator_eq(&it, &end)) { 84 struct ssol_material* mtl = *htable_material_iterator_data_get(&it); 85 SSOL(material_ref_put(mtl)); 86 htable_material_iterator_next(&it); 87 } 88 htable_material_clear(materials); 89 } 90 91 static void 92 clear_objects(struct htable_object* objects) 93 { 94 struct htable_object_iterator it, end; 95 ASSERT(objects); 96 97 htable_object_begin(objects, &it); 98 htable_object_end(objects, &end); 99 while(!htable_object_iterator_eq(&it, &end)) { 100 struct ssol_object* obj = *htable_object_iterator_data_get(&it); 101 SSOL(object_ref_put(obj)); 102 htable_object_iterator_next(&it); 103 } 104 htable_object_clear(objects); 105 } 106 107 static void 108 clear_nodes(struct darray_nodes* nodes) 109 { 110 size_t i, n; 111 ASSERT(nodes); 112 n = darray_nodes_size_get(nodes); 113 FOR_EACH(i, 0, n) { 114 solstice_node_ref_put(darray_nodes_data_get(nodes)[i]); 115 } 116 darray_nodes_clear(nodes); 117 } 118 119 static void 120 clear_anchors(struct htable_anchor* anchors) 121 { 122 struct htable_anchor_iterator it, end; 123 ASSERT(anchors); 124 125 htable_anchor_begin(anchors, &it); 126 htable_anchor_end(anchors, &end); 127 while(!htable_anchor_iterator_eq(&it, &end)) { 128 struct solstice_node* node = *htable_anchor_iterator_data_get(&it); 129 solstice_node_ref_put(node); 130 htable_anchor_iterator_next(&it); 131 } 132 htable_anchor_clear(anchors); 133 } 134 135 static res_T 136 auto_look_at 137 (struct ssol_scene* scn, 138 const double fov_x, /* Horizontal field of view in radian */ 139 const double proj_ratio, /* Width / height */ 140 const double up[3], /* Up vector */ 141 double position[3], 142 double target[3]) 143 { 144 float flower[3], fupper[3]; 145 double lower[3], upper[3]; 146 double up_abs[3]; 147 double axis_min[3]; 148 double axis_x[3]; 149 double axis_z[3]; 150 double tmp[3]; 151 double radius; 152 double depth; 153 res_T res; 154 ASSERT(scn && fov_x && proj_ratio && up); 155 156 res = ssol_scene_compute_aabb(scn, flower, fupper); 157 if(res != RES_OK) { 158 fprintf(stderr, "Couldn't compute the scene bounding box.\n"); 159 goto error; 160 } 161 162 if(flower[0] > fupper[0] 163 || flower[1] > fupper[1] 164 || flower[2] > fupper[2]) { /* Empty scene */ 165 d3_set(position, SOLSTICE_ARGS_DEFAULT.camera.pos); 166 d3_set(target, SOLSTICE_ARGS_DEFAULT.camera.tgt); 167 goto exit; 168 } 169 170 d3_set_f3(upper, fupper); 171 d3_set_f3(lower, flower); 172 173 /* The target is the scene centroid */ 174 d3_muld(target, d3_add(target, lower, upper), 0.5); 175 176 /* Define which up dimension is minimal and use its unit vector to compute a 177 * vector orthogonal to `up'. This ensures that the unit vector and `up' are 178 * not collinear and thus that their cross product is not a zero vector. */ 179 up_abs[0] = fabs(up[0]); 180 up_abs[1] = fabs(up[1]); 181 up_abs[2] = fabs(up[2]); 182 if(up_abs[0] < up_abs[1]) { 183 if(up_abs[0] < up_abs[2]) d3(axis_min, 1, 0, 0); 184 else d3(axis_min, 0, 0, 1); 185 } else { 186 if(up_abs[1] < up_abs[2]) d3(axis_min, 0, 1, 0); 187 else d3(axis_min, 0, 0, 1); 188 } 189 d3_normalize(axis_x, d3_cross(axis_x, up, axis_min)); 190 d3_normalize(axis_z, d3_cross(axis_z, up, axis_x)); 191 192 /* Approximate whether on the XYZ or the ZYX basis the visible part of the 193 * model is maximise */ 194 if(fabs(d3_dot(axis_x, upper)) < fabs(d3_dot(axis_z, upper))) { 195 SWAP(double, axis_x[0], axis_z[0]); 196 SWAP(double, axis_x[1], axis_z[1]); 197 SWAP(double, axis_x[2], axis_z[2]); 198 } 199 200 /* Ensure that the whole model is visible */ 201 radius = d3_len(d3_sub(tmp, upper, lower)) * 0.5; 202 if(proj_ratio < 1) { 203 depth = radius / sin(fov_x/2.0); 204 } else { 205 depth = radius / sin(fov_x/(2.0*proj_ratio)); 206 } 207 208 /* Define the camera position */ 209 d3_sub(position, target, d3_muld(tmp, axis_z, depth)); 210 211 /* Empirically move the position to find a better point of view */ 212 d3_add(position, position, d3_muld(tmp, up, radius)); /*Empirical offset*/ 213 d3_add(position, position, d3_muld(tmp, axis_x, radius)); /*Empirical offset*/ 214 d3_normalize(tmp, d3_sub(tmp, target, position)); 215 d3_sub(position, target, d3_muld(tmp, tmp, depth)); 216 217 exit: 218 return res; 219 error: 220 goto exit; 221 } 222 223 static res_T 224 setup_camera(struct solstice* solstice, const struct solstice_args* args) 225 { 226 struct ssol_camera* cam = NULL; 227 double proj_ratio = 0; 228 double pos[3], tgt[3]; 229 res_T res = RES_OK; 230 ASSERT(solstice && args); 231 232 res = ssol_camera_create(solstice->ssol, &cam); 233 if(res != RES_OK) { 234 fprintf(stderr, "Could not create the rendering camera.\n"); 235 goto error; 236 } 237 238 proj_ratio = (double)args->img.width / (double)args->img.height; 239 res = ssol_camera_set_proj_ratio(cam, proj_ratio); 240 if(res != RES_OK) { 241 fprintf(stderr, "Invalid image ratio '%g'.\n", proj_ratio); 242 goto error; 243 } 244 245 res = ssol_camera_set_fov(cam, MDEG2RAD(args->camera.fov_x)); 246 if(res != RES_OK) { 247 fprintf(stderr, "Invalid horizontal field of view '%g' degrees.\n", 248 args->camera.fov_x); 249 goto error; 250 } 251 252 if(!args->camera.auto_look_at) { 253 d3_set(pos, args->camera.pos); 254 d3_set(tgt, args->camera.tgt); 255 } else { 256 res = auto_look_at(solstice->scene, MDEG2RAD(args->camera.fov_x), 257 proj_ratio, args->camera.up, pos, tgt); 258 if(res != RES_OK) goto error; 259 } 260 261 res = ssol_camera_look_at(cam, pos, tgt, args->camera.up); 262 if(res != RES_OK) { 263 fprintf(stderr, 264 "Invalid camera point of view:\n" 265 " position = %g %g %g\n" 266 " target = %g %g %g\n" 267 " up = %g %g %g\n", 268 SPLIT3(args->camera.pos), 269 SPLIT3(args->camera.tgt), 270 SPLIT3(args->camera.up)); 271 goto error; 272 } 273 274 exit: 275 solstice->camera = cam; 276 return res; 277 error: 278 if(cam) { 279 SSOL(camera_ref_put(cam)); 280 cam = NULL; 281 } 282 goto exit; 283 } 284 285 static res_T 286 setup_framebuffer(struct solstice* solstice, const struct solstice_args* args) 287 { 288 struct ssol_image* fbuf = NULL; 289 res_T res = RES_OK; 290 ASSERT(solstice && args); 291 292 res = ssol_image_create(solstice->ssol, &fbuf); 293 if(res != RES_OK) { 294 fprintf(stderr, "Could not create the rendering framebuffer.\n"); 295 goto error; 296 } 297 298 res = ssol_image_setup 299 (fbuf, args->img.width, args->img.height, SSOL_PIXEL_DOUBLE3); 300 if(res != RES_OK) { 301 fprintf(stderr, 302 "Could not set the framebuffer definition to %lux%lu.\n", 303 args->img.width, args->img.height); 304 goto error; 305 } 306 307 exit: 308 solstice->framebuffer = fbuf; 309 return res; 310 311 error: 312 if(fbuf) { 313 SSOL(image_ref_put(fbuf)); 314 fbuf = NULL; 315 } 316 goto exit; 317 } 318 319 static INLINE void 320 spherical_to_cartesian_sun_dir 321 (struct solstice_args_spherical* spherical, double sun_dir[3]) 322 { 323 double cos_azimuth; 324 double sin_azimuth; 325 double cos_elevation; 326 double sin_elevation; 327 double azimuth; 328 double elevation; 329 ASSERT(spherical && sun_dir); 330 331 azimuth = MDEG2RAD(spherical->azimuth); 332 elevation = MDEG2RAD(spherical->elevation); 333 334 cos_azimuth = cos(azimuth); 335 sin_azimuth = sin(azimuth); 336 cos_elevation = cos(elevation); 337 sin_elevation = sin(elevation); 338 339 sun_dir[0] = -(cos_elevation * cos_azimuth); 340 sun_dir[1] = -(cos_elevation * sin_azimuth); 341 sun_dir[2] = -(sin_elevation); 342 } 343 344 static res_T 345 setup_sun_dirs(struct solstice* solstice, const struct solstice_args* args) 346 { 347 double* sun_dirs = NULL; 348 double* sun_angles = NULL; 349 size_t i; 350 res_T res = RES_OK; 351 ASSERT(solstice && args); 352 353 res = darray_double_resize(&solstice->sun_dirs, args->nsun_dirs*3/*#dims*/); 354 if(res != RES_OK) { 355 fprintf(stderr, 356 "Could not reserve the list of %lu sun directions.\n", 357 (unsigned long)args->nsun_dirs); 358 goto error; 359 } 360 res = darray_double_resize(&solstice->sun_angles, args->nsun_dirs*2/*#dims*/); 361 if(res != RES_OK) { 362 fprintf(stderr, 363 "Could not reserve the list of %lu sun angles.\n", 364 (unsigned long)args->nsun_dirs); 365 goto error; 366 } 367 sun_dirs = darray_double_data_get(&solstice->sun_dirs); 368 sun_angles = darray_double_data_get(&solstice->sun_angles); 369 FOR_EACH(i, 0, args->nsun_dirs) { 370 spherical_to_cartesian_sun_dir(args->sun_dirs + i, sun_dirs + i*3/*#dims*/); 371 d2(sun_angles + i*2, args->sun_dirs[i].azimuth, args->sun_dirs[i].elevation); 372 } 373 374 exit: 375 return res; 376 error: 377 darray_double_clear(&solstice->sun_dirs); 378 darray_double_clear(&solstice->sun_angles); 379 goto exit; 380 } 381 382 static res_T 383 load_data(struct solstice* solstice, const struct solstice_args* args) 384 { 385 struct solparser_entity_iterator it, end; 386 FILE* file = stdin; 387 const char* name = "stdin"; 388 res_T res = RES_OK; 389 ASSERT(solstice && args); 390 391 if(args->input_filename) { 392 file = fopen(args->input_filename, "r"); 393 if(!file) { 394 fprintf(stderr, "Could not open the file `%s'.\n", args->input_filename); 395 res = RES_IO_ERR; 396 goto error; 397 } 398 name = args->input_filename; 399 } else if(!args->quiet) { 400 #ifndef OS_WINDOWS 401 fprintf(stderr, 402 "Enter the solar facility data. Type ^D (i.e. CTRL+d) to stop:\n"); 403 #else 404 fprintf(stderr, 405 "Enter the solar facility data. Type ^Z (i.e. CTRL+z) to stop:\n"); 406 #endif 407 } 408 409 res = solparser_setup(solstice->parser, name, file); 410 if(res != RES_OK) goto error; 411 412 res = solparser_load(solstice->parser); 413 if(res != RES_OK) goto error; 414 415 solparser_entity_iterator_begin(solstice->parser, &it); 416 solparser_entity_iterator_end(solstice->parser, &end); 417 if(solparser_entity_iterator_eq(&it, &end)) { 418 fprintf(stderr, "No entity is defined.\n"); 419 res = RES_BAD_ARG; 420 goto error; 421 } 422 423 exit: 424 if(file && file != stdin) fclose(file); 425 return res; 426 error: 427 goto exit; 428 } 429 430 static res_T 431 setup_receivers(struct solstice* solstice, struct srcvl* srcvl) 432 { 433 size_t i, n; 434 res_T res = RES_OK; 435 ASSERT(solstice && srcvl); 436 437 htable_receiver_clear(&solstice->receivers); 438 darray_receiver_clear(&solstice->rcvs_list); 439 440 n = srcvl_count(srcvl); 441 442 res = darray_receiver_resize(&solstice->rcvs_list, n); 443 if(res != RES_OK) { 444 fprintf(stderr, "Could not reserve memory space for the receivers.\n"); 445 goto error; 446 } 447 448 FOR_EACH(i, 0, n) { 449 struct solstice_receiver* receiver; 450 struct srcvl_receiver rcv; 451 const struct solparser_entity* entity; 452 const char* name; 453 454 receiver = darray_receiver_data_get(&solstice->rcvs_list) + i; 455 456 srcvl_get(srcvl, i, &rcv); 457 entity = solparser_find_entity(solstice->parser, rcv.name); 458 if(!entity) { 459 fprintf(stderr, "Invalid entity `%s'.\n", rcv.name); 460 res = RES_BAD_ARG; 461 goto error; 462 } 463 464 if(entity->type != SOLPARSER_ENTITY_GEOMETRY) { 465 fprintf(stderr, 466 "The entity `%s' is not a geometry. It cannot be a receiver.\n", 467 rcv.name); 468 res = RES_BAD_ARG; 469 goto error; 470 } 471 472 res = str_set(&receiver->name, rcv.name); 473 if(res != RES_OK) { 474 fprintf(stderr, "Could not copy the receiver name.\n"); 475 goto error; 476 } 477 478 receiver->node = NULL; 479 receiver->side = rcv.side; 480 receiver->per_primitive_output = rcv.per_primitive_output; 481 482 name = str_cget(&receiver->name); 483 res = htable_receiver_set(&solstice->receivers, &name, &i); 484 if(res != RES_OK) { 485 fprintf(stderr, 486 "Could not register the receiver `%s' against Solstice.\n", 487 rcv.name); 488 goto error; 489 } 490 } 491 492 exit: 493 return res; 494 error: 495 htable_receiver_clear(&solstice->receivers); 496 darray_receiver_clear(&solstice->rcvs_list); 497 goto exit; 498 } 499 500 static res_T 501 load_receivers(struct solstice* solstice, const struct solstice_args* args) 502 { 503 FILE* file = NULL; 504 struct srcvl* srcvl = NULL; 505 res_T res = RES_OK; 506 ASSERT(solstice && args); 507 508 file = fopen(args->receivers_filename, "r"); 509 if(!file) { 510 fprintf(stderr, "Could not open the list of receivers `%s'.\n", 511 args->receivers_filename); 512 res = RES_IO_ERR; 513 goto error; 514 } 515 516 res = srcvl_create(solstice->allocator, &srcvl); 517 if(res != RES_OK) goto error; 518 res = srcvl_setup_stream(srcvl, args->receivers_filename, file); 519 if(res != RES_OK) goto error; 520 res = srcvl_load(srcvl); 521 if(res != RES_OK) goto error; 522 res = setup_receivers(solstice, srcvl); 523 if(res != RES_OK) goto error; 524 525 exit: 526 if(file) fclose(file); 527 if(srcvl) { 528 srcvl_ref_put(srcvl); 529 srcvl = NULL; 530 } 531 return res; 532 error: 533 goto exit; 534 } 535 536 static res_T 537 open_output_stream(const char* name, const int force_overwriting, FILE** stream) 538 { 539 res_T res = RES_OK; 540 int fd = -1; 541 FILE* fp = NULL; 542 ASSERT(name); 543 544 if(force_overwriting) { 545 fp = fopen(name, "w"); 546 if(!fp) { 547 fprintf(stderr, "Could not open the output file `%s'.\n", name); 548 goto error; 549 } 550 } else { 551 fd = open(name, O_CREAT|O_WRONLY|O_EXCL|O_TRUNC, S_IRUSR|S_IWUSR); 552 if(fd >= 0) { 553 fp = fdopen(fd, "w"); 554 if(fp == NULL) { 555 fprintf(stderr, "Could not open the output file `%s'.\n", name); 556 goto error; 557 } 558 } else if(errno == EEXIST) { 559 fprintf(stderr, 560 "The output file `%s' already exists. Use -f to overwrite it.\n", name); 561 goto error; 562 } else { 563 fprintf(stderr, 564 "Unexpected error while opening the output file `%s'.\n", name); 565 goto error; 566 } 567 } 568 569 exit: 570 *stream = fp; 571 return res; 572 error: 573 res = RES_IO_ERR; 574 if(fp) { 575 CHK(fclose(fp) == 0); 576 fp = NULL; 577 } else if(fd >= 0) { 578 CHK(close(fd) == 0); 579 } 580 goto exit; 581 } 582 583 /******************************************************************************* 584 * Solstice local functions 585 ******************************************************************************/ 586 res_T 587 solstice_init 588 (struct mem_allocator* allocator, 589 const struct solstice_args* args, 590 struct solstice* solstice) 591 { 592 res_T res = RES_OK; 593 ASSERT(solstice && args); 594 595 memset(solstice, 0, sizeof(struct solstice)); 596 htable_material_init(allocator, &solstice->materials); 597 htable_object_init(allocator, &solstice->objects); 598 htable_anchor_init(allocator, &solstice->anchors); 599 htable_receiver_init(allocator, &solstice->receivers); 600 htable_primary_init(allocator, &solstice->primaries); 601 darray_nodes_init(allocator, &solstice->roots); 602 darray_nodes_init(allocator, &solstice->pivots); 603 darray_receiver_init(allocator, &solstice->rcvs_list); 604 darray_double_init(allocator, &solstice->sun_dirs); 605 darray_double_init(allocator, &solstice->sun_angles); 606 607 solstice->allocator = allocator ? allocator : &mem_default_allocator; 608 609 logger_init(solstice->allocator, &solstice->logger); 610 logger_set_stream(&solstice->logger, LOG_ERROR, log_err, NULL); 611 logger_set_stream(&solstice->logger, LOG_WARNING, log_warn, NULL); 612 613 res = ssol_device_create(&solstice->logger, allocator, args->nthreads, 614 args->verbose, &solstice->ssol); 615 if(res != RES_OK) { 616 fprintf(stderr, "Could not create the Solstice Solver device.\n"); 617 goto error; 618 } 619 620 res = ssol_scene_create(solstice->ssol, &solstice->scene); 621 if(res != RES_OK) { 622 fprintf(stderr, "Could not create the Solstice Solver scene.\n"); 623 goto error; 624 } 625 626 res = ssol_material_create_virtual(solstice->ssol, &solstice->mtl_virtual); 627 if(res != RES_OK) { 628 fprintf(stderr, "Could not create the global virtual material.\n"); 629 goto error; 630 } 631 632 res = solparser_create(allocator, &solstice->parser); 633 if(res != RES_OK) { 634 fprintf(stderr, "Could not create the Solstice Parser.\n"); 635 goto error; 636 } 637 638 res = setup_sun_dirs(solstice, args); 639 if(res != RES_OK) goto error; 640 641 if(args->rng_state_input_filename) { 642 solstice->rng_state_input = fopen(args->rng_state_input_filename, "r"); 643 if(!solstice->rng_state_input) { 644 fprintf(stderr, "Could not open the input RNG state file.\n"); 645 res = RES_IO_ERR; 646 goto error; 647 } 648 } 649 650 if(args->rng_state_output_filename) { 651 res = open_output_stream(args->rng_state_output_filename, 652 args->force_overwriting, &solstice->rng_state_output); 653 if(res != RES_OK) goto error; 654 } 655 656 if(!args->output_filename) { 657 solstice->output = stdout; 658 } else { 659 res = open_output_stream(args->output_filename, args->force_overwriting, 660 &solstice->output); 661 if(res != RES_OK) goto error; 662 } 663 664 res = load_data(solstice, args); 665 if(res != RES_OK) goto error; 666 667 if(args->receivers_filename) { 668 res = load_receivers(solstice, args); 669 if(res != RES_OK) goto error; 670 } 671 672 res = solstice_setup_entities(solstice); 673 if(res != RES_OK) { 674 fprintf(stderr, "Could not setup the Solstice entities.\n"); 675 goto error; 676 } 677 678 res = solstice_create_sun(solstice); 679 if(res != RES_OK) { 680 fprintf(stderr, "Could not setup the Solstice sun.\n"); 681 goto error; 682 } 683 684 res = solstice_create_atmosphere(solstice); 685 if(res != RES_OK) { 686 fprintf(stderr, "Could not setup the Solstice atmosphere.\n"); 687 goto error; 688 } 689 690 solstice->nexperiments = args->nexperiments; 691 solstice->dump_format = args->dump_format; 692 solstice->dump_split_mode = args->dump_split_mode; 693 solstice->dump_paths = args->dump_paths; 694 695 solstice->path_tracker = SSOL_PATH_TRACKER_DEFAULT; 696 solstice->path_tracker.infinite_ray_length = args->infinite_ray_length; 697 solstice->path_tracker.sun_ray_length = args->sun_ray_length; 698 699 if(args->rendering) { 700 res = setup_camera(solstice, args); 701 if(res != RES_OK) goto error; 702 res = setup_framebuffer(solstice, args); 703 if(res != RES_OK) goto error; 704 solstice->render_mode = args->render_mode; 705 solstice->spp = args->img.spp; 706 d3_set(solstice->up, args->camera.up); 707 } 708 709 exit: 710 return res; 711 error: 712 solstice_release(solstice); 713 goto exit; 714 } 715 716 void 717 solstice_release(struct solstice* solstice) 718 { 719 ASSERT(solstice); 720 clear_materials(&solstice->materials); 721 clear_objects(&solstice->objects); 722 clear_nodes(&solstice->roots); 723 clear_anchors(&solstice->anchors); 724 /* Don't clear pivots, as they are cleared from some root */ 725 if(solstice->ssol) SSOL(device_ref_put(solstice->ssol)); 726 if(solstice->scene) SSOL(scene_ref_put(solstice->scene)); 727 if(solstice->sun) SSOL(sun_ref_put(solstice->sun)); 728 if(solstice->atmosphere) SSOL(atmosphere_ref_put(solstice->atmosphere)); 729 if(solstice->parser) solparser_ref_put(solstice->parser); 730 if(solstice->camera) SSOL(camera_ref_put(solstice->camera)); 731 if(solstice->framebuffer) SSOL(image_ref_put(solstice->framebuffer)); 732 if(solstice->output && solstice->output != stdout) fclose(solstice->output); 733 if(solstice->mtl_virtual) SSOL(material_ref_put(solstice->mtl_virtual)); 734 if(solstice->rng_state_input) fclose(solstice->rng_state_input); 735 if(solstice->rng_state_output) fclose(solstice->rng_state_output); 736 htable_material_release(&solstice->materials); 737 htable_object_release(&solstice->objects); 738 htable_anchor_release(&solstice->anchors); 739 htable_receiver_release(&solstice->receivers); 740 htable_primary_release(&solstice->primaries); 741 darray_nodes_release(&solstice->roots); 742 darray_nodes_release(&solstice->pivots); 743 darray_receiver_release(&solstice->rcvs_list); 744 darray_double_release(&solstice->sun_dirs); 745 darray_double_release(&solstice->sun_angles); 746 logger_release(&solstice->logger); 747 } 748 749 res_T 750 solstice_run(struct solstice* solstice) 751 { 752 const double* sun_dirs = NULL; 753 const double* sun_angles = NULL; 754 size_t nsun_dirs = 0; 755 size_t i; 756 int dump; 757 int draw; 758 res_T res = RES_OK; 759 ASSERT(solstice); 760 761 sun_dirs = darray_double_cdata_get(&solstice->sun_dirs); 762 sun_angles = darray_double_cdata_get(&solstice->sun_angles); 763 nsun_dirs = darray_double_size_get(&solstice->sun_dirs); 764 ASSERT(nsun_dirs%3 == 0); 765 nsun_dirs /= 3/*#dims*/; 766 767 dump = solstice->dump_format != SOLSTICE_ARGS_DUMP_NONE; 768 draw = solstice->framebuffer != NULL; 769 770 if(!nsun_dirs) { 771 const double sun_dir[3] = {0, 0, -1}; 772 773 res = ssol_sun_set_direction(solstice->sun, sun_dir); 774 if(res != RES_OK) { 775 fprintf(stderr, "Could not update the sun direction.\n"); 776 goto error; 777 } 778 779 fprintf(solstice->output, "#--- No Sun direction\n"); 780 781 if(dump) { 782 res = solstice_dump(solstice); 783 if(res != RES_OK) goto error; 784 } else { 785 ASSERT(draw); 786 res = solstice_draw(solstice); 787 if(res != RES_OK) goto error; 788 } 789 } else { 790 FOR_EACH(i, 0, nsun_dirs) { 791 const double* sun_dir = sun_dirs + i*3/*#dims*/; 792 const double* sun_angle = sun_angles + i*2/*#angles*/; 793 fprintf(solstice->output, "#--- Sun direction: %g %g (%g %g %g)\n", 794 SPLIT2(sun_angle), SPLIT3(sun_dir)); 795 796 res = solstice_update_entities(solstice, sun_dir); 797 if(res != RES_OK) goto error; 798 799 res = ssol_sun_set_direction(solstice->sun, sun_dir); 800 if(res != RES_OK) { 801 fprintf(stderr, "Could not update the sun direction.\n"); 802 goto error; 803 } 804 805 if(draw) { 806 res = solstice_draw(solstice); 807 if(res != RES_OK) goto error; 808 } else if(dump) { 809 res = solstice_dump(solstice); 810 if(res != RES_OK) goto error; 811 } else { 812 res = solstice_solve(solstice); 813 if(res != RES_OK) goto error; 814 } 815 } 816 } 817 818 exit: 819 return res; 820 error: 821 goto exit; 822 } 823