AnimatedModel.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "AnimatedModel.h"
  25. #include "Animation.h"
  26. #include "AnimationState.h"
  27. #include "Camera.h"
  28. #include "Geometry.h"
  29. #include "IndexBuffer.h"
  30. #include "Log.h"
  31. #include "Material.h"
  32. #include "Octree.h"
  33. #include "OctreeQuery.h"
  34. #include "Profiler.h"
  35. #include "Renderer.h"
  36. #include "ReplicationUtils.h"
  37. #include "ResourceCache.h"
  38. #include "Scene.h"
  39. #include "StringUtils.h"
  40. #include "VertexBuffer.h"
  41. #include <algorithm>
  42. #include "DebugNew.h"
  43. static bool compareAnimationOrder(AnimationState* lhs, AnimationState* rhs)
  44. {
  45. return lhs->getPriority() < rhs->getPriority();
  46. }
  47. AnimatedModel::AnimatedModel(Octant* octant, const std::string& name) :
  48. StaticModel(NODE_ANIMATEDMODEL, octant, name),
  49. mAnimationLodDistance(0.0f),
  50. mAnimationLodFrameNumber(M_MAX_UNSIGNED),
  51. mAnimationLodBias(1.0f),
  52. mAnimationLodTimer(0.0f),
  53. mAnimationDirty(true),
  54. mAnimationOrderDirty(true),
  55. mMorphsDirty(true),
  56. mLocalAnimation(false)
  57. {
  58. }
  59. AnimatedModel::~AnimatedModel()
  60. {
  61. removeAllAnimationStates();
  62. }
  63. void AnimatedModel::save(Serializer& dest)
  64. {
  65. // Write GeometryNode properties
  66. GeometryNode::save(dest);
  67. // Write StaticModel properties
  68. dest.writeStringHash(getResourceHash(mModel));
  69. dest.writeVLE(mMaterials.size());
  70. for (unsigned i = 0; i < mMaterials.size(); ++i)
  71. dest.writeStringHash(getResourceHash(mMaterials[i]));
  72. // Write skeletal animation properties
  73. dest.writeFloat(mAnimationLodBias);
  74. dest.writeVLE(mAnimationStates.size());
  75. for (unsigned i = 0; i < mAnimationStates.size(); ++i)
  76. {
  77. AnimationState* state = mAnimationStates[i];
  78. state->save(dest);
  79. }
  80. // Write morph properties
  81. dest.writeVLE(mMorphs.size());
  82. for (unsigned i = 0; i < mMorphs.size(); ++i)
  83. dest.writeFloat(mMorphs[i].mWeight);
  84. }
  85. void AnimatedModel::load(Deserializer& source, ResourceCache* cache)
  86. {
  87. // Read GeometryNode properties
  88. GeometryNode::load(source, cache);
  89. // Read StaticModel properties
  90. // Note: can not use StaticModel::load() because we need to set the skeleton
  91. setModel(cache->getResource<Model>(source.readStringHash()));
  92. unsigned numMaterials = source.readVLE();
  93. for (unsigned i = 0; i < numMaterials; ++i)
  94. setMaterial(i, cache->getResource<Material>(source.readStringHash()));
  95. // Read skeletal animation properties
  96. mAnimationLodBias = source.readFloat();
  97. std::set<StringHash> processed;
  98. unsigned numAnimationStates = source.readVLE();
  99. for (unsigned i = 0; i < numAnimationStates; ++i)
  100. {
  101. StringHash animation = source.readStringHash();
  102. AnimationState* newState = addAnimationState(cache->getResource<Animation>(animation));
  103. newState->load(source);
  104. processed.insert(animation);
  105. }
  106. removeExtraAnimations(processed);
  107. // Read morph properties
  108. unsigned numMorphs = source.readVLE();
  109. for (unsigned i = 0; i < numMorphs; ++i)
  110. setMorphWeight(i, source.readFloat());
  111. }
  112. void AnimatedModel::saveXML(XMLElement& dest)
  113. {
  114. // Write GeometryNode properties
  115. GeometryNode::saveXML(dest);
  116. // Write StaticModel properties
  117. XMLElement modelElem = dest.createChildElement("model");
  118. modelElem.setString("name", getResourceName(mModel));
  119. for (unsigned i = 0; i < mMaterials.size(); ++i)
  120. {
  121. XMLElement materialElem = dest.createChildElement("material");
  122. materialElem.setInt("index", i);
  123. materialElem.setString("name", getResourceName(mMaterials[i]));
  124. }
  125. // Write skeletal animation properties
  126. XMLElement lodElem = dest.getChildElement("lod");
  127. lodElem.setFloat("animlodbias", mAnimationLodBias);
  128. for (unsigned i = 0; i < mAnimationStates.size(); ++i)
  129. {
  130. XMLElement animationElem = dest.createChildElement("animation");
  131. mAnimationStates[i]->saveXML(animationElem);
  132. }
  133. // Write morph properties
  134. for (unsigned i = 0; i < mMorphs.size(); ++i)
  135. {
  136. XMLElement morphElem = dest.createChildElement("morph");
  137. morphElem.setInt("index", i);
  138. morphElem.setFloat("weight", mMorphs[i].mWeight);
  139. }
  140. }
  141. void AnimatedModel::loadXML(const XMLElement& source, ResourceCache* cache)
  142. {
  143. // Read GeometryNode properties
  144. GeometryNode::loadXML(source, cache);
  145. // Read StaticModel properties
  146. // Note: can not use StaticModel::loadXML() because we need to set the skeleton
  147. XMLElement modelElem = source.getChildElement("model");
  148. setModel(cache->getResource<Model>(modelElem.getString("name")));
  149. XMLElement materialElem = source.getChildElement("material", false);
  150. while (materialElem.notNull())
  151. {
  152. unsigned index = materialElem.getInt("index");
  153. setMaterial(index, cache->getResource<Material>(materialElem.getString("name")));
  154. materialElem = materialElem.getNextElement("material");
  155. }
  156. // Read skeletal animation properties
  157. XMLElement lodElem = source.getChildElement("lod");
  158. mAnimationLodBias = lodElem.getFloat("animlodbias");
  159. removeAllAnimationStates();
  160. XMLElement animationElem = source.getChildElement("animation", false);
  161. while (animationElem.notNull())
  162. {
  163. AnimationState* newState = addAnimationState(cache->getResource<Animation>(animationElem.getString("name")));
  164. newState->loadXML(animationElem);
  165. animationElem = animationElem.getNextElement("animation");
  166. }
  167. // Read morph properties
  168. XMLElement morphElem = source.getChildElement("morph", false);
  169. while (morphElem.notNull())
  170. {
  171. unsigned index = morphElem.getInt("index");
  172. setMorphWeight(index, morphElem.getFloat("weight"));
  173. morphElem = morphElem.getNextElement("morph");
  174. }
  175. }
  176. bool AnimatedModel::writeNetUpdate(Serializer& dest, Serializer& destRevision, Deserializer& baseRevision, const NetUpdateInfo& info)
  177. {
  178. // Write GeometryNode properties and see if there were any changes
  179. bool prevBits = GeometryNode::writeNetUpdate(dest, destRevision, baseRevision, info);
  180. // Build bitmask of changed properties
  181. unsigned char bits = 0;
  182. // Model
  183. checkStringHash(getResourceHash(mModel), baseRevision, bits, 1);
  184. // Materials
  185. unsigned numBaseMaterials = baseRevision.getSize() ? baseRevision.readVLE() : 0;
  186. if (mMaterials.size() != numBaseMaterials)
  187. bits |= 2;
  188. for (unsigned i = 0; i < numBaseMaterials; ++i)
  189. {
  190. if (i < mMaterials.size())
  191. checkStringHash(getResourceHash(mMaterials[i]), baseRevision, bits, 2);
  192. else
  193. baseRevision.readStringHash();
  194. }
  195. // Animation LOD bias
  196. checkFloat(mAnimationLodBias, baseRevision, bits, 4);
  197. // Animations
  198. unsigned numBaseAnimations = baseRevision.getSize() ? baseRevision.readVLE() : 0;
  199. unsigned enabledAnimations = 0;
  200. if (mAnimationStates.size() != numBaseAnimations)
  201. bits |= 8;
  202. static std::vector<unsigned char> animBits;
  203. animBits.resize(mAnimationStates.size());
  204. // Assume that animations are new ie. require update of all fields
  205. for (unsigned i = 0; i < mAnimationStates.size(); ++i)
  206. {
  207. if (mAnimationStates[i]->isEnabled())
  208. {
  209. animBits[i] = 1 | 2 | 4 | 8 | 16;
  210. ++enabledAnimations;
  211. }
  212. else
  213. animBits[i] = 0;
  214. }
  215. for (unsigned i = 0; i < numBaseAnimations; ++i)
  216. {
  217. StringHash animation = baseRevision.readStringHash();
  218. StringHash startBone = baseRevision.readStringHash();
  219. bool looped = baseRevision.readBool();
  220. float weight = baseRevision.readFloat();
  221. float time = baseRevision.readFloat();
  222. int priority = baseRevision.readUByte();
  223. bool found = false;
  224. for (unsigned j = 0; j < mAnimationStates.size(); ++j)
  225. {
  226. AnimationState* state = mAnimationStates[j];
  227. if (state->getAnimation()->getNameHash() == animation)
  228. {
  229. // If animation exists in base state, update only the necessary properties
  230. found = true;
  231. // If zero weight (disabled), do not update anything
  232. if (!state->isEnabled())
  233. continue;
  234. animBits[j] = 0;
  235. if (startBone != state->getStartBone()->getNameHash())
  236. animBits[j] |= 1;
  237. if (looped != state->isLooped())
  238. animBits[j] |= 2;
  239. if (weight != state->getWeight())
  240. animBits[j] |= 4;
  241. if (time != state->getTime())
  242. animBits[j] |= 8;
  243. if (priority != state->getPriority())
  244. animBits[j] |= 16;
  245. if (animBits[j])
  246. bits |= 8;
  247. break;
  248. }
  249. }
  250. // If not found, the number of animations has stayed same, but the animations are different
  251. if (!found)
  252. bits |= 8;
  253. }
  254. // Morphs
  255. unsigned numBaseMorphs = baseRevision.getSize() ? baseRevision.readVLE() : 0;
  256. if (mMorphs.size() != numBaseMorphs)
  257. bits |= 16;
  258. for (unsigned i = 0; i < numBaseMorphs; ++i)
  259. {
  260. if (i < mMorphs.size())
  261. checkUByte((unsigned char)(mMorphs[i].mWeight * 255.0f), baseRevision, bits, 16);
  262. else
  263. baseRevision.readUByte();
  264. }
  265. // If local animation, do not send even if changed. It is slightly unoptimal to first check, then disable, but it ensures
  266. // that the base revision data stays the same (otherwise out of bounds reads might result when toggling local animation)
  267. if (mLocalAnimation)
  268. bits &= ~(8 | 16);
  269. // Update replication state fully, and network stream by delta
  270. dest.writeUByte(bits);
  271. writeStringHashDelta(getResourceHash(mModel), dest, destRevision, bits & 1);
  272. writeVLEDelta(mMaterials.size(), dest, destRevision, bits & 2);
  273. for (unsigned i = 0; i < mMaterials.size(); ++i)
  274. writeStringHashDelta(getResourceHash(mMaterials[i]), dest, destRevision, bits & 2);
  275. writeFloatDelta(mAnimationLodBias, dest, destRevision, bits & 4);
  276. // Write all animations to the base replication state
  277. destRevision.writeVLE(mAnimationStates.size());
  278. for (unsigned i = 0; i < mAnimationStates.size(); ++i)
  279. {
  280. AnimationState* state = mAnimationStates[i];
  281. destRevision.writeStringHash(state->getAnimation()->getNameHash());
  282. destRevision.writeStringHash(state->getStartBone()->getNameHash());
  283. destRevision.writeBool(state->isLooped());
  284. destRevision.writeFloat(state->getWeight());
  285. destRevision.writeFloat(state->getTime());
  286. destRevision.writeUByte(state->getPriority());
  287. }
  288. // Then write delta of enabled animations to the net stream
  289. if (bits & 8)
  290. {
  291. dest.writeVLE(enabledAnimations);
  292. for (unsigned i = 0; i < mAnimationStates.size(); ++i)
  293. {
  294. AnimationState* state = mAnimationStates[i];
  295. if (!state->isEnabled())
  296. continue;
  297. dest.writeStringHash(state->getAnimation()->getNameHash());
  298. dest.writeUByte(animBits[i]);
  299. if (animBits[i] & 1)
  300. dest.writeStringHash(state->getStartBone()->getNameHash());
  301. if (animBits[i] & 2)
  302. dest.writeBool(state->isLooped());
  303. if (animBits[i] & 4)
  304. dest.writeUByte((unsigned char)(state->getWeight() * 255.0f));
  305. if (animBits[i] & 8)
  306. dest.writeUShort((unsigned short)(state->getTime() * 65535.0f / state->getAnimation()->getLength()));
  307. if (animBits[i] & 16)
  308. dest.writeUByte(state->getPriority());
  309. }
  310. }
  311. writeVLEDelta(mMorphs.size(), dest, destRevision, bits & 16);
  312. for (unsigned i = 0; i < mMorphs.size(); ++i)
  313. writeUByteDelta((unsigned char)(mMorphs[i].mWeight * 255.0f), dest, destRevision, bits & 16);
  314. return prevBits || (bits != 0);
  315. }
  316. void AnimatedModel::readNetUpdate(Deserializer& source, ResourceCache* cache, const NetUpdateInfo& info)
  317. {
  318. // Read GeometryNode properties
  319. GeometryNode::readNetUpdate(source, cache, info);
  320. unsigned char bits = source.readUByte();
  321. if (bits & 1)
  322. setModel(cache->getResource<Model>(source.readStringHash()));
  323. if (bits & 2)
  324. {
  325. unsigned numMaterials = source.readVLE();
  326. for (unsigned i = 0; i < numMaterials; ++i)
  327. setMaterial(i, cache->getResource<Material>(source.readStringHash()));
  328. }
  329. readFloatDelta(mAnimationLodBias, source, bits & 4);
  330. if (bits & 8)
  331. {
  332. unsigned numAnimations = source.readVLE();
  333. std::set<StringHash> processed;
  334. for (unsigned i = 0; i < numAnimations; ++i)
  335. {
  336. StringHash animation = source.readStringHash();
  337. unsigned char animBits = source.readUByte();
  338. processed.insert(animation);
  339. // Find the animation state. If not found, create new
  340. AnimationState* state = getAnimationState(animation);
  341. bool newState = false;
  342. if (!state)
  343. {
  344. state = addAnimationState(cache->getResource<Animation>(animation));
  345. newState = true;
  346. }
  347. if (state)
  348. {
  349. if (animBits & 1)
  350. state->setStartBone(mSkeleton.getBone(source.readStringHash()));
  351. if (animBits & 2)
  352. state->setLooped(source.readBool());
  353. if (animBits & 4)
  354. state->setWeight(source.readUByte() / 255.0f);
  355. if (animBits & 8)
  356. state->setTime(source.readUShort() * state->getAnimation()->getLength() / 65535.0f);
  357. if (animBits & 16)
  358. state->setPriority(source.readUByte());
  359. // If state is new, interpolate directly to the end
  360. if (newState)
  361. state->interpolate(true, mEntity->getScene()->getInterpolationLerpFactor());
  362. }
  363. else
  364. {
  365. // If state could not be added, just read the data to avoid desyncing the stream
  366. if (animBits & 1)
  367. source.readStringHash();
  368. if (animBits & 2)
  369. source.readBool();
  370. if (animBits & 4)
  371. source.readUByte();
  372. if (animBits & 8)
  373. source.readUShort();
  374. if (animBits & 16)
  375. source.readUByte();
  376. }
  377. }
  378. removeExtraAnimations(processed);
  379. }
  380. if (bits & 16)
  381. {
  382. unsigned numMorphs = source.readVLE();
  383. for (unsigned i = 0; i < numMorphs; ++i)
  384. setMorphWeight(i, source.readUByte() / 255.0f);
  385. }
  386. }
  387. void AnimatedModel::interpolate(bool snapToEnd)
  388. {
  389. Node::interpolate(snapToEnd);
  390. float t = mEntity->getScene()->getInterpolationLerpFactor();
  391. for (std::vector<AnimationState*>::iterator i = mAnimationStates.begin(); i != mAnimationStates.end(); ++i)
  392. (*i)->interpolate(snapToEnd, t);
  393. }
  394. void AnimatedModel::processRayQuery(RayOctreeQuery& query, float initialDistance)
  395. {
  396. // If no bones or no bone-level testing, use the GeometryNode test
  397. if ((!mSkeleton.getNumBones()) || (query.mLevel < RAY_AABB))
  398. {
  399. GeometryNode::processRayQuery(query, initialDistance);
  400. return;
  401. }
  402. PROFILE(AnimatedModel_Raycast);
  403. const std::vector<SharedPtr<Bone> >& bones = mSkeleton.getBones();
  404. Sphere boneSphere;
  405. RayQueryLevel level = query.mLevel;
  406. for (unsigned i = 0; i < bones.size(); ++i)
  407. {
  408. Bone* bone = bones[i];
  409. unsigned collisionMask = bone->getCollisionMask();
  410. // Use hitbox if available
  411. if (collisionMask & BONECOLLISION_BOX)
  412. {
  413. // Do an initial crude test using the bone's AABB
  414. const Matrix4x3& transform = bone->getWorldTransform();
  415. const BoundingBox& box = bone->getBoundingBox();
  416. float distance = box.getTransformed(transform).getDistance(query.mRay);
  417. if (distance < query.mMaxDistance)
  418. {
  419. if (level == RAY_AABB)
  420. {
  421. RayQueryResult result;
  422. result.mNode = this;
  423. result.mDistance = distance;
  424. result.mSubObject = i;
  425. query.mResult.push_back(result);
  426. }
  427. else
  428. {
  429. // Follow with an OBB test if required
  430. Matrix4x3 inverse = transform.getInverse();
  431. Ray localRay(inverse * query.mRay.mOrigin, inverse * Vector4(query.mRay.mDirection, 0.0f));
  432. distance = box.getDistance(localRay);
  433. if (distance < query.mMaxDistance)
  434. {
  435. RayQueryResult result;
  436. result.mNode = this;
  437. result.mDistance = distance;
  438. result.mSubObject = i;
  439. query.mResult.push_back(result);
  440. }
  441. }
  442. }
  443. }
  444. else if (collisionMask & BONECOLLISION_SPHERE)
  445. {
  446. boneSphere.mCenter = bone->getWorldPosition();
  447. boneSphere.mRadius = bone->getRadius();
  448. float distance = boneSphere.getDistance(query.mRay);
  449. if (distance < query.mMaxDistance)
  450. {
  451. RayQueryResult result;
  452. result.mNode = this;
  453. result.mSubObject = i;
  454. result.mDistance = distance;
  455. query.mResult.push_back(result);
  456. }
  457. }
  458. }
  459. }
  460. void AnimatedModel::updateNode(const FrameInfo& frame)
  461. {
  462. // Update animation here
  463. if ((!mAnimationDirty) && (!mAnimationOrderDirty))
  464. return;
  465. // If node was invisible last frame, need to decide animation LOD distance here
  466. // If headless, retain the current animation distance (should be 0)
  467. if ((frame.mCamera) && (abs((int)frame.mFrameNumber - (int)mAnimationLodFrameNumber) > 1))
  468. {
  469. float distance = frame.mCamera->getDistance(getWorldPosition());
  470. // If distance is greater than draw distance, no need to update at all
  471. if ((mDrawDistance != 0.0f) && (distance > mDrawDistance))
  472. return;
  473. // Multiply the distance by 2 so that invisible nodes don't update that often
  474. static const Vector3 dotScale(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
  475. float scale = getWorldScale().dotProduct(dotScale);
  476. mAnimationLodDistance = frame.mCamera->getLodDistance(2.0f * distance, scale, mLodBias);
  477. }
  478. updateAnimation(frame);
  479. }
  480. void AnimatedModel::updateDistance(const FrameInfo& frame)
  481. {
  482. mDistance = frame.mCamera->getDistance(getWorldPosition());
  483. static const Vector3 dotScale(1 / 3.0f, 1 / 3.0f, 1 / 3.0f);
  484. float scale = getWorldScale().dotProduct(dotScale);
  485. float newLodDistance = frame.mCamera->getLodDistance(mDistance, scale, mLodBias);
  486. // If model is rendered from several views, use the minimum LOD distance for animation LOD
  487. if (frame.mFrameNumber != mAnimationLodFrameNumber)
  488. {
  489. mAnimationLodDistance = newLodDistance;
  490. mAnimationLodFrameNumber = frame.mFrameNumber;
  491. }
  492. else
  493. mAnimationLodDistance = min(mAnimationLodDistance, newLodDistance);
  494. if (newLodDistance != mLodDistance)
  495. {
  496. mLodDistance = newLodDistance;
  497. mLodLevelsDirty = true;
  498. }
  499. }
  500. void AnimatedModel::updateGeometry(const FrameInfo& frame, Renderer* renderer)
  501. {
  502. if (mLodLevelsDirty)
  503. calculateLodLevels();
  504. if ((mMorphsDirty) && (mMorphs.size()))
  505. updateMorphs();
  506. if ((mSkeleton.getNumBones()) && (mSkeleton.getRootBone()->isSkinningDirty()))
  507. updateSkinning();
  508. }
  509. bool AnimatedModel::getVertexShaderParameter(unsigned batchIndex, VSParameter parameter, const float** data, unsigned* count)
  510. {
  511. if ((parameter == VSP_MODELSKINMATRICES) && (mSkinMatrices.size()))
  512. {
  513. // Check if model has per-geometry bone mappings
  514. if ((mGeometrySkinMatrices.size()) && (mGeometrySkinMatrices[batchIndex].size()))
  515. {
  516. *count = mGeometrySkinMatrices[batchIndex].size() * 12;
  517. *data = mGeometrySkinMatrices[batchIndex][0].getData();
  518. }
  519. // If not, use the global skin matrices
  520. else
  521. {
  522. *count = mSkinMatrices.size() * 12;
  523. *data = mSkinMatrices[0].getData();
  524. }
  525. return true;
  526. }
  527. return false;
  528. }
  529. bool AnimatedModel::setModel(Model* model)
  530. {
  531. if (model == mModel)
  532. return true;
  533. PROFILE(AnimatedModel_SetModel);
  534. if (!model)
  535. {
  536. LOGERROR("Null model for AnimatedModel");
  537. return false;
  538. }
  539. mModel = model;
  540. // Copy the subgeometry & LOD level structure
  541. setNumGeometries(model->getNumGeometries());
  542. const std::vector<std::vector<SharedPtr<Geometry> > >& geometries = model->getGeometries();
  543. for (unsigned i = 0; i < geometries.size(); ++i)
  544. mGeometries[i] = geometries[i];
  545. // Copy geometry bone mappings
  546. const std::vector<std::vector<unsigned> >& geometryBoneMappings = model->getGeometryBoneMappings();
  547. mGeometryBoneMappings.clear();
  548. for (unsigned i = 0; i < geometryBoneMappings.size(); ++i)
  549. mGeometryBoneMappings.push_back(geometryBoneMappings[i]);
  550. // Copy morphs
  551. mMorphVertexBuffers.clear();
  552. mMorphs.clear();
  553. const std::vector<ModelMorph>& morphs = model->getMorphs();
  554. for (unsigned i = 0; i < morphs.size(); ++i)
  555. {
  556. ModelMorph newMorph;
  557. newMorph.mName = morphs[i].mName;
  558. newMorph.mNameHash = morphs[i].mNameHash;
  559. newMorph.mWeight = 0.0f;
  560. newMorph.mBuffers = morphs[i].mBuffers;
  561. mMorphs.push_back(newMorph);
  562. }
  563. // If model has morphs, must clone all geometries & vertex buffers that refer to morphable vertex data
  564. if (morphs.size())
  565. {
  566. cloneGeometries();
  567. markMorphsDirty();
  568. }
  569. // Copy bounding box & skeleton
  570. setBoundingBox(model->getBoundingBox());
  571. setSkeleton(model->getSkeleton());
  572. return true;
  573. }
  574. AnimationState* AnimatedModel::addAnimationState(Animation* animation)
  575. {
  576. if (!animation)
  577. return 0;
  578. if (!mSkeleton.getNumBones())
  579. {
  580. LOGERROR("Animations can not be added to a model without skeleton");
  581. return 0;
  582. }
  583. // Check for not adding twice
  584. AnimationState* existing = getAnimationState(animation);
  585. if (existing)
  586. return existing;
  587. AnimationState* newState = new AnimationState(this, animation);
  588. mAnimationStates.push_back(newState);
  589. markAnimationOrderDirty();
  590. return newState;
  591. }
  592. void AnimatedModel::removeAnimationState(Animation* animation)
  593. {
  594. if (animation)
  595. removeAnimationState(animation->getNameHash());
  596. }
  597. void AnimatedModel::removeAnimationState(const std::string& animationName)
  598. {
  599. removeAnimationState(StringHash(animationName));
  600. }
  601. void AnimatedModel::removeAnimationState(StringHash animationNameHash)
  602. {
  603. for (std::vector<AnimationState*>::iterator i = mAnimationStates.begin(); i != mAnimationStates.end(); ++i)
  604. {
  605. AnimationState* state = *i;
  606. Animation* animation = state->getAnimation();
  607. // Check both the animation and the resource name
  608. if ((animation->getNameHash() == animationNameHash) || (animation->getAnimationNameHash() == animationNameHash))
  609. {
  610. // If animation is still interpolating, do not remove immediately, but set target weight to zero
  611. if ((isProxy()) && (state->isInterpolating()))
  612. state->setWeight(0.0f);
  613. else
  614. {
  615. delete state;
  616. mAnimationStates.erase(i);
  617. markAnimationDirty();
  618. }
  619. return;
  620. }
  621. }
  622. }
  623. void AnimatedModel::removeAnimationState(AnimationState* state)
  624. {
  625. for (std::vector<AnimationState*>::iterator i = mAnimationStates.begin(); i != mAnimationStates.end(); ++i)
  626. {
  627. if (*i == state)
  628. {
  629. // If animation is still interpolating, do not remove immediately, but set target weight to zero
  630. if ((isProxy()) && (state->isInterpolating()))
  631. state->setWeight(0.0f);
  632. else
  633. {
  634. delete state;
  635. mAnimationStates.erase(i);
  636. markAnimationDirty();
  637. }
  638. return;
  639. }
  640. }
  641. }
  642. void AnimatedModel::removeAllAnimationStates()
  643. {
  644. for (std::vector<AnimationState*>::iterator i = mAnimationStates.begin(); i != mAnimationStates.end(); ++i)
  645. delete *i;
  646. mAnimationStates.clear();
  647. markAnimationDirty();
  648. }
  649. void AnimatedModel::setAnimationLodBias(float bias)
  650. {
  651. mAnimationLodBias = max(bias, 0.0f);
  652. }
  653. void AnimatedModel::setMorphWeight(unsigned index, float weight)
  654. {
  655. if (index >= mMorphs.size())
  656. return;
  657. weight = clamp(weight, 0.0f, 1.0f);
  658. if (weight != mMorphs[index].mWeight)
  659. {
  660. mMorphs[index].mWeight = weight;
  661. markMorphsDirty();
  662. }
  663. }
  664. void AnimatedModel::setMorphWeight(const std::string& name, float weight)
  665. {
  666. weight = clamp(weight, 0.0f, 1.0f);
  667. for (std::vector<ModelMorph>::iterator i = mMorphs.begin(); i != mMorphs.end(); ++i)
  668. {
  669. if (i->mName == name)
  670. {
  671. if (weight != i->mWeight)
  672. {
  673. i->mWeight = weight;
  674. markMorphsDirty();
  675. }
  676. return;
  677. }
  678. }
  679. }
  680. void AnimatedModel::setMorphWeight(StringHash nameHash, float weight)
  681. {
  682. weight = clamp(weight, 0.0f, 1.0f);
  683. for (std::vector<ModelMorph>::iterator i = mMorphs.begin(); i != mMorphs.end(); ++i)
  684. {
  685. if (i->mNameHash == nameHash)
  686. {
  687. if (weight != i->mWeight)
  688. {
  689. i->mWeight = weight;
  690. markMorphsDirty();
  691. }
  692. return;
  693. }
  694. }
  695. }
  696. void AnimatedModel::resetMorphWeights()
  697. {
  698. for (std::vector<ModelMorph>::iterator i = mMorphs.begin(); i != mMorphs.end(); ++i)
  699. i->mWeight = 0.0f;
  700. markMorphsDirty();
  701. }
  702. void AnimatedModel::syncAnimation(AnimatedModel* srcNode)
  703. {
  704. if (!srcNode)
  705. return;
  706. // Make sure the animation proceeds at the same rate as in the source
  707. mAnimationLodBias = srcNode->mAnimationLodBias;
  708. mAnimationLodDistance = srcNode->mAnimationLodDistance;
  709. mAnimationLodFrameNumber = srcNode->mAnimationLodFrameNumber;
  710. const std::vector<AnimationState*>& srcStates = srcNode->getAnimationStates();
  711. std::set<Animation*> srcAnimations;
  712. for (unsigned i = 0; i < srcStates.size(); ++i)
  713. {
  714. AnimationState* src = srcStates[i];
  715. Animation* anim = src->getAnimation();
  716. srcAnimations.insert(anim);
  717. AnimationState* dest = getAnimationState(anim);
  718. if (!dest)
  719. dest = addAnimationState(anim);
  720. dest->sync(src);
  721. }
  722. // Check for extra states in destination and remove them
  723. if (mAnimationStates.size() > srcStates.size())
  724. {
  725. for (unsigned i = 0; i < mAnimationStates.size(); ++i)
  726. {
  727. AnimationState* state = mAnimationStates[i];
  728. if (srcAnimations.find(state->getAnimation()) == srcAnimations.end())
  729. removeAnimationState(state);
  730. }
  731. }
  732. }
  733. void AnimatedModel::syncMorphs(AnimatedModel* srcNode)
  734. {
  735. for (unsigned i = 0; i < mMorphs.size(); ++i)
  736. {
  737. float srcWeight = srcNode->getMorphWeight(mMorphs[i].mName);
  738. setMorphWeight(i, srcWeight);
  739. }
  740. }
  741. void AnimatedModel::setLocalAnimation(bool enable)
  742. {
  743. mLocalAnimation = enable;
  744. }
  745. float AnimatedModel::getMorphWeight(unsigned index) const
  746. {
  747. if (index >= mMorphs.size())
  748. return 0.0f;
  749. return mMorphs[index].mWeight;
  750. }
  751. float AnimatedModel::getMorphWeight(const std::string& name) const
  752. {
  753. for (std::vector<ModelMorph>::const_iterator i = mMorphs.begin(); i != mMorphs.end(); ++i)
  754. {
  755. if (i->mName == name)
  756. return i->mWeight;
  757. }
  758. return 0.0f;
  759. }
  760. float AnimatedModel::getMorphWeight(StringHash nameHash) const
  761. {
  762. for (std::vector<ModelMorph>::const_iterator i = mMorphs.begin(); i != mMorphs.end(); ++i)
  763. {
  764. if (i->mNameHash == nameHash)
  765. return i->mWeight;
  766. }
  767. return 0.0f;
  768. }
  769. AnimationState* AnimatedModel::getAnimationState(Animation* animation) const
  770. {
  771. for (std::vector<AnimationState*>::const_iterator i = mAnimationStates.begin(); i != mAnimationStates.end(); ++i)
  772. {
  773. if ((*i)->getAnimation() == animation)
  774. return *i;
  775. }
  776. return 0;
  777. }
  778. AnimationState* AnimatedModel::getAnimationState(const std::string& animationName) const
  779. {
  780. for (std::vector<AnimationState*>::const_iterator i = mAnimationStates.begin(); i != mAnimationStates.end(); ++i)
  781. {
  782. Animation* animation = (*i)->getAnimation();
  783. // Check both the animation and the resource name
  784. if ((animation->getName() == animationName) || (animation->getAnimationName() == animationName))
  785. return *i;
  786. }
  787. return 0;
  788. }
  789. AnimationState* AnimatedModel::getAnimationState(StringHash animationNameHash) const
  790. {
  791. for (std::vector<AnimationState*>::const_iterator i = mAnimationStates.begin(); i != mAnimationStates.end(); ++i)
  792. {
  793. Animation* animation = (*i)->getAnimation();
  794. // Check both the animation and the resource name
  795. if ((animation->getNameHash() == animationNameHash) || (animation->getAnimationNameHash() == animationNameHash))
  796. return *i;
  797. }
  798. return 0;
  799. }
  800. void AnimatedModel::setSkeleton(const Skeleton& skeleton)
  801. {
  802. PROFILE(AnimatedModel_SetSkeleton);
  803. removeAllAnimationStates();
  804. mSkeleton.define(skeleton.getBones());
  805. // Parent the root bone to the this node, so that objects can further be properly attached to bones
  806. Bone* rootBone = mSkeleton.getRootBone();
  807. if (rootBone)
  808. addChild(rootBone);
  809. // Reserve space for skinning matrices
  810. mSkinMatrices.resize(mSkeleton.getNumBones());
  811. refreshGeometryBoneMappings();
  812. }
  813. void AnimatedModel::onWorldBoundingBoxUpdate(BoundingBox& worldBoundingBox)
  814. {
  815. if (!mSkeleton.getNumBones())
  816. worldBoundingBox = mBoundingBox.getTransformed(getWorldTransform());
  817. else
  818. {
  819. // If has bones, update world bounding box based on them
  820. worldBoundingBox.mDefined = false;
  821. const std::vector<SharedPtr<Bone> >& bones = mSkeleton.getBones();
  822. for (std::vector<SharedPtr<Bone> >::const_iterator i = bones.begin(); i != bones.end(); ++i)
  823. {
  824. Bone* bone = *i;
  825. unsigned collisionMask = bone->getCollisionMask();
  826. // Use hitbox if available. If not, use only half of the sphere radius
  827. if (collisionMask & BONECOLLISION_BOX)
  828. worldBoundingBox.merge(bone->getBoundingBox().getTransformed(bone->getWorldTransform()));
  829. else if (collisionMask & BONECOLLISION_SPHERE)
  830. worldBoundingBox.merge(Sphere(bone->getWorldPosition(), bone->getRadius() * 0.5f));
  831. }
  832. }
  833. }
  834. void AnimatedModel::markAnimationDirty()
  835. {
  836. mAnimationDirty = true;
  837. // Mark for octree update, as animation is updated before octree reinsertion
  838. if (mOctant)
  839. mOctant->getRoot()->markNodeForUpdate(this);
  840. }
  841. void AnimatedModel::markAnimationOrderDirty()
  842. {
  843. mAnimationOrderDirty = true;
  844. // Mark for octree update, as animation is updated before octree reinsertion
  845. if (mOctant)
  846. mOctant->getRoot()->markNodeForUpdate(this);
  847. }
  848. void AnimatedModel::markMorphsDirty()
  849. {
  850. mMorphsDirty = true;
  851. }
  852. void AnimatedModel::cloneGeometries()
  853. {
  854. PROFILE(AnimatedModel_CloneGeometries);
  855. // Clone vertex buffers as necessary
  856. const std::vector<SharedPtr<VertexBuffer> >& originalVertexBuffers = mModel->getVertexBuffers();
  857. std::map<VertexBuffer*, SharedPtr<VertexBuffer> > clonedVertexBuffers;
  858. mMorphVertexBuffers.resize(originalVertexBuffers.size());
  859. for (unsigned i = 0; i < originalVertexBuffers.size(); ++i)
  860. {
  861. VertexBuffer* original = originalVertexBuffers[i];
  862. if (original->hasMorphRange())
  863. {
  864. SharedPtr<VertexBuffer> clone(new VertexBuffer(original->getRenderer()));
  865. clone->setSize(original->getVertexCount(), original->getElementMask());
  866. void* originalData = original->lock(0, original->getVertexCount(), LOCK_NORMAL);
  867. clone->setData(originalData);
  868. original->unlock();
  869. clone->setMorphRange(original->getMorphRangeStart(), original->getMorphRangeCount());
  870. clone->setMorphRangeResetData(original->getMorphRangeResetData());
  871. clonedVertexBuffers[original] = clone;
  872. mMorphVertexBuffers[i] = clone;
  873. }
  874. }
  875. // Geometries will always be cloned fully. They contain only references to buffer, so they are relatively light
  876. for (unsigned i = 0; i < mGeometries.size(); ++i)
  877. {
  878. for (unsigned j = 0; j < mGeometries[i].size(); ++j)
  879. {
  880. SharedPtr<Geometry> original = mGeometries[i][j];
  881. const std::vector<SharedPtr<VertexBuffer> >& originalBuffers = original->getVertexBuffers();
  882. SharedPtr<Geometry> clone(new Geometry());
  883. clone->setNumVertexBuffers(originalVertexBuffers.size());
  884. for (unsigned k = 0; k < originalVertexBuffers.size(); ++k)
  885. {
  886. VertexBuffer* originalBuffer = originalBuffers[k];
  887. if (clonedVertexBuffers.find(originalBuffer) != clonedVertexBuffers.end())
  888. clone->setVertexBuffer(k, clonedVertexBuffers[originalBuffer], original->getVertexElementMask(k));
  889. else
  890. clone->setVertexBuffer(k, originalBuffers[k], original->getVertexElementMask(k));
  891. }
  892. clone->setIndexBuffer(original->getIndexBuffer());
  893. clone->setDrawRange(original->getPrimitiveType(), original->getIndexStart(), original->getIndexCount());
  894. clone->setLodDistance(original->getLodDistance());
  895. mGeometries[i][j] = clone;
  896. }
  897. }
  898. }
  899. void AnimatedModel::refreshGeometryBoneMappings()
  900. {
  901. mGeometrySkinMatrices.clear();
  902. mGeometrySkinMatrixPtrs.clear();
  903. if (!mGeometryBoneMappings.size())
  904. return;
  905. // Check if all mappings are empty, then we do not need to use mapped skinning
  906. bool allEmpty = true;
  907. for (unsigned i = 0; i < mGeometryBoneMappings.size(); ++i)
  908. if (mGeometryBoneMappings[i].size())
  909. allEmpty = false;
  910. if (allEmpty)
  911. return;
  912. // Reserve space for per-geometry skinning matrices
  913. mGeometrySkinMatrices.resize(mGeometryBoneMappings.size());
  914. for (unsigned i = 0; i < mGeometryBoneMappings.size(); ++i)
  915. mGeometrySkinMatrices[i].resize(mGeometryBoneMappings[i].size());
  916. // Build original-to-skinindex matrix pointer mapping for fast copying
  917. // Note: at this point layout of mGeometrySkinMatrices cannot be modified or pointers become invalid
  918. mGeometrySkinMatrixPtrs.resize(mSkeleton.getNumBones());
  919. for (unsigned i = 0; i < mGeometryBoneMappings.size(); ++i)
  920. {
  921. for (unsigned j = 0; j < mGeometryBoneMappings[i].size(); ++j)
  922. mGeometrySkinMatrixPtrs[mGeometryBoneMappings[i][j]].push_back(&mGeometrySkinMatrices[i][j]);
  923. }
  924. }
  925. void AnimatedModel::updateAnimation(const FrameInfo& frame)
  926. {
  927. // If using animation LOD, accumulate time and see if it is time to update
  928. if ((mAnimationLodBias > 0.0f) && (mAnimationLodDistance > 0.0f))
  929. {
  930. mAnimationLodTimer += mAnimationLodBias * frame.mTimeStep * ANIMATION_LOD_BASESCALE;
  931. if (mAnimationLodTimer >= mAnimationLodDistance)
  932. mAnimationLodTimer = fmodf(mAnimationLodTimer, mAnimationLodDistance);
  933. else
  934. {
  935. // If animation order changed (animations added/removed), force always an immediate update
  936. if (!mAnimationOrderDirty)
  937. return;
  938. }
  939. }
  940. PROFILE(AnimatedModel_UpdateAnimation);
  941. // Make sure animations are in ascending priority order
  942. if (mAnimationOrderDirty)
  943. {
  944. std::sort(mAnimationStates.begin(), mAnimationStates.end(), compareAnimationOrder);
  945. mAnimationOrderDirty = false;
  946. }
  947. // Reset skeleton, then apply all animations
  948. mSkeleton.reset();
  949. for (std::vector<AnimationState*>::iterator i = mAnimationStates.begin(); i != mAnimationStates.end(); ++i)
  950. (*i)->apply();
  951. // Animation has changed the bounding box: mark node for octree reinsertion
  952. VolumeNode::onMarkedDirty();
  953. mAnimationDirty = false;
  954. }
  955. void AnimatedModel::updateSkinning()
  956. {
  957. PROFILE(AnimatedModel_UpdateSkinning);
  958. // Note: the model's world transform will be baked in the skin matrices. When preparing to render,
  959. // the model transform will then be set to identity
  960. const std::vector<SharedPtr<Bone > >& bones = mSkeleton.getBones();
  961. // Skinning with global matrices only
  962. if (!mGeometrySkinMatrices.size())
  963. {
  964. for (unsigned i = 0; i < bones.size(); ++i)
  965. {
  966. Bone* bone = bones[i];
  967. if (bone->isSkinningDirty())
  968. {
  969. mSkinMatrices[i] = bone->getWorldTransform() * bone->getBindInverseTransform();
  970. bone->clearSkinningDirty();
  971. }
  972. }
  973. }
  974. // Skinning with per-geometry matrices
  975. else
  976. {
  977. for (unsigned i = 0; i < bones.size(); ++i)
  978. {
  979. Bone* bone = bones[i];
  980. if (bone->isSkinningDirty())
  981. {
  982. mSkinMatrices[i] = bone->getWorldTransform() * bone->getBindInverseTransform();
  983. // Copy the skin matrix to per-geometry matrices as needed
  984. for (unsigned j = 0; j < mGeometrySkinMatrixPtrs[i].size(); ++j)
  985. *mGeometrySkinMatrixPtrs[i][j] = mSkinMatrices[i];
  986. bone->clearSkinningDirty();
  987. }
  988. }
  989. }
  990. }
  991. void AnimatedModel::updateMorphs()
  992. {
  993. PROFILE(AnimatedModel_UpdateMorphs);
  994. if (mMorphs.size())
  995. {
  996. // Reset the morph data range from all morphable vertex buffers, then apply morphs
  997. for (unsigned i = 0; i < mMorphVertexBuffers.size(); ++i)
  998. {
  999. VertexBuffer* buffer = mMorphVertexBuffers[i];
  1000. if (buffer)
  1001. {
  1002. void* lockedMorphRange = buffer->lockMorphRange();
  1003. buffer->resetMorphRange(lockedMorphRange);
  1004. for (unsigned j = 0; j < mMorphs.size(); ++j)
  1005. {
  1006. if (mMorphs[j].mWeight > 0.0f)
  1007. {
  1008. std::map<unsigned, VertexBufferMorph>::iterator k = mMorphs[j].mBuffers.find(i);
  1009. if (k != mMorphs[j].mBuffers.end())
  1010. applyMorph(buffer, lockedMorphRange, k->second, mMorphs[j].mWeight);
  1011. }
  1012. }
  1013. buffer->unlock();
  1014. }
  1015. }
  1016. }
  1017. mMorphsDirty = false;
  1018. }
  1019. void AnimatedModel::applyMorph(VertexBuffer* buffer, void* lockedMorphRange, const VertexBufferMorph& morph, float weight)
  1020. {
  1021. unsigned elementMask = morph.mElementMask;
  1022. unsigned vertexCount = morph.mVertexCount;
  1023. unsigned normalOffset = buffer->getElementOffset(ELEMENT_NORMAL);
  1024. unsigned tangentOffset = buffer->getElementOffset(ELEMENT_TANGENT);
  1025. unsigned morphRangeStart = buffer->getMorphRangeStart();
  1026. unsigned vertexSize = buffer->getVertexSize();
  1027. unsigned char* srcData = morph.mMorphData;
  1028. unsigned char* destData = (unsigned char*)lockedMorphRange;
  1029. while (vertexCount--)
  1030. {
  1031. unsigned vertexIndex = *((unsigned*)srcData) - morphRangeStart;
  1032. srcData += sizeof(unsigned);
  1033. if (elementMask & MASK_POSITION)
  1034. {
  1035. float* dest = (float*)(destData + vertexIndex * vertexSize);
  1036. float* src = (float*)srcData;
  1037. dest[0] += src[0] * weight;
  1038. dest[1] += src[1] * weight;
  1039. dest[2] += src[2] * weight;
  1040. srcData += 3 * sizeof(float);
  1041. }
  1042. if (elementMask & MASK_NORMAL)
  1043. {
  1044. float* dest = (float*)(destData + vertexIndex * vertexSize + normalOffset);
  1045. float* src = (float*)srcData;
  1046. dest[0] += src[0] * weight;
  1047. dest[1] += src[1] * weight;
  1048. dest[2] += src[2] * weight;
  1049. srcData += 3 * sizeof(float);
  1050. }
  1051. if (elementMask & MASK_TANGENT)
  1052. {
  1053. float* dest = (float*)(destData + vertexIndex * vertexSize + tangentOffset);
  1054. float* src = (float*)srcData;
  1055. dest[0] += src[0] * weight;
  1056. dest[1] += src[1] * weight;
  1057. dest[2] += src[2] * weight;
  1058. srcData += 3 * sizeof(float);
  1059. }
  1060. }
  1061. }
  1062. void AnimatedModel::removeExtraAnimations(const std::set<StringHash>& animations)
  1063. {
  1064. bool removedAny = false;
  1065. for (std::vector<AnimationState*>::iterator i = mAnimationStates.begin(); i != mAnimationStates.end();)
  1066. {
  1067. AnimationState* state = *i;
  1068. if (animations.find(state->getAnimation()->getNameHash()) == animations.end())
  1069. {
  1070. // If animation is still interpolating, do not remove immediately, but set target weight to zero
  1071. if ((isProxy()) && (state->isInterpolating()))
  1072. {
  1073. state->setWeight(0.0f);
  1074. ++i;
  1075. }
  1076. else
  1077. {
  1078. delete state;
  1079. i = mAnimationStates.erase(i);
  1080. removedAny = true;
  1081. }
  1082. }
  1083. else
  1084. ++i;
  1085. }
  1086. if (removedAny)
  1087. markAnimationDirty();
  1088. }