sphor_sources.c (9787B)
1 /* Copyright (C) 2024-2026 Centre National de la Recherche Scientifique 2 * Copyright (C) 2024-2026 Clermont Auvergne INP 3 * Copyright (C) 2024-2026 INSA Lyon 4 * Copyright (C) 2024-2026 Institut Mines Télécom Albi-Carmaux 5 * Copyright (C) 2024-2026 Institut National Polytechnique de Toulouse 6 * Copyright (C) 2024-2026 |Méso|Star> (contact@meso-star.com) 7 * Copyright (C) 2024-2026 PhotonLyX (info@photonlyx.com) 8 * Copyright (C) 2024-2026 Université de Lorraine 9 * Copyright (C) 2024-2026 Université Paul Sabatier 10 * Copyright (C) 2024-2026 Université Toulouse - Jean Jaurès 11 * 12 * This program is free software: you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation, either version 3 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 24 25 #include "sphor_c.h" 26 #include "sphor_config.h" 27 #include "sphor_sources.h" 28 29 #include <rsys/double3.h> 30 #include <rsys/dynamic_array_double.h> 31 #include <star/s3d.h> 32 #include <star/sphin.h> 33 #include <star/ssp.h> 34 #include <star/suniq.h> 35 36 struct sphin_geometry; 37 struct sphin_surface; 38 39 /******************************************************************************* 40 * Helper functions 41 ******************************************************************************/ 42 static res_T 43 register_surface_geometry 44 (struct sphor* sphor, 45 const struct sphor_create_args* args, 46 const struct sphin_geometry* geom, 47 struct suniq* suniq_scene, 48 struct suniq* suniq, 49 struct source_view* source) 50 { 51 struct sphin_geometry_descriptor geom_desc = SPHIN_GEOMETRY_DESCRIPTOR_NULL; 52 size_t itri = 0; 53 size_t id_scene; 54 size_t id_source; 55 res_T res = RES_OK; 56 57 ASSERT(NULL != sphor); 58 59 (void)sphor; 60 (void)args; 61 62 res = sphin_geometry_get_desc(geom, &geom_desc); 63 if (RES_OK != res) { goto error; } 64 65 FOR_EACH(itri, 0, geom_desc.mesh.triangle_count) { 66 struct suniq_triangle tri = SUNIQ_TRIANGLE_NULL; 67 68 setup_triangle(&geom_desc, itri, &tri); 69 70 /* Reverse triangle normal if side is back: 71 * 72 * Since a geometry can only be declared with one side at a time in sphin 73 * for the same source, the strategy taken is to store the triangle in the 74 * scene view in such a way that its normal points always to the hemisphere 75 * corresponding to the emitting side. In such a way, during path sampling, 76 * one can simply retrieve the normal of the sampled primitive and it will 77 * correspond to the emitting direction (subject to the convention: left or 78 * right-hand of each library) 79 */ 80 81 if (SPHIN_SIDE_BACK == geom_desc.side) { 82 double tmp[3] = {0}; 83 d3_set(tmp, tri.vertices[0]); 84 d3_set(tri.vertices[0], tri.vertices[1]); 85 d3_set(tri.vertices[1], tmp); 86 } 87 88 res = suniq_register_triangle(suniq, &tri, &id_source); 89 if (RES_OK != res) { goto error; } 90 91 /* Retrieve the id to the corresponding primitive in the scene */ 92 res = suniq_register_triangle(suniq_scene, &tri, &id_scene); 93 if (RES_OK != res) { goto error; } 94 95 /* Append scene prim_id to the source <-> scene correspondance array */ 96 if (id_source == darray_size_t_size_get(&source->src2scn)){ 97 res = darray_size_t_push_back(&source->src2scn, &id_scene); 98 if (RES_OK != res) { goto error; } 99 } 100 } 101 102 exit: 103 return res; 104 error: 105 goto exit; 106 } 107 108 static res_T 109 setup_emission_spectrum_pdf 110 (struct sphor* sphor, 111 struct sphin_surface* surface, 112 struct source_view* source) 113 { 114 struct sphin_source_surface* sphin_source = NULL; 115 struct sphin_spectral_property_descriptor spectrum = 116 SPHIN_SPECTRAL_PROPERTY_DESCRIPTOR_NULL; 117 struct sphin_source_surface_flux_density density = 118 SPHIN_SOURCE_SURFACE_FLUX_DENSITY_NULL; 119 res_T res = RES_OK; 120 121 ASSERT(NULL != sphor); 122 ASSERT(NULL != surface); 123 ASSERT(NULL != source); 124 125 SPHIN(surface_get_source(surface, &sphin_source)); 126 if (NULL == sphin_source) { res = RES_BAD_ARG; goto error; } 127 128 SPHIN(source_surface_get_flux_density(sphin_source, &density)); 129 130 if (NULL == density.emission_spectrum) { res = RES_BAD_ARG; goto error; } 131 132 SPHIN(spectral_property_get_desc(density.emission_spectrum, &spectrum)); 133 134 res = ssp_ranst_piecewise_linear_create 135 (sphor->allocator, &source->emission_spectrum_pdf); 136 if (RES_OK != res) { goto error; } 137 138 res = ssp_ranst_piecewise_linear_setup 139 (source->emission_spectrum_pdf, 140 spectrum.wavelengths, 141 spectrum.values, 142 spectrum.data_count); 143 if (RES_OK != res) { goto error; } 144 145 exit: 146 return res; 147 error: 148 if (source->emission_spectrum_pdf != NULL) { 149 SSP(ranst_piecewise_linear_ref_put(source->emission_spectrum_pdf)); 150 } 151 goto exit; 152 } 153 154 static res_T 155 setup_source_view 156 (struct sphor* sphor, 157 const struct sphor_create_args* args, 158 struct sphin_surface* surface, 159 struct suniq* suniq_scene, 160 struct source_view* source) 161 { 162 struct suniq* suniq = NULL; 163 struct sphin_geometry* geom = NULL; 164 size_t i_geometry = 0; 165 size_t geometry_count = 0; 166 res_T res = RES_OK; 167 168 ASSERT(NULL != sphor); 169 170 res = suniq_create(sphor->allocator, &suniq); 171 if (RES_OK != res) { goto error; } 172 173 res = sphin_surface_get_geometry_count(surface, &geometry_count); 174 if (RES_OK != res) { goto error; } 175 176 FOR_EACH(i_geometry, 0, geometry_count) { 177 res = sphin_surface_get_geometry(surface, i_geometry, &geom); 178 if (RES_OK != res) { goto error; } 179 180 res = register_surface_geometry 181 (sphor, args, geom, suniq_scene, suniq, source); 182 if (RES_OK != res) { goto error; } 183 } 184 185 res = setup_geometry_accel_struct(sphor, suniq, S3D_SAMPLE, &source->view); 186 if (RES_OK != res) { goto error; } 187 188 res = setup_emission_spectrum_pdf(sphor, surface, source); 189 if (RES_OK != res) { goto error; } 190 191 exit: 192 if (NULL != suniq) { SUNIQ(ref_put(suniq)); } 193 return res; 194 error: 195 goto exit; 196 } 197 198 static res_T 199 register_source_view 200 (struct sphor* sphor, 201 const struct sphor_create_args* args, 202 const size_t isurface, 203 struct suniq* suniq_scene) 204 { 205 struct sphin_surface* surface = NULL; 206 struct sphin_source_surface* source_surface = NULL; 207 struct source_view source = SOURCE_VIEW_NULL; 208 res_T res = RES_OK; 209 210 ASSERT(NULL != sphor); 211 ASSERT(NULL != args); 212 213 source_init(sphor->allocator, &source); 214 215 SPHIN(config_get_surface(sphor->config, isurface, &surface)); 216 SPHIN(surface_get_source(surface, &source_surface)); 217 ASSERT(NULL != source_surface); 218 219 source.sphin_id = isurface; 220 221 res = setup_source_view(sphor, args, surface, suniq_scene, &source); 222 if (RES_OK != res) { goto error; } 223 224 res = darray_source_view_push_back(&sphor->source_views, &source); 225 if (RES_OK != res) { goto error; } 226 227 exit: 228 source_release(&source); 229 return res; 230 error: 231 goto exit; 232 } 233 234 /******************************************************************************* 235 * Local functions 236 ******************************************************************************/ 237 res_T 238 setup_source_views 239 (struct sphor* sphor, 240 const struct sphor_create_args* args, 241 struct suniq* suniq_scene) 242 243 { 244 struct sphin_source_surface* source_surface = NULL; 245 struct sphin_surface* surface = NULL; 246 size_t surface_count = 0; 247 size_t i_surface = 0; 248 res_T res = RES_OK; 249 250 ASSERT(NULL != sphor); 251 ASSERT(NULL != sphor->config); 252 253 res = sphin_config_get_surface_count(sphor->config, &surface_count); 254 if (RES_OK != res) { goto error; } 255 256 FOR_EACH(i_surface, 0, surface_count) { 257 res = sphin_config_get_surface(sphor->config, i_surface, &surface); 258 if (RES_OK != res) { goto error; } 259 260 res = sphin_surface_get_source(surface, &source_surface); 261 if (RES_OK != res) { goto error; } 262 263 if (NULL != source_surface) { 264 res = register_source_view(sphor, args, i_surface, suniq_scene); 265 if (RES_OK != res) { goto error; } 266 } 267 } 268 269 exit: 270 return res; 271 error: 272 goto exit; 273 } 274 275 res_T 276 setup_source_distrib_power 277 (struct sphor* sphor, 278 const struct sphor_create_args* args) 279 { 280 double power = 0; 281 size_t i_surface = 0; 282 size_t surface_count = 0; 283 struct darray_double powers; 284 struct sphin_source_surface* source_surface = NULL; 285 struct sphin_surface* surface = NULL; 286 res_T res = RES_OK; 287 288 ASSERT(NULL != sphor); 289 ASSERT(NULL != args); 290 291 (void) args; 292 293 darray_double_init(sphor->allocator, &powers); 294 295 res = sphin_config_get_surface_count(sphor->config, &surface_count); 296 if (RES_OK != res) { goto error; } 297 298 FOR_EACH(i_surface, 0, surface_count) { 299 res = sphin_config_get_surface(sphor->config, i_surface, &surface); 300 if (RES_OK != res) { goto error; } 301 302 res = sphin_surface_get_source(surface, &source_surface); 303 if (RES_OK != res) { goto error; } 304 305 if (NULL != source_surface) { 306 res = sphin_surface_source_get_power(surface, &power); 307 if (RES_OK != res) { goto error; } 308 res = darray_double_push_back(&powers, &power); 309 if (RES_OK != res) { goto error; } 310 } 311 } 312 313 if (0 == darray_double_size_get(&powers)) { 314 ERROR(sphor, 315 "No sources defined in input file. " 316 "Nothing to do.\n"); 317 res = RES_BAD_ARG; 318 goto error; 319 } 320 321 res = ssp_ranst_discrete_create 322 (sphor->allocator, &sphor->source_distrib_power); 323 if (RES_OK != res) { goto error; } 324 325 res = ssp_ranst_discrete_setup 326 (sphor->source_distrib_power, 327 darray_double_cdata_get(&powers), 328 darray_double_size_get(&powers)); 329 if (RES_OK != res) { goto error; } 330 331 exit: 332 darray_double_release(&powers); 333 return res; 334 error: 335 goto exit; 336 }