solstice-solver

Solver library of the solstice app
git clone git://git.meso-star.com/solstice-solver.git
Log | Files | Refs | README | LICENSE

commit 617cc197d9c3b90196aad0674d28c4107f88d50f
parent 507c5813afe8e4c9c27362c1de7ed0794ac0a718
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  2 Sep 2016 08:58:05 +0200

Merge remote-tracking branch 'origin/master'

Diffstat:
Msrc/ssol.h | 5+++++
Msrc/ssol_c.h | 12+-----------
Msrc/ssol_material.c | 1+
Msrc/ssol_material_c.h | 2++
Msrc/ssol_object_instance.c | 13+++++++++++++
Msrc/ssol_object_instance_c.h | 8++++++++
Msrc/ssol_scene.c | 85+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/ssol_scene_c.h | 4++--
Msrc/ssol_shape.c | 2+-
Msrc/ssol_solver.c | 748++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/ssol_solver_c.h | 76+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/test_ssol_geometries.h | 16+++++++++-------
Msrc/test_ssol_object_instance.c | 5+++++
Msrc/test_ssol_solver.c | 103++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
14 files changed, 706 insertions(+), 374 deletions(-)

diff --git a/src/ssol.h b/src/ssol.h @@ -424,6 +424,11 @@ ssol_object_instance_set_receiver const char* name); /* May be NULL <=> it is no more a receiver */ SSOL_API res_T +ssol_object_instance_set_target_mask + (struct ssol_object_instance* instance, + const uint32_t mask); + +SSOL_API res_T ssol_object_instance_is_attached (struct ssol_object_instance* instance, char* is_attached); diff --git a/src/ssol_c.h b/src/ssol_c.h @@ -23,16 +23,6 @@ #define SSOL_TO_S3D_NORMAL S3D_ATTRIB_0 #define SSOL_TO_S3D_TEXCOORD S3D_ATTRIB_1 -struct ray_data { - struct ssol_scene* scene; /* Scene in which the ray is traced */ - struct s3d_primitive prim_from; /* Primitive from which the ray starts */ - unsigned path_id; /* Identifier of the path to which the ray belongs to */ - unsigned ray_id; /* Identifier of the ray into the path */ - double radiance; /* Current path radiance in W.sr^-1.m^-2 */ - double wavelength; /* Wavelength of the current path in nanometer */ - FILE* stream; -}; - static FINLINE enum s3d_attrib_usage ssol_to_s3d_attrib_usage(const enum ssol_attrib_usage usage) { @@ -49,7 +39,7 @@ hit_filter_function (const struct s3d_hit* hit, const float org[3], const float dir[3], - void* ray_data, + void* realization, void* filter_data); #endif /* SSOL_C_H */ diff --git a/src/ssol_material.c b/src/ssol_material.c @@ -231,6 +231,7 @@ surface_fragment_setup float transform[12]; float vec[3]; + /* TODO: review this code */ S3D(primitive_get_attrib(primitive, SSOL_TO_S3D_NORMAL, uv, &attr)); ASSERT(attr.type == S3D_FLOAT3); diff --git a/src/ssol_material_c.h b/src/ssol_material_c.h @@ -20,6 +20,8 @@ struct brdf_composite; struct s3d_hit; +struct s3d_primitive; +struct ssol_device; struct surface_fragment { double dir[3]; /* World space incoming direction */ diff --git a/src/ssol_object_instance.c b/src/ssol_object_instance.c @@ -74,6 +74,7 @@ ssol_object_instantiate instance->dev = dev; instance->object = object; + instance->target_mask = 0; str_init(dev->allocator, &instance->receiver_name); SSOL(object_ref_get(object)); SSOL(device_ref_get(dev)); @@ -145,6 +146,18 @@ ssol_object_instance_set_receiver } res_T +ssol_object_instance_set_target_mask + (struct ssol_object_instance* instance, + const uint32_t mask) +{ + if (!instance) + return RES_BAD_ARG; + + instance->target_mask = mask; + return RES_OK; +} + +res_T ssol_object_instance_is_attached (struct ssol_object_instance* instance, char* is_attached) { diff --git a/src/ssol_object_instance_c.h b/src/ssol_object_instance_c.h @@ -25,6 +25,7 @@ struct ssol_object_instance struct ssol_object* object; /* Instantiated object */ struct s3d_shape* s3d_shape; /* Instantiated Star-3D shape */ struct str receiver_name; /* Empty if not a receiver */ + uint32_t target_mask; struct ssol_device* dev; ref_T ref; @@ -53,4 +54,11 @@ object_instance_get_receiver_name(const struct ssol_object_instance* instance) ? NULL : str_cget(&instance->receiver_name); } +static INLINE uint32_t +object_instance_get_target_mask(const struct ssol_object_instance* instance) +{ + ASSERT(instance); + return instance->target_mask; +} + #endif /* SSOL_OBJECT_INSTANCE_C_H */ diff --git a/src/ssol_scene.c b/src/ssol_scene.c @@ -16,6 +16,7 @@ #include "ssol.h" #include "ssol_c.h" #include "ssol_scene_c.h" +#include "ssol_solver_c.h" #include "ssol_sun_c.h" #include "ssol_device_c.h" #include "ssol_material_c.h" @@ -39,7 +40,7 @@ scene_release(ref_T* ref) dev = scene->dev; ASSERT(dev && dev->allocator); SSOL(scene_clear(scene)); - if (scene->s3d_scn) S3D(scene_ref_put(scene->s3d_scn)); + if (scene->s3d_raytracing_scn) S3D(scene_ref_put(scene->s3d_raytracing_scn)); if (scene->s3d_sampling_scn) S3D(scene_ref_put(scene->s3d_sampling_scn)); if(scene->sun) SSOL(sun_ref_put(scene->sun)); htable_instance_release(&scene->instances); @@ -72,7 +73,7 @@ ssol_scene_create scene->dev = dev; ref_init(&scene->ref); - res = s3d_scene_create(dev->s3d, &scene->s3d_scn); + res = s3d_scene_create(dev->s3d, &scene->s3d_raytracing_scn); if (res != RES_OK) goto error; res = s3d_scene_create(dev->s3d, &scene->s3d_sampling_scn); @@ -116,8 +117,8 @@ ssol_scene_attach_object_instance if(!scene || !instance) return RES_BAD_ARG; shape = object_instance_get_s3d_shape(instance); - /* Try to attach the instantiated s3d shape to s3d scene */ - res = s3d_scene_attach_shape(scene->s3d_scn, shape); + /* attach the instantiated s3d shape to s3d scene */ + res = s3d_scene_attach_shape(scene->s3d_raytracing_scn, shape); if(res != RES_OK) return res; /* Register the instance against the scene */ @@ -125,7 +126,7 @@ ssol_scene_attach_object_instance ASSERT(!htable_instance_find(&scene->instances, &id)); res = htable_instance_set(&scene->instances, &id, &instance); if(res != RES_OK) { - S3D(scene_detach_shape(scene->s3d_scn, shape)); + S3D(scene_detach_shape(scene->s3d_raytracing_scn, shape)); return res; } SSOL(object_instance_ref_get(instance)); @@ -159,7 +160,7 @@ ssol_scene_detach_object_instance /* Detach the object instance */ n = htable_instance_erase(&scene->instances, &id); ASSERT(n == 1); - S3D(scene_detach_shape(scene->s3d_scn, shape)); + S3D(scene_detach_shape(scene->s3d_raytracing_scn, shape)); SSOL(object_instance_ref_put(instance)); return RES_OK; @@ -176,12 +177,12 @@ ssol_scene_clear(struct ssol_scene* scene) while(!htable_instance_iterator_eq(&it, &it_end)) { struct ssol_object_instance* inst; inst = *htable_instance_iterator_data_get(&it); - S3D(scene_detach_shape(scene->s3d_scn, object_instance_get_s3d_shape(inst))); + S3D(scene_detach_shape(scene->s3d_raytracing_scn, object_instance_get_s3d_shape(inst))); SSOL(object_instance_ref_put(inst)); htable_instance_iterator_next(&it); } htable_instance_clear(&scene->instances); - S3D(scene_clear(scene->s3d_scn)); + S3D(scene_clear(scene->s3d_raytracing_scn)); if(scene->sun) ssol_scene_detach_sun(scene, scene->sun); return RES_OK; @@ -218,10 +219,10 @@ ssol_scene_detach_sun(struct ssol_scene* scene, struct ssol_sun* sun) * Local functions ******************************************************************************/ struct s3d_scene* -scene_get_s3d_scene(const struct ssol_scene* scn) +scene_get_s3d_raytracing_scn(const struct ssol_scene* scn) { ASSERT(scn); - return scn->s3d_scn; + return scn->s3d_raytracing_scn; } struct s3d_scene* @@ -251,46 +252,66 @@ hit_filter_function (const struct s3d_hit* hit, const float org[3], const float dir[3], - void* ray_data, + void* realization, void* filter_data) { - struct ray_data* rdata = ray_data; struct ssol_object_instance* instance; struct ssol_material* material; const char* receiver_name; - (void)org, (void)dir, (void)filter_data; - ASSERT(rdata); - - if(!ray_data) return 0; - - if(S3D_PRIMITIVE_EQ(&hit->prim, &rdata->prim_from)) + struct realisation* rz = realization; + struct segment* seg; + struct segment* prev; + int front_face = 0; + + (void) filter_data; + ASSERT(rz); + prev = previous_segment(rz); + seg = current_segment(rz); + ASSERT(seg); + + /* TODO: need to detect self intersect at the instance level, + using front/back face to avoid false self intersect events */ + if(prev && S3D_PRIMITIVE_EQ(&hit->prim, &prev->hit.prim)) return 1; /* Discard self intersection */ - instance = scene_get_object_instance_from_s3d_hit(rdata->scene, hit); + instance = scene_get_object_instance_from_s3d_hit(rz->data.scene, hit); /* Check if the hit surface is a receiver that registers hit data */ receiver_name = object_instance_get_receiver_name(instance); if(receiver_name) { - struct surface_fragment frag; - float tmp[3]; - f3_set(tmp, f3_add(tmp, org, f3_mulf(tmp, dir, hit->distance))); - surface_fragment_setup(&frag, tmp, dir, hit->normal, &hit->prim, hit->uv); - fprintf(rdata->stream, "%s %u %u %g %g (%g:%g:%g) (%g:%g:%g) (%g:%g)\n", - receiver_name, - rdata->path_id, - rdata->ray_id, - rdata->wavelength, - rdata->radiance, - SPLIT3(frag.pos), - SPLIT3(frag.dir), - SPLIT2(frag.uv)); + float cos_in; + /* check normal orientation */ + cos_in = f3_dot(hit->normal, dir); + if (cos_in < 0) { + float pos[3]; + + f3_set(pos, f3_add(pos, org, f3_mulf(pos, dir, hit->distance))); + front_face = 1; + fprintf(rz->data.out_stream, + "Receiver '%s': %u %u %g %g (%g:%g:%g) (%g:%g:%g) (%g:%g)\n", + receiver_name, + (unsigned)rz->rz_id, + (unsigned)rz->s_idx, + rz->freq, + seg->weight, + SPLIT3(pos), + SPLIT3(dir), + SPLIT2(hit->uv)); + } } + /* register success mask */ + if (front_face) + rz->success_mask |= object_instance_get_target_mask(instance); + material = object_get_material(object_instance_get_object(instance)); + if(material_get_type(material) == MATERIAL_VIRTUAL) { return 1; /* Discard virtual material */ } + rz->data.instance = instance; + return 0; } diff --git a/src/ssol_scene_c.h b/src/ssol_scene_c.h @@ -29,7 +29,7 @@ struct ssol_scene { struct htable_instance instances; - struct s3d_scene* s3d_scn; + struct s3d_scene* s3d_raytracing_scn; struct s3d_scene* s3d_sampling_scn; struct ssol_sun* sun; @@ -45,7 +45,7 @@ struct ssol_sun; struct ssol_device; extern LOCAL_SYM struct s3d_scene* -scene_get_s3d_scene +scene_get_s3d_raytracing_scn (const struct ssol_scene* scn); extern LOCAL_SYM struct s3d_scene* diff --git a/src/ssol_shape.c b/src/ssol_shape.c @@ -148,7 +148,7 @@ shape_create goto error; } - /* create a s3d_scene to hold a mesh */ + /* create a s3d_shape to hold a mesh */ res = s3d_shape_create_mesh(dev->s3d, &shape->s3d_shape); if(res != RES_OK) goto error; res = s3d_mesh_set_hit_filter_function diff --git a/src/ssol_solver.c b/src/ssol_solver.c @@ -14,6 +14,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "ssol.h" +#include "ssol_c.h" #include "ssol_solver_c.h" #include "ssol_device_c.h" #include "ssol_scene_c.h" @@ -31,17 +32,9 @@ #include <rsys/double3.h> #include <rsys/double44.h> -#include <star/ssp.h> +#define END_TEXT__ { "NONE", "SUCCESS", "SHADOW", "POINTING", "MISSING", "BLOCKED", "ERROR" }; -enum realization_termination { - TERM_NONE, - TERM_SHADOW, - TERM_MISSING, - TERM_BLOCKED, - TERM_ERR, - - TERM_COUNT__ -}; +static const char* END_TEXT[] = END_TEXT__; enum realization_mode { MODE_NONE, @@ -51,32 +44,9 @@ enum realization_mode { MODE_COUNT__ }; -struct segment { - double weight; - float range[2]; - struct s3d_hit hit; - /* TODO: use double? */ - float org[3], dir[4]; - float hit_pos[3]; -}; - -#include <rsys/dynamic_array.h> -#define DARRAY_DATA struct segment -#define DARRAY_NAME segment -#include <rsys/dynamic_array.h> - -struct realisation { - enum realization_termination end; - enum realization_mode mode; - struct darray_segment segments; - struct segment sun_segment; - double freq, final_weight; - size_t s_idx; -}; - /******************************************************************************* - * Helper functions - ******************************************************************************/ +* Helper functions +******************************************************************************/ static INLINE int is_instance_punched(const struct ssol_object_instance* instance) { @@ -98,252 +68,11 @@ get_3dscene(const struct ssol_object_instance* instance) return instance->object->s3d_scn; } -static res_T -init_solver_data(struct ssol_scene* scene, struct solver_data* data) -{ - res_T res = RES_OK; - - if (!data || !scene) return RES_BAD_ARG; - - data->scene = scene; - /* create 2 s3d_scene_view for raytracing and sampling */ - res = set_views(data); - if (res != RES_OK) goto error; - /* create sun distributions */ - res = set_sun_distributions(data); - if (res != RES_OK) goto error; - -exit: - return res; -error: - /* TODO: clear data */ - goto exit; -} - -static struct segment* -current_segment(struct realisation* rz) -{ - ASSERT(rz); - ASSERT(rz->s_idx < darray_segment_size_get(&rz->segments)); - return darray_segment_data_get(&rz->segments) + rz->s_idx; -} - -static res_T -next_segment(struct realisation* rz) -{ - ASSERT(rz); - ++rz->s_idx; - if (rz->s_idx >= darray_segment_size_get(&rz->segments)) - return darray_segment_resize(&rz->segments, rz->s_idx + 1); - return RES_OK; -} - -static void -reset_realization(struct realisation* rz) -{ - ASSERT(rz); - rz->s_idx = 0; - rz->s_idx = 0; - rz->end = TERM_NONE; - rz->mode = MODE_STD; -} - -static res_T -init_realization(struct mem_allocator* allocator, struct realisation* rz) -{ - ASSERT(rz); - darray_segment_init(allocator, &rz->segments); - /* set a first size; will grow up with time if needed */ - return darray_segment_resize(&rz->segments, 16); -} - -static void -clear_realization(struct realisation* rz) -{ - ASSERT(rz); - darray_segment_clear(&rz->segments); -} - -static void -reset_segment(struct segment* seg) -{ - ASSERT(seg); - seg->range[0] = 0; - seg->range[1] = FLT_MAX; - seg->hit = S3D_HIT_NULL; -} - -static struct ssol_material* -get_material_from_hit(struct ssol_scene* scene, struct s3d_hit* hit) -{ - struct ssol_object_instance* instance; - struct ssol_object* object; - struct ssol_material* material; - ASSERT(scene && hit); - instance = scene_get_object_instance_from_s3d_hit(scene, hit); - ASSERT(instance); - object = object_instance_get_object(instance); - ASSERT(object); - material = object_get_material(object); - ASSERT(material); - return material; -} - -/******************************************************************************* - * Exported function - ******************************************************************************/ -res_T -ssol_solve - (struct ssol_scene* scene, - struct ssp_rng* rng, - const size_t realisations_count, - FILE* output) -{ - struct solver_data data; - struct brdf_composite* brdfs = NULL; - struct s3d_primitive primitive; - struct s3d_attrib attrib; - float uv[2]; - const struct ssol_sun* sun = NULL; - struct realisation rz; - size_t r; - double _dir[3]; - res_T res = RES_OK; - - struct ssol_device* device = NULL; - - if (!scene || !rng || !output || !realisations_count) - return RES_BAD_ARG; - - /* init realization */ - device = scene_get_device(scene); - ASSERT(device && device->allocator); - res = init_realization(device->allocator, &rz); - if (res != RES_OK) goto error; - - res = brdf_composite_create(device, &brdfs); - if (res != RES_OK) goto error; - - /* init scene representation data */ - res = init_solver_data(scene, &data); - if (res != RES_OK) goto error; - - sun = scene_get_sun(scene); - rz.sun_segment.weight = sun_get_dni(sun); - for (r = 0; r < realisations_count; r++) { - struct segment* prev = NULL; - struct segment* seg = &rz.sun_segment; - struct surface_fragment fragment; - float r1, r2, r3; - float sundir[3]; - float normal[3]; - /* reset realization */ - reset_realization(&rz); - - /* sample a point on the reflectors */ - r1 = ssp_rng_canonical_float(rng); - r2 = ssp_rng_canonical_float(rng); - r3 = ssp_rng_canonical_float(rng); - S3D(scene_view_sample(data.sample_view, r1, r2, r3, &primitive, uv)); - S3D(primitive_get_attrib(&primitive, S3D_POSITION, uv, &attrib)); - CHECK(attrib.type, S3D_FLOAT3); - - /* sample an input dir from the sun */ - ranst_sun_dir_get(data.sun_dir_ran, rng, _dir); - - /* setup sun segment in the reverse direction to detect shadows */ - reset_segment(seg); - f3_set(seg->org, attrib.value); - f3_set_d3(sundir, _dir); - f3_mulf(seg->dir, sundir, -1); - CHECK(f3_is_normalized(seg->dir), 1); - - /* sample a frequency */ - rz.freq = ssp_ranst_piecewise_linear_get(data.sun_spectrum_ran, rng); - - /* check if the point receives sunlight */ - /* TODO: need only an occlusion test */ - S3D(scene_view_trace_ray - (data.trace_view, seg->org, seg->dir, seg->range, NULL, &seg->hit)); - if (!S3D_HIT_NONE(&seg->hit)) { - rz.final_weight = 0; - rz.end = TERM_SHADOW; - } - - /* fill fragment from starting point */ - S3D(primitive_get_attrib(&primitive, S3D_GEOMETRY_NORMAL, uv, &attrib)); - CHECK(attrib.type, S3D_FLOAT3); - f3_set(normal, attrib.value); - surface_fragment_setup(&fragment, seg->org, sundir, normal, &primitive, uv); - - /* start propagating from rz.sun_segment.hit_pos */ - while (rz.end == TERM_NONE) { - struct ssol_material* material; - float tmp[3]; - - prev = seg; - seg = current_segment(&rz); - reset_segment(seg); - - /* the current segment starts at prev->hit_pos */ - f3_set(seg->org, prev->hit_pos); - - /* compute the output direction from the material */ - material = get_material_from_hit(scene, &prev->hit); - CHECK(material_get_type(material), MATERIAL_MIRROR); - res = material_shade(material, &fragment, rz.freq, brdfs); - if (res != RES_OK) { - rz.end = TERM_ERR; - goto error; - } - f3_set_d3(tmp, fragment.Ns); - seg->weight = prev->weight * - brdf_composite_sample(brdfs, rng, prev->dir, tmp, seg->dir); - - /* then check if the ray hits something */ - S3D(scene_view_trace_ray - (data.trace_view, seg->org, seg->dir, seg->range, NULL, &seg->hit)); - if (S3D_HIT_NONE(&seg->hit)) { - rz.final_weight = 0; - rz.end = TERM_MISSING; - continue; - } - /* should not stop on a virtual surface */ - ASSERT(material_get_type(get_material_from_hit(scene, &seg->hit)) - != MATERIAL_VIRTUAL); - - /* fill fragment from hit and loop */ - f3_add(tmp, seg->org, f3_mulf(tmp, seg->dir, seg->hit.distance)); - surface_fragment_setup - (&fragment, tmp, seg->dir, seg->hit.normal, &seg->hit.prim, seg->hit.uv); - - /* continue propagation with next segment */ - res = next_segment(&rz); - if (res != RES_OK) { - rz.end = TERM_ERR; - goto error; - } - } - rz.final_weight = seg->weight; - - fprintf(output, "%d %g %g\n", rz.end, rz.final_weight, rz.freq); - continue; - } - -exit: - /* TODO: release data */ - clear_realization(&rz); - return res; -error: - goto exit; -} - /******************************************************************************* * Local functions ******************************************************************************/ res_T -set_sun_distributions(struct solver_data* data) -{ +set_sun_distributions(struct solver_data* data) { struct ssol_spectrum* spectrum; struct ssol_device* dev; const struct ssol_sun* sun; @@ -351,7 +80,6 @@ set_sun_distributions(struct solver_data* data) const double* intensities; res_T res = RES_OK; size_t sz; - if (!data) return RES_BAD_ARG; ASSERT(data->scene); @@ -403,12 +131,22 @@ error: goto exit; } +static void +release_solver_data(struct solver_data* data) { + ASSERT(data); + if (data->trace_view) s3d_scene_view_ref_put(data->trace_view); + if (data->sample_view) s3d_scene_view_ref_put(data->sample_view); + if (data->sun_dir_ran) ranst_sun_dir_ref_put(data->sun_dir_ran); + if (data->sun_spectrum_ran) ssp_ranst_piecewise_linear_ref_put(data->sun_spectrum_ran); + if (data->brdfs) brdf_composite_ref_put(data->brdfs); + *data = SOLVER_DATA_NULL; +} + res_T -set_views(struct solver_data* data) -{ +set_views(struct solver_data* data) { res_T res = RES_OK; struct ssol_scene* scene; - struct s3d_scene* raytrace_scene; + struct s3d_scene* raytracing_scene; struct s3d_scene* sampling_scene; struct htable_instance_iterator it, it_end; int mirror_found = 0; @@ -417,26 +155,42 @@ set_views(struct solver_data* data) scene = data->scene; ASSERT(scene); - raytrace_scene = scene_get_s3d_scene(scene); - ASSERT(raytrace_scene); + raytracing_scene = scene_get_s3d_raytracing_scn(scene); + ASSERT(raytracing_scene); sampling_scene = scene_get_s3d_sampling_scn(scene); ASSERT(sampling_scene); /* feed sampling s3d_scene */ S3D(scene_clear(sampling_scene)); - htable_instance_begin(&scene->instances, &it); htable_instance_end(&scene->instances, &it_end); - while (!htable_instance_iterator_eq(&it, &it_end)) { + for ( + htable_instance_begin(&scene->instances, &it); + !htable_instance_iterator_eq(&it, &it_end); + htable_instance_iterator_next(&it)) + { struct ssol_object_instance* inst; struct ssol_material* mat; + struct ssol_object* object; inst = *htable_instance_iterator_data_get(&it); - /* keep only primary mirrors */ + + /* TODO: keep only primary mirrors */ mat = inst->object->material; if (material_get_type(mat) != MATERIAL_MIRROR) continue; mirror_found = 1; - res = s3d_scene_attach_shape(sampling_scene, inst->s3d_shape); + + object = object_instance_get_object(inst); + switch (object->shape->type) { + case SHAPE_MESH: + /* the same mesh is used for sampling and raytracing */ + res = s3d_scene_attach_shape(sampling_scene, inst->s3d_shape); + break; + case SHAPE_PUNCHED: + /* use the carving's mesh for sampling */ + FATAL("TODO\n"); + break; + default: FATAL("Unreachable code\n"); break; + } if (res != RES_OK) goto error; - htable_instance_iterator_next(&it); } if (!mirror_found) { res = RES_BAD_ARG; @@ -444,7 +198,7 @@ set_views(struct solver_data* data) goto error; } /* create views from scenes */ - res = s3d_scene_view_create(raytrace_scene, S3D_TRACE, &data->trace_view); + res = s3d_scene_view_create(raytracing_scene, S3D_TRACE, &data->trace_view); if (res != RES_OK) goto error; res = s3d_scene_view_create(sampling_scene, S3D_SAMPLE, &data->sample_view); if (res != RES_OK) goto error; @@ -452,8 +206,422 @@ set_views(struct solver_data* data) exit: return res; error: - /* TODO: clear data */ + release_solver_data(data); goto exit; } +struct segment* +previous_segment(struct realisation* rz) +{ + size_t idx; + ASSERT(rz); + if (!rz->s_idx) return NULL; + idx = rz->s_idx - 1; + ASSERT(idx < darray_segment_size_get(&rz->segments)); + return darray_segment_data_get(&rz->segments) + idx; +} + +struct segment* +sun_segment(struct realisation* rz) +{ + struct segment* seg; + ASSERT(rz); + seg = darray_segment_data_get(&rz->segments); + ASSERT(seg); + return seg; +} + +struct segment* +current_segment(struct realisation* rz) +{ + struct segment* seg; + ASSERT(rz); + ASSERT(rz->s_idx < darray_segment_size_get(&rz->segments)); + seg = darray_segment_data_get(&rz->segments) + rz->s_idx; + ASSERT(seg); + return seg; +} +res_T +next_segment(struct realisation* rz) +{ + res_T res = RES_OK; + ASSERT(rz); + ++rz->s_idx; + if (rz->s_idx >= darray_segment_size_get(&rz->segments)) { + res = darray_segment_resize(&rz->segments, rz->s_idx + 1); + if (res != RES_OK) return res; + } + reset_segment(current_segment(rz)); + return RES_OK; +} + +/* TODO: move to Star3D */ +static INLINE void s3d_invalidate_hit(struct s3d_hit* hit) { + ASSERT(hit); + hit->distance = FLT_MAX; +} + +void +reset_segment(struct segment* seg) +{ + ASSERT(seg); + seg->range[0] = 0; + seg->range[1] = FLT_MAX; + s3d_invalidate_hit(&seg->hit); +} + +static void +reset_starting_point(struct starting_point* start) +{ + ASSERT(start); + start->primitive = S3D_PRIMITIVE_NULL; +} + +static void +reset_realization(size_t cpt, struct realisation* rz) +{ + rz->s_idx = 0; + rz->s_idx = 0; + rz->end = TERM_NONE; + rz->mode = MODE_STD; + rz->rz_id = cpt; + rz->success_mask = 0; + reset_starting_point(&rz->start); + brdf_composite_clear(rz->data.brdfs); + rz->data.instance = NULL; + /* reset sun segment (always used) */ + reset_segment(sun_segment(rz)); +} + +static res_T +init_realization + (struct ssol_scene* scene, + struct ssp_rng* rng, + FILE* out, + struct realisation* rz) +{ + res_T res = RES_OK; + struct ssol_device* device; + + if (!scene || !rng || !rz) return RES_BAD_ARG; + + device = scene_get_device(scene); + ASSERT(device && device->allocator); + + darray_segment_init(device->allocator, &rz->segments); + /* set a first size; will grow up with time if needed */ + res = darray_segment_resize(&rz->segments, 16); + if (res != RES_OK) goto error; + + rz->data = SOLVER_DATA_NULL; + rz->data.scene = scene; + rz->data.rng = rng; + rz->data.out_stream = out; + /* create 2 s3d_scene_view for raytracing and sampling */ + res = set_views(&rz->data); + if (res != RES_OK) goto error; + /* create sun distributions */ + res = set_sun_distributions(&rz->data); + if (res != RES_OK) goto error; + res = brdf_composite_create(device, &rz->data.brdfs); + if (res != RES_OK) goto error; + +exit: + return res; +error: + release_solver_data(&rz->data); + goto exit; +} + +static void +release_realization(struct realisation* rz) +{ + ASSERT(rz); + release_solver_data(&rz->data); + darray_segment_release(&rz->segments); +} + +static struct ssol_material* +get_material_from_hit(struct ssol_scene* scene, struct s3d_hit* hit) { + struct ssol_object_instance* instance; + struct ssol_object* object; + struct ssol_material* material; + ASSERT(scene && hit); + instance = scene_get_object_instance_from_s3d_hit(scene, hit); + ASSERT(instance); + object = object_instance_get_object(instance); + ASSERT(object); + material = object_get_material(object); + ASSERT(material); + return material; +} + +static void +sample_point_on_primary_mirror(struct realisation* rz) +{ + struct s3d_attrib attrib; + struct ssol_object* object; + float r1, r2, r3; + struct solver_data* data; + struct segment* seg = sun_segment(rz); + struct s3d_primitive tmp_prim; + + data = &rz->data; + ASSERT(data->rng && data->sample_view && data->scene); + /* sample a point on a primary mirror's carving */ + r1 = ssp_rng_canonical_float(data->rng); + r2 = ssp_rng_canonical_float(data->rng); + r3 = ssp_rng_canonical_float(data->rng); + S3D(scene_view_sample(data->sample_view, r1, r2, r3, &tmp_prim, rz->start.uv)); + S3D(primitive_get_attrib(&tmp_prim, S3D_POSITION, rz->start.uv, &attrib)); + CHECK(attrib.type, S3D_FLOAT3); + /* find the solstice shape and project the sampled point on the mirror */ + rz->start.instance = + *htable_instance_find(&data->scene->instances, &tmp_prim.inst_id); + ASSERT(rz->start.instance); + object = object_instance_get_object(rz->start.instance); + ASSERT(object && object->shape); + rz->start.material = object_get_material(object); + ASSERT(rz->start.material); + switch (object->shape->type) { + case SHAPE_MESH: + /* no projection needed */ + f3_set(seg->org, attrib.value); + /* to avoid self intersect */ + rz->start.primitive = tmp_prim; + break; + case SHAPE_PUNCHED: + /* project the sampled point on the quadric */ + FATAL("TODO\n"); + /* cannot self intersect as the sampled mesh is not raytraced */ + rz->start.primitive = S3D_PRIMITIVE_NULL; + break; + default: FATAL("Unreachable code\n"); break; + } +} + +static void +sample_input_sundir(struct realisation* rz) +{ + ASSERT(rz); + ranst_sun_dir_get(rz->data.sun_dir_ran, rz->data.rng, rz->start.sundir); +} + +static void +sample_wavelength(struct realisation* rz) +{ + ASSERT(rz); + rz->freq = ssp_ranst_piecewise_linear_get(rz->data.sun_spectrum_ran, rz->data.rng); +} + +static int +receive_sunlight(struct realisation* rz) +{ + float sundir_f[3]; + struct s3d_attrib attrib; + struct segment* seg = sun_segment(rz); + int receives; + const char* receiver_name; + + f3_set_d3(sundir_f, rz->start.sundir); + f3_mulf(seg->dir, sundir_f, -1); + CHECK(f3_is_normalized(seg->dir), 1); + /* check normal orientation */ + S3D(primitive_get_attrib(&rz->start.primitive, S3D_GEOMETRY_NORMAL, rz->start.uv, &attrib)); + CHECK(attrib.type, S3D_FLOAT3); + /* fill fragment from starting point; must use sundir_f, not seg->dir */ + surface_fragment_setup(&rz->data.fragment, seg->org, sundir_f, attrib.value, &rz->start.primitive, rz->start.uv); + /* check normal orientation */ + rz->start.cos_sun = d3_dot(rz->data.fragment.Ng, rz->start.sundir); + if (rz->start.cos_sun >= 0) + return 0; + /* check occlusion, avoiding self intersect */ + seg->hit.prim = rz->start.primitive; + /* TODO (in s3d): need an occlusion test */ + S3D(scene_view_trace_ray(rz->data.trace_view, seg->org, seg->dir, seg->range, rz, &seg->hit)); + receives = S3D_HIT_NONE(&seg->hit); + if (!receives) return receives; + + /* if the sampled instance is a receiver, register the sampled point */ + receiver_name = object_instance_get_receiver_name(rz->start.instance); + if (receiver_name) { + /* normal orientation has already been checked */ + fprintf(rz->data.out_stream, + "Receiver '%s': %u %u %g %g (%g:%g:%g) (%g:%g:%g) (%g:%g)\n", + receiver_name, + (unsigned) rz->rz_id, + (unsigned) rz->s_idx, + rz->freq, + seg->weight, + SPLIT3(seg->org), + SPLIT3(sundir_f), + SPLIT2(rz->start.uv)); + } + + /* register success mask (normal orientation has already been checked) */ + rz->success_mask |= object_instance_get_target_mask(rz->start.instance); + + /* restaure self intersect information for further visibility test + (previous call to trace_ray overwrote prim) */ + seg->hit.prim = rz->start.primitive; + + return receives; +} + +static res_T +set_output_pos_and_dir(struct realisation* rz) { + struct ssol_material* material; + struct segment* seg = current_segment(rz); + struct segment* prev = previous_segment(rz); + struct ssol_scene* scene = rz->data.scene; + float tmp[3]; + int fst_segment; + res_T res = RES_OK; + + /* next_segment should have been called */ + ASSERT(prev); + + fst_segment = (prev == sun_segment(rz)); + + if (fst_segment) { + f3_set(seg->org, prev->org); + material = rz->start.material; + } + else { + f3_set(seg->org, prev->hit_pos); + material = get_material_from_hit(scene, &prev->hit); + } + CHECK(material_get_type(material), MATERIAL_MIRROR); + res = material_shade(material, &rz->data.fragment, rz->freq, rz->data.brdfs); + if (res != RES_OK) { + rz->end = TERM_ERR; + return res; + } + f3_set_d3(tmp, rz->data.fragment.Ns); + + if (fst_segment) { + float sundir_f[3]; + const struct ssol_sun* sun = scene_get_sun(rz->data.scene); + ASSERT(-1 <= rz->start.cos_sun && rz->start.cos_sun <= 0); + f3_set_d3(sundir_f, rz->start.sundir); + seg->weight = sun_get_dni(sun) + * brdf_composite_sample(rz->data.brdfs, rz->data.rng, sundir_f, tmp, seg->dir) + * -rz->start.cos_sun; + } + else { + seg->weight = prev->weight * + brdf_composite_sample(rz->data.brdfs, rz->data.rng, prev->dir, tmp, seg->dir); + } + return res; +} + +static void +propagate(struct realisation* rz) +{ + struct segment* seg = current_segment(rz); + struct ssol_scene* scene = rz->data.scene; + + /* check if the ray hits something */ + S3D(scene_view_trace_ray(rz->data.trace_view, seg->org, seg->dir, seg->range, rz, &seg->hit)); + if (S3D_HIT_NONE(&seg->hit)) { + rz->end = TERM_MISSING; + return; + } + /* should not stop on a virtual surface */ + ASSERT(material_get_type(get_material_from_hit(scene, &seg->hit)) + != MATERIAL_VIRTUAL); + + /* offset the impact point and recompute normal if needed */ + ASSERT(rz->data.instance); + switch (rz->data.instance->object->shape->type) { + case SHAPE_MESH: + /* no postprocess needed */ + break; + case SHAPE_PUNCHED: + /* project the impact point on the quadric */ + FATAL("TODO\n"); + /* compute normal to quadric */ + break; + default: FATAL("Unreachable code\n"); break; + } + + /* fill fragment from hit and loop */ + f3_set(seg->hit_pos, f3_add(seg->hit_pos, seg->org, f3_mulf(seg->hit_pos, seg->dir, seg->hit.distance))); + surface_fragment_setup(&rz->data.fragment, seg->hit_pos, seg->dir, seg->hit.normal, &seg->hit.prim, seg->hit.uv); +} + +/******************************************************************************* + * Exported function + ******************************************************************************/ +res_T +ssol_solve + (struct ssol_scene* scene, + struct ssp_rng* rng, + const size_t realisations_count, + FILE* output) +{ + struct realisation rz; + size_t r; + res_T res = RES_OK; + + struct ssol_device* device = NULL; + + if (!scene || !rng || !output || !realisations_count) + return RES_BAD_ARG; + + device = scene_get_device(scene); + ASSERT(device && device->allocator); + + /* init realization */ + res = init_realization(scene, rng, output, &rz); + if (res != RES_OK) goto error; + + for (r = 0; r < realisations_count; r++) { + /* reset realization */ + reset_realization(r, &rz); + + /* sample a point on a primary mirror */ + sample_point_on_primary_mirror(&rz); + + /* sample an input dir from the sun */ + sample_input_sundir(&rz); + + /* sample a frequency */ + sample_wavelength(&rz); + + /* check if the point receives sun light */ + if (!receive_sunlight(&rz)) { + rz.end = rz.start.cos_sun >= 0 ? TERM_POINTING : TERM_SHADOW; + } + else { + /* start propagating from mirror */ + do { + if (RES_OK != next_segment(&rz)) { + rz.end = TERM_ERR; + } + else { + /* set next segment and propagate */ + set_output_pos_and_dir(&rz); + propagate(&rz); + } + } while (rz.end == TERM_NONE); + } + + /* propagation ended */ + if (rz.success_mask) + fprintf(output, "Realization %u succeeded: 0x%0x\n", (unsigned)r, rz.success_mask); + else + fprintf(output, "Realization %u failed: %s\n", (unsigned)r, END_TEXT[rz.end]); + + /* next realization */ + continue; + } + +exit: + release_realization(&rz); + return res; +error: + /* TODO: release data */ + goto exit; +} diff --git a/src/ssol_solver_c.h b/src/ssol_solver_c.h @@ -17,12 +17,16 @@ #define SSOL_SOLVER_C_H #include "ssol_ranst_sun_dir.h" +#include "ssol_material_c.h" +#include "ssol_c.h" #include <rsys/ref_count.h> #include <rsys/list.h> #include <rsys/dynamic_array.h> #include <star/ssp.h> +#include <star/s3d.h> + #define DARRAY_NAME quadric #define DARRAY_DATA struct ssol_quadric @@ -32,8 +36,45 @@ #define DARRAY_DATA struct s3d_shape* #include <rsys/dynamic_array.h> +enum realization_termination { + TERM_NONE, + TERM_SUCCESS, + TERM_SHADOW, + TERM_POINTING, + TERM_MISSING, + TERM_BLOCKED, + TERM_ERR, + + TERM_COUNT__ +}; + +struct segment { + double weight; + float range[2]; + struct s3d_hit hit; + /* TODO: use double? */ + float org[3], dir[4]; + float hit_pos[3]; +}; + +struct starting_point { + struct ssol_object_instance* instance; + struct ssol_material* material; + struct s3d_primitive primitive; + double sundir[3]; + double cos_sun; + float uv[2]; +}; + +#include <rsys/dynamic_array.h> +#define DARRAY_DATA struct segment +#define DARRAY_NAME segment +#include <rsys/dynamic_array.h> + struct solver_data { struct ssol_scene* scene; + struct ssp_rng* rng; + FILE* out_stream; /* the s3d_scene_view used for raytracing */ struct s3d_scene_view* trace_view; /* the s3d_scene_view used for sampling */ @@ -41,9 +82,27 @@ struct solver_data { /* the random distributions for sun sampling */ struct ranst_sun_dir* sun_dir_ran; struct ssp_ranst_piecewise_linear* sun_spectrum_ran; + /* tmp data used for propagation */ + struct brdf_composite* brdfs; + struct ssol_object_instance* instance; + struct surface_fragment fragment; }; -/* TODO: refcount management for data */ +#define SOLVER_DATA_NULL__ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +struct realisation { + enum realization_termination end; + enum realization_mode mode; + struct darray_segment segments; + struct starting_point start; + struct solver_data data; + double freq; + size_t s_idx; + size_t rz_id; + uint32_t success_mask; +}; + +static const struct solver_data SOLVER_DATA_NULL = SOLVER_DATA_NULL__; extern LOCAL_SYM res_T set_sun_distributions(struct solver_data* data); @@ -51,5 +110,20 @@ set_sun_distributions(struct solver_data* data); extern LOCAL_SYM res_T set_views(struct solver_data* data); +extern LOCAL_SYM struct segment* +previous_segment(struct realisation* rz); + +extern LOCAL_SYM struct segment* +sun_segment(struct realisation* rz); + +extern LOCAL_SYM struct segment* +current_segment(struct realisation* rz); + +extern LOCAL_SYM res_T +next_segment(struct realisation* rz); + +extern LOCAL_SYM void +reset_segment(struct segment* seg); + #endif /* SSOL_SOLVER_C_H */ diff --git a/src/test_ssol_geometries.h b/src/test_ssol_geometries.h @@ -25,18 +25,20 @@ struct desc { * Plane ******************************************************************************/ -static const float plane_walls [] = { +static const float square_walls [] = { -1, -1, 0, - 1, -1, 0, - 1, 1, 0, + 1, -1, 0, + 1, 1, 0, -1, 1, 0 }; -const unsigned plane_walls_nverts = sizeof(plane_walls) / sizeof(float[3]); +const unsigned square_walls_nverts = sizeof(square_walls) / sizeof(float[3]); -const unsigned plane_walls_ids [] = { - 0, 1, 2, 2, 3, 0 +const unsigned square_walls_ids [] = { + 0, 2, 1, 2, 0, 3 }; -const unsigned plane_walls_ntris = sizeof(plane_walls_ids) / sizeof(unsigned[3]); +const unsigned square_walls_ntris = sizeof(square_walls_ids) / sizeof(unsigned[3]); + +static struct desc square_walls_desc = { square_walls, square_walls_ids }; /******************************************************************************* * Box diff --git a/src/test_ssol_object_instance.c b/src/test_ssol_object_instance.c @@ -63,6 +63,11 @@ main(int argc, char** argv) CHECK(ssol_object_instance_set_receiver(instance, "receiver 0"), RES_OK); CHECK(ssol_object_instance_set_receiver(instance, NULL), RES_OK); + CHECK(ssol_object_instance_set_target_mask(NULL, 1), RES_BAD_ARG); + CHECK(ssol_object_instance_set_target_mask(instance, 1), RES_OK); + CHECK(ssol_object_instance_set_target_mask(instance, 0), RES_OK); + CHECK(ssol_object_instance_set_target_mask(instance, 0x10), RES_OK); + CHECK(ssol_object_instance_ref_put(instance), RES_OK); CHECK(ssol_object_ref_put(object), RES_OK); diff --git a/src/test_ssol_solver.c b/src/test_ssol_solver.c @@ -16,14 +16,19 @@ #include "ssol.h" #include "test_ssol_utils.h" #include "test_ssol_geometries.h" +#include "test_ssol_materials.h" #include "ssol_solver_c.h" #include <rsys/logger.h> -#include <rsys/double3.h> +#include <rsys/double33.h> #include <star/ssp.h> + + +#include <star/s3d.h> + /******************************************************************************* * test main program ******************************************************************************/ @@ -35,19 +40,36 @@ main(int argc, char** argv) struct ssol_device* dev; struct ssp_rng* rng; struct ssol_scene* scene; - struct ssol_shape* shape; - struct ssol_vertex_data attribs[3]; - struct ssol_material* material; + struct ssol_shape* square; + struct ssol_vertex_data attribs[1]; + struct ssol_material* m_material; + struct ssol_material* v_material; struct ssol_mirror_shader shader; - struct ssol_object* object; - struct ssol_object_instance* instance; + struct ssol_object* m_object; + struct ssol_object* t_object; + struct ssol_object_instance* heliostat; + struct ssol_object_instance* secondary; + struct ssol_object_instance* target; struct ssol_sun* sun; struct ssol_spectrum* spectrum; double dir[3]; double frequencies[3] = { 1, 2, 3 }; double intensities[3] = { 1, 0.8, 1 }; + double transform1[12]; /* 3x4 column major matrix */ + double transform2[12]; /* 3x4 column major matrix */ + (void) argc, (void) argv; + d33_splat(transform1, 0); + d3_splat(transform1 + 9, 0); + d33_rotation_pitch(transform1, PI); /* flip faces: invert normal */ + transform1[9] = 2; /* +2 offset along X axis */ + transform1[11] = 2; /* +2 offset along Z axis */ + + d33_set_identity(transform2); + d3_splat(transform2 + 9, 0); + transform2[9] = 4; /* +4 offset along X axis */ + mem_init_proxy_allocator(&allocator, &mem_default_allocator); CHECK(logger_init(&allocator, &logger), RES_OK); @@ -62,7 +84,7 @@ main(int argc, char** argv) CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK); CHECK(ssol_spectrum_setup(spectrum, frequencies, intensities, 3), RES_OK); CHECK(ssol_sun_create_directional(dev, &sun), RES_OK); - CHECK(ssol_sun_set_direction(sun, d3(dir, 0, 0, -10)), RES_OK); + CHECK(ssol_sun_set_direction(sun, d3(dir, 1, 0, -1)), RES_OK); CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK); CHECK(ssol_sun_set_dni(sun, 1000), RES_OK); CHECK(ssol_scene_create(dev, &scene), RES_OK); @@ -75,34 +97,55 @@ main(int argc, char** argv) CHECK(ssol_solve(scene, rng, 10, stdout), RES_BAD_ARG); /* no geometry */ /* create scene content */ - CHECK(ssol_shape_create_mesh(dev, &shape), RES_OK); + + CHECK(ssol_shape_create_mesh(dev, &square), RES_OK); attribs[0].usage = SSOL_POSITION; attribs[0].get = get_position; - attribs[1].usage = SSOL_NORMAL; - attribs[1].get = get_normal; - attribs[2].usage = SSOL_TEXCOORD; - attribs[2].get = get_uv; - CHECK(ssol_mesh_setup(shape, box_walls_ntris, get_ids, box_walls_nverts, - attribs, 3, &box_walls_desc), RES_OK); - CHECK(ssol_material_create_mirror(dev, &material), RES_OK); - CHECK(ssol_mirror_set_shader(material, &shader), RES_OK); - CHECK(ssol_object_create(dev, shape, material, &object), RES_OK); - CHECK(ssol_object_instantiate(object, &instance), RES_OK); - CHECK(ssol_scene_attach_object_instance(scene, instance), RES_OK); - - CHECK(ssol_solve(scene, rng, 10, stdout), RES_OK); - - CHECK(ssol_scene_detach_object_instance(scene, instance), RES_OK); - - CHECK(ssol_object_instance_ref_put(instance), RES_OK); - CHECK(ssol_object_ref_put(object), RES_OK); - CHECK(ssol_shape_ref_put(shape), RES_OK); - CHECK(ssol_material_ref_put(material), RES_OK); + CHECK(ssol_mesh_setup + (square, square_walls_ntris, get_ids, square_walls_nverts, attribs, 1, &square_walls_desc), RES_OK); + + CHECK(ssol_material_create_mirror(dev, &m_material), RES_OK); + shader.normal = get_shader_normal; + shader.reflectivity = get_shader_reflectivity; + shader.roughness = get_shader_roughness; + CHECK(ssol_mirror_set_shader(m_material, &shader), RES_OK); + CHECK(ssol_material_create_virtual(dev, &v_material), RES_OK); + + CHECK(ssol_object_create(dev, square, m_material, &m_object), RES_OK); + CHECK(ssol_object_instantiate(m_object, &heliostat), RES_OK); + CHECK(ssol_object_instance_set_receiver(heliostat, "miroir"), RES_OK); + CHECK(ssol_object_instance_set_target_mask(heliostat, 0x1), RES_OK); + CHECK(ssol_scene_attach_object_instance(scene, heliostat), RES_OK); + + CHECK(ssol_object_instantiate(m_object, &secondary), RES_OK); + CHECK(ssol_object_instance_set_receiver(secondary, "secondaire"), RES_OK); + CHECK(ssol_object_instance_set_transform(secondary, transform1), RES_OK); + CHECK(ssol_object_instance_set_target_mask(secondary, 0x2), RES_OK); + CHECK(ssol_scene_attach_object_instance(scene, secondary), RES_OK); + + CHECK(ssol_object_create(dev, square, v_material, &t_object), RES_OK); + CHECK(ssol_object_instantiate(t_object, &target), RES_OK); + CHECK(ssol_object_instance_set_transform(target, transform2), RES_OK); + CHECK(ssol_object_instance_set_receiver(target, "cible"), RES_OK); + CHECK(ssol_object_instance_set_target_mask(target, 0x4), RES_OK); + CHECK(ssol_scene_attach_object_instance(scene, target), RES_OK); + + CHECK(ssol_solve(scene, rng, 20, stdout), RES_OK); + + /* free data */ + + CHECK(ssol_object_instance_ref_put(heliostat), RES_OK); + CHECK(ssol_object_instance_ref_put(secondary), RES_OK); + CHECK(ssol_object_instance_ref_put(target), RES_OK); + CHECK(ssol_object_ref_put(m_object), RES_OK); + CHECK(ssol_object_ref_put(t_object), RES_OK); + CHECK(ssol_shape_ref_put(square), RES_OK); + CHECK(ssol_material_ref_put(m_material), RES_OK); + CHECK(ssol_material_ref_put(v_material), RES_OK); CHECK(ssol_device_ref_put(dev), RES_OK); - CHECK(ssol_scene_clear(scene), RES_OK); + CHECK(ssol_scene_ref_put(scene), RES_OK); CHECK(ssp_rng_ref_put(rng), RES_OK); CHECK(ssol_spectrum_ref_put(spectrum), RES_OK); - CHECK(ssol_scene_detach_sun(scene, sun), RES_OK); CHECK(ssol_sun_ref_put(sun), RES_OK); logger_release(&logger);