Skeleton.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. /******************************************************************************/
  5. uint EditSkeleton::Node::memUsage()C {return name.memUsage();}
  6. bool EditSkeleton::Node::save(File &f)C
  7. {
  8. f.cmpUIntV(0);
  9. f<<name<<parent<<orient_pos;
  10. return f.ok();
  11. }
  12. bool EditSkeleton::Node::load(File &f)
  13. {
  14. switch(f.decUIntV())
  15. {
  16. case 0:
  17. {
  18. f>>name>>parent>>orient_pos;
  19. if(f.ok())return true;
  20. }break;
  21. }
  22. return false;
  23. }
  24. bool EditSkeleton::Node::loadOld(File &f)
  25. {
  26. switch(f.decUIntV())
  27. {
  28. case 0:
  29. {
  30. GetStr2(f, name); f>>parent>>orient_pos;
  31. if(f.ok())return true;
  32. }break;
  33. }
  34. return false;
  35. }
  36. uint EditSkeleton::Bone::memUsage()C {return name.memUsage()+::EE::Mems< ::EE::IndexWeight>::memUsage();}
  37. void EditSkeleton::Bone::init(C Str &name, int node) {T.name=name; ::EE::Mems< ::EE::IndexWeight>::setNum(1)[0].set(node, 1);}
  38. void EditSkeleton::Bone::addWeight(int index, flt weight)
  39. {
  40. if(index>=0)
  41. {
  42. REPA(T)if(T[i].index==index){T[i].weight+=weight; return;}
  43. New().set(index, weight);
  44. }
  45. }
  46. int EditSkeleton::Bone::mainNode()C // get the first node with highest weight
  47. {
  48. int node_i=-1; flt weight;
  49. REPA(T)
  50. {
  51. C IndexWeight &iw=T[i];
  52. if(node_i<0 || iw.weight>weight){node_i=iw.index; weight=iw.weight;}
  53. }
  54. return node_i;
  55. }
  56. bool EditSkeleton::Bone::save(File &f)C {f<<name; return ::EE::Mems< ::EE::IndexWeight>::saveRaw(f);}
  57. bool EditSkeleton::Bone::load(File &f) {f>>name; return ::EE::Mems< ::EE::IndexWeight>::loadRaw(f);}
  58. bool EditSkeleton::Bone::loadOld(File &f) {name=GetStr2(f); return ::EE::Mems< ::EE::IndexWeight>::loadRaw(f);}
  59. uint EditSkeleton::memUsage()C
  60. {
  61. uint mem=0;
  62. REPA(nodes)mem+=nodes[i].memUsage();
  63. REPA(bones)mem+=bones[i].memUsage();
  64. return mem;
  65. }
  66. void EditSkeleton::del()
  67. {
  68. root=-1;
  69. nodes.del();
  70. bones.del();
  71. }
  72. void EditSkeleton::create(C Skeleton &skel, C MemPtr<Str> &node_names)
  73. {
  74. root=-1;
  75. nodes.setNum(skel.bones.elms()); REPA(nodes)
  76. {
  77. Node &node = nodes[i];
  78. C SkelBone &bone =skel.bones[i];
  79. node.name =(InRange(i, node_names) ? node_names[i] : Str(bone.name)); // remember that 'node_names' are allowed to be empty strings
  80. node.parent =skel.boneParent(i);
  81. node.orient_pos=bone;
  82. }
  83. bones.setNum(nodes.elms()); REPAO(bones).init(skel.bones[i].name, i); // have to use 'SkelBone' name
  84. }
  85. void EditSkeleton::set(Skeleton &skel)C
  86. {
  87. skel.del().bones.setNum(nodes.elms()); REPA(nodes)
  88. {
  89. C Node &node= nodes[i];
  90. SkelBone &bone=skel.bones[i];
  91. SCAST(OrientP, bone)=node.orient_pos;
  92. Set(bone.name, TextInt(i));
  93. bone.parent=(InRange(node.parent, skel.bones) ? node.parent : 0xFF);
  94. }
  95. skel.sortBones();
  96. }
  97. void EditSkeleton::set(Mems<Mems<IndexWeight> > &weights, C Skeleton &old_skel, C Skeleton &new_skel, MAPPING mapping)C
  98. {
  99. MemtN<int, 256> node_to_bone; // converts node index to 'old_skel' bone index
  100. if(mapping!=KEEP)
  101. {
  102. node_to_bone.setNum(nodes.elms()); switch(mapping)
  103. {
  104. case BONE_NAME_IS_NODE_INDEX: REPAO(node_to_bone)=old_skel.findBoneI((Str8)TextInt(i) ); break;
  105. case BONE_NAME_IS_NODE_NAME : REPAO(node_to_bone)=old_skel.findBoneI((Str8) nodes[i].name); break;
  106. }
  107. }
  108. weights.setNum(new_skel.bones.elms()); REPA(weights)
  109. {
  110. Mems<IndexWeight> &weight=weights[i];
  111. if(C Bone *bone=findBone(new_skel.bones[i].name))
  112. {
  113. weight=*bone;
  114. if(mapping!=KEEP)REPA(weight)
  115. {
  116. IndexWeight &w=weight[i]; w.index=(InRange(w.index, node_to_bone) ? node_to_bone[w.index] : -1); if(w.index<0)weight.remove(i, true);
  117. }
  118. }else weight.clear();
  119. }
  120. }
  121. Str EditSkeleton::nodeUID(int i)C // unique string identifying a node !! needs to be the same as 'Import.nodeUID' !!
  122. {
  123. Str path; Memt<int> parents; for(; InRange(i, nodes) && parents.include(i); )
  124. {
  125. C Node &node=nodes[i];
  126. path+=node.name; // node name
  127. int parent=node.parent, child_index=0; REPD(j, i)if(nodes[j].parent==parent && nodes[j].name==node.name)child_index++; if(child_index){path+=CharAlpha; path+=child_index;} // node child index in parent (only children with same names are counted)
  128. path+='/'; // separator
  129. i=parent;
  130. }
  131. return path;
  132. }
  133. bool EditSkeleton::rootZero()C {return InRange(root, nodes) && Equal(nodes[root].orient_pos.pos, VecZero);}
  134. bool EditSkeleton::hasNode(C Str &name) {return findNodeI(name)>=0;}
  135. ::EditSkeleton::Node* EditSkeleton::findNode(C Str &name) {return nodes.addr(findNodeI(name));}
  136. C ::EditSkeleton::Node* EditSkeleton::findNode(C Str &name)C {return ConstCast(T).findNode(name);}
  137. int EditSkeleton::findNodeI(C Str &name, C Str &path)C
  138. {
  139. int index=-1, difference=INT_MAX;
  140. REPA(nodes)if(nodes[i].name==name) // always check even if 'name' is empty (because original full name can be empty)
  141. {
  142. int d=Difference(path, nodeUID(i));
  143. if(!d)return i; // exact match
  144. if( d<difference){difference=d; index=i;}
  145. }
  146. return index;
  147. }
  148. int EditSkeleton::findBoneI(C Str &name)C {REPA(bones)if(bones[i].name==name)return i; return -1;}
  149. ::EditSkeleton::Bone* EditSkeleton::findBone(C Str &name) {return bones.addr(findBoneI(name));}
  150. C ::EditSkeleton::Bone* EditSkeleton::findBone(C Str &name)C {return ConstCast(T).findBone(name);}
  151. void EditSkeleton::removeBone(C Str &name) {bones.remove(findBoneI(name), true);}
  152. void EditSkeleton::renameBone(C Str &old_name, C Str &new_name) {if(Bone *bone=findBone(old_name))bone->name=new_name;}
  153. int EditSkeleton::nodeToBone(int node_i)C // will return only direct mapping (if 1 weight and 1 bone link) only
  154. {
  155. int bone_i=-1;
  156. if( node_i>=0)FREPA(bones) // go from the start to find the first parent linked with this node
  157. {
  158. C Bone &bone=bones[i];
  159. FREPAD(w, bone)if(bone[w].index==node_i) // if bone is linked to this node
  160. {
  161. if(bone_i>=0 || bone.elms()!=1)return -1; // we need direct mapping
  162. bone_i=i;
  163. }
  164. }
  165. return bone_i;
  166. }
  167. int EditSkeleton::boneToNode(int bone_i)C // find the first node with highest weight
  168. {
  169. return InRange(bone_i, bones) ? bones[bone_i].mainNode() : -1;
  170. }
  171. int EditSkeleton::boneToNode(C Str &name)C // find the first node with highest weight
  172. {
  173. if(C Bone *bone=findBone(name))return bone->mainNode();
  174. return -1;
  175. }
  176. ::EditSkeleton::Bone* EditSkeleton::getBone(C Str &name)
  177. {
  178. if(name.is())
  179. {
  180. if(Bone *bone=findBone(name))return bone;
  181. Bone &bone=bones.New(); bone.name=name; return &bone;
  182. }
  183. return null;
  184. }
  185. void EditSkeleton::animate(C AnimSkel &anim_skel, C MemPtrN<Matrix, 256> &matrixes)
  186. {
  187. REPAD(n, nodes)
  188. {
  189. OrientP &orient_pos=nodes[n].orient_pos, temp; temp.zero(); bool processed=false;
  190. REPAD(b, bones) // have to iterate all bones to check which are linked to this node
  191. {
  192. C Bone &bone=bones[b]; REPA(bone)if(bone[i].index==n)
  193. {
  194. int anim_bone=anim_skel.findBoneI(bone.name)+1; // +root
  195. if(InRange(anim_bone, matrixes))
  196. {
  197. processed=true;
  198. temp+=(orient_pos*matrixes[anim_bone])*bone[i].weight;
  199. }
  200. }
  201. }
  202. if(processed){temp.fix(); orient_pos=temp;}
  203. }
  204. }
  205. void EditSkeleton::NodePtr::set(int node_i, C EditSkeleton &skel) {if(is=InRange(node_i, skel.nodes))name=skel.nodes[node_i].name;}
  206. void EditSkeleton::add(C EditSkeleton &src_skel, bool replace) // assumes that 'bones' names are unique in both skeletons, but 'nodes' names can overlap
  207. {
  208. if(this==&src_skel)return;
  209. // nodes
  210. Memc<NodePtr> parents; parents.setNum(nodes.elms()); REPAO(parents).set(nodes[i].parent, T); // first set parents of existing nodes
  211. FREPA(src_skel.nodes) // add 'src_skel' nodes in order
  212. {
  213. C Node &src_node =src_skel.nodes[i];
  214. int node_i=findNodeI(src_node.name); // check if that node already exists in this skeleton
  215. if(node_i<0){nodes.add (src_node); parents.New() .set(src_node.parent, src_skel);}else // if not found
  216. if(replace ){nodes[node_i]=src_node ; parents[node_i].set(src_node.parent, src_skel);} // found and replace
  217. }
  218. // add rest after all nodes have been copied
  219. // parents
  220. REPA(parents)nodes[i].parent=(parents[i].is ? findNodeI(parents[i].name) : -1);
  221. // root
  222. if(InRange(src_skel.root, src_skel.nodes) && (replace || root<0))root=findNodeI(src_skel.nodes[src_skel.root].name);
  223. // bones
  224. int offset=bones.addNum(src_skel.bones.elms()); REPA(src_skel.bones)
  225. {
  226. Bone &dest=bones[i+offset]; dest=src_skel.bones[i]; REPA(dest)
  227. {
  228. IndexWeight &weight=dest[i]; if(InRange(weight.index, src_skel.nodes))
  229. {
  230. weight.index=findNodeI(src_skel.nodes[weight.index].name); // find src node in this skeleton
  231. if(weight.index>=0)continue; // if found this node then continue
  232. }
  233. dest.remove(i, true); // for some reason didn't find a node, so remove this weight
  234. }
  235. if(!dest.elms())bones.remove(i+offset, true); // if no weights were found, then remove this bone
  236. }
  237. }
  238. bool EditSkeleton::save(File &f)C
  239. {
  240. f.cmpUIntV(2);
  241. f<<root; nodes.save(f); bones.save(f);
  242. return f.ok();
  243. }
  244. bool EditSkeleton::load(File &f)
  245. {
  246. switch(f.decUIntV())
  247. {
  248. case 2: f>>root; if(nodes.load(f) && bones.load(f) && f.ok())return true; break;
  249. case 1:
  250. {
  251. f>>root;
  252. nodes.setNum(f.decUIntV()); FREPA(nodes)if(!nodes[i].loadOld(f))goto error;
  253. bones.setNum(f.decUIntV()); FREPA(bones)if(!bones[i].loadOld(f))goto error;
  254. if(f.ok())return true;
  255. }break;
  256. case 0:
  257. {
  258. Mems<Bone0> bones0; if(bones0.load(f) && f.ok())
  259. {
  260. del();
  261. nodes.setNum(bones0.elms()); REPA(nodes)
  262. {
  263. nodes[i].name =bones0[i].original_name;
  264. nodes[i].orient_pos=bones0[i].orient_pos;
  265. }
  266. REPAO(nodes).parent=findNodeI(bones0[i].parent_original_name); // get parent after all nodes were set
  267. REPA (bones0)if(bones0[i].dest_name.is())bones.New().init(bones0[i].dest_name, i);
  268. return true;
  269. }
  270. }break;
  271. }
  272. error:
  273. del(); return false;
  274. }
  275. bool EditSkeleton::load(C Str &name)
  276. {
  277. File f; if(f.readTry(name))return load(f);
  278. del(); return false;
  279. }
  280. bool EditSkeleton::Bone0::load(File &f)
  281. {
  282. if(f.decUIntV()==0)
  283. {
  284. original_name=GetStr2(f); dest_name=GetStr2(f); parent_original_name=GetStr2(f); f>>orient_pos;
  285. if(f.ok())return true;
  286. }
  287. return false;
  288. }
  289. EditSkeleton::EditSkeleton() : root(-1) {}
  290. EditSkeleton::Node::Node() : parent(-1) {}
  291. EditSkeleton::NodePtr::NodePtr() : is(false) {}
  292. /******************************************************************************/