eggMatrixTablePointer.cxx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file eggMatrixTablePointer.cxx
  10. * @author drose
  11. * @date 2001-02-26
  12. */
  13. #include "eggMatrixTablePointer.h"
  14. #include "dcast.h"
  15. #include "eggCharacterDb.h"
  16. #include "eggSAnimData.h"
  17. #include "eggXfmAnimData.h"
  18. #include "eggXfmSAnim.h"
  19. using std::string;
  20. TypeHandle EggMatrixTablePointer::_type_handle;
  21. /**
  22. *
  23. */
  24. EggMatrixTablePointer::
  25. EggMatrixTablePointer(EggObject *object) {
  26. _table = DCAST(EggTable, object);
  27. if (_table != nullptr) {
  28. // Now search for the child named "xform". This contains the actual table
  29. // data.
  30. EggGroupNode::iterator ci;
  31. bool found = false;
  32. for (ci = _table->begin(); ci != _table->end() && !found; ++ci) {
  33. EggNode *child = (*ci);
  34. if (child->get_name() == "xform") {
  35. if (child->is_of_type(EggXfmSAnim::get_class_type())) {
  36. _xform = DCAST(EggXfmSAnim, child);
  37. _xform->normalize();
  38. found = true;
  39. } else if (child->is_of_type(EggXfmAnimData::get_class_type())) {
  40. // Quietly replace old-style XfmAnim tables with new-style XfmSAnim
  41. // tables.
  42. PT(EggXfmAnimData) anim = DCAST(EggXfmAnimData, child);
  43. _xform = new EggXfmSAnim(*anim);
  44. _table->replace(ci, _xform.p());
  45. found = true;
  46. }
  47. }
  48. }
  49. }
  50. }
  51. /**
  52. * Returns the stated frame rate of this particular joint, or 0.0 if it
  53. * doesn't state.
  54. */
  55. double EggMatrixTablePointer::
  56. get_frame_rate() const {
  57. if (_xform == nullptr || !_xform->has_fps()) {
  58. return 0.0;
  59. } else {
  60. return _xform->get_fps();
  61. }
  62. }
  63. /**
  64. * Returns the number of frames of animation for this particular joint.
  65. */
  66. int EggMatrixTablePointer::
  67. get_num_frames() const {
  68. if (_xform == nullptr) {
  69. return 0;
  70. } else {
  71. return _xform->get_num_rows();
  72. }
  73. }
  74. /**
  75. * Extends the table to the indicated number of frames.
  76. */
  77. void EggMatrixTablePointer::
  78. extend_to(int num_frames) {
  79. nassertv(_xform != nullptr);
  80. _xform->normalize();
  81. int num_rows = _xform->get_num_rows();
  82. LMatrix4d last_mat;
  83. if (num_rows == 0) {
  84. last_mat = LMatrix4d::ident_mat();
  85. } else {
  86. _xform->get_value(num_rows - 1, last_mat);
  87. }
  88. while (num_rows < num_frames) {
  89. _xform->add_data(last_mat);
  90. num_rows++;
  91. }
  92. }
  93. /**
  94. * Returns the transform matrix corresponding to this joint position in the
  95. * nth frame.
  96. */
  97. LMatrix4d EggMatrixTablePointer::
  98. get_frame(int n) const {
  99. if (get_num_frames() == 1) {
  100. // If we have exactly one frame, then we have as many frames as we want;
  101. // just repeat the first frame.
  102. n = 0;
  103. } else if (get_num_frames() == 0) {
  104. // If we have no frames, we really have the identity matrix.
  105. return LMatrix4d::ident_mat();
  106. }
  107. nassertr(n >= 0 && n < get_num_frames(), LMatrix4d::ident_mat());
  108. LMatrix4d mat;
  109. _xform->get_value(n, mat);
  110. return mat;
  111. }
  112. /**
  113. * Sets the transform matrix corresponding to this joint position in the nth
  114. * frame.
  115. */
  116. void EggMatrixTablePointer::
  117. set_frame(int n, const LMatrix4d &mat) {
  118. nassertv(n >= 0 && n < get_num_frames());
  119. _xform->set_value(n, mat);
  120. }
  121. /**
  122. * Appends a new frame onto the end of the data, if possible; returns true if
  123. * not possible, or false otherwise (e.g. for a static joint).
  124. */
  125. bool EggMatrixTablePointer::
  126. add_frame(const LMatrix4d &mat) {
  127. if (_xform == nullptr) {
  128. return false;
  129. }
  130. return _xform->add_data(mat);
  131. }
  132. /**
  133. * Performs the actual reparenting operation by removing the node from its old
  134. * parent and associating it with its new parent, if any.
  135. */
  136. void EggMatrixTablePointer::
  137. do_finish_reparent(EggJointPointer *new_parent) {
  138. if (new_parent == nullptr) {
  139. // No new parent; unparent the joint.
  140. EggGroupNode *egg_parent = _table->get_parent();
  141. if (egg_parent != nullptr) {
  142. egg_parent->remove_child(_table.p());
  143. }
  144. } else {
  145. // Reparent the joint to its new parent (implicitly unparenting it from
  146. // its previous parent).
  147. EggMatrixTablePointer *new_node = DCAST(EggMatrixTablePointer, new_parent);
  148. if (new_node->_table != _table->get_parent()) {
  149. new_node->_table->add_child(_table.p());
  150. }
  151. }
  152. }
  153. /**
  154. * Rebuilds the entire table all at once, based on the frames added by
  155. * repeated calls to add_rebuild_frame() since the last call to
  156. * begin_rebuild().
  157. *
  158. * Until do_rebuild() is called, the animation table is not changed.
  159. *
  160. * The return value is true if all frames are acceptable, or false if there is
  161. * some problem.
  162. */
  163. bool EggMatrixTablePointer::
  164. do_rebuild(EggCharacterDb &db) {
  165. LMatrix4d mat;
  166. if (!db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, 0, mat)) {
  167. // No rebuild frame; this is OK.
  168. return true;
  169. }
  170. if (_xform == nullptr) {
  171. return false;
  172. }
  173. bool all_ok = true;
  174. _xform->clear_data();
  175. if (!_xform->add_data(mat)) {
  176. all_ok = false;
  177. }
  178. // Assume all frames will be contiguous.
  179. int n = 1;
  180. while (db.get_matrix(this, EggCharacterDb::TT_rebuild_frame, n, mat)) {
  181. if (!_xform->add_data(mat)) {
  182. all_ok = false;
  183. }
  184. ++n;
  185. }
  186. return all_ok;
  187. }
  188. /**
  189. * Resets the table before writing to disk so that redundant rows (e.g. i { 1
  190. * 1 1 1 1 1 1 1 }) are collapsed out.
  191. */
  192. void EggMatrixTablePointer::
  193. optimize() {
  194. if (_xform != nullptr) {
  195. _xform->optimize();
  196. }
  197. }
  198. /**
  199. * Zeroes out the named components of the transform in the animation frames.
  200. */
  201. void EggMatrixTablePointer::
  202. zero_channels(const string &components) {
  203. if (_xform == nullptr) {
  204. return;
  205. }
  206. // This is particularly easy: we only have to remove children from the
  207. // _xform object whose name is listed in the components.
  208. string::const_iterator si;
  209. for (si = components.begin(); si != components.end(); ++si) {
  210. string table_name(1, *si);
  211. EggNode *child = _xform->find_child(table_name);
  212. if (child != nullptr) {
  213. _xform->remove_child(child);
  214. }
  215. }
  216. }
  217. /**
  218. * Rounds the named components of the transform to the nearest multiple of
  219. * quantum.
  220. */
  221. void EggMatrixTablePointer::
  222. quantize_channels(const string &components, double quantum) {
  223. if (_xform == nullptr) {
  224. return;
  225. }
  226. // This is similar to the above: we quantize children of the _xform object
  227. // whose name is listed in the components.
  228. string::const_iterator si;
  229. for (si = components.begin(); si != components.end(); ++si) {
  230. string table_name(1, *si);
  231. EggNode *child = _xform->find_child(table_name);
  232. if (child != nullptr &&
  233. child->is_of_type(EggSAnimData::get_class_type())) {
  234. EggSAnimData *anim = DCAST(EggSAnimData, child);
  235. anim->quantize(quantum);
  236. }
  237. }
  238. }
  239. /**
  240. * Creates a new child of the current joint in the egg data, and returns a
  241. * pointer to it.
  242. */
  243. EggJointPointer *EggMatrixTablePointer::
  244. make_new_joint(const string &name) {
  245. EggTable *new_table = new EggTable(name);
  246. _table->add_child(new_table);
  247. CoordinateSystem cs = CS_default;
  248. if (_xform != nullptr) {
  249. cs = _xform->get_coordinate_system();
  250. }
  251. EggXfmSAnim *new_xform = new EggXfmSAnim("xform", cs);
  252. new_table->add_child(new_xform);
  253. new_xform->add_data(LMatrix4d::ident_mat());
  254. return new EggMatrixTablePointer(new_table);
  255. }
  256. /**
  257. * Applies the indicated name change to the egg file.
  258. */
  259. void EggMatrixTablePointer::
  260. set_name(const string &name) {
  261. _table->set_name(name);
  262. }