commit fb9bc1a8fca117c98d92d61d4fe86b8ffa02fb86
parent bf386fec2bd9fe2c42621cc7a8470d917050989f
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 27 Mar 2017 15:45:41 +0200
Merge branch 'release_0.1'
Diffstat:
53 files changed, 5258 insertions(+), 1268 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -27,7 +27,7 @@ find_package(RCMake 0.2.3 REQUIRED)
find_package(RSys 0.4 REQUIRED)
find_package(Star3D 0.4 REQUIRED)
find_package(StarCPR REQUIRED)
-find_package(StarSF 0.0 REQUIRED)
+find_package(StarSF 0.1 REQUIRED)
find_package(StarSP 0.4 REQUIRED)
find_package(OpenMP 1.2 REQUIRED)
@@ -57,9 +57,12 @@ set(SSOL_FILES_SRC
ssol_camera.c
ssol_device.c
ssol_draw.c
+ ssol_draw_pt.c
+ ssol_draw_draft.c
ssol_estimator.c
ssol_image.c
ssol_material.c
+ ssol_mc_receiver.c
ssol_object.c
ssol_instance.c
ssol_param_buffer.c
@@ -79,6 +82,7 @@ set(SSOL_FILES_INC
ssol_c.h
ssol_camera.h
ssol_device_c.h
+ ssol_draw.h
ssol_estimator_c.h
ssol_image_c.h
ssol_material_c.h
@@ -123,15 +127,22 @@ rcmake_setup_devel(solstice-solver SolSolver ${VERSION} solstice/ssol_version.h)
# Add tests
################################################################################
if(NOT NO_TEST)
- function(new_test _name)
- add_executable(${_name}
- ${SSOL_SOURCE_DIR}/${_name}.c)
+ function(build_test _name)
+ add_executable(${_name} ${SSOL_SOURCE_DIR}/${_name}.c)
target_link_libraries(${_name}
solstice-solver solstice-test RSys Star3D StarSP)
- add_test(${_name} ${_name})
+ endfunction()
+
+ function(register_test _name)
+ add_test(${_name} ${ARGN})
rcmake_set_test_runtime_dirs(${_name} _runtime_dirs)
endfunction()
+ function(new_test _name)
+ build_test(${_name})
+ register_test(${_name} ${_name})
+ endfunction()
+
add_library(solstice-test STATIC
${SSOL_SOURCE_DIR}/test_ssol_geometries.h
${SSOL_SOURCE_DIR}/test_ssol_materials.h
@@ -142,7 +153,6 @@ if(NOT NO_TEST)
new_test(test_ssol_by_receiver_integration)
new_test(test_ssol_camera)
new_test(test_ssol_device)
- new_test(test_ssol_draw)
new_test(test_ssol_image)
new_test(test_ssol_material)
new_test(test_ssol_object)
@@ -158,7 +168,15 @@ if(NOT NO_TEST)
new_test(test_ssol_solver4)
new_test(test_ssol_solver5)
new_test(test_ssol_solver6)
+ new_test(test_ssol_solver7)
+ new_test(test_ssol_solver8)
+ new_test(test_ssol_solver9)
new_test(test_ssol_sun)
+
+ build_test(test_ssol_draw)
+ register_test(test_ssol_draw_draft test_ssol_draw draft)
+ register_test(test_ssol_draw_pt test_ssol_draw pt)
+
endif()
################################################################################
diff --git a/src/ssol.h b/src/ssol.h
@@ -66,6 +66,21 @@ enum ssol_side_flag {
SSOL_INVALID_SIDE = BIT(2)
};
+enum ssol_path_type {
+ SSOL_PATH_MISSING, /* The path misses the receivers */
+ SSOL_PATH_SHADOW, /* The path is occluded before the sampled geometry */
+ SSOL_PATH_SUCCESS /* The path contributes to at least one receiver */
+};
+
+enum ssol_material_type {
+ SSOL_MATERIAL_DIELECTRIC,
+ SSOL_MATERIAL_MATTE,
+ SSOL_MATERIAL_MIRROR,
+ SSOL_MATERIAL_THIN_DIELECTRIC,
+ SSOL_MATERIAL_VIRTUAL,
+ SSOL_MATERIAL_TYPES_COUNT__
+};
+
enum ssol_clipping_op {
SSOL_AND,
SSOL_SUB,
@@ -85,6 +100,7 @@ enum ssol_parametrization_type {
enum ssol_quadric_type {
SSOL_QUADRIC_PLANE,
SSOL_QUADRIC_PARABOL,
+ SSOL_QUADRIC_HYPERBOL,
SSOL_QUADRIC_PARABOLIC_CYLINDER,
SSOL_QUADRIC_TYPE_COUNT__
};
@@ -149,6 +165,15 @@ struct ssol_quadric_parabol {
static const struct ssol_quadric_parabol SSOL_QUADRIC_PARABOL_NULL =
SSOL_QUADRIC_PARABOL_NULL__;
+struct ssol_quadric_hyperbol {
+ /* Define (x^2 + y^2) / a^2 - (z - 1/2)^2 / b^2 + 1 = 0
+ * with a^2 = f - f^2; b = f -1/2; f = real_focal / (img_focal + real_focal) */
+ double img_focal, real_focal;
+};
+#define SSOL_QUADRIC_HYPERBOL_NULL__ { -1.0 , -1.0 }
+static const struct ssol_quadric_hyperbol SSOL_QUADRIC_HYPERBOL_NULL =
+SSOL_QUADRIC_HYPERBOL_NULL__;
+
struct ssol_quadric_parabolic_cylinder {
double focal; /* Define y^2 - 4 focal z = 0 */
};
@@ -161,18 +186,24 @@ struct ssol_quadric {
union {
struct ssol_quadric_plane plane;
struct ssol_quadric_parabol parabol;
+ struct ssol_quadric_hyperbol hyperbol;
struct ssol_quadric_parabolic_cylinder parabolic_cylinder;
} data;
/* 3x4 column major transformation of the quadric in object space */
double transform[12];
+
+ /* Hint on the how to discretised */
+ size_t slices_count_hint;
};
#define SSOL_QUADRIC_DEFAULT__ { \
SSOL_QUADRIC_PLANE, \
{SSOL_QUADRIC_PLANE_DEFAULT__}, \
- {1,0,0, 0,1,0, 0,0,1, 0,0,0} \
+ {1,0,0, 0,1,0, 0,0,1, 0,0,0}, \
+ SIZE_MAX /* <=> Use default discretisation */ \
}
+
static const struct ssol_quadric SSOL_QUADRIC_DEFAULT = SSOL_QUADRIC_DEFAULT__;
/* Define the contour of a 2D polygon as well as the clipping operation to
@@ -196,6 +227,13 @@ struct ssol_punched_surface {
static const struct ssol_punched_surface SSOL_PUNCHED_SURFACE_NULL =
SSOL_PUNCHED_SURFACE_NULL__;
+struct ssol_medium {
+ double absorptivity;
+ double refractive_index;
+};
+#define SSOL_MEDIUM_VACUUM__ { 0, 1 }
+static const struct ssol_medium SSOL_MEDIUM_VACUUM = SSOL_MEDIUM_VACUUM__;
+
typedef void
(*ssol_shader_getter_T)
(struct ssol_device* dev,
@@ -208,6 +246,14 @@ typedef void
const double w[3], /* Incoming direction. Point toward the surface */
double* val); /* Returned value */
+/* Dielectric material shader */
+struct ssol_dielectric_shader {
+ ssol_shader_getter_T normal;
+};
+#define SSOL_DIELECTRIC_SHADER_NULL__ { NULL }
+static const struct ssol_dielectric_shader SSOL_DIELECTRIC_SHADER_NULL =
+ SSOL_DIELECTRIC_SHADER_NULL__;
+
/* Mirror material shader */
struct ssol_mirror_shader {
ssol_shader_getter_T normal;
@@ -227,6 +273,14 @@ struct ssol_matte_shader {
static const struct ssol_matte_shader SSOL_MATTE_SHADER_NULL =
SSOL_MATTE_SHADER_NULL__;
+/* Thin dielectric shader */
+struct ssol_thin_dielectric_shader {
+ ssol_shader_getter_T normal;
+};
+#define SSOL_THIN_DIELECTRIC_SHADER_NULL__ { NULL }
+static const struct ssol_thin_dielectric_shader
+SSOL_THIN_DIELECTRIC_SHADER_NULL = SSOL_THIN_DIELECTRIC_SHADER_NULL__;
+
/* The type of data produced on receiver hits as ssol_solve() write them on its
* FILE* argument */
struct ssol_receiver_data {
@@ -248,28 +302,106 @@ struct ssol_receiver_data {
/* TODO Add the geometry and primitive identifier */
};
+struct ssol_instantiated_shaded_shape {
+ struct ssol_shape* shape;
+ struct ssol_material* mtl_front;
+ struct ssol_material* mtl_back;
+
+ /* Internal data */
+ double R__[9];
+ double T__[3];
+ double R_invtrans__[9];
+};
+
+#define SSOL_INSTANTIATED_SHADED_SHAPE_NULL__ { 0 }
+static const struct ssol_instantiated_shaded_shape
+SSOL_INSTANTIATED_SHADED_SHAPE_NULL = SSOL_INSTANTIATED_SHADED_SHAPE_NULL__;
+
+struct ssol_path_tracker {
+ /* Control the length of the path segment starting/ending from/to the
+ * infinite. A value less than zero means for default value */
+ double sun_ray_length;
+ double infinite_ray_length;
+};
+
+#define SSOL_PATH_TRACKER_DEFAULT__ {-1, -1}
+static const struct ssol_path_tracker SSOL_PATH_TRACKER_DEFAULT =
+ SSOL_PATH_TRACKER_DEFAULT__;
+
+struct ssol_path {
+ /* Internal data */
+ const void* path__;
+};
+
+struct ssol_path_vertex {
+ double pos[3]; /* Position */
+ double weight; /* Monte-Carlo weight */
+};
+
struct ssol_mc_result {
double E; /* Expectation */
double V; /* Variance */
double SE; /* Standard error, i.e. sqrt(Expectation / N) */
};
+#define SSOL_MC_RESULT_NULL__ {0, 0, 0}
+static const struct ssol_mc_result SSOL_MC_RESULT_NULL = SSOL_MC_RESULT_NULL__;
-/* result for MC simulations */
-struct ssol_estimator_status {
- struct ssol_mc_result irradiance;
- struct ssol_mc_result absorptivity_loss;
- struct ssol_mc_result reflectivity_loss;
- struct ssol_mc_result cos_loss;
- size_t N; /* Samples count */
- size_t Nf; /* Failed samples count */
+struct ssol_mc_global {
+ struct ssol_mc_result cos_loss; /* In W */
+ struct ssol_mc_result shadowed; /* In W */
+ struct ssol_mc_result missing; /* In W */
};
-
-/* the always-ON indicators (MC computations) */
-enum ssol_status_type {
- SSOL_STATUS_SHADOW,
- SSOL_STATUS_MISSING,
- SSOL_STATUS_TYPES_COUNT__
+#define SSOL_MC_GLOBAL_NULL__ { \
+ SSOL_MC_RESULT_NULL__, \
+ SSOL_MC_RESULT_NULL__, \
+ SSOL_MC_RESULT_NULL__ \
+}
+static const struct ssol_mc_global SSOL_MC_GLOBAL_NULL = SSOL_MC_GLOBAL_NULL__;
+
+struct ssol_mc_receiver {
+ struct ssol_mc_result integrated_irradiance; /* In W */
+ struct ssol_mc_result absorptivity_loss; /* In W */
+ struct ssol_mc_result reflectivity_loss; /* In W */
+ struct ssol_mc_result cos_loss; /* In W TODO remove this */
+
+ /* Internal data */
+ size_t N__;
+ void* mc__;
+ const struct ssol_instance* instance__;
+};
+#define SSOL_MC_RECEIVER_NULL__ { \
+ SSOL_MC_RESULT_NULL__, \
+ SSOL_MC_RESULT_NULL__, \
+ SSOL_MC_RESULT_NULL__, \
+ SSOL_MC_RESULT_NULL__, \
+ 0, NULL, NULL \
+}
+static const struct ssol_mc_receiver SSOL_MC_RECEIVER_NULL =
+ SSOL_MC_RECEIVER_NULL__;
+
+struct ssol_mc_shape {
+ /* Internal data */
+ size_t N__;
+ void* mc__;
+ const struct ssol_shape* shape__;
+};
+#define SSOL_MC_SHAPE_NULL__ { 0, NULL, NULL }
+static const struct ssol_mc_shape SSOL_MC_SHAPE_NULL = SSOL_MC_SHAPE_NULL__;
+
+struct ssol_mc_primitive {
+ struct ssol_mc_result integrated_irradiance; /* In W */
+ struct ssol_mc_result absorptivity_loss; /* In W */
+ struct ssol_mc_result reflectivity_loss; /* In W */
+ struct ssol_mc_result cos_loss; /* In W TODO remove this */
};
+#define SSOL_MC_PRIMITIVE_NULL__ { \
+ SSOL_MC_RESULT_NULL__, \
+ SSOL_MC_RESULT_NULL__, \
+ SSOL_MC_RESULT_NULL__, \
+ SSOL_MC_RESULT_NULL__ \
+}
+static const struct ssol_mc_primitive SSOL_MC_PRIMITIVE_NULL =
+ SSOL_MC_PRIMITIVE_NULL__;
typedef res_T
(*ssol_write_pixels_T)
@@ -427,6 +559,12 @@ ssol_scene_detach_instance
(struct ssol_scene* scn,
struct ssol_instance* instance);
+SSOL_API res_T
+ssol_scene_compute_aabb
+ (const struct ssol_scene* scn,
+ float lower[3],
+ float upper[3]);
+
/* Detach all the instances from the scene and release the reference that the
* scene takes onto them.
* Also detach the attached sun if any. */
@@ -454,6 +592,12 @@ ssol_scene_detach_atmosphere
(struct ssol_scene* scn,
struct ssol_atmosphere* atm);
+SSOL_API res_T
+ssol_scene_for_each_instance
+ (struct ssol_scene* scn,
+ res_T (*func)(struct ssol_instance* instance, void* ctx),
+ void* ctx);
+
/*******************************************************************************
* Shape API - Define a geometry that can be generated from a quadric equation
* or from a triangular mesh.
@@ -476,6 +620,29 @@ SSOL_API res_T
ssol_shape_ref_put
(struct ssol_shape* shape);
+SSOL_API res_T
+ssol_shape_get_vertices_count
+ (const struct ssol_shape* shape,
+ unsigned* nverts);
+
+SSOL_API res_T
+ssol_shape_get_vertex_attrib
+ (const struct ssol_shape* shape,
+ const unsigned ivert,
+ const enum ssol_attrib_usage usage,
+ double value[]);
+
+SSOL_API res_T
+ssol_shape_get_triangles_count
+ (const struct ssol_shape* shape,
+ unsigned* ntris);
+
+SSOL_API res_T
+ssol_shape_get_triangle_indices
+ (const struct ssol_shape* shape,
+ const unsigned itri,
+ unsigned ids[3]);
+
/* Define a punched surface in local space, i.e. no translation & no orientation */
SSOL_API res_T
ssol_punched_surface_setup
@@ -500,6 +667,11 @@ ssol_mesh_setup
* (e.g.: refractive index) properties of a geometry.
******************************************************************************/
SSOL_API res_T
+ssol_material_create_dielectric
+ (struct ssol_device* dev,
+ struct ssol_material** mtl);
+
+SSOL_API res_T
ssol_material_create_mirror
(struct ssol_device* dev,
struct ssol_material** mtl);
@@ -515,6 +687,16 @@ ssol_material_create_virtual
struct ssol_material** mtl);
SSOL_API res_T
+ssol_material_create_thin_dielectric
+ (struct ssol_device* dev,
+ struct ssol_material** mtl);
+
+SSOL_API res_T
+ssol_material_get_type
+ (const struct ssol_material* mtl,
+ enum ssol_material_type* type);
+
+SSOL_API res_T
ssol_material_ref_get
(struct ssol_material* mtl);
@@ -528,15 +710,30 @@ ssol_material_set_param_buffer
struct ssol_param_buffer* buf);
SSOL_API res_T
-ssol_mirror_set_shader
+ssol_dielectric_setup
+ (struct ssol_material* mtl,
+ const struct ssol_dielectric_shader* shader,
+ const struct ssol_medium* outside_medium,
+ const struct ssol_medium* inside_medium);
+
+SSOL_API res_T
+ssol_mirror_setup
(struct ssol_material* mtl,
const struct ssol_mirror_shader* shader);
SSOL_API res_T
-ssol_matte_set_shader
+ssol_matte_setup
(struct ssol_material* mtl,
const struct ssol_matte_shader* shader);
+SSOL_API res_T
+ssol_thin_dielectric_setup
+ (struct ssol_material* mtl,
+ const struct ssol_thin_dielectric_shader* shader,
+ const struct ssol_medium* outside_medium,
+ const struct ssol_medium* slab_medium,
+ const double thickness);
+
/*******************************************************************************
* Object API - Opaque abstraction of a geometry with its associated properties.
******************************************************************************/
@@ -565,6 +762,12 @@ SSOL_API res_T
ssol_object_clear
(struct ssol_object* object);
+/* Retrieve the area of the object */
+SSOL_API res_T
+ssol_object_get_area
+ (const struct ssol_object* object,
+ double* area);
+
/*******************************************************************************
* Object Instance API - Clone of an object with a set of per instance data as
* world transformation, material parameters, etc. Note that the object
@@ -593,7 +796,8 @@ ssol_instance_set_transform
SSOL_API res_T
ssol_instance_set_receiver
(struct ssol_instance* instance,
- const int mask); /* Combination of ssol_side_flag */
+ const int mask, /* Combination of ssol_side_flag */
+ const int per_primitive); /* Enable the per primitive integration */
/* Define whether or not the instance is sampled or not. By default an instance
* is sampled. */
@@ -608,6 +812,30 @@ ssol_instance_get_id
(const struct ssol_instance* instance,
uint32_t* id);
+/* Retrieve the area of the instance */
+SSOL_API res_T
+ssol_instance_get_area
+ (const struct ssol_instance* instance,
+ double* area);
+
+SSOL_API res_T
+ssol_instance_get_shaded_shapes_count
+ (const struct ssol_instance* instance,
+ size_t* nshaded_shapes);
+
+SSOL_API res_T
+ssol_instance_get_shaded_shape
+ (const struct ssol_instance* instance,
+ const size_t ishaded_shape,
+ struct ssol_instantiated_shaded_shape* shaded_shape_instance);
+
+SSOL_API res_T
+ssol_instantiated_shaded_shape_get_vertex_attrib
+ (const struct ssol_instantiated_shaded_shape* sshape,
+ const unsigned ivert,
+ const enum ssol_attrib_usage usage,
+ double value[]);
+
/*******************************************************************************
* Param buffer API
******************************************************************************/
@@ -767,17 +995,17 @@ ssol_estimator_ref_put
(struct ssol_estimator* estimator);
SSOL_API res_T
-ssol_estimator_get_status
+ssol_estimator_get_mc_global
(const struct ssol_estimator* estimator,
- const enum ssol_status_type type,
- struct ssol_estimator_status* status);
+ struct ssol_mc_global* mc_global);
SSOL_API res_T
-ssol_estimator_get_receiver_status
+ssol_estimator_get_mc_sampled_x_receiver
(struct ssol_estimator* estimator,
- const struct ssol_instance* instance,
+ const struct ssol_instance* prim_instance,
+ const struct ssol_instance* recv_instance,
const enum ssol_side_flag side,
- struct ssol_estimator_status* status);
+ struct ssol_mc_receiver* rcv);
SSOL_API res_T
ssol_estimator_get_count
@@ -789,15 +1017,63 @@ ssol_estimator_get_failed_count
(const struct ssol_estimator* estimator,
size_t* count);
+/* Retrieve the overall area of the sampled instances */
SSOL_API res_T
ssol_estimator_get_sampled_area
(const struct ssol_estimator* estimator,
double* area);
+/*******************************************************************************
+ * Tracked paths
+ ******************************************************************************/
SSOL_API res_T
-ssol_estimator_get_primary_area
+ssol_estimator_get_tracked_paths_count
(const struct ssol_estimator* estimator,
- double* area);
+ size_t* npaths);
+
+SSOL_API res_T
+ssol_estimator_get_tracked_path
+ (const struct ssol_estimator* estimator,
+ const size_t ipath,
+ struct ssol_path* path);
+
+SSOL_API res_T
+ssol_path_get_vertices_count
+ (const struct ssol_path* path,
+ size_t* nvertices);
+
+SSOL_API res_T
+ssol_path_get_vertex
+ (const struct ssol_path* path,
+ const size_t ivertex,
+ struct ssol_path_vertex* vertex);
+
+SSOL_API res_T
+ssol_path_get_type
+ (const struct ssol_path* path,
+ enum ssol_path_type* type);
+
+/*******************************************************************************
+ * Per receiver MC estimations
+ ******************************************************************************/
+SSOL_API res_T
+ssol_estimator_get_mc_receiver
+ (struct ssol_estimator* estimator,
+ const struct ssol_instance* instance,
+ const enum ssol_side_flag side,
+ struct ssol_mc_receiver* rcv);
+
+SSOL_API res_T
+ssol_mc_receiver_get_mc_shape
+ (struct ssol_mc_receiver* rcv,
+ const struct ssol_shape* shape,
+ struct ssol_mc_shape* mc);
+
+SSOL_API res_T
+ssol_mc_shape_get_mc_primitive
+ (struct ssol_mc_shape* shape,
+ const unsigned i, /* In [0, ssol_shape_get_triangles_count[ */
+ struct ssol_mc_primitive* prim);
/*******************************************************************************
* Miscellaneous functions
@@ -807,15 +1083,27 @@ ssol_solve
(struct ssol_scene* scn,
struct ssp_rng* rng,
const size_t realisations_count,
+ const struct ssol_path_tracker* tracker, /* NULL<=>Do not record the paths */
FILE* output, /* May be NULL <=> does not ouput ssol_receiver_data */
struct ssol_estimator** estimator);
SSOL_API res_T
-ssol_draw
+ssol_draw_draft
+ (struct ssol_scene* scn,
+ struct ssol_camera* cam,
+ const size_t width, /* #pixels in X */
+ const size_t height, /* #pixels in Y */
+ const size_t spp, /* #samples per pixel */
+ ssol_write_pixels_T writer,
+ void* writer_data);
+
+SSOL_API res_T
+ssol_draw_pt
(struct ssol_scene* scn,
struct ssol_camera* cam,
const size_t width, /* #pixels in X */
const size_t height, /* #pixels in Y */
+ const size_t spp,
ssol_write_pixels_T writer,
void* writer_data);
diff --git a/src/ssol_atmosphere.c b/src/ssol_atmosphere.c
@@ -123,24 +123,13 @@ ssol_atmosphere_set_uniform_absorption
* Local functions
******************************************************************************/
double
-compute_atmosphere_transmissivity
+atmosphere_uniform_get_absorption
(const struct ssol_atmosphere* atmosphere,
- const double distance,
const double wavelength)
{
- double ka;
const struct ssol_spectrum* spectrum;
- if (!atmosphere)
- return 1;
-
- ASSERT(distance >= 0 && wavelength >= 0);
- switch (atmosphere->type) {
- case ATMOS_UNIFORM:
- spectrum = atmosphere->data.uniform.spectrum;
- ka = spectrum_interpolate(spectrum, wavelength);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
- return exp(-ka * distance);
+ ASSERT(atmosphere && atmosphere->type == ATMOS_UNIFORM && wavelength >= 0);
+ spectrum = atmosphere->data.uniform.spectrum;
+ return spectrum_interpolate(spectrum, wavelength);
}
diff --git a/src/ssol_atmosphere_c.h b/src/ssol_atmosphere_c.h
@@ -42,9 +42,8 @@ struct ssol_atmosphere {
};
extern LOCAL_SYM double
-compute_atmosphere_transmissivity
+atmosphere_uniform_get_absorption
(const struct ssol_atmosphere* atmosphere,
- const double distance,
const double wavelength);
#endif /* SSOL_ATMOSPHERE_C_H */
diff --git a/src/ssol_c.h b/src/ssol_c.h
@@ -41,11 +41,11 @@ struct ray_data {
/* Output data */
double N[3]; /* Normal of the nearest punched surface point */
- double dst; /* Hit distance of the nearest punced surface point */
+ double dst; /* Hit distance of the nearest punched surface point */
};
static const struct ray_data RAY_DATA_NULL = {
- NULL, S3D_PRIMITIVE_NULL__, NULL, SSOL_INVALID_SIDE, 0, 0, 0, {0, 0, 0}, 0
+ NULL, S3D_PRIMITIVE_NULL__, NULL, SSOL_INVALID_SIDE, 0, 0, 0, {0,0,0}, FLT_MAX
};
diff --git a/src/ssol_device.c b/src/ssol_device.c
@@ -19,6 +19,7 @@
#include <rsys/logger.h>
#include <rsys/mem_allocator.h>
+#include <star/s3d.h>
#include <star/scpr.h>
#include <omp.h>
diff --git a/src/ssol_device_c.h b/src/ssol_device_c.h
@@ -19,7 +19,6 @@
#include <rsys/dynamic_array.h>
#include <rsys/free_list.h>
#include <rsys/ref_count.h>
-#include <star/s3d.h>
#define DARRAY_NAME byte
#define DARRAY_DATA char
@@ -35,6 +34,7 @@
#include <rsys/dynamic_array.h>
struct scpr_mesh;
+struct s3d_device;
struct ssol_device {
struct logger* logger;
diff --git a/src/ssol_draw.c b/src/ssol_draw.c
@@ -14,16 +14,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "ssol.h"
-#include "ssol_c.h"
-#include "ssol_camera.h"
#include "ssol_device_c.h"
+#include "ssol_draw.h"
#include "ssol_scene_c.h"
-#include <rsys/double3.h>
-#include <rsys/math.h>
#include <star/s3d.h>
#include <omp.h>
+#include <star/ssf.h>
+#include <star/ssp.h>
#define TILE_SIZE 32 /* definition in X & Y of a tile */
STATIC_ASSERT(IS_POW2(TILE_SIZE), TILE_SIZE_must_be_a_power_of_2);
@@ -43,41 +42,23 @@ morton2D_decode(const uint32_t u32)
}
static void
-Li(struct ssol_scene* scn,
- struct s3d_scene_view* view,
- const float org[3],
- const float dir[3],
- double val[3])
-{
- const float range[2] = {0, FLT_MAX};
- struct ray_data ray_data = RAY_DATA_NULL;
- struct s3d_hit hit;
-
- ray_data.scn = scn;
- ray_data.discard_virtual_materials = 1;
- S3D(scene_view_trace_ray(view, org, dir, range, &ray_data, &hit));
- if(S3D_HIT_NONE(&hit)) {
- d3_splat(val, 0);
- } else {
- float N[3]={0};
- f3_normalize(N, hit.normal);
- d3_splat(val, fabs(f3_dot(N, dir)));
- }
-}
-
-static void
draw_tile
(struct ssol_scene* scn,
struct s3d_scene_view* view,
const struct ssol_camera* cam,
+ const int ithread,
+ const size_t spp,
const size_t origin[2], /* Tile origin */
const size_t size[2], /* Tile definition */
const float pix_sz[2], /* Normalized size of a pixel in the image plane */
- double* pixels)
+ double* pixels,
+ pixel_shader_T shader,
+ void* shader_data)
{
size_t npixels;
size_t mcode; /* Morton code of the tile pixel */
- ASSERT(scn && view && cam && origin && size && pix_sz && pixels);
+ ASSERT(scn && view && cam && spp && origin && size && pix_sz && pixels);
+ ASSERT(shader);
/* Adjust the #pixels to process them wrt a morton order */
npixels = round_up_pow2(MMAX(size[0], size[1]));
@@ -85,7 +66,6 @@ draw_tile
FOR_EACH(mcode, 0, npixels) {
size_t ipix[2];
- float org[3], dir[3], samp[2];
double* pixel;
ipix[0] = morton2D_decode((uint32_t)(mcode>>0));
@@ -94,29 +74,27 @@ draw_tile
if(ipix[1] >= size[1]) continue;
pixel = pixels + (ipix[1]*size[0] + ipix[0])*3/*#channels*/;
-
ipix[0] = ipix[0] + origin[0];
ipix[1] = ipix[1] + origin[1];
- samp[0] = ((float)ipix[0] + 0.5f) * pix_sz[0];
- samp[1] = ((float)ipix[1] + 0.5f) * pix_sz[1];
-
- camera_ray(cam, samp, org, dir);
- Li(scn, view, org, dir, pixel);
+ shader(scn, cam, view, ithread, ipix, pix_sz, spp, pixel, shader_data);
}
}
/*******************************************************************************
- * Exported function
+ * Local function
******************************************************************************/
res_T
-ssol_draw
+draw
(struct ssol_scene* scn,
- struct ssol_camera* cam,
+ const struct ssol_camera* cam,
const size_t width,
const size_t height,
+ const size_t spp, /* #samples per pixel */
ssol_write_pixels_T writer,
- void* data)
+ void* writer_data,
+ pixel_shader_T pixel_shader,
+ void* pixel_shader_data)
{
struct s3d_scene_view* view = NULL;
struct darray_byte* tiles = NULL;
@@ -126,10 +104,8 @@ ssol_draw
size_t i;
ATOMIC res = RES_OK;
- if(!scn || !cam || !width || !height || !writer) {
- res = RES_BAD_ARG;
- goto error;
- }
+ if(!scn || !cam || !width || !height || !spp || !writer || !pixel_shader)
+ return RES_BAD_ARG;
tiles = darray_tile_data_get(&scn->dev->tiles);
ASSERT(darray_tile_size_get(&scn->dev->tiles) == scn->dev->nthreads);
@@ -154,7 +130,7 @@ ssol_draw
for(mcode=0; mcode<(int64_t)ntiles; ++mcode) {
size_t tile_org[2];
size_t tile_sz[2];
- int ithread = omp_get_thread_num();
+ const int ithread = omp_get_thread_num();
double* pixels;
res_T res_local;
@@ -172,9 +148,10 @@ ssol_draw
pixels = (double*)darray_byte_data_get(tiles+ithread);
- draw_tile(scn, view, cam, tile_org, tile_sz, pix_sz, pixels);
+ draw_tile(scn, view, cam, ithread, spp, tile_org, tile_sz, pix_sz, pixels,
+ pixel_shader, pixel_shader_data);
- res_local = writer(data, tile_org, tile_sz, SSOL_PIXEL_DOUBLE3, pixels);
+ res_local = writer(writer_data, tile_org, tile_sz, SSOL_PIXEL_DOUBLE3, pixels);
if(res_local != RES_OK) {
ATOMIC_SET(&res, res_local);
continue;
@@ -188,3 +165,4 @@ error:
goto exit;
}
+
diff --git a/src/ssol_draw.h b/src/ssol_draw.h
@@ -0,0 +1,52 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SSOL_DRAW_H
+#define SSOL_DRAW_H
+
+#include "ssol.h"
+#include <rsys/rsys.h>
+
+/* Forward declarations */
+struct s3d_scene_view;
+struct ssf_bsdf;
+struct ssp_rng;
+
+typedef void
+(*pixel_shader_T)
+ (struct ssol_scene* scn,
+ const struct ssol_camera* cam,
+ struct s3d_scene_view* view,
+ const int ithread, /* Id of the thread invoking the function */
+ const size_t pix_coords[2], /* Image space pixel coordinates */
+ const float pix_sz[2], /* Normalized pixel size */
+ const size_t nsamples, /* #samples per pixel */
+ double pixel[3], /* Output pixel */
+ void* ctx); /* User defined data */
+
+extern LOCAL_SYM res_T
+draw
+ (struct ssol_scene* scn,
+ const struct ssol_camera* cam,
+ const size_t width,
+ const size_t height,
+ const size_t spp,
+ ssol_write_pixels_T writer,
+ void* writer_data,
+ pixel_shader_T pixel_shader,
+ void* pixel_shader_data);
+
+#endif /* SSOL_DRAW_H */
+
diff --git a/src/ssol_draw_draft.c b/src/ssol_draw_draft.c
@@ -0,0 +1,162 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "ssol_c.h"
+#include "ssol_camera.h"
+#include "ssol_device_c.h"
+#include "ssol_draw.h"
+#include "ssol_object_c.h"
+#include "ssol_scene_c.h"
+#include "ssol_shape_c.h"
+
+#include <rsys/double3.h>
+#include <rsys/dynamic_array_float.h>
+#include <rsys/float3.h>
+
+#include <star/ssp.h>
+
+#include <float.h>
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+Li
+ (struct ssol_scene* scn,
+ struct s3d_scene_view* view,
+ const float org[3],
+ const float dir[3],
+ double val[3])
+{
+ const float range[2] = {0, FLT_MAX};
+ struct ray_data ray_data = RAY_DATA_NULL;
+ struct s3d_hit hit;
+ ASSERT(scn && view && org && dir && val);
+
+ ray_data.scn = scn;
+ ray_data.discard_virtual_materials = 1;
+ S3D(scene_view_trace_ray(view, org, dir, range, &ray_data, &hit));
+ if(S3D_HIT_NONE(&hit)) {
+ d3_splat(val, 0);
+ } else {
+ struct ssol_instance* inst;
+ const struct shaded_shape* sshape;
+ size_t isshape;
+ float N[3]={0};
+
+ /* Retrieve the hit shaded shape */
+ inst = *htable_instance_find(&scn->instances_rt, &hit.prim.inst_id);
+ isshape = *htable_shaded_shape_find
+ (&inst->object->shaded_shapes_rt, &hit.prim.geom_id);
+ sshape = darray_shaded_shape_cdata_get
+ (&inst->object->shaded_shapes) + isshape;
+
+ /* Retrieve and normalized the hit normal */
+ switch(sshape->shape->type) {
+ case SHAPE_MESH: f3_normalize(N, hit.normal); break;
+ case SHAPE_PUNCHED: f3_normalize(N, f3_set_d3(N, ray_data.N)); break;
+ default: FATAL("Unreachable code"); break;
+ }
+ ASSERT(f3_is_normalized(N));
+ d3_splat(val, fabs(f3_dot(N, dir)));
+ }
+}
+
+static void
+draw_pixel
+ (struct ssol_scene* scn,
+ const struct ssol_camera* cam,
+ struct s3d_scene_view* view,
+ const int ithread,
+ const size_t pix_coords[2], /* Image space pixel coordinates */
+ const float pix_sz[2], /* Normalized pixel size */
+ const size_t nsamples,
+ double pixel[3],
+ void* ctx)
+{
+ struct darray_float* samples = ctx;
+ float samp[2];
+ float ray_org[3], ray_dir[3];
+ double sum[3] = {0, 0, 0};
+ size_t i;
+ ASSERT(scn && cam && view && pix_coords && pix_sz && nsamples && pixel && ctx);
+ (void)ithread;
+
+ FOR_EACH(i, 0, nsamples) {
+ double weight[3];
+ const float* r = darray_float_cdata_get(samples) + i*2;
+
+ /* Generate a sample into the pixel */
+ samp[0] = ((float)pix_coords[0] + r[0]) * pix_sz[0];
+ samp[1] = ((float)pix_coords[1] + r[1]) * pix_sz[1];
+
+ /* Generate a ray starting from the pinhole camera and passing through the
+ * pixel sample */
+ camera_ray(cam, samp, ray_org, ray_dir);
+
+ /* Compute the radiance arriving through the sampled camera ray */
+ Li(scn, view, ray_org, ray_dir, weight);
+ d3_add(sum, sum, weight);
+ }
+ d3_divd(pixel, sum, (double)nsamples);
+}
+
+
+/*******************************************************************************
+ * Exported function
+ ******************************************************************************/
+res_T
+ssol_draw_draft
+ (struct ssol_scene* scn,
+ struct ssol_camera* cam,
+ const size_t width,
+ const size_t height,
+ const size_t spp,
+ ssol_write_pixels_T writer,
+ void* data)
+{
+ struct darray_float samples;
+ struct ssp_rng* rng = NULL;
+ size_t i;
+ res_T res = RES_OK;
+
+ if(!scn || !spp) return RES_BAD_ARG;
+
+ darray_float_init(scn->dev->allocator, &samples);
+ res = darray_float_reserve(&samples, spp * 2/*#dimensions*/);
+ if(res != RES_OK) goto error;
+
+ res = ssp_rng_create(scn->dev->allocator, &ssp_rng_threefry, &rng);
+ if(res != RES_OK) goto error;
+
+ /* Generate the pixel samples */
+ FOR_EACH(i, 0, spp) {
+ const float x = ssp_rng_canonical_float(rng);
+ const float y = ssp_rng_canonical_float(rng);
+ darray_float_push_back(&samples, &x);
+ darray_float_push_back(&samples, &y);
+ }
+
+ res = draw(scn, cam, width, height, spp, writer, data, draw_pixel, &samples);
+ if(res != RES_OK) goto error;
+
+exit:
+ darray_float_release(&samples);
+ if(rng) SSP(rng_ref_put(rng));
+ return res;
+error:
+ goto exit;
+}
+
diff --git a/src/ssol_draw_pt.c b/src/ssol_draw_pt.c
@@ -0,0 +1,360 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "ssol_c.h"
+#include "ssol_camera.h"
+#include "ssol_device_c.h"
+#include "ssol_draw.h"
+#include "ssol_material_c.h"
+#include "ssol_object_c.h"
+#include "ssol_scene_c.h"
+#include "ssol_shape_c.h"
+#include "ssol_sun_c.h"
+
+#include <rsys/double2.h>
+#include <rsys/double3.h>
+#include <rsys/float3.h>
+
+#include <star/s3d.h>
+#include <star/ssf.h>
+#include <star/ssp.h>
+
+/*******************************************************************************
+ * Per thread draw_pt context
+ ******************************************************************************/
+struct thread_context {
+ struct ssp_rng* rng;
+ struct ssf_bsdf* bsdf;
+};
+
+static void
+thread_context_release(struct thread_context* ctx)
+{
+ ASSERT(ctx);
+ if(ctx->rng) SSP(rng_ref_put(ctx->rng));
+ if(ctx->bsdf) SSF(bsdf_ref_put(ctx->bsdf));
+}
+
+static res_T
+thread_context_init
+ (struct mem_allocator* allocator,
+ struct thread_context* ctx)
+{
+ res_T res = RES_OK;
+ ASSERT(ctx);
+ memset(ctx, 0, sizeof(ctx[0]));
+ res = ssf_bsdf_create(allocator, &ctx->bsdf);
+ if(res != RES_OK) goto error;
+exit:
+ return res;
+error:
+ thread_context_release(ctx);
+ goto exit;
+}
+
+static void
+thread_context_setup
+ (struct thread_context* ctx,
+ struct ssp_rng* rng)
+{
+ ASSERT(ctx && rng);
+ if(ctx->rng) SSP(rng_ref_put(ctx->rng));
+ SSP(rng_ref_get(rng));
+ ctx->rng = rng;
+}
+
+/* Declare the container of the per thread contexts */
+#define DARRAY_NAME thread_context
+#define DARRAY_DATA struct thread_context
+#define DARRAY_FUNCTOR_INIT thread_context_init
+#define DARRAY_FUNCTOR_RELEASE thread_context_release
+#include <rsys/dynamic_array.h>
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static INLINE double
+sun_lighting
+ (struct ssol_sun* sun,
+ struct s3d_scene_view* view,
+ struct ray_data* ray_data,
+ struct ssf_bsdf* bsdf,
+ const double wo[3],
+ const double N[3],
+ const float ray_org[3])
+{
+ struct s3d_hit hit;
+ const float ray_range[2] = {0, FLT_MAX};
+ double wi[3];
+ float ray_dir[3];
+ double cos_wi_N;
+ double R;
+ ASSERT(sun && view && ray_data && bsdf && wo && N && ray_org);
+ ASSERT(d3_dot(wo, N) >= 0); /* Assume that wo point outward the surface */
+
+ /* Ensure that the incoming direction point outward the surface */
+ d3_minus(wi, sun->direction);
+
+ /* The point look backward the sun */
+ if(d3_dot(wi, N) < 0) return 0.0;
+
+ R = ssf_bsdf_eval(bsdf, wo, N, wi);
+ if(R <= 0) return 0.0;
+
+ cos_wi_N = d3_dot(wi, N);
+
+ f3_set_d3(ray_dir, wi);
+ S3D(scene_view_trace_ray(view, ray_org, ray_dir, ray_range, ray_data, &hit));
+ if(S3D_HIT_NONE(&hit)) return R * cos_wi_N;
+ return 0;
+}
+
+static res_T
+Li(struct ssol_scene* scn,
+ struct thread_context* ctx,
+ struct s3d_scene_view* view,
+ const float org[3],
+ const float dir[3],
+ double val[3])
+{
+ struct ssol_medium medium;
+ struct s3d_hit hit;
+ struct ray_data ray_data = RAY_DATA_NULL;
+ struct ssol_instance* inst;
+ struct ssol_material* mtl;
+ const struct shaded_shape* sshape;
+ struct surface_fragment frag;
+ size_t isshape;
+ double throughput = 1.0;
+ double wi[3], o[3], uv[3];
+ double wo[3];
+ double N[3];
+ double L = 0;
+ double R;
+ double pdf;
+ const float ray_range[2] = {0, FLT_MAX};
+ float ray_org[3];
+ float ray_dir[3];
+ enum ssol_side_flag side;
+ int russian_roulette = 0;
+ int type;
+ res_T res = RES_OK;
+ ASSERT(scn && view && org && dir && val);
+
+ ray_data.scn = scn;
+ ray_data.discard_virtual_materials = 1;
+
+ f3_set(ray_org, org);
+ f3_set(ray_dir, dir);
+
+ /* Assume that the path starts from vacuum */
+ medium = SSOL_MEDIUM_VACUUM;
+
+ for(;;) {
+ S3D(scene_view_trace_ray
+ (view, ray_org, ray_dir, ray_range, &ray_data, &hit));
+
+ if(medium.absorptivity > 0) {
+ throughput *= exp(-medium.absorptivity * hit.distance);
+ }
+
+ if(S3D_HIT_NONE(&hit)) { /* Background lighting */
+ if(ray_dir[2] > 0) L += throughput * 1.e-1;
+ break;
+ }
+
+ /* Retrieve the hit shaded shape */
+ inst = *htable_instance_find(&scn->instances_rt, &hit.prim.inst_id);
+ isshape = *htable_shaded_shape_find
+ (&inst->object->shaded_shapes_rt, &hit.prim.geom_id);
+ sshape = darray_shaded_shape_cdata_get(&inst->object->shaded_shapes)+isshape;
+
+ d3_set_f3(o, ray_org);
+ d3_set_f3(wo, ray_dir);
+ d2_set_f2(uv, hit.uv);
+ d3_normalize(wo, wo);
+
+ /* Retrieve and normalized the hit normal */
+ switch(sshape->shape->type) {
+ case SHAPE_MESH: d3_normalize(N, d3_set_f3(N, hit.normal)); break;
+ case SHAPE_PUNCHED: d3_normalize(N, ray_data.N); break;
+ default: FATAL("Unreachable code"); break;
+ }
+
+ if(d3_dot(N, wo) < 0) {
+ mtl = sshape->mtl_front;
+ side = SSOL_FRONT;
+ } else {
+ mtl = sshape->mtl_back;
+ side = SSOL_BACK;
+ d3_minus(N, N);
+ }
+
+ surface_fragment_setup(&frag, o, wo, N, &hit.prim, hit.uv);
+ SSF(bsdf_clear(ctx->bsdf));
+ res = material_shade_rendering
+ (mtl, &frag, 1/*TODO wavelength*/, &medium, ctx->bsdf);
+ if(res != RES_OK) goto error;
+
+ /* Update the ray */
+ ray_data.prim_from = hit.prim;
+ ray_data.inst_from = inst;
+ ray_data.side_from = side;
+ f3_mulf(ray_dir, ray_dir, hit.distance);
+ f3_add(ray_org, ray_org, ray_dir);
+
+ d3_minus(wo, wo);
+ if(scn->sun) {
+ L += throughput * sun_lighting
+ (scn->sun, view, &ray_data, ctx->bsdf, wo, N, ray_org);
+ }
+
+ R = ssf_bsdf_sample(ctx->bsdf, ctx->rng, wo, frag.Ns, wi, &type, &pdf);
+ ASSERT(0 <= R && R <= 1);
+ f3_set_d3(ray_dir, wi);
+ if(type & SSF_TRANSMISSION) material_get_next_medium(mtl, &medium, &medium);
+
+ if(!russian_roulette) {
+ throughput *= fabs(d3_dot(wi, N)) * R;
+ } else {
+ if(ssp_rng_canonical(ctx->rng) >= R) break;
+ throughput *= d3_dot(wi, N);
+ }
+
+ if(throughput <= 0) break;
+
+ if(!russian_roulette) {
+ russian_roulette = throughput < 0.1;
+ }
+ }
+ d3_splat(val, L);
+
+exit:
+ return res;
+error:
+ d3(val, 1, 1, 0);
+ goto exit;
+}
+
+static void
+draw_pixel
+ (struct ssol_scene* scn,
+ const struct ssol_camera* cam,
+ struct s3d_scene_view* view,
+ const int ithread,
+ const size_t pix_coords[2], /* Image space pixel coordinates */
+ const float pix_sz[2], /* Normalized pixel size */
+ const size_t nsamples,
+ double pixel[3],
+ void* data)
+{
+ struct darray_thread_context* thread_ctxs = data;
+ struct thread_context* ctx;
+ double sum[3] = {0, 0, 0};
+ size_t isample;
+ res_T res = RES_OK;
+ ASSERT(scn && cam && pix_coords && pix_sz && nsamples && pixel && data);
+ ASSERT((size_t)ithread < darray_thread_context_size_get(thread_ctxs));
+
+ ctx = darray_thread_context_data_get(thread_ctxs) + ithread;
+
+ FOR_EACH(isample, 0, nsamples) {
+ const int MAX_NFAILURES = 10;
+ double weight[3];
+ float samp[2]; /* Pixel sample */
+ float ray_org[3], ray_dir[3];
+ int nfailures = 0;
+
+ /* Generate a sample into the pixel */
+ samp[0] = ((float)pix_coords[0]+ssp_rng_canonical_float(ctx->rng))*pix_sz[0];
+ samp[1] = ((float)pix_coords[1]+ssp_rng_canonical_float(ctx->rng))*pix_sz[1];
+
+ do {
+ /* Generate a ray starting from the pinhole camera and passing through the
+ * pixel sample */
+ camera_ray(cam, samp, ray_org, ray_dir);
+
+ /* Compute the radiance arriving through the sampled camera ray */
+ res = Li(scn, ctx, view, ray_org, ray_dir, weight);
+ } while(res == RES_BAD_OP && ++nfailures < MAX_NFAILURES);
+ if(res != RES_OK) goto error;
+
+ d3_add(sum, sum, weight);
+ }
+
+ d3_divd(pixel, sum, (double)nsamples);
+exit:
+ return;
+error:
+ log_error(scn->dev, "Path tracing integrator error.\n");
+ d3(pixel, 1, 1, 0);
+ goto exit;
+}
+
+/*******************************************************************************
+ * Exported function
+ ******************************************************************************/
+res_T
+ssol_draw_pt
+ (struct ssol_scene* scn,
+ struct ssol_camera* cam,
+ const size_t width,
+ const size_t height,
+ const size_t spp,
+ ssol_write_pixels_T writer,
+ void* data)
+{
+ struct darray_thread_context thread_ctxs;
+ struct ssp_rng_proxy* rng_proxy = NULL;
+ size_t i;
+ res_T res = RES_OK;
+
+ if(!scn)
+ return RES_BAD_ARG;
+
+ darray_thread_context_init(scn->dev->allocator, &thread_ctxs);
+
+ /* Create a RNG proxy */
+ res = ssp_rng_proxy_create
+ (scn->dev->allocator, &ssp_rng_threefry, scn->dev->nthreads, &rng_proxy);
+ if(res != RES_OK) goto error;
+
+ /* Create the thread contexts */
+ res = darray_thread_context_resize(&thread_ctxs, scn->dev->nthreads);
+ if(res != RES_OK) goto error;
+ FOR_EACH(i, 0, scn->dev->nthreads) {
+ struct thread_context* ctx;
+ struct ssp_rng* rng;
+
+ ctx = darray_thread_context_data_get(&thread_ctxs)+i;
+
+ res = ssp_rng_proxy_create_rng(rng_proxy, i, &rng);
+ if(res != RES_OK) goto error;
+
+ thread_context_setup(ctx, rng);
+ SSP(rng_ref_put(rng));
+ }
+
+ /* Invoke the draw process */
+ res = draw(scn, cam, width, height, spp, writer, data, draw_pixel, &thread_ctxs);
+ if(res != RES_OK) goto error;
+
+exit:
+ darray_thread_context_release(&thread_ctxs);
+ if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
+ return (res_T)res;
+error:
+ goto exit;
+}
diff --git a/src/ssol_estimator.c b/src/ssol_estimator.c
@@ -20,9 +20,10 @@
#include "ssol_device_c.h"
#include "ssol_instance_c.h"
-#include <rsys/rsys.h>
+#include <rsys/double3.h>
#include <rsys/mem_allocator.h>
#include <rsys/ref_count.h>
+#include <rsys/rsys.h>
#include <math.h>
@@ -30,31 +31,42 @@
* Helper functions
******************************************************************************/
static res_T
-create_per_receiver_mc_data
+create_mc_receivers
(struct ssol_estimator* estimator,
struct ssol_scene* scene)
{
struct htable_instance_iterator it, end;
+ struct mc_receiver mc_rcv_null;
+ struct mc_sampled mc_samp_null;
res_T res = RES_OK;
ASSERT(scene && estimator);
htable_instance_begin(&scene->instances_rt, &it);
htable_instance_end(&scene->instances_rt, &end);
+ mc_receiver_init(estimator->dev->allocator, &mc_rcv_null);
+ mc_sampled_init(estimator->dev->allocator, &mc_samp_null);
+
while(!htable_instance_iterator_eq(&it, &end)) {
const struct ssol_instance* inst = *htable_instance_iterator_data_get(&it);
htable_instance_iterator_next(&it);
- if(!inst->receiver_mask) continue;
-
- res = htable_receiver_set
- (&estimator->global_receivers, &inst, &MC_RECV_DATA_NULL);
- if(res != RES_OK) goto error;
+ if(inst->receiver_mask) {
+ res = htable_receiver_set(&estimator->mc_receivers, &inst, &mc_rcv_null);
+ if(res != RES_OK) goto error;
+ }
+ if(inst->sample) {
+ res = htable_sampled_set(&estimator->mc_sampled, &inst, &mc_samp_null);
+ if(res != RES_OK) goto error;
+ }
}
exit:
+ mc_receiver_release(&mc_rcv_null);
+ mc_sampled_release(&mc_samp_null);
return res;
error:
- htable_receiver_clear(&estimator->global_receivers);
+ htable_receiver_clear(&estimator->mc_receivers);
+ htable_sampled_clear(&estimator->mc_sampled);
goto exit;
}
@@ -66,7 +78,9 @@ estimator_release(ref_T* ref)
CONTAINER_OF(ref, struct ssol_estimator, ref);
ASSERT(ref);
dev = estimator->dev;
- htable_receiver_release(&estimator->global_receivers);
+ htable_receiver_release(&estimator->mc_receivers);
+ htable_sampled_release(&estimator->mc_sampled);
+ darray_path_release(&estimator->paths);
ASSERT(dev && dev->allocator);
MEM_RM(dev->allocator, estimator);
SSOL(device_ref_put(dev));
@@ -76,89 +90,90 @@ estimator_release(ref_T* ref)
* Exported function
******************************************************************************/
res_T
-ssol_estimator_ref_get
-(struct ssol_estimator* estimator)
+ssol_estimator_ref_get(struct ssol_estimator* estimator)
{
- if (!estimator) return RES_BAD_ARG;
+ if(!estimator) return RES_BAD_ARG;
ref_get(&estimator->ref);
return RES_OK;
}
res_T
-ssol_estimator_ref_put
-(struct ssol_estimator* estimator)
+ssol_estimator_ref_put(struct ssol_estimator* estimator)
{
- if (!estimator) return RES_BAD_ARG;
+ if(!estimator) return RES_BAD_ARG;
ref_put(&estimator->ref, estimator_release);
return RES_OK;
}
res_T
-ssol_estimator_get_status
+ssol_estimator_get_mc_global
(const struct ssol_estimator* estimator,
- const enum ssol_status_type type,
- struct ssol_estimator_status* status)
+ struct ssol_mc_global* global)
{
- const struct mc_data* data;
- if (!estimator || type >= SSOL_STATUS_TYPES_COUNT__ || !status)
- return RES_BAD_ARG;
-
- switch (type) {
- case SSOL_STATUS_SHADOW: data = &estimator->shadow; break;
- case SSOL_STATUS_MISSING: data = &estimator->missing; break;
- default: FATAL("Unreachable code.\n"); break;
- }
- status->N = estimator->realisation_count;
- status->Nf = estimator->failed_count;
- status->irradiance.E = data->weight / (double)status->N;
- status->irradiance.V
- = data->sqr_weight / (double)status->N
- - status->irradiance.E * status->irradiance.E;
- status->irradiance.SE
- = (status->irradiance.V > 0)
- ? sqrt(status->irradiance.V / (double)status->N) : 0;
- status->absorptivity_loss.E = 0;
- status->absorptivity_loss.V = 0;
- status->absorptivity_loss.SE = 0;
- status->reflectivity_loss.E = 0;
- status->reflectivity_loss.V = 0;
- status->reflectivity_loss.SE = 0;
- status->cos_loss.E = 0;
- status->cos_loss.V = 0;
- status->cos_loss.SE = 0;
+ if(!estimator || !global) return RES_BAD_ARG;
+ #define SETUP_MC_RESULT(Name) { \
+ const double N = (double)estimator->realisation_count; \
+ const struct mc_data* data = &estimator->Name; \
+ global->Name.E = data->weight / N; \
+ global->Name.V = data->sqr_weight / N - global->Name.E*global->Name.E; \
+ global->Name.SE = global->Name.V > 0 ? sqrt(global->Name.V / N) : 0; \
+ } (void)0
+ SETUP_MC_RESULT(cos_loss);
+ SETUP_MC_RESULT(shadowed);
+ SETUP_MC_RESULT(missing);
+ #undef SETUP_MC_RESULT
return RES_OK;
}
res_T
-ssol_estimator_get_receiver_status
+ssol_estimator_get_mc_sampled_x_receiver
(struct ssol_estimator* estimator,
- const struct ssol_instance* instance,
+ const struct ssol_instance* samp_instance,
+ const struct ssol_instance* recv_instance,
const enum ssol_side_flag side,
- struct ssol_estimator_status* status)
+ struct ssol_mc_receiver* rcv)
{
- const struct mc_per_receiver_1side_data* data = NULL;
- if (!estimator || !instance || !status
- || (side != SSOL_BACK && side != SSOL_FRONT))
+ struct mc_sampled* mc_samp = NULL;
+ struct mc_receiver* mc_rcv = NULL;
+ struct mc_receiver_1side* mc_rcv1 = NULL;
+
+ if(!estimator || !samp_instance || !recv_instance || !rcv
+ || (side != SSOL_BACK && side != SSOL_FRONT)
+ || !samp_instance->sample
+ || !(recv_instance->receiver_mask & (int)side))
return RES_BAD_ARG;
- /* Check if a receiver is defined for this instance/side */
- data = estimator_get_receiver_data
- (&estimator->global_receivers, instance, side);
- if(data == NULL) return RES_BAD_ARG;
+ memset(rcv, 0, sizeof(rcv[0]));
- status->N = estimator->realisation_count;
- status->Nf = estimator->failed_count;
- #define SETUP_MC_STATUS(Name) { \
- const double N = (double)estimator->realisation_count; \
- status->Name.E = data->Name.weight / N; \
- status->Name.V = data->Name.sqr_weight/N - status->Name.E*status->Name.E; \
- status->Name.SE = status->Name.V > 0 ? sqrt(status->Name.V / N) : 0; \
+
+ mc_samp = htable_sampled_find(&estimator->mc_sampled, &samp_instance);
+ if(!mc_samp || !mc_samp->nb_samples) {
+ /* The sampled instance has no MC estimation */
+ return RES_BAD_ARG;
+ }
+
+ mc_rcv = htable_receiver_find(&mc_samp->mc_rcvs, &recv_instance);
+ if(!mc_rcv) {
+ /* No radiative path starting from the sampled instance reaches the receiver
+ * instance. */
+ return RES_OK;
+ }
+
+ mc_rcv1 = side == SSOL_FRONT ? &mc_rcv->front : &mc_rcv->back;
+ #define SETUP_MC_RESULT(Name) { \
+ const double N = (double)mc_samp->nb_samples; \
+ const struct mc_data* data = &mc_rcv1->Name; \
+ rcv->Name.E = data->weight / N; \
+ rcv->Name.V = data->sqr_weight / N - rcv->Name.E*rcv->Name.E; \
+ rcv->Name.SE = rcv->Name.V > 0 ? sqrt(rcv->Name.V / N) : 0; \
} (void)0
- SETUP_MC_STATUS(irradiance);
- SETUP_MC_STATUS(absorptivity_loss);
- SETUP_MC_STATUS(reflectivity_loss);
- SETUP_MC_STATUS(cos_loss);
- #undef SETUP_MC_STATUS
+ SETUP_MC_RESULT(integrated_irradiance);
+ SETUP_MC_RESULT(absorptivity_loss);
+ SETUP_MC_RESULT(reflectivity_loss);
+ SETUP_MC_RESULT(cos_loss);
+ #undef SETUP_MC_RESULT
+ rcv->mc__ = mc_rcv1;
+ rcv->N__ = mc_samp->nb_samples;
return RES_OK;
}
@@ -182,21 +197,64 @@ ssol_estimator_get_failed_count
res_T
ssol_estimator_get_sampled_area
- (const struct ssol_estimator* estimator,
- double* area)
+ (const struct ssol_estimator* estimator, double* area)
{
- if (!estimator || !area) return RES_BAD_ARG;
+ if(!estimator || !area) return RES_BAD_ARG;
*area = estimator->sampled_area;
return RES_OK;
}
res_T
-ssol_estimator_get_primary_area
+ssol_estimator_get_tracked_paths_count
+ (const struct ssol_estimator* estimator, size_t* npaths)
+{
+ if(!estimator || !npaths) return RES_BAD_ARG;
+ *npaths = darray_path_size_get(&estimator->paths);
+ return RES_OK;
+}
+
+res_T
+ssol_estimator_get_tracked_path
(const struct ssol_estimator* estimator,
- double* area)
+ const size_t ipath,
+ struct ssol_path* path)
+{
+ if(!estimator || ipath >= darray_path_size_get(&estimator->paths) || !path)
+ return RES_BAD_ARG;
+ path->path__ = darray_path_cdata_get(&estimator->paths) + ipath;
+ return RES_OK;
+}
+
+res_T
+ssol_path_get_vertices_count(const struct ssol_path* path, size_t* nvertices)
+{
+ const struct path* p;
+ if(!path || !nvertices) return RES_BAD_ARG;
+ p = path->path__;
+ *nvertices = darray_path_vertex_size_get(&p->vertices);
+ return RES_OK;
+}
+
+res_T
+ssol_path_get_vertex
+ (const struct ssol_path* path,
+ const size_t ivertex,
+ struct ssol_path_vertex* vertex)
+{
+ const struct path* p;
+ if(!path || !vertex) return RES_BAD_ARG;
+ p = path->path__;
+ if(ivertex >= darray_path_vertex_size_get(&p->vertices)) return RES_BAD_ARG;
+ *vertex = darray_path_vertex_cdata_get(&p->vertices)[ivertex];
+ return RES_OK;
+}
+
+res_T
+ssol_path_get_type(const struct ssol_path* path, enum ssol_path_type* type)
{
- if (!estimator || !area) return RES_BAD_ARG;
- *area = estimator->primary_area;
+ ASSERT(path && type);
+ if(!path || !type) return RES_BAD_ARG;
+ *type = ((struct path*)path->path__)->type;
return RES_OK;
}
@@ -223,12 +281,14 @@ estimator_create
goto error;
}
- htable_receiver_init(dev->allocator, &estimator->global_receivers);
+ htable_receiver_init(dev->allocator, &estimator->mc_receivers);
+ htable_sampled_init(dev->allocator, &estimator->mc_sampled);
+ darray_path_init(dev->allocator, &estimator->paths);
SSOL(device_ref_get(dev));
estimator->dev = dev;
ref_init(&estimator->ref);
- res = create_per_receiver_mc_data(estimator, scene);
+ res = create_mc_receivers(estimator, scene);
if(res != RES_OK) goto error;
exit:
diff --git a/src/ssol_estimator_c.h b/src/ssol_estimator_c.h
@@ -1,93 +1,473 @@
/* Copyright (C) CNRS 2016-2017
-*
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, either version 3 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef SSOL_ESTIMATOR_C_H
#define SSOL_ESTIMATOR_C_H
+#include "ssol_device_c.h"
+#include "ssol_instance_c.h"
+#include "ssol_shape_c.h"
+
#include <rsys/ref_count.h>
#include <rsys/hash_table.h>
+/* Forward declaration */
struct mem_allocator;
-
-static FINLINE int
-side_idx(const enum ssol_side_flag side)
-{
- ASSERT(side == SSOL_FRONT || side == SSOL_BACK);
- return side == SSOL_FRONT ? 0 : 1;
-}
+struct ssol_instance;
/* Monte carlo data */
struct mc_data {
double weight;
double sqr_weight;
};
-
#define MC_DATA_NULL__ { 0, 0 }
static const struct mc_data MC_DATA_NULL = MC_DATA_NULL__;
-struct mc_per_receiver_1side_data {
- struct mc_data irradiance;
- struct mc_data absorptivity_loss;
- struct mc_data reflectivity_loss;
- struct mc_data cos_loss;
+#define MC_RECEIVER_DATA \
+ struct mc_data integrated_irradiance; /* In W */ \
+ struct mc_data absorptivity_loss; /* In W */ \
+ struct mc_data reflectivity_loss; /* In W */ \
+ struct mc_data cos_loss; /* In W */
+
+#define MC_RECEIVER_DATA_NULL__ \
+ MC_DATA_NULL__, \
+ MC_DATA_NULL__, \
+ MC_DATA_NULL__, \
+ MC_DATA_NULL__
+
+/*******************************************************************************
+ * One sided per shape MC data
+ ******************************************************************************/
+struct mc_primitive_1side {
+ MC_RECEIVER_DATA
};
-#define MC_RECV_1SIDE_DATA_NULL__ {\
- MC_DATA_NULL__, MC_DATA_NULL__, MC_DATA_NULL__, MC_DATA_NULL__ }
+#define MC_PRIMITIVE_1SIDE_NULL__ { MC_RECEIVER_DATA_NULL__ }
+static const struct mc_primitive_1side MC_PRIMITIVE_1SIDE_NULL =
+ MC_PRIMITIVE_1SIDE_NULL__;
+
+/* Map an unsigned to a struct mc_primitive_1side */
+#define HTABLE_NAME prim2mc
+#define HTABLE_KEY unsigned
+#define HTABLE_DATA struct mc_primitive_1side
+#include <rsys/hash_table.h>
+
+struct mc_shape_1side {
+ struct htable_prim2mc prim2mc;
+};
+
+static INLINE void
+mc_shape_1side_init
+ (struct mem_allocator* allocator, struct mc_shape_1side* mc)
+{
+ ASSERT(mc);
+ htable_prim2mc_init(allocator, &mc->prim2mc);
+}
+
+static INLINE void
+mc_shape_1side_release(struct mc_shape_1side* mc)
+{
+ ASSERT(mc);
+ htable_prim2mc_release(&mc->prim2mc);
+}
+
+static INLINE res_T
+mc_shape_1side_copy
+ (struct mc_shape_1side* dst, const struct mc_shape_1side* src)
+{
+ ASSERT(dst && src);
+ return htable_prim2mc_copy(&dst->prim2mc, &src->prim2mc);
+}
+
+static INLINE res_T
+mc_shape_1side_copy_and_release
+ (struct mc_shape_1side* dst, struct mc_shape_1side* src)
+{
+ ASSERT(dst && src);
+ return htable_prim2mc_copy_and_release(&dst->prim2mc, &src->prim2mc);
+}
+
+static INLINE res_T
+mc_shape_1side_get_mc_primitive
+ (struct mc_shape_1side* mc_shape1,
+ const unsigned iprim,
+ struct mc_primitive_1side** out_mc_prim1)
+{
+ struct mc_primitive_1side* mc_prim1 = NULL;
+ res_T res = RES_OK;
+ ASSERT(mc_shape1 && out_mc_prim1);
+
+ mc_prim1 = htable_prim2mc_find(&mc_shape1->prim2mc, &iprim);
+ if(!mc_prim1) {
+ res = htable_prim2mc_set(&mc_shape1->prim2mc, &iprim, &MC_PRIMITIVE_1SIDE_NULL);
+ if(res != RES_OK) goto error;
+
+ mc_prim1 = htable_prim2mc_find(&mc_shape1->prim2mc, &iprim);
+ }
+
+exit:
+ *out_mc_prim1 = mc_prim1;
+ return res;
+error:
+ goto exit;
+}
-static const struct mc_per_receiver_1side_data
-MC_RECV_1SIDE_DATA_NULL = MC_RECV_1SIDE_DATA_NULL__;
+/*******************************************************************************
+ * One sided per receiver MC data
+ ******************************************************************************/
+/* Map a ssol shape to a struct mc_shape_1side */
+#define HTABLE_NAME shape2mc
+#define HTABLE_KEY const struct ssol_shape*
+#define HTABLE_DATA struct mc_shape_1side
+#define HTABLE_DATA_FUNCTOR_INIT mc_shape_1side_init
+#define HTABLE_DATA_FUNCTOR_RELEASE mc_shape_1side_release
+#define HTABLE_DATA_FUNCTOR_COPY mc_shape_1side_copy
+#define HTABLE_DATA_FUNCTOR_COPY_AND_RELEASE mc_shape_1side_copy_and_release
+#include <rsys/hash_table.h>
-struct mc_per_receiver_data {
- struct mc_per_receiver_1side_data front;
- struct mc_per_receiver_1side_data back;
+struct mc_receiver_1side {
+ MC_RECEIVER_DATA
+ struct htable_shape2mc shape2mc;
};
-#define MC_RECV_DATA_NULL__ { MC_RECV_1SIDE_DATA_NULL__, MC_RECV_1SIDE_DATA_NULL__ }
+static INLINE void
+mc_receiver_1side_init
+ (struct mem_allocator* allocator, struct mc_receiver_1side* mc)
+{
+ ASSERT(mc);
+ mc->integrated_irradiance = MC_DATA_NULL;
+ mc->absorptivity_loss = MC_DATA_NULL;
+ mc->reflectivity_loss = MC_DATA_NULL;
+ mc->cos_loss = MC_DATA_NULL;
+ htable_shape2mc_init(allocator, &mc->shape2mc);
+}
+
+static INLINE void
+mc_receiver_1side_release(struct mc_receiver_1side* mc)
+{
+ ASSERT(mc);
+ htable_shape2mc_release(&mc->shape2mc);
+}
+
+static INLINE res_T
+mc_receiver_1side_copy
+ (struct mc_receiver_1side* dst, const struct mc_receiver_1side* src)
+{
+ ASSERT(dst && src);
+ dst->integrated_irradiance = src->integrated_irradiance;
+ dst->absorptivity_loss = src->absorptivity_loss;
+ dst->reflectivity_loss = src->reflectivity_loss;
+ dst->cos_loss = src->cos_loss;
+ return htable_shape2mc_copy(&dst->shape2mc, &src->shape2mc);
+}
+
+static INLINE res_T
+mc_receiver_1side_copy_and_release
+ (struct mc_receiver_1side* dst, struct mc_receiver_1side* src)
+{
+ ASSERT(dst && src);
+ dst->integrated_irradiance = src->integrated_irradiance;
+ dst->absorptivity_loss = src->absorptivity_loss;
+ dst->reflectivity_loss = src->reflectivity_loss;
+ dst->cos_loss = src->cos_loss;
+ return htable_shape2mc_copy_and_release(&dst->shape2mc, &src->shape2mc);
+}
+
+static INLINE res_T
+mc_receiver_1side_get_mc_shape
+ (struct mc_receiver_1side* mc_rcv,
+ const struct ssol_shape* shape,
+ struct mc_shape_1side** out_mc_shape1)
+{
+ struct mc_shape_1side* mc_shape1 = NULL;
+ struct mc_shape_1side mc_shape1_null;
+ res_T res = RES_OK;
+ ASSERT(mc_rcv && shape && out_mc_shape1);
+
+ mc_shape_1side_init(shape->dev->allocator, &mc_shape1_null);
-static const struct mc_per_receiver_data
-MC_RECV_DATA_NULL = MC_RECV_DATA_NULL__;
+ mc_shape1 = htable_shape2mc_find(&mc_rcv->shape2mc, &shape);
+ if(!mc_shape1) {
+ res = htable_shape2mc_set(&mc_rcv->shape2mc, &shape, &mc_shape1_null);
+ if(res != RES_OK) goto error;
+
+ mc_shape1 = htable_shape2mc_find(&mc_rcv->shape2mc, &shape);
+ }
+
+exit:
+ mc_shape_1side_release(&mc_shape1_null);
+ *out_mc_shape1 = mc_shape1;
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Double sided per receiver MC data
+ ******************************************************************************/
+struct mc_receiver {
+ struct mc_receiver_1side front;
+ struct mc_receiver_1side back;
+};
+
+static INLINE void
+mc_receiver_init(struct mem_allocator* allocator, struct mc_receiver* mc)
+{
+ ASSERT(mc);
+ mc_receiver_1side_init(allocator, &mc->front);
+ mc_receiver_1side_init(allocator, &mc->back);
+}
static INLINE void
-init_mc_per_recv_data
- (struct mem_allocator* alloc,
- struct mc_per_receiver_data* data)
+mc_receiver_release(struct mc_receiver* mc)
+{
+ ASSERT(mc);
+ mc_receiver_1side_release(&mc->front);
+ mc_receiver_1side_release(&mc->back);
+}
+
+static INLINE res_T
+mc_receiver_copy(struct mc_receiver* dst, const struct mc_receiver* src)
{
- (void)alloc;
- ASSERT(data);
- *data = MC_RECV_DATA_NULL;
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ res = mc_receiver_1side_copy(&dst->front, &src->front);
+ if(res != RES_OK) return res;
+ res = mc_receiver_1side_copy(&dst->back, &src->back);
+ if(res != RES_OK) return res;
+ return RES_OK;
+}
+
+static INLINE res_T
+mc_receiver_copy_and_release
+ (struct mc_receiver* dst, struct mc_receiver* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ res = mc_receiver_1side_copy_and_release(&dst->front, &src->front);
+ if(res != RES_OK) return res;
+ res = mc_receiver_1side_copy_and_release(&dst->back, &src->back);
+ if(res != RES_OK) return res;
+ return RES_OK;
}
/* Define the htable_receiver data structure */
-struct ssol_instance;
#define HTABLE_NAME receiver
#define HTABLE_KEY const struct ssol_instance*
-#define HTABLE_DATA struct mc_per_receiver_data
-#define HTABLE_FUNCTOR_INIT init_mc_per_recv_data
+#define HTABLE_DATA struct mc_receiver
+#define HTABLE_DATA_FUNCTOR_INIT mc_receiver_init
+#define HTABLE_DATA_FUNCTOR_RELEASE mc_receiver_release
+#define HTABLE_DATA_FUNCTOR_COPY mc_receiver_copy
+#define HTABLE_DATA_FUNCTOR_COPY_AND_RELEASE mc_receiver_copy_and_release
#include <rsys/hash_table.h>
+/*******************************************************************************
+ * Per sampled instance MC data
+ ******************************************************************************/
+struct mc_sampled {
+ /* Global data for this entity */
+ struct mc_data cos_loss;
+ struct mc_data shadowed;
+ double area;
+ double sun_cos;
+ size_t nb_samples;
+
+ /* By-receptor data for this entity */
+ struct htable_receiver mc_rcvs;
+};
+
+static INLINE void
+mc_sampled_init
+ (struct mem_allocator* allocator,
+ struct mc_sampled* samp)
+{
+ ASSERT(samp);
+ samp->cos_loss = MC_DATA_NULL;
+ samp->shadowed = MC_DATA_NULL;
+ samp->area = 0;
+ samp->sun_cos = 0;
+ samp->nb_samples = 0;
+ htable_receiver_init(allocator, &samp->mc_rcvs);
+}
+
+static INLINE void
+mc_sampled_release(struct mc_sampled* samp)
+{
+ ASSERT(samp);
+ htable_receiver_release(&samp->mc_rcvs);
+}
+
+static INLINE res_T
+mc_sampled_copy(struct mc_sampled* dst, const struct mc_sampled* src)
+{
+ ASSERT(dst && src);
+ dst->cos_loss = src->cos_loss;
+ dst->shadowed = src->shadowed;
+ dst->area = src->area;
+ dst->sun_cos = src->sun_cos;
+ dst->nb_samples = src->nb_samples;
+ return htable_receiver_copy(&dst->mc_rcvs, &src->mc_rcvs);
+}
+
+static INLINE res_T
+mc_sampled_copy_and_release(struct mc_sampled* dst, struct mc_sampled* src)
+{
+ ASSERT(dst && src);
+ dst->cos_loss = src->cos_loss;
+ dst->shadowed = src->shadowed;
+ dst->area = src->area;
+ dst->sun_cos = src->sun_cos;
+ dst->nb_samples = src->nb_samples;
+ return htable_receiver_copy_and_release(&dst->mc_rcvs, &src->mc_rcvs);
+}
+
+static INLINE res_T
+mc_sampled_get_mc_receiver_1side
+ (struct mc_sampled* mc_samp,
+ const struct ssol_instance* inst,
+ const enum ssol_side_flag side,
+ struct mc_receiver_1side** out_mc_rcv1)
+{
+ struct mc_receiver* mc_rcv = NULL;
+ struct mc_receiver_1side* mc_rcv1 = NULL;
+ struct mc_receiver mc_rcv_null;
+ res_T res = RES_OK;
+ ASSERT(mc_samp && inst);
+ ASSERT(inst->receiver_mask & (int)side);
+
+ mc_receiver_init(inst->dev->allocator, &mc_rcv_null);
+
+ mc_rcv = htable_receiver_find(&mc_samp->mc_rcvs, &inst);
+ if(!mc_rcv) {
+ res = htable_receiver_set(&mc_samp->mc_rcvs, &inst, &mc_rcv_null);
+ if(res != RES_OK) goto error;
+ mc_rcv = htable_receiver_find(&mc_samp->mc_rcvs, &inst);
+ }
+ mc_rcv1 = side == SSOL_FRONT ? &mc_rcv->front : &mc_rcv->back;
+
+exit:
+ mc_receiver_release(&mc_rcv_null);
+ *out_mc_rcv1 = mc_rcv1;
+ return res;
+error:
+ mc_rcv1 = NULL;
+ goto exit;
+}
+
+/* Define the htable_primary data structure */
+#define HTABLE_NAME sampled
+#define HTABLE_KEY const struct ssol_instance*
+#define HTABLE_DATA struct mc_sampled
+#define HTABLE_DATA_FUNCTOR_INIT mc_sampled_init
+#define HTABLE_DATA_FUNCTOR_RELEASE mc_sampled_release
+#define HTABLE_DATA_FUNCTOR_COPY mc_sampled_copy
+#define HTABLE_DATA_FUNCTOR_COPY_AND_RELEASE mc_sampled_copy_and_release
+#include <rsys/hash_table.h>
+
+/*******************************************************************************
+ * Radiative path
+ ******************************************************************************/
+#define DARRAY_NAME path_vertex
+#define DARRAY_DATA struct ssol_path_vertex
+#include <rsys/dynamic_array.h>
+
+struct path {
+ enum ssol_path_type type;
+ struct darray_path_vertex vertices;
+};
+
+static INLINE void
+path_init(struct mem_allocator* allocator, struct path* path)
+{
+ ASSERT(path);
+ path->type = SSOL_PATH_MISSING;
+ darray_path_vertex_init(allocator, &path->vertices);
+}
+
+static INLINE void
+path_release(struct path* path)
+{
+ ASSERT(path);
+ darray_path_vertex_release(&path->vertices);
+}
+
+static INLINE res_T
+path_copy(struct path* dst, const struct path* src)
+{
+ ASSERT(dst && src);
+ dst->type = src->type;
+ return darray_path_vertex_copy(&dst->vertices, &src->vertices);
+}
+
+static INLINE res_T
+path_copy_and_release(struct path* dst, struct path* src)
+{
+ ASSERT(dst && src);
+ dst->type = src->type;
+ return darray_path_vertex_copy_and_release(&dst->vertices, &src->vertices);
+}
+
+static INLINE res_T
+path_copy_and_clear(struct path* dst, struct path* src)
+{
+ ASSERT(dst && src);
+ dst->type = src->type;
+ return darray_path_vertex_copy_and_clear(&dst->vertices, &src->vertices);
+}
+
+static INLINE res_T
+path_add_vertex(struct path* path, const double pos[3], const double weight)
+{
+ struct ssol_path_vertex vertex;
+ ASSERT(path && pos && weight >= 0);
+ vertex.pos[0] = pos[0];
+ vertex.pos[1] = pos[1];
+ vertex.pos[2] = pos[2];
+ vertex.weight = weight;
+ return darray_path_vertex_push_back(&path->vertices, &vertex);
+}
+
+#define DARRAY_NAME path
+#define DARRAY_DATA struct path
+#define DARRAY_FUNCTOR_INIT path_init
+#define DARRAY_FUNCTOR_RELEASE path_release
+#define DARRAY_FUNCTOR_COPY path_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE path_copy_and_release
+#include <rsys/dynamic_array.h>
+
+/*******************************************************************************
+ * Estimator data structure
+ ******************************************************************************/
struct ssol_estimator {
size_t realisation_count;
size_t failed_count;
- /* the implicit MC computations */
- struct mc_data shadow;
+
+ /* Implicit MC computations */
+ struct mc_data shadowed;
struct mc_data missing;
- /* 1 global MC per receiver */
- struct htable_receiver global_receivers;
- /* areas */
- double sampled_area, primary_area;
+ struct mc_data cos_loss; /* TODO compute it */
+
+ struct htable_receiver mc_receivers; /* Per receiver MC */
+ struct htable_sampled mc_sampled; /* Per sampled instance MC */
+
+ struct darray_path paths; /* Tracked paths */
+
+ /* Overall area of the sampled instances. Actually this is not the area that
+ * is effectively sampled since an instance may be sampled through a proxy
+ * geometry */
+ double sampled_area;
struct ssol_device* dev;
ref_T ref;
@@ -99,18 +479,65 @@ estimator_create
struct ssol_scene* scene,
struct ssol_estimator** estimator);
-static FINLINE struct mc_per_receiver_1side_data*
-estimator_get_receiver_data
+static FINLINE res_T
+get_mc_receiver_1side
(struct htable_receiver* receivers,
- const struct ssol_instance* instance,
- const enum ssol_side_flag side)
+ const struct ssol_instance* inst,
+ const enum ssol_side_flag side,
+ struct mc_receiver_1side** out_mc_rcv1)
+{
+ struct mc_receiver* mc_rcv = NULL;
+ struct mc_receiver_1side* mc_rcv1 = NULL;
+ struct mc_receiver mc_rcv_null;
+ res_T res = RES_OK;
+ ASSERT(receivers && inst && out_mc_rcv1);
+ ASSERT(inst->receiver_mask & (int)side);
+
+ mc_receiver_init(inst->dev->allocator, &mc_rcv_null);
+
+ mc_rcv = htable_receiver_find(receivers, &inst);
+ if(!mc_rcv) {
+ res = htable_receiver_set(receivers, &inst, &mc_rcv_null);
+ if(res != RES_OK) goto error;
+ mc_rcv = htable_receiver_find(receivers, &inst);
+ }
+
+ mc_rcv1 = side == SSOL_FRONT ? &mc_rcv->front : &mc_rcv->back;
+exit:
+ mc_receiver_release(&mc_rcv_null);
+ *out_mc_rcv1 = mc_rcv1;
+ return res;
+error:
+ goto exit;
+}
+
+static FINLINE res_T
+get_mc_sampled
+ (struct htable_sampled* sampled,
+ const struct ssol_instance* inst,
+ struct mc_sampled** out_mc_samp)
{
- struct mc_per_receiver_data* data;
- ASSERT(receivers && instance);
- if(!(instance->receiver_mask & (int)side)) return NULL;
- data = htable_receiver_find(receivers, &instance);
- if(!data) return NULL;
- return side == SSOL_FRONT ? &data->front : &data->back;
+ struct mc_sampled* mc_samp = NULL;
+ struct mc_sampled mc_samp_null;
+ res_T res = RES_OK;
+ ASSERT(sampled && inst && out_mc_samp);
+
+ mc_sampled_init(inst->dev->allocator, &mc_samp_null);
+
+ mc_samp = htable_sampled_find(sampled, &inst);
+ if(!mc_samp) {
+ res = htable_sampled_set(sampled, &inst, &mc_samp_null);
+ if(res != RES_OK) goto error;
+ mc_samp = htable_sampled_find(sampled, &inst);
+ }
+
+exit:
+ mc_sampled_release(&mc_samp_null);
+ *out_mc_samp = mc_samp;
+ return res;
+error:
+ goto exit;
}
#endif /* SSOL_ESTIMATOR_C_H */
+
diff --git a/src/ssol_instance.c b/src/ssol_instance.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_object_c.h"
#include "ssol_shape_c.h"
#include "ssol_instance_c.h"
@@ -84,10 +85,12 @@ ssol_object_instantiate
/* Create the Star-3D instance to ray-trace */
res = s3d_scene_instantiate(object->scn_rt, &instance->shape_rt);
if(res != RES_OK) goto error;
+ instance->shape_rt_area = object->scn_rt_area;
/* Create the Star-3D instance to sample */
res = s3d_scene_instantiate(object->scn_samp, &instance->shape_samp);
if(res != RES_OK) goto error;
+ instance->shape_samp_area = object->scn_samp_area;
exit:
if(out_instance) *out_instance = instance;
@@ -152,10 +155,14 @@ error:
}
res_T
-ssol_instance_set_receiver(struct ssol_instance* instance, const int mask)
+ssol_instance_set_receiver
+ (struct ssol_instance* instance,
+ const int mask,
+ const int per_primitive)
{
if(!instance) return RES_BAD_ARG;
instance->receiver_mask = mask;
+ instance->receiver_per_primitive = per_primitive;
return RES_OK;
}
@@ -181,3 +188,76 @@ ssol_instance_get_id(const struct ssol_instance* instance, uint32_t* id)
return RES_OK;
}
+res_T
+ssol_instance_get_area
+ (const struct ssol_instance* instance,
+ double* area)
+{
+ if (!instance || !area) return RES_BAD_ARG;;
+ /* the area of the 3D surface */
+ *area = instance->shape_rt_area;
+ return RES_OK;
+}
+
+res_T
+ssol_instance_get_shaded_shapes_count
+ (const struct ssol_instance* instance, size_t* count)
+{
+ if(!instance || !count) return RES_BAD_ARG;
+ *count = darray_shaded_shape_size_get(&instance->object->shaded_shapes);
+ return RES_OK;
+}
+
+res_T
+ssol_instance_get_shaded_shape
+ (const struct ssol_instance* instance,
+ const size_t ishape,
+ struct ssol_instantiated_shaded_shape* sshape)
+{
+ const struct shaded_shape* shaded_shape;
+
+ if(!instance || !sshape) return RES_BAD_ARG;
+ if(ishape >= darray_shaded_shape_size_get(&instance->object->shaded_shapes))
+ return RES_BAD_ARG;
+
+ shaded_shape = darray_shaded_shape_cdata_get
+ (&instance->object->shaded_shapes) + ishape;
+ sshape->shape = shaded_shape->shape;
+ sshape->mtl_front = shaded_shape->mtl_front;
+ sshape->mtl_back = shaded_shape->mtl_back;
+
+ d33_set(sshape->R__, instance->transform);
+ d3_set(sshape->T__, instance->transform+9);
+ d33_invtrans(sshape->R_invtrans__, sshape->R__);
+ return RES_OK;
+}
+
+res_T
+ssol_instantiated_shaded_shape_get_vertex_attrib
+ (const struct ssol_instantiated_shaded_shape* sshape,
+ const unsigned ivert,
+ const enum ssol_attrib_usage usage,
+ double value[])
+{
+ res_T res = RES_OK;
+
+ if(!sshape || (unsigned)usage >= SSOL_ATTRIBS_COUNT__ || !value)
+ return RES_BAD_ARG;
+
+ res = shape_fetched_raw_vertex_attrib(sshape->shape, ivert, usage, value);
+ if(res != RES_OK) return res;
+
+ /* Transform the fetched attrib */
+ switch(usage) {
+ case SSOL_NORMAL:
+ d33_muld3(value, sshape->R_invtrans__, value);
+ break;
+ case SSOL_POSITION:
+ d33_muld3(value, sshape->R__, value);
+ d3_add(value, sshape->T__, value);
+ break;
+ default: /* Do nothing */ break;
+ }
+ return RES_OK;
+}
+
diff --git a/src/ssol_instance_c.h b/src/ssol_instance_c.h
@@ -24,8 +24,10 @@ struct ssol_instance {
struct ssol_object* object; /* Instantiated object */
struct s3d_shape* shape_rt; /* Instantiated Star-3D shape to ray-trace */
struct s3d_shape* shape_samp; /* Instantiated Star-3D shape to sample */
+ double shape_rt_area, shape_samp_area;
double transform[12]; /* Column major 4x3 affine transformation */
- int receiver_mask; /* Combination of ssol_face_flag */
+ int receiver_mask; /* Combination of ssol_side_flag */
+ int receiver_per_primitive; /* Enable the per primitive receiver */
int sample; /* Define whether or not the instance should be sampled */
struct fid id; /* Unique identifier */
diff --git a/src/ssol_material.c b/src/ssol_material.c
@@ -34,6 +34,63 @@
* Helper functions
******************************************************************************/
static res_T
+dielectric_shade
+ (const struct ssol_material* mtl,
+ const struct surface_fragment* fragment,
+ const double wavelength, /* In nanometer */
+ const struct ssol_medium* medium,
+ struct ssf_bsdf* bsdf)
+{
+ struct ssf_bxdf* brdf = NULL;
+ struct ssf_bxdf* btdf = NULL;
+ struct ssf_fresnel* fresnel = NULL;
+ const struct ssol_dielectric_shader* shader;
+ double eta_i, eta_t;
+ double N[3];
+ res_T res = RES_OK;
+ ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_DIELECTRIC);
+ ASSERT(medium && bsdf);
+
+ shader = &mtl->data.dielectric;
+
+ /* Fetch material attribs */
+ shader->normal(mtl->dev, mtl->buf, wavelength, fragment->pos, fragment->Ng,
+ fragment->Ns, fragment->uv, fragment->dir, N);
+
+ if(!MEDIA_EQ(medium, &mtl->out_medium)) {
+ log_error(mtl->dev, "Inconsistent medium description.\n");
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ eta_i = mtl->out_medium.refractive_index;
+ eta_t = mtl->in_medium.refractive_index;
+
+ #define CALL(Func) { res = Func; if(res != RES_OK) goto error; } (void)0
+ /* Setup the reflective part */
+ CALL(ssf_fresnel_create
+ (mtl->dev->allocator, &ssf_fresnel_dielectric_dielectric, &fresnel));
+ CALL(ssf_fresnel_dielectric_dielectric_setup(fresnel, eta_i, eta_t));
+ CALL(ssf_bxdf_create(mtl->dev->allocator, &ssf_specular_reflection, &brdf));
+ CALL(ssf_specular_reflection_setup(brdf, fresnel));
+ /* Setup the transmissive part */
+ CALL(ssf_bxdf_create(mtl->dev->allocator, &ssf_specular_transmission, &btdf));
+ CALL(ssf_specular_transmission_setup(btdf, eta_i, eta_t));
+ /* Setup the scattering function */
+ CALL(ssf_bsdf_add(bsdf, brdf, 0.5));
+ CALL(ssf_bsdf_add(bsdf, btdf, 0.5));
+ #undef CALL
+
+exit:
+ if(brdf) SSF(bxdf_ref_put(brdf));
+ if(btdf) SSF(bxdf_ref_put(btdf));
+ if(fresnel) SSF(fresnel_ref_put(fresnel));
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
matte_shade
(const struct ssol_material* mtl,
const struct surface_fragment* fragment,
@@ -45,7 +102,7 @@ matte_shade
double normal[3];
double reflectivity;
res_T res;
- ASSERT(mtl && fragment && mtl->type == MATERIAL_MATTE);
+ ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_MATTE);
ASSERT(bsdf);
shader = &mtl->data.matte;
@@ -78,6 +135,7 @@ mirror_shade
(const struct ssol_material* mtl,
const struct surface_fragment* fragment,
const double wavelength, /* In nanometer */
+ const int rendering,
struct ssf_bsdf* bsdf)
{
struct ssf_bxdf* brdf = NULL;
@@ -88,7 +146,7 @@ mirror_shade
double roughness;
double reflectivity;
res_T res;
- ASSERT(mtl && fragment && mtl->type == MATERIAL_MIRROR);
+ ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_MIRROR);
ASSERT(bsdf);
shader = &mtl->data.mirror;
@@ -120,8 +178,16 @@ mirror_shade
res = ssf_beckmann_distribution_setup(distrib, roughness);
if(res != RES_OK) goto error;
- res = ssf_bxdf_create
- (mtl->dev->allocator, &ssf_microfacet2_reflection, &brdf);
+ /* Microfacet2 is not well suited for rendering since it cannot be
+ * evaluated and consequently it returns an invalid result for direct
+ * lighting. */
+ if(rendering) {
+ res = ssf_bxdf_create
+ (mtl->dev->allocator, &ssf_microfacet_reflection, &brdf);
+ } else {
+ res = ssf_bxdf_create
+ (mtl->dev->allocator, &ssf_microfacet2_reflection, &brdf);
+ }
if(res != RES_OK) goto error;
res = ssf_microfacet_reflection_setup(brdf, fresnel, distrib);
if(res != RES_OK) goto error;
@@ -140,17 +206,90 @@ error:
goto exit;
}
-static void
-material_release(ref_T* ref)
+static res_T
+thin_dielectric_shade
+ (const struct ssol_material* mtl,
+ const struct surface_fragment* fragment,
+ const double wavelength, /* In nanometer */
+ struct ssf_bsdf* bsdf)
{
- struct ssol_device* dev;
- struct ssol_material* material = CONTAINER_OF(ref, struct ssol_material, ref);
- ASSERT(ref);
- dev = material->dev;
- if(material->buf) SSOL(param_buffer_ref_put(material->buf));
- ASSERT(dev && dev->allocator);
- MEM_RM(dev->allocator, material);
- SSOL(device_ref_put(dev));
+ struct ssf_bxdf* bxdf = NULL;
+ const struct ssol_thin_dielectric_shader* shader;
+ double N[3];
+ double thickness;
+ double absorptivity;
+ double eta_i;
+ double eta_t;
+ res_T res = RES_OK;
+ ASSERT(mtl && fragment && mtl->type == SSOL_MATERIAL_THIN_DIELECTRIC);
+ ASSERT(bsdf);
+
+ shader = &mtl->data.thin_dielectric.shader;
+
+ /* Fetch material attribs */
+ shader->normal(mtl->dev, mtl->buf, wavelength, fragment->pos,
+ fragment->Ng, fragment->Ns, fragment->uv, fragment->dir, N);
+ eta_i = mtl->out_medium.refractive_index;
+ eta_t = mtl->data.thin_dielectric.slab_medium.refractive_index;
+ absorptivity = mtl->data.thin_dielectric.slab_medium.absorptivity;
+ thickness = mtl->data.thin_dielectric.thickness;
+
+ /* Setup the BxDF */
+ res = ssf_bxdf_create
+ (mtl->dev->allocator, &ssf_thin_specular_dielectric, &bxdf);
+ if(res != RES_OK) goto error;
+ res = ssf_thin_specular_dielectric_setup
+ (bxdf, absorptivity, eta_i, eta_t, thickness);
+ if(res != RES_OK) goto error;
+
+ /* Setup the BSDF */
+ res = ssf_bsdf_add(bsdf, bxdf, 1.0);
+ if(res != RES_OK) goto error;
+
+exit:
+ if(bxdf) SSF(bxdf_ref_put(bxdf));
+ return res;
+error:
+ goto exit;
+}
+
+static INLINE res_T
+shade
+ (const struct ssol_material* mtl,
+ const struct surface_fragment* fragment,
+ const double wavelength, /* In nanometer */
+ const int rendering, /* Is material used for rendering */
+ const struct ssol_medium* medium,
+ struct ssf_bsdf* bsdf)
+{
+ res_T res = RES_OK;
+ ASSERT(mtl);
+
+ /* Specific material shading */
+ switch(mtl->type) {
+ case SSOL_MATERIAL_DIELECTRIC:
+ res = dielectric_shade
+ (mtl, fragment, wavelength, medium, bsdf);
+ break;
+ case SSOL_MATERIAL_MATTE:
+ res = matte_shade(mtl, fragment, wavelength, bsdf);
+ break;
+ case SSOL_MATERIAL_MIRROR:
+ res = mirror_shade(mtl, fragment, wavelength, rendering, bsdf);
+ break;
+ case SSOL_MATERIAL_THIN_DIELECTRIC:
+ res = thin_dielectric_shade(mtl, fragment, wavelength, bsdf);
+ break;
+ case SSOL_MATERIAL_VIRTUAL: /* Nothing to shade */ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ return res;
+}
+
+static INLINE int
+check_shader_dielectric(const struct ssol_dielectric_shader* shader)
+{
+ return shader && shader->normal;
}
static INLINE int
@@ -170,6 +309,33 @@ check_shader_matte(const struct ssol_matte_shader* shader)
&& shader->reflectivity;
}
+static INLINE int
+check_shader_thin_differential(const struct ssol_thin_dielectric_shader* shader)
+{
+ return shader && shader->normal;
+}
+
+static INLINE int
+check_medium(const struct ssol_medium* medium)
+{
+ return medium
+ && medium->refractive_index > 0
+ && medium->absorptivity >= 0;
+}
+
+static void
+material_release(ref_T* ref)
+{
+ struct ssol_device* dev;
+ struct ssol_material* material = CONTAINER_OF(ref, struct ssol_material, ref);
+ ASSERT(ref);
+ dev = material->dev;
+ if(material->buf) SSOL(param_buffer_ref_put(material->buf));
+ ASSERT(dev && dev->allocator);
+ MEM_RM(dev->allocator, material);
+ SSOL(device_ref_put(dev));
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
@@ -177,13 +343,13 @@ static res_T
ssol_material_create
(struct ssol_device* dev,
struct ssol_material** out_material,
- enum material_type type)
+ enum ssol_material_type type)
{
struct ssol_material* material = NULL;
res_T res = RES_OK;
if(!dev
|| !out_material
- || type >= MATERIAL_TYPES_COUNT__) {
+ || type >= SSOL_MATERIAL_TYPES_COUNT__) {
return RES_BAD_ARG;
}
@@ -198,6 +364,8 @@ ssol_material_create
material->dev = dev;
ref_init(&material->ref);
material->type = type;
+ material->in_medium = SSOL_MEDIUM_VACUUM;
+ material->out_medium = SSOL_MEDIUM_VACUUM;
exit:
if (out_material) *out_material = material;
@@ -218,7 +386,7 @@ ssol_material_ref_get(struct ssol_material* material)
{
if (!material)
return RES_BAD_ARG;
- ASSERT(material->type < MATERIAL_TYPES_COUNT__);
+ ASSERT(material->type < SSOL_MATERIAL_TYPES_COUNT__);
ref_get(&material->ref);
return RES_OK;
}
@@ -228,12 +396,21 @@ ssol_material_ref_put(struct ssol_material* material)
{
if (!material)
return RES_BAD_ARG;
- ASSERT(material->type < MATERIAL_TYPES_COUNT__);
+ ASSERT(material->type < SSOL_MATERIAL_TYPES_COUNT__);
ref_put(&material->ref, material_release);
return RES_OK;
}
res_T
+ssol_material_get_type
+ (const struct ssol_material* mtl, enum ssol_material_type* type)
+{
+ if(!mtl || !type) return RES_BAD_ARG;
+ *type = mtl->type;
+ return RES_OK;
+}
+
+res_T
ssol_material_set_param_buffer
(struct ssol_material* mtl, struct ssol_param_buffer* buf)
{
@@ -244,25 +421,58 @@ ssol_material_set_param_buffer
}
res_T
+ssol_material_create_dielectric
+ (struct ssol_device* dev, struct ssol_material** out_material)
+{
+ return ssol_material_create(dev, out_material, SSOL_MATERIAL_DIELECTRIC);
+}
+
+res_T
ssol_material_create_mirror
(struct ssol_device* dev, struct ssol_material** out_material)
{
- return ssol_material_create(dev, out_material, MATERIAL_MIRROR);
+ return ssol_material_create(dev, out_material, SSOL_MATERIAL_MIRROR);
}
res_T
ssol_material_create_matte
(struct ssol_device* dev, struct ssol_material** out_material)
{
- return ssol_material_create(dev, out_material, MATERIAL_MATTE);
+ return ssol_material_create(dev, out_material, SSOL_MATERIAL_MATTE);
}
res_T
-ssol_mirror_set_shader
+ssol_material_create_thin_dielectric
+ (struct ssol_device* dev, struct ssol_material** out_material)
+{
+ return ssol_material_create(dev, out_material, SSOL_MATERIAL_THIN_DIELECTRIC);
+}
+
+res_T
+ssol_dielectric_setup
+ (struct ssol_material* material,
+ const struct ssol_dielectric_shader* shader,
+ const struct ssol_medium* outside_medium,
+ const struct ssol_medium* inside_medium)
+{
+ if(!material
+ || material->type != SSOL_MATERIAL_DIELECTRIC
+ || !check_shader_dielectric(shader)
+ || !check_medium(outside_medium)
+ || !check_medium(inside_medium))
+ return RES_BAD_ARG;
+ material->data.dielectric = *shader;
+ material->out_medium = *outside_medium;
+ material->in_medium = *inside_medium;
+ return RES_OK;
+}
+
+res_T
+ssol_mirror_setup
(struct ssol_material* material, const struct ssol_mirror_shader* shader)
{
if(!material
- || material->type != MATERIAL_MIRROR
+ || material->type != SSOL_MATERIAL_MIRROR
|| !check_shader_mirror(shader))
return RES_BAD_ARG;
material->data.mirror = *shader;
@@ -270,11 +480,11 @@ ssol_mirror_set_shader
}
res_T
-ssol_matte_set_shader
+ssol_matte_setup
(struct ssol_material* material, const struct ssol_matte_shader* shader)
{
if(!material
- || material->type != MATERIAL_MATTE
+ || material->type != SSOL_MATERIAL_MATTE
|| !check_shader_matte(shader))
return RES_BAD_ARG;
material->data.matte = *shader;
@@ -282,10 +492,33 @@ ssol_matte_set_shader
}
res_T
+ssol_thin_dielectric_setup
+ (struct ssol_material* material,
+ const struct ssol_thin_dielectric_shader* shader,
+ const struct ssol_medium* outside_medium,
+ const struct ssol_medium* slab_medium,
+ const double thickness)
+{
+ if(!material
+ || material->type != SSOL_MATERIAL_THIN_DIELECTRIC
+ || !check_shader_thin_differential(shader)
+ || !check_medium(outside_medium)
+ || !check_medium(slab_medium)
+ || thickness < 0)
+ return RES_BAD_ARG;
+ material->data.thin_dielectric.shader = *shader;
+ material->data.thin_dielectric.slab_medium = *slab_medium;
+ material->data.thin_dielectric.thickness = thickness;
+ material->out_medium = *outside_medium;
+ material->in_medium = *outside_medium;
+ return RES_OK;
+}
+
+res_T
ssol_material_create_virtual
(struct ssol_device* dev, struct ssol_material** out_material)
{
- return ssol_material_create(dev, out_material, MATERIAL_VIRTUAL);
+ return ssol_material_create(dev, out_material, SSOL_MATERIAL_VIRTUAL);
}
/*******************************************************************************
@@ -365,22 +598,47 @@ material_shade
(const struct ssol_material* mtl,
const struct surface_fragment* fragment,
const double wavelength, /* In nanometer */
+ const struct ssol_medium* medium,
struct ssf_bsdf* bsdf)
{
- res_T res = RES_OK;
- ASSERT(mtl);
+ return shade(mtl, fragment, wavelength, 0, medium, bsdf);
+}
- /* Specific material shading */
+res_T
+material_shade_rendering
+ (const struct ssol_material* mtl,
+ const struct surface_fragment* fragment,
+ const double wavelength, /* In nanometer */
+ const struct ssol_medium* medium,
+ struct ssf_bsdf* bsdf)
+{
+ return shade(mtl, fragment, wavelength, 1, medium, bsdf);
+}
+
+res_T
+material_get_next_medium
+ (const struct ssol_material* mtl,
+ const struct ssol_medium* medium,
+ struct ssol_medium* next_medium)
+{
+ ASSERT(mtl && medium && next_medium);
switch(mtl->type) {
- case MATERIAL_MATTE:
- res = matte_shade(mtl, fragment, wavelength, bsdf);
+ /* The material is an interface between 2 media */
+ case SSOL_MATERIAL_DIELECTRIC:
+ if(MEDIA_EQ(&mtl->out_medium, medium)) {
+ *next_medium = mtl->in_medium;
+ } else {
+ *next_medium = mtl->out_medium;
+ }
break;
- case MATERIAL_MIRROR:
- res = mirror_shade(mtl, fragment, wavelength, bsdf);
+ /* The material is not an interface between 2 media */
+ case SSOL_MATERIAL_MATTE:
+ case SSOL_MATERIAL_MIRROR:
+ case SSOL_MATERIAL_THIN_DIELECTRIC:
+ *next_medium = *medium;
break;
- case MATERIAL_VIRTUAL: /* Nothing to shade */ break;
default: FATAL("Unreachable code\n"); break;
}
- return res;
+ return RES_OK;
}
diff --git a/src/ssol_material_c.h b/src/ssol_material_c.h
@@ -23,6 +23,10 @@ struct s3d_primitive;
struct ssf_bsdf;
struct ssol_device;
+#define MEDIA_EQ(A, B) \
+ ( ((A)->refractive_index == (B)->refractive_index) \
+ && ((A)->absorptivity == (B)->absorptivity))
+
struct surface_fragment {
double dir[3]; /* World space incoming direction */
double pos[3]; /* World space position */
@@ -34,21 +38,25 @@ struct surface_fragment {
static const struct surface_fragment SURFACE_FRAGMENT_NULL =
SURFACE_FRAGMENT_NULL__;
-enum material_type {
- MATERIAL_MATTE,
- MATERIAL_MIRROR,
- MATERIAL_VIRTUAL,
- MATERIAL_TYPES_COUNT__
+struct thin_dielectric {
+ struct ssol_thin_dielectric_shader shader;
+ struct ssol_medium slab_medium;
+ double thickness;
};
struct ssol_material {
- enum material_type type;
+ enum ssol_material_type type;
union {
+ struct ssol_dielectric_shader dielectric;
struct ssol_matte_shader matte;
struct ssol_mirror_shader mirror;
+ struct thin_dielectric thin_dielectric;
} data;
+ struct ssol_medium out_medium;
+ struct ssol_medium in_medium;
+
struct ssol_param_buffer* buf;
struct ssol_device* dev;
ref_T ref;
@@ -68,7 +76,22 @@ material_shade
(const struct ssol_material* mtl,
const struct surface_fragment* fragment,
const double wavelength, /* In nanometer */
+ const struct ssol_medium* medium, /* Current medium */
struct ssf_bsdf* bsdf); /* Bidirectional Scattering Distribution Function */
-#endif /* SSOL_MATERIAL_C_H */
+/* Material shading for rendering purposes */
+extern LOCAL_SYM res_T
+material_shade_rendering
+ (const struct ssol_material* mtl,
+ const struct surface_fragment* fragment,
+ const double wavelength, /* In nanometer */
+ const struct ssol_medium* medium,
+ struct ssf_bsdf* bsdf); /* Bidirectional Scattering Distribution Function */
+
+extern LOCAL_SYM res_T
+material_get_next_medium
+ (const struct ssol_material* mtl,
+ const struct ssol_medium* medium, /* Current mediu */
+ struct ssol_medium* next_medium);
+#endif /* SSOL_MATERIAL_C_H */
diff --git a/src/ssol_mc_receiver.c b/src/ssol_mc_receiver.c
@@ -0,0 +1,133 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "ssol.h"
+#include "ssol_estimator_c.h"
+#include "ssol_object_c.h"
+
+#ifdef COMPILER_CL
+ #pragma warning(push)
+ #pragma warning(disable:4706) /* Assignment within a condition */
+#endif
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+ssol_estimator_get_mc_receiver
+ (struct ssol_estimator* estimator,
+ const struct ssol_instance* instance,
+ const enum ssol_side_flag side,
+ struct ssol_mc_receiver* rcv)
+{
+ struct mc_receiver* mc_rcv = NULL;
+ struct mc_receiver_1side* mc_rcv1 = NULL;
+
+ if(!estimator || !instance || !rcv
+ || !(instance->receiver_mask & (int)side))
+ return RES_BAD_ARG;
+
+ memset(rcv, 0, sizeof(rcv[0]));
+
+ mc_rcv = htable_receiver_find(&estimator->mc_receivers, &instance);
+ if(!mc_rcv) {
+ /* The receiver has no MC estimation */
+ return RES_OK;
+ }
+
+ mc_rcv1 = side == SSOL_FRONT ? &mc_rcv->front : &mc_rcv->back;
+ #define SETUP_MC_RESULT(Name) { \
+ const double N = (double)estimator->realisation_count; \
+ const struct mc_data* data = &mc_rcv1->Name; \
+ rcv->Name.E = data->weight / N; \
+ rcv->Name.V = data->sqr_weight/N - rcv->Name.E*rcv->Name.E; \
+ rcv->Name.SE = rcv->Name.V > 0 ? sqrt(rcv->Name.V / N) : 0; \
+ } (void)0
+ SETUP_MC_RESULT(integrated_irradiance);
+ SETUP_MC_RESULT(absorptivity_loss);
+ SETUP_MC_RESULT(reflectivity_loss);
+ SETUP_MC_RESULT(cos_loss);
+ #undef SETUP_MC_RESULT
+ rcv->mc__ = mc_rcv1;
+ rcv->N__ = estimator->realisation_count;
+ rcv->instance__ = instance;
+ return RES_OK;
+}
+
+res_T
+ssol_mc_receiver_get_mc_shape
+ (struct ssol_mc_receiver* rcv,
+ const struct ssol_shape* shape,
+ struct ssol_mc_shape* mc)
+{
+ struct mc_receiver_1side* mc_rcv1;
+
+ if(!rcv || !shape || !mc) return RES_BAD_ARG;
+ if(!object_has_shape(rcv->instance__->object, shape)) return RES_BAD_ARG;
+ mc_rcv1 = rcv->mc__;
+ mc->N__ = rcv->N__;
+ mc->mc__ = htable_shape2mc_find(&mc_rcv1->shape2mc, &shape);
+ mc->shape__ = shape;
+ return RES_OK;
+}
+
+res_T
+ssol_mc_shape_get_mc_primitive
+ (struct ssol_mc_shape* shape,
+ const unsigned i,
+ struct ssol_mc_primitive* prim)
+{
+ struct mc_shape_1side* mc_shape1;
+ struct mc_primitive_1side* mc_prim1;
+ unsigned ntris;
+
+ if(!shape || !prim) return RES_BAD_ARG;
+
+ SSOL(shape_get_triangles_count(shape->shape__, &ntris));
+ if(i >= ntris) return RES_BAD_ARG;
+
+ mc_shape1 = shape->mc__;
+ if(!mc_shape1 || !(mc_prim1 = htable_prim2mc_find(&mc_shape1->prim2mc, &i))) {
+ #define SETUP_MC_RESULT(Name) { \
+ prim->Name.E = 0; \
+ prim->Name.V = 0; \
+ prim->Name.SE = 0; \
+ } (void)0
+ SETUP_MC_RESULT(integrated_irradiance);
+ SETUP_MC_RESULT(absorptivity_loss);
+ SETUP_MC_RESULT(reflectivity_loss);
+ SETUP_MC_RESULT(cos_loss);
+ #undef SETUP_MC_RESULT
+ } else {
+ #define SETUP_MC_RESULT(Name) { \
+ const double N = (double)shape->N__; \
+ const struct mc_data* data = &mc_prim1->Name; \
+ prim->Name.E = data->weight / N; \
+ prim->Name.V = data->sqr_weight/N - prim->Name.E*prim->Name.E; \
+ prim->Name.SE = prim->Name.V > 0 ? sqrt(prim->Name.V / N) : 0; \
+ } (void)0
+ SETUP_MC_RESULT(integrated_irradiance);
+ SETUP_MC_RESULT(absorptivity_loss);
+ SETUP_MC_RESULT(reflectivity_loss);
+ SETUP_MC_RESULT(cos_loss);
+ #undef SETUP_MC_RESULT
+ }
+ return RES_OK;
+}
+
+#ifdef COMPILER_CL
+ #pragma warning(pop)
+#endif
+
diff --git a/src/ssol_object.c b/src/ssol_object.c
@@ -18,6 +18,8 @@
#include "ssol_object_c.h"
#include "ssol_shape_c.h"
+#include <star/s3d.h>
+
#include <rsys/ref_count.h>
#include <rsys/rsys.h>
#include <rsys/mem_allocator.h>
@@ -111,7 +113,7 @@ ssol_object_add_shaded_shape
struct ssol_material* front,
struct ssol_material* back)
{
- enum {
+ enum {
ATTACH_S3D_RT, ATTACH_S3D_SAMP, REGISTER_RT, REGISTER_SAMP, REGISTER_SHAPE
};
struct shaded_shape* shaded_shape;
@@ -137,11 +139,13 @@ ssol_object_add_shaded_shape
res = s3d_scene_attach_shape(object->scn_rt, shape->shape_rt);
if(res != RES_OK) goto error;
mask |= BIT(ATTACH_S3D_RT);
+ object->scn_rt_area += shape->shape_rt_area;
/* Add the shape samp to the sampling scene of the object */
res = s3d_scene_attach_shape(object->scn_samp, shape->shape_samp);
if(res != RES_OK) goto error;
mask |= BIT(ATTACH_S3D_SAMP);
+ object->scn_samp_area += shape->shape_samp_area;
/* Ask for a shaded shape identifier */
i = darray_shaded_shape_size_get(&object->shaded_shapes);
@@ -208,9 +212,32 @@ ssol_object_clear(struct ssol_object* obj)
htable_shaded_shape_clear(&obj->shaded_shapes_rt);
htable_shaded_shape_clear(&obj->shaded_shapes_samp);
+ obj->scn_rt_area = 0;
+
S3D(scene_clear(obj->scn_rt));
S3D(scene_clear(obj->scn_samp));
return RES_OK;
}
+res_T
+ssol_object_get_area(const struct ssol_object* object, double* area)
+{
+ if(!object || !area) return RES_BAD_ARG;;
+ /* the area of the 3D surface */
+ *area = object->scn_rt_area;
+ return RES_OK;
+}
+
+/*******************************************************************************
+ * Local function
+ ******************************************************************************/
+int
+object_has_shape(struct ssol_object* obj, const struct ssol_shape* shape)
+{
+ unsigned id;
+ ASSERT(obj && shape);
+ S3D(shape_get_id(shape->shape_rt, &id));
+ return htable_shaded_shape_find(&obj->shaded_shapes_rt, &id) != NULL;
+}
+
diff --git a/src/ssol_object_c.h b/src/ssol_object_c.h
@@ -47,9 +47,16 @@ struct ssol_object {
struct s3d_scene* scn_rt; /* RT scene to instantiate */
struct s3d_scene* scn_samp; /* Sampling scene to instantiate */
+ double scn_rt_area, scn_samp_area;
struct ssol_device* dev;
ref_T ref;
};
+extern LOCAL_SYM int
+object_has_shape
+ (struct ssol_object* obj,
+ const struct ssol_shape* shape);
+
#endif /* SSOL_OBJECT_C_H */
+
diff --git a/src/ssol_scene.c b/src/ssol_scene.c
@@ -45,7 +45,6 @@ scene_release(ref_T* ref)
SSOL(scene_clear(scene));
if(scene->scn_rt) S3D(scene_ref_put(scene->scn_rt));
if(scene->scn_samp) S3D(scene_ref_put(scene->scn_samp));
- if(scene->scn_prim) S3D(scene_ref_put(scene->scn_prim));
if(scene->sun) SSOL(sun_ref_put(scene->sun));
if(scene->atmosphere) SSOL(atmosphere_ref_put(scene->atmosphere));
htable_instance_release(&scene->instances_rt);
@@ -84,8 +83,6 @@ ssol_scene_create
if(res != RES_OK) goto error;
res = s3d_scene_create(dev->s3d, &scene->scn_samp);
if(res != RES_OK) goto error;
- res = s3d_scene_create(dev->s3d, &scene->scn_prim);
- if(res != RES_OK) goto error;
exit:
if(out_scene) *out_scene = scene;
@@ -118,15 +115,18 @@ res_T
ssol_scene_attach_instance
(struct ssol_scene* scene, struct ssol_instance* instance)
{
+ enum { ATTACH_S3D, SET_INSTANCE_RT };
unsigned id;
struct ssol_instance** pinst;
+ int mask = 0;
res_T res;
if(!scene || !instance) return RES_BAD_ARG;
/* Attach the instantiated s3d shape to ray-trace to the RT scene */
res = s3d_scene_attach_shape(scene->scn_rt, instance->shape_rt);
- if(res != RES_OK) return res;
+ if(res != RES_OK) goto error;
+ mask |= BIT(ATTACH_S3D);
/* Register the instance against the scene */
S3D(shape_get_id(instance->shape_rt, &id));
@@ -134,15 +134,26 @@ ssol_scene_attach_instance
if(pinst) {
/* already attached */
ASSERT(*pinst == instance); /* cannot be attached to another instance! */
- return RES_OK;
+ goto exit;
}
+
res = htable_instance_set(&scene->instances_rt, &id, &instance);
- if(res != RES_OK) {
+ if(res != RES_OK) goto error;
+ mask |= BIT(SET_INSTANCE_RT);
+
+ SSOL(instance_ref_get(instance));
+
+exit:
+ return res;
+error:
+ if(mask & BIT(ATTACH_S3D)) {
S3D(scene_detach_shape(scene->scn_rt, instance->shape_rt));
- return res;
}
- SSOL(instance_ref_get(instance));
- return RES_OK;
+ if(mask & BIT(SET_INSTANCE_RT)) {
+ const size_t n = htable_instance_erase(&scene->instances_rt, &id);
+ ASSERT(n == 1); (void)n;
+ }
+ goto exit;
}
res_T
@@ -177,6 +188,30 @@ ssol_scene_detach_instance
}
res_T
+ssol_scene_compute_aabb
+ (const struct ssol_scene* scene, float lower[3], float upper[3])
+{
+ struct s3d_scene_view* view = NULL;
+ res_T res = RES_OK;
+
+ if(!scene || !lower || !upper) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = s3d_scene_view_create(scene->scn_rt, S3D_GET_PRIMITIVE, &view);
+ if(res != RES_OK) goto error;
+ res = s3d_scene_view_get_aabb(view, lower, upper);
+ if(res != RES_OK) goto error;
+
+exit:
+ if(view) S3D(scene_view_ref_put(view));
+ return res;
+error:
+ goto exit;
+}
+
+res_T
ssol_scene_clear(struct ssol_scene* scene)
{
struct htable_instance_iterator it, it_end;
@@ -195,10 +230,8 @@ ssol_scene_clear(struct ssol_scene* scene)
htable_instance_clear(&scene->instances_samp);
S3D(scene_clear(scene->scn_rt));
S3D(scene_clear(scene->scn_samp));
- S3D(scene_clear(scene->scn_prim));
- if (scene->sun) ssol_scene_detach_sun(scene, scene->sun);
- if (scene->atmosphere)
- ssol_scene_detach_atmosphere(scene, scene->atmosphere);
+ if(scene->sun) SSOL(scene_detach_sun(scene, scene->sun));
+ if(scene->atmosphere) SSOL(scene_detach_atmosphere(scene, scene->atmosphere));
return RES_OK;
}
@@ -208,13 +241,11 @@ ssol_scene_attach_sun(struct ssol_scene* scene, struct ssol_sun* sun)
if(!scene || ! sun)
return RES_BAD_ARG;
if(sun->scene_attachment || scene->sun) {
- /* already attached: must be linked together */
+ /* Already attached: must be linked together */
if(sun->scene_attachment != scene || scene->sun != sun) {
- /* if not detach first! */
- return RES_BAD_ARG;
+ return RES_BAD_ARG; /* If not detach first! */
} else {
- /* nothing to change */
- return RES_OK;
+ return RES_OK; /* Nothing to change */
}
}
/* no previous attachment */
@@ -273,6 +304,36 @@ ssol_scene_detach_atmosphere(struct ssol_scene* scene, struct ssol_atmosphere* a
return RES_OK;
}
+res_T
+ssol_scene_for_each_instance
+ (struct ssol_scene* scn,
+ res_T (*func)(struct ssol_instance* instance, void* ctx),
+ void* ctx)
+{
+ struct htable_instance_iterator it, end;
+ res_T res = RES_OK;
+
+ if(!scn || !func) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ htable_instance_begin(&scn->instances_rt, &it);
+ htable_instance_end(&scn->instances_rt, &end);
+ while(!htable_instance_iterator_eq(&it, &end)) {
+ struct ssol_instance* inst = *htable_instance_iterator_data_get(&it);
+ htable_instance_iterator_next(&it);
+
+ res = func(inst, ctx);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
@@ -281,25 +342,27 @@ scene_create_s3d_views
(struct ssol_scene* scn,
struct s3d_scene_view** out_view_rt,
struct s3d_scene_view** out_view_samp,
- struct s3d_scene_view** out_view_prim)
+ double* out_sampled_area,
+ double* out_sampled_area_proxy)
{
struct htable_instance_iterator it, end;
struct s3d_scene_view* view_rt = NULL;
struct s3d_scene_view* view_samp = NULL;
- struct s3d_scene_view* view_prim = NULL;
+ double sampled_area = 0;
+ double sampled_area_proxy = 0;
int has_sampled = 0;
int has_receiver = 0;
res_T res = RES_OK;
ASSERT(scn && out_view_rt && out_view_samp);
+ ASSERT(out_sampled_area && out_sampled_area_proxy);
S3D(scene_clear(scn->scn_samp));
- S3D(scene_clear(scn->scn_prim));
htable_instance_clear(&scn->instances_samp);
htable_instance_begin(&scn->instances_rt, &it);
htable_instance_end(&scn->instances_rt, &end);
- while (!htable_instance_iterator_eq(&it, &end)) {
+ while(!htable_instance_iterator_eq(&it, &end)) {
struct ssol_instance* inst = *htable_instance_iterator_data_get(&it);
unsigned id;
htable_instance_iterator_next(&it);
@@ -310,6 +373,9 @@ scene_create_s3d_views
if(!inst->sample) continue;
+ sampled_area += inst->shape_rt_area;
+ sampled_area_proxy += inst->shape_samp_area;
+
/* Note that geometries with virtual material can be sampled without risk
* since the solver avoid to shade them and simply pursue the primary ray */
has_sampled = 1;
@@ -318,10 +384,6 @@ scene_create_s3d_views
res = s3d_scene_attach_shape(scn->scn_samp, inst->shape_samp);
if(res != RES_OK) goto error;
- /* Attach the instantiated s3d raytraced shape to the s3d primary scene */
- res = s3d_scene_attach_shape(scn->scn_prim, inst->shape_rt);
- if(res != RES_OK) goto error;
-
/* Register the instantiated s3d sampling shape */
S3D(shape_get_id(inst->shape_samp, &id));
ASSERT(!htable_instance_find(&scn->instances_samp, &id));
@@ -346,13 +408,12 @@ scene_create_s3d_views
if(res != RES_OK) goto error;
res = s3d_scene_view_create(scn->scn_samp, S3D_SAMPLE, &view_samp);
if(res != RES_OK) goto error;
- res = s3d_scene_view_create(scn->scn_prim, S3D_SAMPLE, &view_prim);
- if (res != RES_OK) goto error;
exit:
*out_view_rt = view_rt;
*out_view_samp = view_samp;
- *out_view_prim = view_prim;
+ *out_sampled_area = sampled_area;
+ *out_sampled_area_proxy = sampled_area_proxy;
return res;
error:
S3D(scene_clear(scn->scn_samp));
@@ -365,10 +426,6 @@ error:
S3D(scene_view_ref_put(view_samp));
view_samp = NULL;
}
- if (view_prim) {
- S3D(scene_view_ref_put(view_prim));
- view_prim = NULL;
- }
goto exit;
}
@@ -378,7 +435,7 @@ error:
int
hit_filter_function
(const struct s3d_hit* hit,
- const float posf[3],
+ const float orgf[3],
const float dirf[3],
void* ray_data,
void* filter_data)
@@ -388,10 +445,10 @@ hit_filter_function
struct ray_data* rdata = ray_data;
const struct shaded_shape* sshape;
enum ssol_side_flag hit_side = SSOL_INVALID_SIDE;
- double pos[3], dir[3], N[3], dst = FLT_MAX;
+ double org[3], dir[3], N[3], dst = FLT_MAX;
size_t id;
(void)filter_data;
- ASSERT(hit && posf && dirf);
+ ASSERT(hit && orgf && dirf);
/* No ray data => nothing to filter */
if(!ray_data) return 0;
@@ -420,23 +477,23 @@ hit_filter_function
case SHAPE_PUNCHED:
/* Project the hit position into the punched shape */
d3_set_f3(dir, dirf);
- d3_set_f3(pos, posf);
- dst = punched_shape_trace_ray(sshape->shape, inst->transform, pos, dir,
- hit->distance, pos, N);
+ d3_set_f3(org, orgf);
+ dst = punched_shape_trace_ray(sshape->shape, inst->transform, org, dir,
+ hit->distance, N);
if(dst >= FLT_MAX) {
/* No projection is found => the ray does not intersect the quadric */
return 1;
}
if((float)dst <= rdata->range_min) {
/* Handle RT numerical imprecision, the hit is below the lower bound
- * of the ray range. */
+ * of the ray range. */
return 1;
}
hit_side = d3_dot(dir, N) < 0 ? SSOL_FRONT : SSOL_BACK;
if(inst == rdata->inst_from && hit_side != rdata->side_from) {
/* The intersected instance is the one from which the ray starts,
* ensure that the ray does not intersect the opposite side of the
- * quadric
+ * quadric
*
* Note that reversed_ray is intentionally not considered here! */
return 1;
@@ -449,7 +506,7 @@ hit_filter_function
hit_side = (hit_side == SSOL_FRONT) ? SSOL_BACK : SSOL_FRONT;
}
mtl = hit_side == SSOL_FRONT ? sshape->mtl_front : sshape->mtl_back;
- if(mtl->type == MATERIAL_VIRTUAL) {
+ if(mtl->type == SSOL_MATERIAL_VIRTUAL) {
/* Discard all virtual materials */
if(rdata->discard_virtual_materials) return 1;
/* Discard virtual material that are not receivers */
diff --git a/src/ssol_scene_c.h b/src/ssol_scene_c.h
@@ -22,7 +22,7 @@
struct ssol_instance;
- /* Define the htable_instance data structure */
+/* Define the htable_instance data structure */
#define HTABLE_NAME instance
#define HTABLE_KEY unsigned /* S3D object instance identifier */
#define HTABLE_DATA struct ssol_instance*
@@ -42,7 +42,6 @@ struct ssol_scene {
struct s3d_scene* scn_rt; /* S3D scene to ray trace */
struct s3d_scene* scn_samp; /* S3D scene to sample */
- struct s3d_scene* scn_prim; /* S3D scene of primary objects */
struct ssol_sun* sun; /* Sun of the scene */
struct ssol_atmosphere* atmosphere; /* Atmosphere of the scene */
@@ -58,7 +57,8 @@ scene_create_s3d_views
(struct ssol_scene* scn,
struct s3d_scene_view** view_rt,
struct s3d_scene_view** view_samp,
- struct s3d_scene_view** out_view_prim);
+ double* sampled_area, /* Area of the instance set as "samplable" */
+ double* sampled_area_proxy); /* Area of the sampled geometries */
#endif /* SSOL_SCENE_C_H */
diff --git a/src/ssol_shape.c b/src/ssol_shape.c
@@ -44,7 +44,7 @@ struct mesh_context {
struct quadric_mesh_context {
const double* coords;
const size_t* ids;
- double focal; /* Use by parabol and parabolic cylinder quadrics */
+ const union priv_quadric_data* quadric;
const double* transform; /* 3x4 column major matrix */
};
@@ -64,6 +64,12 @@ check_parabol(const struct ssol_quadric_parabol* parabol)
}
static INLINE int
+check_hyperbol(const struct ssol_quadric_hyperbol* hyperbol)
+{
+ return hyperbol && hyperbol->img_focal > 0 && hyperbol->real_focal > 0;
+}
+
+static INLINE int
check_parabolic_cylinder
(const struct ssol_quadric_parabolic_cylinder* parabolic_cylinder)
{
@@ -80,6 +86,8 @@ check_quadric(const struct ssol_quadric* quadric)
return check_plane(&quadric->data.plane);
case SSOL_QUADRIC_PARABOL:
return check_parabol(&quadric->data.parabol);
+ case SSOL_QUADRIC_HYPERBOL:
+ return check_hyperbol(&quadric->data.hyperbol);
case SSOL_QUADRIC_PARABOLIC_CYLINDER:
return check_parabolic_cylinder(&quadric->data.parabolic_cylinder);
default: return 0;
@@ -183,6 +191,33 @@ quadric_mesh_plane_get_pos(const unsigned ivert, float pos[3], void* ctx)
f3_set_d3(pos, p);
}
+static FINLINE double
+hyperbol_z
+ (const double p[2],
+ const struct priv_hyperbol_data* hyperbol)
+{
+ const double z0 = hyperbol->g_2 + hyperbol->abs_b;
+ const double r2 = p[0] * p[0] + p[1] * p[1];
+ return hyperbol->abs_b * sqrt(1 + r2 * hyperbol->_1_a2) + hyperbol->g_2 - z0;
+}
+
+static FINLINE double
+parabol_z
+ (const double p[2],
+ const struct priv_parabol_data* parabol)
+{
+ const double r2 = p[0] * p[0] + p[1] * p[1];
+ return r2 * parabol->_1_4f;
+}
+
+static FINLINE double
+parabolic_cylinder_z
+ (const double p[2],
+ const struct priv_pcylinder_data* pcyl)
+{
+ return (p[1] * p[1]) * pcyl->_1_4f;
+}
+
static void
quadric_mesh_parabol_get_pos(const unsigned ivert, float pos[3], void* ctx)
{
@@ -192,7 +227,25 @@ quadric_mesh_parabol_get_pos(const unsigned ivert, float pos[3], void* ctx)
ASSERT(pos && ctx);
p[0] = msh->coords[i+0];
p[1] = msh->coords[i+1];
- p[2] = (p[0]*p[0] + p[1]*p[1]) / (4.0*msh->focal);
+ p[2] = parabol_z(p, &msh->quadric->parabol);
+
+ /* Transform the position in object space */
+ d33_muld3(p, msh->transform, p);
+ d3_add(p, p, msh->transform+9);
+
+ f3_set_d3(pos, p);
+}
+
+static void
+quadric_mesh_hyperbol_get_pos(const unsigned ivert, float pos[3], void* ctx)
+{
+ const size_t i = ivert * 2/*#coords per vertex*/;
+ const struct quadric_mesh_context* msh = ctx;
+ double p[3]; /* Temporary quadric space position */
+ ASSERT(pos && ctx);
+ p[0] = msh->coords[i+0];
+ p[1] = msh->coords[i+1];
+ p[2] = hyperbol_z(p, &msh->quadric->hyperbol);
/* Transform the position in object space */
d33_muld3(p, msh->transform, p);
@@ -211,7 +264,7 @@ quadric_mesh_parabolic_cylinder_get_pos
ASSERT(pos && ctx);
p[0] = msh->coords[i+0];
p[1] = msh->coords[i+1];
- p[2] = ((p[1]*p[1]) / (4.0*msh->focal));
+ p[2] = parabolic_cylinder_z(p, &msh->quadric->pcylinder);
/* Transform the position in object space */
d33_muld3(p, msh->transform, p);
@@ -415,21 +468,60 @@ error:
goto exit;
}
+static double
+mesh_compute_area
+ (const unsigned ntris,
+ void (*get_indices)(const unsigned itri, unsigned ids[3], void* data),
+ const unsigned nverts,
+ void (*get_position)(const unsigned ivert, float position[3], void* data),
+ void* ctx)
+{
+ unsigned itri;
+ double area = 0;
+ (void)nverts;
+
+ FOR_EACH(itri, 0, ntris) {
+ float v0[3], v1[3], v2[3];
+ double E0[3], E1[3], N[3];
+ double V0[3], V1[3], V2[3];
+ unsigned IDS[3];
+
+ get_indices(itri, IDS, ctx);
+ ASSERT(IDS[0] < nverts);
+ ASSERT(IDS[1] < nverts);
+ ASSERT(IDS[2] < nverts);
+
+ get_position(IDS[0], v0, ctx);
+ get_position(IDS[1], v1, ctx);
+ get_position(IDS[2], v2, ctx);
+ d3_set_f3(V0, v0);
+ d3_set_f3(V1, v1);
+ d3_set_f3(V2, v2);
+ d3_sub(E0, V1, V0);
+ d3_sub(E1, V2, V0);
+
+ area += d3_len(d3_cross(N, E0, E1));
+ }
+ return area * 0.5;
+}
+
/* Setup the Star-3D shape of the quadric to ray-trace, i.e. the clipped 2D
* profile of the quadric whose vertices are displaced with respect to the
* quadric equation */
static res_T
quadric_setup_s3d_shape_rt
- (const struct ssol_quadric* quadric,
+ (const struct ssol_shape* shape,
const struct darray_double* coords,
const struct darray_size_t* ids,
- struct s3d_shape* shape)
+ struct s3d_shape* s3dshape,
+ double* rt_area)
{
struct quadric_mesh_context ctx;
struct s3d_vertex_data vdata;
unsigned nverts;
unsigned ntris;
- ASSERT(quadric && coords && ids && shape);
+ res_T res;
+ ASSERT(shape && coords && ids && s3dshape && rt_area);
ASSERT(darray_double_size_get(coords)%2 == 0);
ASSERT(darray_size_t_size_get(ids)%3 == 0);
ASSERT(darray_double_size_get(coords)/2 <= UINT_MAX);
@@ -439,17 +531,20 @@ quadric_setup_s3d_shape_rt
ntris = (unsigned)darray_size_t_size_get(ids) / 3/*#ids per triangle*/;
ctx.coords = darray_double_cdata_get(coords);
ctx.ids = darray_size_t_cdata_get(ids);
- ctx.transform = quadric->transform;
+ ctx.transform = shape->quadric.transform;
vdata.usage = S3D_POSITION;
vdata.type = S3D_FLOAT3;
- switch(quadric->type) {
+ vdata.get = NULL;
+ ctx.quadric = &shape->priv_quadric;
+ switch (shape->quadric.type) {
case SSOL_QUADRIC_PARABOL:
- ctx.focal = quadric->data.parabol.focal;
vdata.get = quadric_mesh_parabol_get_pos;
break;
+ case SSOL_QUADRIC_HYPERBOL:
+ vdata.get = quadric_mesh_hyperbol_get_pos;
+ break;
case SSOL_QUADRIC_PARABOLIC_CYLINDER:
- ctx.focal = quadric->data.parabolic_cylinder.focal;
vdata.get = quadric_mesh_parabolic_cylinder_get_pos;
break;
case SSOL_QUADRIC_PLANE:
@@ -458,8 +553,14 @@ quadric_setup_s3d_shape_rt
default: FATAL("Unreachable code.\n"); break;
}
- return s3d_mesh_setup_indexed_vertices
- (shape, ntris, quadric_mesh_get_ids, nverts, &vdata, 1, &ctx);
+ res = s3d_mesh_setup_indexed_vertices
+ (s3dshape, ntris, quadric_mesh_get_ids, nverts, &vdata, 1, &ctx);
+ if(res != RES_OK) return res;
+
+ ASSERT(vdata.get);
+ *rt_area = mesh_compute_area
+ (ntris, quadric_mesh_get_ids, nverts, vdata.get, &ctx);
+ return RES_OK;
}
/* Setup the Star-3D shape of the quadric to sample, i.e. the clipped 2D
@@ -469,12 +570,14 @@ quadric_setup_s3d_shape_samp
(const struct ssol_quadric* quadric,
const struct darray_double* coords,
const struct darray_size_t* ids,
- struct s3d_shape* shape)
+ struct s3d_shape* shape,
+ double *samp_area)
{
struct quadric_mesh_context ctx;
struct s3d_vertex_data vdata;
unsigned nverts;
unsigned ntris;
+ res_T res;
ASSERT(coords && ids && shape);
ASSERT(darray_double_size_get(coords)%2 == 0);
ASSERT(darray_size_t_size_get(ids)%3 == 0);
@@ -490,8 +593,12 @@ quadric_setup_s3d_shape_samp
vdata.usage = S3D_POSITION;
vdata.type = S3D_FLOAT3;
vdata.get = quadric_mesh_plane_get_pos;
- return s3d_mesh_setup_indexed_vertices
+ res = s3d_mesh_setup_indexed_vertices
(shape, ntris, quadric_mesh_get_ids, nverts, &vdata, 1, &ctx);
+ if(res != RES_OK) return res;
+ *samp_area = mesh_compute_area
+ (ntris, quadric_mesh_get_ids, nverts, quadric_mesh_plane_get_pos, &ctx);
+ return RES_OK;
}
static res_T
@@ -584,30 +691,41 @@ quadric_plane_gradient_local(double grad[3])
static FINLINE void
quadric_parabol_gradient_local
- (const struct ssol_quadric_parabol* quad,
+ (const struct priv_parabol_data* quad,
const double pt[3],
double grad[3])
{
- double tmp[3];
ASSERT(quad && pt && grad);
- tmp[0] = -pt[0];
- tmp[1] = -pt[1];
- tmp[2] = 2 * quad->focal;
- d3_set(grad, tmp);
+ grad[0] = -pt[0];
+ grad[1] = -pt[1];
+ grad[2] = 2 * quad->focal;
+}
+
+static FINLINE void
+quadric_hyperbol_gradient_local
+ (const struct priv_hyperbol_data* quad,
+ const double pt[3],
+ double grad[3])
+{
+ ASSERT(quad && pt && grad);
+ {
+ const double z0 = quad->g_2 + quad->abs_b;
+ grad[0] = pt[0];
+ grad[1] = pt[1];
+ grad[2] = -(pt[2] + z0 - quad->g_2) * quad->_a2_b2;
+ }
}
static FINLINE void
quadric_parabolic_cylinder_gradient_local
- (const struct ssol_quadric_parabolic_cylinder* quad,
+ (const struct priv_pcylinder_data* quad,
const double pt[3],
double grad[3])
{
- double tmp[3];
ASSERT(quad && pt && grad);
- tmp[0] = 0;
- tmp[1] = -pt[1];
- tmp[2] = 2 * quad->focal;
- d3_set(grad, tmp);
+ grad[0] = 0;
+ grad[1] = -pt[1];
+ grad[2] = 2 * quad->focal;
}
static FINLINE int
@@ -615,7 +733,7 @@ quadric_plane_intersect_local
(const double org[3],
const double dir[3],
const double hint,
- double pt[3],
+ double hit_pt[3],
double grad[3],
double* dist)
{
@@ -623,14 +741,11 @@ quadric_plane_intersect_local
const double a = 0;
const double b = dir[2];
const double c = org[2];
- double tmp[3];
double dst;
int sol = quadric_solve_second(a, b, c, hint, &dst);
if(!sol) return 0;
- d3_add(tmp, org, d3_muld(tmp, dir, dst));
-
- d3_set(pt, tmp);
+ d3_add(hit_pt, org, d3_muld(hit_pt, dir, dst));
quadric_plane_gradient_local(grad);
*dist = dst;
return 1;
@@ -638,11 +753,11 @@ quadric_plane_intersect_local
static FINLINE int
quadric_parabol_intersect_local
- (const struct ssol_quadric_parabol* quad,
+ (const struct priv_parabol_data* quad,
const double org[3],
const double dir[3],
const double hint,
- double pt[3],
+ double hit_pt[3],
double grad[3],
double* dist) /* in/out: */
{
@@ -653,23 +768,50 @@ quadric_parabol_intersect_local
2 * org[0] * dir[0] + 2 * org[1] * dir[1] - 4 * quad->focal * dir[2];
const double c = org[0] * org[0] + org[1] * org[1] - 4 * quad->focal * org[2];
const int sol = quadric_solve_second(a, b, c, hint, &dst);
- double tmp[3];
if(!sol) return 0;
- d3_add(tmp, org, d3_muld(tmp, dir, dst));
- quadric_parabol_gradient_local(quad, tmp, grad);
- d3_set(pt, tmp);
+ d3_add(hit_pt, org, d3_muld(hit_pt, dir, dst));
+ quadric_parabol_gradient_local(quad, hit_pt, grad);
+ *dist = dst;
+ return 1;
+}
+
+static FINLINE int
+quadric_hyperbol_intersect_local
+ (const struct priv_hyperbol_data* quad,
+ const double org[3],
+ const double dir[3],
+ const double hint,
+ double hit_pt[3],
+ double grad[3],
+ double* dist)
+{
+ double dst;
+ const double b2 = quad->abs_b * quad->abs_b;
+ const double b2_a2 = b2 * quad->_1_a2;
+ const double z0 = quad->g_2 + quad->abs_b;
+ const double a =
+ b2_a2 * (dir[0] * dir[0] + dir[1] * dir[1]) - dir[2] * dir[2];
+ const double b =
+ 2 * (b2_a2 * (org[0] * dir[0] + org[1] * dir[1]) - (org[2] + z0 - quad->g_2) * dir[2]);
+ const double c = b2_a2 * (org[0] * org[0] + org[1] * org[1]) + b2
+ - (org[2] + z0 - quad->g_2) * (org[2] + z0 - quad->g_2);
+ const int sol = quadric_solve_second(a, b, c, hint, &dst);
+
+ if(!sol) return 0;
+ d3_add(hit_pt, org, d3_muld(hit_pt, dir, dst));
+ quadric_hyperbol_gradient_local(quad, hit_pt, grad);
*dist = dst;
return 1;
}
static FINLINE int
quadric_parabolic_cylinder_intersect_local
- (const struct ssol_quadric_parabolic_cylinder* quad,
+ (const struct priv_pcylinder_data* quad,
const double org[3],
const double dir[3],
const double hint,
- double pt[3],
+ double hit_pt[3],
double grad[3],
double* dist)
{
@@ -678,9 +820,10 @@ quadric_parabolic_cylinder_intersect_local
const double b = 2 * org[1] * dir[1] - 4 * quad->focal * dir[2];
const double c = org[1] * org[1] - 4 * quad->focal * org[2];
const int sol = quadric_solve_second(a, b, c, hint, dist);
+
if(!sol) return 0;
- d3_add(pt, org, d3_muld(pt, dir, *dist));
- quadric_parabolic_cylinder_gradient_local(quad, pt, grad);
+ d3_add(hit_pt, org, d3_muld(hit_pt, dir, *dist));
+ quadric_parabolic_cylinder_gradient_local(quad, hit_pt, grad);
return 1;
}
@@ -690,21 +833,18 @@ punched_shape_set_z_local(const struct ssol_shape* shape, double pt[3])
ASSERT(shape && pt);
ASSERT(shape->type == SHAPE_PUNCHED);
switch (shape->quadric.type) {
- case SSOL_QUADRIC_PLANE: {
+ case SSOL_QUADRIC_PLANE:
pt[2] = 0;
break;
- }
- case SSOL_QUADRIC_PARABOLIC_CYLINDER: {
- const struct ssol_quadric_parabolic_cylinder* quad
- = &shape->quadric.data.parabolic_cylinder;
- pt[2] = (pt[1] * pt[1]) / (4.0 * quad->focal);
+ case SSOL_QUADRIC_PARABOLIC_CYLINDER:
+ pt[2] = parabolic_cylinder_z(pt, &shape->priv_quadric.pcylinder);
break;
- }
- case SSOL_QUADRIC_PARABOL: {
- const struct ssol_quadric_parabol* quad = &shape->quadric.data.parabol;
- pt[2] = (pt[0] * pt[0] + pt[1] * pt[1]) / (4.0 * quad->focal);
+ case SSOL_QUADRIC_PARABOL:
+ pt[2] = parabol_z(pt, &shape->priv_quadric.parabol);
+ break;
+ case SSOL_QUADRIC_HYPERBOL:
+ pt[2] = hyperbol_z(pt, &shape->priv_quadric.hyperbol);
break;
- }
default: FATAL("Unreachable code\n"); break;
}
}
@@ -723,11 +863,15 @@ punched_shape_set_normal_local
break;
case SSOL_QUADRIC_PARABOLIC_CYLINDER:
quadric_parabolic_cylinder_gradient_local
- (&shape->quadric.data.parabolic_cylinder, pt, normal);
+ (&shape->priv_quadric.pcylinder, pt, normal);
break;
case SSOL_QUADRIC_PARABOL: {
quadric_parabol_gradient_local
- (&shape->quadric.data.parabol, pt, normal);
+ (&shape->priv_quadric.parabol, pt, normal);
+ break;
+ case SSOL_QUADRIC_HYPERBOL:
+ quadric_hyperbol_gradient_local
+ (&shape->priv_quadric.hyperbol, pt, normal);
break;
}
default: FATAL("Unreachable code\n"); break;
@@ -756,11 +900,15 @@ punched_shape_intersect_local
break;
case SSOL_QUADRIC_PARABOLIC_CYLINDER:
hit = quadric_parabolic_cylinder_intersect_local
- (&shape->quadric.data.parabolic_cylinder, org, dir, hint, pt, N, dist);
+ (&shape->priv_quadric.pcylinder, org, dir, hint, pt, N, dist);
break;
case SSOL_QUADRIC_PARABOL:
hit = quadric_parabol_intersect_local
- (&shape->quadric.data.parabol, org, dir, hint, pt, N, dist);
+ (&shape->priv_quadric.parabol, org, dir, hint, pt, N, dist);
+ break;
+ case SSOL_QUADRIC_HYPERBOL:
+ hit = quadric_hyperbol_intersect_local
+ (&shape->priv_quadric.hyperbol, org, dir, hint, pt, N, dist);
break;
default: FATAL("Unreachable code\n"); break;
}
@@ -781,6 +929,106 @@ shape_release(ref_T* ref)
SSOL(device_ref_put(dev));
}
+/* Return the parabol discretisation parameter */
+static FINLINE void
+priv_parabol_data_setup
+ (struct priv_parabol_data* data,
+ const struct ssol_quadric_parabol* parabol)
+{
+ ASSERT(data && parabol);
+ data->focal = parabol->focal;
+ data->_1_4f = 1 / (4.0 * parabol->focal);
+}
+
+static FINLINE void
+priv_hyperbol_data_setup
+ (struct priv_hyperbol_data* data,
+ const struct ssol_quadric_hyperbol* hyperbol)
+{
+ double g, f, a2;
+ ASSERT(data && hyperbol);
+
+ /* Re-dimensionalize */
+ g = hyperbol->real_focal + hyperbol->img_focal;
+ f = hyperbol->real_focal / g;
+ a2 = g * g * (f - f * f);
+
+ data->g_2 = g * 0.5;
+ data->abs_b = g * fabs(f - 0.5);
+ data->_a2_b2 = a2 / (data->abs_b * data->abs_b);
+ data->_1_a2 = 1 / a2;
+}
+
+static FINLINE void
+priv_parabolic_cylinder_data_setup
+ (struct priv_pcylinder_data* data,
+ const struct ssol_quadric_parabolic_cylinder* parabolic_cylinder)
+{
+ ASSERT(data && parabolic_cylinder);
+ data->focal = parabolic_cylinder->focal;
+ data->_1_4f = 1 / (4.0 * parabolic_cylinder->focal);
+}
+
+static INLINE void
+priv_quadric_data_setup
+ (union priv_quadric_data* priv_data,
+ const struct ssol_quadric* quadric)
+{
+ ASSERT(priv_data && quadric);
+ switch(quadric->type) {
+ case SSOL_QUADRIC_PLANE: /* Do nothing */ break;
+ case SSOL_QUADRIC_PARABOL:
+ priv_parabol_data_setup
+ (&priv_data->parabol, &quadric->data.parabol);
+ break;
+ case SSOL_QUADRIC_HYPERBOL:
+ priv_hyperbol_data_setup
+ (&priv_data->hyperbol, &quadric->data.hyperbol);
+ break;
+ case SSOL_QUADRIC_PARABOLIC_CYLINDER:
+ priv_parabolic_cylinder_data_setup
+ (&priv_data->pcylinder, &quadric->data.parabolic_cylinder);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+}
+
+static INLINE size_t
+priv_quadric_data_compute_slices_count
+ (const enum ssol_quadric_type type,
+ const union priv_quadric_data* priv_data,
+ const double lower[3],
+ const double upper[3])
+{
+ size_t nslices;
+ double max_z;
+ ASSERT(priv_data && lower && upper);
+
+ switch(type) {
+ case SSOL_QUADRIC_PLANE: nslices = 1; break;
+ case SSOL_QUADRIC_PARABOL:
+ max_z = MMAX
+ (parabol_z(lower, &priv_data->parabol),
+ parabol_z(upper, &priv_data->parabol));
+ nslices = MMIN(50, (size_t)(3 + sqrt(max_z) * 6));
+ break;
+ case SSOL_QUADRIC_HYPERBOL:
+ max_z = MMAX
+ (hyperbol_z(lower, &priv_data->hyperbol),
+ hyperbol_z(upper, &priv_data->hyperbol));
+ nslices = MMIN(50, (size_t)(3 + sqrt(max_z) * 6));
+ break;
+ case SSOL_QUADRIC_PARABOLIC_CYLINDER:
+ max_z = MMAX
+ (parabolic_cylinder_z(lower, &priv_data->pcylinder),
+ parabolic_cylinder_z(upper, &priv_data->pcylinder));
+ nslices = MMIN(50, (size_t)(3 + sqrt(max_z) * 6));
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ return nslices;
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
@@ -829,10 +1077,9 @@ double
punched_shape_trace_ray
(struct ssol_shape* shape,
const double transform[12], /* Shape to world space transformation */
- const double pos[3], /* World space position near of the quadric */
- const double dir[3], /* World space projection direction */
+ const double org[3], /* World space position near of the ray origin */
+ const double dir[3], /* World space ray direction */
const double hint_dst, /* Hint on the hit distance */
- double pos_quadric[3], /* World space position onto the quadric */
double N_quadric[3]) /* World space normal onto the quadric */
{
double R[9]; /* Quadric to world rotation matrix */
@@ -840,11 +1087,12 @@ punched_shape_trace_ray
double T[3]; /* Quadric to world translation vector */
double T_inv[3]; /* Inverse of T */
double dir_local[3];
- double pos_local[3];
+ double org_local[3];
+ double hit_local[3];
double N_local[3];
double dst; /* Hit distance */
int valid;
- ASSERT(shape && transform && pos && pos_quadric && N_quadric);
+ ASSERT(shape && transform && org && N_quadric);
ASSERT(shape->type == SHAPE_PUNCHED);
/* Compute world<->quadric space transformations */
@@ -855,27 +1103,52 @@ punched_shape_trace_ray
d3_minus(T_inv, T);
/* Transform pos in quadric space */
- d3_add(pos_local, pos, T_inv);
- d3_muld33(pos_local, pos_local, R_invtrans);
+ d3_add(org_local, org, T_inv);
+ d3_muld33(org_local, org_local, R_invtrans);
/* Transform dir in quadric space */
d3_muld33(dir_local, dir, R_invtrans);
/* Project pos_local onto the quadric and compute its associated normal */
valid = punched_shape_intersect_local
- (shape, pos_local, dir_local, hint_dst, pos_local, N_local, &dst);
+ (shape, org_local, dir_local, hint_dst, hit_local, N_local, &dst);
if(!valid) return INF;
- /* Transform the local position in world space */
- d33_muld3(pos_quadric, R, pos_local);
- d3_add(pos_quadric, pos_quadric, T);
-
/* Transform the quadric normal in world space */
d33_muld3(N_quadric, R_invtrans, N_local);
d3_normalize(N_quadric, N_quadric);
return dst;
}
+res_T
+shape_fetched_raw_vertex_attrib
+ (const struct ssol_shape* shape,
+ const unsigned ivert,
+ const enum ssol_attrib_usage usage,
+ double value[3])
+{
+ struct s3d_attrib s3d_attr;
+ enum s3d_attrib_usage s3d_usage;
+ res_T res = RES_OK;
+
+ ASSERT(shape && value);
+ s3d_usage = ssol_to_s3d_attrib_usage(usage);
+
+ res = s3d_mesh_get_vertex_attrib
+ (shape->shape_rt, ivert, s3d_usage, &s3d_attr);
+ if(res != RES_OK) return res;
+
+ d3_splat(value, 1);
+ switch(s3d_attr.type) {
+ case S3D_FLOAT3: value[2] = (double)s3d_attr.value[2];
+ case S3D_FLOAT2: value[1] = (double)s3d_attr.value[1];
+ case S3D_FLOAT: value[0] = (double)s3d_attr.value[0];
+ break;
+ default: FATAL("Unexpected vertex attrib type\n"); break;
+ }
+ return RES_OK;
+}
+
/*******************************************************************************
* Exported ssol_shape functions
******************************************************************************/
@@ -912,6 +1185,57 @@ ssol_shape_ref_put(struct ssol_shape* shape)
}
res_T
+ssol_shape_get_vertices_count
+ (const struct ssol_shape* shape, unsigned* nverts)
+{
+ if(!shape || !nverts) return RES_BAD_ARG;
+ return s3d_mesh_get_vertices_count(shape->shape_rt, nverts);
+}
+
+res_T
+ssol_shape_get_vertex_attrib
+ (const struct ssol_shape* shape,
+ const unsigned ivert,
+ const enum ssol_attrib_usage usage,
+ double value[])
+{
+ res_T res = RES_OK;
+ if(!shape || (unsigned)usage >= SSOL_ATTRIBS_COUNT__ || !value)
+ return RES_BAD_ARG;
+
+ res = shape_fetched_raw_vertex_attrib(shape, ivert, usage, value);
+ if(res != RES_OK) return res;
+
+ /* Transform the fetch attrib */
+ if(shape->type == SHAPE_PUNCHED) {
+ if(usage == SSOL_POSITION) {
+ d33_muld3(value, shape->quadric.transform, value);
+ d3_add(value, shape->quadric.transform + 9, value);
+ } else if(usage == SSOL_NORMAL) {
+ double R_invtrans[9];
+ d33_invtrans(R_invtrans, shape->quadric.transform);
+ d33_muld3(value, R_invtrans, value);
+ }
+ }
+ return RES_OK;
+}
+
+res_T
+ssol_shape_get_triangles_count(const struct ssol_shape* shape, unsigned* ntris)
+{
+ if(!shape || !ntris) return RES_BAD_ARG;
+ return s3d_mesh_get_triangles_count(shape->shape_rt, ntris);
+}
+
+res_T
+ssol_shape_get_triangle_indices
+ (const struct ssol_shape* shape, const unsigned itri, unsigned ids[3])
+{
+ if(!shape || !ids) return RES_BAD_ARG;
+ return s3d_mesh_get_triangle_indices(shape->shape_rt, itri, ids);
+}
+
+res_T
ssol_punched_surface_setup
(struct ssol_shape* shape,
const struct ssol_punched_surface* psurf)
@@ -944,30 +1268,15 @@ ssol_punched_surface_setup
goto error;
}
+ /* Setup internal data */
+ priv_quadric_data_setup(&shape->priv_quadric, psurf->quadric);
+
/* Define the #slices of the discretized quadric */
- switch (psurf->quadric->type) {
- case SSOL_QUADRIC_PLANE:
- nslices = 1;
- break;
- case SSOL_QUADRIC_PARABOL: {
- double z[2];
- z[0] = (lower[0] * lower[0] + lower[1] * lower[1])
- / (4.0 * psurf->quadric->data.parabol.focal);
- z[1] = (upper[0] * upper[0] + upper[1] * upper[1])
- / (4.0 * psurf->quadric->data.parabol.focal);
- nslices = MMIN(50, (size_t)(3 + sqrt(MMAX(z[0], z[1])) * 6));
- break;
- }
- case SSOL_QUADRIC_PARABOLIC_CYLINDER: {
- double z[2];
- z[0] = (lower[1] * lower[1]) /
- (4.0 * psurf->quadric->data.parabolic_cylinder.focal);
- z[1] = (upper[1] * upper[1]) /
- (4.0 * psurf->quadric->data.parabolic_cylinder.focal);
- nslices = MMIN(50, (size_t)(3 + sqrt(MMAX(z[0], z[1])) * 6));
- break;
- }
- default: FATAL("Unreachable code\n"); break;
+ if(psurf->quadric->slices_count_hint != SIZE_MAX) {
+ nslices = psurf->quadric->slices_count_hint;
+ } else {
+ nslices = priv_quadric_data_compute_slices_count
+ (shape->quadric.type, &shape->priv_quadric, lower, upper);
}
res = build_triangulated_plane(&coords, &ids, lower, upper, nslices);
@@ -979,11 +1288,12 @@ ssol_punched_surface_setup
/* Setup the Star-3D shape to ray-trace */
res = quadric_setup_s3d_shape_rt
- (psurf->quadric, &coords, &ids, shape->shape_rt);
+ (shape, &coords, &ids, shape->shape_rt, &shape->shape_rt_area);
if(res != RES_OK) goto error;
/* Setup the Star-3D shape to sample */
- res = quadric_setup_s3d_shape_samp(psurf->quadric, &coords, &ids, shape->shape_samp);
+ res = quadric_setup_s3d_shape_samp
+ (psurf->quadric, &coords, &ids, shape->shape_samp, &shape->shape_samp_area);
if(res != RES_OK) goto error;
exit:
@@ -1005,6 +1315,7 @@ ssol_mesh_setup
void* data)
{
struct s3d_vertex_data attrs[SSOL_ATTRIBS_COUNT__];
+ void (*get_position)(const unsigned ivert, float position[3], void* data) = NULL;
res_T res = RES_OK;
unsigned i;
@@ -1030,6 +1341,8 @@ ssol_mesh_setup
case SSOL_POSITION:
attrs[i].usage = SSOL_TO_S3D_POSITION;
attrs[i].type = S3D_FLOAT3;
+ ASSERT(!get_position);
+ get_position = attrs[i].get;
break;
case SSOL_NORMAL:
attrs[i].usage = SSOL_TO_S3D_NORMAL;
@@ -1042,13 +1355,18 @@ ssol_mesh_setup
default: FATAL("Unreachable code.\n"); break;
}
}
+ ASSERT(get_position);
+
res = s3d_mesh_setup_indexed_vertices
(shape->shape_rt, ntris, get_indices, nverts, attrs, nattribs, data);
if(res != RES_OK) goto error;
+ shape->shape_rt_area =
+ mesh_compute_area(ntris, get_indices, nverts, get_position, data);
/* The Star-3D shape to sample is the same of the one to ray-traced */
res = s3d_mesh_copy(shape->shape_rt, shape->shape_samp);
if(res != RES_OK) goto error;
+ shape->shape_samp_area = shape->shape_rt_area;
exit:
return res;
diff --git a/src/ssol_shape_c.h b/src/ssol_shape_c.h
@@ -26,12 +26,37 @@ enum shape_type {
SHAPE_TYPES_COUNT__
};
+struct priv_parabol_data {
+ double focal;
+ double _1_4f;
+};
+
+struct priv_hyperbol_data {
+ double g_2;
+ double _a2_b2;
+ double _1_a2;
+ double abs_b;
+};
+
+struct priv_pcylinder_data {
+ double focal;
+ double _1_4f;
+};
+
+union priv_quadric_data {
+ struct priv_hyperbol_data hyperbol;
+ struct priv_parabol_data parabol;
+ struct priv_pcylinder_data pcylinder;
+};
+
struct ssol_shape {
enum shape_type type;
struct s3d_shape* shape_rt; /* Star-3D shape to ray-trace */
struct s3d_shape* shape_samp; /* Star-3D shape to sample */
+ union priv_quadric_data priv_quadric;
struct ssol_quadric quadric;
+ double shape_rt_area, shape_samp_area;
struct ssol_device* dev;
ref_T ref;
@@ -55,8 +80,16 @@ punched_shape_trace_ray
const double org[3], /* Ray origin in world space */
const double dir[3], /* Ray direction in world space */
const double hint_dst, /* Hint on the hit distance */
- double pos_quadric[3], /* World space position onto the quadric */
double N_quadric[3]); /* World space normal onto the quadric */
+/* Fetch vertex attrib without any post treatment, i.e. the position and the
+ * normal are not transformed */
+extern LOCAL_SYM res_T
+shape_fetched_raw_vertex_attrib
+ (const struct ssol_shape* shape,
+ const unsigned ivert,
+ const enum ssol_attrib_usage usage,
+ double value[]);
+
#endif /* SSOL_SHAPE_C_H */
diff --git a/src/ssol_solver.c b/src/ssol_solver.c
@@ -44,9 +44,117 @@
#include <limits.h>
#include <omp.h>
+/*******************************************************************************
+ * Thread context
+ ******************************************************************************/
+struct thread_context {
+ struct ssp_rng* rng;
+ struct ssf_bsdf* bsdf;
+ struct mc_data shadowed;
+ struct mc_data missing;
+ struct mc_data cos_loss;
+ struct htable_receiver mc_rcvs;
+ struct htable_sampled mc_samps;
+ struct darray_path paths; /* paths */
+};
+
+static void
+thread_context_release(struct thread_context* ctx)
+{
+ ASSERT(ctx);
+ if(ctx->rng) SSP(rng_ref_put(ctx->rng));
+ if(ctx->bsdf) SSF(bsdf_ref_put(ctx->bsdf));
+ htable_receiver_release(&ctx->mc_rcvs);
+ htable_sampled_release(&ctx->mc_samps);
+ darray_path_release(&ctx->paths);
+}
+
+static res_T
+thread_context_init(struct mem_allocator* allocator, struct thread_context* ctx)
+{
+ res_T res = RES_OK;
+ ASSERT(ctx);
+
+ memset(ctx, 0, sizeof(ctx[0]));
+ htable_receiver_init(allocator, &ctx->mc_rcvs);
+ htable_sampled_init(allocator, &ctx->mc_samps);
+ darray_path_init(allocator, &ctx->paths);
+
+ res = ssf_bsdf_create(allocator, &ctx->bsdf);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ thread_context_release(ctx);
+ goto exit;
+}
+
+/* Define a copy functor only for consistency since this function will not be
+ * used */
+static res_T
+thread_context_copy
+ (struct thread_context* dst, const struct thread_context* src)
+{
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+ dst->rng = src->rng;
+ dst->bsdf = src->bsdf;
+ dst->shadowed = src->shadowed;
+ dst->missing = src->missing;
+ dst->cos_loss = src->cos_loss;
+ res = htable_receiver_copy(&dst->mc_rcvs, &src->mc_rcvs);
+ if(res != RES_OK) return res;
+ res = htable_sampled_copy(&dst->mc_samps, &src->mc_samps);
+ if(res != RES_OK) return res;
+ res = darray_path_copy(&dst->paths, &src->paths);
+ if(res != RES_OK) return res;
+ return RES_OK;
+}
+
+static void
+thread_context_clear(struct thread_context* ctx)
+{
+ ASSERT(ctx);
+ if(ctx->rng) SSP(rng_ref_put(ctx->rng));
+ htable_receiver_clear(&ctx->mc_rcvs);
+ htable_sampled_clear(&ctx->mc_samps);
+ darray_path_clear(&ctx->paths);
+}
+
+static res_T
+thread_context_setup
+ (struct thread_context* ctx,
+ struct ssp_rng_proxy* rng_proxy,
+ const size_t ithread)
+{
+ res_T res = RES_OK;
+ ASSERT(rng_proxy && ctx);
+ thread_context_clear(ctx);
+ res = ssp_rng_proxy_create_rng(rng_proxy, ithread, &ctx->rng);
+ if(res != RES_OK) goto error;
+exit:
+ return res;
+error:
+ thread_context_clear(ctx);
+ goto exit;
+}
+
+/* Declare the container of the per thread contexts */
+#define DARRAY_NAME thread_ctx
+#define DARRAY_DATA struct thread_context
+#define DARRAY_FUNCTOR_INIT thread_context_init
+#define DARRAY_FUNCTOR_RELEASE thread_context_release
+#define DARRAY_FUNCTOR_COPY thread_context_copy
+#include <rsys/dynamic_array.h>
+
+/*******************************************************************************
+ * Random walk point
+ ******************************************************************************/
struct point {
const struct ssol_instance* inst;
const struct shaded_shape* sshape;
+ struct mc_sampled* mc_samp;
struct s3d_primitive prim;
double N[3];
double pos[3];
@@ -63,6 +171,7 @@ struct point {
#define POINT_NULL__ { \
NULL, /* Instance */ \
NULL, /* Shaded shape */ \
+ NULL, /* Primary data */ \
S3D_PRIMITIVE_NULL__, /* Primitive */ \
{0, 0, 0}, /* Normal */ \
{0, 0, 0}, /* Position */ \
@@ -74,27 +183,27 @@ struct point {
}
static const struct point POINT_NULL = POINT_NULL__;
-/*******************************************************************************
- * Helper functions
- ******************************************************************************/
-/* Return 1 if the returned point is lit by the sun and 0 otherwise */
-static int
+static res_T
point_init
(struct point* pt,
+ const double sampled_area_proxy,
struct ssol_scene* scn,
- const double sampled_area,
+ struct htable_sampled* sampled,
struct s3d_scene_view* view_samp,
struct s3d_scene_view* view_rt,
struct ranst_sun_dir* ran_sun_dir,
struct ranst_sun_wl* ran_sun_wl,
- struct ssp_rng* rng)
+ struct ssp_rng* rng,
+ int* is_lit)
{
struct s3d_attrib attr;
struct s3d_hit hit;
struct ray_data ray_data = RAY_DATA_NULL;
float dir[3], pos[3], range[2] = { 0, FLT_MAX };
- double cos_sun;
size_t id;
+ res_T res = RES_OK;
+ ASSERT(pt && scn && sampled && view_samp && view_rt);
+ ASSERT(ran_sun_dir && ran_sun_wl && rng && is_lit);
/* Sample a point into the scene view */
S3D(scene_view_sample
@@ -113,15 +222,6 @@ point_init
f3_normalize(attr.value, attr.value);
d3_set_f3(pt->N, attr.value);
- /* Sample a sun direction */
- ranst_sun_dir_get(ran_sun_dir, rng, pt->dir);
-
- /* Initialise the Monte Carlo weight */
- cos_sun = fabs(d3_dot(pt->N, pt->dir));
- pt->weight = scn->sun->dni * sampled_area * cos_sun;
- pt->cos_loss = scn->sun->dni * sampled_area * (1 - cos_sun);
- pt->absorptivity_loss = pt->reflectivity_loss = 0;
-
/* Retrieve the sampled instance and shaded shape */
pt->inst = *htable_instance_find(&scn->instances_samp, &pt->prim.inst_id);
id = *htable_shaded_shape_find
@@ -129,12 +229,36 @@ point_init
pt->sshape = darray_shaded_shape_cdata_get
(&pt->inst->object->shaded_shapes) + id;
- /* For punched surface, retrieve the sampled position and normal onto the
- * quadric surface */
- if(pt->sshape->shape->type == SHAPE_PUNCHED) {
+ /* Sample a sun direction */
+ ranst_sun_dir_get(ran_sun_dir, rng, pt->dir);
+
+ /* Initialise the Monte Carlo weight */
+ if(pt->sshape->shape->type != SHAPE_PUNCHED) {
+ double surface_sun_cos = fabs(d3_dot(pt->N, pt->dir));
+ pt->weight = scn->sun->dni * sampled_area_proxy * surface_sun_cos;
+ pt->cos_loss = scn->sun->dni * sampled_area_proxy * (1 - surface_sun_cos);
+ } else {
+ double proxy_sun_cos = fabs(d3_dot(pt->N, pt->dir));
+ double cos_ratio, surface_proxy_cos, surface_sun_cos, tmp_n[3];
+ /* For punched surface, retrieve the sampled position and normal onto the
+ * quadric surface */
punched_shape_project_point
- (pt->sshape->shape, pt->inst->transform, pt->pos, pt->pos, pt->N);
+ (pt->sshape->shape, pt->inst->transform, pt->pos, pt->pos, tmp_n);
+ surface_proxy_cos = d3_dot(pt->N, tmp_n);
+ surface_sun_cos = d3_dot(tmp_n, pt->dir);
+ cos_ratio = fabs(surface_sun_cos / surface_proxy_cos);
+ d3_set(pt->N, tmp_n);
+ pt->weight = scn->sun->dni * sampled_area_proxy * cos_ratio;
+ pt->cos_loss = scn->sun->dni * sampled_area_proxy * (1 - proxy_sun_cos);
}
+ pt->absorptivity_loss = pt->reflectivity_loss = 0;
+
+ /* Store sampled entity related weights */
+ res = get_mc_sampled(sampled, pt->inst, &pt->mc_samp);
+ if(res != RES_OK) goto error;
+ pt->mc_samp->cos_loss.weight += pt->cos_loss;
+ pt->mc_samp->cos_loss.sqr_weight += pt->cos_loss * pt->cos_loss;
+ pt->mc_samp->nb_samples++;
/* Define the primitive side on which the point lies */
if(d3_dot(pt->N, pt->dir) < 0) {
@@ -157,11 +281,15 @@ point_init
f3_minus(dir, f3_set_d3(dir, pt->dir));
f3_set_d3(pos, pt->pos);
S3D(scene_view_trace_ray(view_rt, pos, dir, range, &ray_data, &hit));
- if(!S3D_HIT_NONE(&hit)) return 0;
+ *is_lit = S3D_HIT_NONE(&hit);
+ if(*is_lit) {
+ pt->wl = ranst_sun_wl_get(ran_sun_wl, rng); /* Sample a wavelength */
+ }
- /* Sample a wavelength */
- pt->wl = ranst_sun_wl_get(ran_sun_wl, rng);
- return 1;
+exit:
+ return res;
+error:
+ goto exit;
}
static FINLINE void
@@ -220,11 +348,19 @@ point_get_material(const struct point* pt)
static FINLINE res_T
point_shade
- (struct point* pt, struct ssf_bsdf* bsdf, struct ssp_rng* rng, double dir[3])
+ (struct point* pt,
+ struct ssf_bsdf* bsdf,
+ struct ssol_medium* medium,
+ struct ssp_rng* rng,
+ double dir[3])
{
+ struct ssol_material* mtl;
struct surface_fragment frag;
- double wi[3], pdf, r;
+ double r = 1;
+ double wi[3], pdf;
+ int type;
res_T res;
+ ASSERT(pt && bsdf && medium && rng && dir);
/* TODO ensure that if `prim' was sampled, then the surface fragment setup
* remains valid in *all* situations, i.e. even though the point primitive
@@ -240,19 +376,25 @@ point_shade
surface_fragment_setup(&frag, pt->pos, pt->dir, pt->N, &pt->prim, pt->uv);
/* Shade the surface fragment */
+ mtl = point_get_material(pt);
SSF(bsdf_clear(bsdf));
- res = material_shade(point_get_material(pt), &frag, pt->wl, bsdf);
+ res = material_shade(mtl, &frag, pt->wl, medium, bsdf);
if(res != RES_OK) return res;
/* By convention, Star-SF assumes that incoming and reflected
* directions point outward the surface => negate incoming dir */
d3_minus(wi, pt->dir);
- r = ssf_bsdf_sample(bsdf, rng, wi, frag.Ns, dir, &pdf);
- ASSERT(0 <= r && r <= 1);
+ if(d3_dot(wi, frag.Ns) <= 0) {
+ r = 0;
+ } else {
+ r = ssf_bsdf_sample(bsdf, rng, wi, frag.Ns, dir, &type, &pdf);
+ ASSERT(0 <= r && r <= 1);
+ }
pt->reflectivity_loss += (1 - r) * pt->weight;
pt->weight *= r;
+ if(type & SSF_TRANSMISSION) material_get_next_medium(mtl, medium, medium);
return RES_OK;
}
@@ -296,32 +438,35 @@ point_dump
return n != 1 ? RES_IO_ERR : RES_OK;
}
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
static FINLINE res_T
check_scene(const struct ssol_scene* scene, const char* caller)
{
ASSERT(scene && caller);
- if (!scene->sun) {
+ if(!scene->sun) {
log_error(scene->dev, "%s: no sun attached.\n", caller);
return RES_BAD_ARG;
}
- if (!scene->sun->spectrum) {
+ if(!scene->sun->spectrum) {
log_error(scene->dev, "%s: sun's spectrum undefined.\n", caller);
return RES_BAD_ARG;
}
- if (scene->sun->dni <= 0) {
+ if(scene->sun->dni <= 0) {
log_error(scene->dev, "%s: sun's DNI undefined.\n", caller);
return RES_BAD_ARG;
}
- if (scene->atmosphere) {
+ if(scene->atmosphere) {
int i;
ASSERT(scene->atmosphere->type == ATMOS_UNIFORM);
i = spectrum_includes
(scene->atmosphere->data.uniform.spectrum, scene->sun->spectrum);
- if (!i) {
+ if(!i) {
log_error(scene->dev, "%s: sun/atmosphere spectra mismatch.\n", caller);
return RES_BAD_ARG;
}
@@ -329,145 +474,289 @@ check_scene(const struct ssol_scene* scene, const char* caller)
return RES_OK;
}
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-res_T
-ssol_solve
- (struct ssol_scene* scn,
- struct ssp_rng* rng_state,
- const size_t realisations_count,
- FILE* output,
- struct ssol_estimator** out_estimator)
+/* Compute an empirical length of the path segment coming from/going to the
+ * infinite, wrt the scene bounding box */
+static INLINE double
+compute_infinite_path_segment_extend(struct s3d_scene_view* view)
{
- struct htable_receiver_iterator it, end;
- struct s3d_scene_view* view_rt = NULL;
- struct s3d_scene_view* view_samp = NULL;
- struct s3d_scene_view* view_prim = NULL;
- struct ranst_sun_dir* ran_sun_dir = NULL;
- struct ranst_sun_wl* ran_sun_wl = NULL;
- struct ssf_bsdf** bsdfs = NULL;
- struct ssp_rng** rngs = NULL;
- struct ssp_rng_proxy* rng_proxy = NULL;
- struct mc_data* mc_shadows = NULL;
- struct mc_data* mc_missings = NULL;
- struct htable_receiver* mc_rcvs = NULL;
- struct ssol_estimator* estimator = NULL;
- float area;
- int nthreads = 0;
- int nrealisations = 0;
- int i = 0;
- ATOMIC res = RES_OK;
- ASSERT(nrealisations <= INT_MAX);
+ float lower[3], upper[3], size[3];
+ ASSERT(view);
+ S3D(scene_view_get_aabb(view, lower, upper));
+ f3_sub(size, upper, lower);
+ return MMAX(size[0], MMAX(size[1], size[2])) * 0.75;
+}
- if(!scn || !rng_state || !realisations_count || !out_estimator) {
- res = RES_BAD_ARG;
- goto error;
+static INLINE res_T
+path_register_and_clear
+ (struct darray_path* paths,
+ struct path* path)
+{
+ struct path* dst_path;
+ size_t ipath;
+ res_T res = RES_OK;
+ ASSERT(paths && path);
+
+ ipath = darray_path_size_get(paths);
+ res = darray_path_resize(paths, ipath + 1);
+ if(res != RES_OK) return res;
+
+ dst_path = darray_path_data_get(paths) + ipath;
+ return path_copy_and_clear(dst_path, path);
+}
+
+static res_T
+accum_mc_receivers_1side
+ (struct mc_receiver_1side* dst,
+ struct mc_receiver_1side* src)
+{
+ struct htable_shape2mc_iterator it_shape, end_shape;
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+
+ #define ACCUM_WEIGHT(Name) { \
+ dst->Name.weight += src->Name.weight; \
+ dst->Name.sqr_weight += src->Name.sqr_weight; \
+ } (void)0
+ ACCUM_WEIGHT(integrated_irradiance);
+ ACCUM_WEIGHT(absorptivity_loss);
+ ACCUM_WEIGHT(reflectivity_loss);
+ ACCUM_WEIGHT(cos_loss);
+ #undef ACCUM_WEIGHT
+
+ /* Merge the per shape MC */
+ htable_shape2mc_begin(&src->shape2mc, &it_shape);
+ htable_shape2mc_end(&src->shape2mc, &end_shape);
+ while(!htable_shape2mc_iterator_eq(&it_shape, &end_shape)) {
+ struct htable_prim2mc_iterator it_prim, end_prim;
+ const struct ssol_shape* shape = *htable_shape2mc_iterator_key_get(&it_shape);
+ struct mc_shape_1side* mc_shape1_src;
+ struct mc_shape_1side* mc_shape1_dst;
+
+ mc_shape1_src = htable_shape2mc_iterator_data_get(&it_shape);
+
+ res = mc_receiver_1side_get_mc_shape(dst, shape, &mc_shape1_dst);
+ if(res != RES_OK) goto error;
+
+ /* Merge the per primitive MC */
+ htable_prim2mc_begin(&mc_shape1_src->prim2mc, &it_prim);
+ htable_prim2mc_end(&mc_shape1_src->prim2mc, &end_prim);
+ while(!htable_prim2mc_iterator_eq(&it_prim, &end_prim)) {
+ const unsigned iprim = *htable_prim2mc_iterator_key_get(&it_prim);
+ struct mc_primitive_1side* mc_prim1_src;
+ struct mc_primitive_1side* mc_prim1_dst;
+
+ mc_prim1_src = htable_prim2mc_iterator_data_get(&it_prim);
+
+ res = mc_shape_1side_get_mc_primitive(mc_shape1_dst, iprim, &mc_prim1_dst);
+ if(res != RES_OK) goto error;
+
+ #define ACCUM_WEIGHT(Name) { \
+ mc_prim1_dst->Name.weight += mc_prim1_src->Name.weight; \
+ mc_prim1_dst->Name.sqr_weight += mc_prim1_src->Name.sqr_weight; \
+ } (void)0
+ ACCUM_WEIGHT(integrated_irradiance);
+ ACCUM_WEIGHT(absorptivity_loss);
+ ACCUM_WEIGHT(reflectivity_loss);
+ ACCUM_WEIGHT(cos_loss);
+ #undef ACCUM_WEIGHT
+
+ htable_prim2mc_iterator_next(&it_prim);
+ }
+ htable_shape2mc_iterator_next(&it_shape);
}
- /* CL compiler supports OpenMP parallel loop whose indices are signed. The
- * following line ensures that the unsigned number of realisations does not
- * overflow the realisation index. */
- if(realisations_count > INT_MAX) {
- res = RES_BAD_ARG;
- goto error;
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+accum_mc_sampled(struct mc_sampled* dst, struct mc_sampled* src)
+{
+ struct htable_receiver_iterator it, end;
+ struct mc_receiver mc_rcv_null;
+ res_T res = RES_OK;
+ ASSERT(dst && src);
+
+ mc_receiver_init(NULL, &mc_rcv_null);
+
+ #define ACCUM_WEIGHT(Name) { \
+ dst->Name.weight += src->Name.weight; \
+ dst->Name.sqr_weight += src->Name.sqr_weight; \
+ } (void)0
+ ACCUM_WEIGHT(cos_loss);
+ ACCUM_WEIGHT(shadowed);
+ #undef ACCUM_WEIGHT
+
+ dst->nb_samples += src->nb_samples;
+
+ /* dst->by_receiver += src->by_receiver; */
+ htable_receiver_begin(&src->mc_rcvs, &it);
+ htable_receiver_end(&src->mc_rcvs, &end);
+ while(!htable_receiver_iterator_eq(&it, &end)) {
+ struct mc_receiver* src_mc_rcv = htable_receiver_iterator_data_get(&it);
+ const struct ssol_instance* inst = *htable_receiver_iterator_key_get(&it);
+ struct mc_receiver* dst_mc_rcv = htable_receiver_find(&dst->mc_rcvs, &inst);
+ htable_receiver_iterator_next(&it);
+
+ if(!dst_mc_rcv) {
+ res = htable_receiver_set(&dst->mc_rcvs, &inst, &mc_rcv_null);
+ if(res != RES_OK) goto error;
+ dst_mc_rcv = htable_receiver_find(&dst->mc_rcvs, &inst);
+ }
+
+ if(inst->receiver_mask & (int)SSOL_FRONT) {
+ res = accum_mc_receivers_1side(&dst_mc_rcv->front, &src_mc_rcv->front);
+ if(res != RES_OK) goto error;
+ }
+ if(inst->receiver_mask & (int)SSOL_BACK) {
+ res = accum_mc_receivers_1side(&dst_mc_rcv->back, &src_mc_rcv->back);
+ if(res != RES_OK) goto error;
+ }
}
- nrealisations = (int)realisations_count;
- nthreads = (int) scn->dev->nthreads;
+exit:
+ mc_receiver_release(&mc_rcv_null);
+ return res;
+error:
+ goto exit;
+}
- res = check_scene(scn, FUNC_NAME);
- if(res != RES_OK) goto error;
+static res_T
+update_mc
+ (const struct point* pt,
+ const size_t irealisation,
+ const size_t ibounce,
+ struct htable_receiver* mc_rcvs,
+ FILE* output)
+{
+ struct mc_receiver_1side* mc_rcv1 = NULL;
+ struct mc_receiver_1side* mc_samp_x_rcv1 = NULL;
+ res_T res = RES_OK;
+ ASSERT(pt && mc_rcvs && point_is_receiver(pt));
- /* Create data structures shared by all threads */
- res = scene_create_s3d_views(scn, &view_rt, &view_samp, &view_prim);
- if(res != RES_OK) goto error;
- res = sun_create_distributions(scn->sun, &ran_sun_dir, &ran_sun_wl);
+ res = point_dump(pt, irealisation, ibounce, output);
if(res != RES_OK) goto error;
- /* Create the estimator */
- res = estimator_create(scn->dev, scn, &estimator);
- if (res != RES_OK) goto error;
- S3D(scene_view_compute_area(view_samp, &area));
- estimator->sampled_area = area;
- S3D(scene_view_compute_area(view_prim, &area));
- estimator->primary_area = area;
-
- /* Create a RNG proxy from the submitted RNG state */
- res = ssp_rng_proxy_create_from_rng
- (scn->dev->allocator, rng_state, scn->dev->nthreads, &rng_proxy);
+ /* Per receiver MC accumulation */
+ res = get_mc_receiver_1side(mc_rcvs, pt->inst, pt->side, &mc_rcv1);
if(res != RES_OK) goto error;
- /* Create per thread data structures */
- #define CREATE(Data) { \
- ASSERT(!(Data)); \
- if(!sa_add((Data), scn->dev->nthreads)) { \
- res = RES_BAD_ARG; \
- goto error; \
- } \
- memset((Data), 0, sizeof((Data)[0])*scn->dev->nthreads); \
+ #define ACCUM_WEIGHT(Name, W) { \
+ mc_rcv1->Name.weight += (W); \
+ mc_rcv1->Name.sqr_weight += (W)*(W); \
} (void)0
- CREATE(rngs);
- CREATE(bsdfs);
- CREATE(mc_shadows);
- CREATE(mc_missings);
- CREATE(mc_rcvs);
- #undef CREATE
-
- /* Setup per thread data structures */
- FOR_EACH(i, 0, nthreads) {
- res = ssf_bsdf_create(scn->dev->allocator, bsdfs+i);
- if(res != RES_OK) goto error;
- res = ssp_rng_proxy_create_rng(rng_proxy, (size_t)i, rngs + i);
+ ACCUM_WEIGHT(integrated_irradiance, pt->weight);
+ ACCUM_WEIGHT(absorptivity_loss, pt->absorptivity_loss);
+ ACCUM_WEIGHT(reflectivity_loss, pt->reflectivity_loss);
+ ACCUM_WEIGHT(cos_loss, pt->cos_loss);
+ #undef ACCUM_WEIGHT
+
+ /* Per-sampled/receiver MC accumulation */
+ res = mc_sampled_get_mc_receiver_1side
+ (pt->mc_samp, pt->inst, pt->side, &mc_samp_x_rcv1);
+ if(res != RES_OK) goto error;
+ #define ACCUM_WEIGHT(Name, W) { \
+ mc_samp_x_rcv1->Name.weight += (W); \
+ mc_samp_x_rcv1->Name.sqr_weight += (W)*(W); \
+ } (void)0
+ ACCUM_WEIGHT(integrated_irradiance, pt->weight);
+ ACCUM_WEIGHT(absorptivity_loss, pt->absorptivity_loss);
+ ACCUM_WEIGHT(reflectivity_loss, pt->reflectivity_loss);
+ ACCUM_WEIGHT(cos_loss, pt->cos_loss);
+ #undef ACCUM_WEIGHT
+
+ /* Per primitive receiver MC accumulation */
+ if(pt->inst->receiver_per_primitive) {
+ struct mc_shape_1side* mc_shape1;
+ struct mc_primitive_1side* mc_prim1;
+
+ res = mc_receiver_1side_get_mc_shape(mc_rcv1, pt->sshape->shape, &mc_shape1);
if(res != RES_OK) goto error;
- htable_receiver_init(scn->dev->allocator, mc_rcvs + i);
- res = htable_receiver_copy(mc_rcvs + i, &estimator->global_receivers);
+
+ res = mc_shape_1side_get_mc_primitive(mc_shape1, pt->prim.prim_id, &mc_prim1);
if(res != RES_OK) goto error;
- htable_receiver_begin(mc_rcvs + i, &it);
- htable_receiver_end(mc_rcvs + i, &end);
- while (!htable_receiver_iterator_eq(&it, &end)) {
- struct mc_per_receiver_data* estimator_data =
- htable_receiver_iterator_data_get(&it);
- *estimator_data = MC_RECV_DATA_NULL;
- htable_receiver_iterator_next(&it);
- }
+
+ #define ACCUM_WEIGHT(Name, W) { \
+ mc_prim1->Name.weight += (W); \
+ mc_prim1->Name.sqr_weight += (W)*(W); \
+ } (void)0
+ ACCUM_WEIGHT(integrated_irradiance, pt->weight);
+ ACCUM_WEIGHT(absorptivity_loss, pt->absorptivity_loss);
+ ACCUM_WEIGHT(reflectivity_loss, pt->reflectivity_loss);
+ ACCUM_WEIGHT(cos_loss, pt->cos_loss);
+ #undef ACCUM_WEIGHT
}
- #pragma omp parallel for schedule(static)
- for(i = 0; i < nrealisations; ++i) {
- struct s3d_hit hit = S3D_HIT_NULL;
- struct point pt;
- struct ssp_rng* rng;
- struct ssf_bsdf* bsdf;
- struct mc_data* shadow;
- struct mc_data* missing;
- struct htable_receiver* receiver;
- float org[3], dir[3], range[2] = { 0, FLT_MAX };
- const int ithread = omp_get_thread_num();
- size_t depth = 0;
- int is_lit;
- int hit_a_receiver = 0;
+exit:
+ return res;
+error:
+ goto exit;
+}
- if(ATOMIC_GET(&res) != RES_OK) continue; /* An error occurs */
+static res_T
+trace_radiative_path
+ (const size_t path_id, /* Unique id of the radiative path */
+ const double sampled_area_proxy, /* Overall area of the sampled geometries */
+ struct thread_context* thread_ctx,
+ struct ssol_scene* scn,
+ struct s3d_scene_view* view_samp,
+ struct s3d_scene_view* view_rt,
+ struct ranst_sun_dir* ran_sun_dir,
+ struct ranst_sun_wl* ran_sun_wl,
+ const struct ssol_path_tracker* tracker, /* May be NULL */
+ FILE* output) /* May be NULL */
+{
+ struct ssol_medium medium = SSOL_MEDIUM_VACUUM;
+ struct path path;
+ struct s3d_hit hit = S3D_HIT_NULL;
+ struct point pt;
+ float org[3], dir[3], range[2] = { 0, FLT_MAX };
+ size_t depth = 0;
+ int is_lit = 0;
+ res_T res = RES_OK;
+ ASSERT(thread_ctx && scn && view_samp && view_rt && ran_sun_dir && ran_sun_wl);
+
+ if(tracker) path_init(scn->dev->allocator, &path);
+
+ /* Find a new starting point of the radiative random walk */
+ res = point_init(&pt, sampled_area_proxy, scn, &thread_ctx->mc_samps,
+ view_samp, view_rt, ran_sun_dir, ran_sun_wl, thread_ctx->rng, &is_lit);
+ if(res != RES_OK) goto error;
- /* Fetch per thread data */
- rng = rngs[ithread];
- bsdf = bsdfs[ithread];
- shadow = mc_shadows + ithread;
- missing = mc_missings + ithread;
- receiver = mc_rcvs + ithread;
-
- /* Find a new starting point of the radiative random walk */
- is_lit = point_init(&pt, scn, estimator->sampled_area, view_samp, view_rt,
- ran_sun_dir, ran_sun_wl, rng);
-
- if(!is_lit) { /* The starting point is not lit */
- shadow->weight += pt.weight;
- shadow->sqr_weight += pt.weight * pt.weight;
- continue;
+ if(scn->atmosphere) {
+ /* Assume that the path starts from an uniform atmosphere */
+ medium.absorptivity = atmosphere_uniform_get_absorption
+ (scn->atmosphere, pt.wl);
+ }
+
+ if(tracker) {
+ /* Add the first point of the starting segment */
+ if(tracker->sun_ray_length > 0) {
+ double pos[3], wi[3];
+ d3_minus(wi, pt.dir);
+ d3_muld(wi, wi, tracker->sun_ray_length);
+ d3_add(pos, pt.pos, wi);
+ res = path_add_vertex(&path, pos, scn->sun->dni);
+ if(res != RES_OK) goto error;
}
- /* Setup the ray as if it starts from the current point position in order to handle
- * the points that start from a virtual material */
+ /* Register the init position onto the sampled geometry */
+ res = path_add_vertex(&path, pt.pos, pt.weight);
+ if(res != RES_OK) goto error;
+ }
+
+ if(!is_lit) { /* The starting point is not lit */
+ pt.mc_samp->shadowed.weight += pt.weight;
+ pt.mc_samp->shadowed.sqr_weight += pt.weight;
+ thread_ctx->shadowed.weight += pt.weight;
+ thread_ctx->shadowed.sqr_weight += pt.weight * pt.weight;
+ if(tracker) path.type = SSOL_PATH_SHADOW;
+ } else {
+ int hit_a_receiver = 0;
+
+ /* Setup the ray as if it starts from the current point position in order
+ * to handle the points that start from a virtual material */
f3_set_d3(org, pt.pos);
f3_set_d3(dir, pt.dir);
hit.distance = 0;
@@ -477,27 +766,13 @@ ssol_solve
struct ssol_material* mtl;
if(point_is_receiver(&pt)) {
- const res_T res_local = point_dump(&pt, (size_t)i, depth, output);
- struct mc_per_receiver_1side_data* data = NULL;
- if(res_local != RES_OK) {
- ATOMIC_SET(&res, res_local);
- break;
- }
- data = estimator_get_receiver_data(receiver, pt.inst, pt.side);
- ASSERT(data);
- data->irradiance.weight += pt.weight;
- data->irradiance.sqr_weight += pt.weight*pt.weight;
- data->absorptivity_loss.weight += pt.absorptivity_loss;
- data->absorptivity_loss.sqr_weight += pt.absorptivity_loss * pt.absorptivity_loss;
- data->reflectivity_loss.weight += pt.reflectivity_loss;
- data->reflectivity_loss.sqr_weight += pt.reflectivity_loss * pt.reflectivity_loss;
- data->cos_loss.weight += pt.cos_loss;
- data->cos_loss.sqr_weight += pt.cos_loss * pt.cos_loss;
hit_a_receiver = 1;
+ res = update_mc(&pt, path_id, depth, &thread_ctx->mc_rcvs, output);
+ if(res != RES_OK) goto error;
}
mtl = point_get_material(&pt);
- if(mtl->type == MATERIAL_VIRTUAL) {
+ if(mtl->type == SSOL_MATERIAL_VIRTUAL) {
/* Note that for Virtual materials, the ray parameters 'org' & 'dir'
* are not updated to ensure that it pursues its traversal without any
* accuracy issue */
@@ -506,12 +781,11 @@ ssol_solve
} else {
/* Modulate the point weight wrt to its scattering functions and
* generate an outgoing direction */
- res_T res_local = point_shade(&pt, bsdf, rng, pt.dir);
- if(res_local != RES_OK) {
- ATOMIC_SET(&res, res_local);
- break;
- }
- if (pt.weight == 0) break;
+ res = point_shade(&pt, thread_ctx->bsdf, &medium, thread_ctx->rng, pt.dir);
+ if(res != RES_OK) goto error;
+
+ /* Stop the radiative random walk */
+ if(pt.weight == 0) break;
/* Setup new ray parameters */
f2(range, 0, FLT_MAX);
@@ -529,14 +803,23 @@ ssol_solve
ray_data.range_min = range[0];
ray_data.dst = FLT_MAX;
S3D(scene_view_trace_ray(view_rt, org, dir, range, &ray_data, &hit));
- if(S3D_HIT_NONE(&hit)) break;
+ if(S3D_HIT_NONE(&hit)) {
+ /* Add the point of the last path segment going to the infinite */
+ if(tracker && tracker->infinite_ray_length > 0) {
+ double pos[3], wi[3];
+ d3_set_f3(wi, dir);
+ d3_add(pos, pt.pos, d3_muld(wi, wi, tracker->infinite_ray_length));
+ res = path_add_vertex(&path, pos, pt.weight);
+ if(res != RES_OK) goto error;
+ }
+ break;
+ }
- depth += mtl->type != MATERIAL_VIRTUAL;
+ depth += mtl->type != SSOL_MATERIAL_VIRTUAL;
- /* Take into account the atmosphere attenuation along the new ray */
- if(scn->atmosphere) {
- double transmissivity =
- compute_atmosphere_transmissivity(scn->atmosphere, hit.distance, pt.wl);
+ /* Take into account the medium attenuation */
+ if(medium.absorptivity > 0 && hit.distance > 0) {
+ const double transmissivity = exp(-medium.absorptivity * hit.distance);
ASSERT(0 < transmissivity && transmissivity <= 1);
pt.absorptivity_loss += (1 - transmissivity) * pt.weight;
pt.weight *= transmissivity;
@@ -544,70 +827,227 @@ ssol_solve
/* Update the point */
point_update_from_hit(&pt, scn, org, dir, &hit, &ray_data);
- }
+ if(tracker) {
+ res = path_add_vertex(&path, pt.pos, pt.weight);
+ if(res != RES_OK) goto error;
+ }
+ }
if(!hit_a_receiver) {
- missing->weight += pt.weight;
- missing->sqr_weight += pt.weight*pt.weight;
+ thread_ctx->missing.weight += pt.weight;
+ thread_ctx->missing.sqr_weight += pt.weight*pt.weight;
+ }
+ if(tracker) {
+ path.type = hit_a_receiver ? SSOL_PATH_SUCCESS : SSOL_PATH_MISSING;
}
}
- /* Merge per thread estimations */
+ if(tracker) {
+ res = path_register_and_clear(&thread_ctx->paths, &path);
+ if(res != RES_OK) goto error;
+ }
+
+exit:
+ if(tracker) path_release(&path);
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+res_T
+ssol_solve
+ (struct ssol_scene* scn,
+ struct ssp_rng* rng_state,
+ const size_t realisations_count,
+ const struct ssol_path_tracker* path_tracker,
+ FILE* output,
+ struct ssol_estimator** out_estimator)
+{
+ struct htable_receiver_iterator r_it, r_end;
+ struct htable_sampled_iterator s_it, s_end;
+ struct s3d_scene_view* view_rt = NULL;
+ struct s3d_scene_view* view_samp = NULL;
+ struct ranst_sun_dir* ran_sun_dir = NULL;
+ struct ranst_sun_wl* ran_sun_wl = NULL;
+ struct darray_thread_ctx thread_ctxs;
+ struct ssol_estimator* estimator = NULL;
+ struct ssol_path_tracker tracker;
+ struct ssp_rng_proxy* rng_proxy = NULL;
+ double sampled_area;
+ double sampled_area_proxy;
+ int nthreads = 0;
+ int64_t nrealisations = 0;
+ int i = 0;
+ ATOMIC res = RES_OK;
+ ASSERT(nrealisations <= INT_MAX);
+
+ if(!scn || !rng_state || !realisations_count || !out_estimator)
+ return RES_BAD_ARG;
+
+ darray_thread_ctx_init(scn->dev->allocator, &thread_ctxs);
+
+ /* CL compiler supports OpenMP parallel loop whose indices are signed. The
+ * following line ensures that the unsigned number of realisations does not
+ * overflow the realisation index. */
+ if(realisations_count > INT64_MAX) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ nrealisations = (int)realisations_count;
+ nthreads = (int) scn->dev->nthreads;
+
+ res = check_scene(scn, FUNC_NAME);
+ if(res != RES_OK) goto error;
+
+ /* Create data structures shared by all threads */
+ res = scene_create_s3d_views(scn, &view_rt, &view_samp, &sampled_area,
+ &sampled_area_proxy);
+ if(res != RES_OK) goto error;
+ res = sun_create_distributions(scn->sun, &ran_sun_dir, &ran_sun_wl);
+ if(res != RES_OK) goto error;
+
+ /* Create a RNG proxy from the submitted RNG state */
+ res = ssp_rng_proxy_create_from_rng
+ (scn->dev->allocator, rng_state, scn->dev->nthreads, &rng_proxy);
+ if(res != RES_OK) goto error;
+
+ /* Create the estimator */
+ res = estimator_create(scn->dev, scn, &estimator);
+ if (res != RES_OK) goto error;
+
+ /* Create per thread data structures */
+ res = darray_thread_ctx_resize(&thread_ctxs, scn->dev->nthreads);
+ if(res != RES_OK) goto error;
FOR_EACH(i, 0, nthreads) {
- estimator->shadow.weight += mc_shadows[i].weight;
- estimator->shadow.sqr_weight += mc_shadows[i].sqr_weight;
- estimator->missing.weight += mc_missings[i].weight;
- estimator->missing.sqr_weight += mc_missings[i].sqr_weight;
+ struct thread_context* ctx = darray_thread_ctx_data_get(&thread_ctxs)+i;
+ res = thread_context_setup(ctx, rng_proxy, (size_t)i);
+ if(res != RES_OK) goto error;
}
- /* Merge per thread estimations */
- htable_receiver_begin(&estimator->global_receivers, &it);
- htable_receiver_end(&estimator->global_receivers, &end);
- while (!htable_receiver_iterator_eq(&it, &end)) {
- struct mc_per_receiver_data* estimator_data
- = htable_receiver_iterator_data_get(&it);
- const struct ssol_instance* key = *htable_receiver_iterator_key_get(&it);
- htable_receiver_iterator_next(&it);
+ /* Setup the path tracker */
+ if(path_tracker) {
+ tracker = *path_tracker;
+ if(tracker.sun_ray_length < 0 || tracker.infinite_ray_length < 0) {
+ const double extend = compute_infinite_path_segment_extend(view_rt);
+ if(tracker.sun_ray_length < 0) tracker.sun_ray_length = extend;
+ if(tracker.infinite_ray_length < 0) tracker.infinite_ray_length = extend;
+ }
+ path_tracker = &tracker;
+ }
+
+ /* Launch the parallel MC estimation */
+ #pragma omp parallel for schedule(static)
+ for(i = 0; i < nrealisations; ++i) {
+ struct thread_context* thread_ctx;
+ const int ithread = omp_get_thread_num();
+ res_T res_local;
+
+ if(ATOMIC_GET(&res) != RES_OK) continue; /* An error occurs */
+
+ /* Fetch per thread data */
+ thread_ctx = darray_thread_ctx_data_get(&thread_ctxs) + ithread;
+
+ /* Execute a MC experiment */
+ res_local = trace_radiative_path((size_t)i, sampled_area_proxy, thread_ctx,
+ scn, view_samp, view_rt, ran_sun_dir, ran_sun_wl, path_tracker, output);
+ if(res_local != RES_OK) {
+ ATOMIC_SET(&res, res_local);
+ continue;
+ }
+ }
+
+ /* Merge per thread global MC estimations */
+ FOR_EACH(i, 0, nthreads) {
+ const struct thread_context* thread_ctx;
+ thread_ctx = darray_thread_ctx_cdata_get(&thread_ctxs)+i;
+ #define ACCUM_WEIGHT(Name) { \
+ estimator->Name.weight += thread_ctx->Name.weight; \
+ estimator->Name.sqr_weight += thread_ctx->Name.sqr_weight; \
+ } (void)0
+ ACCUM_WEIGHT(shadowed);
+ ACCUM_WEIGHT(missing);
+ ACCUM_WEIGHT(cos_loss);
+ #undef ACCUM_WEIGHT
+ }
+
+ /* Merge per thread receiver MC estimations */
+ htable_receiver_begin(&estimator->mc_receivers, &r_it);
+ htable_receiver_end(&estimator->mc_receivers, &r_end);
+ while(!htable_receiver_iterator_eq(&r_it, &r_end)) {
+ struct mc_receiver* mc_rcv = htable_receiver_iterator_data_get(&r_it);
+ const struct ssol_instance* inst = *htable_receiver_iterator_key_get(&r_it);
+ htable_receiver_iterator_next(&r_it);
+
FOR_EACH(i, 0, nthreads) {
- /* Sum both sides, even if no receiver is defined to avoid tests */
- struct mc_per_receiver_data* thread_data
- = htable_receiver_find(mc_rcvs + i, &key);
- #define ACCUM_WEIGHT(Name) { \
- estimator_data->front.Name.weight += thread_data->front.Name.weight; \
- estimator_data->back.Name.weight += thread_data->back.Name.weight; \
- estimator_data->front.Name.sqr_weight += thread_data->front.Name.sqr_weight;\
- estimator_data->back.Name.sqr_weight += thread_data->back.Name.sqr_weight;\
- } (void)0
- ACCUM_WEIGHT(irradiance);
- ACCUM_WEIGHT(absorptivity_loss);
- ACCUM_WEIGHT(reflectivity_loss);
- ACCUM_WEIGHT(cos_loss);
- #undef ACCUM_WEIGHT
+ struct thread_context* thread_ctx;
+ struct mc_receiver* mc_rcv_thread;
+
+ thread_ctx = darray_thread_ctx_data_get(&thread_ctxs) + i;
+ mc_rcv_thread = htable_receiver_find(&thread_ctx->mc_rcvs, &inst);
+ if(!mc_rcv_thread) continue; /* Receiver was not visited in this thread */
+
+ if(inst->receiver_mask & (int)SSOL_FRONT) {
+ res = accum_mc_receivers_1side(&mc_rcv->front, &mc_rcv_thread->front);
+ if(res != RES_OK) goto error;
+ }
+ if(inst->receiver_mask & (int)SSOL_BACK) {
+ res = accum_mc_receivers_1side(&mc_rcv->back, &mc_rcv_thread->back);
+ if(res != RES_OK) goto error;
+ }
+ }
+ }
+
+ /* Merge per thread sampled instance MC estimations */
+ htable_sampled_begin(&estimator->mc_sampled, &s_it);
+ htable_sampled_end(&estimator->mc_sampled, &s_end);
+ while(!htable_sampled_iterator_eq(&s_it, &s_end)) {
+ struct mc_sampled* mc_samp = htable_sampled_iterator_data_get(&s_it);
+ const struct ssol_instance* inst = *htable_sampled_iterator_key_get(&s_it);
+ htable_sampled_iterator_next(&s_it);
+
+ FOR_EACH(i, 0, nthreads) {
+ struct thread_context* thread_ctx;
+ struct mc_sampled* mc_samp_thread;
+
+ thread_ctx = darray_thread_ctx_data_get(&thread_ctxs) + i;
+ mc_samp_thread = htable_sampled_find(&thread_ctx->mc_samps, &inst);
+ if(!mc_samp_thread) continue; /* Instance was not sampled in this thread */
+
+ res = accum_mc_sampled(mc_samp, mc_samp_thread);
+ if(res != RES_OK) goto error;
}
}
- estimator->realisation_count += realisations_count;
+
+ /* Merge per thread tracked paths */
+ if(path_tracker) {
+ FOR_EACH(i, 0, nthreads) {
+ struct thread_context* thread_ctx;
+ size_t ipath, npaths;
+
+ thread_ctx = darray_thread_ctx_data_get(&thread_ctxs) + i;
+ npaths = darray_path_size_get(&thread_ctx->paths);
+ FOR_EACH(ipath, 0, npaths) {
+ struct path* path;
+ path = darray_path_data_get(&thread_ctx->paths) + ipath;
+ res = path_register_and_clear(&estimator->paths, path);
+ if(res != RES_OK) goto error;
+ }
+ }
+ }
+
+ estimator->realisation_count = realisations_count;
+ estimator->sampled_area = sampled_area;
exit:
+ darray_thread_ctx_release(&thread_ctxs);
if(view_rt) S3D(scene_view_ref_put(view_rt));
if(view_samp) S3D(scene_view_ref_put(view_samp));
- if(view_prim) S3D(scene_view_ref_put(view_prim));
if(ran_sun_dir) ranst_sun_dir_ref_put(ran_sun_dir);
if(ran_sun_wl) ranst_sun_wl_ref_put(ran_sun_wl);
if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy));
- if(bsdfs) {
- FOR_EACH(i, 0, nthreads) if(bsdfs[i]) SSF(bsdf_ref_put(bsdfs[i]));
- sa_release(bsdfs);
- }
- if(rngs) {
- FOR_EACH(i, 0, nthreads) if(rngs[i]) SSP(rng_ref_put(rngs[i]));
- sa_release(rngs);
- }
- if(mc_rcvs) {
- FOR_EACH(i, 0, nthreads) htable_receiver_release(mc_rcvs + i);
- sa_release(mc_rcvs);
- }
- sa_release(mc_shadows);
- sa_release(mc_missings);
if(out_estimator) *out_estimator = estimator;
return (res_T)res;
error:
diff --git a/src/test_ssol_atmosphere.c b/src/test_ssol_atmosphere.c
@@ -16,12 +16,9 @@
#include "ssol.h"
#include "test_ssol_utils.h"
-#include <rsys/logger.h>
-
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssol_spectrum* spectrum;
@@ -31,13 +28,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum2), RES_OK);
@@ -64,8 +56,6 @@ main(int argc, char** argv)
CHECK(ssol_spectrum_ref_put(spectrum2), RES_OK);
CHECK(ssol_device_ref_put(dev), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_by_receiver_integration.c b/src/test_ssol_by_receiver_integration.c
@@ -27,7 +27,6 @@
#define HALF_Y 10
#include "test_ssol_rect2D_geometry.h"
-#include <rsys/logger.h>
#include <rsys/double33.h>
#include <star/s3d.h>
@@ -47,7 +46,6 @@ get_wlen(const size_t i, double* wlen, double* data, void* ctx)
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssp_rng* rng;
@@ -68,7 +66,7 @@ main(int argc, char** argv)
struct ssol_sun* sun;
struct ssol_spectrum* spectrum;
struct ssol_estimator *estimator1, *estimator2;
- struct ssol_estimator_status status;
+ struct ssol_mc_receiver mc_rcv;
double dir[3];
double transform[12]; /* 3x4 column major matrix */
@@ -80,13 +78,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
@@ -121,7 +114,7 @@ main(int argc, char** argv)
shader.normal = get_shader_normal;
shader.reflectivity = get_shader_reflectivity;
shader.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK);
+ CHECK(ssol_mirror_setup(m_mtl, &shader), RES_OK);
CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
CHECK(ssol_object_create(dev, &m_object), RES_OK);
@@ -133,33 +126,35 @@ main(int argc, char** argv)
CHECK(ssol_object_add_shaded_shape(t_object, square, v_mtl, v_mtl), RES_OK);
CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
CHECK(ssol_instance_set_transform(target, transform), RES_OK);
- CHECK(ssol_instance_set_receiver(target, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_sample(target, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
#define N__ 10000
#define S_DNI_cos (4 * 1000 * cos(PI / 4))
-#define GET_RCV_STATUS ssol_estimator_get_receiver_status
- CHECK(ssol_solve(scene, rng, N__, NULL, &estimator1), RES_OK);
- CHECK(GET_RCV_STATUS(estimator1, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT), RES_OK);
- CHECK(eq_eps(status.irradiance.E, S_DNI_cos, S_DNI_cos * 2e-1), 1);
- CHECK(ssol_solve(scene, rng, 8 * N__, NULL, &estimator2), RES_OK);
- CHECK(GET_RCV_STATUS(estimator2, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, S_DNI_cos, S_DNI_cos * 5e-2), 1);
+#define GET_MC_RCV ssol_estimator_get_mc_receiver
+#define GET_MC_SAMP_X_RCV ssol_estimator_get_mc_sampled_x_receiver
+ CHECK(ssol_solve(scene, rng, N__, 0, NULL, &estimator1), RES_OK);
+ CHECK(GET_MC_RCV(estimator1, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT, 0), RES_OK);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, S_DNI_cos, S_DNI_cos * 2e-1), 1);
+ CHECK(ssol_solve(scene, rng, 8 * N__, 0, NULL, &estimator2), RES_OK);
+ CHECK(GET_MC_RCV(estimator2, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, S_DNI_cos, S_DNI_cos * 5e-2), 1);
CHECK(ssol_estimator_ref_put(estimator1), RES_OK);
- CHECK(ssol_solve(scene, rng, 3 * N__, NULL, &estimator1), RES_OK);
- CHECK(GET_RCV_STATUS(estimator1, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, S_DNI_cos, S_DNI_cos * 1e-1), 1);
-#undef N__
-#undef S_DNI_cos
-#undef GET_RCV_STATUS
+ CHECK(ssol_solve(scene, rng, 3 * N__, 0, NULL, &estimator1), RES_OK);
+ CHECK(GET_MC_RCV(estimator1, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, S_DNI_cos, S_DNI_cos * 1e-1), 1);
+ CHECK(GET_MC_SAMP_X_RCV(estimator1, heliostat, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(heliostat=>target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, S_DNI_cos, S_DNI_cos * 1e-1), 1);
/* Free data */
CHECK(ssol_instance_ref_put(heliostat), RES_OK);
@@ -178,8 +173,6 @@ main(int argc, char** argv)
CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_circ2D_geometry.h b/src/test_ssol_circ2D_geometry.h
@@ -0,0 +1,54 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "test_ssol_geometries.h"
+#include <rsys/math.h>
+
+
+/*******************************************************************************
+* Circle polygon
+******************************************************************************/
+#if !defined(RADIUS)
+#error "Missing the RADIUS macro defining the circle radius"
+#endif
+#if !defined(NVERTS)
+#define NVERTS 36
+#endif
+#if !defined(CIRCLE_NAME)
+#error "Missing the CIRCLE_NAME macro defining the circle name"
+#endif
+
+#define EDGES__ CONCAT(CIRCLE_NAME, _EDGES__)
+#define INIT_FUNC__ CONCAT(init_, CIRCLE_NAME)
+
+/* should be const but scpr expects non-const data */
+static double EDGES__ [2*NVERTS];
+
+static void INIT_FUNC__() {
+ int n;
+ /* radius that give the same area than a circle */
+ double r = sqrt(2 * RADIUS * RADIUS * PI / (sin(2 * PI / NVERTS) * NVERTS));
+ for (n = 0; n < NVERTS; n++) {
+ EDGES__[2 * n] = r * cos((double)-n * 2 * PI / (double)NVERTS);
+ EDGES__[2 * n + 1] = r * sin((double)-n * 2 * PI / (double) NVERTS);
+ }
+}
+
+#undef EDGES__
+#undef INIT_FUNC__
+
+#undef RADIUS
+#undef NVERTS
+#undef CIRCLE_NAME
diff --git a/src/test_ssol_cube_geometry.h b/src/test_ssol_cube_geometry.h
@@ -0,0 +1,107 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "test_ssol_geometries.h"
+
+/*******************************************************************************
+* Rectangle polygon
+******************************************************************************/
+#if !defined(HALF_X) && !(defined(X_MIN) && defined(X_MAX))
+#error "Missing the HALF_X or X_MIN and X_MAX macros defining the cube size"
+#endif
+#if !defined(HALF_Y) && !(defined(Y_MIN) && defined(Y_MAX))
+#error "Missing the HALF_Y or Y_MIN and Y_MAX macros defining the cube size"
+#endif
+#if !defined(HALF_Z) && !(defined(Z_MIN) && defined(Z_MAX))
+#error "Missing the HALF_Z or Z_MIN and Z_MAX macros defining the cube size"
+#endif
+#if !defined(CUBE_NAME)
+#error "Missing the CUBE_NAME macro defining the rectangle name"
+#endif
+
+#define EDGES__ CONCAT(CUBE_NAME, _EDGES__)
+#define CUBE_NVERTS__ CONCAT(CUBE_NAME, _NVERTS__)
+
+#if !defined(X_MIN)
+#define X_MIN (float)(-(HALF_X))
+#endif
+
+#if !defined(X_MAX)
+#define X_MAX (float)(HALF_X)
+#endif
+
+#if !defined(Y_MIN)
+#define Y_MIN (float)(-(HALF_Y))
+#endif
+
+#if !defined(Y_MAX)
+#define Y_MAX (float)(HALF_Y)
+#endif
+
+#if !defined(Z_MIN)
+#define Z_MIN (float)(-(HALF_Z))
+#endif
+
+#if !defined(Z_MAX)
+#define Z_MAX (float)(HALF_Z)
+#endif
+
+static const float EDGES__ [] = {
+ X_MIN, Y_MIN, Z_MIN,
+ X_MIN, Y_MIN, Z_MAX,
+ X_MIN, Y_MAX, Z_MIN,
+ X_MIN, Y_MAX, Z_MAX,
+ X_MAX, Y_MIN, Z_MIN,
+ X_MAX, Y_MIN, Z_MAX,
+ X_MAX, Y_MAX, Z_MIN,
+ X_MAX, Y_MAX, Z_MAX
+};
+
+const unsigned CUBE_NVERTS__ = sizeof(EDGES__) / sizeof(float[3]);
+
+const unsigned TRG_IDS__ [] = {
+ 0, 6, 4,
+ 0, 2, 6,
+ 0, 3, 2,
+ 0, 1, 3,
+ 2, 7, 6,
+ 2, 3, 7,
+ 4, 6, 7,
+ 4, 7, 5,
+ 0, 4, 5,
+ 0, 5, 1,
+ 1, 5, 7,
+ 1, 7, 3
+};
+const unsigned CUBE_NTRIS__ = sizeof(TRG_IDS__) / sizeof(unsigned[3]);
+
+static const struct desc CUBE_DESC__ = { EDGES__, TRG_IDS__ };
+
+#undef EDGES__
+#undef TRG_IDS__
+#undef CUBE_DESC__
+#undef CUBE_NVERTS__
+#undef CUBE_NTRIS__
+
+#undef HALF_X
+#undef HALF_Y
+#undef HALF_Z
+#undef X_MIN
+#undef X_MAX
+#undef Y_MIN
+#undef Y_MAX
+#undef Z_MIN
+#undef Z_MAX
+#undef CUBE_NAME
diff --git a/src/test_ssol_device.c b/src/test_ssol_device.c
@@ -18,6 +18,14 @@
#include <rsys/logger.h>
+static INLINE void
+log_stream(const char* msg, void* ctx)
+{
+ ASSERT(msg);
+ (void) msg, (void) ctx;
+ printf("%s\n", msg);
+}
+
int
main(int argc, char** argv)
{
diff --git a/src/test_ssol_draw.c b/src/test_ssol_draw.c
@@ -18,11 +18,15 @@
#include "test_ssol_geometries.h"
#include "test_ssol_materials.h"
+#include <rsys/double3.h>
+#include <rsys/float3.h>
#include <rsys/image.h>
#include <rsys/math.h>
-#define WIDTH 800
-#define HEIGHT 600
+#include <string.h>
+
+#define WIDTH 256
+#define HEIGHT 256
#define PITCH (WIDTH*sizeof(unsigned char[3]))
#define PROJ_RATIO ((double)WIDTH/(double)HEIGHT)
@@ -113,15 +117,16 @@ setup_cornell_box(struct ssol_device* dev, struct ssol_scene* scn)
struct ssol_object* obj;
struct ssol_instance* inst;
struct ssol_material* mtl;
- struct ssol_mirror_shader shader = SSOL_MIRROR_SHADER_NULL;
+ struct ssol_matte_shader shader = SSOL_MATTE_SHADER_NULL;
struct ssol_vertex_data vdata;
struct desc desc;
+ float lower[3], upper[3];
+ float tmp[3];
shader.normal = get_shader_normal;
shader.reflectivity = get_shader_reflectivity;
- shader.roughness = get_shader_roughness;
- CHECK(ssol_material_create_mirror(dev, &mtl), RES_OK);
- CHECK(ssol_mirror_set_shader(mtl, &shader), RES_OK);
+ CHECK(ssol_material_create_matte(dev, &mtl), RES_OK);
+ CHECK(ssol_matte_setup(mtl, &shader), RES_OK);
vdata.usage = SSOL_POSITION;
vdata.get = get_position;
@@ -164,6 +169,10 @@ setup_cornell_box(struct ssol_device* dev, struct ssol_scene* scn)
CHECK(ssol_object_ref_put(obj), RES_OK);
CHECK(ssol_material_ref_put(mtl), RES_OK);
+
+ CHECK(ssol_scene_compute_aabb(scn, lower, upper), RES_OK);
+ CHECK(f3_eq_eps(lower, f3(tmp, 0, 0, 0), 1.e-6f), 1);
+ CHECK(f3_eq_eps(upper, f3(tmp, 552.f, 559.f, 548.f), 1.e-6f), 1);
}
int
@@ -173,12 +182,36 @@ main(int argc, char** argv)
struct ssol_device* dev;
struct ssol_camera* cam;
struct ssol_scene* scn;
+ struct ssol_sun* sun;
unsigned char* pixels = NULL;
const double pos[3] = {278.0, -1000.0, 273.0};
const double tgt[3] = {278.0, 0.0, 273.0};
const double up[3] = {0.0, 0.0, 1.0};
+ double dir[3];
+ res_T (*draw_func)
+ (struct ssol_scene* scn,
+ struct ssol_camera* cam,
+ const size_t width,
+ const size_t height,
+ const size_t spp,
+ ssol_write_pixels_T writer,
+ void* data);
(void)argc, (void)argv;
+ if(argc <= 1) {
+ fprintf(stderr, "Usage: %s <draft|pt>\n", argv[0]);
+ return -1;
+ }
+
+ if(!strcmp(argv[1], "draft")) {
+ draw_func = ssol_draw_draft;
+ } else if(!strcmp(argv[1], "pt")) {
+ draw_func = ssol_draw_pt;
+ } else {
+ fprintf(stderr, "Usage: %s <draft|pt>\n", argv[0]);
+ return -1;
+ }
+
CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK);
CHECK(ssol_device_create
@@ -193,41 +226,80 @@ main(int argc, char** argv)
CHECK(ssol_camera_set_fov(cam, PI/4.0), RES_OK);
CHECK(ssol_camera_look_at(cam, pos, tgt, up), RES_OK);
+ d3(dir, 1, 1, -1);
+ d3_normalize(dir, dir);
+ CHECK(ssol_sun_create_directional(dev, &sun), RES_OK);
+ CHECK(ssol_sun_set_direction(sun, dir), RES_OK);
+ CHECK(ssol_sun_set_dni(sun, 1000), RES_OK);
+ CHECK(ssol_scene_attach_sun(scn, sun), RES_OK);
+
pixels = MEM_CALLOC(&allocator, HEIGHT, PITCH);
NCHECK(pixels, NULL);
- CHECK(ssol_draw(NULL, NULL, 0, 0, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, NULL, 0, 0, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, cam, 0, 0, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, cam, 0, 0, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, NULL, WIDTH, 0, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, NULL, WIDTH, 0, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, cam, WIDTH, 0, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, cam, WIDTH, 0, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, NULL, 0, HEIGHT, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, NULL, 0, HEIGHT, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, cam, 0, HEIGHT, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, cam, 0, HEIGHT, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, NULL, WIDTH, HEIGHT, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, NULL, WIDTH, HEIGHT, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, cam, WIDTH, WIDTH, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, cam, WIDTH, HEIGHT, NULL, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, NULL, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, NULL, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, cam, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, cam, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, NULL, WIDTH, 0, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, NULL, WIDTH, 0, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, cam, WIDTH, 0, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, cam, WIDTH, 0, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, NULL, 0, HEIGHT, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, NULL, 0, HEIGHT, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, cam, 0, HEIGHT, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, cam, 0, HEIGHT, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, NULL, WIDTH, HEIGHT, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, NULL, WIDTH, HEIGHT, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(NULL, cam, WIDTH, WIDTH, write_RGB8, pixels), RES_BAD_ARG);
- CHECK(ssol_draw(scn, cam, WIDTH, HEIGHT, write_RGB8, pixels), RES_OK);
+ CHECK(draw_func(NULL, NULL, 0, 0, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, 0, 0, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, 0, 0, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, 0, 0, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, WIDTH, 0, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, WIDTH, 0, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, WIDTH, 0, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, WIDTH, 0, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, 0, HEIGHT, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, 0, HEIGHT, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, 0, HEIGHT, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, 0, HEIGHT, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, WIDTH, HEIGHT, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, WIDTH, HEIGHT, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, WIDTH, WIDTH, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, WIDTH, HEIGHT, 0, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, 0, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, 0, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, 0, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, 0, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, WIDTH, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, WIDTH, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, WIDTH, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, WIDTH, 0, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, 0, HEIGHT, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, 0, HEIGHT, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, 0, HEIGHT, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, 0, HEIGHT, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, WIDTH, HEIGHT, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, WIDTH, HEIGHT, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, WIDTH, WIDTH, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, WIDTH, HEIGHT, 0, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, 0, 0, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, 0, 0, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, 0, 0, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, 0, 0, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, WIDTH, 0, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, WIDTH, 0, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, WIDTH, 0, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, WIDTH, 0, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, 0, HEIGHT, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, 0, HEIGHT, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, 0, HEIGHT, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, 0, HEIGHT, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, WIDTH, HEIGHT, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, WIDTH, HEIGHT, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, WIDTH, WIDTH, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, WIDTH, HEIGHT, 4, NULL, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, 0, 0, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, 0, 0, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, 0, 0, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, 0, 0, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, WIDTH, 0, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, WIDTH, 0, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, WIDTH, 0, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, WIDTH, 0, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, 0, HEIGHT, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, 0, HEIGHT, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, 0, HEIGHT, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, 0, HEIGHT, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, NULL, WIDTH, HEIGHT, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, NULL, WIDTH, HEIGHT, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(NULL, cam, WIDTH, WIDTH, 4, write_RGB8, pixels), RES_BAD_ARG);
+ CHECK(draw_func(scn, cam, WIDTH, HEIGHT, 4, write_RGB8, pixels), RES_OK);
CHECK(image_ppm_write_stream(stdout, WIDTH, HEIGHT, 3, pixels), RES_OK);
@@ -235,6 +307,7 @@ main(int argc, char** argv)
CHECK(ssol_device_ref_put(dev), RES_OK);
CHECK(ssol_camera_ref_put(cam), RES_OK);
CHECK(ssol_scene_ref_put(scn), RES_OK);
+ CHECK(ssol_sun_ref_put(sun), RES_OK);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
diff --git a/src/test_ssol_image.c b/src/test_ssol_image.c
@@ -16,13 +16,10 @@
#include "ssol.h"
#include "test_ssol_utils.h"
-#include <rsys/logger.h>
-
int
main(int argc, char** argv)
{
double block[8/*#rows*/*3/*#channels*/*8/*#column*/];
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssol_image* img;
@@ -35,13 +32,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssol_image_create(dev, &img), RES_OK);
@@ -139,11 +131,8 @@ main(int argc, char** argv)
}
CHECK(ssol_image_ref_put(img), RES_OK);
-
CHECK(ssol_device_ref_put(dev), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_instance.c b/src/test_ssol_instance.c
@@ -15,13 +15,16 @@
#include "ssol.h"
#include "test_ssol_utils.h"
+#include <rsys/double33.h>
-#include <rsys/logger.h>
+#define PLANE_NAME SQUARE
+#define HALF_X 1
+#define HALF_Y 1
+#include "test_ssol_rect_geometry.h"
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssol_shape* shape;
@@ -29,23 +32,28 @@ main(int argc, char** argv)
struct ssol_object* object;
struct ssol_instance* instance;
struct ssol_instance* instance1;
- double transform[12];
+ struct ssol_vertex_data attrib = SSOL_VERTEX_DATA_NULL;
+ struct ssol_instantiated_shaded_shape sshape;
+ double transform[12] = {1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 0, 0};
+ double val[3];
+ size_t n;
+ unsigned i, count;
uint32_t id, id1;
(void) argc, (void) argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssol_material_create_virtual(dev, &material), RES_OK);
- CHECK(ssol_shape_create_punched_surface(dev, &shape), RES_OK);
+ attrib.usage = SSOL_POSITION;
+ attrib.get = get_position;
+ CHECK(ssol_shape_create_mesh(dev, &shape), RES_OK);
+ CHECK(ssol_mesh_setup(shape, SQUARE_NTRIS__, get_ids, SQUARE_NVERTS__,
+ &attrib, 1, (void*)&SQUARE_DESC__), RES_OK);
+
CHECK(ssol_object_create(dev, &object), RES_OK);
CHECK(ssol_object_add_shaded_shape(object, shape, material, material), RES_OK);
@@ -64,31 +72,89 @@ main(int argc, char** argv)
CHECK(ssol_instance_ref_put(NULL), RES_BAD_ARG);
CHECK(ssol_instance_ref_put(instance), RES_OK);
- CHECK(ssol_instance_ref_put(instance1), RES_OK);
CHECK(ssol_instance_set_transform(NULL, transform), RES_BAD_ARG);
CHECK(ssol_instance_set_transform(instance, NULL), RES_BAD_ARG);
CHECK(ssol_instance_set_transform(instance, transform), RES_OK);
CHECK(ssol_instance_set_transform(instance, transform), RES_OK);
- #define SET_RECEIVER ssol_instance_set_receiver
- CHECK(ssol_instance_set_receiver(NULL, 0), RES_BAD_ARG);
- CHECK(ssol_instance_set_receiver(instance, 0), RES_OK);
- #undef SET_RECEIVER
+ CHECK(ssol_instance_set_receiver(NULL, 0, 0), RES_BAD_ARG);
+ CHECK(ssol_instance_set_receiver(instance, 0, 0), RES_OK);
CHECK(ssol_instance_sample(NULL, 0), RES_BAD_ARG);
CHECK(ssol_instance_sample(instance, 0), RES_OK);
CHECK(ssol_instance_sample(instance, 1), RES_OK);
- CHECK(ssol_instance_ref_put(instance), RES_OK);
+ CHECK(ssol_instance_get_shaded_shapes_count(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shapes_count(instance, NULL), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shapes_count(NULL, &n), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shapes_count(instance, &n), RES_OK);
+ CHECK(n, 1);
+
+ CHECK(ssol_instance_get_shaded_shape(NULL, n, NULL), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shape(instance, n, NULL), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shape(NULL, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shape(instance, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shape(NULL, n, &sshape), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shape(instance, n, &sshape), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shape(NULL, 0, &sshape), RES_BAD_ARG);
+ CHECK(ssol_instance_get_shaded_shape(instance, 0, &sshape), RES_OK);
+
+ CHECK(sshape.shape, shape);
+ CHECK(sshape.mtl_front, material);
+ CHECK(sshape.mtl_back, material);
+
+ CHECK(ssol_shape_get_vertices_count(sshape.shape, &count), RES_OK);
+
+ #define GET_ATTR ssol_instantiated_shaded_shape_get_vertex_attrib
+ CHECK(GET_ATTR(NULL, count, (unsigned)-1, NULL), RES_BAD_ARG);
+ CHECK(GET_ATTR(&sshape, count, (unsigned)-1, NULL), RES_BAD_ARG);
+ CHECK(GET_ATTR(NULL, 0, (unsigned)-1, NULL), RES_BAD_ARG);
+ CHECK(GET_ATTR(&sshape, 0, (unsigned)-1, NULL), RES_BAD_ARG);
+ CHECK(GET_ATTR(NULL, count, SSOL_POSITION, NULL), RES_BAD_ARG);
+ CHECK(GET_ATTR(&sshape, count, SSOL_POSITION, NULL), RES_BAD_ARG);
+ CHECK(GET_ATTR(NULL, 0, SSOL_POSITION, NULL), RES_BAD_ARG);
+ CHECK(GET_ATTR(&sshape, 0, SSOL_POSITION, NULL), RES_BAD_ARG);
+ CHECK(GET_ATTR(NULL, count, (unsigned)-1, val), RES_BAD_ARG);
+ CHECK(GET_ATTR(&sshape, count, (unsigned)-1, val), RES_BAD_ARG);
+ CHECK(GET_ATTR(NULL, 0, (unsigned)-1, val), RES_BAD_ARG);
+ CHECK(GET_ATTR(&sshape, 0, (unsigned)-1, val), RES_BAD_ARG);
+ CHECK(GET_ATTR(NULL, count, SSOL_POSITION, val), RES_BAD_ARG);
+ CHECK(GET_ATTR(&sshape, count, SSOL_POSITION, val), RES_BAD_ARG);
+ CHECK(GET_ATTR(NULL, 0, SSOL_POSITION, val), RES_BAD_ARG);
+ FOR_EACH(i, 0, count) {
+ float valf[3];
+ double val2[3];
+
+ CHECK(GET_ATTR(&sshape, i, SSOL_POSITION, val), RES_OK);
+ get_position(i, valf, (void*)&SQUARE_DESC__);
+ d3_set_f3(val2, valf);
+ d33_muld3(val2, transform, val2);
+ d3_add(val2, transform+9, val2);
+ CHECK(eq_eps(val[0], val2[0], 1.e-6), 1);
+ CHECK(eq_eps(val[1], val2[1], 1.e-6), 1);
+ CHECK(eq_eps(val[2], val2[2], 1.e-6), 1);
+ }
+ CHECK(ssol_instance_get_shaded_shape(instance1, 0, &sshape), RES_OK);
+ FOR_EACH(i, 0, count) {
+ float valf[3];
+
+ CHECK(GET_ATTR(&sshape, i, SSOL_POSITION, val), RES_OK);
+ get_position(i, valf, (void*)&SQUARE_DESC__);
+ CHECK((float)val[0], valf[0]);
+ CHECK((float)val[1], valf[1]);
+ CHECK((float)val[2], valf[2]);
+ }
+ #undef GET_ATTR
+
+ CHECK(ssol_instance_ref_put(instance), RES_OK);
+ CHECK(ssol_instance_ref_put(instance1), 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_device_ref_put(dev), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_material.c b/src/test_ssol_material.c
@@ -17,34 +17,25 @@
#include "test_ssol_utils.h"
#include "test_ssol_materials.h"
-#include <rsys/logger.h>
-
-int
-main(int argc, char** argv)
+static void
+test_mirror(struct ssol_device* dev)
{
- struct logger logger;
- struct mem_allocator allocator;
- struct ssol_device* dev;
- struct ssol_material* material;
struct ssol_mirror_shader mirror = SSOL_MIRROR_SHADER_NULL;
- struct ssol_matte_shader matte = SSOL_MATTE_SHADER_NULL;
struct ssol_param_buffer* pbuf = NULL;
- (void) argc, (void) argv;
-
- mem_init_proxy_allocator(&allocator, &mem_default_allocator);
-
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
- CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ struct ssol_material* material;
+ enum ssol_material_type type;
+ CHECK(ssol_material_create_mirror(NULL, NULL), RES_BAD_ARG);
CHECK(ssol_material_create_mirror(NULL, &material), RES_BAD_ARG);
CHECK(ssol_material_create_mirror(dev, NULL), RES_BAD_ARG);
CHECK(ssol_material_create_mirror(dev, &material), RES_OK);
+ CHECK(ssol_material_get_type(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_material_get_type(material, NULL), RES_BAD_ARG);
+ CHECK(ssol_material_get_type(NULL, &type), RES_BAD_ARG);
+ CHECK(ssol_material_get_type(material, &type), RES_OK);
+ CHECK(type, SSOL_MATERIAL_MIRROR);
+
CHECK(ssol_material_ref_get(NULL), RES_BAD_ARG);
CHECK(ssol_material_ref_get(material), RES_OK);
@@ -57,10 +48,10 @@ main(int argc, char** argv)
mirror.reflectivity = get_shader_reflectivity;
mirror.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(NULL, &mirror), RES_BAD_ARG);
- CHECK(ssol_mirror_set_shader(material, NULL), RES_BAD_ARG);
- CHECK(ssol_mirror_set_shader(material, &mirror), RES_OK);
- CHECK(ssol_mirror_set_shader(material, &mirror), RES_OK);
+ CHECK(ssol_mirror_setup(NULL, &mirror), RES_BAD_ARG);
+ CHECK(ssol_mirror_setup(material, NULL), RES_BAD_ARG);
+ CHECK(ssol_mirror_setup(material, &mirror), RES_OK);
+ CHECK(ssol_mirror_setup(material, &mirror), RES_OK);
CHECK(ssol_material_set_param_buffer(NULL, NULL), RES_BAD_ARG);
CHECK(ssol_material_set_param_buffer(material, NULL), RES_BAD_ARG);
@@ -68,48 +59,223 @@ main(int argc, char** argv)
CHECK(ssol_material_set_param_buffer(material, pbuf), RES_OK);
mirror.normal = NULL;
- CHECK(ssol_mirror_set_shader(material, &mirror), RES_BAD_ARG);
+ CHECK(ssol_mirror_setup(material, &mirror), RES_BAD_ARG);
mirror.normal = get_shader_normal;
mirror.reflectivity = NULL;
- CHECK(ssol_mirror_set_shader(material, &mirror), RES_BAD_ARG);
+ CHECK(ssol_mirror_setup(material, &mirror), RES_BAD_ARG);
mirror.reflectivity = get_shader_reflectivity;
mirror.roughness = NULL;
- CHECK(ssol_mirror_set_shader(material, &mirror), RES_BAD_ARG);
+ CHECK(ssol_mirror_setup(material, &mirror), RES_BAD_ARG);
mirror.roughness = get_shader_roughness;
CHECK(ssol_material_ref_put(material), RES_OK);
-
- CHECK(ssol_material_create_virtual(NULL, &material), RES_BAD_ARG);
- CHECK(ssol_material_create_virtual(dev, NULL), RES_BAD_ARG);
- CHECK(ssol_material_create_virtual(dev, &material), RES_OK);
-
- CHECK(ssol_material_ref_put(material), RES_OK);
CHECK(ssol_param_buffer_ref_put(pbuf), RES_OK);
+}
+
+static void
+test_matte(struct ssol_device* dev)
+{
+ struct ssol_matte_shader matte = SSOL_MATTE_SHADER_NULL;
+ struct ssol_material* material;
+ enum ssol_material_type type;
CHECK(ssol_material_create_matte(NULL, NULL), RES_BAD_ARG);
CHECK(ssol_material_create_matte(dev, NULL), RES_BAD_ARG);
CHECK(ssol_material_create_matte(NULL, &material), RES_BAD_ARG);
CHECK(ssol_material_create_matte(dev, &material), RES_OK);
+ CHECK(ssol_material_get_type(material, &type), RES_OK);
+ CHECK(type, SSOL_MATERIAL_MATTE);
+
matte.normal = get_shader_normal;
matte.reflectivity = get_shader_reflectivity;
- CHECK(ssol_matte_set_shader(NULL, NULL), RES_BAD_ARG);
- CHECK(ssol_matte_set_shader(material, NULL), RES_BAD_ARG);
- CHECK(ssol_matte_set_shader(NULL, &matte), RES_BAD_ARG);
- CHECK(ssol_matte_set_shader(material, &matte), RES_OK);
+ CHECK(ssol_matte_setup(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_matte_setup(material, NULL), RES_BAD_ARG);
+ CHECK(ssol_matte_setup(NULL, &matte), RES_BAD_ARG);
+ CHECK(ssol_matte_setup(material, &matte), RES_OK);
matte.normal = NULL;
- CHECK(ssol_matte_set_shader(material, &matte), RES_BAD_ARG);
+ CHECK(ssol_matte_setup(material, &matte), RES_BAD_ARG);
matte.normal = get_shader_normal;
matte.reflectivity = NULL;
- CHECK(ssol_matte_set_shader(material, &matte), RES_BAD_ARG);
+ CHECK(ssol_matte_setup(material, &matte), RES_BAD_ARG);
CHECK(ssol_material_ref_put(material), RES_OK);
- CHECK(ssol_device_ref_put(dev), RES_OK);
+}
+
+static void
+test_thin_dielectric(struct ssol_device* dev)
+{
+ struct ssol_thin_dielectric_shader shader =
+ SSOL_THIN_DIELECTRIC_SHADER_NULL;
+ struct ssol_material* mtl;
+ struct ssol_medium mdm0 = SSOL_MEDIUM_VACUUM;
+ struct ssol_medium mdm1 = SSOL_MEDIUM_VACUUM;
+ enum ssol_material_type type;
+
+ CHECK(ssol_material_create_thin_dielectric(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_material_create_thin_dielectric(dev, NULL), RES_BAD_ARG);
+ CHECK(ssol_material_create_thin_dielectric(NULL, &mtl), RES_BAD_ARG);
+ CHECK(ssol_material_create_thin_dielectric(dev, &mtl), RES_OK);
+
+ CHECK(ssol_material_get_type(mtl, &type), RES_OK);
+ CHECK(type, SSOL_MATERIAL_THIN_DIELECTRIC);
+
+ shader.normal = get_shader_normal;
+
+ CHECK(ssol_thin_dielectric_setup(NULL, NULL, NULL, NULL, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, NULL, NULL, NULL, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, &shader, NULL, NULL, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, NULL, NULL, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, NULL, &mdm0, NULL, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, NULL, &mdm0, NULL, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, &shader, &mdm0, NULL, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, &mdm0, NULL, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, NULL, NULL, NULL, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, NULL, NULL, NULL, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, &shader, NULL, NULL, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, NULL, NULL, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, NULL, &mdm0, NULL, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, NULL, &mdm0, NULL, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, &shader, &mdm0, NULL, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, &mdm0, NULL, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, NULL, NULL, &mdm1, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, NULL, NULL, &mdm1, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, &shader, NULL, &mdm1, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, NULL, &mdm1, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, NULL, &mdm0, &mdm1, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, NULL, &mdm0, &mdm1, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, &shader, &mdm0, &mdm1, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, &mdm0, &mdm1, -1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, NULL, NULL, &mdm1, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, NULL, NULL, &mdm1, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, &shader, NULL, &mdm1, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, NULL, &mdm1, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, NULL, &mdm0, &mdm1, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, NULL, &mdm0, &mdm1, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(NULL, &shader, &mdm0, &mdm1, 1), RES_BAD_ARG);
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, &mdm0, &mdm1, 1), RES_OK);
+
+ shader.normal = NULL;
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, &mdm0, &mdm1, 1), RES_BAD_ARG);
+ shader.normal = get_shader_normal;
+
+ mdm0.absorptivity = -1;
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, &mdm0, &mdm1, 1), RES_BAD_ARG);
+ mdm0.absorptivity = SSOL_MEDIUM_VACUUM.absorptivity;
+
+ mdm0.refractive_index = 0;
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, &mdm0, &mdm1, 1), RES_BAD_ARG);
+ mdm0.refractive_index = SSOL_MEDIUM_VACUUM.refractive_index;
+
+ mdm1.absorptivity = -1;
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, &mdm0, &mdm1, 1), RES_BAD_ARG);
+ mdm1.absorptivity = SSOL_MEDIUM_VACUUM.absorptivity;
+
+ mdm1.refractive_index = 0;
+ CHECK(ssol_thin_dielectric_setup(mtl, &shader, &mdm0, &mdm1, 1), RES_BAD_ARG);
+ mdm1.refractive_index = SSOL_MEDIUM_VACUUM.refractive_index;
+
+ CHECK(ssol_material_ref_put(mtl), RES_OK);
+}
+
+static void
+test_dielectric(struct ssol_device* dev)
+{
+ struct ssol_dielectric_shader dielectric = SSOL_DIELECTRIC_SHADER_NULL;
+ struct ssol_material* material;
+ struct ssol_medium mdm0 = SSOL_MEDIUM_VACUUM;
+ struct ssol_medium mdm1 = SSOL_MEDIUM_VACUUM;
+ enum ssol_material_type type;
+
+ CHECK(ssol_material_create_dielectric(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_material_create_dielectric(dev, NULL), RES_BAD_ARG);
+ CHECK(ssol_material_create_dielectric(NULL, &material), RES_BAD_ARG);
+ CHECK(ssol_material_create_dielectric(dev, &material), RES_OK);
+
+ CHECK(ssol_material_get_type(material, &type), RES_OK);
+ CHECK(type, SSOL_MATERIAL_DIELECTRIC);
+
+ dielectric.normal = get_shader_normal;
+
+ CHECK(ssol_dielectric_setup(NULL, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(material, NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(NULL, &dielectric, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(material, &dielectric, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(NULL, NULL, &mdm0, NULL), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(material, NULL, &mdm0, NULL), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(NULL, &dielectric, &mdm0, NULL), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(material, &dielectric, &mdm0, NULL), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(NULL, NULL, NULL, &mdm1), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(material, NULL, NULL, &mdm1), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(NULL, &dielectric, NULL, &mdm1), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(material, &dielectric, NULL, &mdm1), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(NULL, NULL, &mdm0, &mdm1), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(material, NULL, &mdm0, &mdm1), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(NULL, &dielectric, &mdm0, &mdm1), RES_BAD_ARG);
+ CHECK(ssol_dielectric_setup(material, &dielectric, &mdm0, &mdm1), RES_OK);
+
+ dielectric.normal = NULL;
+ CHECK(ssol_dielectric_setup(NULL, &dielectric, &mdm0, &mdm1), RES_BAD_ARG);
+ dielectric.normal = get_shader_normal;
+
+ mdm0.refractive_index = 0;
+ CHECK(ssol_dielectric_setup(NULL, &dielectric, &mdm0, &mdm1), RES_BAD_ARG);
+ mdm0.refractive_index = SSOL_MEDIUM_VACUUM.refractive_index;
+
+ mdm1.refractive_index = 0;
+ CHECK(ssol_dielectric_setup(NULL, &dielectric, &mdm0, &mdm1), RES_BAD_ARG);
+ mdm1.refractive_index = SSOL_MEDIUM_VACUUM.refractive_index;
- logger_release(&logger);
+ mdm0.absorptivity = -1;
+ CHECK(ssol_dielectric_setup(NULL, &dielectric, &mdm0, &mdm1), RES_BAD_ARG);
+ mdm0.absorptivity = SSOL_MEDIUM_VACUUM.refractive_index;
+
+ mdm1.absorptivity = -1;
+ CHECK(ssol_dielectric_setup(NULL, &dielectric, &mdm0, &mdm1), RES_BAD_ARG);
+ mdm1.refractive_index = SSOL_MEDIUM_VACUUM.refractive_index;
+
+ CHECK(ssol_material_ref_put(material), RES_OK);
+}
+
+static void
+test_virtual(struct ssol_device* dev)
+{
+ struct ssol_material* material;
+ enum ssol_material_type type;
+
+ CHECK(ssol_material_create_virtual(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_material_create_virtual(NULL, &material), RES_BAD_ARG);
+ CHECK(ssol_material_create_virtual(dev, NULL), RES_BAD_ARG);
+ CHECK(ssol_material_create_virtual(dev, &material), RES_OK);
+
+ CHECK(ssol_material_get_type(material, &type), RES_OK);
+ CHECK(type, SSOL_MATERIAL_VIRTUAL);
+
+ CHECK(ssol_material_ref_put(material), RES_OK);
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct ssol_device* dev;
+ (void) argc, (void) argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(ssol_device_create
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+
+ test_mirror(dev);
+ test_matte(dev);
+ test_thin_dielectric(dev);
+ test_dielectric(dev);
+ test_virtual(dev);
+
+ CHECK(ssol_device_ref_put(dev), RES_OK);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
@@ -117,3 +283,4 @@ main(int argc, char** argv)
return 0;
}
+
diff --git a/src/test_ssol_materials.h b/src/test_ssol_materials.h
@@ -90,4 +90,55 @@ get_shader_roughness
*val = 0;
}
+static INLINE void
+get_shader_absorption
+ (struct ssol_device* dev,
+ struct ssol_param_buffer* buf,
+ const double wavelength,
+ const double P[3],
+ const double Ng[3],
+ const double Ns[3],
+ const double uv[2],
+ const double w[3],
+ double* val)
+{
+ (void)dev, (void)buf, (void)wavelength;
+ (void)P, (void)Ng, (void)Ns, (void)uv, (void) w;
+ *val = 0;
+}
+
+static INLINE void
+get_shader_thickness
+ (struct ssol_device* dev,
+ struct ssol_param_buffer* buf,
+ const double wavelength,
+ const double P[3],
+ const double Ng[3],
+ const double Ns[3],
+ const double uv[2],
+ const double w[3],
+ double* val)
+{
+ (void)dev, (void)buf, (void)wavelength;
+ (void)P, (void)Ng, (void)Ns, (void)uv, (void) w;
+ *val = 1;
+}
+
+static INLINE void
+get_shader_refractive_index
+ (struct ssol_device* dev,
+ struct ssol_param_buffer* buf,
+ const double wavelength,
+ const double P[3],
+ const double Ng[3],
+ const double Ns[3],
+ const double uv[2],
+ const double w[3],
+ double* val)
+{
+ (void)dev, (void)buf, (void)wavelength;
+ (void)P, (void)Ng, (void)Ns, (void)uv, (void) w;
+ *val = 1.5;
+}
+
#endif /* TEST_SSOL_MATERIALS_H */
diff --git a/src/test_ssol_object.c b/src/test_ssol_object.c
@@ -16,12 +16,9 @@
#include "ssol.h"
#include "test_ssol_utils.h"
-#include <rsys/logger.h>
-
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssol_shape* shape;
@@ -33,13 +30,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssol_material_create_virtual(dev, &mtl), RES_OK);
CHECK(ssol_material_create_virtual(dev, &mtl2), RES_OK);
CHECK(ssol_shape_create_punched_surface(dev, &shape), RES_OK);
@@ -88,7 +80,6 @@ main(int argc, char** argv)
CHECK(ssol_material_ref_put(mtl2), RES_OK);
CHECK(ssol_device_ref_put(dev), RES_OK);
- logger_release(&logger);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_rect2D_geometry.h b/src/test_ssol_rect2D_geometry.h
@@ -18,25 +18,41 @@
/*******************************************************************************
* Rectangle polygon
******************************************************************************/
-#if !defined(HALF_X)
-#error "Missing the HALF_X macro defining the rectangle size"
+#if !defined(HALF_X) && !(defined(X_MIN) && defined(X_MAX))
+#error "Missing the HALF_X or X_MIN and X_MAX macros defining the rectangle size"
#endif
-#if !defined(HALF_Y)
-#error "Missing the HALF_Y macro defining the rectangle size"
+#if !defined(HALF_Y) && !(defined(Y_MIN) && defined(Y_MAX))
+#error "Missing the HALF_Y or Y_MIN and Y_MAX macros defining the rectangle size"
#endif
#if !defined(POLYGON_NAME)
-#error "Missing the POLYGON_NAME macro defining the polygon name"
+#error "Missing the POLYGON_NAME macro defining the rectangle name"
#endif
#define EDGES__ CONCAT(POLYGON_NAME, _EDGES__)
#define POLY_NVERTS__ CONCAT(POLYGON_NAME, _NVERTS__)
+#if !defined(X_MIN)
+#define X_MIN (float)(-(HALF_X))
+#endif
+
+#if !defined(X_MAX)
+#define X_MAX (float)(HALF_X)
+#endif
+
+#if !defined(Y_MIN)
+#define Y_MIN (float)(-(HALF_Y))
+#endif
+
+#if !defined(Y_MAX)
+#define Y_MAX (float)(HALF_Y)
+#endif
+
/* should be const but scpr expects non-const data */
static double EDGES__ [] = {
- -HALF_X, -HALF_Y,
- -HALF_X, HALF_Y,
- HALF_X, HALF_Y,
- HALF_X, -HALF_Y,
+ X_MIN, Y_MIN,
+ X_MIN, Y_MAX,
+ X_MAX, Y_MAX,
+ X_MAX, Y_MIN
};
const unsigned POLY_NVERTS__ = sizeof(EDGES__) / sizeof(double[2]);
@@ -46,4 +62,8 @@ const unsigned POLY_NVERTS__ = sizeof(EDGES__) / sizeof(double[2]);
#undef HALF_X
#undef HALF_Y
+#undef X_MIN
+#undef X_MAX
+#undef Y_MIN
+#undef Y_MAX
#undef POLYGON_NAME
diff --git a/src/test_ssol_rect_geometry.h b/src/test_ssol_rect_geometry.h
@@ -18,11 +18,11 @@
/*******************************************************************************
* Rectangle plane
******************************************************************************/
-#if !defined(HALF_X)
-#error "Missing the HALF_X macro defining the rectangle size"
+#if !defined(HALF_X) && !(defined(X_MIN) && defined(X_MAX))
+#error "Missing the HALF_X or X_MIN and X_MAX macros defining the rectangle size"
#endif
-#if !defined(HALF_Y)
-#error "Missing the HALF_Y macro defining the rectangle size"
+#if !defined(HALF_Y) && !(defined(Y_MIN) && defined(Y_MAX))
+#error "Missing the HALF_Y or Y_MIN and Y_MAX macros defining the rectangle size"
#endif
#if !defined(PLANE_NAME)
#error "Missing the DARRAY_NAME macro defining the rectangle name"
@@ -34,11 +34,27 @@
#define RECT_NVERTS__ CONCAT(PLANE_NAME, _NVERTS__)
#define RECT_NTRIS__ CONCAT(PLANE_NAME, _NTRIS__)
+#if !defined(X_MIN)
+#define X_MIN (float)(-(HALF_X))
+#endif
+
+#if !defined(X_MAX)
+#define X_MAX (float)(HALF_X)
+#endif
+
+#if !defined(Y_MIN)
+#define Y_MIN (float)(-(HALF_Y))
+#endif
+
+#if !defined(Y_MAX)
+#define Y_MAX (float)(HALF_Y)
+#endif
+
static const float EDGES__ [] = {
- (float) -HALF_X, (float) -HALF_Y, 0.f,
- (float) HALF_X, (float) -HALF_Y, 0.f,
- (float) HALF_X, (float) HALF_Y, 0.f,
- (float) -HALF_X, (float) HALF_Y, 0.f
+ X_MIN, Y_MIN, 0.f,
+ X_MAX, Y_MIN, 0.f,
+ X_MAX, Y_MAX, 0.f,
+ X_MIN, Y_MAX, 0.f
};
const unsigned RECT_NVERTS__ = sizeof(EDGES__) / sizeof(float[3]);
@@ -56,4 +72,8 @@ static const struct desc RECT_DESC__ = { EDGES__, TRG_IDS__ };
#undef HALF_X
#undef HALF_Y
+#undef X_MIN
+#undef X_MAX
+#undef Y_MIN
+#undef Y_MAX
#undef PLANE_NAME
diff --git a/src/test_ssol_scene.c b/src/test_ssol_scene.c
@@ -15,8 +15,35 @@
#include "ssol.h"
#include "test_ssol_utils.h"
+#include "test_ssol_geometries.h"
-#include <rsys/logger.h>
+#include <rsys/float3.h>
+
+struct scene_ctx {
+ struct ssol_instance* instance;
+ struct ssol_instance* instance2;
+ int instance_found;
+ int instance2_found;
+};
+
+static res_T
+instance_func(struct ssol_instance* inst, void* context)
+{
+ struct scene_ctx* ctx = context;
+ NCHECK(inst, NULL);
+ if(!ctx) return RES_BAD_ARG;
+
+ if(inst == ctx->instance) {
+ CHECK(ctx->instance_found, 0);
+ ctx->instance_found = 1;
+ } else if(inst == ctx->instance2) {
+ CHECK(ctx->instance2_found, 0);
+ ctx->instance2_found = 1;
+ } else {
+ FATAL("Unreachable code.\n");
+ }
+ return RES_OK;
+}
static void
get_wlen(const size_t i, double* wlen, double* data, void* ctx)
@@ -32,13 +59,30 @@ get_wlen(const size_t i, double* wlen, double* data, void* ctx)
int
main(int argc, char** argv)
{
- struct logger logger;
+ const float tall_block[] = {
+ 423.f, 247.f, 0.f,
+ 265.f, 296.f, 0.f,
+ 314.f, 456.f, 0.f,
+ 472.f, 406.f, 0.f,
+ 423.f, 247.f, 330.f,
+ 265.f, 296.f, 330.f,
+ 314.f, 456.f, 330.f,
+ 472.f, 406.f, 330.f
+ };
+ const unsigned block_ids[] = {
+ 4, 5, 6, 6, 7, 4,
+ 1, 2, 6, 6, 5, 1,
+ 0, 3, 7, 7, 4, 0,
+ 2, 3, 7, 7, 6, 2,
+ 0, 1, 5, 5, 4, 0
+ };
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssol_shape* shape;
struct ssol_material* material;
struct ssol_object* object;
struct ssol_instance* instance;
+ struct ssol_instance* instance2;
struct ssol_sun* sun;
struct ssol_sun* sun2;
struct ssol_scene* scene;
@@ -46,18 +90,17 @@ main(int argc, char** argv)
struct ssol_spectrum* spectrum;
struct ssol_atmosphere* atm;
struct ssol_atmosphere* atm2;
+ struct ssol_vertex_data vdata;
+ struct scene_ctx ctx;
+ struct desc desc;
double transform[12];
+ float lower[3], upper[3], tmp[3];
(void) argc, (void) argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssol_material_create_virtual(dev, &material), RES_OK);
@@ -65,6 +108,7 @@ main(int argc, char** argv)
CHECK(ssol_object_create(dev, &object), RES_OK);
CHECK(ssol_object_add_shaded_shape(object, shape, material, material), RES_OK);
CHECK(ssol_object_instantiate(object, &instance), RES_OK);
+ CHECK(ssol_object_instantiate(object, &instance2), RES_OK);
CHECK(ssol_instance_set_transform(instance, transform), RES_OK);
CHECK(ssol_sun_create_directional(dev, &sun), RES_OK);
CHECK(ssol_sun_create_directional(dev, &sun2), RES_OK);
@@ -85,11 +129,28 @@ main(int argc, char** argv)
CHECK(ssol_scene_attach_instance(scene, NULL), RES_BAD_ARG);
CHECK(ssol_scene_attach_instance(scene, instance), RES_OK);
CHECK(ssol_scene_attach_instance(scene, instance), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, instance2), RES_OK);
+
+ ctx.instance = instance;
+ ctx.instance2 = instance2;
+ ctx.instance_found = 0;
+ ctx.instance2_found = 0;
+ CHECK(ssol_scene_for_each_instance(NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_scene_for_each_instance(scene, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_scene_for_each_instance(NULL, instance_func, NULL), RES_BAD_ARG);
+ CHECK(ssol_scene_for_each_instance(scene, instance_func, NULL), RES_BAD_ARG);
+ CHECK(ssol_scene_for_each_instance(NULL, NULL, &ctx), RES_BAD_ARG);
+ CHECK(ssol_scene_for_each_instance(scene, NULL, &ctx), RES_BAD_ARG);
+ CHECK(ssol_scene_for_each_instance(NULL, instance_func, &ctx), RES_BAD_ARG);
+ CHECK(ssol_scene_for_each_instance(scene, instance_func, &ctx), RES_OK);
+ CHECK(ctx.instance_found, 1);
+ CHECK(ctx.instance2_found, 1);
CHECK(ssol_scene_detach_instance(NULL, instance), RES_BAD_ARG);
CHECK(ssol_scene_detach_instance(scene, NULL), RES_BAD_ARG);
CHECK(ssol_scene_detach_instance(scene, instance), RES_OK);
CHECK(ssol_scene_detach_instance(scene, instance), RES_BAD_ARG);
+ CHECK(ssol_scene_detach_instance(scene, instance2), RES_OK);
CHECK(ssol_scene_attach_instance(scene, instance), RES_OK);
CHECK(ssol_scene_attach_instance(scene2, instance), RES_OK);
@@ -154,8 +215,54 @@ main(int argc, char** argv)
CHECK(ssol_scene_ref_put(scene), RES_OK);
CHECK(ssol_scene_ref_put(scene2), RES_OK);
+ CHECK(ssol_shape_ref_put(shape), RES_OK);
+ CHECK(ssol_object_ref_put(object), RES_OK);
+ CHECK(ssol_instance_ref_put(instance), RES_OK);
+
+ CHECK(ssol_scene_create(dev, &scene), RES_OK);
+ CHECK(ssol_shape_create_mesh(dev, &shape), RES_OK);
+ CHECK(ssol_object_create(dev, &object), RES_OK);
+
+ vdata.usage = SSOL_POSITION;
+ vdata.get = get_position;
+ desc.vertices = tall_block;;
+ desc.indices = block_ids;
+
+ CHECK(ssol_mesh_setup(shape, 10, get_ids, 8, &vdata, 1, &desc), RES_OK);
+ CHECK(ssol_object_add_shaded_shape(object, shape, material, material), RES_OK);
+ CHECK(ssol_object_instantiate(object, &instance), RES_OK);
+
+ CHECK(ssol_scene_compute_aabb(NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_scene_compute_aabb(scene, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_scene_compute_aabb(NULL, lower, NULL), RES_BAD_ARG);
+ CHECK(ssol_scene_compute_aabb(scene, lower, NULL), RES_BAD_ARG);
+ CHECK(ssol_scene_compute_aabb(NULL, NULL, upper), RES_BAD_ARG);
+ CHECK(ssol_scene_compute_aabb(scene, NULL, upper), RES_BAD_ARG);
+ CHECK(ssol_scene_compute_aabb(NULL, lower, upper), RES_BAD_ARG);
+ CHECK(ssol_scene_compute_aabb(scene, lower, upper), RES_OK);
+
+ /* Empty scene */
+ CHECK(lower[0] > upper[0], 1);
+ CHECK(lower[1] > upper[1], 1);
+ CHECK(lower[2] > upper[2], 1);
+
+ CHECK(ssol_scene_attach_instance(scene, instance), RES_OK);
+ CHECK(ssol_scene_compute_aabb(scene, lower, upper), RES_OK);
+ CHECK(f3_eq_eps(lower, f3(tmp, 265.f, 247.f, 0.f), 1.e-6f), 1);
+ CHECK(f3_eq_eps(upper, f3(tmp, 472.f, 456.f, 330.f), 1.e-6f), 1);
+
+ CHECK(ssol_scene_clear(scene), RES_OK);
+ CHECK(ssol_scene_compute_aabb(scene, lower, upper), RES_OK);
+
+ /* Empty scene */
+ CHECK(lower[0] > upper[0], 1);
+ CHECK(lower[1] > upper[1], 1);
+ CHECK(lower[2] > upper[2], 1);
+
+ CHECK(ssol_scene_ref_put(scene), RES_OK);
CHECK(ssol_instance_ref_put(instance), RES_OK);
+ CHECK(ssol_instance_ref_put(instance2), RES_OK);
CHECK(ssol_object_ref_put(object), RES_OK);
CHECK(ssol_shape_ref_put(shape), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
@@ -166,8 +273,6 @@ main(int argc, char** argv)
CHECK(ssol_device_ref_put(dev), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_shape.c b/src/test_ssol_shape.c
@@ -21,19 +21,14 @@
#define HALF_Y 1
#include "test_ssol_rect_geometry.h"
-#include <rsys/logger.h>
-
-/*******************************************************************************
- * Test main program
- ******************************************************************************/
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssol_shape* shape;
- struct ssol_vertex_data attribs[3] = { SSOL_VERTEX_DATA_NULL__, SSOL_VERTEX_DATA_NULL__, SSOL_VERTEX_DATA_NULL__ };
+ struct ssol_vertex_data attribs[3] =
+ {SSOL_VERTEX_DATA_NULL__, SSOL_VERTEX_DATA_NULL__, SSOL_VERTEX_DATA_NULL__};
struct ssol_punched_surface punched_surface = SSOL_PUNCHED_SURFACE_NULL;
struct ssol_carving carving = SSOL_CARVING_NULL;
struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT;
@@ -41,17 +36,15 @@ main(int argc, char** argv)
-1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 0.f, -2.f
};
const size_t npolygon_verts = sizeof(polygon)/sizeof(double[2]);
+ double val[3];
+ unsigned ids[3];
+ unsigned i, n;
(void) argc, (void) argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssol_shape_create_mesh(NULL, NULL), RES_BAD_ARG);
CHECK(ssol_shape_create_mesh(dev, NULL), RES_BAD_ARG);
@@ -86,6 +79,72 @@ main(int argc, char** argv)
CHECK(ssol_mesh_setup(shape, SQUARE_NTRIS__, get_ids, SQUARE_NVERTS__,
attribs, 3, (void*)&SQUARE_DESC__), RES_OK);
+ CHECK(ssol_shape_get_vertices_count(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertices_count(shape, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertices_count(NULL, &n), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertices_count(shape, &n), RES_OK);
+ CHECK(n, SQUARE_NVERTS__);
+
+ CHECK(ssol_shape_get_vertex_attrib(NULL, n, (unsigned)-1, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(shape, n, (unsigned)-1, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(NULL, 0, (unsigned)-1, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(shape, 0, (unsigned)-1, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(NULL, n, SSOL_POSITION, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(shape, n, SSOL_POSITION, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(NULL, 0, SSOL_POSITION, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(shape, 0, SSOL_POSITION, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(NULL, n, (unsigned)-1, val), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(shape, n, (unsigned)-1, val), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(NULL, 0, (unsigned)-1, val), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(shape, 0, (unsigned)-1,val), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(NULL, n, SSOL_POSITION, val), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(shape, n, SSOL_POSITION, val), RES_BAD_ARG);
+ CHECK(ssol_shape_get_vertex_attrib(NULL, 0, SSOL_POSITION, val), RES_BAD_ARG);
+
+ FOR_EACH(i, 0, n) {
+ float valf[3];
+
+ CHECK(ssol_shape_get_vertex_attrib(shape, i, SSOL_POSITION, val), RES_OK);
+ get_position(i, valf, (void*)&SQUARE_DESC__);
+ CHECK((float)val[0], valf[0]);
+ CHECK((float)val[1], valf[1]);
+ CHECK((float)val[2], valf[2]);
+
+ CHECK(ssol_shape_get_vertex_attrib(shape, i, SSOL_NORMAL, val), RES_OK);
+ get_normal(i, valf, (void*)&SQUARE_DESC__);
+ CHECK((float)val[0], valf[0]);
+ CHECK((float)val[1], valf[1]);
+ CHECK((float)val[2], valf[2]);
+
+ CHECK(ssol_shape_get_vertex_attrib(shape, i, SSOL_TEXCOORD, val), RES_OK);
+ get_uv(i, valf, (void*)&SQUARE_DESC__);
+ CHECK((float)val[0], valf[0]);
+ CHECK((float)val[1], valf[1]);
+ }
+
+ CHECK(ssol_shape_get_triangles_count(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_triangles_count(shape, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_triangles_count(NULL, &n), RES_BAD_ARG);
+ CHECK(ssol_shape_get_triangles_count(shape, &n), RES_OK);
+ CHECK(n, SQUARE_NTRIS__);
+
+ CHECK(ssol_shape_get_triangle_indices(NULL, n, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_triangle_indices(shape, n, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_triangle_indices(NULL, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_triangle_indices(shape, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_shape_get_triangle_indices(NULL, n, ids), RES_BAD_ARG);
+ CHECK(ssol_shape_get_triangle_indices(shape, n, ids), RES_BAD_ARG);
+ CHECK(ssol_shape_get_triangle_indices(NULL, 0, ids), RES_BAD_ARG);
+
+ FOR_EACH(i, 0, n) {
+ unsigned ids2[3];
+ CHECK(ssol_shape_get_triangle_indices(shape, i, ids), RES_OK);
+ get_ids(i, ids2, (void*)&SQUARE_DESC__);
+ CHECK(ids[0], ids2[0]);
+ CHECK(ids[1], ids2[1]);
+ CHECK(ids[2], ids2[2]);
+ }
+
CHECK(ssol_shape_ref_put(shape), RES_OK);
CHECK(ssol_shape_create_punched_surface(NULL, NULL), RES_BAD_ARG);
@@ -141,6 +200,19 @@ main(int argc, char** argv)
CHECK(ssol_punched_surface_setup(shape, &punched_surface), RES_BAD_ARG);
quadric.data.parabol.focal = 1;
+ quadric.type = SSOL_QUADRIC_HYPERBOL;
+ quadric.data.hyperbol.real_focal = 1;
+ quadric.data.hyperbol.img_focal = 1;
+ CHECK(ssol_punched_surface_setup(shape, &punched_surface), RES_OK);
+
+ quadric.data.hyperbol.real_focal = 0;
+ CHECK(ssol_punched_surface_setup(shape, &punched_surface), RES_BAD_ARG);
+ quadric.data.hyperbol.real_focal = 1;
+
+ quadric.data.hyperbol.img_focal = 0;
+ CHECK(ssol_punched_surface_setup(shape, &punched_surface), RES_BAD_ARG);
+ quadric.data.hyperbol.img_focal = 1;
+
quadric.type = SSOL_QUADRIC_PARABOLIC_CYLINDER;
quadric.data.parabolic_cylinder.focal = 1;
CHECK(ssol_punched_surface_setup(shape, &punched_surface), RES_OK);
@@ -150,11 +222,8 @@ main(int argc, char** argv)
quadric.data.parabolic_cylinder.focal = 1;
CHECK(ssol_shape_ref_put(shape), RES_OK);
-
CHECK(ssol_device_ref_put(dev), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_solver1.c b/src/test_ssol_solver1.c
@@ -24,7 +24,6 @@
#define PLANE_NAME SQUARE
#include "test_ssol_rect_geometry.h"
-#include <rsys/logger.h>
#include <rsys/double33.h>
#include <star/s3d.h>
@@ -49,11 +48,11 @@ int
main(int argc, char** argv)
{
struct spectrum_desc desc = {0};
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssp_rng* rng;
struct ssol_scene* scene;
+ struct ssol_shape* dummy;
struct ssol_shape* square;
struct ssol_vertex_data attribs[1] = { SSOL_VERTEX_DATA_NULL__ };
struct ssol_material *m_mtl, *m_mtl2;
@@ -70,7 +69,12 @@ main(int argc, char** argv)
struct ssol_spectrum* abs;
struct ssol_atmosphere* atm;
struct ssol_estimator* estimator;
- struct ssol_estimator_status status;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
+ struct ssol_mc_shape mc_shape;
+ struct ssol_mc_primitive mc_prim;
+ struct ssol_path path;
+ struct ssol_path_vertex vertex;
double dir[3];
double wavelengths[3] = { 1, 2, 3 };
double intensities[3] = { 1, 0.8, 1 };
@@ -80,11 +84,12 @@ main(int argc, char** argv)
double transform1[12]; /* 3x4 column major matrix */
double transform2[12]; /* 3x4 column major matrix */
double dbl;
- size_t count, fcount;
+ size_t i, count, fcount;
FILE* tmp = NULL;
double m, std;
double a_m, a_std;
uint32_t r_id;
+ unsigned ntris;
(void) argc, (void) argv;
@@ -100,13 +105,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
@@ -122,18 +122,17 @@ main(int argc, char** argv)
CHECK(ssol_scene_create(dev, &scene), RES_OK);
CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
- CHECK(ssol_solve(NULL, rng, 10, NULL, &estimator), RES_BAD_ARG);
- CHECK(ssol_solve(scene, NULL, 10, NULL, &estimator), RES_BAD_ARG);
- CHECK(ssol_solve(scene, rng, 0, NULL, &estimator), RES_BAD_ARG);
- CHECK(ssol_solve(scene, rng, 10, NULL, &estimator), RES_BAD_ARG);
- CHECK(ssol_solve(scene, rng, 10, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_solve(NULL, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, NULL, 10, 0, NULL, &estimator), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 0, 0, NULL, &estimator), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, NULL), RES_BAD_ARG);
/* No geometry */
- CHECK(ssol_solve(scene, rng, 10, NULL, &estimator), RES_BAD_ARG);
-
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
/* Create scene content */
-
+ CHECK(ssol_shape_create_mesh(dev, &dummy), RES_OK);
CHECK(ssol_shape_create_mesh(dev, &square), RES_OK);
attribs[0].usage = SSOL_POSITION;
attribs[0].get = get_position;
@@ -144,17 +143,17 @@ main(int argc, char** argv)
shader.normal = get_shader_normal;
shader.reflectivity = get_shader_reflectivity;
shader.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK);
+ CHECK(ssol_mirror_setup(m_mtl, &shader), RES_OK);
CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
CHECK(ssol_object_create(dev, &m_object), RES_OK);
CHECK(ssol_object_add_shaded_shape(m_object, square, m_mtl, m_mtl), RES_OK);
CHECK(ssol_object_instantiate(m_object, &heliostat), RES_OK);
- CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, heliostat), RES_OK);
CHECK(ssol_object_instantiate(m_object, &secondary), RES_OK);
- CHECK(ssol_instance_set_receiver(secondary, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(secondary, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_set_transform(secondary, transform1), RES_OK);
CHECK(ssol_scene_attach_instance(scene, secondary), RES_OK);
@@ -162,10 +161,49 @@ main(int argc, char** argv)
CHECK(ssol_object_add_shaded_shape(t_object, square, v_mtl, v_mtl), RES_OK);
CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
CHECK(ssol_instance_set_transform(target, transform2), RES_OK);
- CHECK(ssol_instance_set_receiver(target, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
- CHECK(ssol_solve(scene, rng, 1, NULL, &estimator), RES_OK);
+ CHECK(ssol_solve
+ (scene, rng, 1, &SSOL_PATH_TRACKER_DEFAULT, NULL, &estimator), RES_OK);
+
+ CHECK(ssol_estimator_get_tracked_paths_count(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_paths_count(estimator, NULL), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_paths_count(NULL, &count), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_paths_count(estimator, &count), RES_OK);
+ CHECK(count, 1);
+
+ CHECK(ssol_estimator_get_tracked_path(NULL, count, NULL), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_path(estimator, count, NULL), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_path(NULL, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_path(estimator, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_path(NULL, count, &path), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_path(estimator, count, &path), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_path(NULL, 0, &path), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_tracked_path(estimator, 0, &path), RES_OK);
+
+ CHECK(ssol_path_get_vertices_count(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_path_get_vertices_count(&path, NULL), RES_BAD_ARG);
+ CHECK(ssol_path_get_vertices_count(NULL, &count), RES_BAD_ARG);
+ CHECK(ssol_path_get_vertices_count(&path, &count), RES_OK);
+ NCHECK(count, 0);
+
+ CHECK(ssol_path_get_vertex(NULL, count, NULL), RES_BAD_ARG);
+ CHECK(ssol_path_get_vertex(&path, count, NULL), RES_BAD_ARG);
+ CHECK(ssol_path_get_vertex(NULL, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_path_get_vertex(&path, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_path_get_vertex(NULL, count, &vertex), RES_BAD_ARG);
+ CHECK(ssol_path_get_vertex(&path, count, &vertex), RES_BAD_ARG);
+ CHECK(ssol_path_get_vertex(NULL, 0, &vertex), RES_BAD_ARG);
+ FOR_EACH(i, 0, count) {
+ CHECK(ssol_path_get_vertex(&path, i, &vertex), RES_OK);
+ }
+
+ CHECK(ssol_estimator_get_sampled_area(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_sampled_area(estimator, NULL), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_sampled_area(NULL, &dbl), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_sampled_area(estimator, &dbl), RES_OK);
+ CHECK(eq_eps(dbl, 12, 1.e-6), 1);
CHECK(ssol_estimator_get_count(NULL, NULL), RES_BAD_ARG);
CHECK(ssol_estimator_get_count(estimator, NULL), RES_BAD_ARG);
@@ -179,12 +217,9 @@ main(int argc, char** argv)
CHECK(ssol_estimator_get_failed_count(estimator, &fcount), RES_OK);
CHECK(fcount, 0);
- #define GET_STATUS ssol_estimator_get_status
- CHECK(GET_STATUS(NULL, SSOL_STATUS_MISSING, &status), RES_BAD_ARG);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_TYPES_COUNT__, &status), RES_BAD_ARG);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, NULL), RES_BAD_ARG);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- #undef GET_STATUS
+ CHECK(ssol_estimator_get_mc_global(NULL, &mc_global), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_mc_global(estimator, NULL), RES_BAD_ARG);
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
CHECK(ssol_estimator_ref_get(NULL), RES_BAD_ARG);
CHECK(ssol_estimator_ref_get(estimator), RES_OK);
@@ -196,7 +231,7 @@ main(int argc, char** argv)
CHECK(ssol_instance_sample(target, 0), RES_OK);
CHECK(ssol_instance_sample(secondary, 0), RES_OK);
CHECK(ssol_instance_sample(heliostat, 0), RES_OK);
- CHECK(ssol_solve(scene, rng, 10, NULL, &estimator), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
CHECK(ssol_instance_sample(target, 1), RES_OK);
CHECK(ssol_instance_sample(secondary, 1), RES_OK);
@@ -204,7 +239,7 @@ main(int argc, char** argv)
/* No attached sun */
CHECK(ssol_scene_detach_sun(scene, sun), RES_OK);
- CHECK(ssol_solve(scene, rng, 10, NULL, &estimator), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
CHECK(ssol_sun_ref_put(sun), RES_OK);
/* Sun with no spectrum */
@@ -212,7 +247,7 @@ main(int argc, char** argv)
CHECK(ssol_sun_set_direction(sun, d3(dir, 1, 0, -1)), RES_OK);
CHECK(ssol_sun_set_dni(sun, 1000), RES_OK);
CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
- CHECK(ssol_solve(scene, rng, 10, NULL, &estimator), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
CHECK(ssol_scene_detach_sun(scene, sun), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
@@ -221,20 +256,20 @@ main(int argc, char** argv)
CHECK(ssol_sun_set_direction(sun, d3(dir, 1, 0, -1)), RES_OK);
CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK);
CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
- CHECK(ssol_solve(scene, rng, 10, NULL, &estimator), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
CHECK(ssol_sun_set_dni(sun, 1000), RES_OK);
/* No receiver in scene */
- CHECK(ssol_instance_set_receiver(heliostat, 0), RES_OK);
- CHECK(ssol_instance_set_receiver(secondary, 0), RES_OK);
- CHECK(ssol_instance_set_receiver(target, 0), RES_OK);
- CHECK(ssol_solve(scene, rng, 10, NULL, &estimator), RES_OK);
- CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT), RES_OK);
- CHECK(ssol_instance_set_receiver(secondary, SSOL_FRONT), RES_OK);
- CHECK(ssol_instance_set_receiver(target, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat, 0, 0), RES_OK);
+ CHECK(ssol_instance_set_receiver(secondary, 0, 0), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, 0, 0), RES_OK);
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT, 0), RES_OK);
+ CHECK(ssol_instance_set_receiver(secondary, SSOL_FRONT, 0), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_estimator_ref_put(estimator), RES_OK);
- /* Spectra mismatch */
+ /* Spectra mismatch */
desc.wavelengths = mismatch;
desc.wavelengths = ka;
desc.count = 2;
@@ -243,7 +278,7 @@ main(int argc, char** argv)
CHECK(ssol_atmosphere_create_uniform(dev, &atm), RES_OK);
CHECK(ssol_atmosphere_set_uniform_absorption(atm, abs), RES_OK);
CHECK(ssol_scene_attach_atmosphere(scene, atm), RES_OK);
- CHECK(ssol_solve(scene, rng, 10, NULL, &estimator), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 10, 0, NULL, &estimator), RES_BAD_ARG);
CHECK(ssol_scene_detach_atmosphere(scene, atm), RES_OK);
CHECK(ssol_spectrum_ref_put(abs), RES_OK);
CHECK(ssol_atmosphere_ref_put(atm), RES_OK);
@@ -251,9 +286,9 @@ main(int argc, char** argv)
/* Can sample any geometry; variance is high */
NCHECK(tmp = tmpfile(), 0);
#define N__ 10000
-#define GET_STATUS ssol_estimator_get_status
-#define GET_RCV_STATUS ssol_estimator_get_receiver_status
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+#define GET_MC_RCV ssol_estimator_get_mc_receiver
+#define GET_MC_GLOBAL ssol_estimator_get_mc_global
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_instance_get_id(target, &r_id), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
CHECK(count, N__);
@@ -261,47 +296,40 @@ main(int argc, char** argv)
CHECK(fclose(tmp), 0);
CHECK(ssol_estimator_get_failed_count(estimator, &fcount), RES_OK);
CHECK(fcount, 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g", m, std);
+ printf("Ir = %g +/- %g; ", m, std);
#define COS cos(PI / 4)
-#define DNI 1000
+#define DNI 1000
#define DNI_cos (DNI * COS)
CHECK(eq_eps(m, 4 * DNI_cos, MMAX(4 * DNI_cos * 1e-2, 2*std)), 1);
#define SQR(x) ((x)*(x))
dbl = sqrt((SQR(12 * DNI_cos) / 3 - SQR(4 * DNI_cos)) / (double)count);
CHECK(eq_eps(std, dbl, dbl*1e-2), 1);
/* Target was sampled but shadowed by secondary */
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 2 * dbl), 1);
- CHECK(status.N, count);
- CHECK(status.Nf, fcount);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 2*status.irradiance.SE), 1);
- CHECK(status.N, count);
- CHECK(status.Nf, fcount);
- CHECK(GET_RCV_STATUS(NULL, NULL, SSOL_BACK, NULL), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(estimator, NULL, SSOL_BACK, NULL), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(NULL, target, SSOL_BACK, NULL), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_BACK, NULL), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(NULL, NULL, SSOL_BACK, &status), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(estimator, NULL, SSOL_BACK, &status), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(NULL, target, SSOL_BACK, &status), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_BACK, &status), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(NULL, NULL, SSOL_FRONT, NULL), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(estimator, NULL, SSOL_FRONT, NULL), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(NULL, target, SSOL_FRONT, NULL), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, NULL), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(NULL, NULL, SSOL_FRONT, &status), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(estimator, NULL, SSOL_FRONT, &status), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(NULL, target, SSOL_FRONT, &status), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std, 1e-4), 1);
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g; ", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g; ", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, m, 2 * dbl), 1);
+ CHECK(eq_eps(mc_global.missing.E, m, 2*mc_global.missing.SE), 1);
+ CHECK(GET_MC_RCV(NULL, NULL, SSOL_BACK, NULL), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(estimator, NULL, SSOL_BACK, NULL), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(NULL, target, SSOL_BACK, NULL), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_BACK, NULL), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(NULL, NULL, SSOL_BACK, &mc_rcv), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(estimator, NULL, SSOL_BACK, &mc_rcv), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(NULL, target, SSOL_BACK, &mc_rcv), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_BACK, &mc_rcv), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(NULL, NULL, SSOL_FRONT, NULL), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(estimator, NULL, SSOL_FRONT, NULL), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(NULL, target, SSOL_FRONT, NULL), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, NULL), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(NULL, NULL, SSOL_FRONT, &mc_rcv), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(estimator, NULL, SSOL_FRONT, &mc_rcv), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(NULL, target, SSOL_FRONT, &mc_rcv), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std, 1e-4), 1);
CHECK(ssol_estimator_ref_put(estimator), RES_OK);
/* Sample primary mirror only; variance is low */
@@ -309,27 +337,24 @@ main(int argc, char** argv)
CHECK(ssol_instance_sample(secondary, 0), RES_OK);
NCHECK(tmp = tmpfile(), 0);
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
CHECK(count, N__);
CHECK(pp_sum(tmp, (int32_t)r_id, count, &m, &std), RES_OK);
CHECK(fclose(tmp), 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g", m, std);
+ printf("Ir = %g +/- %g; ", m, std);
CHECK(eq_eps(m, 4 * DNI_cos, MMAX(4 * DNI_cos * 1e-2, std)), 1);
CHECK(eq_eps(std, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std, 1e-4), 1);
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g; ", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g; ", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std, 1e-4), 1);
CHECK(ssol_estimator_ref_put(estimator), RES_OK);
/* Check atmosphere model; with no absorption result is unchanged */
@@ -343,30 +368,27 @@ main(int argc, char** argv)
CHECK(ssol_scene_attach_atmosphere(scene, atm), RES_OK);
NCHECK(tmp = tmpfile(), 0);
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
CHECK(count, N__);
CHECK(pp_sum(tmp, (int32_t)r_id, count, &m, &std), RES_OK);
CHECK(fclose(tmp), 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g", m, std);
+ printf("Ir = %g +/- %g; ", m, std);
CHECK(eq_eps(m, 4 * DNI_cos, MMAX(4 * DNI_cos * 1e-2, std)), 1);
CHECK(eq_eps(std, 0, 1e-4), 1);
CHECK(ssol_scene_detach_atmosphere(scene, atm), RES_OK);
CHECK(ssol_spectrum_ref_put(abs), RES_OK);
CHECK(ssol_atmosphere_ref_put(atm), RES_OK);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std, 1e-4), 1);
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g; ", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g; ", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std, 1e-4), 1);
CHECK(ssol_estimator_ref_put(estimator), RES_OK);
/* Check atmosphere model and imperfect mirror: there are losses */
@@ -376,12 +398,12 @@ main(int argc, char** argv)
shader.normal = get_shader_normal;
shader.reflectivity = get_shader_reflectivity_2;
shader.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(m_mtl2, &shader), RES_OK);
+ CHECK(ssol_mirror_setup(m_mtl2, &shader), RES_OK);
CHECK(ssol_object_create(dev, &m_object2), RES_OK);
CHECK(ssol_object_add_shaded_shape(m_object2, square, m_mtl2, m_mtl2), RES_OK);
CHECK(ssol_object_instantiate(m_object2, &heliostat2), RES_OK);
- CHECK(ssol_instance_set_receiver(heliostat2, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat2, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, heliostat2), RES_OK);
#define KA 0.03
@@ -391,52 +413,91 @@ main(int argc, char** argv)
CHECK(ssol_atmosphere_create_uniform(dev, &atm), RES_OK);
CHECK(ssol_atmosphere_set_uniform_absorption(atm, abs), RES_OK);
CHECK(ssol_scene_attach_atmosphere(scene, atm), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 1), RES_OK);
NCHECK(tmp = tmpfile(), 0);
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
CHECK(count, N__);
CHECK(pp_sum(tmp, (int32_t)r_id, count, &a_m, &a_std), RES_OK);
CHECK(fclose(tmp), 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g", a_m, a_std);
+ printf("Ir = %g +/- %g; ", a_m, a_std);
#define K (exp(-KA * 4 * sqrt(2)))
- CHECK(eq_eps(a_m, REFLECTIVITY * 4 * K * DNI_cos,
+ CHECK(eq_eps(a_m, REFLECTIVITY * 4 * K * DNI_cos,
MMAX(4 * K * DNI_cos * 1e-1, a_std)), 1);
CHECK(eq_eps(a_std, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT,
- "Ir(target) = %g +/- %g (%.2g %%)",
- status.irradiance.E, status.irradiance.SE, 100 * status.irradiance.E / m);
- logger_print(&logger, LOG_OUTPUT,
- "Atmospheric Loss(target) = %g +/- %g (%.2g %%)",
- status.absorptivity_loss.E, status.absorptivity_loss.SE,
- 100 * status.absorptivity_loss.E / m);
- logger_print(&logger, LOG_OUTPUT,
- "Reflectivity Loss(target) = %g +/- %g (%.2g %%)",
- status.reflectivity_loss.E, status.reflectivity_loss.SE,
- 100 * status.reflectivity_loss.E / m);
- logger_print(&logger, LOG_OUTPUT,
- "Cos Loss(target) = %g +/- %g (%.2g %%)",
- status.cos_loss.E, status.cos_loss.SE, 100 * status.cos_loss.E / m);
- CHECK(eq_eps(status.irradiance.E, a_m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, a_std, 1e-4), 1);
- CHECK(eq_eps(status.irradiance.E + status.absorptivity_loss.E
- + status.reflectivity_loss.E, m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.E + status.absorptivity_loss.E
- + status.reflectivity_loss.E + status.cos_loss.E, 4 * DNI, 1e-8), 1);
- CHECK(eq_eps(status.cos_loss.E / (4 * DNI), 1 - COS, 1e-8), 1);
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g; ", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g\n", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf
+ ("\tIr(target) = %g +/- %g (%.2g %%)\n",
+ mc_rcv.integrated_irradiance.E,
+ mc_rcv.integrated_irradiance.SE,
+ 100 * mc_rcv.integrated_irradiance.E / m);
+ printf
+ ("\tAtmospheric Loss(target) = %g +/- %g (%.2g %%)\n",
+ mc_rcv.absorptivity_loss.E,
+ mc_rcv.absorptivity_loss.SE,
+ 100 * mc_rcv.absorptivity_loss.E / m);
+ printf
+ ("\tReflectivity Loss(target) = %g +/- %g (%.2g %%)\n",
+ mc_rcv.reflectivity_loss.E,
+ mc_rcv.reflectivity_loss.SE,
+ 100 * mc_rcv.reflectivity_loss.E / m);
+ printf
+ ("\tCos Loss(target) = %g +/- %g (%.2g %%)\n",
+ mc_rcv.cos_loss.E,
+ mc_rcv.cos_loss.SE,
+ 100 * mc_rcv.cos_loss.E / m);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, a_m, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, a_std, 1e-4), 1);
+ CHECK(eq_eps
+ ( mc_rcv.integrated_irradiance.E
+ + mc_rcv.absorptivity_loss.E
+ + mc_rcv.reflectivity_loss.E, m, 1e-8), 1);
+ CHECK(eq_eps
+ ( mc_rcv.integrated_irradiance.E
+ + mc_rcv.absorptivity_loss.E
+ + mc_rcv.reflectivity_loss.E
+ + mc_rcv.cos_loss.E, 4 * DNI, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.cos_loss.E / (4 * DNI), 1 - COS, 1e-8), 1);
+
+ CHECK(ssol_mc_receiver_get_mc_shape(NULL, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_mc_receiver_get_mc_shape(&mc_rcv, NULL, NULL), RES_BAD_ARG);
+ CHECK(ssol_mc_receiver_get_mc_shape(NULL, square, NULL), RES_BAD_ARG);
+ CHECK(ssol_mc_receiver_get_mc_shape(&mc_rcv, square, NULL), RES_BAD_ARG);
+ CHECK(ssol_mc_receiver_get_mc_shape(NULL, NULL, &mc_shape), RES_BAD_ARG);
+ CHECK(ssol_mc_receiver_get_mc_shape(&mc_rcv, NULL, &mc_shape), RES_BAD_ARG);
+ CHECK(ssol_mc_receiver_get_mc_shape(NULL, square, &mc_shape), RES_BAD_ARG);
+ CHECK(ssol_mc_receiver_get_mc_shape(&mc_rcv, dummy, &mc_shape), RES_BAD_ARG);
+ CHECK(ssol_mc_receiver_get_mc_shape(&mc_rcv, square, &mc_shape), RES_OK);
+
+ CHECK(ssol_shape_get_triangles_count(square, &ntris), RES_OK);
+ NCHECK(ntris, 0);
+
+ CHECK(ssol_mc_shape_get_mc_primitive(NULL, ntris, NULL), RES_BAD_ARG);
+ CHECK(ssol_mc_shape_get_mc_primitive(&mc_shape, ntris, NULL), RES_BAD_ARG);
+ CHECK(ssol_mc_shape_get_mc_primitive(NULL, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_mc_shape_get_mc_primitive(&mc_shape, 0, NULL), RES_BAD_ARG);
+ CHECK(ssol_mc_shape_get_mc_primitive(NULL, ntris, &mc_prim), RES_BAD_ARG);
+ CHECK(ssol_mc_shape_get_mc_primitive(&mc_shape, ntris, &mc_prim), RES_BAD_ARG);
+ CHECK(ssol_mc_shape_get_mc_primitive(NULL, 0, &mc_prim), RES_BAD_ARG);
+
+ dbl = 0;
+ FOR_EACH(i, 0, ntris) {
+ CHECK(ssol_mc_shape_get_mc_primitive(&mc_shape, (unsigned)i, &mc_prim), RES_OK);
+ dbl += mc_prim.integrated_irradiance.E;
+ }
+
+ CHECK(eq_eps(dbl, a_m, 1.e-6), 1);
CHECK(ssol_estimator_ref_put(estimator), RES_OK);
CHECK(ssol_scene_detach_instance(scene, heliostat2), RES_OK);
CHECK(ssol_scene_attach_instance(scene, heliostat), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
/* Check a monochromatic sun */
desc.wavelengths = &mono;
@@ -455,30 +516,25 @@ main(int argc, char** argv)
desc.count = 2;
CHECK(ssol_spectrum_setup(abs, get_wlen, 2, &desc), RES_OK);
NCHECK(tmp = tmpfile(), 0);
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
CHECK(count, N__);
CHECK(pp_sum(tmp, (int32_t)r_id, count, &m, &std), RES_OK);
CHECK(fclose(tmp), 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g", m, std);
+ printf("Ir = %g +/- %g; ", m, std);
#define K2 (exp(-0.121 * 4 * sqrt(2)))
CHECK(eq_eps(m, 4 * K2 * DNI_cos, MMAX(4 * K2 * DNI_cos * 1e-4, std)), 1);
CHECK(eq_eps(std, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g",
- status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g",
-status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std, 1e-4), 1);
-#undef GET_STATUS
-#undef GET_RCV_STATUS
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g; ", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g; ", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std, 1e-4), 1);
/* Free data */
CHECK(ssol_instance_ref_put(heliostat2), RES_OK);
@@ -489,20 +545,19 @@ status.irradiance.E, status.irradiance.SE);
CHECK(ssol_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(dummy), RES_OK);
CHECK(ssol_shape_ref_put(square), RES_OK);
CHECK(ssol_material_ref_put(m_mtl), RES_OK);
CHECK(ssol_material_ref_put(v_mtl), RES_OK);
CHECK(ssol_device_ref_put(dev), RES_OK);
CHECK(ssol_scene_ref_put(scene), RES_OK);
- CHECK(ssp_rng_ref_put(rng), RES_OK);
CHECK(ssol_spectrum_ref_put(abs), RES_OK);
CHECK(ssol_atmosphere_ref_put(atm), RES_OK);
CHECK(ssol_estimator_ref_put(estimator), RES_OK);
CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
CHECK(ssol_sun_ref_put(sun_mono), RES_OK);
-
- logger_release(&logger);
+ CHECK(ssp_rng_ref_put(rng), RES_OK);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
diff --git a/src/test_ssol_solver2.c b/src/test_ssol_solver2.c
@@ -32,7 +32,6 @@
#define HALF_Y 1
#include "test_ssol_rect2D_geometry.h"
-#include <rsys/logger.h>
#include <rsys/double33.h>
#include <star/s3d.h>
@@ -52,7 +51,6 @@ get_wlen(const size_t i, double* wlen, double* data, void* ctx)
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssp_rng* rng;
@@ -77,7 +75,8 @@ main(int argc, char** argv)
struct ssol_sun* sun;
struct ssol_spectrum* spectrum;
struct ssol_estimator* estimator;
- struct ssol_estimator_status status;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
double dir[3];
double transform1[12]; /* 3x4 column major matrix */
double transform2[12]; /* 3x4 column major matrix */
@@ -104,13 +103,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
@@ -151,15 +145,15 @@ main(int argc, char** argv)
shader.normal = get_shader_normal;
shader.reflectivity = get_shader_reflectivity;
shader.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK);
+ CHECK(ssol_mirror_setup(m_mtl, &shader), RES_OK);
CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
CHECK(ssol_object_create(dev, &m_object), RES_OK);
CHECK(ssol_object_add_shaded_shape(m_object, rect, m_mtl, m_mtl), RES_OK);
CHECK(ssol_object_instantiate(m_object, &heliostat1), RES_OK);
CHECK(ssol_object_instantiate(m_object, &heliostat2), RES_OK);
- CHECK(ssol_instance_set_receiver(heliostat1, SSOL_FRONT), RES_OK);
- CHECK(ssol_instance_set_receiver(heliostat2, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat1, SSOL_FRONT, 0), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat2, SSOL_FRONT, 0), RES_OK);
transform3[9] = -0.5; /* -0.5 offset along X axis */
CHECK(ssol_instance_set_transform(heliostat1, transform3), RES_OK);
transform3[9] = +0.5; /* +0.5 offset along X axis */
@@ -170,7 +164,7 @@ main(int argc, char** argv)
CHECK(ssol_object_create(dev, &s_object), RES_OK);
CHECK(ssol_object_add_shaded_shape(s_object, quad_square, m_mtl, m_mtl), RES_OK);
CHECK(ssol_object_instantiate(s_object, &secondary), RES_OK);
- CHECK(ssol_instance_set_receiver(secondary, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(secondary, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_set_transform(secondary, transform1), RES_OK);
CHECK(ssol_instance_sample(secondary, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, secondary), RES_OK);
@@ -179,44 +173,38 @@ main(int argc, char** argv)
CHECK(ssol_object_add_shaded_shape(t_object, square, v_mtl, v_mtl), RES_OK);
CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
CHECK(ssol_instance_set_transform(target, transform2), RES_OK);
- CHECK(ssol_instance_set_receiver(target, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_sample(target, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
NCHECK(tmp = tmpfile(), 0);
#define N__ 10000
-#define GET_STATUS ssol_estimator_get_status
-#define GET_RCV_STATUS ssol_estimator_get_receiver_status
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+#define GET_MC_RCV ssol_estimator_get_mc_receiver
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_instance_get_id(target, &r_id), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
CHECK(count, N__);
CHECK(pp_sum(tmp, (int32_t)r_id, count, &m, &std), RES_OK);
CHECK(fclose(tmp), 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g\n", m, std);
+ printf("Ir = %g +/- %g\n", m, std);
#define DNI_cos (1000 * cos(PI / 4))
CHECK(eq_eps(m, 4 * DNI_cos, 4 * DNI_cos * 1e-4), 1);
#define SQR(x) ((x)*(x))
CHECK(eq_eps(std, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_RCV_STATUS(estimator, heliostat1, SSOL_BACK, &status), RES_BAD_ARG);
- CHECK(GET_RCV_STATUS(estimator, heliostat1, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(heliostat1) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(GET_RCV_STATUS(estimator, heliostat2, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(heliostat2) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(GET_RCV_STATUS(estimator, secondary, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(secondary) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std, 1e-4), 1);
-#undef GET_STATUS
-#undef GET_RCV_STATUS
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g\n", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(GET_MC_RCV(estimator, heliostat1, SSOL_BACK, &mc_rcv), RES_BAD_ARG);
+ CHECK(GET_MC_RCV(estimator, secondary, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(secondary) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std, 1e-4), 1);
/* Free data */
CHECK(ssol_instance_ref_put(heliostat1), RES_OK);
@@ -238,8 +226,6 @@ main(int argc, char** argv)
CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_solver2b.c b/src/test_ssol_solver2b.c
@@ -32,7 +32,6 @@
#define HALF_Y 1
#include "test_ssol_rect2D_geometry.h"
-#include <rsys/logger.h>
#include <rsys/double33.h>
#include <star/s3d.h>
@@ -52,7 +51,6 @@ get_wlen(const size_t i, double* wlen, double* data, void* ctx)
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssp_rng* rng;
@@ -77,7 +75,8 @@ main(int argc, char** argv)
struct ssol_sun* sun;
struct ssol_spectrum* spectrum;
struct ssol_estimator* estimator;
- struct ssol_estimator_status status;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
double dir[3];
double transform1[12]; /* 3x4 column major matrix */
double transform2[12]; /* 3x4 column major matrix */
@@ -86,7 +85,6 @@ main(int argc, char** argv)
FILE* tmp;
double m, std;
uint32_t r_id;
-
(void) argc, (void) argv;
d33_splat(transform1, 0);
@@ -104,13 +102,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
@@ -122,7 +115,7 @@ main(int argc, char** argv)
CHECK(ssol_scene_create(dev, &scene), RES_OK);
CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
- /* create scene content */
+ /* Create scene content */
CHECK(ssol_shape_create_mesh(dev, &rect), RES_OK);
attribs[0].usage = SSOL_POSITION;
@@ -156,15 +149,15 @@ main(int argc, char** argv)
shader.normal = get_shader_normal;
shader.reflectivity = get_shader_reflectivity;
shader.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK);
+ CHECK(ssol_mirror_setup(m_mtl, &shader), RES_OK);
CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
CHECK(ssol_object_create(dev, &m_object), RES_OK);
CHECK(ssol_object_add_shaded_shape(m_object, quad_rect, m_mtl, m_mtl), RES_OK);
CHECK(ssol_object_instantiate(m_object, &heliostat1), RES_OK);
CHECK(ssol_object_instantiate(m_object, &heliostat2), RES_OK);
- CHECK(ssol_instance_set_receiver(heliostat1, SSOL_FRONT), RES_OK);
- CHECK(ssol_instance_set_receiver(heliostat2, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat1, SSOL_FRONT, 0), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat2, SSOL_FRONT, 0), RES_OK);
transform3[9] = -0.5; /* -0.5 offset along X axis */
CHECK(ssol_instance_set_transform(heliostat1, transform3), RES_OK);
transform3[9] = +0.5; /* +0.5 offset along X axis */
@@ -175,7 +168,7 @@ main(int argc, char** argv)
CHECK(ssol_object_create(dev, &s_object), RES_OK);
CHECK(ssol_object_add_shaded_shape(s_object, quad_square, m_mtl, m_mtl), RES_OK);
CHECK(ssol_object_instantiate(s_object, &secondary), RES_OK);
- CHECK(ssol_instance_set_receiver(secondary, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(secondary, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_set_transform(secondary, transform1), RES_OK);
CHECK(ssol_instance_sample(secondary, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, secondary), RES_OK);
@@ -184,39 +177,37 @@ main(int argc, char** argv)
CHECK(ssol_object_add_shaded_shape(t_object, rect, v_mtl, v_mtl), RES_OK);
CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
CHECK(ssol_instance_set_transform(target, transform2), RES_OK);
- CHECK(ssol_instance_set_receiver(target, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_sample(target, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
NCHECK(tmp = tmpfile(), 0);
#define N__ 50000
-#define GET_STATUS ssol_estimator_get_status
-#define GET_RCV_STATUS ssol_estimator_get_receiver_status
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_instance_get_id(target, &r_id), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
CHECK(count, N__);
CHECK(pp_sum(tmp, (int32_t)r_id, count, &m, &std), RES_OK);
CHECK(fclose(tmp), 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g\n", m, std);
+ printf("Ir = %g +/- %g\n", m, std);
#define DNI_cos (1000 * cos(PI / 4))
CHECK(eq_eps(m, 2 * DNI_cos, MMAX(2 * DNI_cos * 1e-2, std)), 1);
#define SQR(x) ((x)*(x))
CHECK(eq_eps(std,
sqrt((SQR(4 * DNI_cos) / 2 - SQR(2 * DNI_cos)) / (double)count), 1e-3), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(status.Nf, 0);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std, 1e-4), 1);
-#undef GET_STATUS
-#undef GET_RCV_STATUS
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g\n", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g\n", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(ssol_estimator_get_mc_receiver
+ (estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std, 1e-4), 1);
+ CHECK(ssol_estimator_get_failed_count(estimator, &count), RES_OK);
+ CHECK(count, 0);
/* Free data */
CHECK(ssol_instance_ref_put(heliostat1), RES_OK);
@@ -238,8 +229,6 @@ main(int argc, char** argv)
CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_solver3.c b/src/test_ssol_solver3.c
@@ -27,7 +27,6 @@
#define HALF_Y 10
#include "test_ssol_rect2D_geometry.h"
-#include <rsys/logger.h>
#include <rsys/double33.h>
#include <star/s3d.h>
@@ -47,7 +46,6 @@ get_wlen(const size_t i, double* wlen, double* data, void* ctx)
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssp_rng* rng;
@@ -68,14 +66,14 @@ main(int argc, char** argv)
struct ssol_sun* sun;
struct ssol_spectrum* spectrum;
struct ssol_estimator* estimator;
- struct ssol_estimator_status status;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
double dir[3];
double transform[12]; /* 3x4 column major matrix */
size_t count;
FILE* tmp;
double m, std;
uint32_t r_id;
-
(void) argc, (void) argv;
d3_splat(transform + 9, 0);
@@ -84,13 +82,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
@@ -125,52 +118,50 @@ main(int argc, char** argv)
shader.normal = get_shader_normal;
shader.reflectivity = get_shader_reflectivity;
shader.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK);
+ CHECK(ssol_mirror_setup(m_mtl, &shader), RES_OK);
CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
CHECK(ssol_object_create(dev, &m_object), RES_OK);
CHECK(ssol_object_add_shaded_shape(m_object, quad_square, m_mtl, m_mtl), RES_OK);
CHECK(ssol_object_instantiate(m_object, &heliostat), RES_OK);
- CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, heliostat), RES_OK);
CHECK(ssol_object_create(dev, &t_object), RES_OK);
CHECK(ssol_object_add_shaded_shape(t_object, square, v_mtl, v_mtl), RES_OK);
CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
CHECK(ssol_instance_set_transform(target, transform), RES_OK);
- CHECK(ssol_instance_set_receiver(target, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_sample(target, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
NCHECK(tmp = tmpfile(), 0);
#define N__ 20000
-#define GET_STATUS ssol_estimator_get_status
-#define GET_RCV_STATUS ssol_estimator_get_receiver_status
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_instance_get_id(target, &r_id), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
CHECK(count, N__);
CHECK(pp_sum(tmp, (int32_t)r_id, count, &m, &std), RES_OK);
CHECK(fclose(tmp), 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g\n", m, std);
+ printf("Ir = %g +/- %g\n", m, std);
#define DNI_cos (1000 * cos(PI / 4))
CHECK(eq_eps(m, 4 * DNI_cos, 4 * DNI_cos * 2e-1), 1);
#define SQR(x) ((x)*(x))
CHECK(eq_eps(std,
sqrt((SQR(400*DNI_cos) / 100 - SQR(4*DNI_cos)) / (double)count), 20), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(status.Nf, 0);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std, 1e-4), 1);
-#undef GET_STATUS
-#undef GET_RCV_STATUS
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g\n", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g\n", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(ssol_estimator_get_mc_receiver
+ (estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std, 1e-4), 1);
+ CHECK(ssol_estimator_get_failed_count(estimator, &count), RES_OK);
+ CHECK(count, 0);
/* Free data */
CHECK(ssol_instance_ref_put(heliostat), RES_OK);
@@ -188,8 +179,6 @@ main(int argc, char** argv)
CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_solver4.c b/src/test_ssol_solver4.c
@@ -27,7 +27,6 @@
#define HALF_Y 10
#include "test_ssol_rect2D_geometry.h"
-#include <rsys/logger.h>
#include <rsys/double33.h>
#include <star/s3d.h>
@@ -47,7 +46,6 @@ get_wlen(const size_t i, double* wlen, double* data, void* ctx)
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssp_rng* rng;
@@ -69,7 +67,8 @@ main(int argc, char** argv)
struct ssol_sun* sun;
struct ssol_spectrum* spectrum;
struct ssol_estimator* estimator;
- struct ssol_estimator_status status;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
double dir[3];
double transform[12]; /* 3x4 column major matrix */
size_t count;
@@ -85,13 +84,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
@@ -103,7 +97,7 @@ main(int argc, char** argv)
CHECK(ssol_scene_create(dev, &scene), RES_OK);
CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
- /* create scene content */
+ /* Create scene content */
CHECK(ssol_shape_create_mesh(dev, &square), RES_OK);
attribs[0].usage = SSOL_POSITION;
@@ -127,7 +121,7 @@ main(int argc, char** argv)
shader.normal = get_shader_normal;
shader.reflectivity = get_shader_reflectivity;
shader.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK);
+ CHECK(ssol_mirror_setup(m_mtl, &shader), RES_OK);
CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
CHECK(ssol_object_create(dev, &m_object), RES_OK);
@@ -139,21 +133,20 @@ main(int argc, char** argv)
CHECK(ssol_object_add_shaded_shape(t_object, square, v_mtl, v_mtl), RES_OK);
CHECK(ssol_object_instantiate(t_object, &target1), RES_OK);
CHECK(ssol_instance_set_transform(target1, transform), RES_OK);
- CHECK(ssol_instance_set_receiver(target1, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(target1, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_sample(target1, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target1), RES_OK);
CHECK(ssol_object_instantiate(t_object, &target2), RES_OK);
transform[11] += 1.e-4;
CHECK(ssol_instance_set_transform(target2, transform), RES_OK);
- CHECK(ssol_instance_set_receiver(target2, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(target2, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_sample(target2, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target2), RES_OK);
NCHECK(tmp = tmpfile(), 0);
#define N__ 10000
-#define GET_STATUS ssol_estimator_get_status
-#define GET_RCV_STATUS ssol_estimator_get_receiver_status
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+#define GET_MC_RCV ssol_estimator_get_mc_receiver
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_instance_get_id(target1, &r_id1), RES_OK);
CHECK(ssol_instance_get_id(target2, &r_id2), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
@@ -161,29 +154,29 @@ main(int argc, char** argv)
CHECK(pp_sum(tmp, (int32_t)r_id1, count, &m1, &std1), RES_OK);
CHECK(pp_sum(tmp, (int32_t)r_id2, count, &m2, &std2), RES_OK);
CHECK(fclose(tmp), 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g\n", m1, std1);
+ printf("Ir = %g +/- %g\n", m1, std1);
#define DNI_cos (1000 * cos(0))
CHECK(eq_eps(m1, 400 * DNI_cos, 400 * DNI_cos * 1e-4), 1);
CHECK(eq_eps(std1, 0, 1), 1);
CHECK(m1, m2);
CHECK(std1, std2);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(status.Nf, 0);
- CHECK(GET_RCV_STATUS(estimator, target1, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target1) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m1, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std1, 1e-4), 1);
- CHECK(GET_RCV_STATUS(estimator, target2, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target2) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m2, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std2, 1e-4), 1);
-#undef GET_STATUS
-#undef GET_RCV_STATUS
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g\n", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g\n", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(GET_MC_RCV(estimator, target1, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target1) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m1, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std1, 1e-4), 1);
+ CHECK(GET_MC_RCV(estimator, target2, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target2) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m2, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std2, 1e-4), 1);
+ CHECK(ssol_estimator_get_failed_count(estimator, &count), RES_OK);
+ CHECK(count, 0);
/* Free data */
CHECK(ssol_instance_ref_put(heliostat), RES_OK);
@@ -202,8 +195,6 @@ main(int argc, char** argv)
CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_solver5.c b/src/test_ssol_solver5.c
@@ -27,7 +27,6 @@
#define HALF_Y 10
#include "test_ssol_rect2D_geometry.h"
-#include <rsys/logger.h>
#include <rsys/double33.h>
#include <star/s3d.h>
@@ -47,7 +46,6 @@ get_wlen(const size_t i, double* wlen, double* data, void* ctx)
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssp_rng* rng;
@@ -68,15 +66,16 @@ main(int argc, char** argv)
struct ssol_sun* sun;
struct ssol_spectrum* spectrum;
struct ssol_estimator* estimator;
- struct ssol_estimator_status status;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
double dir[3];
double transform[12]; /* 3x4 column major matrix */
size_t count;
FILE* tmp;
double m, std;
uint32_t r_id;
-
(void) argc, (void) argv;
+
#define FOCAL 10
d3_splat(transform + 9, 0);
d33_rotation_pitch(transform, PI); /* flip faces: invert normal */
@@ -84,13 +83,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
@@ -102,7 +96,7 @@ main(int argc, char** argv)
CHECK(ssol_scene_create(dev, &scene), RES_OK);
CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
- /* create scene content */
+ /* Create scene content */
CHECK(ssol_shape_create_mesh(dev, &rect), RES_OK);
attribs[0].usage = SSOL_POSITION;
@@ -126,7 +120,7 @@ main(int argc, char** argv)
shader.normal = get_shader_normal;
shader.reflectivity = get_shader_reflectivity;
shader.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK);
+ CHECK(ssol_mirror_setup(m_mtl, &shader), RES_OK);
CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
CHECK(ssol_object_create(dev, &m_object), RES_OK);
@@ -138,37 +132,35 @@ main(int argc, char** argv)
CHECK(ssol_object_add_shaded_shape(t_object, rect, v_mtl, v_mtl), RES_OK);
CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
CHECK(ssol_instance_set_transform(target, transform), RES_OK);
- CHECK(ssol_instance_set_receiver(target, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_sample(target, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
NCHECK(tmp = tmpfile(), 0);
#define N__ 10000
-#define GET_STATUS ssol_estimator_get_status
-#define GET_RCV_STATUS ssol_estimator_get_receiver_status
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(ssol_instance_get_id(target, &r_id), RES_OK);
CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
CHECK(count, N__);
CHECK(pp_sum(tmp, (int32_t)r_id, count, &m, &std), RES_OK);
CHECK(fclose(tmp), 0);
- logger_print(&logger, LOG_OUTPUT, "\nIr = %g +/- %g\n", m, std);
+ printf("Ir = %g +/- %g\n", m, std);
#define DNI_cos (1000 * cos(0))
CHECK(eq_eps(m, 400 * DNI_cos, 20), 1);
CHECK(eq_eps(std, 0, 1), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1e-4), 1);
- CHECK(status.Nf, 0);
- CHECK(GET_RCV_STATUS(estimator, target, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, m, 1e-8), 1);
- CHECK(eq_eps(status.irradiance.SE, std, 1e-4), 1);
-#undef GET_STATUS
-#undef GET_RCV_STATUS
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g\n", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g\n", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(ssol_estimator_get_mc_receiver
+ (estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, m, 1e-8), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, std, 1e-4), 1);
+ CHECK(ssol_estimator_get_failed_count(estimator, &count), RES_OK);
+ CHECK(count, 0);
/* Free data */
CHECK(ssol_instance_ref_put(heliostat), RES_OK);
@@ -186,8 +178,6 @@ main(int argc, char** argv)
CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_solver6.c b/src/test_ssol_solver6.c
@@ -29,7 +29,6 @@
#define HALF_Y 5
#include "test_ssol_rect2D_geometry.h"
-#include <rsys/logger.h>
#include <rsys/double33.h>
#include <star/s3d.h>
@@ -49,10 +48,17 @@ get_wlen(const size_t i, double* wlen, double* data, void* ctx)
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssp_rng* rng;
+ struct ssol_object *m_object1;
+ struct ssol_object *m_object2;
+ struct ssol_object* t_object1;
+ struct ssol_object* t_object2;
+ struct ssol_instance* heliostat1;
+ struct ssol_instance* heliostat2;
+ struct ssol_instance* target1;
+ struct ssol_instance* target2;
struct ssol_scene* scene;
struct ssol_shape* square;
struct ssol_vertex_data attribs[1] = { SSOL_VERTEX_DATA_NULL__ };
@@ -68,7 +74,8 @@ main(int argc, char** argv)
struct ssol_sun* sun;
struct ssol_spectrum* spectrum;
struct ssol_estimator* estimator;
- struct ssol_estimator_status status;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
double dir[3];
double transform[12]; /* 3x4 column major matrix */
FILE* tmp;
@@ -77,13 +84,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, 1, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
@@ -118,16 +120,14 @@ main(int argc, char** argv)
m_shader.normal = get_shader_normal;
m_shader.reflectivity = get_shader_reflectivity;
m_shader.roughness = get_shader_roughness;
- CHECK(ssol_mirror_set_shader(m_mtl, &m_shader), RES_OK);
+ CHECK(ssol_mirror_setup(m_mtl, &m_shader), RES_OK);
CHECK(ssol_material_create_matte(dev, &bck_mtl), RES_OK);
bck_shader.normal = get_shader_normal;
bck_shader.reflectivity = get_shader_reflectivity_2;
- CHECK(ssol_matte_set_shader(bck_mtl, &bck_shader), RES_OK);
+ CHECK(ssol_matte_setup(bck_mtl, &bck_shader), RES_OK);
CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
/* 1st reflector */
- struct ssol_object *m_object1;
- struct ssol_instance* heliostat1;
CHECK(ssol_object_create(dev, &m_object1), RES_OK);
CHECK(ssol_object_add_shaded_shape(m_object1, quad_square, m_mtl, m_mtl), RES_OK);
CHECK(ssol_object_instantiate(m_object1, &heliostat1), RES_OK);
@@ -138,8 +138,6 @@ main(int argc, char** argv)
CHECK(ssol_instance_set_transform(heliostat1, transform), RES_OK);
/* 2nd reflector */
- struct ssol_object *m_object2;
- struct ssol_instance* heliostat2;
CHECK(ssol_object_create(dev, &m_object2), RES_OK);
CHECK(ssol_object_add_shaded_shape(m_object2, quad_square, m_mtl, m_mtl), RES_OK);
CHECK(ssol_object_instantiate(m_object2, &heliostat2), RES_OK);
@@ -150,13 +148,11 @@ main(int argc, char** argv)
CHECK(ssol_instance_set_transform(heliostat2, transform), RES_OK);
/* 1st target */
- struct ssol_object* t_object1;
- struct ssol_instance* target1;
CHECK(ssol_object_create(dev, &t_object1), RES_OK);
CHECK(ssol_object_add_shaded_shape(t_object1, square, bck_mtl, v_mtl), RES_OK);
CHECK(ssol_object_instantiate(t_object1, &target1), RES_OK);
CHECK(ssol_instance_set_transform(target1, transform), RES_OK);
- CHECK(ssol_instance_set_receiver(target1, SSOL_FRONT), RES_OK);
+ CHECK(ssol_instance_set_receiver(target1, SSOL_FRONT, 0), RES_OK);
CHECK(ssol_instance_sample(target1, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target1), RES_OK);
d33_rotation_pitch(transform, PI); /* flip faces: invert normal */
@@ -166,13 +162,11 @@ main(int argc, char** argv)
CHECK(ssol_instance_set_transform(target1, transform), RES_OK);
/* 2nd target */
- struct ssol_object* t_object2;
- struct ssol_instance* target2;
CHECK(ssol_object_create(dev, &t_object2), RES_OK);
CHECK(ssol_object_add_shaded_shape(t_object2, square, bck_mtl, v_mtl), RES_OK);
CHECK(ssol_object_instantiate(t_object2, &target2), RES_OK);
CHECK(ssol_instance_set_transform(target2, transform), RES_OK);
- CHECK(ssol_instance_set_receiver(target2, SSOL_BACK), RES_OK);
+ CHECK(ssol_instance_set_receiver(target2, SSOL_BACK, 0), RES_OK);
CHECK(ssol_instance_sample(target2, 0), RES_OK);
CHECK(ssol_scene_attach_instance(scene, target2), RES_OK);
d33_set_identity(transform);
@@ -183,30 +177,24 @@ main(int argc, char** argv)
NCHECK(tmp = tmpfile(), 0);
#define N__ 10000
-#define GET_STATUS ssol_estimator_get_status
-#define GET_RCV_STATUS ssol_estimator_get_receiver_status
- CHECK(ssol_solve(scene, rng, N__, tmp, &estimator), RES_OK);
+#define GET_MC_RCV ssol_estimator_get_mc_receiver
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
CHECK(fclose(tmp), 0);
-
- CHECK(GET_STATUS(estimator, SSOL_STATUS_SHADOW, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Shadows = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 100000, 2 * 100000/sqrt(N__)), 1);
- CHECK(status.Nf, 0);
-
- CHECK(GET_STATUS(estimator, SSOL_STATUS_MISSING, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Missing = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 0), 1);
-
- CHECK(GET_RCV_STATUS(estimator, target1, SSOL_FRONT, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target1) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 100000, 2 * 100000 / sqrt(N__)), 1);
-
- CHECK(GET_RCV_STATUS(estimator, target2, SSOL_BACK, &status), RES_OK);
- logger_print(&logger, LOG_OUTPUT, "Ir(target2) = %g +/- %g", status.irradiance.E, status.irradiance.SE);
- CHECK(eq_eps(status.irradiance.E, 0, 1), 1);
-
-#undef GET_STATUS
-#undef GET_RCV_STATUS
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g\n", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g\n", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 100000, 2 * 100000/sqrt(N__)), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 0), 1);
+
+ CHECK(GET_MC_RCV(estimator, target1, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target1) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, 100000, 2*100000/sqrt(N__)), 1);
+
+ CHECK(GET_MC_RCV(estimator, target2, SSOL_BACK, &mc_rcv), RES_OK);
+ printf("Ir(target2) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, 0, 1), 1);
/* Free data */
CHECK(ssol_instance_ref_put(heliostat1), RES_OK);
@@ -229,8 +217,6 @@ main(int argc, char** argv)
CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
CHECK(ssol_sun_ref_put(sun), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_solver7.c b/src/test_ssol_solver7.c
@@ -0,0 +1,245 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "ssol.h"
+#include "test_ssol_utils.h"
+
+#include <rsys/mem_allocator.h>
+#include <rsys/image.h>
+
+#define SCREEN_GAMMA 2.2
+#define WIDTH 640
+#define HEIGHT 480
+#define PROJ_RATIO (double)WIDTH/(double)HEIGHT
+
+#define REFLECTIVITY 0
+#include "test_ssol_materials.h"
+
+#define TARGET_SZ 2
+#define PLANE_NAME TARGET
+#define HALF_X (TARGET_SZ/2)
+#define HALF_Y (TARGET_SZ/2)
+STATIC_ASSERT((HALF_X * 2 == TARGET_SZ), ONLY_ENVEN_VALUES_FOR_SZ);
+#include "test_ssol_rect_geometry.h"
+
+#define HELIOSTAT_SZ 4
+#define POLYGON_NAME HELIOSTAT
+#define HALF_X (HELIOSTAT_SZ/2)
+#define HALF_Y (HELIOSTAT_SZ/2)
+STATIC_ASSERT(HALF_X * 2 == HELIOSTAT_SZ, ONLY_ENVEN_VALUES_FOR_SZ);
+#include "test_ssol_rect2D_geometry.h"
+
+#define HYPERBOL_SZ 24
+#define POLYGON_NAME HYPERBOL
+#define HALF_X (HYPERBOL_SZ/2)
+#define HALF_Y (HYPERBOL_SZ/2)
+STATIC_ASSERT(HALF_X * 2 == HYPERBOL_SZ, ONLY_ENVEN_VALUES_FOR_SZ);
+#include "test_ssol_rect2D_geometry.h"
+
+#include <rsys/double33.h>
+
+#include <star/s3d.h>
+#include <star/ssp.h>
+
+static void
+get_wlen(const size_t i, double* wlen, double* data, void* ctx)
+{
+ double wavelengths[3] = { 1, 2, 3 };
+ double intensities[3] = { 1, 0.8, 1 };
+ CHECK(i < 3, 1);
+ (void)ctx;
+ *wlen = wavelengths[i];
+ *data = intensities[i];
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct ssol_device* dev;
+ struct ssp_rng* rng;
+ struct ssol_scene* scene;
+ struct ssol_shape* square;
+ struct ssol_vertex_data attribs[1] = { SSOL_VERTEX_DATA_NULL__ };
+ struct ssol_carving carving1 = SSOL_CARVING_NULL;
+ struct ssol_carving carving2 = SSOL_CARVING_NULL;
+ struct ssol_material *m_mtl, *bck_mtl, *v_mtl;
+ struct ssol_mirror_shader m_shader = SSOL_MIRROR_SHADER_NULL;
+ struct ssol_matte_shader bck_shader = SSOL_MATTE_SHADER_NULL;
+ struct ssol_object* t_object;
+ struct ssol_instance* target;
+ struct ssol_sun* sun;
+ struct ssol_spectrum* spectrum;
+ struct ssol_estimator* estimator;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
+ double dir[3];
+ double transform[12]; /* 3x4 column major matrix */
+ FILE* tmp;
+ /* primary is a parabol */
+ struct ssol_quadric quadric1 = SSOL_QUADRIC_DEFAULT;
+ struct ssol_punched_surface punched1 = SSOL_PUNCHED_SURFACE_NULL;
+ struct ssol_object* m_object1;
+ struct ssol_shape* quad_square1;
+ struct ssol_instance* heliostat;
+ /* secondary is an hyperbol */
+ struct ssol_quadric quadric2 = SSOL_QUADRIC_DEFAULT;
+ struct ssol_punched_surface punched2 = SSOL_PUNCHED_SURFACE_NULL;
+ struct ssol_object* m_object2;
+ struct ssol_shape* quad_square2;
+ struct ssol_instance* secondary;
+ (void) argc, (void) argv;
+
+#define H 10
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(ssol_device_create
+ (NULL, &allocator, 1, 0, &dev), RES_OK);
+
+ CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
+ CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
+ CHECK(ssol_spectrum_setup(spectrum, get_wlen, 3, NULL), RES_OK);
+ CHECK(ssol_sun_create_directional(dev, &sun), 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);
+ CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
+
+ /* create scene content */
+
+ CHECK(ssol_shape_create_mesh(dev, &square), RES_OK);
+ attribs[0].usage = SSOL_POSITION;
+ attribs[0].get = get_position;
+ CHECK(ssol_mesh_setup(square, TARGET_NTRIS__, get_ids,
+ TARGET_NVERTS__, attribs, 1, (void*) &TARGET_DESC__), RES_OK);
+
+ CHECK(ssol_material_create_mirror(dev, &m_mtl), RES_OK);
+ m_shader.normal = get_shader_normal;
+ m_shader.reflectivity = get_shader_reflectivity;
+ m_shader.roughness = get_shader_roughness;
+ CHECK(ssol_mirror_setup(m_mtl, &m_shader), RES_OK);
+ CHECK(ssol_material_create_matte(dev, &bck_mtl), RES_OK);
+ bck_shader.normal = get_shader_normal;
+ bck_shader.reflectivity = get_shader_reflectivity_2;
+ CHECK(ssol_matte_setup(bck_mtl, &bck_shader), RES_OK);
+ CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
+
+ carving1.get = get_polygon_vertices;
+ carving1.operation = SSOL_AND;
+ carving1.nb_vertices = HELIOSTAT_NVERTS__;
+ carving1.context = &HELIOSTAT_EDGES__;
+
+ CHECK(ssol_shape_create_punched_surface(dev, &quad_square1), RES_OK);
+ quadric1.type = SSOL_QUADRIC_PARABOL;
+ quadric1.data.parabol.focal = 10 * sqrt(2) * H;
+ punched1.nb_carvings = 1;
+ punched1.quadric = &quadric1;
+ punched1.carvings = &carving1;
+ CHECK(ssol_punched_surface_setup(quad_square1, &punched1), RES_OK);
+ CHECK(ssol_object_create(dev, &m_object1), RES_OK);
+ CHECK(ssol_object_add_shaded_shape(m_object1, quad_square1, m_mtl, m_mtl), RES_OK);
+ CHECK(ssol_object_instantiate(m_object1, &heliostat), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, heliostat), RES_OK);
+ d33_rotation_yaw(transform, -0.25 * PI);
+ d3_splat(transform + 9, 0);
+ transform[9] = 10 * H; /* target the img focal point of the hyperbol */
+ CHECK(ssol_instance_set_transform(heliostat, transform), RES_OK);
+
+ carving2.get = get_polygon_vertices;
+ carving2.operation = SSOL_AND;
+ carving2.nb_vertices = HYPERBOL_NVERTS__;
+ carving2.context = &HYPERBOL_EDGES__;
+
+ CHECK(ssol_shape_create_punched_surface(dev, &quad_square2), RES_OK);
+ quadric2.type = SSOL_QUADRIC_HYPERBOL;
+ quadric2.data.hyperbol.real_focal = 9 * H;
+ quadric2.data.hyperbol.img_focal = 1 * H;
+ punched2.nb_carvings = 1;
+ punched2.quadric = &quadric2;
+ punched2.carvings = &carving2;
+ CHECK(ssol_punched_surface_setup(quad_square2, &punched2), RES_OK);
+ CHECK(ssol_object_create(dev, &m_object2), RES_OK);
+ CHECK(ssol_object_add_shaded_shape(m_object2, quad_square2, m_mtl, v_mtl), RES_OK);
+ CHECK(ssol_object_instantiate(m_object2, &secondary), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, secondary), RES_OK);
+ d33_set_identity(transform);
+ d3_splat(transform + 9, 0);
+ transform[11] = 9 * H;
+ CHECK(ssol_instance_set_transform(secondary, transform), RES_OK);
+ CHECK(ssol_instance_sample(secondary, 0), RES_OK);
+
+ CHECK(ssol_object_create(dev, &t_object), RES_OK);
+ CHECK(ssol_object_add_shaded_shape(t_object, square, bck_mtl, v_mtl), RES_OK);
+ CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
+ CHECK(ssol_instance_sample(target, 0), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
+ d33_set_identity(transform);
+ d3_splat(transform + 9, 0);
+ CHECK(ssol_instance_set_transform(target, transform), RES_OK);
+
+#define N__ 10000
+#define DNI_cos (1000 * cos(0))
+#define TOTAL (HELIOSTAT_SZ * HELIOSTAT_SZ * DNI_cos)
+#define GET_MC_RCV ssol_estimator_get_mc_receiver
+
+ NCHECK(tmp = tmpfile(), 0);
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
+ CHECK(fclose(tmp), 0);
+
+ printf("Total = %g\n", TOTAL);
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Shadows = %g +/- %g\n",
+ mc_global.shadowed.E, mc_global.shadowed.SE);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ printf("Missing = %g +/- %g\n",
+ mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target1) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, TOTAL, TOTAL * 1e-4), 1);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.SE, 0, 1e-4), 1);
+
+ /* Free data */
+ CHECK(ssol_instance_ref_put(heliostat), RES_OK);
+ CHECK(ssol_instance_ref_put(secondary), RES_OK);
+ CHECK(ssol_instance_ref_put(target), RES_OK);
+ CHECK(ssol_object_ref_put(m_object1), RES_OK);
+ CHECK(ssol_object_ref_put(m_object2), RES_OK);
+ CHECK(ssol_object_ref_put(t_object), RES_OK);
+ CHECK(ssol_shape_ref_put(square), RES_OK);
+ CHECK(ssol_shape_ref_put(quad_square1), RES_OK);
+ CHECK(ssol_shape_ref_put(quad_square2), RES_OK);
+ CHECK(ssol_material_ref_put(m_mtl), RES_OK);
+ CHECK(ssol_material_ref_put(bck_mtl), RES_OK);
+ CHECK(ssol_material_ref_put(v_mtl), RES_OK);
+ CHECK(ssol_estimator_ref_put(estimator), RES_OK);
+ CHECK(ssol_device_ref_put(dev), 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_sun_ref_put(sun), RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+
+ return 0;
+}
+
diff --git a/src/test_ssol_solver8.c b/src/test_ssol_solver8.c
@@ -0,0 +1,187 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "ssol.h"
+#include "test_ssol_utils.h"
+#include "test_ssol_materials.h"
+
+#define PLANE_NAME TARGET
+#define HALF_X 10
+#define HALF_Y 10
+#include "test_ssol_rect_geometry.h"
+
+#define X_SZ 10
+#define Y_SZ 4
+#define POLYGON_NAME POLY
+#define HALF_X (X_SZ / 2)
+STATIC_ASSERT((HALF_X * 2 == X_SZ), ONLY_ENVEN_VALUES_FOR_X_SZ);
+#define Y_MIN 0
+#define Y_MAX Y_SZ
+#include "test_ssol_rect2D_geometry.h"
+
+#include <rsys/double33.h>
+
+#include <star/s3d.h>
+#include <star/ssp.h>
+
+static void
+get_wlen(const size_t i, double* wlen, double* data, void* ctx)
+{
+ double wavelengths[3] = { 1, 2, 3 };
+ double intensities[3] = { 1, 0.8, 1 };
+ CHECK(i < 3, 1);
+ (void) ctx;
+ *wlen = wavelengths[i];
+ *data = intensities[i];
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct ssol_device* dev;
+ struct ssp_rng* rng;
+ struct ssol_scene* scene;
+ struct ssol_shape* square;
+ struct ssol_vertex_data attribs[1] = { SSOL_VERTEX_DATA_NULL__ };
+ struct ssol_shape* quad_square;
+ struct ssol_carving carving = SSOL_CARVING_NULL;
+ struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT;
+ struct ssol_punched_surface punched = SSOL_PUNCHED_SURFACE_NULL;
+ struct ssol_material* m_mtl;
+ struct ssol_material* v_mtl;
+ struct ssol_mirror_shader shader = SSOL_MIRROR_SHADER_NULL;
+ struct ssol_object* m_object;
+ struct ssol_object* t_object;
+ struct ssol_instance* heliostat;
+ struct ssol_instance* target;
+ struct ssol_sun* sun;
+ struct ssol_spectrum* spectrum;
+ struct ssol_estimator* estimator;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
+ double dir[3];
+ double transform[12]; /* 3x4 column major matrix */
+ size_t count;
+ FILE* tmp;
+ uint32_t r_id;
+
+ (void) argc, (void) argv;
+ d3_splat(transform + 9, 0);
+ d33_rotation_pitch(transform, PI); /* flip faces: invert normal */
+ transform[11] = 4; /* set it just above the parabolic cylinder */
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(ssol_device_create
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+
+#define DNI 1000
+ CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
+ CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
+ CHECK(ssol_spectrum_setup(spectrum, get_wlen, 3, NULL), RES_OK);
+ CHECK(ssol_sun_create_directional(dev, &sun), RES_OK);
+ CHECK(ssol_sun_set_direction(sun, d3(dir, 0, 1, -1)), RES_OK);
+ CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK);
+ CHECK(ssol_sun_set_dni(sun, DNI), RES_OK);
+ CHECK(ssol_scene_create(dev, &scene), RES_OK);
+ CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
+
+ /* Create scene content */
+
+ CHECK(ssol_shape_create_mesh(dev, &square), RES_OK);
+ attribs[0].usage = SSOL_POSITION;
+ attribs[0].get = get_position;
+ CHECK(ssol_mesh_setup(square, TARGET_NTRIS__, get_ids,
+ TARGET_NVERTS__, attribs, 1, (void*) &TARGET_DESC__), RES_OK);
+
+ CHECK(ssol_shape_create_punched_surface(dev, &quad_square), RES_OK);
+ carving.get = get_polygon_vertices;
+ carving.operation = SSOL_AND;
+ carving.nb_vertices = POLY_NVERTS__;
+ carving.context = &POLY_EDGES__;
+ quadric.type = SSOL_QUADRIC_PARABOLIC_CYLINDER;
+ quadric.data.parabol.focal = 1;
+ punched.nb_carvings = 1;
+ punched.quadric = &quadric;
+ punched.carvings = &carving;
+ CHECK(ssol_punched_surface_setup(quad_square, &punched), RES_OK);
+
+ CHECK(ssol_material_create_mirror(dev, &m_mtl), RES_OK);
+ shader.normal = get_shader_normal;
+ shader.reflectivity = get_shader_reflectivity;
+ shader.roughness = get_shader_roughness;
+ CHECK(ssol_mirror_setup(m_mtl, &shader), RES_OK);
+ CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
+
+ CHECK(ssol_object_create(dev, &m_object), RES_OK);
+ CHECK(ssol_object_add_shaded_shape(m_object, quad_square, m_mtl, m_mtl), RES_OK);
+ CHECK(ssol_object_instantiate(m_object, &heliostat), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, heliostat), RES_OK);
+
+ CHECK(ssol_object_create(dev, &t_object), RES_OK);
+ CHECK(ssol_object_add_shaded_shape(t_object, square, v_mtl, v_mtl), RES_OK);
+ CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
+ CHECK(ssol_instance_set_transform(target, transform), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
+ CHECK(ssol_instance_sample(target, 0), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
+
+ NCHECK(tmp = tmpfile(), 0);
+#define N__ 100000
+#define GET_MC_RCV ssol_estimator_get_mc_receiver
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
+ CHECK(ssol_instance_get_id(target, &r_id), RES_OK);
+ CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
+ CHECK(count, N__);
+ CHECK(fclose(tmp), 0);
+ CHECK(ssol_estimator_get_failed_count(estimator, &count), RES_OK);
+ CHECK(count, 0);
+#define S (sqrt(2) * X_SZ * Y_SZ)
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Cos = %g +/- %g\n", mc_global.cos_loss.E, mc_global.cos_loss.SE);
+ printf("Shadows = %g +/- %g\n", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g\n", mc_global.missing.E, mc_global.missing.SE);
+ CHECK(eq_eps(mc_global.cos_loss.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.shadowed.E, 0, 1e-4), 1);
+ CHECK(eq_eps(mc_global.missing.E, 0, 1e-4), 1);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target1) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, S * DNI,
+ 2 * mc_rcv.integrated_irradiance.SE), 1);
+
+ /* Free data */
+ CHECK(ssol_instance_ref_put(heliostat), RES_OK);
+ CHECK(ssol_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_shape_ref_put(quad_square), RES_OK);
+ CHECK(ssol_material_ref_put(m_mtl), RES_OK);
+ CHECK(ssol_material_ref_put(v_mtl), RES_OK);
+ CHECK(ssol_estimator_ref_put(estimator), RES_OK);
+ CHECK(ssol_device_ref_put(dev), 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_sun_ref_put(sun), RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+
+ return 0;
+}
diff --git a/src/test_ssol_solver9.c b/src/test_ssol_solver9.c
@@ -0,0 +1,184 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "ssol.h"
+#include "test_ssol_utils.h"
+#include "test_ssol_materials.h"
+
+#include <rsys/math.h>
+
+#define TGT_X 6
+#define TGT_Y 10
+#define PLANE_NAME TARGET
+#define HALF_X (TGT_X / 2)
+#define HALF_Y (TGT_Y / 2)
+STATIC_ASSERT((HALF_X * 2 == TGT_X), ONLY_ENVEN_VALUES_FOR_TGT_X);
+STATIC_ASSERT((HALF_Y * 2 == TGT_Y), ONLY_ENVEN_VALUES_FOR_TGT_Y);
+#include "test_ssol_rect_geometry.h"
+
+#define SZ MMAX(TGT_X, TGT_Y)
+#define CUBE_NAME CUBE
+#define HALF_X (SZ / 2)
+#define HALF_Y (SZ / 2)
+#define HALF_Z (SZ / 2)
+STATIC_ASSERT((HALF_X * 2 == SZ), ONLY_ENVEN_VALUES_FOR_SZ);
+#include "test_ssol_cube_geometry.h"
+
+#include <rsys/double33.h>
+
+#include <star/s3d.h>
+#include <star/ssp.h>
+
+static void
+get_wlen(const size_t i, double* wlen, double* data, void* ctx)
+{
+ double wavelengths[3] = { 1, 2, 3 };
+ double intensities[3] = { 1, 0.8, 1 };
+ CHECK(i < 3, 1);
+ (void) ctx;
+ *wlen = wavelengths[i];
+ *data = intensities[i];
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct ssol_device* dev;
+ struct ssp_rng* rng;
+ struct ssol_scene* scene;
+ struct ssol_shape* square;
+ struct ssol_vertex_data attribs[1] = { SSOL_VERTEX_DATA_NULL__ };
+ struct ssol_shape* cube;
+ struct ssol_material* m_mtl;
+ struct ssol_material* v_mtl;
+ struct ssol_mirror_shader shader = SSOL_MIRROR_SHADER_NULL;
+ struct ssol_object* m_object;
+ struct ssol_object* t_object;
+ struct ssol_instance* heliostat;
+ struct ssol_instance* target;
+ struct ssol_sun* sun;
+ struct ssol_spectrum* spectrum;
+ struct ssol_estimator* estimator;
+ struct ssol_mc_global mc_global;
+ struct ssol_mc_receiver mc_rcv;
+ double dir[3];
+ double transform[12]; /* 3x4 column major matrix */
+ size_t count;
+ FILE* tmp;
+ uint32_t r_id;
+
+ (void) argc, (void) argv;
+ d3_splat(transform + 9, 0);
+ d33_rotation_pitch(transform, PI); /* flip faces: invert normal */
+ transform[11] = 6; /* set it above the cube */
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(ssol_device_create
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+
+#define DNI 1000
+ CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
+ CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
+ CHECK(ssol_spectrum_setup(spectrum, get_wlen, 3, NULL), RES_OK);
+ CHECK(ssol_sun_create_directional(dev, &sun), RES_OK);
+ CHECK(ssol_sun_set_direction(sun, d3(dir, 0, 0, -1)), RES_OK);
+ CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK);
+ CHECK(ssol_sun_set_dni(sun, DNI), RES_OK);
+ CHECK(ssol_scene_create(dev, &scene), RES_OK);
+ CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
+
+ /* Create scene content */
+
+ CHECK(ssol_shape_create_mesh(dev, &square), RES_OK);
+ attribs[0].usage = SSOL_POSITION;
+ attribs[0].get = get_position;
+ CHECK(ssol_mesh_setup(square, TARGET_NTRIS__, get_ids,
+ TARGET_NVERTS__, attribs, 1, (void*) &TARGET_DESC__), RES_OK);
+
+ CHECK(ssol_shape_create_mesh(dev, &cube), RES_OK);
+ CHECK(ssol_mesh_setup(cube, CUBE_NTRIS__, get_ids,
+ CUBE_NVERTS__, attribs, 1, (void*) &CUBE_DESC__), RES_OK);
+
+ CHECK(ssol_material_create_mirror(dev, &m_mtl), RES_OK);
+ shader.normal = get_shader_normal;
+ shader.reflectivity = get_shader_reflectivity;
+ shader.roughness = get_shader_roughness;
+ CHECK(ssol_mirror_setup(m_mtl, &shader), RES_OK);
+ CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
+
+ CHECK(ssol_object_create(dev, &m_object), RES_OK);
+ CHECK(ssol_object_add_shaded_shape(m_object, cube, m_mtl, m_mtl), RES_OK);
+ CHECK(ssol_object_instantiate(m_object, &heliostat), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, heliostat), RES_OK);
+
+ CHECK(ssol_object_create(dev, &t_object), RES_OK);
+ CHECK(ssol_object_add_shaded_shape(t_object, square, v_mtl, v_mtl), RES_OK);
+ CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
+ CHECK(ssol_instance_set_transform(target, transform), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK);
+ CHECK(ssol_instance_sample(target, 0), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
+
+ NCHECK(tmp = tmpfile(), 0);
+#define N__ 100000
+#define GET_MC_RCV ssol_estimator_get_mc_receiver
+ CHECK(ssol_solve(scene, rng, N__, 0, tmp, &estimator), RES_OK);
+ CHECK(ssol_instance_get_id(target, &r_id), RES_OK);
+ CHECK(ssol_estimator_get_count(estimator, &count), RES_OK);
+ CHECK(count, N__);
+ CHECK(fclose(tmp), 0);
+ CHECK(ssol_estimator_get_failed_count(estimator, &count), RES_OK);
+ CHECK(count, 0);
+#define DNI_TGT_S (DNI * TGT_X * TGT_Y)
+#define DNI_S (DNI * SZ * SZ)
+ CHECK(ssol_estimator_get_mc_global(estimator, &mc_global), RES_OK);
+ printf("Cos = %g +/- %g\n", mc_global.cos_loss.E, mc_global.cos_loss.SE);
+ printf("Shadows = %g +/- %g\n", mc_global.shadowed.E, mc_global.shadowed.SE);
+ printf("Missing = %g +/- %g\n", mc_global.missing.E, mc_global.missing.SE);
+ /* CHECK(eq_eps(mc_global.cos_loss.E, 4 * DNI_S, DNI_S * 1e-4), 1); */
+ CHECK(eq_eps(mc_global.shadowed.E, DNI_S, 3 * mc_global.shadowed.SE), 1);
+ CHECK(eq_eps(mc_global.missing.E,
+ MMAX(DNI_S, DNI_TGT_S) - MMIN(DNI_S, DNI_TGT_S),
+ 3 * mc_global.missing.SE), 1);
+ CHECK(GET_MC_RCV(estimator, target, SSOL_FRONT, &mc_rcv), RES_OK);
+ printf("Ir(target1) = %g +/- %g\n",
+ mc_rcv.integrated_irradiance.E, mc_rcv.integrated_irradiance.SE);
+ CHECK(eq_eps(mc_rcv.integrated_irradiance.E, MMIN(DNI_S, DNI_TGT_S),
+ 3 * mc_rcv.integrated_irradiance.SE), 1);
+
+ /* Free data */
+ CHECK(ssol_instance_ref_put(heliostat), RES_OK);
+ CHECK(ssol_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_shape_ref_put(cube), RES_OK);
+ CHECK(ssol_material_ref_put(m_mtl), RES_OK);
+ CHECK(ssol_material_ref_put(v_mtl), RES_OK);
+ CHECK(ssol_estimator_ref_put(estimator), RES_OK);
+ CHECK(ssol_device_ref_put(dev), 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_sun_ref_put(sun), RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+
+ return 0;
+}
diff --git a/src/test_ssol_spectrum.c b/src/test_ssol_spectrum.c
@@ -16,8 +16,6 @@
#include "ssol.h"
#include "test_ssol_utils.h"
-#include <rsys/logger.h>
-
struct spectrum_desc {
double wavelengths[3];
double data[3];
@@ -41,7 +39,6 @@ get_wlen(const size_t i, double* wlen, double* data, void* ctx)
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssol_spectrum* spectrum;
@@ -50,13 +47,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssol_spectrum_create(NULL, &spectrum), RES_BAD_ARG);
CHECK(ssol_spectrum_create(dev, NULL), RES_BAD_ARG);
@@ -90,8 +82,6 @@ main(int argc, char** argv)
CHECK(ssol_device_ref_put(dev), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_sun.c b/src/test_ssol_sun.c
@@ -16,13 +16,11 @@
#include "ssol.h"
#include "test_ssol_utils.h"
-#include <rsys/logger.h>
#include <rsys/double3.h>
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
struct ssol_device* dev;
struct ssol_spectrum* spectrum;
@@ -36,13 +34,8 @@ main(int argc, char** argv)
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
-
CHECK(ssol_device_create
- (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ (NULL, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
CHECK(ssol_spectrum_create(dev, &spectrum2), RES_OK);
@@ -198,8 +191,6 @@ main(int argc, char** argv)
CHECK(ssol_spectrum_ref_put(spectrum2), RES_OK);
CHECK(ssol_device_ref_put(dev), RES_OK);
- logger_release(&logger);
-
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);
diff --git a/src/test_ssol_utils.h b/src/test_ssol_utils.h
@@ -20,14 +20,6 @@
#include <stdio.h>
static INLINE void
-log_stream(const char* msg, void* ctx)
-{
- ASSERT(msg);
- (void) msg, (void) ctx;
- printf("%s\n", msg);
-}
-
-static INLINE void
check_memory_allocator(struct mem_allocator* allocator)
{
if(MEM_ALLOCATED_SIZE(allocator)) {