star-gf

Compute Gebhart factors
git clone git://git.meso-star.fr/star-gf.git
Log | Files | Refs | README | LICENSE

sgf_scene.c (11671B)


      1 /* Copyright (C) 2021, 2024 |Meso|Star> (contact@meso-star.com)
      2  * Copyright (C) 2015-2018 EDF S.A., France (syrthes-support@edf.fr)
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     16 
     17 #include "sgf.h"
     18 #include "sgf_device_c.h"
     19 #include "sgf_scene_c.h"
     20 
     21 #include <star/s2d.h>
     22 #include <star/s3d.h>
     23 
     24 /*******************************************************************************
     25  * Helper functions
     26  ******************************************************************************/
     27 static int
     28 hit_filter_s3d
     29   (const struct s3d_hit* hit,
     30    const float org[3],
     31    const float dir[3],
     32    const float range[2],
     33    void* ray_data,
     34    void* filter_data)
     35 {
     36   struct s3d_primitive* prim_from = ray_data;
     37   (void)org, (void)dir, (void)range, (void)filter_data;
     38 
     39   if(!ray_data) return 0;
     40   /* Discard primitive from which the ray starts from */
     41   if(S3D_PRIMITIVE_EQ(prim_from, &hit->prim)) return 1;
     42   /* Ray starts on an edge and intersect the neighbor triangle */
     43   if(hit->distance <= 0) return 1;
     44   return 0;
     45 }
     46 
     47 static int
     48 hit_filter_s2d
     49   (const struct s2d_hit* hit,
     50    const float org[3],
     51    const float dir[3],
     52    const float range[2],
     53    void* ray_data,
     54    void* filter_data)
     55 {
     56   struct s2d_primitive* prim_from = ray_data;
     57   (void)org, (void)dir, (void)range, (void)filter_data;
     58 
     59   if(!ray_data) return 0;
     60   /* Discard primitive from which the ray starts from */
     61   if(S2D_PRIMITIVE_EQ(prim_from, &hit->prim)) return 1;
     62   /* Ray starts on an edge and intersect the neighbor triangle */
     63   if(hit->distance <= 0) return 1;
     64   return 0;
     65 }
     66 
     67 static FINLINE int
     68 check_scene_desc(const struct sgf_scene_desc* desc)
     69 {
     70   return desc
     71       && desc->get_indices
     72       && desc->get_emissivity
     73       && desc->get_reflectivity
     74       && desc->get_specularity
     75       && desc->get_position
     76       && desc->nprims
     77       && desc->nverts
     78       && desc->nbands;
     79 }
     80 
     81 static INLINE void
     82 scene_release_s3d(struct sgf_scene* scn)
     83 {
     84   if(scn->geometry.s3d.scn) {
     85     S3D(scene_ref_put(scn->geometry.s3d.scn));
     86     scn->geometry.s3d.scn = NULL;
     87   }
     88   if(scn->geometry.s3d.shape) {
     89     S3D(shape_ref_put(scn->geometry.s3d.shape));
     90     scn->geometry.s3d.shape = NULL;
     91   }
     92   scn->dimensionality = 0;
     93 }
     94 
     95 static INLINE res_T
     96 scene_init_s3d(struct sgf_scene* scn)
     97 {
     98   res_T res = RES_OK;
     99   ASSERT(scn);
    100 
    101   /* Create Star-3D data structures */
    102   res = s3d_scene_create(scn->dev->s3d, &scn->geometry.s3d.scn);
    103   if(res != RES_OK) goto error;
    104   res = s3d_shape_create_mesh(scn->dev->s3d, &scn->geometry.s3d.shape);
    105   if(res != RES_OK) goto error;
    106   res = s3d_mesh_set_hit_filter_function
    107     (scn->geometry.s3d.shape, &hit_filter_s3d, NULL);
    108   if(res != RES_OK) goto error;
    109   res = s3d_scene_attach_shape(scn->geometry.s3d.scn, scn->geometry.s3d.shape);
    110   if(res != RES_OK) goto error;
    111   scn->dimensionality = 3;
    112 
    113 exit:
    114   return res;
    115 error:
    116   scene_release_s3d(scn);
    117   goto exit;
    118 }
    119 
    120 static INLINE void
    121 scene_release_s2d(struct sgf_scene* scn)
    122 {
    123   if(scn->geometry.s2d.scn) {
    124     S2D(scene_ref_put(scn->geometry.s2d.scn));
    125     scn->geometry.s2d.scn = NULL;
    126   }
    127   if(scn->geometry.s2d.shape) {
    128     S2D(shape_ref_put(scn->geometry.s2d.shape));
    129     scn->geometry.s2d.shape = NULL;
    130   }
    131   scn->dimensionality = 0;
    132 }
    133 
    134 static INLINE res_T
    135 scene_init_s2d(struct sgf_scene* scn)
    136 {
    137   res_T res = RES_OK;
    138   ASSERT(scn);
    139 
    140   /* Create Star-3D data structures */
    141   res = s2d_scene_create(scn->dev->s2d, &scn->geometry.s2d.scn);
    142   if(res != RES_OK) goto error;
    143   res = s2d_shape_create_line_segments(scn->dev->s2d, &scn->geometry.s2d.shape);
    144   if(res != RES_OK) goto error;
    145   res = s2d_line_segments_set_hit_filter_function
    146     (scn->geometry.s2d.shape, &hit_filter_s2d, NULL);
    147   if(res != RES_OK) goto error;
    148   res = s2d_scene_attach_shape(scn->geometry.s2d.scn, scn->geometry.s2d.shape);
    149   if(res != RES_OK) goto error;
    150   scn->dimensionality = 2;
    151 
    152 exit:
    153   return res;
    154 error:
    155   scene_release_s2d(scn);
    156   goto exit;
    157 }
    158 
    159 static res_T
    160 scene_setup
    161   (struct sgf_scene* scn,
    162    const struct sgf_scene_desc* desc,
    163    const int dimensionality,
    164    const char* caller)
    165 {
    166   struct s2d_vertex_data vdata2d;
    167   struct s3d_vertex_data vdata3d;
    168   unsigned iprim, iband, i;
    169   double* abs, *emi, *refl, *spec;
    170   res_T res = RES_OK;
    171 
    172   if(!scn || !check_scene_desc(desc)) {
    173     res = RES_BAD_ARG;
    174     goto error;
    175   }
    176 
    177   /* Allocate the buffers of material attributes */
    178   #define RESIZE(V, Name) {                                                    \
    179     res = darray_double_resize(&(V), desc->nprims*desc->nbands);               \
    180     if(res != RES_OK) {                                                        \
    181       log_error(scn->dev, "%s: couldn't allocate the "Name" buffer.", caller); \
    182       goto error;                                                              \
    183     }                                                                          \
    184   } (void)0
    185   RESIZE(scn->emi, "emissivity");
    186   RESIZE(scn->refl, "reflectivity");
    187   RESIZE(scn->spec, "specularity");
    188   if(desc->get_absorption) RESIZE(scn->abs, "absorption");
    189   #undef RESIZE
    190 
    191   /* Setup the material */
    192   abs = desc->get_absorption ? darray_double_data_get(&scn->abs) : NULL;
    193   emi = darray_double_data_get(&scn->emi);
    194   refl = darray_double_data_get(&scn->refl);
    195   spec = darray_double_data_get(&scn->spec);
    196   i = 0;
    197   FOR_EACH(iband, 0, desc->nbands) {
    198   FOR_EACH(iprim, 0, desc->nprims) {
    199     #define FETCH(Dst, Name, Low, Upp) {                                       \
    200       (Dst) = desc->get_##Name(iprim, iband, desc->context);                   \
    201       if((Dst) < (Low) || (Dst) > (Upp)) {                                     \
    202         log_error(scn->dev, "%s: invalid "STR(Name)" `%g'.\n", caller, (Dst)); \
    203         res = RES_BAD_ARG;                                                     \
    204         goto error;                                                            \
    205       }                                                                        \
    206     } (void) 0
    207 
    208     if(abs) FETCH(abs[i], absorption, 0, DBL_MAX);
    209     FETCH(emi[i], emissivity, 0, 1);
    210     FETCH(refl[i], reflectivity, 0, 1);
    211     FETCH(spec[i], specularity, 0, 1);
    212     #undef FETCH
    213     ++i;
    214   }}
    215 
    216   /* Initialise the Star-3D structures */
    217   if(scn->dimensionality != dimensionality) {
    218     if(scn->dimensionality == 2) scene_release_s2d(scn);
    219     if(scn->dimensionality == 3) scene_release_s3d(scn);
    220 
    221     if(dimensionality == 2) {
    222       res = scene_init_s2d(scn);
    223     } else {
    224       res = scene_init_s3d(scn);
    225     }
    226     if(res != RES_OK) goto error;
    227   }
    228 
    229   /* Setup the geometry */
    230   switch(scn->dimensionality) {
    231     case 2:
    232       vdata2d.usage = S2D_POSITION;
    233       vdata2d.type = S2D_FLOAT2;
    234       vdata2d.get = desc->get_position;
    235       s2d_line_segments_setup_indexed_vertices(scn->geometry.s2d.shape,
    236         desc->nprims, desc->get_indices, desc->nverts, &vdata2d, 1,
    237         desc->context);
    238       break;
    239     case 3:
    240       vdata3d.usage = S3D_POSITION;
    241       vdata3d.type = S3D_FLOAT3;
    242       vdata3d.get = desc->get_position;
    243       res = s3d_mesh_setup_indexed_vertices(scn->geometry.s3d.shape,
    244         desc->nprims, desc->get_indices, desc->nverts, &vdata3d, 1,
    245         desc->context);
    246       break;
    247     default: FATAL("Unreachable code\n"); break;
    248   }
    249 
    250   scn->nbands = desc->nbands;
    251   scn->nprims = desc->nprims;
    252   scn->has_medium = desc->get_absorption != NULL;
    253 
    254 exit:
    255   return res;
    256 error:
    257   if(scn) {
    258     darray_double_clear(&scn->abs);
    259     darray_double_clear(&scn->emi);
    260     darray_double_clear(&scn->refl);
    261     darray_double_clear(&scn->spec);
    262     scn->nprims = 0;
    263     scn->nbands = 0;
    264     scn->has_medium = 0;
    265   }
    266   goto exit;
    267 }
    268 
    269 
    270 
    271 static void
    272 scene_release(ref_T* ref)
    273 {
    274   struct sgf_device* dev;
    275   struct sgf_scene* scn;
    276   ASSERT(ref);
    277   scn = CONTAINER_OF(ref, struct sgf_scene, ref);
    278   dev = scn->dev;
    279   switch(scn->dimensionality) {
    280     case 2: scene_release_s2d(scn); break;
    281     case 3: scene_release_s3d(scn); break;
    282     default: FATAL("Unreachable code\n"); break;
    283   }
    284   darray_double_release(&scn->abs);
    285   darray_double_release(&scn->emi);
    286   darray_double_release(&scn->refl);
    287   darray_double_release(&scn->spec);
    288   MEM_RM(dev->allocator, scn);
    289   SGF(device_ref_put(dev));
    290 }
    291 
    292 /*******************************************************************************
    293  * Exported functions
    294  ******************************************************************************/
    295 res_T
    296 sgf_scene_create(struct sgf_device* dev, struct sgf_scene** out_scn)
    297 {
    298   struct sgf_scene* scn = NULL;
    299   res_T res = RES_OK;
    300 
    301   if(!dev || !out_scn) {
    302     res = RES_BAD_ARG;
    303     goto error;
    304   }
    305 
    306    scn = MEM_CALLOC(dev->allocator, 1, sizeof(struct sgf_scene));
    307    if(!scn) {
    308      res = RES_MEM_ERR;
    309      goto error;
    310    }
    311   ref_init(&scn->ref);
    312   SGF(device_ref_get(dev));
    313   scn->dev = dev;
    314 
    315   /* Initialise the buffers of material properties */
    316   darray_double_init(dev->allocator, &scn->abs);
    317   darray_double_init(dev->allocator, &scn->emi);
    318   darray_double_init(dev->allocator, &scn->refl);
    319   darray_double_init(dev->allocator, &scn->spec);
    320 
    321 exit:
    322   if(out_scn) *out_scn = scn;
    323   return res;
    324 error:
    325   if(scn) {
    326     SGF(scene_ref_put(scn));
    327     scn = NULL;
    328   }
    329   goto exit;
    330 }
    331 
    332 res_T
    333 sgf_scene_ref_get(struct sgf_scene* scn)
    334 {
    335   if(!scn) return RES_BAD_ARG;
    336   ref_get(&scn->ref);
    337   return RES_OK;
    338 }
    339 
    340 res_T
    341 sgf_scene_ref_put(struct sgf_scene* scn)
    342 {
    343   if(!scn) return RES_BAD_ARG;
    344   ref_put(&scn->ref, scene_release);
    345   return RES_OK;
    346 }
    347 
    348 res_T
    349 sgf_scene_setup_3d(struct sgf_scene* scn, const struct sgf_scene_desc* desc)
    350 {
    351   return scene_setup(scn, desc, 3, FUNC_NAME);
    352 }
    353 res_T
    354 sgf_scene_setup_2d(struct sgf_scene* scn, const struct sgf_scene_desc* desc)
    355 {
    356   return scene_setup(scn, desc, 2, FUNC_NAME);
    357 }
    358 
    359 res_T
    360 sgf_scene_primitives_count(struct sgf_scene* scn, unsigned* nprims)
    361 {
    362   if(!scn || !nprims) return RES_BAD_ARG;
    363   *nprims = scn->nprims;
    364   return RES_OK;
    365 }
    366 
    367 res_T
    368 sgf_scene_begin_integration(struct sgf_scene* scn)
    369 {
    370   int i;
    371   res_T res = RES_OK;
    372   if(!scn) return RES_BAD_ARG;
    373 
    374   if(scn->dimensionality == 2) {
    375     i = scn->geometry.s2d.view == NULL;
    376   } else {
    377     ASSERT(scn->dimensionality == 3);
    378     i = scn->geometry.s3d.view == NULL;
    379   }
    380 
    381   if(!i) {
    382     log_error(scn->dev, "%s: an integration process is already active.\n",
    383       FUNC_NAME);
    384     return RES_BAD_OP;
    385   }
    386 
    387   if(scn->dimensionality == 2) {
    388     res = s2d_scene_view_create(scn->geometry.s2d.scn,
    389       S2D_TRACE|S2D_GET_PRIMITIVE, &scn->geometry.s2d.view);
    390   } else {
    391     res = s3d_scene_view_create(scn->geometry.s3d.scn,
    392       S3D_TRACE|S3D_GET_PRIMITIVE, &scn->geometry.s3d.view);
    393   }
    394   return res;
    395 }
    396 
    397 res_T
    398 sgf_scene_end_integration(struct sgf_scene* scn)
    399 {
    400   res_T res = RES_OK;
    401   if(!scn) return RES_BAD_ARG;
    402   if(scn->dimensionality == 2) {
    403     if(!scn->geometry.s2d.view) { 
    404       res = RES_BAD_OP;
    405     } else {
    406       res = s2d_scene_view_ref_put(scn->geometry.s2d.view);
    407       if(res == RES_OK) scn->geometry.s2d.view = NULL;
    408     }
    409   } else {
    410     if(!scn->geometry.s3d.view) {
    411       res = RES_BAD_OP;
    412     } else {
    413       res = s3d_scene_view_ref_put(scn->geometry.s3d.view);
    414       if(res == RES_OK) scn->geometry.s3d.view = NULL;
    415     }
    416   }
    417   if(res != RES_OK) goto error;
    418 exit:
    419   return res;
    420 error:
    421   goto exit;
    422 }
    423