star-sf

Set of surface and volume scattering functions
git clone git://git.meso-star.fr/star-sf.git
Log | Files | Refs | README | LICENSE

commit f99eb39978e78ecc1ba71a47fbc956120e8be079
parent 345529bf27857f07d453303a1aaa0a9d2aa46e45
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 15 Jun 2021 17:15:44 +0200

Merge branch 'release_0.7'

Diffstat:
MREADME.md | 12++++++++++--
Mcmake/CMakeLists.txt | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Asrc/ssf.c | 36++++++++++++++++++++++++++++++++++++
Msrc/ssf.h | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/ssf_beckmann_distribution.c | 2+-
Msrc/ssf_blinn_distribution.c | 2+-
Msrc/ssf_bsdf.c | 2+-
Msrc/ssf_bsdf_c.h | 2+-
Msrc/ssf_fresnel.c | 2+-
Msrc/ssf_fresnel_c.h | 2+-
Msrc/ssf_fresnel_constant.c | 2+-
Msrc/ssf_fresnel_dielectric_conductor.c | 2+-
Msrc/ssf_fresnel_dielectric_dielectric.c | 2+-
Msrc/ssf_fresnel_no_op.c | 2+-
Msrc/ssf_lambertian_reflection.c | 2+-
Msrc/ssf_microfacet_distribution.c | 2+-
Msrc/ssf_microfacet_distribution_c.h | 2+-
Msrc/ssf_microfacet_reflection.c | 2+-
Msrc/ssf_optics.h | 2+-
Msrc/ssf_phase.c | 2+-
Msrc/ssf_phase_c.h | 2+-
Msrc/ssf_phase_hg.c | 3+--
Msrc/ssf_phase_rayleigh.c | 2+-
Asrc/ssf_phase_rdgfa.c | 458+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ssf_phase_rdgfa_simdX.h | 183+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ssf_pillbox_distribution.c | 2+-
Msrc/ssf_specular_dielectric_dielectric_interface.c | 2+-
Msrc/ssf_specular_reflection.c | 2+-
Msrc/ssf_thin_specular_dielectric.c | 2+-
Msrc/test_ssf_beckmann_distribution.c | 2+-
Msrc/test_ssf_blinn_distribution.c | 2+-
Msrc/test_ssf_bsdf.c | 2+-
Msrc/test_ssf_fresnel.c | 2+-
Msrc/test_ssf_fresnel_constant.c | 2+-
Msrc/test_ssf_fresnel_dielectric_conductor.c | 2+-
Msrc/test_ssf_fresnel_dielectric_dielectric.c | 2+-
Msrc/test_ssf_fresnel_no_op.c | 2+-
Msrc/test_ssf_lambertian_reflection.c | 2+-
Msrc/test_ssf_microfacet_distribution.c | 2+-
Msrc/test_ssf_microfacet_reflection.c | 2+-
Msrc/test_ssf_phase.c | 2+-
Msrc/test_ssf_phase_hg.c | 2+-
Msrc/test_ssf_phase_rayleigh.c | 2+-
Asrc/test_ssf_phase_rdgfa.c | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_ssf_pillbox_distribution.c | 2+-
Msrc/test_ssf_specular_dielectric_dielectric_reflection.c | 2+-
Msrc/test_ssf_specular_reflection.c | 2+-
Msrc/test_ssf_thin_specular_dielectric.c | 2+-
Msrc/test_ssf_utils.h | 2+-
49 files changed, 1031 insertions(+), 68 deletions(-)

diff --git a/README.md b/README.md @@ -15,7 +15,10 @@ The library uses [CMake](http://www.cmake.org) and the [RCMake](https://gitlab.com/vaplv/rcmake/#tab-readme) package to build. It also depends on the [Star-SP](https://gitlab.com/meso-star/star-sp/#tab-readme) and the -[RSys](https://gitlab.com/vaplv/rsys/#tab-readme) libraries. +[RSys](https://gitlab.com/vaplv/rsys/#tab-readme) libraries. The +[RSIMD](https://gitlab.com/vaplv/rsimd) library is an optional dependency that, +if it is installed, is used to speed up the setup of the built-in RDG-FA phase +function. First ensure that CMake is installed on your system. Then install the RCMake package as well as all the aforementioned prerequisites. Finally generate the @@ -24,6 +27,11 @@ project from the `cmake/CMakeLists.txt` file by appending to the ## Release notes +### Version 0.7 + +- Add a built-in phase function using the + [RDG-FA](https://doi.org/10.1016/j.jqsrt.2013.08.022) model. + ### Version 0.6 - Add the phase function API allowing the user to define, sample and evaluate a @@ -62,7 +70,7 @@ project from the `cmake/CMakeLists.txt` file by appending to the ## License -Star-ScatteringFunctions is Copyright (C) 2016-2018 +Star-ScatteringFunctions is Copyright (C) 2016-2018, 2021 |Meso|Star>(<contact@meso-star.com>). It is a free software released under the GPL v3+ license. You are welcome to redistribute it under certain conditions; refer to the COPYING file for details. diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +# Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) # # 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 @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.1) project(ssf C) enable_testing() @@ -27,19 +27,60 @@ set(SSF_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src) find_package(RCMake 0.4 REQUIRED) find_package(RSys 0.6 REQUIRED) find_package(StarSP 0.5 REQUIRED) -include_directories(${RSys_INCLUDE_DIR} ${StarSP_INCLUDE_DIR}) +find_package(RSIMD 0.3) +if(RSIMD_FOUND) + option(USE_SIMD "Use SIMD instruction sets" ON) +endif() set(CMAKE_MODULE_PATH ${RCMAKE_SOURCE_DIR}) include(rcmake) include(rcmake_runtime) -rcmake_append_runtime_dirs(_runtime_dirs RSys StarSP) +include_directories(${RSys_INCLUDE_DIR} ${StarSP_INCLUDE_DIR}) + +set(_dependencies RSys StarSP) + +if(USE_SIMD) + include_directories(${RSIMD_INCLUDE_DIR}) + set(_dependencies ${_dependencies} RSIMD) +endif() + +rcmake_append_runtime_dirs(_runtime_dirs ${_dependencies}) + +################################################################################ +# Check SIMD support +################################################################################ +if(NOT USE_SIMD) + message(STATUS "Do not use the SIMD instruction sets") +else() + message(STATUS "Use the SIMD instruction sets") + + option(SSF_USE_SIMD_128 "Enable the SIMD-128 instruction sets" ON) + option(SSF_USE_SIMD_256 "Enable the SIMD-256 instruction sets" ON) + + if(SSF_USE_SIMD_128 AND NOT RSIMD_SSE2) + get_property(_docstring CACHE SSF_USE_SIMD_128 PROPERTY HELPSTRING) + set(SSF_USE_SIMD_128 OFF CACHE BOOL ${_docstring} FORCE) + endif() + if(SSF_USE_SIMD_256 AND NOT RSIMD_AVX) + get_property(_docstring CACHE SSF_USE_SIMD_256 PROPERTY HELPSTRING) + set(SSF_USE_SIMD_256 OFF CACHE BOOL ${_docstring} FORCE) + endif() + + if(SSF_USE_SIMD_128) + set(_simd_size "${_simd_size};SSF_USE_SIMD_128") + endif() + + if(SSF_USE_SIMD_256) + set(_simd_size "${_simd_size};SSF_USE_SIMD_256") + endif() +endif() ################################################################################ # Define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 6) +set(VERSION_MINOR 7) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) @@ -52,6 +93,7 @@ set(SSF_FILES_INC ssf_optics.h ssf_phase_c.h) set(SSF_FILES_SRC + ssf.c ssf_beckmann_distribution.c ssf_blinn_distribution.c ssf_bsdf.c @@ -66,6 +108,7 @@ set(SSF_FILES_SRC ssf_phase.c ssf_phase_hg.c ssf_phase_rayleigh.c + ssf_phase_rdgfa.c ssf_pillbox_distribution.c ssf_specular_dielectric_dielectric_interface.c ssf_specular_reflection.c @@ -76,20 +119,16 @@ rcmake_prepend_path(SSF_FILES_INC_API ${SSF_SOURCE_DIR}) rcmake_prepend_path(SSF_FILES_DOC ${PROJECT_SOURCE_DIR}/../) if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC) - set(MATH_LIB m) + set(_dependencies ${_dependencies} m) endif() -if(BUILD_STATIC) - add_library(ssf STATIC ${SSF_FILES_INC} ${SSF_FILES_SRC} ${SSF_FILES_INC_API}) - set_target_properties(ssf PROPERTIES COMPILE_DEFINITIONS SSF_STATIC_BUILD) -else() - add_library(ssf SHARED ${SSF_FILES_INC} ${SSF_FILES_SRC}) - target_link_libraries(ssf RSys StarSP ${MATH_LIB}) - set_target_properties(ssf PROPERTIES - DEFINE_SYMBOL SSF_SHARED_BUILD - VERSION ${VERSION} - SOVERSION ${VERSION_MAJOR}) -endif() +add_library(ssf SHARED ${SSF_FILES_INC} ${SSF_FILES_SRC}) +target_link_libraries(ssf ${_dependencies}) +set_target_properties(ssf PROPERTIES + DEFINE_SYMBOL SSF_SHARED_BUILD + COMPILE_DEFINITIONS "${_simd_size}" + VERSION ${VERSION} + SOVERSION ${VERSION_MAJOR}) rcmake_setup_devel(ssf StarSF ${VERSION} star/ssf_version.h) @@ -98,10 +137,18 @@ rcmake_setup_devel(ssf StarSF ${VERSION} star/ssf_version.h) ################################################################################ if(NOT NO_TEST) - function(new_test _name) + function(build_test _name) add_executable(${_name} ${SSF_SOURCE_DIR}/${_name}.c) target_link_libraries(${_name} ssf RSys StarSP ${MATH_LIB}) - add_test(${_name} ${_name}) + endfunction() + + function(register_test _name) + add_test(${_name} ${ARGN}) + endfunction() + + function(new_test _name) + build_test(${_name} ${ARGN}) + register_test(${_name} ${_name}) endfunction() new_test(test_ssf_beckmann_distribution) @@ -123,6 +170,15 @@ if(NOT NO_TEST) new_test(test_ssf_specular_reflection) new_test(test_ssf_thin_specular_dielectric) + build_test(test_ssf_phase_rdgfa) + register_test(test_ssf_phase_rdgfa_simd_none test_ssf_phase_rdgfa simd_none) + if(SSF_USE_SIMD_128) + register_test(test_ssf_phase_rdgfa_simd_128 test_ssf_phase_rdgfa simd_128) + endif() + if(SSF_USE_SIMD_256) + register_test(test_ssf_phase_rdgfa_simd_256 test_ssf_phase_rdgfa simd_256) + endif() + rcmake_copy_runtime_libraries(test_ssf_beckmann_distribution) endif() diff --git a/src/ssf.c b/src/ssf.c @@ -0,0 +1,36 @@ +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) + * + * 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 "ssf.h" + +/******************************************************************************* + * API function + ******************************************************************************/ +res_T +ssf_get_info(struct ssf_info* info) +{ + if(!info) return RES_BAD_ARG; +#ifdef SSF_USE_SIMD_128 + info->simd_128 = 1; +#else + info->simd_128 = 0; +#endif +#ifdef SSF_USE_SIMD_256 + info->simd_256 = 1; +#else + info->simd_256 = 0; +#endif + return RES_OK; +} diff --git a/src/ssf.h b/src/ssf.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 @@ -17,6 +17,7 @@ #define SSF_H #include <rsys/rsys.h> +#include <float.h> /* Library symbol management */ #if defined(SSF_SHARED_BUILD) /* Build shared library */ @@ -56,6 +57,12 @@ enum ssf_bxdf_flag { SSF_GLOSSY = BIT(4) }; +enum ssf_simd { + SSF_SIMD_NONE, + SSF_SIMD_128, + SSF_SIMD_256 +}; + /* Generic BSDF type descriptor. Note that by convention the outgoing direction * `wo' and the incoming direction `wi' point outward the surface. Furthermore, * `wo' and the normal N must point on the same side of the surface. As a @@ -153,8 +160,8 @@ SSF_MICROFACET_DISTRIBUTION_TYPE_NULL = SSF_MICROFACET_DISTRIBUTION_TYPE_NULL__; * direction `wo' and the incoming direction `wi' point *OUTWARD* the scattering * point. The scattering angle is thus acos(-wo.wi) */ struct ssf_phase_type { - res_T (*init)(struct mem_allocator* allocator, void* bsdf); /*Can be NULL*/ - void (*release)(void* bsdf); /* Can be NULL */ + res_T (*init)(struct mem_allocator* allocator, void* phase); /*Can be NULL*/ + void (*release)(void* phase); /* Can be NULL */ /* Sample a direction `wi' wrt `wo'. */ void @@ -185,6 +192,49 @@ struct ssf_phase_type { #define SSF_PHASE_TYPE_NULL__ {NULL,NULL,NULL,NULL,NULL,0,1} static const struct ssf_phase_type SSF_PHASE_TYPE_NULL = SSF_PHASE_TYPE_NULL__; +struct ssf_info { + /* Define the supported SIMD instruction sets */ + char simd_128; + char simd_256; +}; +#define SSF_INFO_NULL__ {0,0} +static const struct ssf_info SSF_INFO_NULL = SSF_INFO_NULL__; + +/* RDGFA phase function input arguments */ +struct ssf_phase_rdgfa_setup_args { + double wavelength; /* In nm */ + double fractal_dimension; /* No unit */ + double gyration_radius; /* In nm */ + + /* Number of #intervals to use to discretize the angular domain */ + size_t nintervals; + + enum ssf_simd simd; /* SIMD instruction sets to use */ +}; +#define SSF_PHASE_RDGFA_SETUP_ARGS_DEFAULT__ {0,0,0,1000,SSF_SIMD_NONE} +static const struct ssf_phase_rdgfa_setup_args +SSF_PHASE_RDGFA_SETUP_ARGS_DEFAULT = SSF_PHASE_RDGFA_SETUP_ARGS_DEFAULT__; + +struct ssf_phase_rdgfa_desc { + double wavelength; /* In nm */ + double fractal_dimension; /* No unit */ + double gyration_radius; /* In nm */ + + double normalization_factor; /* Normalization factor of the cumulative */ + size_t nintervals; /* #intervals used to discretized the cumulative */ +}; +#define SSF_PHASE_RDGFA_DESC_NULL__ {0,0,0,0,0} +static const struct ssf_phase_rdgfa_desc SSF_PHASE_RDGFA_DESC_NULL = + SSF_PHASE_RDGFA_DESC_NULL__; + +struct ssf_phase_rdgfa_interval { + double range[2]; /* Angular range of the interval. In rad */ + double cumulative; /* Value of the cumulative of the interval */ +}; +#define SSF_PHASE_RDGFA_INTERVAL_NULL__ {{DBL_MAX,-DBL_MAX}, 0} +static const struct ssf_phase_rdgfa_interval SSF_PHASE_RDGFA_INTERVAL_NULL = + SSF_PHASE_RDGFA_INTERVAL_NULL__; + BEGIN_DECLS /******************************************************************************* @@ -309,6 +359,22 @@ SSF_API const struct ssf_phase_type ssf_phase_hg; * p(wo, wi) = 3/(16*PI) * (1+(-wo.wi)^2) */ SSF_API const struct ssf_phase_type ssf_phase_rayleigh; +/* RDGFA phase function normalized to 1: + * p(wo, wi) = 3/(16*PI) * f(theta)/g * (1+cos(theta)^2); + * theta = acos(wo.wi) + * + * "Effects of multiple scattering on radiative properties of soot fractal + * aggregates" J. Yon et al., Journal of Quantitative Spectroscopy and + * Radiative Transfer Vol 133, pp. 374-381, 2014 */ +SSF_API const struct ssf_phase_type ssf_phase_rdgfa; + +/******************************************************************************* + * SSF API + ******************************************************************************/ +SSF_API res_T +ssf_get_info + (struct ssf_info* info); + /******************************************************************************* * BSDF API - Bidirectional Scattering Distribution Function. Describes the way * the light is scattered by a surface. Note that by convention the outgoing @@ -440,7 +506,26 @@ ssf_phase_get_data SSF_API res_T ssf_phase_hg_setup (struct ssf_phase* phase, - const double g); /* Asymmetric parameter */ + const double g); /* Asymmetric parameter in [-1, 1] */ + +/******************************************************************************* + * RDGFA phase function + ******************************************************************************/ +SSF_API res_T +ssf_phase_rdgfa_setup + (struct ssf_phase* phase, + const struct ssf_phase_rdgfa_setup_args* args); + +SSF_API res_T +ssf_phase_rdgfa_get_desc + (const struct ssf_phase* phase, + struct ssf_phase_rdgfa_desc* desc); + +SSF_API res_T +ssf_phase_rdgfa_get_interval + (const struct ssf_phase* phase, + const size_t interval_id, /* In [0, desc.nintervals[ */ + struct ssf_phase_rdgfa_interval* interval); /******************************************************************************* * Fresnel API - Define the equation of the fresnel term diff --git a/src/ssf_beckmann_distribution.c b/src/ssf_beckmann_distribution.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_blinn_distribution.c b/src/ssf_blinn_distribution.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_bsdf_c.h b/src/ssf_bsdf_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_fresnel.c b/src/ssf_fresnel.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_fresnel_c.h b/src/ssf_fresnel_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_fresnel_constant.c b/src/ssf_fresnel_constant.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_fresnel_dielectric_conductor.c b/src/ssf_fresnel_dielectric_conductor.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_fresnel_dielectric_dielectric.c b/src/ssf_fresnel_dielectric_dielectric.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_fresnel_no_op.c b/src/ssf_fresnel_no_op.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_microfacet_distribution.c b/src/ssf_microfacet_distribution.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_microfacet_distribution_c.h b/src/ssf_microfacet_distribution_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_optics.h b/src/ssf_optics.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_phase.c b/src/ssf_phase.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_phase_c.h b/src/ssf_phase_c.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_phase_hg.c b/src/ssf_phase_hg.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 @@ -110,4 +110,3 @@ ssf_phase_hg_setup(struct ssf_phase* phase, const double g) ((struct hg*)phase->data)->g = g; return RES_OK; } - diff --git a/src/ssf_phase_rayleigh.c b/src/ssf_phase_rayleigh.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_phase_rdgfa.c b/src/ssf_phase_rdgfa.c @@ -0,0 +1,458 @@ +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) + * + * 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 "ssf.h" +#include "ssf_phase_c.h" + +#include <star/ssp.h> + +#include <rsys/algorithm.h> +#include <rsys/dynamic_array_double.h> + +#if defined(SSF_USE_SIMD_128) || defined(SSF_USE_SIMD_256) + /* Helper macro */ + #define USE_SIMD +#endif + +#ifdef USE_SIMD + #include <rsimd/math.h> + #include <rsimd/rsimd.h> + + /* Generate the struct darray_simdf dynamic array */ + #define DARRAY_NAME simdf + #define DARRAY_DATA float + #ifdef SSF_USE_SIMD_256 + #define DARRAY_ALIGNMENT 64 + #else + #define DARRAY_ALIGNMENT 16 + #endif + #include <rsys/dynamic_array.h> +#endif + +#define EXP1 2.7182818284590452354 + +struct rdgfa { + double wavelength; /* In nm */ + double fractal_dimension; /* No unit */ + double gyration_radius; /* In nm */ + + double rcp_normalize_factor; /* Reciprocal normalization factor of the CDF */ + + /* Discretized cumulative (#entries = nintervals) */ + struct darray_double cdf; + +#ifdef USE_SIMD + struct darray_simdf f_list; + struct darray_simdf d_omega_list; +#endif + + /* Precomputed values */ + double Rg2; /* gyration_radius^2 */ + double cst_4pi_div_lambda; /* (4*PI)/wavelength */ + double cst_3Df_div_2E; /* 3*Df/(2*exp(1)) */ + double g; /* g function */ + + /* #intervals used to discretize the [0,pi[ angular domain */ + size_t nintervals; + + /* Length of an angular interval */ + double dtheta; /* In rad */ +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE int +check_phase_rdgfa_setup_args(const struct ssf_phase_rdgfa_setup_args* args) +{ + return args + && args->wavelength > 0 + && args->fractal_dimension > 0 + && args->gyration_radius > 0 + && args->nintervals != 0; +} + +static INLINE int +cmp_dbl(const void* a, const void* b) +{ + const double key = *((double*)a); + const double val = *((double*)b); + if(key < val) { + return -1; + } else if(key > val) { + return 1; + } else { + return 0; + } +} + +static INLINE double +eval_f(struct rdgfa* rdgfa, const double theta) +{ + double Df, Rg2, q, q2Rg2, f; + ASSERT(rdgfa); + + /* Input arguments */ + Df = rdgfa->fractal_dimension; + + /* Fech precomputed constants */ + Rg2 = rdgfa->Rg2; + + /* Precompute values */ + q = rdgfa->cst_4pi_div_lambda * sin(theta*0.5); + q2Rg2 = q*q*Rg2; + + /* Evaluate f(theta) */ + f = q2Rg2 < 1.5*Df + ? exp(-1.0/3.0 * q2Rg2) + : pow(rdgfa->cst_3Df_div_2E * 1/q2Rg2, Df*0.5); + return f; +} + +/* Not normalized */ +static INLINE double +eval2 + (struct rdgfa* rdgfa, + const double theta, + const double cos_theta) +{ + double f, cos2_theta, phase; + ASSERT(rdgfa && eq_eps(cos_theta, cos(theta), fabs(cos_theta*1.e-6))); + + /* Precompute values */ + cos2_theta = cos_theta * cos_theta; + + /* Evaluate phase(theta) */ + f = eval_f(rdgfa, theta); + phase = 3.0/(16*PI) * f / rdgfa->g * (1 + cos2_theta); + return phase; +} + +/* Not normalized */ +static FINLINE double +eval(struct rdgfa* rdgfa, const double theta) +{ + return eval2(rdgfa, theta, cos(theta)); +} + +static INLINE res_T +compute_cumulative(struct rdgfa* rdgfa) +{ + double* cdf = NULL; + double f1; + double theta1; + size_t i; + res_T res = RES_OK; + ASSERT(rdgfa); + + /* Allocate the cumulative array */ + res = darray_double_resize(&rdgfa->cdf, rdgfa->nintervals); + if(res != RES_OK) goto error; + cdf = darray_double_data_get(&rdgfa->cdf); + + /* Compute the angular step for the angular domain */ + rdgfa->dtheta = PI / (double)rdgfa->nintervals; + + theta1 = 0; + f1 = eval(rdgfa, 0); + FOR_EACH(i, 0, rdgfa->nintervals) { + /* Compute the upper bound of the current angular range */ + const double theta2 = theta1 + rdgfa->dtheta; + + /* Compute the (unormalized) cumulative for current interval */ + const double delta_omega = 2*PI*sin((theta1+theta2)*0.5)*rdgfa->dtheta; + const double f2 = eval(rdgfa, theta2); + const double tmp = (f1 + f2) * 0.5 * delta_omega; + cdf[i] = (i == 0 ? tmp : tmp + cdf[i-1]); + + /* Go to the next interval */ + f1 = f2; + theta1 = theta2; + } + + /* Save the normamlization factor */ + rdgfa->rcp_normalize_factor = 1.0 / cdf[rdgfa->nintervals-1]; + + /* Finally normalize the CDF */ + FOR_EACH(i, 0, rdgfa->nintervals) { + cdf[i] *= rdgfa->rcp_normalize_factor; + } + +exit: + return res; +error: + darray_double_clear(&rdgfa->cdf); + goto exit; +} + +/* Generate the simd functions if required */ +#ifdef SSF_USE_SIMD_128 + #define SIMD_WIDTH__ 4 + #include "ssf_phase_rdgfa_simdX.h" +#endif +#ifdef SSF_USE_SIMD_256 + #define SIMD_WIDTH__ 8 + #include "ssf_phase_rdgfa_simdX.h" +#endif + +/******************************************************************************* + * Private functions + ******************************************************************************/ +static res_T +rdgfa_init(struct mem_allocator* allocator, void* phase) +{ + struct rdgfa* rdgfa = phase; + ASSERT(phase); + memset(rdgfa, 0, sizeof(*rdgfa)); + darray_double_init(allocator, &rdgfa->cdf); +#ifdef USE_SIMD + darray_simdf_init(allocator, &rdgfa->f_list); + darray_simdf_init(allocator, &rdgfa->d_omega_list); +#endif /* USE_SIMD */ + return RES_OK; +} + +static void +rdgfa_release(void* phase) +{ + struct rdgfa* rdgfa = phase; + ASSERT(phase); + darray_double_release(&rdgfa->cdf); +#ifdef USE_SIMD + darray_simdf_release(&rdgfa->f_list); + darray_simdf_release(&rdgfa->d_omega_list); +#endif /* USE_SIMD */ +} + +static double +rdgfa_eval(void* data, const double wo[3], const double wi[3]) +{ + const struct rdgfa* rdgfa = data; + const double cos_theta = d3_dot(wo, wi); + const double theta = acos(cos_theta); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(wi)); + return eval2(data, theta, cos_theta) * rdgfa->rcp_normalize_factor; +} + +static void +rdgfa_sample + (void* data, + struct ssp_rng* rng, + const double wo[3], + double wi[3], + double* pdf) +{ + struct rdgfa* rdgfa = data; + const double* cdf = NULL; + double* find = NULL; + double frame[9]; + double w[3]; + double thetas[2]; + double theta; + double sin_theta; + double cos_theta; + double phi; + double r; + double u; + size_t n; + size_t i; + ASSERT(data && rng && wo && wi); + + /* Fetch the CDF array and its number of entries */ + cdf = darray_double_cdata_get(&rdgfa->cdf); + n = darray_double_size_get(&rdgfa->cdf); + + /* Sample the CDF */ + r = ssp_rng_canonical(rng); + find = search_lower_bound(&r, cdf, n, sizeof(double), cmp_dbl); + ASSERT(find && (*find) >= r); + i = (size_t)(find - cdf); + + /* Compute the angular range into which the sample lies */ + thetas[0] = rdgfa->dtheta * (double)(i + 0); + thetas[1] = rdgfa->dtheta * (double)(i + 1); + + /* Compute the sampled theta angle by linearly interpolate it from the + * boundaries of its interval */ + if(i == 0) { + u = r / cdf[0]; + } else { + u = (r - cdf[i-1]) / (cdf[i] - cdf[i-1]); + } + ASSERT(0 <= u && u < 1); + theta = u * (thetas[1] - thetas[0]) + thetas[0]; + + /* Uniformly sample a phi angle in [0, 2PI[ */ + phi = ssp_rng_uniform_double(rng, 0, 2*PI); + sin_theta = sin(theta); + cos_theta = cos(theta); + + /* Compute the cartesian coordinates of the sampled direction in the _local_ + * phase function space */ + wi[0] = cos(phi) * sin_theta; + wi[1] = sin(phi) * sin_theta; + wi[2] = cos_theta; + + /* Compute the transformation matrix from local phase function to world + * space. Note that by convention, in Star-SF the directions point outward + * the scattering position. Revert 'wo' to match the convention used by the + * previous computations */ + d33_basis(frame, d3_minus(w, wo)); + d33_muld3(wi, frame, wi); + + ASSERT(eq_eps(d3_dot(wi, w), cos_theta, fabs(cos_theta*1.e-6))); + + if(pdf) *pdf = rdgfa_eval(rdgfa, wo, wi); +} + +/******************************************************************************* + * Exported symbols + ******************************************************************************/ +const struct ssf_phase_type ssf_phase_rdgfa = { + rdgfa_init, + rdgfa_release, + rdgfa_sample, + rdgfa_eval, + rdgfa_eval, + sizeof(struct rdgfa), + ALIGNOF(struct rdgfa) +}; + +res_T +ssf_phase_rdgfa_setup + (struct ssf_phase* phase, + const struct ssf_phase_rdgfa_setup_args* args) +{ + struct rdgfa* rdgfa = NULL; + double lambda, Df, Rg, k, k2; + res_T res = RES_OK; + + if(!phase + || !PHASE_TYPE_EQ(&phase->type, &ssf_phase_rdgfa) + || !check_phase_rdgfa_setup_args(args)) { + res = RES_BAD_ARG; + goto error; + } + + rdgfa = phase->data; + rdgfa->wavelength = args->wavelength; + rdgfa->fractal_dimension = args->fractal_dimension; + rdgfa->gyration_radius = args->gyration_radius; + rdgfa->nintervals = args->nintervals; + + /* Fetch input data */ + lambda = rdgfa->wavelength; + Df = rdgfa->fractal_dimension; + Rg = rdgfa->gyration_radius; + + /* Precompute constants */ + rdgfa->Rg2 = Rg*Rg; /* gyration_radius^2 */ + rdgfa->cst_4pi_div_lambda = 4*PI / lambda; + rdgfa->cst_3Df_div_2E = 3*Df/(2.0*EXP1); + + /* Precompute the function g */ + k = (2.0*PI) / lambda; + k2 = k*k; + rdgfa->g = pow(1 + 4*k2*rdgfa->Rg2/(3*Df), -Df*0.5); + + /* Precompute the phase function cumulative */ + switch(args->simd) { + case SSF_SIMD_NONE: + res = compute_cumulative(rdgfa); + if(res != RES_OK) goto error; + break; + case SSF_SIMD_128: + #ifdef SSF_USE_SIMD_128 + res = compute_cumulative_simd4(rdgfa); + if(res != RES_OK) goto error; + #else + res = RES_BAD_OP; + goto error; + #endif + break; + case SSF_SIMD_256: + #ifdef SSF_USE_SIMD_256 + res = compute_cumulative_simd8(rdgfa); + if(res != RES_OK) goto error; + #else + res = RES_BAD_OP; + goto error; + #endif + break; + default: FATAL("Unreachable code.\n"); break; + } + +exit: + return res; +error: + goto exit; +} + +res_T +ssf_phase_rdgfa_get_desc + (const struct ssf_phase* phase, + struct ssf_phase_rdgfa_desc* desc) +{ + struct rdgfa* rdgfa = NULL; + res_T res = RES_OK; + + if(!phase || !PHASE_TYPE_EQ(&phase->type, &ssf_phase_rdgfa) || !desc) { + res = RES_BAD_ARG; + goto error; + } + + rdgfa = phase->data; + desc->wavelength = rdgfa->wavelength; + desc->gyration_radius = rdgfa->gyration_radius; + desc->fractal_dimension = rdgfa->fractal_dimension; + desc->normalization_factor = 1.0/rdgfa->rcp_normalize_factor; + desc->nintervals = rdgfa->nintervals; + +exit: + return res; +error: + goto exit; +} + +res_T +ssf_phase_rdgfa_get_interval + (const struct ssf_phase* phase, + const size_t interval_id, /* In [0, #intervals[ */ + struct ssf_phase_rdgfa_interval* interval) +{ + struct rdgfa* rdgfa = NULL; + res_T res = RES_OK; + + if(!phase || !PHASE_TYPE_EQ(&phase->type, &ssf_phase_rdgfa) || !interval) { + res = RES_BAD_ARG; + goto error; + } + + rdgfa = phase->data; + if(interval_id >= darray_double_size_get(&rdgfa->cdf)) { + res = RES_BAD_ARG; + goto error; + } + + interval->range[0] = rdgfa->dtheta * (double)(interval_id + 0); + interval->range[1] = rdgfa->dtheta * (double)(interval_id + 1); + interval->cumulative = darray_double_cdata_get(&rdgfa->cdf)[interval_id]; + +exit: + return res; +error: + goto exit; +} + diff --git a/src/ssf_phase_rdgfa_simdX.h b/src/ssf_phase_rdgfa_simdX.h @@ -0,0 +1,183 @@ +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) + * + * 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/>. */ + +#if !defined(SIMD_WIDTH__) + #error "Undefined SIMD_WIDTH__ macro" +#endif +#if SIMD_WIDTH__ != 4 && SIMD_WIDTH__ != 8 + #error "Unexpected SIMD_WIDTH__ value of "STR(RSIMD_WIDTH__) +#endif + +/* Check that internal macros are not already defined */ +#if defined(vXf__) \ + || defined(vXf_T__) \ + || defined(SIMD_FUNC__) + #error "Unexpected macro definition" +#endif + +/* Macros generic to the SIMD_WIDTH__ */ +#define vXf_T CONCAT(CONCAT(v, SIMD_WIDTH__), f_T) +#define vXf(Func) CONCAT(CONCAT(CONCAT(v, SIMD_WIDTH__), f_), Func) +#define SIMD_FUNC(Func) CONCAT(CONCAT(Func, _simd), SIMD_WIDTH__) + +static INLINE vXf_T +SIMD_FUNC(eval_f)(struct rdgfa* rdgfa, const vXf_T theta) +{ + /* Input arguments */ + const vXf_T Df = vXf(set1)((float)rdgfa->fractal_dimension); + + /* Precompute constants */ + const vXf_T Rg2 = vXf(set1)((float)rdgfa->Rg2); + const vXf_T half_theta = vXf(mul)(theta, vXf(set1)(0.5f)); + + /* Precompute values */ + const vXf_T sin_half_theta = vXf(sin)(half_theta); + const vXf_T q = vXf(mul)(vXf(set1)((float)rdgfa->cst_4pi_div_lambda), sin_half_theta); + const vXf_T q2Rg2 = vXf(mul)(vXf(mul)(q, q), Rg2); + + /* Evaluate f(theta) when q2Rg2 < 1.5*Df */ + const vXf_T val0 = vXf(exp)(vXf(mul)(vXf(set1)(-1.f/3.f), q2Rg2)); + + /* Evaluate f(theta) when q2Rg2 >= 1.5*Df */ + const vXf_T tmp0 = vXf(div)(vXf(set1)((float)rdgfa->cst_3Df_div_2E), q2Rg2); + const vXf_T half_Df = vXf(mul)(Df, vXf(set1)(0.5f)); + const vXf_T val1 = vXf(pow)(tmp0, half_Df); + + /* Setup f */ + const vXf_T mask = vXf(lt)(q2Rg2, vXf(mul)(Df, vXf(set1)(1.5f))); + const vXf_T f = vXf(sel)(val1, val0, mask); + return f; +} + +static INLINE vXf_T +SIMD_FUNC(eval2) + (struct rdgfa* rdgfa, + const vXf_T theta, + const vXf_T cos_theta) +{ + const vXf_T f = SIMD_FUNC(eval_f)(rdgfa, theta); + const vXf_T g = vXf(set1)((float)rdgfa->g); + const vXf_T cos2_theta = vXf(mul)(cos_theta, cos_theta); + const vXf_T cst0 = vXf(set1)(3.f/(16.f*(float)PI)); + const vXf_T tmp0 = vXf(div)(f, g); + const vXf_T tmp1 = vXf(add)(vXf(set1)(1), cos2_theta); + const vXf_T phase = vXf(mul)(vXf(mul)(cst0, tmp0), tmp1); + return phase; +} + +static INLINE vXf_T +SIMD_FUNC(eval)(struct rdgfa* rdgfa, const vXf_T theta) +{ + return SIMD_FUNC(eval2)(rdgfa, theta, vXf(cos)(theta)); +} + +static INLINE res_T +SIMD_FUNC(compute_cumulative)(struct rdgfa* rdgfa) +{ + vXf_T dtheta; + vXf_T theta1; + vXf_T step; + vXf_T two_PI; + float* f_list = NULL; + float* d_omega_list = NULL; + double* cdf = NULL; + size_t nangles; + size_t i; + res_T res = RES_OK; + ASSERT(rdgfa); + + /* Force the number of angles to be a multiple of the SIMD width */ + nangles = rdgfa->nintervals + 1; + nangles = (nangles + SIMD_WIDTH__-1)/ SIMD_WIDTH__ * SIMD_WIDTH__; + + /* Allocate the cumulative array */ + res = darray_double_resize(&rdgfa->cdf, rdgfa->nintervals); + if(res != RES_OK) goto error; + + /* Allocate temporaries arrays */ + res = darray_simdf_resize(&rdgfa->f_list, nangles); + if(res != RES_OK) goto error; + res = darray_simdf_resize(&rdgfa->d_omega_list, nangles); + if(res != RES_OK) goto error; + + /* Fetch data */ + cdf = darray_double_data_get(&rdgfa->cdf); + f_list = darray_simdf_data_get(&rdgfa->f_list); + d_omega_list = darray_simdf_data_get(&rdgfa->d_omega_list); + + /* Compute the angular step for the angular domain */ + rdgfa->dtheta = PI / (double)rdgfa->nintervals; + + step = vXf(set1)((float)rdgfa->dtheta*(float)SIMD_WIDTH__); + dtheta = vXf(set1)((float)rdgfa->dtheta); + two_PI = vXf(set1)((float)(2*PI)); +#if SIMD_WIDTH__ == 4 + theta1 = vXf(mul)(dtheta, vXf(set)(0, 1, 2, 3)); +#elif SIMD_WIDTH__ == 8 + theta1 = vXf(mul)(dtheta, vXf(set)(0, 1, 2, 3, 4, 5, 6, 7)); +#endif + + /* Compute f and d_omaga */ + FOR_EACH(i, 0, nangles/SIMD_WIDTH__) { + /* Compute f */ + const vXf_T f = SIMD_FUNC(eval)(rdgfa, theta1); + + /* Compute d_omega */ + const vXf_T theta2 = vXf(add)(theta1, dtheta); + const vXf_T tmp0 = vXf(mul)(vXf(add)(theta1, theta2), vXf(set1)(0.5f)); + const vXf_T d_omega = vXf(mul)(vXf(mul)(two_PI, vXf(sin)(tmp0)), dtheta); + + /* Store the result */ + vXf(store)(&f_list[i*SIMD_WIDTH__], f); + vXf(store)(&d_omega_list[i*SIMD_WIDTH__], d_omega); + + /* Go to the next angles */ + theta1 = vXf(add)(theta1, step); + } + + /* Compute the (unormalized) cumulative */ + FOR_EACH(i, 0, rdgfa->nintervals) { + const double f1 = f_list[i+0]; + const double f2 = f_list[i+1]; + const double d_omega = d_omega_list[i]; + const double tmp = (f1 + f2) * 0.5 * d_omega; + cdf[i] = (i == 0 ? tmp : tmp + cdf[i-1]); + } + + /* Save the normalization factor */ + rdgfa->rcp_normalize_factor = 1.0 / cdf[rdgfa->nintervals-1]; + + /* Finally normalize the CDF */ + FOR_EACH(i, 0, rdgfa->nintervals) { + cdf[i] *= rdgfa->rcp_normalize_factor; + } + +exit: + return res; +error: + darray_double_clear(&rdgfa->cdf); + darray_simdf_clear(&rdgfa->f_list); + darray_simdf_clear(&rdgfa->d_omega_list); + goto exit; +} + +/* Undef generic macros */ +#undef vXf_T +#undef vXf +#undef SIMD_FUNC + +/* Undef parameter */ +#undef SIMD_WIDTH__ + diff --git a/src/ssf_pillbox_distribution.c b/src/ssf_pillbox_distribution.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_specular_dielectric_dielectric_interface.c b/src/ssf_specular_dielectric_dielectric_interface.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/ssf_thin_specular_dielectric.c b/src/ssf_thin_specular_dielectric.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_beckmann_distribution.c b/src/test_ssf_beckmann_distribution.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_blinn_distribution.c b/src/test_ssf_blinn_distribution.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_bsdf.c b/src/test_ssf_bsdf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_fresnel.c b/src/test_ssf_fresnel.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_fresnel_constant.c b/src/test_ssf_fresnel_constant.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_fresnel_dielectric_conductor.c b/src/test_ssf_fresnel_dielectric_conductor.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_fresnel_dielectric_dielectric.c b/src/test_ssf_fresnel_dielectric_dielectric.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_fresnel_no_op.c b/src/test_ssf_fresnel_no_op.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_lambertian_reflection.c b/src/test_ssf_lambertian_reflection.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_microfacet_distribution.c b/src/test_ssf_microfacet_distribution.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_microfacet_reflection.c b/src/test_ssf_microfacet_reflection.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_phase.c b/src/test_ssf_phase.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_phase_hg.c b/src/test_ssf_phase_hg.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_phase_rayleigh.c b/src/test_ssf_phase_rayleigh.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_phase_rdgfa.c b/src/test_ssf_phase_rdgfa.c @@ -0,0 +1,138 @@ +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) + * + * 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 "ssf.h" +#include "test_ssf_utils.h" + +#include <string.h> + +int +main(int argc, char** argv) +{ + static const size_t NSAMPS = 10000; + + struct mem_allocator allocator; + struct ssf_info info = SSF_INFO_NULL; + struct ssf_phase_rdgfa_setup_args args = SSF_PHASE_RDGFA_SETUP_ARGS_DEFAULT; + struct ssf_phase_rdgfa_desc desc = SSF_PHASE_RDGFA_DESC_NULL; + struct ssf_phase_rdgfa_interval interval = SSF_PHASE_RDGFA_INTERVAL_NULL; + struct ssf_phase* phase; + struct ssf_phase* dummy; + struct ssp_rng* rng; + double cumulative_prev; + double wo[3]; + int err = 0; + size_t i; + (void)argc, (void)argv; + + if(argc <= 1) { + fprintf(stderr, "Usage: %s <simd_none|simd_128|simd_256>\n", argv[0]); + goto error; + } + + if(!strcmp(argv[1], "simd_none")) { + args.simd = SSF_SIMD_NONE; + } else if(!strcmp(argv[1], "simd_128")) { + args.simd = SSF_SIMD_128; + } else if(!strcmp(argv[1], "simd_256")) { + args.simd = SSF_SIMD_256; + } else { + fprintf(stderr, "Invalid argument '%s'.\n", argv[1]); + goto error; + } + + CHK(ssf_get_info(NULL) == RES_BAD_ARG); + CHK(ssf_get_info(&info) == RES_OK); + if(args.simd == SSF_SIMD_128) { + CHK(info.simd_128 != 0); + } + if(args.simd == SSF_SIMD_256) { + CHK(info.simd_256 != 0); + } + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHK(ssp_rng_create(&allocator, &ssp_rng_mt19937_64, &rng) == RES_OK); + + CHK(ssf_phase_create(&allocator, &ssf_phase_rdgfa, &phase) == RES_OK); + CHK(ssf_phase_create(&allocator, &phase_dummy, &dummy) == RES_OK); + + args.wavelength = 633; + args.fractal_dimension = 1.75; + args.gyration_radius = 385.17247758644652; + args.nintervals = 1000; + CHK(ssf_phase_rdgfa_setup(NULL, &args) == RES_BAD_ARG); + CHK(ssf_phase_rdgfa_setup(phase, NULL) == RES_BAD_ARG); + CHK(ssf_phase_rdgfa_setup(dummy, &args) == RES_BAD_ARG); + CHK(ssf_phase_rdgfa_setup(phase, &args) == RES_OK); + + CHK(ssf_phase_rdgfa_get_desc(NULL, &desc) == RES_BAD_ARG); + CHK(ssf_phase_rdgfa_get_desc(phase, NULL) == RES_BAD_ARG); + CHK(ssf_phase_rdgfa_get_desc(dummy, &desc) == RES_BAD_ARG); + CHK(ssf_phase_rdgfa_get_desc(phase, &desc) == RES_OK); + + CHK(desc.wavelength == args.wavelength); + CHK(desc.fractal_dimension == args.fractal_dimension); + CHK(desc.gyration_radius == args.gyration_radius); + CHK(desc.nintervals = args.nintervals); + + CHK(ssf_phase_rdgfa_get_interval(NULL, 0, &interval) == RES_BAD_ARG); + CHK(ssf_phase_rdgfa_get_interval(phase, desc.nintervals+1, &interval) + == RES_BAD_ARG); + CHK(ssf_phase_rdgfa_get_interval(phase, 0, NULL) == RES_BAD_ARG); + + cumulative_prev = 0; + FOR_EACH(i, 0, desc.nintervals) { + double range[2]; + + range[0] = PI/(double)desc.nintervals * (double)(i+0); + range[1] = PI/(double)desc.nintervals * (double)(i+1); + + CHK(ssf_phase_rdgfa_get_interval(phase, i, &interval) == RES_OK); + CHK(eq_eps(interval.range[0], range[0], fabs(range[0]*1.e-6))); + CHK(eq_eps(interval.range[1], range[1], fabs(range[1]*1.e-6))); + CHK(interval.cumulative > cumulative_prev); + CHK(interval.cumulative <= 1.0); + + cumulative_prev = interval.cumulative; + } + + ssp_ran_sphere_uniform(rng, wo, NULL); + FOR_EACH(i, 0, NSAMPS) { + double wi[3]; + double pdf; + ssf_phase_sample(phase, rng, wo, wi, &pdf); + CHK(eq_eps(pdf, ssf_phase_eval(phase, wo, wi), fabs(pdf*1.e-6))); + CHK(d3_is_normalized(wi)); + +#if 0 + fprintf(stderr, "v %g %g %g\n", wi[0]*pdf, wi[1]*pdf, wi[2]*pdf); + fprintf(stderr, "p %lu\n", (unsigned long)(i+1)); +#endif + } + + CHK(ssf_phase_ref_put(phase) == RES_OK); + CHK(ssf_phase_ref_put(dummy) == RES_OK); + CHK(ssp_rng_ref_put(rng) == RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); +exit: + return err; +error: + err = -1; + goto exit; +} + diff --git a/src/test_ssf_pillbox_distribution.c b/src/test_ssf_pillbox_distribution.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_specular_dielectric_dielectric_reflection.c b/src/test_ssf_specular_dielectric_dielectric_reflection.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_specular_reflection.c b/src/test_ssf_specular_reflection.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_thin_specular_dielectric.c b/src/test_ssf_thin_specular_dielectric.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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 diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016-2018 |Meso|Star> (contact@meso-star.com) +/* Copyright (C) 2016-2018, 2021 |Meso|Star> (contact@meso-star.com) * * 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