Animation.cpp 152 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************
  5. About reusing same animations for different skeletons in a better way (the following has not been tested, it's only an initial idea) :
  6. To be able to achieve "absolute target" animations,
  7. So for example an animation would work the same for 2 different skeletons which:
  8. -one has UpperArm connected properly to ShoulderBone (this parent points to the side)
  9. -2nd has UpperArm connected to Spine, because ShoulderBone is not present (this parent points up)
  10. Most likely we would need to have:
  11. -some sort of Matrix3/Orientation in AnimKeys/AnimBone (just 1 per bone, and not 1 per keyframe), which describes the child<->parent orientation relation for which the animation was created
  12. -bone orn, parent orn, or just bone orn relative to parent orn
  13. -some sort of transform, stored per bone in SkelAnim (which is based on above AnimBone orn and adjusted by SkelBone orn of Skeleton that will actually use this animation and its relation to its parent, basically this transforms from what the animation was created for, to what is it going to be used for)
  14. -use that transform in AnimSkelBone when animating bones by animations:
  15. void Animate(AnimSkelBone &asbon, C AnimKeys &keys, C AnimParamsEx &params)
  16. {
  17. ..
  18. bone_orn+=params.blend*orn; // <- this 'orn' would need to be transformed somehow by the above transform
  19. -if that would be done, then it could be done in such a way, that:
  20. void UpdateBoneMatrix(AnimatedSkeleton &anim_skel, Int i)
  21. {
  22. ..
  23. if(parent)bone_orn.transform(parent_matrix, true); // <- this would not be needed because 'bone_orn' is already transformed correctly above
  24. The downsides of this approach:
  25. -more memory needed:
  26. -storing orn in AnimKeys
  27. -storing orn in SkelAnim
  28. -extra processing needed in "void Animate(AnimSkelBone &asbon, C AnimKeys &keys, C AnimParamsEx &params)"
  29. The benefit of simplified "void UpdateBoneMatrix" is smaller compared to more expensive "void Animate", because:
  30. -Animate is called many times for 1 bone (for each blended animation)
  31. -UpdateBoneMatrix is called 1 time for 1 bone
  32. The extra processing in "Animate" could be removed completely, if entire animation (all keyframes) would be transformed to the target Skeleton,
  33. however in that case we would need to have entire copies of every animation for every skeleton that uses them, so I'm not considering this at all, as that would use too much memory.
  34. Unless a better approach is figured out, I think it's just better to make sure to keep Skeletons similar
  35. (all have shoulder bones, and the same bone orientations, setup using "Adjust Bone Orientations" in the Editor).
  36. ----
  37. Scales Keyframes Limitation,
  38. Currently there is a limitation that if imported a Skeleton with Bones with X Scale,
  39. and then importing Animations having the same Skeleton but some Bones with Y scale,
  40. then scales won't be set correctly, because 'Animation.*adjust*' methods take into account only bone positions and orientations,
  41. but don't do anything about bone scales, since there's no functionality for storing original FBX node matrix scales in Skeleton Bones.
  42. This is noticeable when importing "Weretoad.fbx" (which has scaled tongue sticking out) and then trying to import animations to it (which animations initially have tongue at smaller size).
  43. The solution is to Create a Static / T-Pose / Bind Pose FBX from animation files that have normal scales (for example, import "Weretoad.fbx" into 3ds max, then import "idle" animation on top of that to adjust the mesh, and then export the FBX as new base model).
  44. And finally import that base model, and animations to it.
  45. ----
  46. Animation Bone Names vs Types:
  47. Currently the Editor will always adjust AnimBone.name,type,.. when:
  48. -making any change to the Skeleton linked with the Animation
  49. -changing Skeleton linked with the Animation (this may result in loss of animation bones if target skeleton doesn't have some bones as the source, however it results in better consistency so we don't have any leftover animations not visible with the new skeleton, but could show up in the future when changing to new skeletons)
  50. See also: FIND_ANIM_BY_NAME_ONLY and 'RenameAnimBonesOnSkelChange' in the Editor
  51. /******************************************************************************
  52. struct Rot // Relative Rotation
  53. {
  54. Flt time; // time position (seconds)
  55. AxisRoll rot , // rotation
  56. tan ; // tangent
  57. #if EE_PRIVATE
  58. void save(MemPtr<TextNode> nodes)C; // save text
  59. #endif
  60. };
  61. struct Color // Color
  62. {
  63. Flt time ; // time position (seconds)
  64. Vec4 color, // color value
  65. tan ; // color tangent
  66. #if EE_PRIVATE
  67. void save(MemPtr<TextNode> nodes)C; // save text
  68. #endif
  69. };
  70. Mems<Rot > rots;
  71. Mems<Color> colors;
  72. /******************************************************************************/
  73. #define CC4_ANIM CC4('A','N','I','M')
  74. #define SET_ON_FAIL 1
  75. #define FIND_ANIM_BY_NAME_ONLY 1 // if search for animation bones by bone name only
  76. /******************************************************************************/
  77. Cache<Animation> Animations("Animation");
  78. /******************************************************************************/
  79. void AnimParams::set(C Animation &animation, Flt time) {set(animation.loop(), animation.linear(), animation.length(), time);}
  80. /******************************************************************************/
  81. // ANIMATION KEYS
  82. /******************************************************************************/
  83. Bool AnimKeys::orn(Orient &orn, C AnimParams &params)C
  84. {
  85. switch(orns.elms())
  86. {
  87. case 0: if(SET_ON_FAIL)orn.identity() ; return false;
  88. case 1: first: orn=orns[0].orn; return true;
  89. default:
  90. {
  91. Int l, r; for(l=0, r=orns.elms(); l<r; ){Int mid=UInt(l+r)/2; if(params.time<orns[mid].time)r=mid;else l=mid+1;}
  92. Int prev=l-1, next=l; C Orn *p, *n; Flt step;
  93. if( prev<0) // before first key
  94. {
  95. if(params.loop)
  96. {
  97. prev=orns.elms()-1; // last
  98. p=&orns[prev];
  99. n=&orns[next];
  100. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time + params.length)/length;else goto first;
  101. }else goto first;
  102. }else
  103. if(next==orns.elms()) // after last key
  104. {
  105. if(params.loop)
  106. {
  107. next=0; // first
  108. p=&orns[prev];
  109. n=&orns[next];
  110. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time)/length;else goto last;
  111. }else
  112. {
  113. last:
  114. orn=orns.last().orn; return true;
  115. }
  116. }else
  117. {
  118. p=&orns[prev];
  119. n=&orns[next];
  120. if(Flt length=n->time - p->time)step=(params.time - p->time)/length;else{orn=p->orn; return true;}
  121. }
  122. if(params.linear)
  123. {
  124. orn.dir =Lerp(p->orn.dir , n->orn.dir , step);
  125. orn.perp=Lerp(p->orn.perp, n->orn.perp, step);
  126. }else
  127. {
  128. #if HAS_ANIM_TANGENT
  129. orn.dir =LerpTan(prev->orn.dir , next->orn.dir , step, prev->tan.dir , next->tan.dir );
  130. orn.perp=LerpTan(prev->orn.perp, next->orn.perp, step, prev->tan.perp, next->tan.perp);
  131. #else
  132. C Orn *p2, *n2;
  133. if(params.loop)
  134. {
  135. p2=&orns[(prev-1+orns.elms())%orns.elms()]; if(prev== 0 && Equal(p2->time, p ->time+params.length))p2=&orns[orns.elms()-2];
  136. n2=&orns[(next+1 )%orns.elms()]; if(next==orns.elms()-1 && Equal(n ->time, n2->time+params.length))n2=&orns[ 1];
  137. }else
  138. {
  139. p2=&orns[Max(prev-1, 0)];
  140. n2=&orns[Min(next+1, orns.elms()-1)];
  141. }
  142. orn.dir =Lerp4(p2->orn.dir , p->orn.dir , n->orn.dir , n2->orn.dir , step);
  143. orn.perp=Lerp4(p2->orn.perp, p->orn.perp, n->orn.perp, n2->orn.perp, step);
  144. #endif
  145. }
  146. orn.fix();
  147. }return true;
  148. }
  149. }
  150. Bool AnimKeys::pos(Vec &pos, C AnimParams &params)C
  151. {
  152. switch(poss.elms())
  153. {
  154. case 0: if(SET_ON_FAIL)pos.zero() ; return false;
  155. case 1: first: pos=poss[0].pos; return true;
  156. default:
  157. {
  158. Int l, r; for(l=0, r=poss.elms(); l<r; ){Int mid=UInt(l+r)/2; if(params.time<poss[mid].time)r=mid;else l=mid+1;}
  159. Int prev=l-1, next=l; C Pos *p, *n; Flt step;
  160. if( prev<0) // before first key
  161. {
  162. if(params.loop)
  163. {
  164. prev=poss.elms()-1; // last
  165. p=&poss[prev];
  166. n=&poss[next];
  167. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time + params.length)/length;else goto first;
  168. }else goto first;
  169. }else
  170. if(next==poss.elms()) // after last key
  171. {
  172. if(params.loop)
  173. {
  174. next=0; // first
  175. p=&poss[prev];
  176. n=&poss[next];
  177. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time)/length;else goto last;
  178. }else
  179. {
  180. last:
  181. pos=poss.last().pos; return true;
  182. }
  183. }else
  184. {
  185. p=&poss[prev];
  186. n=&poss[next];
  187. if(Flt length=n->time - p->time)step=(params.time - p->time)/length;else{pos=p->pos; return true;}
  188. }
  189. if(params.linear)pos=Lerp(p->pos, n->pos, step);else
  190. {
  191. #if HAS_ANIM_TANGENT
  192. pos=LerpTan(prev->pos, next->pos, step, prev->tan, next->tan);
  193. #else
  194. C Pos *p2, *n2;
  195. if(params.loop)
  196. {
  197. p2=&poss[(prev-1+poss.elms())%poss.elms()]; if(prev== 0 && Equal(p2->time, p ->time+params.length))p2=&poss[poss.elms()-2];
  198. n2=&poss[(next+1 )%poss.elms()]; if(next==poss.elms()-1 && Equal(n ->time, n2->time+params.length))n2=&poss[ 1];
  199. }else
  200. {
  201. p2=&poss[Max(prev-1, 0)];
  202. n2=&poss[Min(next+1, poss.elms()-1)];
  203. }
  204. pos=Lerp4(p2->pos, p->pos, n->pos, n2->pos, step);
  205. #endif
  206. }
  207. }return true;
  208. }
  209. }
  210. Bool AnimKeys::scale(Vec &scale, C AnimParams &params)C
  211. {
  212. switch(scales.elms())
  213. {
  214. case 0: if(SET_ON_FAIL)scale.zero() ; return false;
  215. case 1: first: scale=scales[0].scale; return true;
  216. default:
  217. {
  218. Int l, r; for(l=0, r=scales.elms(); l<r; ){Int mid=UInt(l+r)/2; if(params.time<scales[mid].time)r=mid;else l=mid+1;}
  219. Int prev=l-1, next=l; C Scale *p, *n; Flt step;
  220. if( prev<0) // before first key
  221. {
  222. if(params.loop)
  223. {
  224. prev=scales.elms()-1; // last
  225. p=&scales[prev];
  226. n=&scales[next];
  227. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time + params.length)/length;else goto first;
  228. }else goto first;
  229. }else
  230. if(next==scales.elms()) // after last key
  231. {
  232. if(params.loop)
  233. {
  234. next=0; // first
  235. p=&scales[prev];
  236. n=&scales[next];
  237. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time)/length;else goto last;
  238. }else
  239. {
  240. last:
  241. scale=scales.last().scale; return true;
  242. }
  243. }else
  244. {
  245. p=&scales[prev];
  246. n=&scales[next];
  247. if(Flt length=n->time - p->time)step=(params.time - p->time)/length;else{scale=p->scale; return true;}
  248. }
  249. if(params.linear)scale=Lerp(p->scale, n->scale, step);else
  250. {
  251. #if HAS_ANIM_TANGENT
  252. scale=LerpTan(prev->scale, next->scale, step, prev->tan, next->tan);
  253. #else
  254. C Scale *p2, *n2;
  255. if(params.loop)
  256. {
  257. p2=&scales[(prev-1+scales.elms())%scales.elms()]; if(prev== 0 && Equal(p2->time, p ->time+params.length))p2=&scales[scales.elms()-2];
  258. n2=&scales[(next+1 )%scales.elms()]; if(next==scales.elms()-1 && Equal(n ->time, n2->time+params.length))n2=&scales[ 1];
  259. }else
  260. {
  261. p2=&scales[Max(prev-1, 0)];
  262. n2=&scales[Min(next+1, scales.elms()-1)];
  263. }
  264. scale=Lerp4(p2->scale, p->scale, n->scale, n2->scale, step);
  265. #endif
  266. }
  267. }return true;
  268. }
  269. }
  270. #if HAS_ANIM_ROT
  271. Bool AnimKeys::rot(AxisRoll &rot, C AnimParams &params)C
  272. {
  273. switch(rots.elms())
  274. {
  275. case 0: if(SET_ON_FAIL)rot.zero() ; return false;
  276. case 1: first: rot=rots[0].rot; return true;
  277. default:
  278. {
  279. Int l, r; for(l=0, r=rots.elms(); l<r; ){Int mid=UInt(l+r)/2; if(params.time<rots[mid].time)r=mid;else l=mid+1;}
  280. Int prev=l-1, next=l; C Rot *p, *n; Flt step;
  281. if( prev<0) // before first key
  282. {
  283. if(params.loop)
  284. {
  285. prev=rots.elms()-1; // last
  286. p=&rots[prev];
  287. n=&rots[next];
  288. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time + params.length)/length;else goto first;
  289. }else goto first;
  290. }else
  291. if(next==rots.elms()) // after last key
  292. {
  293. if(params.loop)
  294. {
  295. next=0; // first
  296. p=&rots[prev];
  297. n=&rots[next];
  298. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time)/length;else goto last;
  299. }else
  300. {
  301. last:
  302. rot=rots.last().rot; return true;
  303. }
  304. }else
  305. {
  306. p=&rots[prev];
  307. n=&rots[next];
  308. if(Flt length=n->time - p->time)step=(params.time - p->time)/length;else{rot=p->rot; return true;}
  309. }
  310. if(params.linear)rot.v4()=Lerp(p->rot.v4(), n->rot.v4(), step);else
  311. {
  312. #if HAS_ANIM_TANGENT
  313. rot.v4()=LerpTan(prev->rot.v4(), next->rot.v4(), step, prev->tan.v4(), next->tan.v4());
  314. #else
  315. C Rot *p2, *n2;
  316. if(params.loop)
  317. {
  318. p2=&rots[(prev-1+rots.elms())%rots.elms()]; if(prev== 0 && Equal(p2->time, p ->time+params.length))p2=&rots[rots.elms()-2];
  319. n2=&rots[(next+1 )%rots.elms()]; if(next==rots.elms()-1 && Equal(n ->time, n2->time+params.length))n2=&rots[ 1];
  320. }else
  321. {
  322. p2=&rots[Max(prev-1, 0)];
  323. n2=&rots[Min(next+1, rots.elms()-1)];
  324. }
  325. rot.v4()=Lerp4(p2->rot.v4(), p->rot.v4(), n->rot.v4(), n2->rot.v4(), step);
  326. #endif
  327. }
  328. }return true;
  329. }
  330. }
  331. #endif
  332. #if HAS_ANIM_COLOR
  333. Bool AnimKeys::color(Vec4 &color, C AnimParams &params)C
  334. {
  335. switch(colors.elms())
  336. {
  337. case 0: if(SET_ON_FAIL)color=1 ; return false;
  338. case 1: first: color=colors[0].color; return true;
  339. default:
  340. {
  341. Int l, r; for(l=0, r=colors.elms(); l<r; ){Int mid=UInt(l+r)/2; if(params.time<colors[mid].time)r=mid;else l=mid+1;}
  342. Int prev=l-1, next=l; C Color *p, *n; Flt step;
  343. if( prev<0) // before first key
  344. {
  345. if(params.loop)
  346. {
  347. prev=colors.elms()-1; // last
  348. p=&colors[prev];
  349. n=&colors[next];
  350. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time + params.length)/length;else goto first;
  351. }else goto first;
  352. }else
  353. if(next==colors.elms()) // after last key
  354. {
  355. if(params.loop)
  356. {
  357. next=0; // first
  358. p=&colors[prev];
  359. n=&colors[next];
  360. if(Flt length=params.length - p->time + n->time)step=(params.time - p->time)/length;else goto last;
  361. }else
  362. {
  363. last:
  364. color=colors.last().color; return true;
  365. }
  366. }else
  367. {
  368. p=&colors[prev];
  369. n=&colors[next];
  370. if(Flt length=n->time - p->time)step=(params.time - p->time)/length;else{color=p->color; return true;}
  371. }
  372. if(params.linear)color=Lerp(p->color, n->color, step);else
  373. {
  374. #if HAS_ANIM_TANGENT
  375. color=LerpTan(prev->color, next->color, step, prev->tan, next->tan);
  376. #else
  377. C Color *p2, *n2;
  378. if(params.loop)
  379. {
  380. p2=&colors[(prev-1+colors.elms())%colors.elms()]; if(prev== 0 && Equal(p2->time, p ->time+params.length))p2=&colors[colors.elms()-2];
  381. n2=&colors[(next+1 )%colors.elms()]; if(next==colors.elms()-1 && Equal(n ->time, n2->time+params.length))n2=&colors[ 1];
  382. }else
  383. {
  384. p2=&colors[Max(prev-1, 0)];
  385. n2=&colors[Min(next+1, colors.elms()-1)];
  386. }
  387. color=Lerp4(p2->color, p->color, n->color, n2->color, step);
  388. #endif
  389. }
  390. }return true;
  391. }
  392. }
  393. #endif
  394. void AnimKeys::Orn::save(MemPtr<TextNode> nodes)C
  395. {
  396. nodes.New().set("time" , time );
  397. nodes.New().set("orn.dir" , orn.dir );
  398. nodes.New().set("orn.perp", orn.perp);
  399. #if HAS_ANIM_TANGENT
  400. nodes.New().set("tan.dir" , tan.dir );
  401. nodes.New().set("tan.perp", tan.perp);
  402. #endif
  403. }
  404. void AnimKeys::Pos::save(MemPtr<TextNode> nodes)C
  405. {
  406. nodes.New().set("time", time);
  407. nodes.New().set("pos" , pos );
  408. #if HAS_ANIM_TANGENT
  409. nodes.New().set("tan" , tan );
  410. #endif
  411. }
  412. void AnimKeys::Scale::save(MemPtr<TextNode> nodes)C
  413. {
  414. nodes.New().set("time" , time );
  415. nodes.New().set("scale", scale);
  416. #if HAS_ANIM_TANGENT
  417. nodes.New().set("tan" , tan );
  418. #endif
  419. }
  420. #if HAS_ANIM_ROT
  421. void AnimKeys::Rot::save(MemPtr<TextNode> nodes)C
  422. {
  423. nodes.New().set("time" , time );
  424. nodes.New().set("rot.axis", rot.axis);
  425. nodes.New().set("rot.roll", rot.roll);
  426. #if HAS_ANIM_TANGENT
  427. nodes.New().set("tan.axis", tan.axis);
  428. nodes.New().set("tan.roll", tan.roll);
  429. #endif
  430. }
  431. #endif
  432. #if HAS_ANIM_COLOR
  433. void AnimKeys::Color::save(MemPtr<TextNode> nodes)C
  434. {
  435. nodes.New().set("time" , time );
  436. nodes.New().set("color", color);
  437. #if HAS_ANIM_TANGENT
  438. nodes.New().set("tan" , tan );
  439. #endif
  440. }
  441. #endif
  442. /******************************************************************************/
  443. AnimKeys& AnimKeys::del()
  444. {
  445. orns .del();
  446. poss .del();
  447. scales.del();
  448. #if HAS_ANIM_ROT
  449. rots .del();
  450. #endif
  451. #if HAS_ANIM_COLOR
  452. colors.del();
  453. #endif
  454. return T;
  455. }
  456. /******************************************************************************/
  457. Bool AnimKeys::timeRange(Flt &min, Flt &max)C
  458. {
  459. if(!is()){min=max=0; return false;}
  460. min= FLT_MAX;
  461. max=-FLT_MAX;
  462. REPA(orns ){Flt t=orns [i].time; MIN(min, t); MAX(max, t);}
  463. REPA(poss ){Flt t=poss [i].time; MIN(min, t); MAX(max, t);}
  464. REPA(scales){Flt t=scales[i].time; MIN(min, t); MAX(max, t);}
  465. #if HAS_ANIM_ROT
  466. REPA(rots ){Flt t=rots [i].time; MIN(min, t); MAX(max, t);}
  467. #endif
  468. #if HAS_ANIM_COLOR
  469. REPA(colors){Flt t=colors[i].time; MIN(min, t); MAX(max, t);}
  470. #endif
  471. return true;
  472. }
  473. AnimKeys& AnimKeys::scale(Flt scale)
  474. {
  475. REPA(poss)
  476. {
  477. Pos &pos=T.poss[i]; pos.pos*=scale;
  478. #if HAS_ANIM_TANGENT
  479. pos.tan*=scale;
  480. #endif
  481. }
  482. return T;
  483. }
  484. AnimKeys& AnimKeys::mirrorX()
  485. {
  486. REPA(orns)
  487. {
  488. Orn &orn=T.orns[i]; orn.orn.mirrorX();
  489. #if HAS_ANIM_TANGENT
  490. orn.tan.mirrorX();
  491. #endif
  492. }
  493. REPA(poss)
  494. {
  495. Pos &pos=T.poss[i]; CHS(pos.pos.x);
  496. #if HAS_ANIM_TANGENT
  497. CHS(pos.tan.x);
  498. #endif
  499. }
  500. #if HAS_ANIM_ROT
  501. REPA(rots)
  502. {
  503. Rot &rot=T.rots[i]; CHS(rot.rot.axis.y); CHS(rot.rot.axis.z); CHS(rot.rot.roll);
  504. #if HAS_ANIM_TANGENT
  505. CHS(rot.tan.axis.y); CHS(rot.tan.axis.z); CHS(rot.tan.roll);
  506. #endif
  507. }
  508. #endif
  509. return T;
  510. }
  511. AnimKeys& AnimKeys::transform(C Matrix3 &matrix) // assumes that 'matrix' is normalized
  512. {
  513. REPA(orns)
  514. {
  515. Orn &orn=T.orns[i]; orn.orn.mul(matrix, true);
  516. #if HAS_ANIM_TANGENT
  517. orn.tan.mul(matrix, true);
  518. #endif
  519. }
  520. REPA(poss)
  521. {
  522. Pos &pos=T.poss[i]; pos.pos*=matrix;
  523. #if HAS_ANIM_TANGENT
  524. pos.tan*=matrix;
  525. #endif
  526. }
  527. #if HAS_ANIM_ROT
  528. REPA(rots)
  529. {
  530. Rot &rot=T.rots[i]; rot.rot*=matrix;
  531. #if HAS_ANIM_TANGENT
  532. rot.tan*=matrix;
  533. #endif
  534. }
  535. #endif
  536. return T;
  537. }
  538. /******************************************************************************/
  539. static Int Compare(C AnimKeys::Orn &k0, C AnimKeys::Orn &k1) {return Compare(k0.time, k1.time);}
  540. static Int Compare(C AnimKeys::Pos &k0, C AnimKeys::Pos &k1) {return Compare(k0.time, k1.time);}
  541. static Int Compare(C AnimKeys::Scale &k0, C AnimKeys::Scale &k1) {return Compare(k0.time, k1.time);}
  542. #if HAS_ANIM_ROT
  543. static Int Compare(C AnimKeys::Rot &k0, C AnimKeys::Rot &k1) {return Compare(k0.time, k1.time);}
  544. #endif
  545. #if HAS_ANIM_COLOR
  546. static Int Compare(C AnimKeys::Color &k0, C AnimKeys::Color &k1) {return Compare(k0.time, k1.time);}
  547. #endif
  548. AnimKeys& AnimKeys::sortFrames()
  549. {
  550. orns .sort(Compare);
  551. poss .sort(Compare);
  552. scales.sort(Compare);
  553. #if HAS_ANIM_ROT
  554. rots .sort(Compare);
  555. #endif
  556. #if HAS_ANIM_COLOR
  557. colors.sort(Compare);
  558. #endif
  559. return T;
  560. }
  561. struct TimeScaleClip
  562. {
  563. Flt scale, length, length_eps;
  564. TimeScaleClip(Flt scale, Flt length)
  565. {
  566. T.scale =scale;
  567. T.length =length;
  568. T.length_eps=length-EPS;
  569. }
  570. void adjust(Flt &time)C
  571. {
  572. Flt t=time*scale;
  573. if(t>length_eps)t=length; // align to end, because looped root motion is calculated at time=0 and time=length, so if times are slightly offsetted, we could get root motion start that is actually end
  574. time=t;
  575. }
  576. };
  577. AnimKeys& AnimKeys::scaleTime(Flt scale, Flt anim_length)
  578. {
  579. TimeScaleClip tsc(scale, anim_length);
  580. REPA(orns )tsc.adjust(orns [i].time);
  581. REPA(poss )tsc.adjust(poss [i].time);
  582. REPA(scales)tsc.adjust(scales[i].time);
  583. #if HAS_ANIM_ROT
  584. REPA(rots )tsc.adjust(rots [i].time);
  585. #endif
  586. #if HAS_ANIM_COLOR
  587. REPA(colors)tsc.adjust(colors[i].time);
  588. #endif
  589. return T;
  590. }
  591. AnimKeys& AnimKeys::slideTime(Flt dt, Flt anim_length)
  592. {
  593. REPAO(orns ).time=Frac(orns [i].time+dt, anim_length);
  594. REPAO(poss ).time=Frac(poss [i].time+dt, anim_length);
  595. REPAO(scales).time=Frac(scales[i].time+dt, anim_length);
  596. #if HAS_ANIM_ROT
  597. REPAO(rots ).time=Frac(rots [i].time+dt, anim_length);
  598. #endif
  599. #if HAS_ANIM_COLOR
  600. REPAO(colors).time=Frac(colors[i].time+dt, anim_length);
  601. #endif
  602. return sortFrames();
  603. }
  604. AnimKeys& AnimKeys::reverse(Flt anim_length)
  605. {
  606. REPA(orns)
  607. {
  608. Orn &orn=orns[i]; orn.time=anim_length-orn.time;
  609. #if HAS_ANIM_TANGENT
  610. orn.tan.chs();
  611. #endif
  612. }
  613. orns.reverseOrder();
  614. REPA(poss)
  615. {
  616. Pos &pos=poss[i]; pos.time=anim_length-pos.time;
  617. #if HAS_ANIM_TANGENT
  618. pos.tan.chs();
  619. #endif
  620. }
  621. poss.reverseOrder();
  622. REPA(scales)
  623. {
  624. Scale &scale=scales[i]; scale.time=anim_length-scale.time;
  625. #if HAS_ANIM_TANGENT
  626. scale.tan.chs();
  627. #endif
  628. }
  629. scales.reverseOrder();
  630. #if HAS_ANIM_ROT
  631. REPA(rots)
  632. {
  633. Rot &rot=rots[i]; rot.time=anim_length-rot.time;
  634. #if HAS_ANIM_TANGENT
  635. rot.tan.v4().chs();
  636. #endif
  637. }
  638. rots.reverseOrder();
  639. #endif
  640. #if HAS_ANIM_COLOR
  641. REPA(colors)
  642. {
  643. Color &color=colors[i]; color.time=anim_length-color.time;
  644. #if HAS_ANIM_TANGENT
  645. color.tan.chs();
  646. #endif
  647. }
  648. colors.reverseOrder();
  649. #endif
  650. return T;
  651. }
  652. AnimKeys& AnimKeys::setTangents(Bool anim_loop, Flt anim_length)
  653. {
  654. #if HAS_ANIM_TANGENT
  655. REPA(orns)
  656. {
  657. Int prev=i-1,
  658. next=i+1;
  659. if(prev==-1 ){if(anim_loop){prev+=orns.elms(); if(Equal(orns[ i].time, 0) && Equal(orns[prev].time, anim_length))prev--;}}
  660. if(next==orns.elms()){if(anim_loop){next-=orns.elms(); if(Equal(orns[next].time, 0) && Equal(orns[ i].time, anim_length))next++;}else next=-1;}
  661. if(InRange(prev, orns) && InRange(next, orns))
  662. {
  663. orns[i].tan.dir =GetTangentDir(orns[prev].orn.dir , orns[next].orn.dir );
  664. orns[i].tan.perp=GetTangentDir(orns[prev].orn.perp, orns[next].orn.perp);
  665. }else orns[i].tan.zero();
  666. }
  667. REPA(poss)
  668. {
  669. Int prev=i-1,
  670. next=i+1;
  671. if(prev==-1 ){if(anim_loop){prev+=poss.elms(); if(Equal(poss[ i].time, 0) && Equal(poss[prev].time, anim_length))prev--;}}
  672. if(next==poss.elms()){if(anim_loop){next-=poss.elms(); if(Equal(poss[next].time, 0) && Equal(poss[ i].time, anim_length))next++;}else next=-1;}
  673. #if 1
  674. if(InRange(prev, poss) && InRange(next, poss))poss[i].tan=GetTangent(poss[prev].pos, poss[i].pos, poss[next].pos); // this gives better results for circular movement
  675. #else
  676. if(InRange(prev, poss) && InRange(next, poss))poss[i].tan=GetTangent(poss[prev].pos , poss[next].pos);
  677. #endif
  678. else poss[i].tan.zero();
  679. }
  680. REPA(scales)
  681. {
  682. Int prev=i-1,
  683. next=i+1;
  684. if(prev==-1 ){if(anim_loop){prev+=scales.elms(); if(Equal(scales[ i].time, 0) && Equal(scales[prev].time, anim_length))prev--;}}
  685. if(next==scales.elms()){if(anim_loop){next-=scales.elms(); if(Equal(scales[next].time, 0) && Equal(scales[ i].time, anim_length))next++;}else next=-1;}
  686. if(InRange(prev, scales) && InRange(next, scales))scales[i].tan=GetTangent(scales[prev].scale, scales[next].scale);
  687. else scales[i].tan.zero();
  688. }
  689. #if HAS_ANIM_ROT
  690. REPA(rots)
  691. {
  692. Int prev=i-1,
  693. next=i+1;
  694. if(prev==-1 ){if(anim_loop){prev+=rots.elms(); if(Equal(rots[ i].time, 0) && Equal(rots[prev].time, anim_length))prev--;}}
  695. if(next==rots.elms()){if(anim_loop){next-=rots.elms(); if(Equal(rots[next].time, 0) && Equal(rots[ i].time, anim_length))next++;}else next=-1;}
  696. if(InRange(prev, rots) && InRange(next, rots))rots[i].tan.v4()=GetTangent(rots[prev].rot.v4(), rots[next].rot.v4());
  697. else rots[i].tan.zero();
  698. }
  699. #endif
  700. #if HAS_ANIM_COLOR
  701. REPA(colors)
  702. {
  703. Int prev=i-1,
  704. next=i+1;
  705. if(prev==-1 ){if(anim_loop){prev+=colors.elms(); if(Equal(colors[ i].time, 0) && Equal(colors[prev].time, anim_length))prev--;}}
  706. if(next==colors.elms()){if(anim_loop){next-=colors.elms(); if(Equal(colors[next].time, 0) && Equal(colors[ i].time, anim_length))next++;}else next=-1;}
  707. if(InRange(prev, colors) && InRange(next, colors))colors[i].tan=GetTangent(colors[prev].color, colors[next].color);
  708. else colors[i].tan.zero();
  709. }
  710. #endif
  711. #endif
  712. return T;
  713. }
  714. /******************************************************************************/
  715. static Flt MinDotBetween(C Orient &a, C Orient &b) // this operates on 'Min' because the same vectors will give Dot=1, going down to -1 for vectors having some angle between them
  716. {
  717. return Min(Dot(a.dir, b.dir), Dot(a.perp, b.perp));
  718. }
  719. static Flt MaxAbsAngleBetween(C Orient &a, C Orient &b)
  720. {
  721. return Max(AbsAngleBetweenN(a.dir, b.dir), AbsAngleBetweenN(a.perp, b.perp));
  722. }
  723. static Flt MaxAbsAngleBetween(C AxisRoll &a, C AxisRoll &b)
  724. {
  725. return Dist(a.axis, b.axis) + Abs(a.roll-b.roll);
  726. }
  727. static Flt MaxAbsDelta(C Vec &a, C Vec &b)
  728. {
  729. return Abs(a-b).max();
  730. }
  731. static Flt MaxAbsDelta(C Vec4 &a, C Vec4 &b)
  732. {
  733. return Abs(a-b).max();
  734. }
  735. static Int Index(Int i, Bool loop, Int elms)
  736. {
  737. return loop ? Mod(i, elms) : Mid(i, 0, elms-1);
  738. }
  739. static Int Index(Int i, Bool loop, Int elms, Int ignore) // this assumes that "elms>=2" and "InRange(ignore, elms)"
  740. {
  741. if(i>ignore)i--;
  742. i=(loop ? Mod(i, elms-1) : Mid(i, 0, elms-2)); // add extra -1 to 'elms' because we need it for 'ignore'
  743. if(i>=ignore)i++;
  744. return i;
  745. }
  746. static Flt AfterTime(Flt time, Flt base, Flt length)
  747. {
  748. return (time>=base) ? time : time+length;
  749. }
  750. AnimKeys& AnimKeys::optimize(Bool anim_loop, Bool anim_linear, Flt anim_length, Flt angle_eps, Flt pos_eps, Flt scale_eps, C Orient *bone, C Orient *bone_parent)
  751. {
  752. AnimParams anim_params(anim_loop, anim_linear, anim_length, 0);
  753. Memt<Int> optimized; // indexes to original elements
  754. // orientation
  755. if(angle_eps>=0)
  756. {
  757. #define USE_DOT 1 // calculating Dot is faster than the angle
  758. #if USE_DOT
  759. Flt dot_eps=Cos(angle_eps);
  760. #endif
  761. optimized.setNum(orns.elms()); REPAO(optimized)=i;
  762. REPA(optimized)if(optimized.elms()>=2)
  763. {
  764. Int prev2=optimized[Index(i-2, anim_loop, optimized.elms(), i)],
  765. prev =optimized[Index(i-1, anim_loop, optimized.elms(), i)],
  766. next =optimized[Index(i+1, anim_loop, optimized.elms(), i)],
  767. next2=optimized[Index(i+2, anim_loop, optimized.elms(), i)],
  768. stop =(InRange(i+1, optimized) ? optimized[Min(i+(anim_linear ? 1 : 2), optimized.elms()-1)] : orns.elms()); // stop on the next key that wasn't removed (for non-linear use 2nd next key)
  769. C Orn *p=&orns[prev], *n=&orns[next], *p2=&orns[prev2], *n2=&orns[next2];
  770. Flt n_time=AfterTime(n->time, p->time, anim_length);
  771. Orient test;
  772. // check between this and previous key (this is extra important for orientations)
  773. if(!anim_linear)
  774. {
  775. C Orn &orn=orns[i];
  776. Flt prev_time=(InRange(i-1, orns) ? orns[i-1].time : anim_loop ? orns.last().time-anim_length : 0);
  777. if(!Equal(prev_time, orn.time)) // if times are the same then we don't need to do the following (this can happen when first key is at the start of anim and (it's not looped or the last key is at the end))
  778. {
  779. anim_params.time=Avg(prev_time, orn.time); // set time between previous and this key from the source
  780. // calculate source orn
  781. Int src_prev=Index(i-1, anim_loop, orns.elms()),
  782. src_next=i; // here 'i' is included
  783. Orient orn;
  784. C Orn &src_p=orns[src_prev], &src_n=orns[src_next];
  785. Flt step =0.5f; // here for source, step is always 0.5, because we want to test between keys
  786. #if HAS_ANIM_TANGENT
  787. orn.dir =LerpTan(src_p.orn.dir , src_n.orn.dir , step, src_p.tan.dir , src_n.tan.dir );
  788. orn.perp=LerpTan(src_p.orn.perp, src_n.orn.perp, step, src_p.tan.perp, src_n.tan.perp);
  789. #else
  790. Int src_prev2=Index(i-2, anim_loop, orns.elms()),
  791. src_next2=Index(i+1, anim_loop, orns.elms());
  792. C Orn &src_p2=orns[src_prev2], &src_n2=orns[src_next2];
  793. orn.dir =Lerp4(src_p2.orn.dir , src_p.orn.dir , src_n.orn.dir , src_n2.orn.dir , step);
  794. orn.perp=Lerp4(src_p2.orn.perp, src_p.orn.perp, src_n.orn.perp, src_n2.orn.perp, step);
  795. #endif
  796. orn.fix();
  797. // calculate optimized orn
  798. step=LerpRS(p->time, n_time, AfterTime(anim_params.time, p->time, anim_length)); // use Sat in case orn.time is outside of range, or 'p' has the same time as 'n'
  799. #if HAS_ANIM_TANGENT
  800. test.dir =LerpTan(p->orn.dir , n->orn.dir , step, GetTangentDir(p2->orn.dir , n->orn.dir ), GetTangentDir(p->orn.dir , n2->orn.dir ));
  801. test.perp=LerpTan(p->orn.perp, n->orn.perp, step, GetTangentDir(p2->orn.perp, n->orn.perp), GetTangentDir(p->orn.perp, n2->orn.perp));
  802. #else
  803. test.dir =Lerp4(p2->orn.dir , p->orn.dir , n->orn.dir , n2->orn.dir , step);
  804. test.perp=Lerp4(p2->orn.perp, p->orn.perp, n->orn.perp, n2->orn.perp, step);
  805. #endif
  806. test.fix();
  807. #if USE_DOT
  808. if(MinDotBetween (test, orn)< dot_eps)goto orn_needed;
  809. #else
  810. if(MaxAbsAngleBetween(test, orn)>angle_eps)goto orn_needed;
  811. #endif
  812. }
  813. }
  814. for(Int src=i, i_next=i+3; ; ) // check that all removed keyframes (including this) do not deviate, start from the left because below we're checking if we've reached the next index, we need to go only to the right, because to the left no keys have been removed yet
  815. {
  816. C Orn &orn=orns[src];
  817. #if HAS_ANIM_TANGENT
  818. Orient tan[2];
  819. if(!anim_linear)
  820. {
  821. tan[0].dir=GetTangentDir(p2->orn.dir, n ->orn.dir); tan[0].perp=GetTangentDir(p2->orn.perp, n ->orn.perp);
  822. tan[1].dir=GetTangentDir(p ->orn.dir, n2->orn.dir); tan[1].perp=GetTangentDir(p ->orn.perp, n2->orn.perp);
  823. }
  824. #endif
  825. // check at key location
  826. if(src!=prev) // no need to check time where both source and optimized have a keyframe
  827. {
  828. Flt step=LerpRS(p->time, n_time, AfterTime(orn.time, p->time, anim_length)); // use Sat in case orn.time is outside of range, or 'p' has the same time as 'n'
  829. if(anim_linear)
  830. {
  831. test.dir =Lerp(p->orn.dir , n->orn.dir , step);
  832. test.perp=Lerp(p->orn.perp, n->orn.perp, step);
  833. }else
  834. {
  835. #if HAS_ANIM_TANGENT
  836. test.dir =LerpTan(p->orn.dir , n->orn.dir , step, tan[0].dir , tan[1].dir );
  837. test.perp=LerpTan(p->orn.perp, n->orn.perp, step, tan[0].perp, tan[1].perp);
  838. #else
  839. test.dir =Lerp4(p2->orn.dir , p->orn.dir , n->orn.dir , n2->orn.dir , step);
  840. test.perp=Lerp4(p2->orn.perp, p->orn.perp, n->orn.perp, n2->orn.perp, step);
  841. #endif
  842. }
  843. test.fix();
  844. #if USE_DOT
  845. if(MinDotBetween (test, orn.orn)< dot_eps)goto orn_needed;
  846. #else
  847. if(MaxAbsAngleBetween(test, orn.orn)>angle_eps)goto orn_needed;
  848. #endif
  849. }
  850. // check between keys
  851. if(!anim_linear) // for cubic interpolation we need to check between keys, because due to cubic interpolation the values can get way off
  852. {
  853. Flt next_time=(InRange(src+1, orns) ? orns[src+1].time : anim_loop ? orns[0].time+anim_length : anim_length);
  854. if(!Equal(orn.time, next_time)) // if times are the same then we don't need to do the following (this can happen when last key is at the end of anim and (it's not looped or the first key is at the start))
  855. {
  856. anim_params.time=Avg(orn.time, next_time); // set time between this and next key from the source
  857. Orient orn; T.orn(orn, anim_params);
  858. Flt step=LerpRS(p->time, n_time, AfterTime(anim_params.time, p->time, anim_length)); // use Sat in case orn.time is outside of range, or 'p' has the same time as 'n'
  859. #if HAS_ANIM_TANGENT
  860. test.dir =LerpTan(p->orn.dir , n->orn.dir , step, tan[0].dir , tan[1].dir );
  861. test.perp=LerpTan(p->orn.perp, n->orn.perp, step, tan[0].perp, tan[1].perp);
  862. #else
  863. test.dir =Lerp4(p2->orn.dir , p->orn.dir , n->orn.dir , n2->orn.dir , step);
  864. test.perp=Lerp4(p2->orn.perp, p->orn.perp, n->orn.perp, n2->orn.perp, step);
  865. #endif
  866. test.fix();
  867. #if USE_DOT
  868. if(MinDotBetween (test, orn)< dot_eps)goto orn_needed;
  869. #else
  870. if(MaxAbsAngleBetween(test, orn)>angle_eps)goto orn_needed;
  871. #endif
  872. }
  873. }
  874. if(++src>=stop)break;
  875. if(src==next) // remember that 'next' can be wrapped due to looping, so use == for safety
  876. {
  877. prev2=prev; prev=next; next=next2; next2=optimized[Index(i_next++, anim_loop, optimized.elms(), i)];
  878. p=&orns[prev]; n=&orns[next]; p2=&orns[prev2]; n2=&orns[next2];
  879. n_time=AfterTime(n->time, p->time, anim_length);
  880. }
  881. }
  882. optimized.remove(i, true);
  883. orn_needed:;
  884. }
  885. if(optimized.elms()==1 && bone) // be careful when removing the only 'orn' keyframe even if it's an identity, because it may be needed for correct multi-animation blending
  886. {
  887. Orient identity=GetAnimOrient(*bone, bone_parent);
  888. #if USE_DOT
  889. if(MinDotBetween (identity, orns[optimized[0]].orn)>= dot_eps)optimized.clear();
  890. #else
  891. if(MaxAbsAngleBetween(identity, orns[optimized[0]].orn)<=angle_eps)optimized.clear();
  892. #endif
  893. }
  894. if(optimized.elms()!=orns.elms()){Mems<Orn> temp; temp.setNum(optimized.elms()); REPAO(temp)=orns[optimized[i]]; Swap(temp, orns);}
  895. }
  896. // position
  897. if(pos_eps>=0)
  898. {
  899. pos_eps*=pos_eps; // make square
  900. optimized.setNum(poss.elms()); REPAO(optimized)=i;
  901. REPA(optimized)if(optimized.elms()>=2)
  902. {
  903. Int prev2=optimized[Index(i-2, anim_loop, optimized.elms(), i)],
  904. prev =optimized[Index(i-1, anim_loop, optimized.elms(), i)],
  905. next =optimized[Index(i+1, anim_loop, optimized.elms(), i)],
  906. next2=optimized[Index(i+2, anim_loop, optimized.elms(), i)],
  907. stop =(InRange(i+1, optimized) ? optimized[Min(i+(anim_linear ? 1 : 2), optimized.elms()-1)] : poss.elms()); // stop on the next key that wasn't removed (for non-linear use 2nd next key)
  908. C Pos *p=&poss[prev], *n=&poss[next], *p2=&poss[prev2], *n2=&poss[next2];
  909. Flt n_time=AfterTime(n->time, p->time, anim_length);
  910. for(Int src=i, i_next=i+3; ; ) // check that all removed keyframes (including this) do not deviate, start from the left because below we're checking if we've reached the next index, we need to go only to the right, because to the left no keys have been removed yet
  911. {
  912. C Pos &pos=poss[src];
  913. Vec test;
  914. #if HAS_ANIM_TANGENT
  915. Vec tan[2];
  916. if(!anim_linear)
  917. {
  918. tan[0]=GetTangent(p2->pos, p->pos, n ->pos);
  919. tan[1]=GetTangent(p ->pos, n->pos, n2->pos);
  920. }
  921. #endif
  922. // check at key location
  923. if(src!=prev) // no need to check time where both source and optimized have a keyframe
  924. {
  925. Flt step=LerpRS(p->time, n_time, AfterTime(pos.time, p->time, anim_length)); // use Sat in case pos.time is outside of range, or 'p' has the same time as 'n'
  926. if(anim_linear)test=Lerp(p->pos, n->pos, step);else
  927. {
  928. #if HAS_ANIM_TANGENT
  929. test=LerpTan(p->pos, n->pos, step, tan[0], tan[1]);
  930. #else
  931. test=Lerp4(p2->pos, p->pos, n->pos, n2->pos, step);
  932. #endif
  933. }
  934. if(Dist2(test, pos.pos)>pos_eps)goto pos_needed;
  935. }
  936. // check between keys
  937. if(!anim_linear) // for cubic interpolation we need to check between keys, because due to cubic interpolation the values can get way off
  938. {
  939. Flt next_time=(InRange(src+1, poss) ? poss[src+1].time : anim_loop ? poss[0].time+anim_length : anim_length);
  940. if(!Equal(pos.time, next_time)) // if times are the same then we don't need to do the following (this can happen when last key is at the end of anim and (it's not looped or the first key is at the start))
  941. {
  942. anim_params.time=Avg(pos.time, next_time); // set time between this and next key from the source
  943. Vec pos; T.pos(pos, anim_params);
  944. Flt step=LerpRS(p->time, n_time, AfterTime(anim_params.time, p->time, anim_length)); // use Sat in case pos.time is outside of range, or 'p' has the same time as 'n'
  945. if(anim_linear)test=Lerp(p->pos, n->pos, step);else
  946. {
  947. #if HAS_ANIM_TANGENT
  948. test=LerpTan(p->pos, n->pos, step, tan[0], tan[1]);
  949. #else
  950. test=Lerp4(p2->pos, p->pos, n->pos, n2->pos, step);
  951. #endif
  952. }
  953. if(Dist2(test, pos)>pos_eps)goto pos_needed;
  954. }
  955. }
  956. if(++src>=stop)break;
  957. if(src==next) // remember that 'next' can be wrapped due to looping, so use == for safety
  958. {
  959. prev2=prev; prev=next; next=next2; next2=optimized[Index(i_next++, anim_loop, optimized.elms(), i)];
  960. p=&poss[prev]; n=&poss[next]; p2=&poss[prev2]; n2=&poss[next2];
  961. n_time=AfterTime(n->time, p->time, anim_length);
  962. }
  963. }
  964. optimized.remove(i, true);
  965. pos_needed:;
  966. }
  967. if(optimized.elms()==1 && poss[optimized[0]].pos.length2()<=pos_eps)optimized.clear();
  968. if(optimized.elms()!=poss.elms()){Mems<Pos> temp; temp.setNum(optimized.elms()); REPAO(temp)=poss[optimized[i]]; Swap(temp, poss);}
  969. }
  970. // scale
  971. if(scale_eps>=0)
  972. {
  973. optimized.setNum(scales.elms()); REPAO(optimized)=i;
  974. REPA(optimized)if(optimized.elms()>=2)
  975. {
  976. Int prev2=optimized[Index(i-2, anim_loop, optimized.elms(), i)],
  977. prev =optimized[Index(i-1, anim_loop, optimized.elms(), i)],
  978. next =optimized[Index(i+1, anim_loop, optimized.elms(), i)],
  979. next2=optimized[Index(i+2, anim_loop, optimized.elms(), i)],
  980. stop =(InRange(i+1, optimized) ? optimized[Min(i+(anim_linear ? 1 : 2), optimized.elms()-1)] : scales.elms()); // stop on the next key that wasn't removed (for non-linear use 2nd next key)
  981. C Scale *p=&scales[prev], *n=&scales[next], *p2=&scales[prev2], *n2=&scales[next2];
  982. Flt n_time=AfterTime(n->time, p->time, anim_length);
  983. for(Int src=i, i_next=i+3; ; ) // check that all removed keyframes (including this) do not deviate, start from the left because below we're checking if we've reached the next index, we need to go only to the right, because to the left no keys have been removed yet
  984. {
  985. C Scale &scale=scales[src];
  986. Vec test;
  987. #if HAS_ANIM_TANGENT
  988. Vec tan[2];
  989. if(!anim_linear)
  990. {
  991. tan[0]=GetTangent(p2->scale, p->scale, n ->scale);
  992. tan[1]=GetTangent(p ->scale, n->scale, n2->scale);
  993. }
  994. #endif
  995. // check at key location
  996. if(src!=prev) // no need to check time where both source and optimized have a keyframe
  997. {
  998. Flt step=LerpRS(p->time, n_time, AfterTime(scale.time, p->time, anim_length)); // use Sat in case scale.time is outside of range, or 'p' has the same time as 'n'
  999. if(anim_linear)test=Lerp(p->scale, n->scale, step);else
  1000. {
  1001. #if HAS_ANIM_TANGENT
  1002. test=LerpTan(p->scale, n->scale, step, tan[0], tan[1]);
  1003. #else
  1004. test=Lerp4(p2->scale, p->scale, n->scale, n2->scale, step);
  1005. #endif
  1006. }
  1007. if(MaxAbsDelta(test, scale.scale)>scale_eps)goto scale_needed;
  1008. }
  1009. // check between keys
  1010. if(!anim_linear) // for cubic interpolation we need to check between keys, because due to cubic interpolation the values can get way off
  1011. {
  1012. Flt next_time=(InRange(src+1, scales) ? scales[src+1].time : anim_loop ? scales[0].time+anim_length : anim_length);
  1013. if(!Equal(scale.time, next_time)) // if times are the same then we don't need to do the following (this can happen when last key is at the end of anim and (it's not looped or the first key is at the start))
  1014. {
  1015. anim_params.time=Avg(scale.time, next_time); // set time between this and next key from the source
  1016. Vec scale; T.scale(scale, anim_params);
  1017. Flt step=LerpRS(p->time, n_time, AfterTime(anim_params.time, p->time, anim_length)); // use Sat in case scale.time is outside of range, or 'p' has the same time as 'n'
  1018. if(anim_linear)test=Lerp(p->scale, n->scale, step);else
  1019. {
  1020. #if HAS_ANIM_TANGENT
  1021. test=LerpTan(p->scale, n->scale, step, tan[0], tan[1]);
  1022. #else
  1023. test=Lerp4(p2->scale, p->scale, n->scale, n2->scale, step);
  1024. #endif
  1025. }
  1026. if(MaxAbsDelta(test, scale)>scale_eps)goto scale_needed;
  1027. }
  1028. }
  1029. if(++src>=stop)break;
  1030. if(src==next) // remember that 'next' can be wrapped due to looping, so use == for safety
  1031. {
  1032. prev2=prev; prev=next; next=next2; next2=optimized[Index(i_next++, anim_loop, optimized.elms(), i)];
  1033. p=&scales[prev]; n=&scales[next]; p2=&scales[prev2]; n2=&scales[next2];
  1034. n_time=AfterTime(n->time, p->time, anim_length);
  1035. }
  1036. }
  1037. optimized.remove(i, true);
  1038. scale_needed:;
  1039. }
  1040. if(optimized.elms()==1 && MaxAbsDelta(scales[optimized[0]].scale, VecZero)<=scale_eps)optimized.clear();
  1041. if(optimized.elms()!=scales.elms()){Mems<Scale> temp; temp.setNum(optimized.elms()); REPAO(temp)=scales[optimized[i]]; Swap(temp, scales);}
  1042. }
  1043. #if HAS_ANIM_ROT
  1044. // rotation
  1045. if(angle_eps>=0)
  1046. {
  1047. optimized.setNum(rots.elms()); REPAO(optimized)=i;
  1048. REPA(optimized)if(optimized.elms()>=2)
  1049. {
  1050. Int prev2=optimized[Index(i-2, anim_loop, optimized.elms(), i)],
  1051. prev =optimized[Index(i-1, anim_loop, optimized.elms(), i)],
  1052. next =optimized[Index(i+1, anim_loop, optimized.elms(), i)],
  1053. next2=optimized[Index(i+2, anim_loop, optimized.elms(), i)],
  1054. stop =(InRange(i+1, optimized) ? optimized[Min(i+(anim_linear ? 1 : 2), optimized.elms()-1)] : rots.elms()); // stop on the next key that wasn't removed (for non-linear use 2nd next key)
  1055. C Rot *p=&rots[prev], *n=&rots[next], *p2=&rots[prev2], *n2=&rots[next2];
  1056. Flt n_time=AfterTime(n->time, p->time, anim_length);
  1057. for(Int src=i, i_next=i+3; ; ) // check that all removed keyframes (including this) do not deviate, start from the left because below we're checking if we've reached the next index, we need to go only to the right, because to the left no keys have been removed yet
  1058. {
  1059. C Rot &rot=rots[src];
  1060. AxisRoll test;
  1061. #if HAS_ANIM_TANGENT
  1062. AxisRoll tan[2];
  1063. if(!anim_linear)
  1064. {
  1065. tan[0].v4()=GetTangent(p2->rot.v4(), p->rot.v4(), n ->rot.v4());
  1066. tan[1].v4()=GetTangent(p ->rot.v4(), n->rot.v4(), n2->rot.v4());
  1067. }
  1068. #endif
  1069. // check at key location
  1070. if(src!=prev) // no need to check time where both source and optimized have a keyframe
  1071. {
  1072. Flt step=LerpRS(p->time, n_time, AfterTime(rot.time, p->time, anim_length)); // use Sat in case rot.time is outside of range, or 'p' has the same time as 'n'
  1073. if(anim_linear)test.v4()=Lerp(p->rot.v4(), n->rot.v4(), step);else
  1074. {
  1075. #if HAS_ANIM_TANGENT
  1076. test.v4()=LerpTan(p->rot.v4(), n->rot.v4(), step, tan[0].v4(), tan[1].v4());
  1077. #else
  1078. test.v4()=Lerp4(p2->rot.v4(), p->rot.v4(), n->rot.v4(), n2->rot.v4(), step);
  1079. #endif
  1080. }
  1081. if(MaxAbsAngleBetween(test, rot.rot)>angle_eps)goto rot_needed;
  1082. }
  1083. // check between keys
  1084. if(!anim_linear) // for cubic interpolation we need to check between keys, because due to cubic interpolation the values can get way off
  1085. {
  1086. Flt next_time=(InRange(src+1, rots) ? rots[src+1].time : anim_loop ? rots[0].time+anim_length : anim_length);
  1087. if(!Equal(rot.time, next_time)) // if times are the same then we don't need to do the following (this can happen when last key is at the end of anim and (it's not looped or the first key is at the start))
  1088. {
  1089. anim_params.time=Avg(rot.time, next_time); // set time between this and next key from the source
  1090. AxisRoll rot; T.rot(rot, anim_params);
  1091. Flt step=LerpRS(p->time, n_time, AfterTime(anim_params.time, p->time, anim_length)); // use Sat in case rot.time is outside of range, or 'p' has the same time as 'n'
  1092. if(anim_linear)test.v4()=Lerp(p->rot.v4(), n->rot.v4(), step);else
  1093. {
  1094. #if HAS_ANIM_TANGENT
  1095. test.v4()=LerpTan(p->rot.v4(), n->rot.v4(), step, tan[0].v4(), tan[1].v4());
  1096. #else
  1097. test.v4()=Lerp4(p2->rot.v4(), p->rot.v4(), n->rot.v4(), n2->rot.v4(), step);
  1098. #endif
  1099. }
  1100. if(MaxAbsAngleBetween(test, rot)>angle_eps)goto rot_needed;
  1101. }
  1102. }
  1103. if(++src>=stop)break;
  1104. if(src==next) // remember that 'next' can be wrapped due to looping, so use == for safety
  1105. {
  1106. prev2=prev; prev=next; next=next2; next2=optimized[Index(i_next++, anim_loop, optimized.elms(), i)];
  1107. p=&rots[prev]; n=&rots[next]; p2=&rots[prev2]; n2=&rots[next2];
  1108. n_time=AfterTime(n->time, p->time, anim_length);
  1109. }
  1110. }
  1111. optimized.remove(i, true);
  1112. rot_needed:;
  1113. }
  1114. if(optimized.elms()==1 && MaxAbsAngleBetween(rots[optimized[0]].rot, AxisRoll().zero())<=angle_eps)optimized.clear();
  1115. if(optimized.elms()!=rots.elms()){Mems<Rot> temp; temp.setNum(optimized.elms()); REPAO(temp)=rots[optimized[i]]; Swap(temp, rots);}
  1116. }
  1117. #endif
  1118. #if HAS_ANIM_COLOR
  1119. // color
  1120. if(color_eps>=0)
  1121. {
  1122. optimized.setNum(colors.elms()); REPAO(optimized)=i;
  1123. REPA(optimized)if(optimized.elms()>=2)
  1124. {
  1125. Int prev2=optimized[Index(i-2, anim_loop, optimized.elms(), i)],
  1126. prev =optimized[Index(i-1, anim_loop, optimized.elms(), i)],
  1127. next =optimized[Index(i+1, anim_loop, optimized.elms(), i)],
  1128. next2=optimized[Index(i+2, anim_loop, optimized.elms(), i)],
  1129. stop =(InRange(i+1, optimized) ? optimized[Min(i+(anim_linear ? 1 : 2), optimized.elms()-1)] : colors.elms()); // stop on the next key that wasn't removed (for non-linear use 2nd next key)
  1130. C Color *p=&colors[prev], *n=&colors[next], *p2=&colors[prev2], *n2=&colors[next2];
  1131. Flt n_time=AfterTime(n->time, p->time, anim_length);
  1132. for(Int src=i, i_next=i+3; ; ) // check that all removed keyframes (including this) do not deviate, start from the left because below we're checking if we've reached the next index, we need to go only to the right, because to the left no keys have been removed yet
  1133. {
  1134. C Color &color=colors[src];
  1135. Vec4 test;
  1136. #if HAS_ANIM_TANGENT
  1137. Vec4 tan[2];
  1138. if(!anim_linear)
  1139. {
  1140. tan[0]=GetTangent(p2->color, p->color, n ->color);
  1141. tan[1]=GetTangent(p ->color, n->color, n2->color);
  1142. }
  1143. #endif
  1144. // check at key location
  1145. if(src!=prev) // no need to check time where both source and optimized have a keyframe
  1146. {
  1147. Flt step=LerpRS(p->time, n_time, AfterTime(color.time, p->time, anim_length)); // use Sat in case color.time is outside of range, or 'p' has the same time as 'n'
  1148. if(anim_linear)test=Lerp(p->color, n->color, step);else
  1149. {
  1150. #if HAS_ANIM_TANGENT
  1151. test=LerpTan(p->color, n->color, step, tan[0], tan[1]);
  1152. #else
  1153. test=Lerp4(p2->color, p->color, n->color, n2->color, step);
  1154. #endif
  1155. }
  1156. if(MaxAbsDelta(test, color.color)>color_eps)goto color_needed;
  1157. }
  1158. // check between keys
  1159. if(!anim_linear) // for cubic interpolation we need to check between keys, because due to cubic interpolation the values can get way off
  1160. {
  1161. Flt next_time=(InRange(src+1, colors) ? colors[src+1].time : anim_loop ? colors[0].time+anim_length : anim_length);
  1162. if(!Equal(color.time, next_time)) // if times are the same then we don't need to do the following (this can happen when last key is at the end of anim and (it's not looped or the first key is at the start))
  1163. {
  1164. anim_params.time=Avg(color.time, next_time); // set time between this and next key from the source
  1165. Vec4 color; T.color(color, anim_params);
  1166. Flt step=LerpRS(p->time, n_time, AfterTime(anim_params.time, p->time, anim_length)); // use Sat in case color.time is outside of range, or 'p' has the same time as 'n'
  1167. if(anim_linear)test=Lerp(p->color, n->color, step);else
  1168. {
  1169. #if HAS_ANIM_TANGENT
  1170. test=LerpTan(p->color, n->color, step, tan[0], tan[1]);
  1171. #else
  1172. test=Lerp4(p2->color, p->color, n->color, n2->color, step);
  1173. #endif
  1174. }
  1175. if(MaxAbsDelta(test, color)>color_eps)goto color_needed;
  1176. }
  1177. }
  1178. if(++src>=stop)break;
  1179. if(src==next) // remember that 'next' can be wrapped due to looping, so use == for safety
  1180. {
  1181. prev2=prev; prev=next; next=next2; next2=optimized[Index(i_next++, anim_loop, optimized.elms(), i)];
  1182. p=&colors[prev]; n=&colors[next]; p2=&colors[prev2]; n2=&colors[next2];
  1183. n_time=AfterTime(n->time, p->time, anim_length);
  1184. }
  1185. }
  1186. optimized.remove(i, true);
  1187. color_needed:;
  1188. }
  1189. if(optimized.elms()==1 && MaxAbsDelta(colors[optimized[0]].color, Vec4(1, 1, 1, 1))<=color_eps)optimized.clear();
  1190. if(optimized.elms()!=colors.elms()){Mems<Color> temp; temp.setNum(optimized.elms()); REPAO(temp)=colors[optimized[i]]; Swap(temp, colors);}
  1191. }
  1192. #endif
  1193. return T;
  1194. }
  1195. /******************************************************************************/
  1196. #define TIME_EPS (EPS)
  1197. struct TimeClip
  1198. {
  1199. Flt start_time, end_time, length, length_eps;
  1200. TimeClip(Flt start_time, Flt end_time)
  1201. {
  1202. T.start_time=start_time;
  1203. T. end_time= end_time;
  1204. T.length = end_time-start_time;
  1205. T.length_eps=length-TIME_EPS;
  1206. }
  1207. void adjust(Flt &time)C
  1208. {
  1209. Flt t=time-start_time;
  1210. if(t< TIME_EPS)t= 0;else // it's important to align to start
  1211. if(t>length_eps)t=length; // and end, because looped root motion is calculated at time=0 and time=length, so if times are slightly offsetted, we could get root motion start that is actually end
  1212. time=t;
  1213. }
  1214. T1(TYPE) void find(Mems<TYPE> &keys, Int &before_start, Int &after_end)C
  1215. {
  1216. before_start=-1; FREPA(keys)if(keys[i].time<start_time)before_start=i;else break; // go from start
  1217. after_end =-1; REPA(keys)if(keys[i].time> end_time) after_end =i;else break; // go from end
  1218. }
  1219. T1(TYPE) NOINLINE void clip(Mems<TYPE> &keys)C // use 'NOINLINE' to prevent from inlining because we're using Memt which uses lot of stack memory
  1220. {
  1221. // first add all good keys to a temporary container, because if we would be removing from 'Mems' one by one, then it would be very slow
  1222. Memt<TYPE> clipped;
  1223. FREPA(keys) // process in order to preserve order
  1224. {
  1225. TYPE &key=keys[i]; if(key.time>=start_time && key.time<=end_time) // add only if inside the time range
  1226. {
  1227. adjust(key.time); // adjust time before adding
  1228. clipped.add(key);
  1229. }
  1230. }
  1231. keys=clipped; // always assign, not only if number of keys is different, because we're not only removing, but also adjusting 'time' values
  1232. }
  1233. };
  1234. AnimKeys& AnimKeys::clip(Bool anim_loop, Bool anim_linear, Flt anim_length, Flt start_time, Flt end_time)
  1235. {
  1236. if(end_time<start_time)Swap(start_time, end_time); TimeClip tc(start_time, end_time);
  1237. AnimParams params(anim_loop, anim_linear, anim_length, 0);
  1238. Int before_start, after_end;
  1239. // orientations
  1240. if(orns.elms()==1)tc.adjust(orns[0].time);else // if there is only 1 frame, then keep it
  1241. if(orns.elms()> 1) // otherwise check for before start and after end
  1242. {
  1243. tc.find(orns, before_start, after_end);
  1244. // check for keyframes after end
  1245. if(after_end>=0) // there is a keyframe after end
  1246. if(!InRange(after_end-1, orns) || orns[after_end-1].time<end_time-TIME_EPS) // previous keyframe doesn't exist or isn't at the end
  1247. { // adjust 'after_end' keyframe so it's positioned at the end
  1248. Orn &next=orns[after_end]; params.time=end_time; orn(next.orn, params); next.time=end_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1249. }
  1250. // check for keyframes before start
  1251. if(before_start>=0) // there is a keyframe before start
  1252. if(!InRange(before_start+1, orns) || orns[before_start+1].time>start_time+TIME_EPS) // next keyframe doesn't exist or isn't at the start
  1253. { // adjust 'before_start' keyframe so it's positioned at the start
  1254. Orn &prev=orns[before_start]; params.time=start_time; orn(prev.orn, params); prev.time=start_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1255. }
  1256. tc.clip(orns); // remove keyframes out of range and adjust time
  1257. }
  1258. // positions
  1259. if(poss.elms()==1)tc.adjust(poss[0].time);else // if there is only 1 frame, then keep it
  1260. if(poss.elms()> 1) // otherwise check for before start and after end
  1261. {
  1262. tc.find(poss, before_start, after_end);
  1263. // check for keyframes after end
  1264. if(after_end>=0) // there is a keyframe after end
  1265. if(!InRange(after_end-1, poss) || poss[after_end-1].time<end_time-TIME_EPS) // previous keyframe doesn't exist or isn't at the end
  1266. { // adjust 'after_end' keyframe so it's positioned at the end
  1267. Pos &next=poss[after_end]; params.time=end_time; pos(next.pos, params); next.time=end_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1268. }
  1269. // check for keyframes before start
  1270. if(before_start>=0) // there is a keyframe before start
  1271. if(!InRange(before_start+1, poss) || poss[before_start+1].time>start_time+TIME_EPS) // next keyframe doesn't exist or isn't at the start
  1272. { // adjust 'before_start' keyframe so it's positioned at the start
  1273. Pos &prev=poss[before_start]; params.time=start_time; pos(prev.pos, params); prev.time=start_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1274. }
  1275. tc.clip(poss); // remove keyframes out of range and adjust time
  1276. }
  1277. // scales
  1278. if(scales.elms()==1)tc.adjust(scales[0].time);else // if there is only 1 frame, then keep it
  1279. if(scales.elms()> 1) // otherwise check for before start and after end
  1280. {
  1281. tc.find(scales, before_start, after_end);
  1282. // check for keyframes after end
  1283. if(after_end>=0) // there is a keyframe after end
  1284. if(!InRange(after_end-1, scales) || scales[after_end-1].time<end_time-TIME_EPS) // previous keyframe doesn't exist or isn't at the end
  1285. { // adjust 'after_end' keyframe so it's positioned at the end
  1286. Scale &next=scales[after_end]; params.time=end_time; scale(next.scale, params); next.time=end_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1287. }
  1288. // check for keyframes before start
  1289. if(before_start>=0) // there is a keyframe before start
  1290. if(!InRange(before_start+1, scales) || scales[before_start+1].time>start_time+TIME_EPS) // next keyframe doesn't exist or isn't at the start
  1291. { // adjust 'before_start' keyframe so it's positioned at the start
  1292. Scale &prev=scales[before_start]; params.time=start_time; scale(prev.scale, params); prev.time=start_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1293. }
  1294. tc.clip(scales); // remove keyframes out of range and adjust time
  1295. }
  1296. #if HAS_ANIM_ROT
  1297. // rotations
  1298. if(rots.elms()==1)tc.adjust(rots[0].time);else // if there is only 1 frame, then keep it
  1299. if(rots.elms()> 1) // otherwise check for before start and after end
  1300. {
  1301. tc.find(rots, before_start, after_end);
  1302. // check for keyframes after end
  1303. if(after_end>=0) // there is a keyframe after end
  1304. if(!InRange(after_end-1, rots) || rots[after_end-1].time<end_time-TIME_EPS) // previous keyframe doesn't exist or isn't at the end
  1305. { // adjust 'after_end' keyframe so it's positioned at the end
  1306. Rot &next=rots[after_end]; params.time=end_time; rot(next.rot, params); next.time=end_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1307. }
  1308. // check for keyframes before start
  1309. if(before_start>=0) // there is a keyframe before start
  1310. if(!InRange(before_start+1, rots) || rots[before_start+1].time>start_time+TIME_EPS) // next keyframe doesn't exist or isn't at the start
  1311. { // adjust 'before_start' keyframe so it's positioned at the start
  1312. Rot &prev=rots[before_start]; params.time=start_time; rot(prev.rot, params); prev.time=start_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1313. }
  1314. tc.clip(rots); // remove keyframes out of range and adjust time
  1315. }
  1316. #endif
  1317. #if HAS_ANIM_COLOR
  1318. // colors
  1319. if(colors.elms()==1)tc.adjust(colors[0].time);else // if there is only 1 frame, then keep it
  1320. if(colors.elms()> 1) // otherwise check for before start and after end
  1321. {
  1322. tc.find(colors, before_start, after_end);
  1323. // check for keyframes after end
  1324. if(after_end>=0) // there is a keyframe after end
  1325. if(!InRange(after_end-1, colors) || colors[after_end-1].time<end_time-TIME_EPS) // previous keyframe doesn't exist or isn't at the end
  1326. { // adjust 'after_end' keyframe so it's positioned at the end
  1327. Color &next=colors[after_end]; params.time=end_time; color(next.color, params); next.time=end_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1328. }
  1329. // check for keyframes before start
  1330. if(before_start>=0) // there is a keyframe before start
  1331. if(!InRange(before_start+1, colors) || colors[before_start+1].time>start_time+TIME_EPS) // next keyframe doesn't exist or isn't at the start
  1332. { // adjust 'before_start' keyframe so it's positioned at the start
  1333. Color &prev=colors[before_start]; params.time=start_time; color(prev.color, params); prev.time=start_time; // adjust keyframe 'time' after evaluation so the change doesn't affect it
  1334. }
  1335. tc.clip(colors); // remove keyframes out of range and adjust time
  1336. }
  1337. #endif
  1338. return setTangents(anim_loop, end_time-start_time);
  1339. }
  1340. /******************************************************************************/
  1341. void AnimKeys::includeTimes(MemPtr<Flt, 16384> orn_times, MemPtr<Flt, 16384> pos_times, MemPtr<Flt, 16384> scale_times)C
  1342. {
  1343. if( orn_times){if( orn_times.elms())FREPA( orns) orn_times.binaryInclude( orns[i].time, CompareEps);else { orn_times.setNum( orns.elms()); REPAO( orn_times)= orns[i].time;}} // process forward because keys are sorted
  1344. if( pos_times){if( pos_times.elms())FREPA( poss) pos_times.binaryInclude( poss[i].time, CompareEps);else { pos_times.setNum( poss.elms()); REPAO( pos_times)= poss[i].time;}} // process forward because keys are sorted
  1345. if(scale_times){if(scale_times.elms())FREPA(scales)scale_times.binaryInclude(scales[i].time, CompareEps);else {scale_times.setNum(scales.elms()); REPAO(scale_times)=scales[i].time;}} // process forward because keys are sorted
  1346. }
  1347. static void IncludeTimes(C MemPtr<Flt, 16384> &src, MemPtr<Flt, 16384> dest)
  1348. {
  1349. FREPA(src)dest.binaryInclude(src[i], CompareEps); // process forward because 'src' is most likely sorted
  1350. }
  1351. /******************************************************************************/
  1352. #if HAS_ANIM_ROT
  1353. AnimKeys& AnimKeys::convertRotToOrn(C Skeleton &skeleton, Int skel_bone_index, Bool anim_loop, Flt anim_length) // this method can ignore name differences because it's used only during importing while the names are the same
  1354. {
  1355. if(rots.elms() && (skel_bone_index<0 || InRange(skel_bone_index, skeleton.bones))) // <0 means keys of 'root' bone
  1356. {
  1357. if(skel_bone_index<0)
  1358. {
  1359. orns.setNum(rots.elms());
  1360. REPA(orns)
  1361. {
  1362. C Rot &rot=T.rots[i];
  1363. Orn &orn=T.orns[i]; orn.time=rot.time;
  1364. Vec axis =rot .rot.axis ; // rotation in parent space
  1365. Flt angle=axis.normalize();
  1366. orn.orn=Matrix3().setRotateZ(rot.rot.roll)
  1367. . rotate (axis, angle ); // temp is now set to target orientation in global space
  1368. }
  1369. }else
  1370. {
  1371. C SkelBone &sbon =skeleton.bones[skel_bone_index],
  1372. *parent=skeleton.bones.addr(sbon.parent);
  1373. Matrix3 parent_matrix, parent_matrix_inv; if(parent){parent_matrix=*parent; parent_matrix.inverse(parent_matrix_inv, true);}
  1374. orns.setNum(rots.elms());
  1375. REPA(orns)
  1376. {
  1377. C Rot &rot=T.rots[i];
  1378. Orn &orn=T.orns[i]; orn.time=rot.time;
  1379. Vec axis =rot .rot.axis ; // rotation in parent space
  1380. Flt angle=axis.normalize() ;
  1381. if(parent)axis*=parent_matrix; // rotation in global space
  1382. Orient temp=sbon;
  1383. temp*=Matrix3().setRotate(sbon.dir, rot.rot.roll)
  1384. . rotate(axis , angle ); // temp is now set to target orientation in global space
  1385. if(parent)temp*=parent_matrix_inv; // convert to be in parent space
  1386. orn.orn=temp;
  1387. }
  1388. }
  1389. rots.clear();
  1390. setTangents(anim_loop, anim_length);
  1391. }
  1392. return T;
  1393. }
  1394. AnimKeys& AnimKeys::convertOrnToRot(C Skeleton &skeleton, Int skel_bone_index, Bool anim_loop, Flt anim_length) // this method can ignore name differences because it's used only during importing while the names are the same
  1395. {
  1396. if(orns.elms() && (skel_bone_index<0 || InRange(skel_bone_index, skeleton.bones))) // <0 means keys of 'root' bone
  1397. {
  1398. if(skel_bone_index<0)
  1399. {
  1400. rots.setNum(orns.elms());
  1401. REPA(rots)
  1402. {
  1403. C Orn &orn=T.orns[i];
  1404. Rot &rot=T.rots[i]; rot.time=orn.time;
  1405. Orient dest=orn.orn, // target orientation in parent space
  1406. src; src.identity(); // current orientation in global space
  1407. rot.rot.from(src, dest);
  1408. }
  1409. }else
  1410. {
  1411. C SkelBone &sbon =skeleton.bones[skel_bone_index],
  1412. *parent=skeleton.bones.addr(sbon.parent);
  1413. Matrix3 parent_matrix_inv; if(parent)parent->inverse(parent_matrix_inv);
  1414. rots.setNum(orns.elms());
  1415. REPA(rots)
  1416. {
  1417. C Orn &orn=T.orns[i];
  1418. Rot &rot=T.rots[i]; rot.time=orn.time;
  1419. Orient dest=orn.orn , // target orientation in parent space
  1420. src =sbon ; // current orientation in global space
  1421. if(parent)src*=parent_matrix_inv; // current orientation in parent space
  1422. rot.rot.from(src, dest);
  1423. }
  1424. }
  1425. orns.clear();
  1426. setTangents(anim_loop, anim_length);
  1427. }
  1428. return T;
  1429. }
  1430. #endif
  1431. /******************************************************************************/
  1432. static void LoadOrnTan(File &f, Mems<AnimKeys::Orn> &orns)
  1433. {
  1434. #if HAS_ANIM_TANGENT
  1435. f.getN(orns.data(), orns.elms());
  1436. #else
  1437. FREPA(orns){AnimKeys::Orn &orn=orns[i]; f>>orn.time>>orn.orn; f.skip(SIZE(Orient));}
  1438. #endif
  1439. }
  1440. static void LoadPosTan(File &f, Mems<AnimKeys::Pos> &poss)
  1441. {
  1442. #if HAS_ANIM_TANGENT
  1443. f.getN(poss.data(), poss.elms());
  1444. #else
  1445. FREPA(poss){AnimKeys::Pos &pos=poss[i]; f>>pos.time>>pos.pos; f.skip(SIZE(Vec));}
  1446. #endif
  1447. }
  1448. static void LoadScaleTan(File &f, Mems<AnimKeys::Scale> &scales)
  1449. {
  1450. #if HAS_ANIM_TANGENT
  1451. f.getN(scales.data(), scales.elms());
  1452. #else
  1453. FREPA(scales){AnimKeys::Scale &scale=scales[i]; f>>scale.time>>scale.scale; f.skip(SIZE(Vec));}
  1454. #endif
  1455. }
  1456. #if HAS_ANIM_ROT
  1457. static void LoadRotTan(File &f, Mems<AnimKeys::Rot> &rots)
  1458. {
  1459. #if HAS_ANIM_TANGENT
  1460. f.getN(rots.data(), rots.elms());
  1461. #else
  1462. FREPA(rots){AnimKeys::Rot &rot=rots[i]; f>>rot.time>>rot.rot; f.skip(SIZE(AxisRoll));}
  1463. #endif
  1464. }
  1465. #else
  1466. static void LoadRotTan(File &f, Int rots) {f.skip((SIZE(Flt)+SIZE(AxisRoll)+SIZE(AxisRoll))*rots);} // (time+rot+tan)*rots
  1467. #endif
  1468. #if HAS_ANIM_COLOR
  1469. static void LoadColorTan(File &f, Mems<AnimKeys::Color> &colors)
  1470. {
  1471. #if HAS_ANIM_TANGENT
  1472. f.getN(colors.data(), colors.elms());
  1473. #else
  1474. FREPA(colors){AnimKeys::Color &color=colors[i]; f>>color.time>>color.color; f.skip(SIZE(Vec4));}
  1475. #endif
  1476. }
  1477. #else
  1478. static void LoadColorTan(File &f, Int colors) {f.skip((SIZE(Flt)+SIZE(Vec4)+SIZE(Vec4))*colors);} // (time+color+tan)*color
  1479. #endif
  1480. /******************************************************************************/
  1481. Bool AnimKeys::saveData(File &f)C
  1482. {
  1483. ASSERT(HAS_ANIM_TANGENT==0);
  1484. if(orns .saveRaw(f))
  1485. if(poss .saveRaw(f))
  1486. if(scales.saveRaw(f))
  1487. return f.ok();
  1488. return false;
  1489. }
  1490. Bool AnimKeys::loadData(File &f)
  1491. {
  1492. ASSERT(HAS_ANIM_TANGENT==0);
  1493. if(orns .loadRaw(f))
  1494. if(poss .loadRaw(f))
  1495. if(scales.loadRaw(f))
  1496. if(f.ok())return true;
  1497. del(); return false;
  1498. }
  1499. void AnimKeys::loadData3(File &f)
  1500. {
  1501. orns .setNum(f.decUIntV()); LoadOrnTan (f, orns);
  1502. #if HAS_ANIM_ROT
  1503. rots .setNum(f.decUIntV()); LoadRotTan (f, rots);
  1504. #else
  1505. LoadRotTan (f, f.decUIntV());
  1506. #endif
  1507. poss .setNum(f.decUIntV()); LoadPosTan (f, poss);
  1508. scales.setNum(f.decUIntV()); LoadScaleTan(f, scales);
  1509. #if HAS_ANIM_COLOR
  1510. colors.setNum(f.decUIntV()); LoadColorTan(f, colors);
  1511. #else
  1512. LoadColorTan(f, f.decUIntV());
  1513. #endif
  1514. }
  1515. void AnimKeys::loadData2(File &f)
  1516. {
  1517. orns.setNum(f.getUShort());
  1518. #if HAS_ANIM_ROT
  1519. rots.setNum(f.getUShort());
  1520. #else
  1521. Int rots=f.getUShort();
  1522. #endif
  1523. poss .setNum(f.getUShort());
  1524. scales.setNum(f.getUShort());
  1525. #if HAS_ANIM_COLOR
  1526. colors.setNum(f.getUShort());
  1527. #else
  1528. Int colors=f.getUShort();
  1529. #endif
  1530. LoadOrnTan (f, orns );
  1531. LoadRotTan (f, rots );
  1532. LoadPosTan (f, poss );
  1533. LoadScaleTan(f, scales);
  1534. LoadColorTan(f, colors);
  1535. }
  1536. void AnimKeys::loadData1(File &f)
  1537. {
  1538. orns.setNum(f.getUShort());
  1539. #if HAS_ANIM_ROT
  1540. rots.setNum(f.getUShort());
  1541. #else
  1542. Int rots=f.getUShort();
  1543. #endif
  1544. poss .setNum(f.getUShort());
  1545. scales.setNum(f.getUShort());
  1546. LoadOrnTan(f, orns);
  1547. LoadRotTan(f, rots);
  1548. LoadPosTan(f, poss);
  1549. FREPA(scales)
  1550. {
  1551. scales[i].time =f.getFlt();
  1552. scales[i].scale=f.getFlt();
  1553. #if HAS_ANIM_TANGENT
  1554. scales[i].tan =f.getFlt();
  1555. #else
  1556. f.skip(SIZE(Flt));
  1557. #endif
  1558. }
  1559. }
  1560. void AnimKeys::loadData0(File &f)
  1561. {
  1562. orns.setNum(f.getUShort());
  1563. #if HAS_ANIM_ROT
  1564. rots.setNum(f.getUShort());
  1565. #else
  1566. Int rots=f.getUShort();
  1567. #endif
  1568. poss.setNum(f.getUShort());
  1569. LoadOrnTan(f, orns);
  1570. LoadRotTan(f, rots);
  1571. LoadPosTan(f, poss);
  1572. }
  1573. void AnimKeys::save(MemPtr<TextNode> nodes)C
  1574. {
  1575. if(orns.elms())
  1576. {
  1577. TextNode &node=nodes.New(); node.name="Orientations";
  1578. FREPAO(orns).save(node.nodes.New().nodes);
  1579. }
  1580. if(poss.elms())
  1581. {
  1582. TextNode &node=nodes.New(); node.name="Positions";
  1583. FREPAO(poss).save(node.nodes.New().nodes);
  1584. }
  1585. if(scales.elms())
  1586. {
  1587. TextNode &node=nodes.New(); node.name="Scales";
  1588. FREPAO(scales).save(node.nodes.New().nodes);
  1589. }
  1590. #if HAS_ANIM_ROT
  1591. if(rots.elms())
  1592. {
  1593. TextNode &node=nodes.New(); node.name="Rotations";
  1594. FREPAO(rots).save(node.nodes.New().nodes);
  1595. }
  1596. #endif
  1597. #if HAS_ANIM_COLOR
  1598. if(colors.elms())
  1599. {
  1600. TextNode &node=nodes.New(); node.name="Colors";
  1601. FREPAO(colors).save(node.nodes.New().nodes);
  1602. }
  1603. #endif
  1604. }
  1605. /******************************************************************************/
  1606. // ANIMATION BONE
  1607. /******************************************************************************/
  1608. void AnimBone::save(TextNode &node)C
  1609. {
  1610. node.set(name);
  1611. super::save(node.nodes);
  1612. }
  1613. /******************************************************************************/
  1614. // ANIMATION EVENT
  1615. /******************************************************************************/
  1616. void AnimEvent::save(TextNode &node)C
  1617. {
  1618. node.set(name);
  1619. node.nodes.New().set("Time", time);
  1620. }
  1621. /******************************************************************************/
  1622. // ANIMATION
  1623. /******************************************************************************/
  1624. void Animation::zero()
  1625. {
  1626. _flag =0;
  1627. _length=0;
  1628. _root_start .identity(); _root_start_inv.identity();
  1629. _root_end .identity();
  1630. _root_transform.identity();
  1631. }
  1632. Animation::Animation()
  1633. {
  1634. zero();
  1635. }
  1636. Animation& Animation::del()
  1637. {
  1638. bones .del();
  1639. events.del();
  1640. keys .del();
  1641. zero(); return T;
  1642. }
  1643. /******************************************************************************/
  1644. AnimEvent* Animation::findEvent(CChar8 *name)
  1645. {
  1646. REPA(events)
  1647. {
  1648. AnimEvent &event=events[i];
  1649. if(Equal(event.name, name))return &event;
  1650. }
  1651. return null;
  1652. }
  1653. Int Animation::eventCount(CChar8 *name)C
  1654. {
  1655. Int num=0; REPA(events)if(Equal(events[i].name, name))num++;
  1656. return num;
  1657. }
  1658. Bool Animation::eventAfter(CChar8 *name, Flt time)C
  1659. {
  1660. REPA(events)
  1661. {
  1662. C AnimEvent &event=events[i];
  1663. if(Equal(event.name, name) && time>=event.time)return true;
  1664. }
  1665. return false;
  1666. }
  1667. Bool Animation::eventOccurred(CChar8 *name, Flt start_time, Flt dt)C
  1668. {
  1669. Bool frac=false;
  1670. REPA(events)
  1671. {
  1672. C AnimEvent &event=events[i]; if(Equal(event.name, name))
  1673. {
  1674. Flt event_time=event.time;
  1675. if(loop())
  1676. {
  1677. if(!frac){frac=true; start_time=Frac(start_time, _length);}
  1678. if(event_time<start_time)event_time+=_length; // make sure that 'event_time' is after 'start_time'
  1679. }
  1680. if(EventOccurred(event_time, start_time, dt))return true;
  1681. }
  1682. }
  1683. return false;
  1684. }
  1685. Bool Animation::eventBetween(CChar8 *from, CChar8 *to, Flt start_time, Flt dt)C
  1686. {
  1687. C AnimEvent *event_from=null,
  1688. *event_to =null;
  1689. REPA(events)
  1690. {
  1691. C AnimEvent &event=events[i];
  1692. if(!event_from && Equal(from, event.name)){event_from=&event; if(event_to )goto found;}
  1693. if(!event_to && Equal(to , event.name)){event_to =&event; if(event_from)goto found;}
  1694. }
  1695. return false;
  1696. found:
  1697. Flt time_to=event_to->time;
  1698. if(loop())
  1699. {
  1700. start_time =Frac(start_time, _length);
  1701. if(start_time<event_from->time)start_time+=_length ; // make sure that 'start_time' is after 'event_from->time'
  1702. if( time_to <event_from->time)time_to +=_length ; // make sure that 'time_to' is after 'event_from->time'
  1703. }
  1704. return EventBetween(event_from->time, time_to, start_time, dt);
  1705. }
  1706. Flt Animation::eventProgress(CChar8 *from, CChar8 *to, Flt time)C
  1707. {
  1708. C AnimEvent *event_from=null,
  1709. *event_to =null;
  1710. REPA(events)
  1711. {
  1712. C AnimEvent &event=events[i];
  1713. if(!event_from && Equal(from, event.name)){event_from=&event; if(event_to )goto found;}
  1714. if(!event_to && Equal(to , event.name)){event_to =&event; if(event_from)goto found;}
  1715. }
  1716. return 0;
  1717. found:
  1718. Flt time_to=event_to->time;
  1719. if(loop())
  1720. {
  1721. time=Frac(time, _length);
  1722. if(time_to<event_from->time)time_to+=_length; // make sure that 'time_to' is after 'event_from->time'
  1723. }
  1724. return LerpR(event_from->time, time_to, time);
  1725. }
  1726. AnimBone* Animation::findBone(CChar8 *name, BONE_TYPE type, Int type_index, Int type_sub) {return bones.addr(findBoneI(name, type, type_index, type_sub));}
  1727. AnimBone& Animation:: getBone(CChar8 *name, BONE_TYPE type, Int type_index, Int type_sub)
  1728. {
  1729. if(AnimBone *bone= findBone(name, type, type_index, type_sub)) return *bone;
  1730. AnimBone &bone=bones.New(); bone.set(name, type, type_index, type_sub); return bone;
  1731. }
  1732. /******************************************************************************/
  1733. Animation& Animation::loop(Bool loop)
  1734. {
  1735. if(T.loop()!=loop)
  1736. {
  1737. _flag^=ANIM_LOOP;
  1738. setTangents().setRootMatrix();
  1739. }
  1740. return T;
  1741. }
  1742. Animation& Animation::linear(Bool linear)
  1743. {
  1744. if(T.linear()!=linear)
  1745. {
  1746. FlagToggle(_flag, ANIM_LINEAR);
  1747. setRootMatrix();
  1748. }
  1749. return T;
  1750. }
  1751. /******************************************************************************/
  1752. Animation& Animation::length(Flt length, Bool rescale_keyframes)
  1753. {
  1754. if(length<0){reverse(); CHS(length);}
  1755. if(T._length!=length)
  1756. {
  1757. if(rescale_keyframes)
  1758. {
  1759. Flt scale=((T._length>EPS) ? length/T._length : 0); TimeScaleClip tsc(scale, length);
  1760. keys .scaleTime(scale, length);
  1761. REPAO(bones ).scaleTime(scale, length);
  1762. REPA (events)tsc.adjust(events[i].time);
  1763. }else
  1764. if(length<T.length())clip(0, length); // if making the length shorter, then clip and remove keyframes out of range
  1765. T._length=length;
  1766. }
  1767. return T;
  1768. }
  1769. /******************************************************************************/
  1770. void Animation::setRootMatrix2()
  1771. {
  1772. _root_start.inverse(_root_start_inv);
  1773. _root_end .mul (_root_start_inv, _root_transform); // this is "GetTransform(_root_transform, _root_start, _root_end)"
  1774. }
  1775. Animation& Animation::setRootMatrix()
  1776. {
  1777. getRootMatrixExactTime(_root_end , length());
  1778. getRootMatrix (_root_start, 0);
  1779. setRootMatrix2();
  1780. return T;
  1781. }
  1782. static void GetRootMatrixNoScale(C AnimKeys &keys, Matrix &matrix, C AnimParams &params)
  1783. {
  1784. Orient orn; if( keys.orn( orn, params))matrix.orn()=orn;else matrix.orn().identity(); // if empty then call 'identity' because it's faster than setting from 'Orient'
  1785. if(!keys.pos(matrix.pos, params) && !SET_ON_FAIL)matrix.pos.zero();
  1786. }
  1787. static void GetRootMatrix(C AnimKeys &keys, Matrix &matrix, C AnimParams &params)
  1788. {
  1789. GetRootMatrixNoScale(keys, matrix, params);
  1790. Vec scale; if(keys.scales.elms() && keys.scale(scale, params))matrix.scaleOrnL(ScaleFactor(scale)); // most likely there won't be any scale, so do a fast check without the function call
  1791. }
  1792. void Animation::getRootMatrix(Matrix &matrix, Flt time)C
  1793. {
  1794. AnimParams params(T, time);
  1795. GetRootMatrix(keys, matrix, params);
  1796. }
  1797. void Animation::getRootMatrixCumulative(Matrix &matrix, Flt time)C
  1798. {
  1799. AnimParams params(T, time);
  1800. GetRootMatrix(keys, matrix, params);
  1801. if(params.loop)
  1802. if(Int rounds=Round((time-params.time)/params.length))
  1803. {
  1804. Matrix root_round; // this is root matrix at the start of the round
  1805. #if 0
  1806. rootStart().mulTimes(rounds , rootTransform(), root_round);
  1807. #else // prefer this version, because most likely we're playing animations forward, and this way we save 1 matrix multiplication
  1808. rootEnd ().mulTimes(rounds-1, rootTransform(), root_round); // use "rounds-1" because we start from 'rootEnd' which is end of the loop (1 round already)
  1809. #endif
  1810. RevMatrix rm; matrix.mul(_root_start_inv, rm); // this is "GetTransform(rm, rootStart(), matrix)", this is OK for negative times too, because even though we're transforming from 'rootStart' to 'matrix', we start with 'root_round' which already was moved before 'time' - at the start of that round.
  1811. root_round.mul(rm, matrix); // result = matrix at the start of a round, transformed by (transform from 'rootStart' to matrix at 'params.time')
  1812. }
  1813. }
  1814. void Animation::getRootMatrixExactTime(Matrix &matrix, Flt time)C
  1815. {
  1816. AnimParams params(T, time); params.time=time; // re-apply time to remove possible fraction
  1817. GetRootMatrix(keys, matrix, params);
  1818. }
  1819. void Animation::getRootTransform(RevMatrix &transform, Flt start_time, Flt end_time)C
  1820. {
  1821. AnimParams params;
  1822. RevMatrix rm;
  1823. Matrix m;
  1824. if(!keys.scales.elms()) // normalized
  1825. {
  1826. if(!keys.orns.elms()) // no orientation
  1827. {
  1828. if(!keys.poss.elms())transform.identity();else // nothing
  1829. { // position only
  1830. params.set(T, start_time); keys.pos(transform.pos, params); transform.pos.chs(); // pos=-start
  1831. params.time+=end_time-start_time;
  1832. if(params.loop)
  1833. {
  1834. if(params.time>=params.length)
  1835. {
  1836. transform.pos+=rootTransform().pos;
  1837. params.time-=params.length; if(params.time>=params.length) // if still greater than length, then it means we made more than 1 round (this is unlikely to happen, only when we play animations extremely fast)
  1838. {
  1839. Int rounds=Trunc(params.time/params.length);
  1840. params .time-=rounds*params.length;
  1841. transform.pos +=rounds*rootTransform().pos;
  1842. }
  1843. }else
  1844. if(params.time<0) // going back
  1845. {
  1846. transform.pos-=rootTransform().pos;
  1847. params.time+=params.length; if(params.time<0) // if still smaller than 0, then it means we made more than 1 round (this is unlikely to happen, only when we play animations extremely fast)
  1848. {
  1849. Int rounds=Floor(params.time/params.length);
  1850. params .time-=rounds*params.length;
  1851. transform.pos +=rounds*rootTransform().pos;
  1852. }
  1853. }
  1854. }
  1855. Vec end; keys.pos(end, params); transform.pos+=end; // pos+=end
  1856. transform.orn().identity();
  1857. }
  1858. }else // orientation with optional position
  1859. {
  1860. params.set(T, start_time);
  1861. GetRootMatrixNoScale(keys, m, params);
  1862. params.time+=end_time-start_time;
  1863. if(params.loop)
  1864. {
  1865. if(params.time>=params.length)
  1866. {
  1867. GetTransformNormalized(transform, m, rootEnd());
  1868. params.time-=params.length; if(params.time>=params.length) // if still greater than length, then it means we made more than 1 round (this is unlikely to happen, only when we play animations extremely fast)
  1869. {
  1870. Int rounds=Trunc(params.time/params.length);
  1871. params.time-=rounds*params.length;
  1872. transform.mulTimes(rounds, rootTransform());
  1873. }
  1874. GetRootMatrixNoScale(keys, m, params);
  1875. m.mul(_root_start_inv, rm); // this is "GetTransformNormalized(rm, rootStart(), m)"
  1876. transform*=rm;
  1877. return;
  1878. }else
  1879. if(params.time<0) // going back
  1880. {
  1881. GetTransformNormalized(transform, m, rootStart());
  1882. params.time+=params.length; if(params.time<0) // if still smaller than 0, then it means we made more than 1 round (this is unlikely to happen, only when we play animations extremely fast)
  1883. {
  1884. Int rounds=Floor(params.time/params.length);
  1885. params.time-=rounds*params.length;
  1886. transform.mulTimes(rounds, rootTransform());
  1887. }
  1888. GetRootMatrixNoScale(keys, m, params);
  1889. GetTransformNormalized(rm, rootEnd(), m);
  1890. transform*=rm;
  1891. return;
  1892. }
  1893. }
  1894. Matrix end; GetRootMatrixNoScale(keys, end, params); GetTransformNormalized(transform, m, end);
  1895. }
  1896. }else // scaled with optional orientation+position
  1897. {
  1898. params.set(T, start_time);
  1899. GetRootMatrix(keys, m, params);
  1900. params.time+=end_time-start_time;
  1901. if(params.loop)
  1902. {
  1903. if(params.time>=params.length)
  1904. {
  1905. GetTransform(transform, m, rootEnd());
  1906. params.time-=params.length; if(params.time>=params.length) // if still greater than length, then it means we made more than 1 round (this is unlikely to happen, only when we play animations extremely fast)
  1907. {
  1908. Int rounds=Trunc(params.time/params.length);
  1909. params.time-=rounds*params.length;
  1910. transform.mulTimes(rounds, rootTransform());
  1911. }
  1912. GetRootMatrix(keys, m, params);
  1913. m.mul(_root_start_inv, rm); // this is "GetTransform(rm, rootStart(), m)"
  1914. transform*=rm;
  1915. return;
  1916. }else
  1917. if(params.time<0) // going back
  1918. {
  1919. GetTransform(transform, m, rootStart());
  1920. params.time+=params.length; if(params.time<0) // if still smaller than 0, then it means we made more than 1 round (this is unlikely to happen, only when we play animations extremely fast)
  1921. {
  1922. Int rounds=Floor(params.time/params.length);
  1923. params.time-=rounds*params.length;
  1924. transform.mulTimes(rounds, rootTransform());
  1925. }
  1926. GetRootMatrix(keys, m, params);
  1927. GetTransform(rm, rootEnd(), m);
  1928. transform*=rm;
  1929. return;
  1930. }
  1931. }
  1932. Matrix end; GetRootMatrix(keys, end, params); GetTransform(transform, m, end);
  1933. }
  1934. }
  1935. /******************************************************************************/
  1936. Animation& Animation::removeUnused()
  1937. {
  1938. REPA(bones)if(!bones[i].is())bones.remove(i);
  1939. return T;
  1940. }
  1941. /******************************************************************************
  1942. Animation& removeClones(); // remove bone animations which share the same name, keeping only one of them
  1943. Animation& Animation::removeClones()
  1944. {
  1945. REPA(bones)
  1946. REPD(j, i)if(Equal(bones[i].name, bones[j].name))
  1947. {
  1948. bones.remove(i);
  1949. break;
  1950. }
  1951. return T;
  1952. }
  1953. /******************************************************************************/
  1954. static Bool SameBone(C SkelBone *a, C SkelBone *b)
  1955. {
  1956. return !a && !b
  1957. || a && b && Equal(a->name, b->name);
  1958. }
  1959. static Bool SameSet(C SkelBone &a_child, C SkelBone &b_child, C SkelBone *a_parent, C SkelBone *b_parent) // this assumes that 'a_child' and 'b_child' are the same "SameBone(a_child, b_child)", and checks if their parents are the same, and children positions relative to their parents are also the same
  1960. {
  1961. if(SameBone(a_parent, b_parent))
  1962. return a_parent ? Equal(a_child.pos-a_parent->pos, b_child.pos-b_parent->pos)
  1963. : Equal(a_child.pos , b_child.pos );
  1964. return false;
  1965. }
  1966. Animation& Animation::adjustForSameSkeletonWithDifferentPose(C Skeleton &source, C Skeleton &target) // 'source' and 'target' are assumed to have the same names, this animation bones are also assumed to have the same names because this is typically called during importing
  1967. {
  1968. if(&source!=&target)
  1969. {
  1970. // adjust per-bone orientations (needed because some skeletons may have bones rotated already in the skeleton, not only in keyframes)
  1971. // this will only insert 1 orientation keyframe if skeleton bone orientations are different, it doesn't modify existing keyframes
  1972. REPA(target.bones) // for each bone in target skeleton
  1973. {
  1974. C SkelBone &bone_target =target.bones [ i];
  1975. Int bone_source_i =source.findBoneI(bone_target.name); // find the same bone in source skeleton
  1976. if( bone_source_i>=0)
  1977. {
  1978. C SkelBone &bone_source=source.bones[bone_source_i ];
  1979. AnimBone *abon = findBone (bone_target.name);
  1980. if(!abon || !abon->orns.elms()) // if doesn't have any target orientation keyframes
  1981. {
  1982. C SkelBone *old_parent=source.bones.addr(bone_source.parent),
  1983. *new_parent=target.bones.addr(bone_target.parent);
  1984. if(SameBone(old_parent, new_parent))
  1985. {
  1986. OrientD orient_source=bone_source; if(old_parent)orient_source.div(*old_parent, true); // convert to parent space
  1987. OrientD orient_target=bone_target; if(new_parent)orient_target.div(*new_parent, true); // convert to parent space
  1988. #define EPS_ANIM_COS_PRECISE 0.9999
  1989. if(Dot(orient_source.dir , orient_target.dir )<EPS_ANIM_COS_PRECISE
  1990. || Dot(orient_source.perp, orient_target.perp)<EPS_ANIM_COS_PRECISE)
  1991. {
  1992. AnimKeys::Orn &orn=getBone(bone_target.name, bone_target.type, bone_target.type_index, bone_target.type_sub).orns.New();
  1993. orn.time=0;
  1994. orn.orn =orient_source; // set the main target orientation keyframe
  1995. #if HAS_ANIM_TANGENT
  1996. orn.tan .zero();
  1997. #endif
  1998. }
  1999. }
  2000. }
  2001. }
  2002. }
  2003. // animate skeletons before modifying animation
  2004. AnimatedSkeleton skel_source; SkelAnim sa_source(source, T); skel_source.create(&source).clear().animateExactTime(sa_source, 0).updateMatrix();
  2005. AnimatedSkeleton skel_target; SkelAnim sa_target(target, T); skel_target.create(&target).clear().animateExactTime(sa_target, 0).updateMatrix();
  2006. // adjust per-bone position offsets (needed because some skeletons may have bones repositioned already in the skeleton, not only in keyframes)
  2007. // this will offset existing position keyframes if skeleton bone positions are different (if there are no keyfames then 1 is added)
  2008. REPA(target.bones) // for each bone in target skeleton
  2009. {
  2010. C SkelBone &bone_target =target.bones [ i];
  2011. Int bone_source_i =source.findBoneI(bone_target.name); // find the same bone in source skeleton
  2012. if( bone_source_i>=0)
  2013. {
  2014. C SkelBone &bone_source=source.bones[bone_source_i],
  2015. * old_parent=source.bones.addr(bone_source.parent),
  2016. * new_parent=target.bones.addr(bone_target.parent);
  2017. if(SameBone(old_parent, new_parent))
  2018. {
  2019. VecD pos_target=bone_target.pos; pos_target*=skel_target.bones[ i].matrix(); pos_target/=skel_target.boneRoot(bone_target.parent).matrix(); if(new_parent)pos_target.divNormalized(MatrixD(*new_parent)); // get transformed bone position, divide by parent animation matrix, divide by parent bone matrix
  2020. VecD pos_source=bone_source.pos; pos_source*=skel_source.bones[bone_source_i].matrix(); pos_source/=skel_source.boneRoot(bone_source.parent).matrix(); if(old_parent)pos_source.divNormalized(MatrixD(*old_parent)); // get transformed bone position, divide by parent animation matrix, divide by parent bone matrix
  2021. Vec delta =pos_source-pos_target;
  2022. if( delta.length2()>Sqr(EPS_ANIM_POS)) // if calculated delta is significant, then apply it to the animation bone
  2023. {
  2024. AnimBone &abon=getBone(bone_target.name, bone_target.type, bone_target.type_index, bone_target.type_sub);
  2025. if(!abon.poss.elms()) // if no position keyframes exist, then create an empty one
  2026. {
  2027. AnimKeys::Pos &pos=abon.poss.New();
  2028. pos.time=0;
  2029. pos.pos.zero();
  2030. #if HAS_ANIM_TANGENT
  2031. pos.tan.zero();
  2032. #endif
  2033. }
  2034. REPA(abon.poss)abon.poss[i].pos+=delta; // apply delta
  2035. }
  2036. }
  2037. }
  2038. }
  2039. //setTangents (); currently not needed since tangents don't change in this method
  2040. //setRootMatrix(); currently not needed since root keys aren't changed in this method
  2041. }
  2042. return T;
  2043. }
  2044. struct BoneWeight : IndexWeight
  2045. {
  2046. C SkelBone * bone;
  2047. C AnimSkelBone *asbone;
  2048. };
  2049. static Vec BoneWeightPos(C MemtN<BoneWeight, 4> &weights)
  2050. {
  2051. if(weights.elms()==1)return weights[0].asbone->matrix().pos;
  2052. Vec pos=0; REPA(weights){C BoneWeight &weight=weights[i]; pos+=weight.asbone->matrix().pos*weight.weight;} return pos;
  2053. }
  2054. static Matrix3 BoneWeightOrn(C MemtN<BoneWeight, 4> &weights)
  2055. {
  2056. if(weights.elms()==1)return weights[0].asbone->matrix().orn();
  2057. Vec scale=0;
  2058. Matrix3 matrix; matrix.zero();
  2059. REPA(weights)
  2060. {
  2061. C BoneWeight &weight=weights[i];
  2062. Flt w =weight.weight;
  2063. Matrix3 m =weight.asbone->matrix().orn();
  2064. Flt s=m.x.normalize(); scale.x+=s*w;
  2065. s=m.y.normalize(); scale.y+=s*w;
  2066. s=m.z.normalize(); scale.z+=s*w;
  2067. m*=w; matrix+=m;
  2068. }
  2069. matrix.x.setLength(scale.x);
  2070. matrix.y.setLength(scale.y);
  2071. matrix.z.setLength(scale.z);
  2072. return matrix;
  2073. }
  2074. static void DelRot(Orient &orn, UInt flag)
  2075. {
  2076. if(flag&ROOT_DEL_ROTATION)
  2077. {
  2078. if(FlagAll(flag, ROOT_DEL_ROTATION))orn.identity();else
  2079. {
  2080. MatrixD3 m=orn;
  2081. VecD axis=m.axisAngle(true);
  2082. if(flag&ROOT_DEL_ROTATION_X)axis.x=0;
  2083. if(flag&ROOT_DEL_ROTATION_Y)axis.y=0;
  2084. if(flag&ROOT_DEL_ROTATION_Z)axis.z=0;
  2085. if(Dbl angle=axis.normalize())orn=m.setRotate(axis, angle);else orn.identity();
  2086. }
  2087. }
  2088. }
  2089. static void DelRot(Animation &anim, UInt flag)
  2090. {
  2091. if(FlagAll(flag, ROOT_DEL_ROTATION))anim.keys.orns.del();else
  2092. {
  2093. Bool x=FlagTest(flag, ROOT_DEL_ROTATION_X),
  2094. y=FlagTest(flag, ROOT_DEL_ROTATION_Y),
  2095. z=FlagTest(flag, ROOT_DEL_ROTATION_Z);
  2096. REPA(anim.keys.orns)
  2097. {
  2098. Orient &orn=anim.keys.orns[i].orn;
  2099. MatrixD3 m=orn;
  2100. VecD axis=m.axisAngle(true);
  2101. if(x)axis.x=0;
  2102. if(y)axis.y=0;
  2103. if(z)axis.z=0;
  2104. if(Dbl angle=axis.normalize())orn=m.setRotate(axis, angle);else orn.identity();
  2105. }
  2106. anim.keys.setTangents(anim.loop(), anim.length());
  2107. }
  2108. }
  2109. Animation& Animation::adjustForSameTransformWithDifferentSkeleton(C Skeleton &old_skel, C Skeleton &new_skel, Int old_skel_bone_as_root, C MemPtr< Mems<IndexWeight> > &weights, UInt root_flags)
  2110. {
  2111. /*
  2112. 'old_skel' and 'new_skel' are assumed to have the same names when 'weights' are null (if 'weights' are not null, then their indexes are used as 'new_skel' -> 'old_skel' mapping, and names/types are ignored)
  2113. 'old_skel' and this Animation are assumed to have the same names when FIND_ANIM_BY_NAME_ONLY
  2114. Warning: this method should handle cases when bones are removed, for example:
  2115. 'old_skel':
  2116. "Spine0" BONE_SPINE 0
  2117. "Spine1" BONE_SPINE 1
  2118. "Spine2" BONE_SPINE 2
  2119. 'new_skel' is 'old_skel' with "Spine1" removed:
  2120. "Spine0" BONE_SPINE 0
  2121. "Spine2" BONE_SPINE 1
  2122. "Spine2" now has 'type_index' 1 the same as "Spine1" in 'old_skel'
  2123. The goal here is to preserve transforms (transformation matrixes applied to bones),
  2124. In order to do that, we calculate transforms applied to old skeleton bones,
  2125. and then we set the animations to make sure that they will trigger the same transforms on new skeleton bones.
  2126. */
  2127. Animation anim_out; anim_out.copyParams(T).events=events;
  2128. AnimSkel old_askel; old_askel.create(&old_skel); SkelAnim old_skela(old_skel, T);
  2129. AnimSkel new_askel; new_askel.create(&new_skel);
  2130. Memt<Flt, 16384> orn_times, pos_times, scale_times;
  2131. Bool root_not_changed =!InRange(old_skel_bone_as_root, old_skel.bones),
  2132. root_not_changed_post= true;
  2133. // process root
  2134. if(!root_not_changed)
  2135. {
  2136. C SkelBone &old_bone=old_skel .bones[old_skel_bone_as_root];
  2137. C AnimSkelBone &old_abon=old_askel.bones[old_skel_bone_as_root];
  2138. #if FIND_ANIM_BY_NAME_ONLY
  2139. C AnimBone *old_anim=findBone(old_bone.name);
  2140. #else
  2141. C AnimBone *old_anim=findBone(old_bone.name, old_bone.type, old_bone.type_index, old_bone.type_sub);
  2142. #endif
  2143. Bool no_parent=(old_skel.boneParent(old_skel_bone_as_root)<0); // bone has no parent
  2144. includeTimesForBoneAndItsParents(old_skel, old_skel_bone_as_root, orn_times, pos_times, scale_times);
  2145. // orientation
  2146. if(no_parent && !keys.orns.elms() && !keys.scales.elms()) // simple version
  2147. {
  2148. MatrixD3 old_bone_inv; old_bone.inverse(old_bone_inv);
  2149. anim_out.keys.orns.setNum(old_anim ? old_anim->orns.elms() : 0); REPA(anim_out.keys.orns)
  2150. {
  2151. C AnimKeys::Orn &src= old_anim->orns[i];
  2152. AnimKeys::Orn &orn=anim_out.keys.orns[i];
  2153. orn.time=src.time;
  2154. #if 0
  2155. orn.orn=GetTransform(old_bone, src.orn);
  2156. #else
  2157. MatrixD3 transform=old_bone_inv; transform*=MatrixD3(src.orn); orn.orn=transform;
  2158. #endif
  2159. }
  2160. }else // complex version
  2161. {
  2162. anim_out.keys.orns.setNum(orn_times.elms()); REPA(anim_out.keys.orns)
  2163. {
  2164. AnimKeys::Orn &orn=anim_out.keys.orns[i];
  2165. old_askel.clear().animateExactTime(old_skela, orn.time=orn_times[i]).updateMatrixParents(MatrixIdentity, old_skel_bone_as_root);
  2166. OrientD o=old_abon.matrix(); o.fix(); // root bone world orientation (identity transformed by bone transform) at the current time
  2167. orn.orn=o;
  2168. }
  2169. }
  2170. // scale
  2171. anim_out.keys.scales.setNum(scale_times.elms()); REPA(anim_out.keys.scales)
  2172. { // Warning: Scale conversion is not perfect, because scales are possible only on each axis separately, so if new bone is not rotated by 90 deg, then artifacts may occur
  2173. AnimKeys::Scale &scale=anim_out.keys.scales[i];
  2174. old_askel.clear().animateExactTime(old_skela, scale.time=scale_times[i]).updateMatrixParents(MatrixIdentity, old_skel_bone_as_root);
  2175. Vec old_scale(old_abon.matrix().x.length(),
  2176. old_abon.matrix().y.length(),
  2177. old_abon.matrix().z.length());
  2178. scale.scale=ScaleFactorR(old_scale);
  2179. }
  2180. // position
  2181. Bool root_zero; // if root position is zero
  2182. Vec root_pos;
  2183. if( root_flags&ROOT_BONE_POSITION){root_pos=old_bone.pos; root_zero=(root_pos.length2()<=Sqr(EPS));}
  2184. else root_zero=true;
  2185. if(no_parent && !keys.is() && root_zero) // no parent, no root keys, and root position is zero
  2186. {
  2187. if(old_anim)anim_out.keys.poss=old_anim->poss;
  2188. }else
  2189. {
  2190. IncludeTimes( orn_times, pos_times); // this bone and parent orientations affect this position
  2191. IncludeTimes(scale_times, pos_times); // this bone and parent scales affect this position
  2192. if(pos_times.elms())
  2193. {
  2194. anim_out.keys.poss.setNum(pos_times.elms()); REPA(anim_out.keys.poss)
  2195. {
  2196. AnimKeys::Pos &pos=anim_out.keys.poss[i];
  2197. old_askel.clear().animateExactTime(old_skela, pos.time=pos_times[i]).updateMatrixParents(MatrixIdentity, old_skel_bone_as_root);
  2198. pos.pos=(root_zero ? old_abon.matrix().pos // desired mesh transform offset
  2199. : root_pos*old_abon.matrix() ); // desired bone position
  2200. }
  2201. if(!root_zero)root_not_changed_post=false;
  2202. }
  2203. }
  2204. orn_times.clear();
  2205. scale_times.clear();
  2206. pos_times.clear();
  2207. anim_out.keys.setTangents(loop(), length());
  2208. anim_out.setRootMatrix();
  2209. }else
  2210. { // preserve root keys
  2211. anim_out. keys = keys ;
  2212. anim_out._root_start =_root_start ; anim_out._root_start_inv=_root_start_inv;
  2213. anim_out._root_end =_root_end ;
  2214. anim_out._root_transform=_root_transform;
  2215. }
  2216. MemtN<BoneWeight, 4> old_bones;
  2217. if(root_flags&ROOT_2_KEYS)
  2218. {
  2219. Bool changed=false;
  2220. if(anim_out.keys.poss.elms()>2)
  2221. {
  2222. anim_out.keys.poss.setNum(2);
  2223. anim_out.keys.poss[0].time= 0; anim_out.keys.poss[0].pos=anim_out.rootStart().pos;
  2224. anim_out.keys.poss[1].time=anim_out.length(); anim_out.keys.poss[1].pos=anim_out.rootEnd ().pos;
  2225. changed=true;
  2226. }
  2227. if(anim_out.keys.orns.elms()>2)
  2228. {
  2229. anim_out.keys.orns.setNum(2);
  2230. anim_out.keys.orns[0].time= 0; anim_out.keys.orns[0].orn=anim_out.rootStart(); anim_out.keys.orns[0].orn.fix();
  2231. anim_out.keys.orns[1].time=anim_out.length(); anim_out.keys.orns[1].orn=anim_out.rootEnd (); anim_out.keys.orns[1].orn.fix();
  2232. changed=true;
  2233. }
  2234. if(anim_out.keys.scales.elms()>2)
  2235. {
  2236. anim_out.keys.scales.setNum(2);
  2237. anim_out.keys.scales[0].time= 0; anim_out.keys.scales[0].scale=ScaleFactorR(anim_out.rootStart().scale());
  2238. anim_out.keys.scales[1].time=anim_out.length(); anim_out.keys.scales[1].scale=ScaleFactorR(anim_out.rootEnd ().scale());
  2239. changed=true;
  2240. }
  2241. if(changed)
  2242. {
  2243. anim_out.keys.setTangents(anim_out.loop(), anim_out.length());
  2244. //anim_out.setRootMatrix(); no need to call because it doesn't change
  2245. root_not_changed=root_not_changed_post=false;
  2246. }
  2247. }
  2248. if((root_flags&ROOT_START_IDENTITY) && anim_out.keys.is() && !Equal(anim_out.rootStart(), MatrixIdentity)) // !! adjust before ROOT_DEL !!
  2249. {
  2250. AnimParams params(anim_out, 0);
  2251. if(!anim_out.keys.scales.elms())
  2252. {
  2253. #if 0 // using Matrix
  2254. REPAO(anim_out.keys.poss).pos*=anim_out._root_start_inv;
  2255. REPAO(anim_out.keys.orns).orn*=anim_out._root_start_inv;
  2256. anim_out.keys.setTangents(anim_out.loop(), anim_out.length());
  2257. anim_out._root_start .identity();
  2258. anim_out._root_start_inv.identity();
  2259. anim_out._root_end =rootTransform();
  2260. //anim_out._root_transform=rootTransform(); remains the same
  2261. #else // using RevMatrix
  2262. REPA(anim_out.keys.orns){Orient &orn=anim_out.keys.orns[i].orn; orn=anim_out._root_start_inv.orn()*orn;}
  2263. #endif
  2264. }else
  2265. {
  2266. Matrix root_start_inv=anim_out.rootStart(); Vec root_start_scale=1/root_start_inv.scale(); root_start_inv.scaleOrnL(root_start_scale); root_start_inv.inverse(true);
  2267. REPA(anim_out.keys.orns ){Orient &orn =anim_out.keys.orns [i].orn ; orn=root_start_inv.orn()*orn;}
  2268. REPA(anim_out.keys.scales){Vec &scale=anim_out.keys.scales[i].scale; scale=ScaleFactorR(ScaleFactor(scale)*root_start_scale);}
  2269. }
  2270. REPA(anim_out.keys.poss){AnimKeys::Pos &pos=anim_out.keys.poss[i]; params.time=pos.time; Orient orn; if(!anim_out.keys.orn(orn, params) && !SET_ON_FAIL)orn.identity();else DelRot(orn, root_flags); pos.pos-=anim_out.rootStart().pos*orn;} // this needs to be done after adjusting orientations, it's better to delete rotations before adjusting positions, "this is needed to cast position on plane" for example if character body is rotating and moving, then this will try to cancel out movement through rotation, and just focus on the movement only
  2271. anim_out.keys.setTangents(anim_out.loop(), anim_out.length());
  2272. anim_out.setRootMatrix();
  2273. root_not_changed=root_not_changed_post=false;
  2274. }
  2275. if((root_flags&ROOT_DEL) && anim_out.keys.is()) // !! delete after ROOT_START_IDENTITY because it needs rotations and positions to perform adjustment !!
  2276. {
  2277. Bool changed=false;
  2278. if(FlagAll(root_flags, ROOT_DEL)){anim_out.keys.del(); changed=true;}else
  2279. {
  2280. if((root_flags&ROOT_DEL_POSITION) && anim_out.keys.poss.elms())
  2281. {
  2282. if(FlagAll(root_flags, ROOT_DEL_POSITION))anim_out.keys.poss.del();else
  2283. {
  2284. REPA(anim_out.keys.poss)
  2285. {
  2286. Vec &pos=anim_out.keys.poss[i].pos;
  2287. if(root_flags&ROOT_DEL_POSITION_X)pos.x=0;
  2288. if(root_flags&ROOT_DEL_POSITION_Y)pos.y=0;
  2289. if(root_flags&ROOT_DEL_POSITION_Z)pos.z=0;
  2290. }
  2291. anim_out.keys.setTangents(anim_out.loop(), anim_out.length());
  2292. }
  2293. changed=true;
  2294. }
  2295. if((root_flags&ROOT_DEL_ROTATION) && anim_out.keys.orns .elms()){DelRot(anim_out, root_flags ); changed=true;}
  2296. if((root_flags&ROOT_DEL_SCALE ) && anim_out.keys.scales.elms()){ anim_out.keys.scales.del() ; changed=true;}
  2297. }
  2298. if(changed)
  2299. {
  2300. anim_out.setRootMatrix();
  2301. root_not_changed=root_not_changed_post=false;
  2302. }
  2303. }
  2304. // process bones
  2305. FREPAD(new_bone_i, new_skel.bones) // process in order because when calculating this for children, we need to have parents already setup
  2306. {
  2307. C SkelBone &new_bone=new_skel.bones[new_bone_i];
  2308. // get all links from 'new_bone' to 'old_bones'
  2309. if(!weights)
  2310. {
  2311. Int old_bone_i=old_skel.findBoneI(new_bone.name); if(old_bone_i>=0)old_bones.New().set(old_bone_i, 1);
  2312. }else
  2313. if(InRange(new_bone_i, weights))
  2314. {
  2315. C Mems<IndexWeight> &weight=weights[new_bone_i]; FREPA(weight)
  2316. {
  2317. C IndexWeight &iw=weight[i]; if(InRange(iw.index, old_skel.bones))SCAST(IndexWeight, old_bones.New())=iw;
  2318. }
  2319. }
  2320. if(old_bones.elms()) // if there are any links
  2321. {
  2322. Flt weight_sum=0;
  2323. REPA(old_bones)
  2324. {
  2325. BoneWeight &bw=old_bones[i]; bw.bone=&old_skel.bones[bw.index]; bw.asbone=&old_askel.bones[bw.index]; weight_sum+=bw.weight; // set bone pointers and calculate total weight
  2326. }
  2327. REPAO(old_bones).weight/=weight_sum; // normalize weights
  2328. C SkelBone &old_bone =*old_bones[0].bone,
  2329. *new_parent=new_skel.bones.addr(new_bone.parent),
  2330. *old_parent=old_skel.bones.addr(old_bone.parent);
  2331. if(old_bones.elms()==1 && old_bones[0].index==old_skel_bone_as_root && !new_parent && root_not_changed_post) // if this new bone is made only from one old bone that is converted to root, and the new bone doesn't have any parents, and root wasn't post-changed
  2332. {
  2333. // we can just set identity orientation, because everything else will be handled by root
  2334. OrientD orient=new_bone; if(new_parent)orient.div(*new_parent, true); // convert to parent space
  2335. AnimBone &new_anim=anim_out.bones.New(); new_anim.id()=new_bone;
  2336. AnimKeys::Orn &orn=new_anim.orns.New();
  2337. orn.time=0;
  2338. orn.orn =orient;
  2339. #if HAS_ANIM_TANGENT
  2340. orn.tan .zero();
  2341. #endif
  2342. }else // we can do the simple version only if
  2343. if(old_bones.elms()==1 // bone maps to only 1 old bone
  2344. && SameSet(old_bone, new_bone, old_parent, new_parent) // it has the same set of bones/parents
  2345. && (old_parent || root_not_changed)) // and there are parents or (when there are no parents, which means that parent is root) we preserve root animations
  2346. {
  2347. #if FIND_ANIM_BY_NAME_ONLY
  2348. if(C AnimBone *old_anim=findBone(old_bone.name))
  2349. #else
  2350. if(C AnimBone *old_anim=findBone(old_bone.name, old_bone.type, old_bone.type_index, old_bone.type_sub))
  2351. #endif
  2352. {
  2353. OrientD new_bone_d=new_bone;
  2354. MatrixD3 old_bone_m=old_bone, old_bone_m_inv, old_parent_m, new_parent_m_inv; old_bone.inverse(old_bone_m_inv);
  2355. if(old_parent)old_parent_m=*old_parent;
  2356. if(new_parent)new_parent->inverse(new_parent_m_inv);
  2357. AnimBone &new_anim=anim_out.bones.New(); new_anim=*old_anim; new_anim.id()=new_bone;
  2358. REPA(new_anim.orns) // orientation
  2359. {
  2360. OrientD orn=new_anim.orns[i].orn;
  2361. if(old_parent)orn.mul(old_parent_m, true); // convert to world space from old parent space
  2362. MatrixD3 anim_transform;
  2363. #if 0
  2364. GetTransform(anim_transform, old_bone_m, MatrixD3(orn)); // transform which animates skel bone into animated bone
  2365. #else
  2366. anim_transform=old_bone_m_inv; anim_transform*=MatrixD3(orn); // transform which animates skel bone into animated bone
  2367. #endif
  2368. orn=new_bone_d; // get new bone
  2369. orn.mul(anim_transform, true); // apply animation transform
  2370. if(new_parent)orn.mul(new_parent_m_inv, true); // convert to new parent space
  2371. new_anim.orns[i].orn=orn;
  2372. }
  2373. REPA(new_anim.poss) // position
  2374. {
  2375. VecD pos=new_anim.poss[i].pos;
  2376. if(old_parent)pos*=old_parent_m ; // convert to world space from old parent space
  2377. if(new_parent)pos*=new_parent_m_inv; // convert to new parent space
  2378. new_anim.poss[i].pos=pos;
  2379. }
  2380. // scale
  2381. { // Warning: Scale conversion is not perfect, because scales are possible only on each axis separately, so if new bone is not rotated by 90 deg, then artifacts may occur
  2382. MatrixD3 new_bone_in_old_bone_space=new_bone_d; // get the new bone
  2383. new_bone_in_old_bone_space.divNormalized(old_bone_m); // put it into old bone space
  2384. REPA(new_anim.scales)
  2385. {
  2386. VecD scale=new_anim.scales[i].scale;
  2387. MatrixD3 scaled_new_bone=new_bone_in_old_bone_space;
  2388. scaled_new_bone.scale(ScaleFactor(scale)); // apply old bone scale (we're in old bone space, so scaling in XYZ scales along old bone cross perp and dir)
  2389. new_anim.scales[i].scale=ScaleFactorR(scaled_new_bone.scale()); // calculate new bone scale which is simply each axis length
  2390. }
  2391. }
  2392. new_anim.setTangents(loop(), length());
  2393. }
  2394. }else
  2395. {
  2396. REPA(old_bones)
  2397. for(Int old_parent_i=old_bones[i].index; ; ) // iterate all old parents until one of them is an ancestor of new bone
  2398. {
  2399. old_parent_i=old_skel.boneParent(old_parent_i); if(old_parent_i<0){keys.includeTimes(orn_times, pos_times, scale_times); break;}
  2400. C SkelBone &old_parent =old_skel.bones [old_parent_i];
  2401. #if FIND_ANIM_BY_NAME_ONLY
  2402. if(AnimBone *abon=findBone(old_parent.name))
  2403. #else
  2404. if(AnimBone *abon=findBone(old_parent.name, old_parent.type, old_parent.type_index, old_parent.type_sub))
  2405. #endif
  2406. abon->includeTimes(orn_times, pos_times, scale_times);
  2407. if(!weights)
  2408. {
  2409. Int new_parent_i=new_skel.findBoneI(old_parent.name);
  2410. if( new_parent_i>=0 && new_skel.contains(new_parent_i, new_bone_i))break; // if the parent contains the bone in the new skeleton
  2411. }else
  2412. {
  2413. Bool found=false; REPAD(new_parent_i, weights) // iterate all new bones to check which are connected to 'old_parent_i'
  2414. {
  2415. C Mems<IndexWeight> &weight=weights[new_parent_i]; REPA(weight)if(weight[i].index==old_parent_i) // if this bone points to 'old_parent_i'
  2416. {
  2417. if(!new_skel.contains(new_parent_i, new_bone_i))goto new_parent_not_contains_bone; // if at least one parent doesn't contain the bone, then stop this loop and keep checking next parents
  2418. found=true; // we've found bones connected with 'old_parent_i'
  2419. break;
  2420. }
  2421. }
  2422. if(found)break; // found a parent and all parents contain 'new_bone_i', so we can stop now
  2423. new_parent_not_contains_bone:;
  2424. }
  2425. }
  2426. for(Int new_parent_i=new_bone_i; ; ) // iterate all new parents until one of them is an ancestor of old bone
  2427. {
  2428. new_parent_i=new_skel.boneParent(new_parent_i); if(new_parent_i<0){anim_out.keys.includeTimes(orn_times, pos_times, scale_times); break;}
  2429. C SkelBone &new_parent =new_skel.bones [new_parent_i];
  2430. if(AnimBone *abon=anim_out.findBone(new_parent.name)) // here we're looking in 'anim_out' which already has names set according to 'new_skel'
  2431. abon->includeTimes(orn_times, pos_times, scale_times);
  2432. if(!weights)
  2433. {
  2434. Int old_parent_i=old_skel.findBoneI(new_parent.name);
  2435. if( old_parent_i>=0 && old_skel.contains(old_parent_i, old_bones[0].index))break; // if the parent contains the bone in the old skeleton
  2436. }else
  2437. if(InRange(new_parent_i, weights))
  2438. {
  2439. C Mems<IndexWeight> &parent_weights=weights[new_parent_i]; if(parent_weights.elms()) // if this bone has any links
  2440. {
  2441. REPA(parent_weights)
  2442. {
  2443. Int old_parent_i=parent_weights[i].index;
  2444. REPA(old_bones)if(!old_skel.contains(old_parent_i, old_bones[i].index))goto old_parent_not_contains_bone; // if at least one isn't contained, then stop this loop and keep checking next parents
  2445. }
  2446. break; // all 'old_bones' are contained in this parent, so we can stop now
  2447. old_parent_not_contains_bone:;
  2448. }
  2449. }
  2450. }
  2451. // step 1, normally this could be done after step 2, because this orientations/scales normally don't affect this positions, unless this bone was moved
  2452. REPA(old_bones)
  2453. {
  2454. C SkelBone &old_bone=*old_bones[i].bone;
  2455. #if FIND_ANIM_BY_NAME_ONLY
  2456. if(AnimBone *old_anim=findBone(old_bone.name))
  2457. #else
  2458. if(AnimBone *old_anim=findBone(old_bone.name, old_bone.type, old_bone.type_index, old_bone.type_sub))
  2459. #endif
  2460. old_anim->includeTimes(orn_times, pos_times, scale_times);
  2461. }
  2462. // step 2
  2463. IncludeTimes( orn_times, pos_times); // parent orientations affect this position
  2464. IncludeTimes(scale_times, pos_times); // parent scales affect this position
  2465. if(orn_times.elms() || pos_times.elms() || scale_times.elms())
  2466. {
  2467. C AnimSkelBone &new_abon=new_askel.bones[new_bone_i];
  2468. SkelAnim new_skela(new_skel, anim_out); // this needs to be created here and not once at the start, because we're dynamically adding new AnimBones to 'anim_out'
  2469. AnimBone *added=null, anim; anim.id()=new_bone;
  2470. Bool root_has_orn_scale=(anim_out.keys.orns.elms() || anim_out.keys.scales.elms());
  2471. if(orn_times.elms()) // orientation
  2472. {
  2473. MatrixD3 new_bone_m=new_bone, new_parent_m; if(new_parent)new_parent_m=*new_parent;
  2474. anim.orns.setNum(orn_times.elms()); REPA(anim.orns)
  2475. {
  2476. AnimKeys::Orn &orn=anim.orns[i]; orn.time=orn_times[i];
  2477. old_askel.clear().animateExactTime(old_skela, orn.time); if(old_bones.elms()==1)old_askel.updateMatrixParents(MatrixIdentity, old_bones[0].index);else old_askel.updateMatrix();
  2478. new_askel.clear().animateExactTime(new_skela, orn.time); new_askel.updateMatrixParents(MatrixIdentity, new_bone_i );
  2479. MatrixD3 new_bone_transformed=new_bone_m; new_bone_transformed*=BoneWeightOrn(old_bones); // bone world orientation at the current time
  2480. if(new_parent)
  2481. {
  2482. MatrixD3 new_parent_transformed=new_parent_m; new_parent_transformed*=new_askel.bones[new_bone.parent].matrix(); // parent bone world orientation at the current time
  2483. new_bone_transformed*=new_parent_transformed.inverseNonOrthogonal(); // new_bone_transformed/=new_parent_transformed with non-orthogonal support (needed because of possible scale keyframes)
  2484. }else
  2485. if(root_has_orn_scale)new_bone_transformed/=new_askel.root.matrix().orn();
  2486. OrientD o=new_bone_transformed; o.fix();
  2487. orn.orn=o;
  2488. }
  2489. orn_times.clear();
  2490. // add orientations to the animation only after everything was setup
  2491. anim.setTangents(loop(), length()); if(added)Swap(anim.orns, added->orns);else{added=&anim_out.bones.New(); Swap(anim, *added);}
  2492. new_skela.create(new_skel, anim_out); // need to re-create because we have added orientations
  2493. }
  2494. if(scale_times.elms()) // scale
  2495. {
  2496. anim.scales.setNum(scale_times.elms()); REPA(anim.scales)
  2497. { // Warning: Scale conversion is not perfect, because scales are possible only on each axis separately, so if new bone is not rotated by 90 deg, then artifacts may occur
  2498. AnimKeys::Scale &scale=anim.scales[i]; scale.time=scale_times[i];
  2499. old_askel.clear().animateExactTime(old_skela, scale.time); if(old_bones.elms()==1)old_askel.updateMatrixParents(MatrixIdentity, old_bones[0].index);else old_askel.updateMatrix();
  2500. new_askel.clear().animateExactTime(new_skela, scale.time); new_askel.updateMatrixParents(MatrixIdentity, new_bone_i);
  2501. Matrix3 old_abon_matrix___orn=BoneWeightOrn(old_bones);
  2502. Vec new_bone_cross=new_bone.cross(),
  2503. old_scale((new_bone_cross*old_abon_matrix___orn ).length(), // desired scale (yes here should be 'new_bone' too, because we want to calculate the scale for new bone using old transformation matrix)
  2504. (new_bone.perp *old_abon_matrix___orn ).length(),
  2505. (new_bone.dir *old_abon_matrix___orn ).length()),
  2506. new_scale((new_bone_cross*new_abon.matrix().orn()).length(), // current scale
  2507. (new_bone.perp *new_abon.matrix().orn()).length(),
  2508. (new_bone.dir *new_abon.matrix().orn()).length()),
  2509. rel_scale=old_scale/new_scale; // relative scale that should be applied
  2510. scale.scale=ScaleFactorR(rel_scale);
  2511. }
  2512. scale_times.clear();
  2513. // add scales to the animation only after everything was setup
  2514. anim.setTangents(loop(), length()); if(added)Swap(anim.scales, added->scales);else{added=&anim_out.bones.New(); Swap(anim, *added);}
  2515. new_skela.create(new_skel, anim_out); // need to re-create because we have added scales
  2516. }
  2517. if(pos_times.elms()) // position
  2518. {
  2519. MatrixD3 new_parent_m; if(new_parent)new_parent_m=*new_parent;
  2520. anim.poss.setNum(pos_times.elms()); REPA(anim.poss)
  2521. {
  2522. AnimKeys::Pos &pos=anim.poss[i]; pos.time=pos_times[i];
  2523. old_askel.clear().animateExactTime(old_skela, pos.time); if(old_bones.elms()==1)old_askel.updateMatrixParents(MatrixIdentity, old_bones[0].index);else old_askel.updateMatrix();
  2524. new_askel.clear().animateExactTime(new_skela, pos.time); new_askel.updateMatrixParents(MatrixIdentity, new_bone_i);
  2525. pos.pos=BoneWeightPos(old_bones) // desired mesh transform offset
  2526. -new_abon.matrix().pos; // current mesh transform offset
  2527. if(new_parent)
  2528. {
  2529. MatrixD3 new_parent_transformed=new_parent_m; new_parent_transformed*=new_askel.bones[new_bone.parent].matrix(); // parent bone world orientation at the current time
  2530. pos.pos*=new_parent_transformed.inverseNonOrthogonal(); // pos.pos/=new_parent_transformed with non-orthogonal support (needed because of possible scale keyframes)
  2531. }else
  2532. if(root_has_orn_scale)pos.pos/=new_askel.root.matrix().orn();
  2533. }
  2534. pos_times.clear();
  2535. // add positions to the animation only after everything was setup
  2536. anim.setTangents(loop(), length()); if(added)Swap(anim.poss, added->poss);else{added=&anim_out.bones.New(); Swap(anim, *added);}
  2537. //new_skela.create(new_skel, anim_out); // need to re-create because we have added orientations, won't be used for anything
  2538. }
  2539. }
  2540. }
  2541. old_bones.clear();
  2542. }
  2543. }
  2544. Swap(anim_out, T);
  2545. return T;
  2546. }
  2547. Animation& Animation::offsetRootBones(C Skeleton &skeleton, C Vec &move)
  2548. {
  2549. if(move.any())
  2550. {
  2551. AnimParams params(T, 0);
  2552. Memt<Flt, 16384> times;
  2553. Bool adjust_root=(true && keys.orns.elms()>1); // if adjust root positions too, because normally root is based on body movements relative to body start, when root has variable orientations, then 'move' depends on those orientations, so in that case body movement is variable based on current root orientation, so the body moves in different ways, and this allows to adjust the root movement to follow the body movement, this is needed only if root orientations change during animation, so check for more than 1 orientation keys
  2554. Orient orn;
  2555. Vec root_start, pos;
  2556. if(adjust_root)
  2557. {
  2558. keys.orn(orn, params); // this always succeeds because 'adjust_root' requires orientation keys to be available
  2559. root_start=move*orn;
  2560. }
  2561. REPA(skeleton.bones)
  2562. {
  2563. C SkelBone &sbon=skeleton.bones[i]; if(sbon.parent==0xFF)
  2564. {
  2565. AnimBone &abon=getBone(sbon.name, sbon.type, sbon.type_index, sbon.type_sub);
  2566. if(keys.orns.elms())
  2567. {
  2568. times.clear();
  2569. keys.includeTimes(times, null, null); // orientations from root
  2570. abon.includeTimes(null, times, null); // positions from bone
  2571. if(!times.elms())times.add(0);
  2572. Mems<AnimKeys::Pos> poss; poss.setNum(times.elms()); FREPA(poss)
  2573. {
  2574. AnimKeys::Pos &key=poss[i];
  2575. key.time=params.time=times[i];
  2576. if(keys.orn(orn, params))
  2577. {
  2578. if(adjust_root)
  2579. {
  2580. /*Vec root_offset=root_start - move*orn;
  2581. key.pos=move/orn - root_offset/orn; base formula adjusted by 'root_offset'
  2582. key.pos=move/orn - root_start/orn + move*orn/orn;
  2583. key.pos=(move-root_start)/orn + move;*/
  2584. key.pos.fromDivNormalized(move-root_start, orn)+=move;
  2585. }else
  2586. {
  2587. key.pos.fromDivNormalized(move, orn); // key.pos=move/orn; this is the base formula without 'adjust_root'
  2588. }
  2589. }else key.pos=move; // if there are no orientations then no need to check for 'adjust_root'
  2590. if(abon.pos(pos, params))key.pos+=pos;
  2591. }
  2592. Swap(abon.poss, poss);
  2593. abon.setTangents(loop(), length());
  2594. }else
  2595. {
  2596. if(!abon.poss.elms())
  2597. {
  2598. AnimKeys::Pos &key=abon.poss.New();
  2599. key.time=0;
  2600. key.pos =move;
  2601. }else
  2602. REPAO(abon.poss).pos+=move;
  2603. // tangents don't change
  2604. }
  2605. }
  2606. }
  2607. if(adjust_root)
  2608. {
  2609. times.clear();
  2610. keys.includeTimes(times, times, null); // orientations+positions from root
  2611. Mems<AnimKeys::Pos> poss; poss.setNum(times.elms()); FREPA(poss)
  2612. {
  2613. AnimKeys::Pos &key=poss[i];
  2614. key.time=params.time=times[i];
  2615. keys.orn(orn, params); // this always succeeds because 'adjust_root' requires orientation keys to be available
  2616. key.pos=root_start - move*orn; // this is 'root_offset'
  2617. if(keys.pos(pos, params))key.pos+=pos;
  2618. }
  2619. Swap(keys.poss, poss);
  2620. keys.setTangents(loop(), length());
  2621. setRootMatrix();
  2622. }
  2623. }
  2624. return T;
  2625. }
  2626. /******************************************************************************/
  2627. Animation& Animation::setBoneTypeIndexesFromSkeleton(C Skeleton &skeleton)
  2628. {
  2629. enum MODE
  2630. {
  2631. KEEP ,
  2632. CLEAR ,
  2633. REMOVE,
  2634. }mode=REMOVE;
  2635. REPA(bones)
  2636. {
  2637. AnimBone &bone=bones[i];
  2638. if(C SkelBone *sbon=skeleton.findBone(bone.name))bone.id()=*sbon;else switch(mode) // search only by name because we assume that types/indexes are invalid and need to be set
  2639. {
  2640. case REMOVE: bones.remove(i, true); break;
  2641. case CLEAR : bone .set(bone.name ); break; // clear to BONE_UNKNOWN
  2642. }
  2643. }
  2644. return T;
  2645. }
  2646. Bool Animation::setBoneNameTypeIndexesFromSkeleton(C Skeleton &skeleton)
  2647. {
  2648. Bool changed=false;
  2649. REPA(bones)
  2650. {
  2651. AnimBone &bone=bones[i];
  2652. if(C SkelBone *sbon=skeleton.findBone(bone.name, bone.type, bone.type_index, bone.type_sub)) // this should use names/types/indexes, because this method is called when we're changing animation from one skeleton to another
  2653. {
  2654. if(bone.id()!=sbon->id()){bone .id()=*sbon; changed=true;}
  2655. }else {bones.remove(i, true); changed=true;}
  2656. }
  2657. return changed;
  2658. }
  2659. /******************************************************************************/
  2660. Animation& Animation::reverse()
  2661. {
  2662. keys .reverse(length());
  2663. REPAO(bones).reverse(length());
  2664. return setRootMatrix();
  2665. }
  2666. Animation& Animation::sortFrames()
  2667. {
  2668. keys .sortFrames();
  2669. REPAO(bones).sortFrames();
  2670. return setRootMatrix();
  2671. }
  2672. Animation& Animation::setTangents()
  2673. {
  2674. keys .setTangents(loop(), length());
  2675. REPAO(bones).setTangents(loop(), length());
  2676. return T;
  2677. }
  2678. Animation& Animation::optimize(Flt angle_eps, Flt pos_eps, Flt scale_eps, Bool remove_unused_bones)
  2679. {
  2680. keys .optimize(loop(), linear(), length(), angle_eps, pos_eps, scale_eps, &Orient(Vec(0, 0, 1), Vec(0, 1, 0))); // we can remove default orientation for root
  2681. REPAO(bones).optimize(loop(), linear(), length(), angle_eps, pos_eps, scale_eps);
  2682. if(remove_unused_bones)removeUnused();
  2683. setRootMatrix();
  2684. return T;
  2685. }
  2686. Animation& Animation::clip(Flt start_time, Flt end_time, Bool remove_unused_bones)
  2687. {
  2688. //if(start_time!=0 || end_time!=length()) don't check this, because we may have keyframe data outside of this range that needs to be removed
  2689. {
  2690. if(end_time<start_time)Swap(start_time, end_time);
  2691. keys .clip(loop(), linear(), length(), start_time, end_time);
  2692. REPAO(bones).clip(loop(), linear(), length(), start_time, end_time);
  2693. if(remove_unused_bones)removeUnused();
  2694. _length=end_time-start_time;
  2695. setRootMatrix();
  2696. }
  2697. return T;
  2698. }
  2699. Bool Animation::timeRange(Flt &min, Flt &max)C
  2700. {
  2701. min= FLT_MAX;
  2702. max=-FLT_MAX;
  2703. Flt s, e; if(keys .timeRange(s, e)){MIN(min, s); MAX(max, e);}
  2704. REPA(bones )if(bones[i].timeRange(s, e)){MIN(min, s); MAX(max, e);}
  2705. REPA(events){ Flt t=events[i].time; MIN(min, t); MAX(max, t);}
  2706. if(min<=max)return true;
  2707. min=max=0; return false;
  2708. }
  2709. Animation& Animation::clipAuto()
  2710. {
  2711. Flt min, max; timeRange(min, max);
  2712. return clip(min, max);
  2713. }
  2714. Animation& Animation::maximizeLength()
  2715. {
  2716. Flt min, max; timeRange(min, max);
  2717. return length(Max(length(), max), false);
  2718. }
  2719. Animation& Animation::slideTime(Flt dt)
  2720. {
  2721. if(Flt time=Frac(-dt, length()))
  2722. {
  2723. if(1)
  2724. {
  2725. AnimParams params(T, time);
  2726. Matrix cur, transform, transform2, start=(1 ? MatrixIdentity : rootStart()); GetRootMatrix(keys, cur, params); GetTransform(transform, cur, start);
  2727. _root_start_inv.mul(rootEnd(), transform2); // this is "GetTransform(transform2, rootStart(), rootEnd())" can't just copy from 'rootTransform' because that's in 'RevMatrix' format, this converts from root start space to root end space
  2728. transform2*=transform; // this will additionally convert from 'cur' to 'start' space
  2729. #if DEBUG && 0
  2730. #pragma message("!! Warning: Use only for testing !!")
  2731. AnimKeys keys;
  2732. keys.poss.setNum(100);
  2733. keys.orns.setNum(100);
  2734. FREPA(keys.poss)
  2735. {
  2736. AnimKeys::Pos &pos=keys.poss[i];
  2737. AnimKeys::Orn &orn=keys.orns[i];
  2738. pos.time=orn.time=Lerp(0.0f, length(), i/99.0f);
  2739. Matrix m; getRootMatrixCumulative(m, pos.time+time);
  2740. m*=transform;
  2741. pos.pos=m.pos;
  2742. orn.orn=m.orn();
  2743. }
  2744. Swap(T.keys, keys);
  2745. #else
  2746. if(keys.orns.elms())
  2747. {
  2748. Memc<AnimKeys::Orn> orns; orns.reserve(keys.orns.elms());
  2749. Flt time_start=time+EPS, time_end=time+length()-EPS;
  2750. {AnimKeys::Orn &orn=orns.New(); orn.time=0; orn.orn=start.orn(); orn.orn.fix();} // add first key
  2751. FREPA(keys.orns) // add keys after 'time'
  2752. {
  2753. C AnimKeys::Orn &src=keys.orns[i]; if(src.time>time_start && src.time<time_end)
  2754. {
  2755. time_start=src.time+EPS; AnimKeys::Orn &orn=orns.New(); orn.time=src.time-time; orn.orn=src.orn*transform.orn(); orn.orn.fix();
  2756. }
  2757. }
  2758. time_start-=length();
  2759. time_end -=length();
  2760. FREPA(keys.orns) // add keys before 'time'
  2761. {
  2762. C AnimKeys::Orn &src=keys.orns[i]; if(src.time>time_start && src.time<time_end)
  2763. {
  2764. time_start=src.time+EPS; AnimKeys::Orn &orn=orns.New(); orn.time=src.time-time+length(); orn.orn=src.orn*transform2.orn(); orn.orn.fix();
  2765. }
  2766. }
  2767. {AnimKeys::Orn &orn=orns.New(); orn.time=length(); orn.orn=cur.orn()*transform2.orn(); orn.orn.fix();} // add last key
  2768. keys.orns=orns;
  2769. }
  2770. if(keys.poss.elms())
  2771. {
  2772. Memc<AnimKeys::Pos> poss; poss.reserve(keys.poss.elms());
  2773. Flt time_start=time+EPS, time_end=time+length()-EPS;
  2774. {AnimKeys::Pos &pos=poss.New(); pos.time=0; pos.pos=start.pos;} // add first key
  2775. FREPA(keys.poss) // add keys after 'time'
  2776. {
  2777. C AnimKeys::Pos &src=keys.poss[i]; if(src.time>time_start && src.time<time_end)
  2778. {
  2779. time_start=src.time+EPS; AnimKeys::Pos &pos=poss.New(); pos.time=src.time-time; pos.pos=src.pos*transform;
  2780. }
  2781. }
  2782. time_start-=length();
  2783. time_end -=length();
  2784. FREPA(keys.poss) // add keys before 'time'
  2785. {
  2786. C AnimKeys::Pos &src=keys.poss[i]; if(src.time>time_start && src.time<time_end)
  2787. {
  2788. time_start=src.time+EPS; AnimKeys::Pos &pos=poss.New(); pos.time=src.time-time+length(); pos.pos=src.pos*transform2;
  2789. }
  2790. }
  2791. {AnimKeys::Pos &pos=poss.New(); pos.time=length(); pos.pos=cur.pos*transform2;} // add last key
  2792. keys.poss=poss;
  2793. }
  2794. #endif
  2795. // TODO: Warning: here scale is ignored
  2796. keys.setTangents(loop(), length());
  2797. }else keys.slideTime(dt, length());
  2798. REPAO(bones).slideTime(dt, length());
  2799. setRootMatrix();
  2800. }
  2801. return T;
  2802. }
  2803. /******************************************************************************/
  2804. struct TimeScaleRange
  2805. {
  2806. Flt start_time, end_time, scale, delta, new_length, new_length_eps;
  2807. TimeScaleRange(Flt start_time, Flt end_time, Flt scale, Flt old_length)
  2808. {
  2809. T.start_time=start_time;
  2810. T. end_time= end_time;
  2811. T. scale= scale;
  2812. Flt old_duration=end_time-start_time,
  2813. new_duration=old_duration*scale;
  2814. T.delta=new_duration-old_duration;
  2815. T.new_length =old_length+delta;
  2816. T.new_length_eps=new_length-EPS;
  2817. }
  2818. void adjust(Flt &time)C
  2819. {
  2820. Flt t=time;
  2821. if(t>= end_time)t+=delta;else
  2822. if(t> start_time)t=(t-start_time)*scale+start_time; // this could be optimized into a single MulAdd however most likely it would lose precision
  2823. if(t>new_length_eps)t=new_length; // align to end, because looped root motion is calculated at time=0 and time=length, so if times are slightly offsetted, we could get root motion start that is actually end
  2824. time=t;
  2825. }
  2826. void adjust(AnimEvent &event)C {adjust(event.time);}
  2827. void adjust(AnimKeys &keys )C
  2828. {
  2829. REPA(keys.orns )adjust(keys.orns [i].time);
  2830. REPA(keys.poss )adjust(keys.poss [i].time);
  2831. REPA(keys.scales)adjust(keys.scales[i].time);
  2832. #if HAS_ANIM_ROT
  2833. REPA(keys.rots )adjust(keys.rots [i].time);
  2834. #endif
  2835. #if HAS_ANIM_COLOR
  2836. REPA(keys.colors)adjust(keys.colors[i].time);
  2837. #endif
  2838. }
  2839. };
  2840. Animation& Animation::scaleTime(Flt start_time, Flt end_time, Flt scale)
  2841. {
  2842. if(scale!=1 && scale>=0)
  2843. {
  2844. Clamp(start_time, 0, length());
  2845. Clamp( end_time, 0, length());
  2846. if(end_time>start_time)
  2847. {
  2848. TimeScaleRange ts(start_time, end_time, scale, length());
  2849. ts.adjust( keys);
  2850. REPA( bones)ts.adjust( bones[i]);
  2851. REPA(events)ts.adjust(events[i]);
  2852. length(ts.new_length, false);
  2853. }
  2854. }
  2855. return T;
  2856. }
  2857. /******************************************************************************/
  2858. Animation& Animation::scale(Flt scale)
  2859. {
  2860. keys .scale(scale);
  2861. REPAO(bones).scale(scale);
  2862. return setRootMatrix();
  2863. }
  2864. Animation& Animation::mirrorX()
  2865. {
  2866. keys .mirrorX();
  2867. REPAO(bones).mirrorX();
  2868. return setRootMatrix();
  2869. }
  2870. Animation& Animation::transform(C Matrix &matrix, C Skeleton &source)
  2871. {
  2872. // root
  2873. AnimParams anim_params(T, 0);
  2874. if(keys.orns.elms())
  2875. {
  2876. MatrixD3 matrix_dn=matrix, matrix_dn_inv; matrix_dn.normalize(); matrix_dn.inverse(matrix_dn_inv, true);
  2877. REPA(keys.orns)
  2878. {
  2879. Orient &orn=keys.orns[i].orn;
  2880. orn=matrix_dn_inv*MatrixD3(orn)*matrix_dn;
  2881. }
  2882. }
  2883. if(keys.orns.elms() && matrix.pos.any())
  2884. {
  2885. // if there are any orientations and matrix position offset, then we need to setup position keys from all orientation/position times
  2886. Memt<Flt, 16384> times; keys.includeTimes(times, times, null);
  2887. Mems<AnimKeys::Pos> poss; poss.setNum(times.elms()); // work on temporary container
  2888. REPA(poss)
  2889. {
  2890. AnimKeys::Pos &pos=poss[i]; anim_params.time=pos.time=times[i];
  2891. Orient orn; keys.orn( orn, anim_params);
  2892. if(!keys.pos(pos.pos, anim_params) && !SET_ON_FAIL)pos.pos.zero();
  2893. pos.pos*=matrix.orn();
  2894. pos.pos+=matrix.pos-matrix.pos*orn;
  2895. }
  2896. Swap(keys.poss, poss); // when finished, swap temp with actual
  2897. }else
  2898. {
  2899. REPAO(keys.poss).pos*=matrix.orn();
  2900. }
  2901. #if HAS_ANIM_ROT
  2902. ??
  2903. #endif
  2904. // bones
  2905. Flt scale =matrix.avgScale();
  2906. Matrix3 matrix_n=matrix; matrix_n.normalize();
  2907. REPA(bones)
  2908. {
  2909. AnimBone &abon =bones[i];
  2910. #if FIND_ANIM_BY_NAME_ONLY
  2911. Int sbon_index=source.findBoneI(abon.name);
  2912. #else
  2913. Int sbon_index=source.findBoneI(abon.name, abon.type, abon.type_index, abon.type_sub);
  2914. #endif
  2915. Bool main =(sbon_index>=0 && source.bones[sbon_index].parent==0xFF);
  2916. if(main)
  2917. {
  2918. REPAO(abon.orns).orn.mul(matrix_n, true);
  2919. #if HAS_ANIM_ROT
  2920. REPAO(abon.rots).rot*=matrix_n;
  2921. #endif
  2922. }
  2923. if(main && !keys.orns.elms()
  2924. #if HAS_ANIM_ROT
  2925. && !keys.rots.elms()
  2926. #endif
  2927. ) REPAO(abon.poss).pos*=matrix.orn(); // we can use precise scale only if there are no orientations in parents
  2928. else REPAO(abon.poss).pos*=scale ;
  2929. }
  2930. return setTangents().setRootMatrix();
  2931. }
  2932. Animation& Animation::rightToLeft(C Skeleton &source) // this method can ignore name differences because it's used only during importing while the names are the same
  2933. {
  2934. return transform(Matrix3().setRotateX(-PI_2), source).mirrorX();
  2935. }
  2936. static Str BoneNeutralName(C Str &name)
  2937. {
  2938. Str n=Replace(name, "right", CharAlpha);
  2939. n=Replace(n , "left" , CharAlpha);
  2940. n.replace('r', CharBeta).replace('l', CharBeta).replace('R', CharBeta).replace('L', CharBeta);
  2941. return n;
  2942. }
  2943. Animation& Animation::mirror(C Skeleton &source)
  2944. {
  2945. MemtN<Bool, 256> bone_remapped; bone_remapped.setNumZero(bones.elms());
  2946. REPA(bones)if(!bone_remapped[i])
  2947. {
  2948. bone_remapped[i]=true;
  2949. AnimBone &abon=bones[i]; Str name=BoneNeutralName(abon.name);
  2950. REPAD(s, source.bones)
  2951. {
  2952. C SkelBone &sbon=source.bones[s];
  2953. if(!Equal(abon.name, sbon.name) && name==BoneNeutralName(sbon.name))
  2954. {
  2955. REPD(j, i)if(!bone_remapped[j] && Equal(bones[j].name, sbon.name))
  2956. {
  2957. bone_remapped[j]=true;
  2958. Swap(abon.id(), bones[j].id());
  2959. goto finished;
  2960. }
  2961. abon.id()=sbon;
  2962. break;
  2963. }
  2964. }
  2965. finished:;
  2966. }
  2967. return mirrorX();
  2968. }
  2969. /******************************************************************************/
  2970. #if HAS_ANIM_ROT
  2971. Animation& Animation::convertRotToOrn(C Skeleton &skeleton) // this method can ignore name differences because it's used only during importing while the names are the same
  2972. {
  2973. SkelAnim skel_anim(skeleton, T);
  2974. keys .convertRotToOrn(skeleton, -1 , loop(), length());
  2975. REPAO(bones).convertRotToOrn(skeleton, skel_anim.abonToSbon(i), loop(), length());
  2976. return T;
  2977. }
  2978. Animation& Animation::convertOrnToRot(C Skeleton &skeleton) // this method can ignore name differences because it's used only during importing while the names are the same
  2979. {
  2980. SkelAnim skel_anim(skeleton, T);
  2981. keys .convertOrnToRot(skeleton, -1 , loop(), length());
  2982. REPAO(bones).convertOrnToRot(skeleton, skel_anim.abonToSbon(i), loop(), length());
  2983. return T;
  2984. }
  2985. #endif
  2986. /******************************************************************************/
  2987. void Animation::includeTimesForBoneAndItsParents(C Skeleton &skel, Int skel_bone, MemPtr<Flt, 16384> orn_times, MemPtr<Flt, 16384> pos_times, MemPtr<Flt, 16384> scale_times)C
  2988. {
  2989. if(InRange(skel_bone, skel.bones))for(;;)
  2990. {
  2991. C SkelBone &sbon=skel.bones[skel_bone];
  2992. #if FIND_ANIM_BY_NAME_ONLY
  2993. if(C AnimBone *abon=findBone(sbon.name))
  2994. #else
  2995. if(C AnimBone *abon=findBone(sbon.name, sbon.type, sbon.type_index, sbon.type_sub))
  2996. #endif
  2997. abon->includeTimes(orn_times, pos_times, scale_times);
  2998. if(sbon.parent>=skel_bone)break; // proceed only if the parent has a smaller index (this solves the issue of never ending loops with incorrect data)
  2999. skel_bone=sbon.parent;
  3000. }
  3001. keys.includeTimes(orn_times, pos_times, scale_times);
  3002. }
  3003. /******************************************************************************/
  3004. Animation& Animation::copyParams(C Animation &src)
  3005. {
  3006. T._length=src._length;
  3007. T._flag =src._flag ;
  3008. return T;
  3009. }
  3010. /******************************************************************************
  3011. static Int BonePriority(BONE_TYPE type, Int sub)
  3012. {
  3013. Int p;
  3014. switch(type) // prefer toes
  3015. {
  3016. default : return 0; // we don't want other types at all
  3017. case BONE_UPPER_LEG: p=1; break;
  3018. case BONE_LOWER_LEG: p=2; break;
  3019. case BONE_FOOT : p=3; break;
  3020. case BONE_TOE : p=4; sub=255-sub; break; // for toes actually prefer lower sub bones, to be closer to the foot
  3021. }
  3022. return p*256 + sub;
  3023. }
  3024. Flt calcMovement (C Skeleton &skel)C; // calculate how much does the skeleton move forward in this animation, calculation is done by analyzing the leg movement
  3025. Flt calcMovementSpeed(C Skeleton &skel)C; // calculate average skeleton forward movement speed in this animation, calculation is done by analyzing the leg movement
  3026. Flt Animation::calcMovementSpeed(C Skeleton &skel)C {return length() ? calcMovement(skel)/length() : 0;}
  3027. Flt Animation::calcMovement (C Skeleton &skel)C
  3028. {
  3029. Byte leg_bone[256]; // best bone for i-th leg, 0xFF if none
  3030. SetMem(leg_bone, 0xFF);
  3031. REPA(bones)
  3032. {
  3033. C SkelBone &new_bone=skel.bones[i];
  3034. if(Int new_bone_priority=BonePriority(new_bone.type, new_bone.type_sub)) // if this is a leg bone
  3035. {
  3036. Byte abs_index=(new_bone.type_index&0xFF); // convert to Byte, in case 'type_index' is SByte, using a Byte also guarantees that the index will fit in 'leg_bone' range
  3037. C SkelBone *old_bone =skel.bones.addr(leg_bone[abs_index]);
  3038. if(new_bone_priority>BonePriority(old_bone ? old_bone->type : BONE_UNKNOWN, old_bone ? old_bone->type_sub : 0)) // if new bone is better than the old one
  3039. leg_bone[abs_index]=i; // set this bone as the best bone for 'abs_index' leg
  3040. }
  3041. }
  3042. Flt movement=0;
  3043. // collect all leg bones at the start
  3044. Int leg_bones=0;
  3045. FREPA(leg_bone)if(leg_bone[i]!=0xFF)leg_bone[leg_bones++]=leg_bone[i];
  3046. if( leg_bones)
  3047. {
  3048. // get times for all legs and their parents
  3049. Memt<Flt, 16384> times;
  3050. times.add(0); // include first frame
  3051. REP(leg_bones)includeTimesForBoneAndItsParents(skel, leg_bone[i], times, times, times);
  3052. times.binaryInclude(length(), CompareEps); // include last frame
  3053. Flt bone_pos[256]; // bone positions
  3054. SkelAnim skel_anim(skel, T);
  3055. AnimSkel anim_skel; anim_skel.create(&skel);
  3056. FREPAD(frame, times) // animate forward
  3057. {
  3058. anim_skel.clear().animateExactTime(skel_anim, times[frame]).updateMatrix();
  3059. Flt frame_movement=0; // how much did legs move in this frame, we start with zero and maximize it by each leg, this avoids negative movement, max is used instead of average, for example zombie walk animation could have one leg not moving and just being dragged, and only other one doing the walking, averaging would make the movement smaller than it is
  3060. REPD(b, leg_bones) // iterate all legs
  3061. {
  3062. Int skel_bone_index=leg_bone[b]; // leg bone index in the skeleton
  3063. C SkelBone &skel_bone =skel.bones[skel_bone_index];
  3064. Vec anchor =((skel_bone.type==BONE_TOE) ? skel_bone.pos : skel_bone.to()); // for toes use the starting position, and for others use the target, this is because we're interested in the position which is in contact with the ground, and which "moves" the ground
  3065. Flt new_pos =(anchor*anim_skel.bones[skel_bone_index].matrix()).z,
  3066. &old_pos =bone_pos[b];
  3067. if(frame) // ignore first frame which was not set yet
  3068. MAX(frame_movement, old_pos-new_pos); // how much this bone moved back
  3069. old_pos=new_pos; // remember old position
  3070. }
  3071. movement+=frame_movement;
  3072. }
  3073. }
  3074. return movement;
  3075. }
  3076. /******************************************************************************/
  3077. void Animation::freezeBone(C Skeleton &skel, Int skel_bone)
  3078. {
  3079. if(InRange(skel_bone, skel.bones))
  3080. {
  3081. SkelAnim skel_anim(skel, T);
  3082. AnimSkel anim_skel; anim_skel.create(&skel);
  3083. C SkelBone & bone_sel= skel.bones[skel_bone];
  3084. C AnimSkelBone &abone_sel=anim_skel.bones[skel_bone];
  3085. Memt<Flt, 16384> bone_times; includeTimesForBoneAndItsParents(skel, skel_bone, bone_times, bone_times, bone_times);
  3086. anim_skel.clear().animateExactTime(skel_anim, 0).updateMatrix(); // animate first to get the 'start_pos'
  3087. Vec start_pos=bone_sel.pos*abone_sel.matrix();
  3088. // get root bones
  3089. Byte root_bone[256]; Int root_bones=0;
  3090. REPA(skel.bones)if(skel.bones[i].parent==0xFF){root_bone[root_bones++]=i; if(!InRange(root_bones, root_bone))break;}
  3091. Memt<AnimKeys, 32> root_bone_keys; root_bone_keys.setNum(root_bones);
  3092. Memt<Flt , 16384> root_times; // keep outside the loop to reduce overhead
  3093. REPD(rb, root_bones) // iterate all root bones
  3094. {
  3095. Int iroot= root_bone [rb];
  3096. C SkelBone & root= skel.bones[iroot];
  3097. C AnimSkelBone &aroot=anim_skel.bones[iroot];
  3098. AnimKeys & keys= root_bone_keys[rb];
  3099. root_times=bone_times;
  3100. #if FIND_ANIM_BY_NAME_ONLY
  3101. if(AnimBone *abon=findBone(root.name))
  3102. #else
  3103. if(AnimBone *abon=findBone(root.name, root.type, root.type_index, root.type_sub))
  3104. #endif
  3105. abon->includeTimes(null, root_times, null);
  3106. keys.poss.setNum(root_times.elms());
  3107. FREPAD(t, root_times) // irerate all frames
  3108. {
  3109. Flt time=root_times[t];
  3110. anim_skel.clear().animateExactTime(skel_anim, time).updateMatrix();
  3111. Vec cur_pos=bone_sel.pos*abone_sel.matrix(), delta=cur_pos-start_pos;
  3112. keys.poss[t].time=time;
  3113. keys.poss[t].pos =aroot.pos-delta;
  3114. }
  3115. keys.setTangents(loop(), length()).optimize(loop(), linear(), length());
  3116. }
  3117. // once all is ready, we need to store results in this animation, this can't be done before, because that would affect results of animating the skeleton
  3118. REPD(rb, root_bones)
  3119. {
  3120. Int iroot=root_bone [rb];
  3121. C SkelBone &root=skel.bones[iroot];
  3122. AnimKeys &keys=root_bone_keys[rb];
  3123. Swap(getBone(root.name, root.type, root.type_index, root.type_sub).poss, keys.poss); // swap only positions
  3124. }
  3125. }
  3126. }
  3127. /******************************************************************************/
  3128. Bool Animation::save(File &f)C
  3129. {
  3130. f.putMulti(UInt(CC4_ANIM), Byte(10), _flag, _length, _root_start, _root_end); // version
  3131. if(keys.saveData(f))
  3132. {
  3133. f.cmpUIntV(bones.elms()); FREPA(bones){C AnimBone &abon=bones[i]; f.putStr(abon.name).putMulti(abon.type, abon.type_index, abon.type_sub); if(!abon.saveData(f))return false;}
  3134. if(events.saveRaw(f))
  3135. return f.ok();
  3136. }
  3137. return false;
  3138. }
  3139. Bool Animation::load(File &f)
  3140. {
  3141. if(f.getUInt()==CC4_ANIM)switch(f.decUIntV()) // version
  3142. {
  3143. case 10:
  3144. {
  3145. f.getMulti(_flag, _length, _root_start, _root_end); setRootMatrix2();
  3146. if(!keys.loadData(f))goto error;
  3147. bones.setNum(f.decUIntV()); FREPA(bones){AnimBone &abon=bones[i]; f.getStr(abon.name).getMulti(abon.type, abon.type_index, abon.type_sub); if(!abon.loadData(f))goto error;}
  3148. if(!events.loadRaw(f))goto error;
  3149. if(f.ok())return true;
  3150. }break;
  3151. case 9:
  3152. {
  3153. f.getMulti(_flag, _length);
  3154. if(!keys.loadData(f))goto error;
  3155. bones.setNum(f.decUIntV()); FREPA(bones){AnimBone &abon=bones[i]; f.getStr(abon.name).getMulti(abon.type, abon.type_index, abon.type_sub); if(!abon.loadData(f))goto error;}
  3156. if(!events.loadRaw(f))goto error;
  3157. if(f.ok()){setRootMatrix(); return true;}
  3158. }break;
  3159. case 8:
  3160. {
  3161. f.getMulti(_flag, _length);
  3162. if(!keys.loadData(f))goto error;
  3163. bones.setNum(f.decUIntV()); FREPA(bones){AnimBone &abon=bones[i]; f._getStr2(abon.name).getMulti(abon.type, abon.type_index, abon.type_sub); if(!abon.loadData(f))goto error;}
  3164. if(!events.loadRaw(f))goto error;
  3165. if(f.ok()){setRootMatrix(); return true;}
  3166. }break;
  3167. case 7:
  3168. {
  3169. f>>_flag>>_length;
  3170. keys.loadData3(f);
  3171. bones.setNum(f.decUIntV()); FREPA(bones){AnimBone &abon=bones[i]; f._getStr2(abon.name).getMulti(abon.type, abon.type_index, abon.type_sub); abon.loadData3(f);}
  3172. if(!events.loadRaw(f))goto error;
  3173. if(f.ok()){setRootMatrix(); return true;}
  3174. }break;
  3175. case 6:
  3176. {
  3177. f>>_flag>>_length;
  3178. keys.loadData3(f);
  3179. bones.setNum(f.decUIntV()); FREPA(bones){AnimBone &abon=bones[i]; abon.set(null); f._getStr2(abon.name); abon.loadData3(f);}
  3180. if(!events.loadRaw(f))goto error;
  3181. if(f.ok()){setRootMatrix(); return true;}
  3182. }break;
  3183. case 5:
  3184. {
  3185. bones .setNum(f.getUShort());
  3186. events.setNum(f.getUShort());
  3187. _flag = f.getUShort() ;
  3188. f>>_length;
  3189. keys.loadData2(f);
  3190. FREPA(bones){AnimBone &abon=bones[i]; abon.set(null); f>>abon.name; abon.loadData2(f);}
  3191. f.getN(events.data(), events.elms());
  3192. if(f.ok()){setRootMatrix(); return true;}
  3193. }break;
  3194. case 4:
  3195. {
  3196. bones .setNum(f.getUShort());
  3197. events.setNum(f.getUShort());
  3198. _flag = f.getUShort() ;
  3199. f>>_length;
  3200. keys.loadData1(f);
  3201. FREPA(bones){AnimBone &abon=bones[i]; abon.set(null); f>>abon.name; abon.loadData1(f);}
  3202. f.getN(events.data(), events.elms());
  3203. if(f.ok()){setRootMatrix(); return true;}
  3204. }break;
  3205. case 3:
  3206. {
  3207. bones .setNum(f.getUShort());
  3208. events.setNum(f.getUShort());
  3209. _flag = f.getUShort() ;
  3210. f>>_length;
  3211. keys.loadData0(f);
  3212. FREPA(bones){AnimBone &abon=bones[i]; abon.set(null); f>>abon.name; abon.loadData0(f);}
  3213. f.getN(events.data(), events.elms());
  3214. if(f.ok()){setRootMatrix(); return true;}
  3215. }break;
  3216. case 2:
  3217. {
  3218. bones .setNum(f.getUShort());
  3219. events.setNum(f.getUShort());
  3220. _flag = f.getUShort() ;
  3221. f>>_length;
  3222. FREPA(bones)
  3223. {
  3224. AnimBone &abon=bones[i]; abon.set(null);
  3225. abon.orns.setNum(f.getUShort());
  3226. #if HAS_ANIM_ROT
  3227. Mems<AnimKeys::Rot> &rots=abon.rots.setNum(f.getUShort());
  3228. #else
  3229. Int rots=f.getUShort();
  3230. #endif
  3231. abon.poss.setNum(f.getUShort());
  3232. f.get(abon.name, 16); ASSERT(ELMS(abon.name)>=16);
  3233. LoadOrnTan(f, abon.orns);
  3234. LoadRotTan(f, rots);
  3235. LoadPosTan(f, abon.poss);
  3236. }
  3237. FREPA(events){AnimEvent &e=events[i]; f.get(e.name, 16); ASSERT(ELMS(e.name)>=16); f>>e.time;}
  3238. if(f.ok()){setRootMatrix(); return true;}
  3239. }break;
  3240. case 1:
  3241. {
  3242. f.skip(1); // old version byte
  3243. bones .setNum(f.getUShort());
  3244. events.setNum(f.getUShort());
  3245. _flag = f.getUShort() ;
  3246. f>>_length;
  3247. FREPA(bones)
  3248. {
  3249. AnimBone &abon=bones[i]; abon.set(null);
  3250. abon.orns.setNum(f.getUShort());
  3251. abon.poss.setNum(f.getUShort());
  3252. f.get(abon.name, 16); ASSERT(ELMS(abon.name)>=16);
  3253. LoadOrnTan(f, abon.orns);
  3254. LoadPosTan(f, abon.poss);
  3255. }
  3256. FREPA(events){AnimEvent &e=events[i]; f.get(e.name, 16); ASSERT(ELMS(e.name)>=16); f>>e.time;}
  3257. if(f.ok()){setRootMatrix(); return true;}
  3258. }break;
  3259. case 0:
  3260. {
  3261. f.skip(1); // old version byte
  3262. bones .setNum(f.getUShort());
  3263. events.setNum(f.getUShort());
  3264. _flag = f.getUShort() ;
  3265. f>>_length;
  3266. FREPA(bones)
  3267. {
  3268. AnimBone &abon=bones[i]; abon.set(null);
  3269. abon.orns.setNum(f.getUShort());
  3270. f.get(abon.name, 16); ASSERT(ELMS(abon.name)>=16);
  3271. LoadOrnTan(f, abon.orns);
  3272. }
  3273. FREPA(events){AnimEvent &e=events[i]; f.get(e.name, 16); ASSERT(ELMS(e.name)>=16); f>>e.time;}
  3274. if(f.ok()){setRootMatrix(); return true;}
  3275. }break;
  3276. }
  3277. error:
  3278. del(); return false;
  3279. }
  3280. /******************************************************************************/
  3281. Bool Animation::save(C Str &name)C
  3282. {
  3283. File f; if(f.writeTry(name)){if(save(f) && f.flush())return true; f.del(); FDelFile(name);}
  3284. return false;
  3285. }
  3286. Bool Animation::load(C Str &name)
  3287. {
  3288. File f; if(f.readTry(name))return load(f);
  3289. del(); return false;
  3290. }
  3291. void Animation::operator=(C UID &id ) {T=_EncodeFileName(id);}
  3292. void Animation::operator=(C Str &name)
  3293. {
  3294. if(!load(name))Exit(MLT(S+"Can't load Animation \"" +name+"\"",
  3295. PL,S+u"Nie można wczytać Animacji \""+name+"\""));
  3296. }
  3297. /******************************************************************************/
  3298. void Animation::save(MemPtr<TextNode> nodes)C
  3299. {
  3300. nodes.New().set("Linear", linear());
  3301. nodes.New().set("Loop" , loop ());
  3302. nodes.New().set("Length", length());
  3303. if( bones.elms()){TextNode &node=nodes.New(); node.name= "Bones"; FREPAO( bones).save(node.nodes.New());}
  3304. if(events.elms()){TextNode &node=nodes.New(); node.name="Events"; FREPAO(events).save(node.nodes.New());}
  3305. if( keys.is ()){TextNode &node=nodes.New(); node.name= "Keys"; keys .save(node );}
  3306. }
  3307. /******************************************************************************/
  3308. void XAnimation::save(MemPtr<TextNode> nodes)C
  3309. {
  3310. nodes.New().set("Name" , name );
  3311. nodes.New().set("FPS" , fps );
  3312. nodes.New().set("Start", start);
  3313. anim.save(nodes);
  3314. }
  3315. Bool XAnimation::save(File &f)C
  3316. {
  3317. f.cmpUIntV(0); // version
  3318. f<<fps<<start<<name;
  3319. if(anim.save(f))
  3320. return f.ok();
  3321. return false;
  3322. }
  3323. Bool XAnimation::load(File &f)
  3324. {
  3325. switch(f.decUIntV()) // version
  3326. {
  3327. case 0:
  3328. {
  3329. f>>fps>>start>>name;
  3330. if(anim.load(f))
  3331. if(f.ok())return true;
  3332. }break;
  3333. }
  3334. del(); return false;
  3335. }
  3336. Bool XAnimation::save(C Str &name)C
  3337. {
  3338. File f; if(f.writeTry(name)){if(save(f) && f.flush())return true; f.del(); FDelFile(name);}
  3339. return false;
  3340. }
  3341. Bool XAnimation::load(C Str &name)
  3342. {
  3343. File f; if(f.readTry(name))return load(f);
  3344. del(); return false;
  3345. }
  3346. /******************************************************************************/
  3347. // SKELETON ANIMATION
  3348. /******************************************************************************/
  3349. void SkelAnim::zero()
  3350. {
  3351. _bone =null;
  3352. _animation=null;
  3353. }
  3354. SkelAnim::SkelAnim() {zero();}
  3355. SkelAnim::SkelAnim(C Skeleton &skeleton, C Animation &animation) : SkelAnim() {create(skeleton, animation);}
  3356. SkelAnim::SkelAnim(C SkelAnim &src ) : SkelAnim() {T=src;}
  3357. void SkelAnim::operator=(C SkelAnim &src)
  3358. {
  3359. if(this!=&src)
  3360. {
  3361. del();
  3362. if(_animation=src._animation)
  3363. {
  3364. Int bones=_animation->bones.elms();
  3365. Alloc (_bone, bones);
  3366. CopyFastN(_bone, src._bone, bones);
  3367. }
  3368. }
  3369. }
  3370. SkelAnim& SkelAnim::del()
  3371. {
  3372. Free(_bone);
  3373. zero(); return T;
  3374. }
  3375. SkelAnim& SkelAnim::create(C Skeleton &skeleton, C Animation &animation)
  3376. {
  3377. T._animation=&animation;
  3378. Alloc(Free(_bone), animation.bones.elms());
  3379. REPA( animation.bones)
  3380. {
  3381. C AnimBone &abon=animation.bones[i];
  3382. Int sbon=skeleton .findBoneI(abon.name, abon.type, abon.type_index, abon.type_sub); // here we should always use names/types/indexes because we may share animation between multiple skeletons
  3383. _bone[i]=((sbon>=0) ? sbon : 0xFF);
  3384. }
  3385. return T;
  3386. }
  3387. Bool SkelAnim::load(C Str &name, Ptr user)
  3388. {
  3389. if(Animation *anim=Animations.get(name))
  3390. {
  3391. create(*(Skeleton*)user, *anim);
  3392. return true;
  3393. }
  3394. del(); return false;
  3395. }
  3396. Int SkelAnim::sbonToAbon(Int sbon)C
  3397. {
  3398. if(_animation && sbon>=0)REPA(_animation->bones)if(_bone[i]==sbon)return i;
  3399. return -1;
  3400. }
  3401. /******************************************************************************/
  3402. // MAIN
  3403. /******************************************************************************/
  3404. void ShutAnimation() {Skeletons.del(); Animations.del();}
  3405. /******************************************************************************/
  3406. }
  3407. /******************************************************************************/