star-sf

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

ssf_phase.c (4021B)


      1 /* Copyright (C) 2016-2018, 2021-2025 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #include "ssf.h"
     17 #include "ssf_phase_c.h"
     18 
     19 #include <rsys/double3.h>
     20 #include <rsys/math.h>
     21 #include <rsys/mem_allocator.h>
     22 
     23 #include <string.h>
     24 
     25 /*******************************************************************************
     26  * Helper functions
     27  ******************************************************************************/
     28 static INLINE int
     29 check_phase_type(const struct ssf_phase_type* type)
     30 {
     31   return type
     32       && type->sample
     33       && type->eval
     34       && type->pdf
     35       && IS_POW2(type->alignof_phase);
     36 }
     37 
     38 static void
     39 phase_release(ref_T* ref)
     40 {
     41   struct ssf_phase* phase = CONTAINER_OF(ref, struct ssf_phase, ref);
     42   ASSERT(ref);
     43   if(phase->data) {
     44     if(phase->type.release) phase->type.release(phase->data);
     45     MEM_RM(phase->allocator, phase->data);
     46   }
     47   MEM_RM(phase->allocator, phase);
     48 }
     49 
     50 /*******************************************************************************
     51  * Exported functions
     52  ******************************************************************************/
     53 res_T
     54 ssf_phase_create
     55   (struct mem_allocator* allocator,
     56    const struct ssf_phase_type* type,
     57    struct ssf_phase** out_phase)
     58 {
     59   struct mem_allocator* mem_allocator = NULL;
     60   struct ssf_phase* phase = NULL;
     61   res_T res = RES_OK;
     62 
     63   if(!out_phase || !check_phase_type(type)) {
     64     res = RES_BAD_ARG;
     65     goto error;
     66   }
     67   mem_allocator = allocator ? allocator : &mem_default_allocator;
     68   phase = MEM_CALLOC(mem_allocator, 1, sizeof(struct ssf_phase));
     69   if(!phase) {
     70     res = RES_MEM_ERR;
     71     goto error;
     72   }
     73   ref_init(&phase->ref);
     74   phase->allocator = mem_allocator;
     75   phase->type = *type;
     76 
     77   if(phase->type.sizeof_phase) {
     78     phase->data = MEM_ALLOC_ALIGNED
     79       (phase->allocator, phase->type.sizeof_phase, phase->type.alignof_phase);
     80     if(!phase->data) {
     81       res = RES_MEM_ERR;
     82       goto error;
     83     }
     84     memset(phase->data, 0, phase->type.sizeof_phase);
     85     if(phase->type.init) {
     86       res = phase->type.init(mem_allocator, phase->data);
     87       if(res != RES_OK) goto error;
     88     }
     89   }
     90 
     91 exit:
     92   if(out_phase) *out_phase = phase;
     93   return res;
     94 error:
     95   if(phase) {
     96     SSF(phase_ref_put(phase));
     97     phase = NULL;
     98   }
     99   goto exit;
    100 }
    101 
    102 res_T
    103 ssf_phase_ref_get(struct ssf_phase* phase)
    104 {
    105   if(!phase) return RES_BAD_ARG;
    106   ref_get(&phase->ref);
    107   return RES_OK;
    108 }
    109 
    110 res_T
    111 ssf_phase_ref_put(struct ssf_phase* phase)
    112 {
    113   if(!phase) return RES_BAD_ARG;
    114   ref_put(&phase->ref, phase_release);
    115   return RES_OK;
    116 }
    117 
    118 void
    119 ssf_phase_sample
    120   (struct ssf_phase* phase,
    121    struct ssp_rng* rng,
    122    const double wo[3],
    123    double wi[3],
    124    double* out_pdf)
    125 {
    126   ASSERT(phase && rng && wo && wi);
    127   ASSERT(d3_is_normalized(wo));
    128   phase->type.sample(phase->data, rng, wo, wi, out_pdf);
    129 }
    130 
    131 double
    132 ssf_phase_eval
    133   (struct ssf_phase* phase,
    134    const double wo[3],
    135    const double wi[3])
    136 {
    137   ASSERT(phase && wo && wi);
    138   ASSERT(d3_is_normalized(wo) && d3_is_normalized(wi));
    139   return phase->type.eval(phase->data, wo, wi);
    140 }
    141 
    142 double
    143 ssf_phase_pdf
    144   (struct ssf_phase* phase,
    145    const double wo[3],
    146    const double wi[3])
    147 {
    148   ASSERT(phase && wi && wo);
    149   ASSERT(d3_is_normalized(wo) && d3_is_normalized(wi));
    150   return phase->type.pdf(phase->data, wo, wi);
    151 }
    152 
    153 res_T
    154 ssf_phase_get_data(struct ssf_phase* phase, void** data)
    155 {
    156   if(!phase || !data) return RES_BAD_ARG;
    157   *data = phase->data;
    158   return RES_OK;
    159 }
    160