sdis_interface.c (10080B)
1 /* Copyright (C) 2016-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 "sdis.h" 17 #include "sdis_device_c.h" 18 #include "sdis_interface_c.h" 19 #include "sdis_log.h" 20 #include "sdis_scene_c.h" 21 22 #include <rsys/double2.h> 23 #include <rsys/double3.h> 24 #include <rsys/mem_allocator.h> 25 26 #include <star/s2d.h> 27 #include <star/s3d.h> 28 29 /******************************************************************************* 30 * Helper functions 31 ******************************************************************************/ 32 static int 33 check_interface_shader 34 (struct sdis_device* dev, 35 const char* caller_name, 36 const struct sdis_interface_shader* shader, 37 const struct sdis_medium* front, 38 const struct sdis_medium* back) 39 { 40 enum sdis_medium_type type[2]; 41 const struct sdis_interface_side_shader* shaders[2]; 42 int i; 43 ASSERT(dev && caller_name && shader && front && back); 44 45 type[0] = sdis_medium_get_type(front); 46 type[1] = sdis_medium_get_type(back); 47 shaders[0] = &shader->front; 48 shaders[1] = &shader->back; 49 50 /* Fluid<->solid interface */ 51 if(type[0] == SDIS_SOLID 52 && type[1] == SDIS_SOLID 53 && shader->convection_coef) { 54 log_warn(dev, 55 "%s: a solid/solid interface can't have a convection coefficient. The " 56 "shader's pointer function for this attribute should be NULL.\n", 57 caller_name); 58 } 59 if(shader->convection_coef_upper_bound < 0) { 60 log_warn(dev, 61 "%s: Invalid upper bound for convection coefficient (%g).\n", 62 caller_name, shader->convection_coef_upper_bound); 63 if(type[0] == SDIS_FLUID || type[1] == SDIS_FLUID) return 0; 64 } 65 66 if((type[0] != SDIS_SOLID || type[1] != SDIS_SOLID) 67 && shader->thermal_contact_resistance) { 68 log_warn(dev, 69 "%s: only solid/solid interface can have a thermal contact resistance. The " 70 "shader's pointer function for this attribute should be NULL.\n", 71 caller_name); 72 } 73 74 FOR_EACH(i, 0, 2) { 75 switch(type[i]) { 76 case SDIS_FLUID: /* No constraint */ break; 77 case SDIS_SOLID: 78 if(shaders[i]->emissivity 79 || shaders[i]->specular_fraction 80 || shaders[i]->reference_temperature) { 81 log_warn(dev, 82 "%s: the interface side toward a solid cannot have an emissivity, " 83 "a specular_fraction or a reference temperature. The shader's " 84 "pointer functions for these attributes should be NULL.\n", 85 caller_name); 86 } 87 break; 88 default: FATAL("Unreachable code.\n"); break; 89 } 90 } 91 return 1; 92 } 93 94 static void 95 interface_release(ref_T* ref) 96 { 97 struct sdis_interface* interf = NULL; 98 struct sdis_device* dev = NULL; 99 ASSERT(ref); 100 interf = CONTAINER_OF(ref, struct sdis_interface, ref); 101 dev = interf->dev; 102 if(interf->medium_front) SDIS(medium_ref_put(interf->medium_front)); 103 if(interf->medium_back) SDIS(medium_ref_put(interf->medium_back)); 104 if(interf->data) SDIS(data_ref_put(interf->data)); 105 flist_name_del(&dev->interfaces_names, interf->id); 106 MEM_RM(dev->allocator, interf); 107 SDIS(device_ref_put(dev)); 108 } 109 110 /******************************************************************************* 111 * Exported functions 112 ******************************************************************************/ 113 res_T 114 sdis_interface_create 115 (struct sdis_device* dev, 116 struct sdis_medium* front, 117 struct sdis_medium* back, 118 const struct sdis_interface_shader* shader, 119 struct sdis_data* data, 120 struct sdis_interface** out_interface) 121 { 122 struct sdis_interface* interf = NULL; 123 res_T res = RES_OK; 124 125 if(!dev || !front || !back || !shader || !out_interface) { 126 res = RES_BAD_ARG; 127 goto error; 128 } 129 130 if(sdis_medium_get_type(front) == SDIS_FLUID 131 && sdis_medium_get_type(back) == SDIS_FLUID) { 132 log_err(dev, "%s: invalid fluid<->fluid interface.\n", FUNC_NAME); 133 res = RES_BAD_ARG; 134 goto error; 135 } 136 137 if(!check_interface_shader(dev, FUNC_NAME, shader, front, back)) { 138 log_err(dev, "%s: invalid interface shader.\n", FUNC_NAME); 139 res = RES_BAD_ARG; 140 goto error; 141 } 142 143 interf = MEM_CALLOC(dev->allocator, 1, sizeof(struct sdis_interface)); 144 if(!interf) { 145 log_err(dev, "%s: could not create the interface.\n", FUNC_NAME); 146 res = RES_MEM_ERR; 147 goto error; 148 } 149 ref_init(&interf->ref); 150 SDIS(medium_ref_get(front)); 151 SDIS(medium_ref_get(back)); 152 SDIS(device_ref_get(dev)); 153 interf->medium_front = front; 154 interf->medium_back = back; 155 interf->dev = dev; 156 interf->shader = *shader; 157 interf->id = flist_name_add(&dev->interfaces_names); 158 flist_name_get(&dev->interfaces_names, interf->id)->mem = interf; 159 160 if(data) { 161 SDIS(data_ref_get(data)); 162 interf->data = data; 163 } 164 165 exit: 166 if(out_interface) *out_interface = interf; 167 return res; 168 error: 169 if(interf) { 170 SDIS(interface_ref_put(interf)); 171 interf = NULL; 172 } 173 goto exit; 174 } 175 176 res_T 177 sdis_interface_ref_get(struct sdis_interface* interf) 178 { 179 if(!interf) return RES_BAD_ARG; 180 ref_get(&interf->ref); 181 return RES_OK; 182 } 183 184 res_T 185 sdis_interface_ref_put(struct sdis_interface* interf) 186 { 187 if(!interf) return RES_BAD_ARG; 188 ref_put(&interf->ref, interface_release); 189 return RES_OK; 190 } 191 192 SDIS_API res_T 193 sdis_interface_get_shader 194 (const struct sdis_interface* interf, 195 struct sdis_interface_shader* shader) 196 { 197 if(!interf || !shader) return RES_BAD_ARG; 198 *shader = interf->shader; 199 return RES_OK; 200 } 201 202 struct sdis_data* 203 sdis_interface_get_data(struct sdis_interface* interf) 204 { 205 ASSERT(interf); 206 return interf->data; 207 } 208 209 unsigned 210 sdis_interface_get_id(const struct sdis_interface* interf) 211 { 212 ASSERT(interf); 213 return interf->id.index; 214 } 215 216 /******************************************************************************* 217 * Local function 218 ******************************************************************************/ 219 struct sdis_medium* 220 interface_get_medium 221 (const struct sdis_interface* interf, const enum sdis_side side) 222 { 223 struct sdis_medium* mdm = NULL; 224 ASSERT(interf); 225 switch(side) { 226 case SDIS_FRONT: mdm = interf->medium_front; break; 227 case SDIS_BACK: mdm = interf->medium_back; break; 228 default: FATAL("Unreachable code.\n"); break; 229 } 230 return mdm; 231 } 232 233 void 234 setup_interface_fragment_2d 235 (struct sdis_interface_fragment* frag, 236 const struct sdis_rwalk_vertex* vertex, 237 const struct s2d_hit* hit, 238 const enum sdis_side side) 239 { 240 ASSERT(frag && vertex && hit && !S2D_HIT_NONE(hit)); 241 ASSERT(side == SDIS_FRONT || side == SDIS_BACK); 242 d2_set(frag->P, vertex->P); 243 frag->P[2] = 0; 244 d2_normalize(frag->Ng, d2_set_f2(frag->Ng, hit->normal)); 245 frag->Ng[2] = 0; 246 frag->uv[0] = hit->u; 247 frag->time = vertex->time; 248 frag->side = side; 249 } 250 251 void 252 setup_interface_fragment_3d 253 (struct sdis_interface_fragment* frag, 254 const struct sdis_rwalk_vertex* vertex, 255 const struct s3d_hit* hit, 256 const enum sdis_side side) 257 { 258 ASSERT(frag && vertex && hit && !S3D_HIT_NONE(hit)); 259 ASSERT(side == SDIS_FRONT || side == SDIS_BACK); 260 d3_set(frag->P, vertex->P); 261 d3_normalize(frag->Ng, d3_set_f3(frag->Ng, hit->normal)); 262 d2_set_f2(frag->uv, hit->uv); 263 frag->time = vertex->time; 264 frag->side = side; 265 } 266 267 res_T 268 build_interface_fragment_2d 269 (struct sdis_interface_fragment* frag, 270 const struct sdis_scene* scn, 271 const unsigned iprim, 272 const double uv[1], 273 const enum sdis_side side) 274 { 275 struct s2d_attrib attr_P, attr_N; 276 struct s2d_primitive prim = S2D_PRIMITIVE_NULL; 277 struct s2d_hit hit = S2D_HIT_NULL; 278 struct sdis_rwalk_vertex vtx = SDIS_RWALK_VERTEX_NULL; 279 float st; 280 res_T res = RES_OK; 281 282 ASSERT(frag && scn && uv && scene_is_2d(scn)); 283 ASSERT(side == SDIS_FRONT || side == SDIS_BACK); 284 285 st = (float)uv[0]; 286 287 #define CALL(Func) { res = Func; if(res != RES_OK) goto error; } (void)0 288 CALL(s2d_scene_view_get_primitive(scn->s2d_view, iprim, &prim)); 289 CALL(s2d_primitive_get_attrib(&prim, S2D_POSITION, st, &attr_P)); 290 CALL(s2d_primitive_get_attrib(&prim, S2D_GEOMETRY_NORMAL, st, &attr_N)); 291 #undef CALL 292 293 vtx.P[0] = attr_P.value[0]; 294 vtx.P[1] = attr_P.value[1]; 295 vtx.time = NaN; 296 hit.normal[0] = attr_N.value[0]; 297 hit.normal[1] = attr_N.value[1]; 298 hit.distance = 0; 299 hit.prim = prim; 300 301 setup_interface_fragment_2d(frag, &vtx, &hit, side); 302 303 exit: 304 return res; 305 error: 306 *frag = SDIS_INTERFACE_FRAGMENT_NULL; 307 goto exit; 308 } 309 310 res_T 311 build_interface_fragment_3d 312 (struct sdis_interface_fragment* frag, 313 const struct sdis_scene* scn, 314 const unsigned iprim, 315 const double uv[2], 316 const enum sdis_side side) 317 { 318 struct s3d_attrib attr_P, attr_N; 319 struct s3d_primitive prim = S3D_PRIMITIVE_NULL; 320 struct s3d_hit hit = S3D_HIT_NULL; 321 struct sdis_rwalk_vertex vtx = SDIS_RWALK_VERTEX_NULL; 322 float st[2]; 323 res_T res = RES_OK; 324 325 ASSERT(frag && scn && uv && !scene_is_2d(scn)); 326 ASSERT(side == SDIS_FRONT || side == SDIS_BACK); 327 328 st[0] = (float)uv[0]; 329 st[1] = (float)uv[1]; 330 331 #define CALL(Func) { res = Func; if(res != RES_OK) goto error; } (void)0 332 CALL(s3d_scene_view_get_primitive(scn->s3d_view, iprim, &prim)); 333 CALL(s3d_primitive_get_attrib(&prim, S3D_POSITION, st, &attr_P)); 334 CALL(s3d_primitive_get_attrib(&prim, S3D_GEOMETRY_NORMAL, st, &attr_N)); 335 #undef CALL 336 337 vtx.P[0] = attr_P.value[0]; 338 vtx.P[1] = attr_P.value[1]; 339 vtx.P[2] = attr_P.value[2]; 340 vtx.time = NaN; 341 hit.normal[0] = attr_N.value[0]; 342 hit.normal[1] = attr_N.value[1]; 343 hit.normal[2] = attr_N.value[2]; 344 hit.distance = 0; 345 hit.prim = prim; 346 347 setup_interface_fragment_3d(frag, &vtx, &hit, side); 348 349 exit: 350 return res; 351 error: 352 *frag = SDIS_INTERFACE_FRAGMENT_NULL; 353 goto exit; 354 } 355