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:
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);
}