htrdr_atmosphere_ground.c (7928B)
1 /* Copyright (C) 2018-2019, 2022-2025 Centre National de la Recherche Scientifique 2 * Copyright (C) 2020-2022 Institut Mines Télécom Albi-Carmaux 3 * Copyright (C) 2022-2025 Institut Pierre-Simon Laplace 4 * Copyright (C) 2022-2025 Institut de Physique du Globe de Paris 5 * Copyright (C) 2018-2025 |Méso|Star> (contact@meso-star.com) 6 * Copyright (C) 2022-2025 Observatoire de Paris 7 * Copyright (C) 2022-2025 Université de Reims Champagne-Ardenne 8 * Copyright (C) 2022-2025 Université de Versaille Saint-Quentin 9 * Copyright (C) 2018-2019, 2022-2025 Université Paul Sabatier 10 * 11 * This program is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation, either version 3 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 23 24 25 #include "atmosphere/htrdr_atmosphere_ground.h" 26 27 #include "core/htrdr_log.h" 28 #include "core/htrdr_geometry.h" 29 #include "core/htrdr_slab.h" 30 31 #include <star/s3d.h> 32 33 #include <rsys/cstr.h> 34 #include <rsys/double2.h> 35 #include <rsys/double3.h> 36 #include <rsys/mem_allocator.h> 37 #include <rsys/ref_count.h> 38 39 struct trace_slab_context { 40 struct htrdr_geometry* geom; 41 const struct s3d_hit* hit_prev; 42 struct s3d_hit* hit; 43 }; 44 #define TRACE_SLAB_CONTEXT_NULL__ { NULL, NULL, NULL } 45 static const struct trace_slab_context TRACE_SLAB_CONTEXT_NULL = 46 TRACE_SLAB_CONTEXT_NULL__; 47 48 struct htrdr_atmosphere_ground { 49 struct htrdr_geometry* geom; 50 int repeat; /* Make the ground infinite in X and Y */ 51 struct htrdr* htrdr; 52 ref_T ref; 53 }; 54 55 /******************************************************************************* 56 * Helper functions 57 ******************************************************************************/ 58 static INLINE res_T 59 trace_slab 60 (const double org[3], 61 const double dir[3], 62 const double range[2], 63 void* context, 64 int* hit) 65 { 66 struct trace_slab_context* ctx = context; 67 struct htrdr_geometry_trace_ray_args rt_args = 68 HTRDR_GEOMETRY_TRACE_RAY_ARGS_NULL; 69 res_T res = RES_OK; 70 ASSERT(org && dir && range && context && hit); 71 72 d3_set(rt_args.ray_org, org); 73 d3_set(rt_args.ray_dir, dir); 74 d2_set(rt_args.ray_range, range); 75 rt_args.hit_from = ctx->hit_prev ? *ctx->hit_prev : S3D_HIT_NULL; 76 res = htrdr_geometry_trace_ray(ctx->geom, &rt_args, ctx->hit); 77 if(res != RES_OK) return res; 78 79 *hit = !S3D_HIT_NONE(ctx->hit); 80 return RES_OK; 81 } 82 static void 83 release_ground(ref_T* ref) 84 { 85 struct htrdr_atmosphere_ground* ground; 86 struct htrdr* htrdr; 87 ASSERT(ref); 88 ground = CONTAINER_OF(ref, struct htrdr_atmosphere_ground, ref); 89 if(ground->geom) htrdr_geometry_ref_put(ground->geom); 90 htrdr = ground->htrdr; 91 MEM_RM(htrdr_get_allocator(ground->htrdr), ground); 92 htrdr_ref_put(htrdr); 93 } 94 95 /******************************************************************************* 96 * Local functions 97 ******************************************************************************/ 98 res_T 99 htrdr_atmosphere_ground_create 100 (struct htrdr* htrdr, 101 const char* obj_filename, /* May be NULL */ 102 struct htrdr_materials* mats, /* May be NULL */ 103 const int repeat_ground, /* Infinitely repeat the ground in X and Y */ 104 struct htrdr_atmosphere_ground** out_ground) 105 { 106 struct htrdr_atmosphere_ground* ground = NULL; 107 res_T res = RES_OK; 108 ASSERT(htrdr && out_ground); 109 110 ground = MEM_CALLOC(htrdr_get_allocator(htrdr), 1, sizeof(*ground)); 111 if(!ground) { 112 res = RES_MEM_ERR; 113 htrdr_log_err(htrdr, 114 "%s: could not allocate the ground data structure -- %s.\n", 115 FUNC_NAME, res_to_cstr(res)); 116 goto error; 117 } 118 ref_init(&ground->ref); 119 ground->repeat = repeat_ground; 120 htrdr_ref_get(htrdr); 121 ground->htrdr = htrdr; 122 123 if(!obj_filename) goto exit; 124 125 if(!mats) { 126 htrdr_log_err(htrdr, "%s: missing materials.\n", FUNC_NAME); 127 res = RES_BAD_ARG; 128 goto error; 129 } 130 131 res = htrdr_geometry_create(ground->htrdr, obj_filename, mats, &ground->geom); 132 if(res != RES_OK) goto error; 133 134 exit: 135 *out_ground = ground; 136 return res; 137 error: 138 if(ground) { 139 htrdr_atmosphere_ground_ref_put(ground); 140 ground = NULL; 141 } 142 goto exit; 143 } 144 145 void 146 htrdr_atmosphere_ground_ref_get(struct htrdr_atmosphere_ground* ground) 147 { 148 ASSERT(ground); 149 ref_get(&ground->ref); 150 } 151 152 void 153 htrdr_atmosphere_ground_ref_put(struct htrdr_atmosphere_ground* ground) 154 { 155 ASSERT(ground); 156 ref_put(&ground->ref, release_ground); 157 } 158 159 void 160 htrdr_atmosphere_ground_get_interface 161 (struct htrdr_atmosphere_ground* ground, 162 const struct s3d_hit* hit, 163 struct htrdr_interface* out_interface) 164 { 165 /* Simply wrap the geometry function */ 166 htrdr_geometry_get_interface(ground->geom, hit, out_interface); 167 } 168 169 res_T 170 htrdr_atmosphere_ground_trace_ray 171 (struct htrdr_atmosphere_ground* ground, 172 const double org[3], 173 const double dir[3], /* Must be normalized */ 174 const double range[2], 175 const struct s3d_hit* prev_hit, 176 struct s3d_hit* hit) 177 { 178 res_T res = RES_OK; 179 ASSERT(ground && org && dir && range && hit); 180 181 if(!ground->geom) { /* No ground geometry */ 182 *hit = S3D_HIT_NULL; 183 goto exit; 184 } 185 186 if(!ground->repeat) { 187 struct htrdr_geometry_trace_ray_args rt_args = 188 HTRDR_GEOMETRY_TRACE_RAY_ARGS_NULL; 189 190 d3_set(rt_args.ray_org, org); 191 d3_set(rt_args.ray_dir, dir); 192 d2_set(rt_args.ray_range, range); 193 if(prev_hit) rt_args.hit_from = *prev_hit; 194 res = htrdr_geometry_trace_ray(ground->geom, &rt_args, hit); 195 if(res != RES_OK) goto error; 196 197 } else { 198 struct trace_slab_context slab_ctx = TRACE_SLAB_CONTEXT_NULL; 199 double low[3], upp[3]; 200 201 htrdr_geometry_get_aabb(ground->geom, low, upp); 202 203 *hit = S3D_HIT_NULL; 204 slab_ctx.geom = ground->geom; 205 slab_ctx.hit_prev = prev_hit; 206 slab_ctx.hit = hit; 207 208 res = htrdr_slab_trace_ray(ground->htrdr, org, dir, range, low, upp, 209 trace_slab, 32, &slab_ctx); 210 if(res != RES_OK) goto error; 211 } 212 213 exit: 214 return res; 215 error: 216 goto exit; 217 } 218 219 res_T 220 htrdr_atmosphere_ground_find_closest_point 221 (struct htrdr_atmosphere_ground* ground, 222 const double pos[3], 223 const double radius, 224 struct s3d_hit* hit) 225 { 226 double query_pos[3]; 227 double query_radius; 228 res_T res = RES_OK; 229 ASSERT(ground && pos && hit); 230 231 if(!ground->geom) { /* No ground geometry */ 232 *hit = S3D_HIT_NULL; 233 goto exit; 234 } 235 236 query_radius = radius; 237 d3_set(query_pos, pos); 238 239 if(ground->repeat) { 240 double ground_low[3]; 241 double ground_upp[3]; 242 double ground_sz[3]; 243 double translation[2] = {0, 0}; 244 int64_t xy[2]; 245 246 /* Define the size of the ground geometry pattern */ 247 htrdr_geometry_get_aabb(ground->geom, ground_low, ground_upp); 248 ground_sz[0] = ground_upp[0] - ground_low[0]; 249 ground_sz[1] = ground_upp[1] - ground_low[1]; 250 ground_sz[2] = ground_upp[2] - ground_low[2]; 251 252 /* Define the 2D index of the current ground instance. (0,0) is the index 253 * of the non instantiated ground */ 254 xy[0] = (int64_t)floor((query_pos[0] - ground_low[0]) / ground_sz[0]); 255 xy[1] = (int64_t)floor((query_pos[1] - ground_low[1]) / ground_sz[1]); 256 257 /* Define the translation along the X and Y axis from world space to local 258 * ground geometry space */ 259 translation[0] = -(double)xy[0] * ground_sz[0]; 260 translation[1] = -(double)xy[1] * ground_sz[1]; 261 262 /* Transform the query pos in local ground geometry space */ 263 query_pos[0] += translation[0]; 264 query_pos[1] += translation[1]; 265 } 266 267 res = htrdr_geometry_find_closest_point 268 (ground->geom, query_pos, query_radius, hit); 269 if(res != RES_OK) goto error; 270 271 exit: 272 return res; 273 error: 274 goto exit; 275 }