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

https://github.com/deldiablo/GodheadLips · C · 471 lines · 329 code · 54 blank · 88 comment · 63 complexity · 7cbd777c87b2c626badf8814eff9bb54 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. /*****************************************************************************/
  28. LIMdlNode* limdl_node_new (
  29. LIMdlModel* model)
  30. {
  31. LIMdlNode* self;
  32. self = lisys_calloc (1, sizeof (LIMdlNode));
  33. if (self == NULL)
  34. return NULL;
  35. self->model = model;
  36. self->transform.rest = limat_transform_identity ();
  37. self->transform.local = limat_transform_identity ();
  38. self->transform.local_scale = 1.0f;
  39. self->transform.global = limat_transform_identity ();
  40. self->transform.global_scale = 1.0f;
  41. return self;
  42. }
  43. LIMdlNode* limdl_node_copy (
  44. const LIMdlNode* node)
  45. {
  46. int i;
  47. LIMdlNode* self;
  48. self = lisys_calloc (1, sizeof (LIMdlNode));
  49. if (self == NULL)
  50. return NULL;
  51. self->type = node->type;
  52. self->model = node->model;
  53. self->transform.rest = node->transform.rest;
  54. self->transform.local = node->transform.local;
  55. self->transform.local_scale = node->transform.local_scale;
  56. self->transform.global = node->transform.global;
  57. self->transform.global_scale = node->transform.global_scale;
  58. /* Copy name. */
  59. if (node->name != NULL)
  60. {
  61. self->name = lisys_string_dup (node->name);
  62. if (self->name == NULL)
  63. goto error;
  64. }
  65. /* Copy type specific data. */
  66. switch (node->type)
  67. {
  68. case LIMDL_NODE_BONE:
  69. self->bone = node->bone;
  70. break;
  71. case LIMDL_NODE_EMPTY:
  72. break;
  73. case LIMDL_NODE_LIGHT:
  74. self->light = node->light;
  75. break;
  76. default:
  77. lisys_assert (0);
  78. break;
  79. }
  80. /* Copy child nodes. */
  81. if (node->nodes.count)
  82. {
  83. self->nodes.count = node->nodes.count;
  84. self->nodes.array = lisys_calloc (self->nodes.count, sizeof (LIMdlNode*));
  85. if (self->nodes.array == NULL)
  86. goto error;
  87. for (i = 0 ; i < self->nodes.count ; i++)
  88. {
  89. self->nodes.array[i] = limdl_node_copy (node->nodes.array[i]);
  90. if (self->nodes.array[i] == NULL)
  91. goto error;
  92. self->nodes.array[i]->parent = self;
  93. }
  94. }
  95. return self;
  96. error:
  97. limdl_node_free (self);
  98. return NULL;
  99. }
  100. void limdl_node_free (
  101. LIMdlNode* self)
  102. {
  103. int i;
  104. /* Free nodes. */
  105. if (self->nodes.array != NULL)
  106. {
  107. for (i = 0 ; i < self->nodes.count ; i++)
  108. {
  109. if (self->nodes.array[i] != NULL)
  110. limdl_node_free (self->nodes.array[i]);
  111. }
  112. lisys_free (self->nodes.array);
  113. }
  114. lisys_free (self->name);
  115. lisys_free (self);
  116. }
  117. LIMdlNode* limdl_node_find_node (
  118. const LIMdlNode* self,
  119. const char* name)
  120. {
  121. int i;
  122. LIMdlNode* tmp;
  123. /* Test self. */
  124. if (self->name != NULL && !strcmp (self->name, name))
  125. return (LIMdlNode*) self;
  126. /* Test children. */
  127. for (i = 0 ; i < self->nodes.count ; i++)
  128. {
  129. if (self->nodes.array[i] != NULL)
  130. {
  131. tmp = limdl_node_find_node (self->nodes.array[i], name);
  132. if (tmp != NULL)
  133. return tmp;
  134. }
  135. }
  136. return NULL;
  137. }
  138. int limdl_node_read (
  139. LIMdlNode* self,
  140. LIArcReader* reader)
  141. {
  142. int i;
  143. uint32_t count;
  144. uint32_t type;
  145. LIMatVector position;
  146. LIMatQuaternion rotation;
  147. /* Read header. */
  148. if (!liarc_reader_get_uint32 (reader, &type) ||
  149. !liarc_reader_get_uint32 (reader, &count) ||
  150. !liarc_reader_get_text (reader, "", &self->name) ||
  151. !liarc_reader_get_float (reader, &position.x) ||
  152. !liarc_reader_get_float (reader, &position.y) ||
  153. !liarc_reader_get_float (reader, &position.z) ||
  154. !liarc_reader_get_float (reader, &rotation.x) ||
  155. !liarc_reader_get_float (reader, &rotation.y) ||
  156. !liarc_reader_get_float (reader, &rotation.z) ||
  157. !liarc_reader_get_float (reader, &rotation.w))
  158. return 0;
  159. self->type = type;
  160. self->nodes.count = count;
  161. self->transform.rest = limat_transform_init (position, rotation);
  162. self->transform.local = limat_transform_identity ();
  163. self->transform.local_scale = 1.0f;
  164. self->transform.global = limat_transform_init (position, rotation);
  165. self->transform.global_scale = 1.0f;
  166. /* Read type sepecific data. */
  167. switch (type)
  168. {
  169. case LIMDL_NODE_BONE:
  170. if (!limdl_bone_read (self, reader))
  171. return 0;
  172. break;
  173. case LIMDL_NODE_EMPTY:
  174. break;
  175. case LIMDL_NODE_LIGHT:
  176. if (!limdl_light_read (self, reader))
  177. return 0;
  178. break;
  179. default:
  180. lisys_error_set (EINVAL, "invalid node type %d", type);
  181. return 0;
  182. }
  183. /* Read child nodes. */
  184. if (self->nodes.count)
  185. {
  186. self->nodes.array = lisys_calloc (self->nodes.count, sizeof (LIMdlNode*));
  187. if (self->nodes.array == NULL)
  188. return 0;
  189. for (i = 0 ; i < self->nodes.count ; i++)
  190. {
  191. self->nodes.array[i] = limdl_node_new (self->model);
  192. if (self->nodes.array[i] == NULL)
  193. return 0;
  194. self->nodes.array[i]->parent = self;
  195. if (!limdl_node_read (self->nodes.array[i], reader))
  196. return 0;
  197. }
  198. }
  199. return 1;
  200. }
  201. /**
  202. * \brief Updates the world space transformation of the node and, optionally, its children.
  203. *
  204. * \param self Node.
  205. * \param recursive Nonzero if children should be rebuilt.
  206. */
  207. void
  208. limdl_node_rebuild (LIMdlNode* self,
  209. int recursive)
  210. {
  211. int i;
  212. private_calculate_world_transform (self);
  213. if (recursive)
  214. {
  215. for (i = 0 ; i < self->nodes.count ; i++)
  216. limdl_node_rebuild (self->nodes.array[i], 1);
  217. }
  218. }
  219. int limdl_node_write (
  220. const LIMdlNode* self,
  221. LIArcWriter* writer)
  222. {
  223. int i;
  224. int count = 0;
  225. /* Count the real number of nodes. */
  226. for (i = 0 ; i < self->nodes.count ; i++)
  227. {
  228. if (self->nodes.array[i] != NULL)
  229. count++;
  230. }
  231. /* Write header. */
  232. liarc_writer_append_uint32 (writer, self->type);
  233. liarc_writer_append_uint32 (writer, count);
  234. if (self->name != NULL)
  235. liarc_writer_append_string (writer, self->name);
  236. liarc_writer_append_nul (writer);
  237. liarc_writer_append_float (writer, self->transform.rest.position.x);
  238. liarc_writer_append_float (writer, self->transform.rest.position.y);
  239. liarc_writer_append_float (writer, self->transform.rest.position.z);
  240. liarc_writer_append_float (writer, self->transform.rest.rotation.x);
  241. liarc_writer_append_float (writer, self->transform.rest.rotation.y);
  242. liarc_writer_append_float (writer, self->transform.rest.rotation.z);
  243. liarc_writer_append_float (writer, self->transform.rest.rotation.w);
  244. /* Write type sepecific data. */
  245. switch (self->type)
  246. {
  247. case LIMDL_NODE_BONE:
  248. if (!limdl_bone_write (self, writer))
  249. return 0;
  250. break;
  251. case LIMDL_NODE_EMPTY:
  252. break;
  253. case LIMDL_NODE_LIGHT:
  254. if (!limdl_light_write (self, writer))
  255. return 0;
  256. break;
  257. default:
  258. lisys_assert (0 && "invalid node type");
  259. break;
  260. }
  261. /* Write child nodes. */
  262. for (i = 0 ; i < self->nodes.count ; i++)
  263. {
  264. if (!limdl_node_write (self->nodes.array[i], writer))
  265. return 0;
  266. }
  267. return !writer->error;
  268. }
  269. LIMdlNode* limdl_node_get_child (
  270. const LIMdlNode* self,
  271. int index)
  272. {
  273. return self->nodes.array[index];
  274. }
  275. /**
  276. * \brief Gets the number of direct children.
  277. * \param self Node.
  278. * \return Child count.
  279. */
  280. int limdl_node_get_child_count (
  281. const LIMdlNode* self)
  282. {
  283. return self->nodes.count;
  284. }
  285. /**
  286. * \brief Gets the recursive child count of the node.
  287. * \param self Node.
  288. * \return Recursive child count.
  289. */
  290. int limdl_node_get_child_total (
  291. const LIMdlNode* self)
  292. {
  293. int i;
  294. const LIMdlNode* node;
  295. i = self->nodes.count;
  296. for (i = 0 ; i < self->nodes.count ; i++)
  297. {
  298. node = self->nodes.array[i];
  299. i += limdl_node_get_child_total (node);
  300. }
  301. return i;
  302. }
  303. /**
  304. * \brief Gets the name of the node.
  305. * \param self Node.
  306. * \return Name.
  307. */
  308. const char* limdl_node_get_name (
  309. const LIMdlNode* self)
  310. {
  311. if (self->name != NULL)
  312. return self->name;
  313. return "";
  314. }
  315. /**
  316. * \brief Gets the axes of the node in global coordinates.
  317. *
  318. * \param self Node.
  319. * \param x Return location for the X axis.
  320. * \param y Return location for the Y axis.
  321. * \param z Return location for the Z axis.
  322. */
  323. void limdl_node_get_pose_axes (
  324. const LIMdlNode* self,
  325. LIMatVector* x,
  326. LIMatVector* y,
  327. LIMatVector* z)
  328. {
  329. *x = limat_quaternion_transform (self->transform.global.rotation, limat_vector_init (1.0f, 0.0f, 0.0f));
  330. *y = limat_quaternion_transform (self->transform.global.rotation, limat_vector_init (0.0f, 1.0f, 0.0f));
  331. *z = limat_quaternion_transform (self->transform.global.rotation, limat_vector_init (0.0f, 0.0f, 1.0f));
  332. }
  333. void limdl_node_get_rest_transform (
  334. const LIMdlNode* self,
  335. LIMatTransform* value)
  336. {
  337. *value = self->transform.rest;
  338. }
  339. void limdl_node_get_world_transform (
  340. const LIMdlNode* self,
  341. float* scale,
  342. LIMatTransform* value)
  343. {
  344. *scale = self->transform.global_scale;
  345. *value = self->transform.global;
  346. }
  347. /**
  348. * \brief Sets the pose transformation of the node.
  349. *
  350. * Call #limdl_node_rebuild to apply the transformation.
  351. *
  352. * \param self Node.
  353. * \param scale Scale factor.
  354. * \param value Local transformation of the node.
  355. */
  356. void limdl_node_set_local_transform (
  357. LIMdlNode* self,
  358. float scale,
  359. const LIMatTransform* value)
  360. {
  361. self->transform.local_scale = scale;
  362. self->transform.local = *value;
  363. }
  364. LIMdlNodeType
  365. limdl_node_get_type (const LIMdlNode* self)
  366. {
  367. return self->type;
  368. }
  369. /*****************************************************************************/
  370. static void private_calculate_world_transform (
  371. LIMdlNode* self)
  372. {
  373. LIMatTransform p;
  374. LIMatTransform t;
  375. LIMatVector tmp;
  376. if (self->parent != NULL)
  377. {
  378. /* Get the tail transformation of the parent. */
  379. p = self->parent->transform.global;
  380. if (self->parent->type == LIMDL_NODE_BONE)
  381. p.position = self->parent->bone.tail;
  382. /* Calculate the global scale factor. */
  383. /* This is the product of the local scale factors of all the ancestors. */
  384. self->transform.global_scale = self->parent->transform.global_scale * self->transform.local_scale;
  385. /* Calculate the global transformation. */
  386. /* This is the local transformation concatenated with the parent tail transformation. */
  387. t = self->transform.rest;
  388. t.position = limat_vector_multiply (t.position, self->parent->transform.global_scale);
  389. t = limat_transform_multiply (p, t);
  390. t = limat_transform_multiply (t, self->transform.local);
  391. self->transform.global = t;
  392. /* Calculate the tail position. */
  393. if (self->type == LIMDL_NODE_BONE)
  394. {
  395. tmp = limat_vector_multiply (self->bone.length, self->transform.global_scale);
  396. self->bone.tail = limat_transform_transform (t, tmp);
  397. }
  398. }
  399. else
  400. {
  401. /* Calculate global scale factor. */
  402. /* There are no parents so this is simply the local scale factor. */
  403. self->transform.global_scale = self->transform.local_scale;
  404. /* Calulate the global transformation. */
  405. /* There are no parents so this is simply the local transformation. */
  406. t = limat_transform_multiply (self->transform.rest, self->transform.local);
  407. self->transform.global = t;
  408. /* Calculate the tail position. */
  409. if (self->type == LIMDL_NODE_BONE)
  410. {
  411. tmp = limat_vector_multiply (self->bone.length, self->transform.global_scale);
  412. self->bone.tail = limat_transform_transform (t, tmp);
  413. }
  414. }
  415. }
  416. /** @} */
  417. /** @} */