/src/lipsofsuna/model/model-node.c

https://gitlab.com/xenodora/lipsofsuna · C · 575 lines · 398 code · 62 blank · 115 comment · 72 complexity · 91d064e004c3dd58d7e15a18fef97dc2 MD5 · raw file

  1. /* Lips of Suna
  2. * Copyright© 2007-2010 Lips of Suna development team.
  3. *
  4. * Lips of Suna is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as
  6. * published by the Free Software Foundation, either version 3 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * Lips of Suna 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 Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public License
  15. * along with Lips of Suna. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. /**
  18. * \addtogroup LIMdl Model
  19. * @{
  20. * \addtogroup LIMdlNode Node
  21. * @{
  22. */
  23. #include "lipsofsuna/system.h"
  24. #include "model-node.h"
  25. static void private_calculate_world_transform (
  26. LIMdlNode* self,
  27. LIMdlNodeTransform* ts,
  28. LIMdlNodeTransform* tp);
  29. /*****************************************************************************/
  30. LIMdlNode* limdl_node_new ()
  31. {
  32. LIMdlNode* self;
  33. self = lisys_calloc (1, sizeof (LIMdlNode));
  34. if (self == NULL)
  35. return NULL;
  36. self->rest_transform.rest = limat_transform_identity ();
  37. self->rest_transform.local = limat_transform_identity ();
  38. self->rest_transform.local_scale = 1.0f;
  39. self->rest_transform.global = limat_transform_identity ();
  40. self->rest_transform.global_scale = 1.0f;
  41. self->pose_transform = self->rest_transform;
  42. return self;
  43. }
  44. LIMdlNode* limdl_node_copy (
  45. const LIMdlNode* node,
  46. int recursive)
  47. {
  48. int i;
  49. LIMdlNode* self;
  50. /* Allocate self. */
  51. self = lisys_calloc (1, sizeof (LIMdlNode));
  52. if (self == NULL)
  53. return NULL;
  54. self->type = node->type;
  55. self->rest_transform.rest = node->rest_transform.rest;
  56. self->rest_transform.local = node->rest_transform.local;
  57. self->rest_transform.local_scale = node->rest_transform.local_scale;
  58. self->rest_transform.global = node->rest_transform.global;
  59. self->rest_transform.global_scale = node->rest_transform.global_scale;
  60. self->pose_transform.rest = node->pose_transform.rest;
  61. self->pose_transform.local = node->pose_transform.local;
  62. self->pose_transform.local_scale = node->pose_transform.local_scale;
  63. self->pose_transform.global = node->pose_transform.global;
  64. self->pose_transform.global_scale = node->pose_transform.global_scale;
  65. /* Copy the name. */
  66. if (node->name != NULL)
  67. {
  68. self->name = lisys_string_dup (node->name);
  69. if (self->name == NULL)
  70. {
  71. limdl_node_free (self);
  72. return NULL;
  73. }
  74. }
  75. /* Copy type specific data. */
  76. switch (node->type)
  77. {
  78. case LIMDL_NODE_BONE:
  79. self->bone = node->bone;
  80. break;
  81. case LIMDL_NODE_EMPTY:
  82. break;
  83. case LIMDL_NODE_LIGHT:
  84. self->light = node->light;
  85. break;
  86. default:
  87. lisys_assert (0);
  88. break;
  89. }
  90. /* Copy child nodes. */
  91. if (recursive && node->nodes.count)
  92. {
  93. self->nodes.count = node->nodes.count;
  94. self->nodes.array = lisys_calloc (self->nodes.count, sizeof (LIMdlNode*));
  95. if (self->nodes.array == NULL)
  96. {
  97. limdl_node_free (self);
  98. return NULL;
  99. }
  100. for (i = 0 ; i < self->nodes.count ; i++)
  101. {
  102. self->nodes.array[i] = limdl_node_copy (node->nodes.array[i], 1);
  103. if (self->nodes.array[i] == NULL)
  104. {
  105. limdl_node_free (self);
  106. return NULL;
  107. }
  108. self->nodes.array[i]->parent = self;
  109. }
  110. }
  111. return self;
  112. }
  113. void limdl_node_free (
  114. LIMdlNode* self)
  115. {
  116. int i;
  117. /* Free nodes. */
  118. if (self->nodes.array != NULL)
  119. {
  120. for (i = 0 ; i < self->nodes.count ; i++)
  121. {
  122. if (self->nodes.array[i] != NULL)
  123. limdl_node_free (self->nodes.array[i]);
  124. }
  125. lisys_free (self->nodes.array);
  126. }
  127. lisys_free (self->name);
  128. lisys_free (self);
  129. }
  130. /**
  131. * \brief Adds a child node to the node.
  132. * \param self Node.
  133. * \param node Node.
  134. * \return Nonzero on success.
  135. */
  136. int limdl_node_add_child (
  137. LIMdlNode* self,
  138. LIMdlNode* node)
  139. {
  140. LIMdlNode** tmp;
  141. tmp = lisys_realloc (self->nodes.array, (self->nodes.count + 1) * sizeof (LIMdlNode*));
  142. if (tmp == NULL)
  143. return 0;
  144. self->nodes.array = tmp;
  145. self->nodes.array[self->nodes.count] = node;
  146. self->nodes.count++;
  147. return 1;
  148. }
  149. LIMdlNode* limdl_node_find_node (
  150. const LIMdlNode* self,
  151. const char* name)
  152. {
  153. int i;
  154. LIMdlNode* tmp;
  155. /* Test self. */
  156. if (self->name != NULL && !strcmp (self->name, name))
  157. return (LIMdlNode*) self;
  158. /* Test children. */
  159. for (i = 0 ; i < self->nodes.count ; i++)
  160. {
  161. if (self->nodes.array[i] != NULL)
  162. {
  163. tmp = limdl_node_find_node (self->nodes.array[i], name);
  164. if (tmp != NULL)
  165. return tmp;
  166. }
  167. }
  168. return NULL;
  169. }
  170. int limdl_node_read (
  171. LIMdlNode* self,
  172. LIArcReader* reader)
  173. {
  174. int i;
  175. uint32_t count;
  176. uint32_t type;
  177. LIMatVector position;
  178. LIMatQuaternion rotation;
  179. /* Read header. */
  180. if (!liarc_reader_get_uint32 (reader, &type) ||
  181. !liarc_reader_get_uint32 (reader, &count) ||
  182. !liarc_reader_get_text (reader, "", &self->name) ||
  183. !liarc_reader_get_float (reader, &position.x) ||
  184. !liarc_reader_get_float (reader, &position.y) ||
  185. !liarc_reader_get_float (reader, &position.z) ||
  186. !liarc_reader_get_float (reader, &rotation.x) ||
  187. !liarc_reader_get_float (reader, &rotation.y) ||
  188. !liarc_reader_get_float (reader, &rotation.z) ||
  189. !liarc_reader_get_float (reader, &rotation.w))
  190. return 0;
  191. self->type = type;
  192. self->nodes.count = count;
  193. self->rest_transform.rest = limat_transform_init (position, rotation);
  194. self->rest_transform.local = limat_transform_identity ();
  195. self->rest_transform.local_scale = 1.0f;
  196. self->rest_transform.global = limat_transform_init (position, rotation);
  197. self->rest_transform.global_scale = 1.0f;
  198. self->pose_transform = self->rest_transform;
  199. /* Read type sepecific data. */
  200. switch (type)
  201. {
  202. case LIMDL_NODE_BONE:
  203. if (!limdl_bone_read (self, reader))
  204. return 0;
  205. break;
  206. case LIMDL_NODE_EMPTY:
  207. break;
  208. case LIMDL_NODE_LIGHT:
  209. if (!limdl_light_read (self, reader))
  210. return 0;
  211. break;
  212. default:
  213. lisys_error_set (EINVAL, "invalid node type %d", type);
  214. return 0;
  215. }
  216. /* Read child nodes. */
  217. if (self->nodes.count)
  218. {
  219. self->nodes.array = lisys_calloc (self->nodes.count, sizeof (LIMdlNode*));
  220. if (self->nodes.array == NULL)
  221. return 0;
  222. for (i = 0 ; i < self->nodes.count ; i++)
  223. {
  224. self->nodes.array[i] = limdl_node_new ();
  225. if (self->nodes.array[i] == NULL)
  226. return 0;
  227. self->nodes.array[i]->parent = self;
  228. if (!limdl_node_read (self->nodes.array[i], reader))
  229. return 0;
  230. }
  231. }
  232. return 1;
  233. }
  234. /**
  235. * \brief Updates the world space rest transformation of the node and, optionally, its children.
  236. * \param self Node.
  237. * \param recursive Nonzero if children should be rebuilt.
  238. */
  239. void limdl_node_rebuild (
  240. LIMdlNode* self,
  241. int recursive)
  242. {
  243. int i;
  244. LIMdlNodeTransform* ts;
  245. LIMdlNodeTransform* tp;
  246. /* Calculate the world transformation. */
  247. ts = &self->rest_transform;
  248. if (self->parent != NULL)
  249. tp = &self->parent->rest_transform;
  250. else
  251. tp = NULL;
  252. private_calculate_world_transform (self, ts, tp);
  253. self->pose_transform = *ts;
  254. /* Rebuild children. */
  255. if (recursive)
  256. {
  257. for (i = 0 ; i < self->nodes.count ; i++)
  258. limdl_node_rebuild (self->nodes.array[i], 1);
  259. }
  260. }
  261. /**
  262. * \brief Updates the world space pose transformation of the node and, optionally, its children.
  263. * \param self Node.
  264. * \param recursive Nonzero if children should be rebuilt.
  265. */
  266. void limdl_node_rebuild_pose (
  267. LIMdlNode* self,
  268. int recursive)
  269. {
  270. int i;
  271. LIMdlNodeTransform* ts;
  272. LIMdlNodeTransform* tp;
  273. /* Reset the rest pose. */
  274. self->pose_transform.rest = self->rest_transform.rest;
  275. /* Calculate the world transformation. */
  276. ts = &self->pose_transform;
  277. if (self->parent != NULL)
  278. tp = &self->parent->pose_transform;
  279. else
  280. tp = NULL;
  281. private_calculate_world_transform (self, ts, tp);
  282. /* Rebuild children. */
  283. if (recursive)
  284. {
  285. for (i = 0 ; i < self->nodes.count ; i++)
  286. limdl_node_rebuild (self->nodes.array[i], 1);
  287. }
  288. }
  289. int limdl_node_write (
  290. const LIMdlNode* self,
  291. LIArcWriter* writer)
  292. {
  293. int i;
  294. int count = 0;
  295. /* Count the real number of nodes. */
  296. for (i = 0 ; i < self->nodes.count ; i++)
  297. {
  298. if (self->nodes.array[i] != NULL)
  299. count++;
  300. }
  301. /* Write header. */
  302. liarc_writer_append_uint32 (writer, self->type);
  303. liarc_writer_append_uint32 (writer, count);
  304. if (self->name != NULL)
  305. liarc_writer_append_string (writer, self->name);
  306. liarc_writer_append_nul (writer);
  307. liarc_writer_append_float (writer, self->rest_transform.rest.position.x);
  308. liarc_writer_append_float (writer, self->rest_transform.rest.position.y);
  309. liarc_writer_append_float (writer, self->rest_transform.rest.position.z);
  310. liarc_writer_append_float (writer, self->rest_transform.rest.rotation.x);
  311. liarc_writer_append_float (writer, self->rest_transform.rest.rotation.y);
  312. liarc_writer_append_float (writer, self->rest_transform.rest.rotation.z);
  313. liarc_writer_append_float (writer, self->rest_transform.rest.rotation.w);
  314. /* Write type sepecific data. */
  315. switch (self->type)
  316. {
  317. case LIMDL_NODE_BONE:
  318. if (!limdl_bone_write (self, writer))
  319. return 0;
  320. break;
  321. case LIMDL_NODE_EMPTY:
  322. break;
  323. case LIMDL_NODE_LIGHT:
  324. if (!limdl_light_write (self, writer))
  325. return 0;
  326. break;
  327. default:
  328. lisys_assert (0 && "invalid node type");
  329. break;
  330. }
  331. /* Write child nodes. */
  332. for (i = 0 ; i < self->nodes.count ; i++)
  333. {
  334. if (!limdl_node_write (self->nodes.array[i], writer))
  335. return 0;
  336. }
  337. return !writer->error;
  338. }
  339. LIMdlNode* limdl_node_get_child (
  340. const LIMdlNode* self,
  341. int index)
  342. {
  343. return self->nodes.array[index];
  344. }
  345. /**
  346. * \brief Gets the number of direct children.
  347. * \param self Node.
  348. * \return Child count.
  349. */
  350. int limdl_node_get_child_count (
  351. const LIMdlNode* self)
  352. {
  353. return self->nodes.count;
  354. }
  355. /**
  356. * \brief Gets the recursive child count of the node.
  357. * \param self Node.
  358. * \return Recursive child count.
  359. */
  360. int limdl_node_get_child_total (
  361. const LIMdlNode* self)
  362. {
  363. int i;
  364. int n;
  365. const LIMdlNode* node;
  366. n = self->nodes.count;
  367. for (i = 0 ; i < self->nodes.count ; i++)
  368. {
  369. node = self->nodes.array[i];
  370. n += limdl_node_get_child_total (node);
  371. }
  372. return n;
  373. }
  374. /**
  375. * \brief Gets the name of the node.
  376. * \param self Node.
  377. * \return Name.
  378. */
  379. const char* limdl_node_get_name (
  380. const LIMdlNode* self)
  381. {
  382. if (self->name != NULL)
  383. return self->name;
  384. return "";
  385. }
  386. /**
  387. * \brief Gets the axes of the node in global coordinates.
  388. * \param self Node.
  389. * \param x Return location for the X axis.
  390. * \param y Return location for the Y axis.
  391. * \param z Return location for the Z axis.
  392. */
  393. void limdl_node_get_pose_axes (
  394. const LIMdlNode* self,
  395. LIMatVector* x,
  396. LIMatVector* y,
  397. LIMatVector* z)
  398. {
  399. *x = limat_quaternion_transform (self->rest_transform.global.rotation, limat_vector_init (1.0f, 0.0f, 0.0f));
  400. *y = limat_quaternion_transform (self->rest_transform.global.rotation, limat_vector_init (0.0f, 1.0f, 0.0f));
  401. *z = limat_quaternion_transform (self->rest_transform.global.rotation, limat_vector_init (0.0f, 0.0f, 1.0f));
  402. }
  403. void limdl_node_get_rest_transform (
  404. const LIMdlNode* self,
  405. LIMatTransform* value)
  406. {
  407. *value = self->rest_transform.rest;
  408. }
  409. /**
  410. * \brief Gets the full rest transformation.
  411. * \param self Node.
  412. * \param scale Return location for the scale factor.
  413. * \param value Return location for the transformation.
  414. */
  415. void limdl_node_get_full_rest_transform (
  416. const LIMdlNode* self,
  417. float* scale,
  418. LIMatTransform* value)
  419. {
  420. *scale = self->rest_transform.global_scale;
  421. *value = self->rest_transform.global;
  422. }
  423. /**
  424. * \brief Gets the world space pose transformation.
  425. * \param self Node.
  426. * \param scale Return location for the scale factor.
  427. * \param value Return location for the transformation.
  428. */
  429. void limdl_node_get_world_transform (
  430. const LIMdlNode* self,
  431. float* scale,
  432. LIMatTransform* value)
  433. {
  434. *scale = self->pose_transform.global_scale;
  435. *value = self->pose_transform.global;
  436. }
  437. /**
  438. * \brief Sets the pose transformation of the node.
  439. *
  440. * Call #limdl_node_rebuild to apply the transformation.
  441. *
  442. * \param self Node.
  443. * \param scale Scale factor.
  444. * \param value Local transformation of the node.
  445. */
  446. void limdl_node_set_local_transform (
  447. LIMdlNode* self,
  448. float scale,
  449. const LIMatTransform* value)
  450. {
  451. self->pose_transform.local_scale = scale;
  452. self->pose_transform.local = *value;
  453. }
  454. LIMdlNodeType limdl_node_get_type (
  455. const LIMdlNode* self)
  456. {
  457. return self->type;
  458. }
  459. /*****************************************************************************/
  460. static void private_calculate_world_transform (
  461. LIMdlNode* self,
  462. LIMdlNodeTransform* ts,
  463. LIMdlNodeTransform* tp)
  464. {
  465. LIMatTransform p;
  466. LIMatTransform t;
  467. LIMatVector tmp;
  468. if (self->parent != NULL)
  469. {
  470. /* Get the tail transformation of the parent. */
  471. p = tp->global;
  472. if (self->parent->type == LIMDL_NODE_BONE)
  473. p.position = tp->tail;
  474. /* Calculate the global scale factor. */
  475. /* This is the product of the local scale factors of all the ancestors. */
  476. ts->global_scale = tp->global_scale * ts->local_scale;
  477. /* Calculate the global transformation. */
  478. /* This is the local transformation concatenated with the parent tail transformation. */
  479. t = ts->rest;
  480. t.position = limat_vector_multiply (t.position, tp->global_scale);
  481. t = limat_transform_multiply (p, t);
  482. t = limat_transform_multiply (t, ts->local);
  483. ts->global = t;
  484. /* Calculate the tail position. */
  485. if (self->type == LIMDL_NODE_BONE)
  486. {
  487. tmp = limat_vector_multiply (self->bone.length, ts->global_scale);
  488. ts->tail = limat_transform_transform (t, tmp);
  489. }
  490. else
  491. ts->tail = ts->global.position;
  492. }
  493. else
  494. {
  495. /* Calculate global scale factor. */
  496. /* There are no parents so this is simply the local scale factor. */
  497. ts->global_scale = ts->local_scale;
  498. /* Calculate the global transformation. */
  499. /* There are no parents so this is simply the local transformation. */
  500. t = limat_transform_multiply (ts->rest, ts->local);
  501. ts->global = t;
  502. /* Calculate the tail position. */
  503. if (self->type == LIMDL_NODE_BONE)
  504. {
  505. tmp = limat_vector_multiply (self->bone.length, ts->global_scale);
  506. ts->tail = limat_transform_transform (t, tmp);
  507. }
  508. else
  509. ts->tail = ts->global.position;
  510. }
  511. }
  512. /** @} */
  513. /** @} */