senc3d_scene.c (11585B)
1 /* Copyright (C) 2018-2020, 2023, 2024 |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 "senc3d.h" 17 #include "senc3d_device_c.h" 18 #include "senc3d_scene_c.h" 19 #include "senc3d_scene_analyze_c.h" 20 21 #include <rsys/rsys.h> 22 #include <rsys/double3.h> 23 #include <rsys/mem_allocator.h> 24 25 #include <limits.h> 26 27 /****************************************************************************** 28 * Helper function 29 *****************************************************************************/ 30 static void 31 scene_release(ref_T * ref) 32 { 33 struct senc3d_device* dev = NULL; 34 struct senc3d_scene* scn = NULL; 35 ASSERT(ref); 36 scn = CONTAINER_OF(ref, struct senc3d_scene, ref); 37 dev = scn->dev; 38 darray_triangle_in_release(&scn->triangles_in); 39 darray_position_release(&scn->vertices); 40 darray_side_range_release(&scn->media_use); 41 42 darray_triangle_enc_release(&scn->analyze.triangles_enc); 43 darray_enclosure_release(&scn->analyze.enclosures); 44 darray_enc_ids_array_release(&scn->analyze.enc_ids_array_by_medium); 45 darray_frontier_edge_release(&scn->analyze.frontiers); 46 darray_trg_id_release(&scn->analyze.overlapping_ids); 47 48 MEM_RM(dev->allocator, scn); 49 SENC3D(device_ref_put(dev)); 50 } 51 52 static INLINE int 53 compatible_medium 54 (const medium_id_t m1, 55 const medium_id_t m2) 56 { 57 if(m1 == SENC3D_UNSPECIFIED_MEDIUM || m2 == SENC3D_UNSPECIFIED_MEDIUM) return 1; 58 return (m1 == m2); 59 } 60 61 /****************************************************************************** 62 * Exported functions 63 *****************************************************************************/ 64 res_T 65 senc3d_scene_create 66 (struct senc3d_device* dev, 67 const int conv, 68 const trg_id_t ntris, 69 void(*indices)(const trg_id_t, vrtx_id_t*, void*), 70 void(*media)(const trg_id_t, medium_id_t*, void*), 71 const vrtx_id_t nverts, 72 void(*position)(const vrtx_id_t, double*, void* ctx), 73 void* ctx, 74 struct senc3d_scene** out_scn) 75 { 76 struct senc3d_scene* scn = NULL; 77 /* Tables to detect duplicates */ 78 struct htable_vrtx unique_vertices; 79 struct htable_trg unique_triangles; 80 vrtx_id_t nv; 81 trg_id_t nt; 82 res_T res = RES_OK; 83 84 if(!dev || !out_scn || !indices || !position || !nverts || !ntris 85 /* Convention must be set both regarding FRONT/BACK and INSIDE/OUTSIDE */ 86 || !(conv & (SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_BACK)) 87 || !(conv & (SENC3D_CONVENTION_NORMAL_INSIDE | SENC3D_CONVENTION_NORMAL_OUTSIDE))) 88 return RES_BAD_ARG; 89 90 htable_vrtx_init(dev->allocator, &unique_vertices); 91 htable_trg_init(dev->allocator, &unique_triangles); 92 93 scn = MEM_CALLOC(dev->allocator, 1, sizeof(struct senc3d_scene)); 94 if(!scn) { 95 log_err(dev, LIB_NAME":%s: could not allocate the star_enclosures-3d scene.\n", 96 FUNC_NAME); 97 res = RES_MEM_ERR; 98 goto error; 99 } 100 ref_init(&scn->ref); 101 SENC3D(device_ref_get(dev)); 102 scn->dev = dev; 103 scn->convention = conv; 104 scn->ntris = ntris; 105 scn->nverts = nverts; 106 darray_triangle_in_init(dev->allocator, &scn->triangles_in); 107 darray_position_init(dev->allocator, &scn->vertices); 108 darray_side_range_init(dev->allocator, &scn->media_use); 109 110 darray_triangle_enc_init(scn->dev->allocator, &scn->analyze.triangles_enc); 111 darray_enclosure_init(scn->dev->allocator, &scn->analyze.enclosures); 112 darray_enc_ids_array_init(scn->dev->allocator, 113 &scn->analyze.enc_ids_array_by_medium); 114 darray_frontier_edge_init(scn->dev->allocator, &scn->analyze.frontiers); 115 /* Enclosure 0 is always defined for infinite */ 116 OK(darray_enclosure_resize(&scn->analyze.enclosures, 1)); 117 scn->analyze.enclosures_count = 1; 118 darray_trg_id_init(scn->dev->allocator, &scn->analyze.overlapping_ids); 119 120 OK(darray_position_reserve(&scn->vertices, scn->nverts)); 121 OK(darray_triangle_in_reserve(&scn->triangles_in, scn->ntris)); 122 OK(htable_vrtx_reserve(&unique_vertices, scn->nverts)); 123 OK(htable_trg_reserve(&unique_triangles, scn->ntris)); 124 125 /* Get vertices */ 126 FOR_EACH(nv, 0, nverts) { 127 vrtx_id_t* p_vrtx; 128 union double3 tmp; 129 /* API: position needs an api_t */ 130 position(nv, tmp.vec, ctx); 131 p_vrtx = htable_vrtx_find(&unique_vertices, &tmp); 132 if(p_vrtx) { 133 /* Duplicate vertex */ 134 log_err(scn->dev, LIB_NAME":%s: vertex "PRTF_VRTX" is a duplicate.\n", 135 FUNC_NAME, nv); 136 res = RES_BAD_ARG; 137 goto error; 138 } 139 /* New vertex */ 140 ASSERT(nv == htable_vrtx_size_get(&unique_vertices)); 141 OK(darray_position_push_back(&scn->vertices, &tmp)); 142 OK(htable_vrtx_set(&unique_vertices, &tmp, &nv)); 143 } 144 /* Get triangles */ 145 FOR_EACH(nt, 0, ntris) { 146 int j, dg, s; 147 medium_id_t med[2] 148 = { SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM }; 149 vrtx_id_t ind[3]; 150 union vrtx_id3 trg_key; 151 struct triangle_in tmp; 152 trg_id_t* p_trg; 153 indices(nt, ind, ctx); 154 FOR_EACH(j, 0, 3) { 155 if(ind[j] >= nverts) { 156 log_err(scn->dev, 157 LIB_NAME":%s: triangle "PRTF_TRG" uses invalid vertex id "PRTF_VRTX".\n", 158 FUNC_NAME, nt, ind[j]); 159 res = RES_BAD_ARG; 160 goto error; 161 } 162 ASSERT(ind[j] <= VRTX_MAX__); 163 tmp.vertice_id[j] = (vrtx_id_t)ind[j]; 164 } 165 dg = tmp.vertice_id[0] == tmp.vertice_id[1] 166 || tmp.vertice_id[0] == tmp.vertice_id[2] 167 || tmp.vertice_id[1] == tmp.vertice_id[2]; 168 if(!dg) { 169 double edge1[3], edge2[3], n[3]; 170 const union double3* vertices = darray_position_cdata_get(&scn->vertices); 171 d3_sub(edge1, vertices[tmp.vertice_id[1]].vec, vertices[tmp.vertice_id[0]].vec); 172 d3_sub(edge2, vertices[tmp.vertice_id[2]].vec, vertices[tmp.vertice_id[0]].vec); 173 d3_cross(n, edge1, edge2); 174 dg = d3_len(n) == 0; 175 } 176 if(dg) { 177 log_err(scn->dev, LIB_NAME":%s: triangle "PRTF_TRG" is degenerated.\n", 178 FUNC_NAME, nt); 179 res = RES_BAD_ARG; 180 goto error; 181 } 182 /* Get media */ 183 if(media) { 184 media(nt, med, ctx); 185 FOR_EACH(s, 0, 2) { 186 if(med[s] == SENC3D_UNSPECIFIED_MEDIUM || med[s] <= MEDIUM_MAX__) 187 continue; 188 res = RES_BAD_ARG; 189 goto error; 190 } 191 } 192 trg_make_key(&trg_key, tmp.vertice_id); 193 p_trg = htable_trg_find(&unique_triangles, &trg_key); 194 if(p_trg) { 195 /* Duplicate triangle */ 196 log_err(scn->dev, LIB_NAME":%s: triangle "PRTF_TRG" is a duplicate.\n", 197 FUNC_NAME, nt); 198 res = RES_BAD_ARG; 199 goto error; 200 } 201 /* New triangle */ 202 ASSERT(nt == htable_trg_size_get(&unique_triangles)); 203 OK(htable_trg_set(&unique_triangles, &trg_key, &nt)); 204 FOR_EACH(s, 0, 2) { 205 const enum senc3d_side side[2] = { SENC3D_FRONT, SENC3D_BACK }; 206 struct side_range* media_use; 207 size_t m_idx = medium_id_2_medium_idx(med[s]); 208 tmp.medium[s] = med[s]; 209 if(m_idx >= darray_side_range_size_get(&scn->media_use)) { 210 OK(darray_side_range_resize(&scn->media_use, 1 + m_idx)); 211 } 212 /* media_use 0 is for SENC3D_UNSPECIFIED_MEDIUM */ 213 media_use = darray_side_range_data_get(&scn->media_use) + m_idx; 214 media_use->first = 215 MMIN(media_use->first, TRGIDxSIDE_2_TRGSIDE((trg_id_t)nt, side[s])); 216 ASSERT(media_use->first < 2 * (scn->ntris + 1)); 217 media_use->last = 218 MMAX(media_use->last, TRGIDxSIDE_2_TRGSIDE((trg_id_t)nt, side[s])); 219 ASSERT(media_use->last < 2 * (scn->ntris + 1)); 220 ASSERT(media_use->first <= media_use->last); 221 } 222 OK(darray_triangle_in_push_back(&scn->triangles_in, &tmp)); 223 } 224 225 OK(darray_enc_ids_array_resize(&scn->analyze.enc_ids_array_by_medium, 226 darray_side_range_size_get(&scn->media_use))); 227 /* Proceed to the analyze */ 228 OK(scene_analyze(scn)); 229 230 exit: 231 htable_vrtx_release(&unique_vertices); 232 htable_trg_release(&unique_triangles); 233 if(scn) *out_scn = scn; 234 return res; 235 236 error: 237 if(scn) { 238 SENC3D(scene_ref_put(scn)); 239 scn = NULL; 240 } 241 goto exit; 242 } 243 244 res_T 245 senc3d_scene_get_convention 246 (const struct senc3d_scene* scn, 247 int* convention) 248 { 249 if(!scn || !convention) return RES_BAD_ARG; 250 *convention = scn->convention; 251 return RES_OK; 252 } 253 254 res_T 255 senc3d_scene_get_triangles_count 256 (const struct senc3d_scene* scn, 257 trg_id_t* count) 258 { 259 if(!scn || !count) return RES_BAD_ARG; 260 *count = scn->ntris; 261 return RES_OK; 262 } 263 264 res_T 265 senc3d_scene_get_triangle 266 (const struct senc3d_scene* scn, 267 const trg_id_t itri, 268 vrtx_id_t indices[3]) 269 { 270 const struct triangle_in* trg; 271 int i; 272 if(!scn || !indices 273 || itri >= darray_triangle_in_size_get(&scn->triangles_in)) 274 return RES_BAD_ARG; 275 trg = darray_triangle_in_cdata_get(&scn->triangles_in) + itri; 276 FOR_EACH(i, 0, 3) indices[i] = trg->vertice_id[i]; 277 return RES_OK; 278 } 279 280 res_T 281 senc3d_scene_get_triangle_media 282 (const struct senc3d_scene* scn, 283 const trg_id_t itri, 284 medium_id_t media[2]) 285 { 286 const struct triangle_in* trg; 287 int i; 288 if(!scn || !media 289 || itri >= darray_triangle_in_size_get(&scn->triangles_in)) 290 return RES_BAD_ARG; 291 trg = darray_triangle_in_cdata_get(&scn->triangles_in) + itri; 292 FOR_EACH(i, 0, 2) media[i] = trg->medium[i]; 293 return RES_OK; 294 } 295 296 res_T 297 senc3d_scene_get_vertices_count 298 (const struct senc3d_scene* scn, 299 vrtx_id_t* count) 300 { 301 if(!scn || !count) return RES_BAD_ARG; 302 *count = scn->nverts; 303 return RES_OK; 304 } 305 306 res_T 307 senc3d_scene_get_vertex 308 (const struct senc3d_scene* scn, 309 const vrtx_id_t ivert, 310 double coord[3]) 311 { 312 const union double3* v; 313 if(!scn || !coord 314 || ivert >= darray_position_size_get(&scn->vertices)) 315 return RES_BAD_ARG; 316 v = darray_position_cdata_get(&scn->vertices) + ivert; 317 d3_set(coord, v->vec); 318 return RES_OK; 319 } 320 321 res_T 322 senc3d_scene_dump_enclosure_obj 323 (struct senc3d_scene* scn, 324 const unsigned enc, 325 const char* name) 326 { 327 struct senc3d_enclosure* enclosure = NULL; 328 struct senc3d_enclosure_header header; 329 FILE* stream = NULL; 330 unsigned count, i; 331 res_T res = RES_OK; 332 333 if(!scn || !name) { 334 res = RES_BAD_ARG; 335 goto error; 336 } 337 338 OK(senc3d_scene_get_enclosure_count(scn, &count)); 339 if(enc >= count) { 340 res = RES_BAD_ARG; 341 goto error; 342 } 343 344 OK(senc3d_scene_get_enclosure(scn, enc, &enclosure)); 345 OK(senc3d_enclosure_get_header(enclosure, &header)); 346 347 stream = fopen(name, "w"); 348 if(!stream) { 349 res = RES_BAD_ARG; 350 goto error; 351 } 352 353 FOR_EACH(i, 0, header.vertices_count) { 354 double tmp[3]; 355 OK(senc3d_enclosure_get_vertex(enclosure, i, tmp)); 356 fprintf(stream, "v %g %g %g\n", SPLIT3(tmp)); 357 } 358 FOR_EACH(i, 0, header.primitives_count) { 359 unsigned indices[3]; 360 OK(senc3d_enclosure_get_triangle(enclosure, i, indices)); 361 fprintf(stream, "f %u %u %u\n", 362 1+indices[0], 1+indices[1], 1+indices[2]); 363 } 364 365 exit: 366 if(enclosure) SENC3D(enclosure_ref_put(enclosure)); 367 if(stream) fclose(stream); 368 return res; 369 error: 370 goto exit; 371 } 372 373 res_T 374 senc3d_scene_ref_get(struct senc3d_scene* scn) 375 { 376 if(!scn) return RES_BAD_ARG; 377 ref_get(&scn->ref); 378 return RES_OK; 379 } 380 381 res_T 382 senc3d_scene_ref_put(struct senc3d_scene* scn) 383 { 384 if(!scn) return RES_BAD_ARG; 385 ref_put(&scn->ref, scene_release); 386 return RES_OK; 387 }