solstice_entity.c (14724B)
1 /* Copyright (C) 2018-2026 |Meso|Star> (contact@meso-star.com) 2 * Copyright (C) 2016-2018 CNRS 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #include "solstice.h" 18 #include "solstice_c.h" 19 20 #include <solstice/ssol.h> 21 #include <solstice/sanim.h> 22 23 #include <rsys/double33.h> 24 25 /******************************************************************************* 26 * Helper function 27 ******************************************************************************/ 28 static res_T 29 update_instance_transform 30 (const struct sanim_node* n, const double transform[12], void* data) 31 { 32 res_T res = RES_OK; 33 struct solstice_node* node; 34 ASSERT(n && transform && data); 35 (void)data; 36 node = CONTAINER_OF(n, struct solstice_node, anim); 37 if(node->type != SOLSTICE_NODE_GEOMETRY) return RES_OK; 38 res = ssol_instance_set_transform(node->instance, transform); 39 if(res != RES_OK) goto error; 40 41 exit: 42 return res; 43 error: 44 goto exit; 45 } 46 47 static res_T 48 merge_name 49 (struct str* output, 50 const struct str* name0, 51 const struct str* name1) 52 { 53 res_T res = RES_OK; 54 ASSERT(output && name0 && name1); 55 ASSERT(output != name0 && output != name1); 56 57 res = str_copy(output, name0); 58 if(res != RES_OK) goto error; 59 60 res = str_append_char(output, '.'); 61 if(res != RES_OK) goto error; 62 63 res = str_append(output, str_cget(name1)); 64 if(res != RES_OK) goto error; 65 66 exit: 67 return res; 68 error: 69 fprintf(stderr, "Could not build the name from `%s' and `%s'.\n", 70 str_cget(name0), str_cget(name1)); 71 goto exit; 72 } 73 74 static INLINE int 75 srcvl_side_to_ssol_mask(const enum srcvl_side side) 76 { 77 int mask = 0; 78 switch(side) { 79 case SRCVL_BACK: mask = SSOL_BACK; break; 80 case SRCVL_FRONT: mask = SSOL_FRONT; break; 81 case SRCVL_FRONT_AND_BACK: mask = SSOL_BACK | SSOL_FRONT; break; 82 default: FATAL("Unreachable code.\n"); break; 83 } 84 return mask; 85 } 86 87 static INLINE int 88 srcvl_per_prim_to_bool(const enum srcvl_pp_output output) 89 { 90 int mask = 0; 91 switch (output) { 92 case SRCVL_PP_NONE: mask = 0; break; 93 case SRCVL_PP_INCOMING: mask = 1; break; 94 case SRCVL_PP_ABSORBED: mask = 1; break; 95 case SRCVL_PP_INCOMING_AND_ABSORBED: mask = 1; break; 96 default: FATAL("Unreachable code.\n"); break; 97 } 98 return mask; 99 } 100 101 static struct solstice_node* 102 create_empty_node 103 (struct solstice* solstice, const struct solparser_entity* entity) 104 { 105 struct solstice_node* node = NULL; 106 res_T res = RES_OK; 107 ASSERT(solstice && entity); 108 (void)entity; 109 110 res = solstice_node_empty_create(solstice->allocator, &node); 111 if(res != RES_OK) goto error; 112 113 exit: 114 return node; 115 error: 116 if(node) { 117 solstice_node_ref_put(node); 118 node = NULL; 119 } 120 goto exit; 121 } 122 123 static struct solstice_node* 124 create_geometry_node 125 (struct solstice* solstice, const struct solparser_entity* entity) 126 { 127 struct solstice_node* node = NULL; 128 struct ssol_instance* instance = NULL; 129 res_T res = RES_OK; 130 ASSERT(solstice && entity); 131 132 res = solstice_instantiate_geometry 133 (solstice, entity->data.geometry, &instance); 134 if(res != RES_OK) goto error; 135 136 res = solstice_node_geometry_create(solstice->allocator, instance, &node); 137 if(res != RES_OK) goto error; 138 139 exit: 140 if(instance) SSOL(instance_ref_put(instance)); 141 return node; 142 error: 143 if(node) { 144 solstice_node_ref_put(node); 145 node = NULL; 146 } 147 goto exit; 148 } 149 150 static res_T 151 get_anchor_node 152 (struct solstice* solstice, 153 const struct solparser_anchor_id anchor_id, 154 struct solstice_node** out_node) 155 { 156 struct solstice_node* node = NULL; 157 struct solstice_node** pnode = NULL; 158 res_T res = RES_OK; 159 ASSERT(solstice && out_node); 160 161 pnode = htable_anchor_find(&solstice->anchors, &anchor_id.i); 162 if(pnode) { 163 node = *pnode; 164 } else { 165 res = solstice_node_target_create(solstice->allocator, &node); 166 if(res != RES_OK) goto error; 167 res = htable_anchor_set(&solstice->anchors, &anchor_id.i, &node); 168 if(res != RES_OK) goto error; 169 } 170 171 exit: 172 *out_node = node; 173 return res; 174 error: 175 if(node) solstice_node_ref_put(node); 176 goto exit; 177 } 178 179 static res_T 180 setup_tracking 181 (struct solstice* solstice, 182 struct sanim_tracking* tracking, 183 const struct solparser_target* target) 184 { 185 struct solstice_node* anchor_node = NULL; 186 struct str anchor_name; 187 res_T res = RES_OK; 188 ASSERT(solstice && tracking && target); 189 190 str_init(solstice->allocator, &anchor_name); 191 192 switch(target->type) { 193 case SOLPARSER_TARGET_ANCHOR: 194 tracking->policy = TRACKING_NODE_TARGET; 195 res = get_anchor_node(solstice, target->data.anchor, &anchor_node); 196 if(res != RES_OK) goto error; 197 solstice_node_target_get_tracking(anchor_node, tracking); 198 break; 199 case SOLPARSER_TARGET_DIRECTION: 200 tracking->policy = TRACKING_OUT_DIR; 201 d3_set(tracking->data.out_dir.u, target->data.direction); 202 break; 203 case SOLPARSER_TARGET_POSITION: 204 tracking->policy = TRACKING_POINT; 205 d3_set(tracking->data.point.target, target->data.position); 206 tracking->data.point.target_is_local = 0; 207 break; 208 case SOLPARSER_TARGET_SUN: 209 tracking->policy = TRACKING_SUN; 210 break; 211 default: FATAL("Unreachable code.\n"); break; 212 } 213 214 exit: 215 str_release(&anchor_name); 216 return res; 217 error: 218 goto exit; 219 } 220 221 222 static struct solstice_node* 223 create_x_pivot_node 224 (struct solstice* solstice, 225 const struct solparser_entity* entity) 226 { 227 double n[3]; 228 struct solstice_node* node = NULL; 229 const struct solparser_x_pivot* parser_x_pivot = NULL; 230 struct sanim_pivot anim_pivot = SANIM_PIVOT_NULL; 231 struct sanim_tracking anim_tracking = SANIM_TRACKING_NULL; 232 res_T res = RES_OK; 233 ASSERT(solstice && entity); 234 235 parser_x_pivot = solparser_get_x_pivot(solstice->parser, entity->data.x_pivot); 236 237 anim_pivot.type = PIVOT_SINGLE_AXIS; 238 d3_set(anim_pivot.data.pivot1.ref_normal, d3(n, 0, 0, 1)); 239 d3_set(anim_pivot.data.pivot1.ref_point, parser_x_pivot->ref_point); 240 241 res = setup_tracking(solstice, &anim_tracking, &parser_x_pivot->target); 242 if(res != RES_OK) goto error; 243 244 res = solstice_node_pivot_create 245 (solstice->allocator, &anim_pivot, &anim_tracking, &node); 246 if(res != RES_OK) goto error; 247 248 res = darray_nodes_push_back(&solstice->pivots, &node); 249 if(res != RES_OK) goto error; 250 251 exit: 252 return node; 253 error: 254 if(node) { 255 solstice_node_ref_put(node); 256 node = NULL; 257 } 258 goto exit; 259 } 260 261 static struct solstice_node* 262 create_zx_pivot_node 263 (struct solstice* solstice, 264 const struct solparser_entity* entity) 265 { 266 struct solstice_node* node = NULL; 267 const struct solparser_zx_pivot* parser_zx_pivot = NULL; 268 struct sanim_pivot anim_pivot = SANIM_PIVOT_NULL; 269 struct sanim_tracking anim_tracking = SANIM_TRACKING_NULL; 270 res_T res = RES_OK; 271 ASSERT(solstice && entity); 272 273 parser_zx_pivot = solparser_get_zx_pivot(solstice->parser, entity->data.zx_pivot); 274 275 anim_pivot.type = PIVOT_TWO_AXIS; 276 anim_pivot.data.pivot2.spacing = parser_zx_pivot->spacing; 277 d3_set(anim_pivot.data.pivot2.ref_point, parser_zx_pivot->ref_point); 278 279 res = setup_tracking(solstice, &anim_tracking, &parser_zx_pivot->target); 280 if(res != RES_OK) goto error; 281 282 res = solstice_node_pivot_create 283 (solstice->allocator, &anim_pivot, &anim_tracking, &node); 284 if(res != RES_OK) goto error; 285 286 res = darray_nodes_push_back(&solstice->pivots, &node); 287 if(res != RES_OK) goto error; 288 289 exit: 290 return node; 291 error: 292 if (node) { 293 solstice_node_ref_put(node); 294 node = NULL; 295 } 296 goto exit; 297 } 298 299 static struct solstice_node* 300 create_node 301 (struct solstice* solstice, 302 const struct solparser_entity* entity, 303 const struct str* name) 304 { 305 struct solstice_node* node = NULL; 306 struct solstice_node* child = NULL; 307 struct solstice_receiver* rcv = NULL; 308 const char* str = NULL; 309 size_t* pircv = NULL; 310 struct str child_name; 311 struct str anchor_name; 312 double rotation[3]; 313 size_t i; 314 res_T res = RES_OK; 315 ASSERT(solstice && entity && name); 316 317 str_init(solstice->allocator, &child_name); 318 str_init(solstice->allocator, &anchor_name); 319 320 /* Create the entity node */ 321 switch(entity->type) { 322 case SOLPARSER_ENTITY_EMPTY: 323 node = create_empty_node(solstice, entity); 324 break; 325 case SOLPARSER_ENTITY_GEOMETRY: 326 node = create_geometry_node(solstice, entity); 327 break; 328 case SOLPARSER_ENTITY_X_PIVOT: 329 node = create_x_pivot_node(solstice, entity); 330 break; 331 case SOLPARSER_ENTITY_ZX_PIVOT: 332 node = create_zx_pivot_node(solstice, entity); 333 break; 334 default: FATAL("Unreachable code.\n"); break; 335 } 336 if(!node) { 337 fprintf(stderr, "Could not setup the entity node.\n"); 338 goto error; 339 } 340 341 res = solstice_node_set_name(node, str_cget(name)); 342 if(res != RES_OK) { 343 fprintf(stderr, "Could not setup the solstice node name.\n"); 344 goto error; 345 } 346 347 /* Setup the primary parameter for the geometry entity */ 348 if(entity->type == SOLPARSER_ENTITY_GEOMETRY) { 349 res = solstice_node_geometry_set_primary(node, entity->primary); 350 if(res != RES_OK) { 351 fprintf(stderr, 352 "Could not define the primary parameter of the entity `%s'.\n", 353 str_cget(&entity->name)); 354 goto error; 355 } 356 if(entity->primary) { 357 struct solstice_primary p; 358 p.node = node; 359 res = htable_primary_set(&solstice->primaries, name, &p); 360 if(res != RES_OK) { 361 fprintf(stderr, "Could not define the entity `%s' as primary.\n", 362 str_cget(&entity->name)); 363 goto error; 364 } 365 } 366 } 367 368 /* Setup the entity receiver flags */ 369 str = str_cget(name); 370 pircv = htable_receiver_find(&solstice->receivers, &str); 371 if(pircv) { 372 int side_mask, output; 373 rcv = darray_receiver_data_get(&solstice->rcvs_list) + *pircv; 374 ASSERT(rcv->node == NULL); /* Receiver is not attached to a node */ 375 376 side_mask = srcvl_side_to_ssol_mask(rcv->side); 377 output = srcvl_per_prim_to_bool(rcv->per_primitive_output); 378 379 res = solstice_node_geometry_set_receiver(node, side_mask, output); 380 if(res != RES_OK) { 381 fprintf(stderr, "Could not define the entity `%s' as a receiver.\n", 382 str_cget(&entity->name)); 383 goto error; 384 } 385 rcv->node = node; 386 } 387 388 /* Setup the entity transform */ 389 rotation[0] = MDEG2RAD(entity->rotation[0]); 390 rotation[1] = MDEG2RAD(entity->rotation[1]); 391 rotation[2] = MDEG2RAD(entity->rotation[2]); 392 solstice_node_set_translation(node, entity->translation); 393 solstice_node_set_rotations(node, rotation); 394 395 /* Register entity anchors */ 396 FOR_EACH(i, 0, solparser_entity_get_anchors_count(entity)) { 397 struct solstice_node* tgt = NULL; 398 struct solparser_anchor_id id; 399 const struct solparser_anchor* anchor; 400 401 id = solparser_entity_get_anchor(entity, i); 402 anchor = solparser_get_anchor(solstice->parser, id); 403 404 res = merge_name(&anchor_name, name, &anchor->name); 405 if(res != RES_OK) goto error; 406 407 res = get_anchor_node(solstice, id, &tgt); 408 if(res != RES_OK) goto error; 409 410 solstice_node_set_translation(tgt, anchor->position); 411 412 res = solstice_node_add_child(node, tgt); 413 if(res != RES_OK) goto error; 414 } 415 416 /* Setup children */ 417 FOR_EACH(i, 0, solparser_entity_get_children_count(entity)) { 418 struct solparser_entity_id id; 419 const struct solparser_entity* child_entity; 420 421 id = solparser_entity_get_child(entity, i); 422 child_entity = solparser_get_entity(solstice->parser, id); 423 424 res = merge_name(&child_name, name, &child_entity->name); 425 if(res != RES_OK) goto error; 426 427 child = create_node(solstice, child_entity, &child_name); 428 if(!child) goto error; 429 430 res = solstice_node_add_child(node, child); 431 if(res != RES_OK) goto error; 432 433 solstice_node_ref_put(child); 434 child = NULL; 435 } 436 437 exit: 438 str_release(&child_name); 439 str_release(&anchor_name); 440 return node; 441 error: 442 if(child) solstice_node_ref_put(child); 443 if(node) solstice_node_ref_put(node); 444 node = NULL; 445 goto exit; 446 } 447 448 /******************************************************************************* 449 * Local functions 450 ******************************************************************************/ 451 res_T 452 solstice_setup_entities(struct solstice* solstice) 453 { 454 struct solparser_entity_iterator it, it_end; 455 struct solstice_node* root = NULL; 456 struct str name; 457 const double dummy_sun_dir[3] = {0, 0, -1}; 458 res_T res = RES_OK; 459 ASSERT(solstice); 460 461 str_init(solstice->allocator, &name); 462 463 /* (re) create the list of roots from entities */ 464 solparser_entity_iterator_begin(solstice->parser, &it); 465 solparser_entity_iterator_end(solstice->parser, &it_end); 466 while(!solparser_entity_iterator_eq(&it, &it_end)) { 467 struct solparser_entity_id entity_id; 468 const struct solparser_entity* entity; 469 470 str_clear(&name); 471 entity_id = solparser_entity_iterator_get(&it); 472 entity = solparser_get_entity(solstice->parser, entity_id); 473 474 res = str_copy(&name, &entity->name); 475 if(res != RES_OK) { 476 fprintf(stderr, "Could not initialise the absolute entity name.\n"); 477 goto error; 478 } 479 480 root = create_node(solstice, entity, &name); 481 if(!root) { 482 res = RES_BAD_ARG; 483 goto error; 484 } 485 486 res = darray_nodes_push_back(&solstice->roots, &root); 487 if(res != RES_OK) { 488 fprintf(stderr, "Could not register a root entity.\n"); 489 goto error; 490 } 491 492 solparser_entity_iterator_next(&it); 493 root = NULL; 494 } 495 496 /* Initialise the world space position of the geometries */ 497 res = solstice_update_entities(solstice, dummy_sun_dir); 498 if(res != RES_OK) { 499 fprintf(stderr, "Could not setup the initial position of the entities.\n"); 500 goto error; 501 } 502 503 exit: 504 str_release(&name); 505 return res; 506 error: 507 if(root) solstice_node_ref_put(root); 508 goto exit; 509 } 510 511 res_T 512 solstice_update_entities(struct solstice* solstice, const double sun_dir[3]) 513 { 514 size_t i, n; 515 res_T res = RES_OK; 516 ASSERT(solstice && sun_dir); 517 518 n = darray_nodes_size_get(&solstice->roots); 519 FOR_EACH(i, 0, n) { 520 struct solstice_node* node = darray_nodes_data_get(&solstice->roots)[i]; 521 522 res = sanim_node_visit_tree 523 (&node->anim, sun_dir, solstice, update_instance_transform); 524 if(res != RES_OK) { 525 fprintf(stderr, 526 "Could not update the transformation of the entity geometries.\n"); 527 goto error; 528 } 529 } 530 531 exit: 532 return res; 533 error: 534 goto exit; 535 } 536