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