star-phor

Radiative transfer solver for photoreactors.
git clone https://www.edstar.cnrs.fr/git/star-phor.git
Log | Files | Refs | README | LICENSE

commit 08c0275e93e70fc4af24e8a2b529bd73ca878d70
parent 582c23ab75fdc47c01005dac784bb318443235aa
Author: Eduardo Fontana Lazzari <edufonlaz@gmail.com>
Date:   Tue, 10 Jun 2025 17:18:30 +0200

Setup source views and power distribution functions

This commit introduces intermediate data structures and functions to
enable sampling of sources in different ways within a given
configuration. Two new member variables are added to the sphor struct:

 - a list containing the total power of each source. This list is used
   to sample a source among all sources in the configuration, weighted
   by their total power. Sampling is handled by the star-sampling (ssp)
   library, which provides API functions for sampling discrete
   probability distributions as well as other sampling functions which
   will be used in this project.
 - a list of scene views, where each scene view corresponds to a
   distinct source in the configuration. These scene views are managed
   by s3d, which accelerates sampling of positions within a list of
   triangles using the S3D_SAMPLE mask.

Additionally, functions to sample a source relative to its total power,
to uniformly sample a position within a given source, and to sample a
source position across the entire scene according to each source’s total
power are introduced for internal use in the library.

This commit adds a new dependency on star-sampling.

Diffstat:
MMakefile | 13++++++++-----
MREADME.md | 1+
Mconfig.mk | 7++++---
Msphor.pc.in | 7+++++--
Msrc/sphor.c | 6++++++
Msrc/sphor_c.h | 21++++++++++++++++++++-
Msrc/sphor_config.c | 234++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Asrc/sphor_sources.c | 329+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sphor_sources.h | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_sphor_lib.c | 2+-
10 files changed, 644 insertions(+), 121 deletions(-)

diff --git a/Makefile b/Makefile @@ -38,7 +38,8 @@ all: executable library tests ################################################################################ SRC_LIB =\ src/sphor.c\ - src/sphor_config.c + src/sphor_config.c\ + src/sphor_sources.c OBJ_LIB = $(SRC_LIB:.c=.o) DEP_LIB = $(SRC_LIB:.c=.d) @@ -58,8 +59,9 @@ $(LIBNAME): $(OBJ_LIB) .config: config.mk $(PKG_CONFIG) --atleast-version $(RSYS_VERSION) rsys - $(PKG_CONFIG) --atleast-version $(SPHIN_VERSION) sphin $(PKG_CONFIG) --atleast-version $(S3D_VERSION) s3d + $(PKG_CONFIG) --atleast-version $(SPHIN_VERSION) sphin + $(PKG_CONFIG) --atleast-version $(SSP_VERSION) star-sp $(PKG_CONFIG) --atleast-version $(SUNIQ_VERSION) suniq echo "config done" > $@ @@ -72,7 +74,7 @@ $(LIBNAME): $(OBJ_LIB) clean: clean_test clean_executable rm -f $(DEP_LIB) $(OBJ_LIB) $(LIBNAME) - rm -f .config sphor-local.pc sphor.pc + rm -f .config sphor-local.pc sphor.pc star-phor.1 ################################################################################ # Executable building @@ -114,8 +116,9 @@ pkg: sed -e 's#@PREFIX@#$(PREFIX)#g'\ -e 's#@VERSION@#$(VERSION)#g'\ -e 's#@RSYS_VERSION@#$(RSYS_VERSION)#g'\ - -e 's#@SPHIN_VERSION@#$(SPHIN_VERSION)#g'\ -e 's#@S3D_VERSION@#$(S3D_VERSION)#g'\ + -e 's#@SPHIN_VERSION@#$(SPHIN_VERSION)#g'\ + -e 's#@SSP_VERSION@#$(SSP_VERSION)#g'\ -e 's#@SUNIQ_VERSION@#$(SUNIQ_VERSION)#g'\ sphor.pc.in > sphor.pc @@ -208,5 +211,5 @@ test_sphor_lib\ $(CC) $(CFLAGS_TEST) -o $@ src/$@.o $(LDFLAGS_TEST) clean_test: - rm -f $(TEST_DEP) $(TEST_OBJ) $(TEST_TGT) input + rm -f $(TEST_DEP) $(TEST_OBJ) $(TEST_TGT) input cube.stl for i in $(TEST_SRC); do rm -f "$$(basename "$${i}" ".c")"; done diff --git a/README.md b/README.md @@ -10,6 +10,7 @@ Solver for radiative transfer in photoreactors. - rsys - star-phor-input - star-3d +- star-sp - star-uniq ## Installation diff --git a/config.mk b/config.mk @@ -22,13 +22,14 @@ RANLIB = ranlib ################################################################################ # Dependencies ################################################################################ -SPHIN_VERSION=0.0 RSYS_VERSION=0.14 S3D_VERSION=0.10 +SPHIN_VERSION=0.0 +SSP_VERSION=0.14 SUNIQ_VERSION=0.0 -INCS = $$($(PKG_CONFIG) --cflags rsys sphin s3d suniq) -LIBS = $$($(PKG_CONFIG) --libs rsys sphin s3d suniq) +INCS = $$($(PKG_CONFIG) --cflags rsys s3d sphin star-sp suniq) +LIBS = $$($(PKG_CONFIG) --libs rsys s3d sphin star-sp suniq) ################################################################################ # Compilation options diff --git a/sphor.pc.in b/sphor.pc.in @@ -3,8 +3,11 @@ includedir=${prefix}/include libdir=${prefix}/lib Requires: rsys >= @RSYS_VERSION@ -Requires.private: sphin >= @SPHIN_VERSION@ -Requires.private: s3d >= @S3D_VERSION@ +Requires.private:\ + s3d >= @S3D_VERSION@,\ + sphin >= @SPHIN_VERSION@,\ + star-sp >= @SSP_VERSION@,\ + suniq >= @SUNIQ_VERSION@ Name: Star-Phor Description: statistical solver for radiative transfer in photoreactors Version: @VERSION@ diff --git a/src/sphor.c b/src/sphor.c @@ -27,6 +27,7 @@ #include <star/sphin.h> #include <star/s3d.h> +#include <star/ssp.h> #include <rsys/logger.h> #include <rsys/mem_allocator.h> @@ -58,7 +59,11 @@ release_sphor if (NULL != sphor->scene_view) { s3d_scene_view_ref_put(sphor->scene_view); } + if (NULL != sphor->source_distrib_power) { + ssp_ranst_discrete_ref_put(sphor->source_distrib_power); + } darray_interface_release(&sphor->interfaces); + darray_source_view_release(&sphor->source_views); MEM_RM(sphor->allocator, sphor); } @@ -100,6 +105,7 @@ sphor_create sphor->logger = args->logger; } darray_interface_init(sphor->allocator, &sphor->interfaces); + darray_source_view_init(sphor->allocator, &sphor->source_views); /* Load the system and build data structure for Monte Carlo */ res = setup_config(sphor, args); diff --git a/src/sphor_c.h b/src/sphor_c.h @@ -26,6 +26,7 @@ #define SPHOR_C_H #include "sphor_interface.h" +#include "sphor_sources.h" #include <rsys/double3.h> #include <rsys/dynamic_array.h> @@ -45,17 +46,22 @@ /* Forward declarations */ struct logger; struct mem_allocator; +struct s3d_scene_view; struct sphin_config; +struct sphin_geometry_descriptor; struct sphor_create_args; -struct s3d_scene_view; +struct suniq; +struct suniq_triangle; struct sphor { /* Physical configuration */ struct sphin_config* config; struct darray_interface interfaces; + struct ssp_ranst_discrete* source_distrib_power; /* Geometrical data */ struct s3d_scene_view* scene_view; + struct darray_source_view source_views; /* Log */ struct logger* logger; @@ -71,4 +77,17 @@ setup_config (struct sphor* sphor, const struct sphor_create_args* args); +extern LOCAL_SYM void +setup_triangle + (const struct sphin_geometry_descriptor* geom_desc, + const size_t itri, + struct suniq_triangle* tri); + +extern LOCAL_SYM res_T +setup_geometry_accel_struct + (struct sphor* sphor, + struct suniq* suniq, + const int view_mask, /* Combination of s3d_scene_view flags */ + struct s3d_scene_view** out_view); + #endif /* SPHOR_C_H */ diff --git a/src/sphor_config.c b/src/sphor_config.c @@ -79,50 +79,6 @@ are_triangles_reversed } } -static void -setup_triangle - (const struct sphin_geometry_descriptor* geom_desc, - const size_t itri, - struct suniq_triangle* tri) -{ - const double* coords[3] = {NULL, NULL, NULL}; - size_t ids[3] = {0, 0, 0}; - - ASSERT(NULL != geom_desc); - ASSERT(NULL != tri); - ASSERT(itri < geom_desc->mesh.triangle_count); - - /* Get the indices of the triangle vertices. They are stored in a one - * dimensional array. So, to retrieve the vertex indices of the i^th triangle, - * one has to multiply i by 3, i.e. the number of vertex per triangle : - * - * 0 1 2 3 4 5 6 7 8 - * +---+---+---+---+---+---+---+---+---+----- - * indices |id0|id1|id2|id0|id1|id2|id0|id1|id2| ... - * +---+---+---+---+---+---+---+---+---+----- - * \__tri 0__/ \__tri 1__/ \__tri 2__/ */ - ids[0] = geom_desc->mesh.indices[itri*3/*#indices per triangle*/+0]; - ids[1] = geom_desc->mesh.indices[itri*3/*#indices per triangle*/+1]; - ids[2] = geom_desc->mesh.indices[itri*3/*#indices per triangle*/+2]; - - /* Get coords for the triangle corresponding to the vertices retrieved. Like - * the indices, the coords are stored in an one dimensional array. - * - * 0 1 2 3 4 5 6 7 8 - * +---+---+---+---+---+---+---+---+---+----- - * coords | x | y | z | x | y | z | x | y | z | ... - * +---+---+---+---+---+---+---+---+---+----- - * \__vert0__/ \__vert1__/ \__vert2__/ */ - coords[0] = geom_desc->mesh.coords + ids[0]*3/*#coords per vertex*/; - coords[1] = geom_desc->mesh.coords + ids[1]*3/*#coords per vertex*/; - coords[2] = geom_desc->mesh.coords + ids[2]*3/*#coords per vertex*/; - - /* Set the retrieved coords to the triangle struct */ - d3_set(tri->vertices[0], coords[0]); - d3_set(tri->vertices[1], coords[1]); - d3_set(tri->vertices[2], coords[2]); -} - static res_T register_interface (struct sphor* sphor, @@ -512,70 +468,6 @@ get_vertex_coords } static res_T -setup_geometry_accel_struct - (struct sphor* sphor, - struct suniq* suniq) -{ - struct suniq_desc desc = SUNIQ_DESC_NULL; - struct s3d_vertex_data vertex_data; - struct s3d_device* device = NULL; - struct s3d_scene* scene = NULL; - struct s3d_scene_view* view = NULL; - struct s3d_shape* shape = NULL; - res_T res = RES_OK; - - ASSERT(NULL != sphor); - ASSERT(NULL != suniq); - - res = suniq_get_desc(suniq, &desc); - if (RES_OK != res) { goto error; } - - if (0 == desc.ntriangles) { - ERROR(sphor, - "Could not start simulation: no geometries found in the input file.\n"); - res = RES_BAD_ARG; - goto error; - } - - res = s3d_device_create - (sphor->logger, sphor->allocator, sphor->verbose, &device); - if (RES_OK != res) { goto error; } - - res = s3d_shape_create_mesh(device, &shape); - if (RES_OK != res) { goto error; } - - vertex_data.usage = S3D_POSITION; - vertex_data.type = S3D_FLOAT3; - vertex_data.get = get_vertex_coords; - res = s3d_mesh_setup_indexed_vertices - (shape, (unsigned)desc.ntriangles, get_triangle_indices, - (unsigned)desc.nvertices, &vertex_data, 1, &desc); - if (RES_OK != res) { goto error; } - - res = s3d_scene_create(device, &scene); - if (RES_OK != res) { goto error; } - - res = s3d_scene_attach_shape(scene, shape); - if (RES_OK != res) { goto error; } - - res = s3d_scene_view_create(scene, S3D_TRACE, &view); - if (RES_OK != res) { goto error; } - -exit: - if (NULL != device) { S3D(device_ref_put(device)); } - if (NULL != shape) { S3D(shape_ref_put(shape)); } - if (NULL != scene) { S3D(scene_ref_put(scene)); } - sphor->scene_view = view; - return res; -error: - if (NULL != view) { - S3D(scene_view_ref_put(view)); - view = NULL; - } - goto exit; -} - -static res_T load_config (struct sphor* sphor, const struct sphor_create_args* args) @@ -639,12 +531,23 @@ setup_config res = load_config(sphor, args); if (RES_OK != res) { goto error; } + /* Setup the scene views for each source to accelerate the sampling of a + * position in a given source */ + res = setup_source_views(sphor, args); + if (RES_OK != res) { goto error; } + + /* Compute distribution used to important sample a source with respect to + * their power */ + res = setup_source_distrib_power(sphor, args); + if (RES_OK != res) { goto error; } + /* Attach physical properties to primitives */ res = setup_interfaces(sphor, suniq); if (RES_OK != res) { goto error; } /* Build accelerating structure for geometrical data */ - res = setup_geometry_accel_struct(sphor, suniq); + res = setup_geometry_accel_struct + (sphor, suniq, S3D_TRACE, &sphor->scene_view); if (RES_OK != res) { goto error; } exit: @@ -653,3 +556,116 @@ exit: error: goto exit; } + +void +setup_triangle + (const struct sphin_geometry_descriptor* geom_desc, + const size_t itri, + struct suniq_triangle* tri) +{ + const double* coords[3] = {NULL, NULL, NULL}; + size_t ids[3] = {0, 0, 0}; + + ASSERT(NULL != geom_desc); + ASSERT(NULL != tri); + ASSERT(itri < geom_desc->mesh.triangle_count); + + /* Get the indices of the triangle vertices. They are stored in a one + * dimensional array. So, to retrieve the vertex indices of the i^th triangle, + * one has to multiply i by 3, i.e. the number of vertex per triangle : + * + * 0 1 2 3 4 5 6 7 8 + * +---+---+---+---+---+---+---+---+---+----- + * indices |id0|id1|id2|id0|id1|id2|id0|id1|id2| ... + * +---+---+---+---+---+---+---+---+---+----- + * \__tri 0__/ \__tri 1__/ \__tri 2__/ */ + ids[0] = geom_desc->mesh.indices[itri*3/*#indices per triangle*/+0]; + ids[1] = geom_desc->mesh.indices[itri*3/*#indices per triangle*/+1]; + ids[2] = geom_desc->mesh.indices[itri*3/*#indices per triangle*/+2]; + + /* Get coords for the triangle corresponding to the vertices retrieved. Like + * the indices, the coords are stored in an one dimensional array. + * + * 0 1 2 3 4 5 6 7 8 + * +---+---+---+---+---+---+---+---+---+----- + * coords | x | y | z | x | y | z | x | y | z | ... + * +---+---+---+---+---+---+---+---+---+----- + * \__vert0__/ \__vert1__/ \__vert2__/ */ + coords[0] = geom_desc->mesh.coords + ids[0]*3/*#coords per vertex*/; + coords[1] = geom_desc->mesh.coords + ids[1]*3/*#coords per vertex*/; + coords[2] = geom_desc->mesh.coords + ids[2]*3/*#coords per vertex*/; + + /* Set the retrieved coords to the triangle struct */ + d3_set(tri->vertices[0], coords[0]); + d3_set(tri->vertices[1], coords[1]); + d3_set(tri->vertices[2], coords[2]); +} + +res_T +setup_geometry_accel_struct + (struct sphor* sphor, + struct suniq* suniq, + const int view_mask, /* Combination of s3d_scene_view flags */ + struct s3d_scene_view** out_view) +{ + struct suniq_desc desc = SUNIQ_DESC_NULL; + struct s3d_vertex_data vertex_data; + struct s3d_device* device = NULL; + struct s3d_scene* scene = NULL; + struct s3d_scene_view* view = NULL; + struct s3d_shape* shape = NULL; + res_T res = RES_OK; + + ASSERT(NULL != sphor); + ASSERT(NULL != suniq); + ASSERT(NULL != out_view); + ASSERT(0 != view_mask); + + res = suniq_get_desc(suniq, &desc); + if (RES_OK != res) { goto error; } + + if (0 == desc.ntriangles) { + ERROR(sphor, + "Could not start simulation: " + "surfaces and volumes should have a geometry\n"); + res = RES_BAD_ARG; + goto error; + } + + res = s3d_device_create + (sphor->logger, sphor->allocator, sphor->verbose, &device); + if (RES_OK != res) { goto error; } + + res = s3d_shape_create_mesh(device, &shape); + if (RES_OK != res) { goto error; } + + vertex_data.usage = S3D_POSITION; + vertex_data.type = S3D_FLOAT3; + vertex_data.get = get_vertex_coords; + res = s3d_mesh_setup_indexed_vertices + (shape, (unsigned)desc.ntriangles, get_triangle_indices, + (unsigned)desc.nvertices, &vertex_data, 1, &desc); + if (RES_OK != res) { goto error; } + + res = s3d_scene_create(device, &scene); + if (RES_OK != res) { goto error; } + + res = s3d_scene_attach_shape(scene, shape); + if (RES_OK != res) { goto error; } + + res = s3d_scene_view_create(scene, view_mask, &view); + if (RES_OK != res) { goto error; } + +exit: + if (NULL != device) { S3D(device_ref_put(device)); } + if (NULL != shape) { S3D(shape_ref_put(shape)); } + if (NULL != scene) { S3D(scene_ref_put(scene)); } + *out_view = view; + return res; +error: + if (NULL != view) { + S3D(scene_view_ref_put(view)); + view = NULL; + } + goto exit; +} diff --git a/src/sphor_sources.c b/src/sphor_sources.c @@ -0,0 +1,329 @@ +/* Copyright (C) 2024-2025 Centre National de la Recherche Scientifique + * Copyright (C) 2024-2025 Clermont Auvergne INP + * Copyright (C) 2024-2025 INSA Lyon + * Copyright (C) 2024-2025 Institut Mines Télécom Albi-Carmaux + * Copyright (C) 2024-2025 Institut National Polytechnique de Toulouse + * Copyright (C) 2024-2025 |Méso|Star> (contact@meso-star.com) + * Copyright (C) 2024-2025 PhotonLyX (info@photonlyx.com) + * Copyright (C) 2024-2025 Université de Lorraine + * Copyright (C) 2024-2025 Université Paul Sabatier + * Copyright (C) 2024-2025 Université Toulouse - Jean Jaurès + * + * 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 "sphor_c.h" +#include "sphor_sources.h" + +#include <star/sphin.h> +#include <star/ssp.h> +#include <star/suniq.h> +#include <rsys/dynamic_array_double.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static res_T +register_surface_geometry + (struct sphor* sphor, + const struct sphor_create_args* args, + const struct sphin_geometry* geom, + struct suniq* suniq) +{ + struct sphin_geometry_descriptor geom_desc = SPHIN_GEOMETRY_DESCRIPTOR_NULL; + size_t itri = 0; + res_T res = RES_OK; + + ASSERT(NULL != sphor); + + (void)sphor; + (void)args; + + res = sphin_geometry_get_desc(geom, &geom_desc); + if (RES_OK != res) { goto error; } + + FOR_EACH(itri, 0, geom_desc.mesh.triangle_count) { + struct suniq_triangle tri = SUNIQ_TRIANGLE_NULL; + + setup_triangle(&geom_desc, itri, &tri); + + res = suniq_register_triangle(suniq, &tri, NULL); + if (RES_OK != res) { goto error; } + } + +exit: + return res; +error: + goto exit; +} + +static res_T +setup_source_view + (struct sphor* sphor, + const struct sphor_create_args* args, + struct sphin_surface* surface, + struct s3d_scene_view** out_view) +{ + struct suniq* suniq = NULL; + struct sphin_geometry* geom = NULL; + struct s3d_scene_view* view = NULL; + size_t i_geometry = 0; + size_t geometry_count = 0; + res_T res = RES_OK; + + ASSERT(NULL != sphor); + + res = suniq_create(sphor->allocator, &suniq); + if (RES_OK != res) { goto error; } + + res = sphin_surface_get_geometry_count(surface, &geometry_count); + if (RES_OK != res) { goto error; } + + FOR_EACH(i_geometry, 0, geometry_count) { + res = sphin_surface_get_geometry(surface, i_geometry, &geom); + if (RES_OK != res) { goto error; } + + res = register_surface_geometry(sphor, args, geom, suniq); + if (RES_OK != res) { goto error; } + } + + res = setup_geometry_accel_struct(sphor, suniq, S3D_SAMPLE, &view); + if (RES_OK != res) { goto error; } + +exit: + if (NULL != suniq) { SUNIQ(ref_put(suniq)); } + *out_view = view; + return res; +error: + if (NULL != view) { + S3D(scene_view_ref_get(view)); + view = NULL; + } + goto exit; +} + +static res_T +register_source_view + (struct sphor* sphor, + const struct sphor_create_args* args, + const size_t isurface) +{ + struct sphin_surface* surface = NULL; + struct sphin_source_surface* source_surface = NULL; + struct source_view source = SOURCE_VIEW_NULL; + double power = 0; + res_T res = RES_OK; + + ASSERT(NULL != sphor); + ASSERT(NULL != args); + ASSERT(NULL != surface); + + source_init(sphor->allocator, &source); + + SPHIN(config_get_surface(sphor->config, isurface, &surface)); + SPHIN(surface_get_source(surface, &source_surface)); + ASSERT(NULL != source_surface); + + res = sphin_surface_source_get_power(surface, &power); + if (RES_OK != res) { goto error; } + + source.sphin_id = isurface; + + res = setup_source_view(sphor, args, surface, &source.view); + if (RES_OK != res) { goto error; } + + res = darray_source_view_push_back(&sphor->source_views, &source); + if (RES_OK != res) { goto error; } + +exit: + source_release(&source); + return res; +error: + goto exit; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +setup_source_views + (struct sphor* sphor, + const struct sphor_create_args* args) +{ + struct sphin_source_surface* source_surface = NULL; + struct sphin_surface* surface = NULL; + size_t surface_count = 0; + size_t i_surface = 0; + res_T res = RES_OK; + + ASSERT(NULL != sphor); + ASSERT(NULL != sphor->config); + + res = sphin_config_get_surface_count(sphor->config, &surface_count); + if (RES_OK != res) { goto error; } + + FOR_EACH(i_surface, 0, surface_count) { + res = sphin_config_get_surface(sphor->config, i_surface, &surface); + if (RES_OK != res) { goto error; } + + res = sphin_surface_get_source(surface, &source_surface); + if (RES_OK != res) { goto error; } + + if (NULL != source_surface) { + res = register_source_view(sphor, args, i_surface); + if (RES_OK != res) { goto error; } + } + } + +exit: + return res; +error: + goto exit; +} + +res_T +setup_source_distrib_power + (struct sphor* sphor, + const struct sphor_create_args* args) +{ + size_t i_surface = 0; + size_t surface_count = 0; + struct darray_double powers; + struct sphin_source_surface* source_surface = NULL; + struct sphin_surface* surface = NULL; + res_T res = RES_OK; + + ASSERT(NULL != sphor); + ASSERT(NULL != args); + + (void) args; + + darray_double_init(sphor->allocator, &powers); + + res = sphin_config_get_surface_count(sphor->config, &surface_count); + if (RES_OK != res) { goto error; } + + FOR_EACH(i_surface, 0, surface_count) { + res = sphin_config_get_surface(sphor->config, i_surface, &surface); + if (RES_OK != res) { goto error; } + + res = sphin_surface_get_source(surface, &source_surface); + if (RES_OK != res) { goto error; } + + if (NULL != source_surface) { + double power = 0; + res = sphin_surface_source_get_power(surface, &power); + if (RES_OK != res) { goto error; } + res = darray_double_push_back(&powers, &power); + if (RES_OK != res) { goto error; } + } + } + + res = ssp_ranst_discrete_create + (sphor->allocator, &sphor->source_distrib_power); + if (RES_OK != res) { goto error; } + + res = ssp_ranst_discrete_setup + (sphor->source_distrib_power, + darray_double_cdata_get(&powers), + darray_double_size_get(&powers)); + if (RES_OK != res) { goto error; } + +exit: + darray_double_release(&powers); + return res; +error: + goto exit; +} + +res_T +sample_source_view + (struct sphor* sphor, + struct ssp_rng* rng, + const struct source_view** source_view) +{ + const struct source_view* source_views = NULL; + size_t isource_view = 0; + + ASSERT(NULL != sphor); + ASSERT(NULL != rng); + + isource_view = ssp_ranst_discrete_get(rng, sphor->source_distrib_power); + + source_views = darray_source_view_cdata_get(&sphor->source_views); + *source_view = &source_views[isource_view]; + + return RES_OK; +} + +res_T +sample_source_position + (struct sphor* sphor, + struct ssp_rng* rng, + const struct source_view* source_view, + struct s3d_primitive* primitive, + double st[2]) +{ + float u = 0; + float v = 0; + float w = 0; + float uv[2]; + res_T res = RES_OK; + + ASSERT(NULL != rng); + ASSERT(NULL != sphor); + ASSERT(NULL != source_view); + + (void)sphor; + + u = (float)ssp_rng_canonical(rng); + v = (float)ssp_rng_canonical(rng); + w = (float)ssp_rng_canonical(rng); + + res = s3d_scene_view_sample(source_view->view, u, v, w, primitive, uv); + if (RES_OK != res) { goto error; } + + st[0] = uv[0]; + st[1] = uv[1]; + +exit: + return res; +error: + goto exit; +} + +res_T +sample_source_view_and_position + (struct sphor* sphor, + struct ssp_rng* rng, + struct s3d_primitive* primitive, + double st[2]) +{ + const struct source_view* source_to_sample = NULL; + res_T res = RES_OK; + + ASSERT(NULL != sphor); + ASSERT(NULL != rng); + + res = sample_source_view(sphor, rng, &source_to_sample); + if (RES_OK != res) { goto error; } + + res = sample_source_position(sphor, rng, source_to_sample, primitive, st); + if (RES_OK != res) { goto error; } + +exit: + return res; +error: + goto exit; + +} diff --git a/src/sphor_sources.h b/src/sphor_sources.h @@ -0,0 +1,145 @@ +/* Copyright (C) 2024-2025 Centre National de la Recherche Scientifique + * Copyright (C) 2024-2025 Clermont Auvergne INP + * Copyright (C) 2024-2025 INSA Lyon + * Copyright (C) 2024-2025 Institut Mines Télécom Albi-Carmaux + * Copyright (C) 2024-2025 Institut National Polytechnique de Toulouse + * Copyright (C) 2024-2025 |Méso|Star> (contact@meso-star.com) + * Copyright (C) 2024-2025 PhotonLyX (info@photonlyx.com) + * Copyright (C) 2024-2025 Université de Lorraine + * Copyright (C) 2024-2025 Université Paul Sabatier + + * 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 SPHOR_SOURCES_H +#define SPHOR_SOURCES_H + +#include <star/s3d.h> +#include <rsys/dynamic_array.h> + +/* Forward declarations */ +struct sphor; +struct sphor_create_args; +struct s3d_scene_view; +struct ssp_rng; + +struct source_view { + struct s3d_scene_view* view; /* View of the source */ + size_t sphin_id; /* Source identifier in star-phor-input */ +}; + +#define SOURCE_VIEW_NULL__ {NULL, 0} +static const struct source_view SOURCE_VIEW_NULL = SOURCE_VIEW_NULL__; + +static INLINE void +source_init + (struct mem_allocator* allocator, + struct source_view* source) +{ + ASSERT(NULL != allocator); + ASSERT(NULL != source); + + (void) allocator; + + *source = SOURCE_VIEW_NULL; +} + +static INLINE void +source_release + (struct source_view* source) +{ + ASSERT(NULL != source); + + if(NULL != source->view) { + S3D(scene_view_ref_put(source->view)); + source->view = NULL; + } +} + +static INLINE res_T +source_copy + (struct source_view* dst, + const struct source_view* src) +{ + ASSERT(NULL != dst); + ASSERT(NULL != src); + + dst->sphin_id = src->sphin_id; + S3D(scene_view_ref_get(src->view)); + dst->view = src->view; + + return RES_OK; +} + +static INLINE res_T +source_copy_and_release + (struct source_view* dst, + struct source_view* src) +{ + ASSERT(NULL != dst); + ASSERT(NULL != src); + + dst->sphin_id = src->sphin_id; + dst->view = src->view; + + src->view = NULL; + + return RES_OK; +} + +/* Generate darray_source_view data type and API */ +#define DARRAY_NAME source_view +#define DARRAY_DATA struct source_view +#define DARRAY_FUNCTOR_INIT source_init +#define DARRAY_FUNCTOR_RELEASE source_release +#define DARRAY_FUNCTOR_COPY source_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE source_copy_and_release +#include <rsys/dynamic_array.h> + +extern LOCAL_SYM res_T +setup_source_views + (struct sphor* sphor, + const struct sphor_create_args* args); + +extern LOCAL_SYM res_T +setup_source_distrib_power + (struct sphor* sphor, + const struct sphor_create_args* args); + +/* Sample a source view considering the discrete distribution of power of all + * sources in the config */ +extern LOCAL_SYM res_T +sample_source_view + (struct sphor* sphor, + struct ssp_rng* rng, + const struct source_view** source_view); + +/* Sample a position unifomly in a given source */ +extern LOCAL_SYM res_T +sample_source_position + (struct sphor* sphor, + struct ssp_rng* rng, + const struct source_view* source_view, + struct s3d_primitive* primitive, + double st[2]); + +/* Sample a source considering the discrete distribution of power and then + * sample a position uniformly in this source. */ +extern LOCAL_SYM res_T +sample_source_view_and_position + (struct sphor* sphor, + struct ssp_rng* rng, + struct s3d_primitive* primitive, + double st[2]); + +#endif /* SPHOR_SOURCES_H */ diff --git a/src/test_sphor_lib.c b/src/test_sphor_lib.c @@ -88,7 +88,7 @@ write_input_file(FILE* fp) write_cube(geom_filename); - fprintf(fp, "volume: \"test volume\"\n"); + fprintf(fp, "surface: \"test surface\"\n"); fprintf(fp, "\tgeometry: BACK %s\n", geom_filename); CHK(fflush(fp) == 0); }