1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include "../Precompiled.h"
24 
25 #include "../Core/Context.h"
26 #include "../Core/Profiler.h"
27 #include "../Graphics/AnimatedModel.h"
28 #include "../Graphics/Animation.h"
29 #include "../Graphics/AnimationState.h"
30 #include "../Graphics/Batch.h"
31 #include "../Graphics/Camera.h"
32 #include "../Graphics/DebugRenderer.h"
33 #include "../Graphics/DrawableEvents.h"
34 #include "../Graphics/Geometry.h"
35 #include "../Graphics/Graphics.h"
36 #include "../Graphics/IndexBuffer.h"
37 #include "../Graphics/Material.h"
38 #include "../Graphics/Octree.h"
39 #include "../Graphics/VertexBuffer.h"
40 #include "../IO/Log.h"
41 #include "../Resource/ResourceCache.h"
42 #include "../Resource/ResourceEvents.h"
43 #include "../Scene/Scene.h"
44 
45 #include "../DebugNew.h"
46 
47 namespace Urho3D
48 {
49 
50 extern const char* GEOMETRY_CATEGORY;
51 
52 const char* animationStatesStructureElementNames[] =
53 {
54     "Anim State Count",
55     "   Animation",
56     "   Start Bone",
57     "   Is Looped",
58     "   Weight",
59     "   Time",
60     "   Layer",
61     0
62 };
63 
CompareAnimationOrder(const SharedPtr<AnimationState> & lhs,const SharedPtr<AnimationState> & rhs)64 static bool CompareAnimationOrder(const SharedPtr<AnimationState>& lhs, const SharedPtr<AnimationState>& rhs)
65 {
66     return lhs->GetLayer() < rhs->GetLayer();
67 }
68 
69 static const unsigned MAX_ANIMATION_STATES = 256;
70 
AnimatedModel(Context * context)71 AnimatedModel::AnimatedModel(Context* context) :
72     StaticModel(context),
73     animationLodFrameNumber_(0),
74     morphElementMask_(0),
75     animationLodBias_(1.0f),
76     animationLodTimer_(-1.0f),
77     animationLodDistance_(0.0f),
78     updateInvisible_(false),
79     animationDirty_(false),
80     animationOrderDirty_(false),
81     morphsDirty_(false),
82     skinningDirty_(true),
83     boneBoundingBoxDirty_(true),
84     isMaster_(true),
85     loading_(false),
86     assignBonesPending_(false),
87     forceAnimationUpdate_(false)
88 {
89 }
90 
~AnimatedModel()91 AnimatedModel::~AnimatedModel()
92 {
93     // When being destroyed, remove the bone hierarchy if appropriate (last AnimatedModel in the node)
94     Bone* rootBone = skeleton_.GetRootBone();
95     if (rootBone && rootBone->node_)
96     {
97         Node* parent = rootBone->node_->GetParent();
98         if (parent && !parent->GetComponent<AnimatedModel>())
99             RemoveRootBone();
100     }
101 }
102 
RegisterObject(Context * context)103 void AnimatedModel::RegisterObject(Context* context)
104 {
105     context->RegisterFactory<AnimatedModel>(GEOMETRY_CATEGORY);
106 
107     URHO3D_ACCESSOR_ATTRIBUTE("Is Enabled", IsEnabled, SetEnabled, bool, true, AM_DEFAULT);
108     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Model", GetModelAttr, SetModelAttr, ResourceRef, ResourceRef(Model::GetTypeStatic()), AM_DEFAULT);
109     URHO3D_ACCESSOR_ATTRIBUTE("Material", GetMaterialsAttr, SetMaterialsAttr, ResourceRefList, ResourceRefList(Material::GetTypeStatic()),
110         AM_DEFAULT);
111     URHO3D_ATTRIBUTE("Is Occluder", bool, occluder_, false, AM_DEFAULT);
112     URHO3D_ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
113     URHO3D_ATTRIBUTE("Cast Shadows", bool, castShadows_, false, AM_DEFAULT);
114     URHO3D_ACCESSOR_ATTRIBUTE("Update When Invisible", GetUpdateInvisible, SetUpdateInvisible, bool, false, AM_DEFAULT);
115     URHO3D_ACCESSOR_ATTRIBUTE("Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
116     URHO3D_ACCESSOR_ATTRIBUTE("Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
117     URHO3D_ACCESSOR_ATTRIBUTE("LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
118     URHO3D_ACCESSOR_ATTRIBUTE("Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
119     URHO3D_COPY_BASE_ATTRIBUTES(Drawable);
120     URHO3D_MIXED_ACCESSOR_ATTRIBUTE("Bone Animation Enabled", GetBonesEnabledAttr, SetBonesEnabledAttr, VariantVector,
121         Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
122     URHO3D_MIXED_ACCESSOR_VARIANT_VECTOR_STRUCTURE_ATTRIBUTE("Animation States", GetAnimationStatesAttr, SetAnimationStatesAttr,
123                                                             VariantVector, Variant::emptyVariantVector,
124                                                             animationStatesStructureElementNames, AM_FILE);
125     URHO3D_ACCESSOR_ATTRIBUTE("Morphs", GetMorphsAttr, SetMorphsAttr, PODVector<unsigned char>, Variant::emptyBuffer,
126         AM_DEFAULT | AM_NOEDIT);
127 }
128 
Load(Deserializer & source,bool setInstanceDefault)129 bool AnimatedModel::Load(Deserializer& source, bool setInstanceDefault)
130 {
131     loading_ = true;
132     bool success = Component::Load(source, setInstanceDefault);
133     loading_ = false;
134 
135     return success;
136 }
137 
LoadXML(const XMLElement & source,bool setInstanceDefault)138 bool AnimatedModel::LoadXML(const XMLElement& source, bool setInstanceDefault)
139 {
140     loading_ = true;
141     bool success = Component::LoadXML(source, setInstanceDefault);
142     loading_ = false;
143 
144     return success;
145 }
146 
LoadJSON(const JSONValue & source,bool setInstanceDefault)147 bool AnimatedModel::LoadJSON(const JSONValue& source, bool setInstanceDefault)
148 {
149     loading_ = true;
150     bool success = Component::LoadJSON(source, setInstanceDefault);
151     loading_ = false;
152 
153     return success;
154 }
155 
ApplyAttributes()156 void AnimatedModel::ApplyAttributes()
157 {
158     if (assignBonesPending_)
159         AssignBoneNodes();
160 }
161 
ProcessRayQuery(const RayOctreeQuery & query,PODVector<RayQueryResult> & results)162 void AnimatedModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
163 {
164     // If no bones or no bone-level testing, use the StaticModel test
165     RayQueryLevel level = query.level_;
166     if (level < RAY_TRIANGLE || !skeleton_.GetNumBones())
167     {
168         StaticModel::ProcessRayQuery(query, results);
169         return;
170     }
171 
172     // Check ray hit distance to AABB before proceeding with bone-level tests
173     if (query.ray_.HitDistance(GetWorldBoundingBox()) >= query.maxDistance_)
174         return;
175 
176     const Vector<Bone>& bones = skeleton_.GetBones();
177     Sphere boneSphere;
178 
179     for (unsigned i = 0; i < bones.Size(); ++i)
180     {
181         const Bone& bone = bones[i];
182         if (!bone.node_)
183             continue;
184 
185         float distance;
186 
187         // Use hitbox if available
188         if (bone.collisionMask_ & BONECOLLISION_BOX)
189         {
190             // Do an initial crude test using the bone's AABB
191             const BoundingBox& box = bone.boundingBox_;
192             const Matrix3x4& transform = bone.node_->GetWorldTransform();
193             distance = query.ray_.HitDistance(box.Transformed(transform));
194             if (distance >= query.maxDistance_)
195                 continue;
196             if (level != RAY_AABB)
197             {
198                 // Follow with an OBB test if required
199                 Matrix3x4 inverse = transform.Inverse();
200                 Ray localRay = query.ray_.Transformed(inverse);
201                 distance = localRay.HitDistance(box);
202                 if (distance >= query.maxDistance_)
203                     continue;
204             }
205         }
206         else if (bone.collisionMask_ & BONECOLLISION_SPHERE)
207         {
208             boneSphere.center_ = bone.node_->GetWorldPosition();
209             boneSphere.radius_ = bone.radius_;
210             distance = query.ray_.HitDistance(boneSphere);
211             if (distance >= query.maxDistance_)
212                 continue;
213         }
214         else
215             continue;
216 
217         // If the code reaches here then we have a hit
218         RayQueryResult result;
219         result.position_ = query.ray_.origin_ + distance * query.ray_.direction_;
220         result.normal_ = -query.ray_.direction_;
221         result.distance_ = distance;
222         result.drawable_ = this;
223         result.node_ = node_;
224         result.subObject_ = i;
225         results.Push(result);
226     }
227 }
228 
Update(const FrameInfo & frame)229 void AnimatedModel::Update(const FrameInfo& frame)
230 {
231     // If node was invisible last frame, need to decide animation LOD distance here
232     // If headless, retain the current animation distance (should be 0)
233     if (frame.camera_ && abs((int)frame.frameNumber_ - (int)viewFrameNumber_) > 1)
234     {
235         // First check for no update at all when invisible. In that case reset LOD timer to ensure update
236         // next time the model is in view
237         if (!updateInvisible_)
238         {
239             if (animationDirty_)
240             {
241                 animationLodTimer_ = -1.0f;
242                 forceAnimationUpdate_ = true;
243             }
244             return;
245         }
246         float distance = frame.camera_->GetDistance(node_->GetWorldPosition());
247         // If distance is greater than draw distance, no need to update at all
248         if (drawDistance_ > 0.0f && distance > drawDistance_)
249             return;
250         float scale = GetWorldBoundingBox().Size().DotProduct(DOT_SCALE);
251         animationLodDistance_ = frame.camera_->GetLodDistance(distance, scale, lodBias_);
252     }
253 
254     if (animationDirty_ || animationOrderDirty_)
255         UpdateAnimation(frame);
256     else if (boneBoundingBoxDirty_)
257         UpdateBoneBoundingBox();
258 }
259 
UpdateBatches(const FrameInfo & frame)260 void AnimatedModel::UpdateBatches(const FrameInfo& frame)
261 {
262     const Matrix3x4& worldTransform = node_->GetWorldTransform();
263     const BoundingBox& worldBoundingBox = GetWorldBoundingBox();
264     distance_ = frame.camera_->GetDistance(worldBoundingBox.Center());
265 
266     // Note: per-geometry distances do not take skinning into account. Especially in case of a ragdoll they may be
267     // much off base if the node's own transform is not updated
268     if (batches_.Size() == 1)
269         batches_[0].distance_ = distance_;
270     else
271     {
272         for (unsigned i = 0; i < batches_.Size(); ++i)
273             batches_[i].distance_ = frame.camera_->GetDistance(worldTransform * geometryData_[i].center_);
274     }
275 
276     // Use a transformed version of the model's bounding box instead of world bounding box for LOD scale
277     // determination so that animation does not change the scale
278     BoundingBox transformedBoundingBox = boundingBox_.Transformed(worldTransform);
279     float scale = transformedBoundingBox.Size().DotProduct(DOT_SCALE);
280     float newLodDistance = frame.camera_->GetLodDistance(distance_, scale, lodBias_);
281 
282     // If model is rendered from several views, use the minimum LOD distance for animation LOD
283     if (frame.frameNumber_ != animationLodFrameNumber_)
284     {
285         animationLodDistance_ = newLodDistance;
286         animationLodFrameNumber_ = frame.frameNumber_;
287     }
288     else
289         animationLodDistance_ = Min(animationLodDistance_, newLodDistance);
290 
291     if (newLodDistance != lodDistance_)
292     {
293         lodDistance_ = newLodDistance;
294         CalculateLodLevels();
295     }
296 }
297 
UpdateGeometry(const FrameInfo & frame)298 void AnimatedModel::UpdateGeometry(const FrameInfo& frame)
299 {
300     // Late update in case the model came into view and animation was dirtied in the meanwhile
301     if (forceAnimationUpdate_)
302     {
303         UpdateAnimation(frame);
304         forceAnimationUpdate_ = false;
305     }
306 
307     if (morphsDirty_)
308         UpdateMorphs();
309 
310     if (skinningDirty_)
311         UpdateSkinning();
312 }
313 
GetUpdateGeometryType()314 UpdateGeometryType AnimatedModel::GetUpdateGeometryType()
315 {
316     if (morphsDirty_ || forceAnimationUpdate_)
317         return UPDATE_MAIN_THREAD;
318     else if (skinningDirty_)
319         return UPDATE_WORKER_THREAD;
320     else
321         return UPDATE_NONE;
322 }
323 
DrawDebugGeometry(DebugRenderer * debug,bool depthTest)324 void AnimatedModel::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
325 {
326     if (debug && IsEnabledEffective())
327     {
328         debug->AddBoundingBox(GetWorldBoundingBox(), Color::GREEN, depthTest);
329         debug->AddSkeleton(skeleton_, Color(0.75f, 0.75f, 0.75f), depthTest);
330     }
331 }
332 
SetModel(Model * model,bool createBones)333 void AnimatedModel::SetModel(Model* model, bool createBones)
334 {
335     if (model == model_)
336         return;
337 
338     if (!node_)
339     {
340         URHO3D_LOGERROR("Can not set model while model component is not attached to a scene node");
341         return;
342     }
343 
344     // Unsubscribe from the reload event of previous model (if any), then subscribe to the new
345     if (model_)
346         UnsubscribeFromEvent(model_, E_RELOADFINISHED);
347 
348     model_ = model;
349 
350     if (model)
351     {
352         SubscribeToEvent(model, E_RELOADFINISHED, URHO3D_HANDLER(AnimatedModel, HandleModelReloadFinished));
353 
354         // Copy the subgeometry & LOD level structure
355         SetNumGeometries(model->GetNumGeometries());
356         const Vector<Vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
357         const PODVector<Vector3>& geometryCenters = model->GetGeometryCenters();
358         for (unsigned i = 0; i < geometries.Size(); ++i)
359         {
360             geometries_[i] = geometries[i];
361             geometryData_[i].center_ = geometryCenters[i];
362         }
363 
364         // Copy geometry bone mappings
365         const Vector<PODVector<unsigned> >& geometryBoneMappings = model->GetGeometryBoneMappings();
366         geometryBoneMappings_.Clear();
367         geometryBoneMappings_.Reserve(geometryBoneMappings.Size());
368         for (unsigned i = 0; i < geometryBoneMappings.Size(); ++i)
369             geometryBoneMappings_.Push(geometryBoneMappings[i]);
370 
371         // Copy morphs. Note: morph vertex buffers will be created later on-demand
372         morphVertexBuffers_.Clear();
373         morphs_.Clear();
374         const Vector<ModelMorph>& morphs = model->GetMorphs();
375         morphs_.Reserve(morphs.Size());
376         morphElementMask_ = 0;
377         for (unsigned i = 0; i < morphs.Size(); ++i)
378         {
379             ModelMorph newMorph;
380             newMorph.name_ = morphs[i].name_;
381             newMorph.nameHash_ = morphs[i].nameHash_;
382             newMorph.weight_ = 0.0f;
383             newMorph.buffers_ = morphs[i].buffers_;
384             for (HashMap<unsigned, VertexBufferMorph>::ConstIterator j = morphs[i].buffers_.Begin();
385                  j != morphs[i].buffers_.End(); ++j)
386                 morphElementMask_ |= j->second_.elementMask_;
387             morphs_.Push(newMorph);
388         }
389 
390         // Copy bounding box & skeleton
391         SetBoundingBox(model->GetBoundingBox());
392         // Initial bone bounding box is just the one stored in the model
393         boneBoundingBox_ = boundingBox_;
394         boneBoundingBoxDirty_ = true;
395         SetSkeleton(model->GetSkeleton(), createBones);
396         ResetLodLevels();
397 
398         // Reserve space for skinning matrices
399         skinMatrices_.Resize(skeleton_.GetNumBones());
400         SetGeometryBoneMappings();
401 
402         // Enable skinning in batches
403         for (unsigned i = 0; i < batches_.Size(); ++i)
404         {
405             if (skinMatrices_.Size())
406             {
407                 batches_[i].geometryType_ = GEOM_SKINNED;
408                 // Check if model has per-geometry bone mappings
409                 if (geometrySkinMatrices_.Size() && geometrySkinMatrices_[i].Size())
410                 {
411                     batches_[i].worldTransform_ = &geometrySkinMatrices_[i][0];
412                     batches_[i].numWorldTransforms_ = geometrySkinMatrices_[i].Size();
413                 }
414                 // If not, use the global skin matrices
415                 else
416                 {
417                     batches_[i].worldTransform_ = &skinMatrices_[0];
418                     batches_[i].numWorldTransforms_ = skinMatrices_.Size();
419                 }
420             }
421             else
422             {
423                 batches_[i].geometryType_ = GEOM_STATIC;
424                 batches_[i].worldTransform_ = &node_->GetWorldTransform();
425                 batches_[i].numWorldTransforms_ = 1;
426             }
427         }
428     }
429     else
430     {
431         RemoveRootBone(); // Remove existing root bone if any
432         SetNumGeometries(0);
433         geometryBoneMappings_.Clear();
434         morphVertexBuffers_.Clear();
435         morphs_.Clear();
436         morphElementMask_ = 0;
437         SetBoundingBox(BoundingBox());
438         SetSkeleton(Skeleton(), false);
439     }
440 
441     MarkNetworkUpdate();
442 }
443 
AddAnimationState(Animation * animation)444 AnimationState* AnimatedModel::AddAnimationState(Animation* animation)
445 {
446     if (!isMaster_)
447     {
448         URHO3D_LOGERROR("Can not add animation state to non-master model");
449         return 0;
450     }
451 
452     if (!animation || !skeleton_.GetNumBones())
453         return 0;
454 
455     // Check for not adding twice
456     AnimationState* existing = GetAnimationState(animation);
457     if (existing)
458         return existing;
459 
460     SharedPtr<AnimationState> newState(new AnimationState(this, animation));
461     animationStates_.Push(newState);
462     MarkAnimationOrderDirty();
463     return newState;
464 }
465 
RemoveAnimationState(Animation * animation)466 void AnimatedModel::RemoveAnimationState(Animation* animation)
467 {
468     if (animation)
469         RemoveAnimationState(animation->GetNameHash());
470     else
471     {
472         for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
473         {
474             AnimationState* state = *i;
475             if (!state->GetAnimation())
476             {
477                 animationStates_.Erase(i);
478                 MarkAnimationDirty();
479                 return;
480             }
481         }
482     }
483 }
484 
RemoveAnimationState(const String & animationName)485 void AnimatedModel::RemoveAnimationState(const String& animationName)
486 {
487     RemoveAnimationState(StringHash(animationName));
488 }
489 
RemoveAnimationState(StringHash animationNameHash)490 void AnimatedModel::RemoveAnimationState(StringHash animationNameHash)
491 {
492     for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
493     {
494         AnimationState* state = *i;
495         Animation* animation = state->GetAnimation();
496         if (animation)
497         {
498             // Check both the animation and the resource name
499             if (animation->GetNameHash() == animationNameHash || animation->GetAnimationNameHash() == animationNameHash)
500             {
501                 animationStates_.Erase(i);
502                 MarkAnimationDirty();
503                 return;
504             }
505         }
506     }
507 }
508 
RemoveAnimationState(AnimationState * state)509 void AnimatedModel::RemoveAnimationState(AnimationState* state)
510 {
511     for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
512     {
513         if (*i == state)
514         {
515             animationStates_.Erase(i);
516             MarkAnimationDirty();
517             return;
518         }
519     }
520 }
521 
RemoveAnimationState(unsigned index)522 void AnimatedModel::RemoveAnimationState(unsigned index)
523 {
524     if (index < animationStates_.Size())
525     {
526         animationStates_.Erase(index);
527         MarkAnimationDirty();
528     }
529 }
530 
RemoveAllAnimationStates()531 void AnimatedModel::RemoveAllAnimationStates()
532 {
533     if (animationStates_.Size())
534     {
535         animationStates_.Clear();
536         MarkAnimationDirty();
537     }
538 }
539 
SetAnimationLodBias(float bias)540 void AnimatedModel::SetAnimationLodBias(float bias)
541 {
542     animationLodBias_ = Max(bias, 0.0f);
543     MarkNetworkUpdate();
544 }
545 
SetUpdateInvisible(bool enable)546 void AnimatedModel::SetUpdateInvisible(bool enable)
547 {
548     updateInvisible_ = enable;
549     MarkNetworkUpdate();
550 }
551 
552 
SetMorphWeight(unsigned index,float weight)553 void AnimatedModel::SetMorphWeight(unsigned index, float weight)
554 {
555     if (index >= morphs_.Size())
556         return;
557 
558     // If morph vertex buffers have not been created yet, create now
559     if (weight != 0.0f && morphVertexBuffers_.Empty())
560         CloneGeometries();
561 
562     if (weight != morphs_[index].weight_)
563     {
564         morphs_[index].weight_ = weight;
565 
566         // For a master model, set the same morph weight on non-master models
567         if (isMaster_)
568         {
569             PODVector<AnimatedModel*> models;
570             GetComponents<AnimatedModel>(models);
571 
572             // Indexing might not be the same, so use the name hash instead
573             for (unsigned i = 1; i < models.Size(); ++i)
574             {
575                 if (!models[i]->isMaster_)
576                     models[i]->SetMorphWeight(morphs_[index].nameHash_, weight);
577             }
578         }
579 
580         MarkMorphsDirty();
581         MarkNetworkUpdate();
582     }
583 }
584 
SetMorphWeight(const String & name,float weight)585 void AnimatedModel::SetMorphWeight(const String& name, float weight)
586 {
587     for (unsigned i = 0; i < morphs_.Size(); ++i)
588     {
589         if (morphs_[i].name_ == name)
590         {
591             SetMorphWeight(i, weight);
592             return;
593         }
594     }
595 }
596 
SetMorphWeight(StringHash nameHash,float weight)597 void AnimatedModel::SetMorphWeight(StringHash nameHash, float weight)
598 {
599     for (unsigned i = 0; i < morphs_.Size(); ++i)
600     {
601         if (morphs_[i].nameHash_ == nameHash)
602         {
603             SetMorphWeight(i, weight);
604             return;
605         }
606     }
607 }
608 
ResetMorphWeights()609 void AnimatedModel::ResetMorphWeights()
610 {
611     for (Vector<ModelMorph>::Iterator i = morphs_.Begin(); i != morphs_.End(); ++i)
612         i->weight_ = 0.0f;
613 
614     // For a master model, reset weights on non-master models
615     if (isMaster_)
616     {
617         PODVector<AnimatedModel*> models;
618         GetComponents<AnimatedModel>(models);
619 
620         for (unsigned i = 1; i < models.Size(); ++i)
621         {
622             if (!models[i]->isMaster_)
623                 models[i]->ResetMorphWeights();
624         }
625     }
626 
627     MarkMorphsDirty();
628     MarkNetworkUpdate();
629 }
630 
GetMorphWeight(unsigned index) const631 float AnimatedModel::GetMorphWeight(unsigned index) const
632 {
633     return index < morphs_.Size() ? morphs_[index].weight_ : 0.0f;
634 }
635 
GetMorphWeight(const String & name) const636 float AnimatedModel::GetMorphWeight(const String& name) const
637 {
638     for (Vector<ModelMorph>::ConstIterator i = morphs_.Begin(); i != morphs_.End(); ++i)
639     {
640         if (i->name_ == name)
641             return i->weight_;
642     }
643 
644     return 0.0f;
645 }
646 
GetMorphWeight(StringHash nameHash) const647 float AnimatedModel::GetMorphWeight(StringHash nameHash) const
648 {
649     for (Vector<ModelMorph>::ConstIterator i = morphs_.Begin(); i != morphs_.End(); ++i)
650     {
651         if (i->nameHash_ == nameHash)
652             return i->weight_;
653     }
654 
655     return 0.0f;
656 }
657 
GetAnimationState(Animation * animation) const658 AnimationState* AnimatedModel::GetAnimationState(Animation* animation) const
659 {
660     for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
661     {
662         if ((*i)->GetAnimation() == animation)
663             return *i;
664     }
665 
666     return 0;
667 }
668 
GetAnimationState(const String & animationName) const669 AnimationState* AnimatedModel::GetAnimationState(const String& animationName) const
670 {
671     return GetAnimationState(StringHash(animationName));
672 }
673 
GetAnimationState(StringHash animationNameHash) const674 AnimationState* AnimatedModel::GetAnimationState(StringHash animationNameHash) const
675 {
676     for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
677     {
678         Animation* animation = (*i)->GetAnimation();
679         if (animation)
680         {
681             // Check both the animation and the resource name
682             if (animation->GetNameHash() == animationNameHash || animation->GetAnimationNameHash() == animationNameHash)
683                 return *i;
684         }
685     }
686 
687     return 0;
688 }
689 
GetAnimationState(unsigned index) const690 AnimationState* AnimatedModel::GetAnimationState(unsigned index) const
691 {
692     return index < animationStates_.Size() ? animationStates_[index].Get() : 0;
693 }
694 
SetSkeleton(const Skeleton & skeleton,bool createBones)695 void AnimatedModel::SetSkeleton(const Skeleton& skeleton, bool createBones)
696 {
697     if (!node_ && createBones)
698     {
699         URHO3D_LOGERROR("AnimatedModel not attached to a scene node, can not create bone nodes");
700         return;
701     }
702 
703     if (isMaster_)
704     {
705         // Check if bone structure has stayed compatible (reloading the model.) In that case retain the old bones and animations
706         if (skeleton_.GetNumBones() == skeleton.GetNumBones())
707         {
708             Vector<Bone>& destBones = skeleton_.GetModifiableBones();
709             const Vector<Bone>& srcBones = skeleton.GetBones();
710             bool compatible = true;
711 
712             for (unsigned i = 0; i < destBones.Size(); ++i)
713             {
714                 if (destBones[i].node_ && destBones[i].name_ == srcBones[i].name_ && destBones[i].parentIndex_ ==
715                                                                                      srcBones[i].parentIndex_)
716                 {
717                     // If compatible, just copy the values and retain the old node and animated status
718                     Node* boneNode = destBones[i].node_;
719                     bool animated = destBones[i].animated_;
720                     destBones[i] = srcBones[i];
721                     destBones[i].node_ = boneNode;
722                     destBones[i].animated_ = animated;
723                 }
724                 else
725                 {
726                     compatible = false;
727                     break;
728                 }
729             }
730             if (compatible)
731                 return;
732         }
733 
734         RemoveAllAnimationStates();
735 
736         // Detach the rootbone of the previous model if any
737         if (createBones)
738             RemoveRootBone();
739 
740         skeleton_.Define(skeleton);
741 
742         // Merge bounding boxes from non-master models
743         FinalizeBoneBoundingBoxes();
744 
745         Vector<Bone>& bones = skeleton_.GetModifiableBones();
746         // Create scene nodes for the bones
747         if (createBones)
748         {
749             for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i)
750             {
751                 // Create bones as local, as they are never to be directly synchronized over the network
752                 Node* boneNode = node_->CreateChild(i->name_, LOCAL);
753                 boneNode->AddListener(this);
754                 boneNode->SetTransform(i->initialPosition_, i->initialRotation_, i->initialScale_);
755                 // Copy the model component's temporary status
756                 boneNode->SetTemporary(IsTemporary());
757                 i->node_ = boneNode;
758             }
759 
760             for (unsigned i = 0; i < bones.Size(); ++i)
761             {
762                 unsigned parentIndex = bones[i].parentIndex_;
763                 if (parentIndex != i && parentIndex < bones.Size())
764                     bones[parentIndex].node_->AddChild(bones[i].node_);
765             }
766         }
767 
768         using namespace BoneHierarchyCreated;
769 
770         VariantMap& eventData = GetEventDataMap();
771         eventData[P_NODE] = node_;
772         node_->SendEvent(E_BONEHIERARCHYCREATED, eventData);
773     }
774     else
775     {
776         // For non-master models: use the bone nodes of the master model
777         skeleton_.Define(skeleton);
778 
779         // Instruct the master model to refresh (merge) its bone bounding boxes
780         AnimatedModel* master = node_->GetComponent<AnimatedModel>();
781         if (master && master != this)
782             master->FinalizeBoneBoundingBoxes();
783 
784         if (createBones)
785         {
786             Vector<Bone>& bones = skeleton_.GetModifiableBones();
787             for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i)
788             {
789                 Node* boneNode = node_->GetChild(i->name_, true);
790                 if (boneNode)
791                     boneNode->AddListener(this);
792                 i->node_ = boneNode;
793             }
794         }
795     }
796 
797     assignBonesPending_ = !createBones;
798 }
799 
SetModelAttr(const ResourceRef & value)800 void AnimatedModel::SetModelAttr(const ResourceRef& value)
801 {
802     ResourceCache* cache = GetSubsystem<ResourceCache>();
803     // When loading a scene, set model without creating the bone nodes (will be assigned later during post-load)
804     SetModel(cache->GetResource<Model>(value.name_), !loading_);
805 }
806 
SetBonesEnabledAttr(const VariantVector & value)807 void AnimatedModel::SetBonesEnabledAttr(const VariantVector& value)
808 {
809     Vector<Bone>& bones = skeleton_.GetModifiableBones();
810     for (unsigned i = 0; i < bones.Size() && i < value.Size(); ++i)
811         bones[i].animated_ = value[i].GetBool();
812 }
813 
SetAnimationStatesAttr(const VariantVector & value)814 void AnimatedModel::SetAnimationStatesAttr(const VariantVector& value)
815 {
816     ResourceCache* cache = GetSubsystem<ResourceCache>();
817     RemoveAllAnimationStates();
818     unsigned index = 0;
819     unsigned numStates = index < value.Size() ? value[index++].GetUInt() : 0;
820     // Prevent negative or overly large value being assigned from the editor
821     if (numStates > M_MAX_INT)
822         numStates = 0;
823     if (numStates > MAX_ANIMATION_STATES)
824         numStates = MAX_ANIMATION_STATES;
825 
826     animationStates_.Reserve(numStates);
827     while (numStates--)
828     {
829         if (index + 5 < value.Size())
830         {
831             // Note: null animation is allowed here for editing
832             const ResourceRef& animRef = value[index++].GetResourceRef();
833             SharedPtr<AnimationState> newState(new AnimationState(this, cache->GetResource<Animation>(animRef.name_)));
834             animationStates_.Push(newState);
835 
836             newState->SetStartBone(skeleton_.GetBone(value[index++].GetString()));
837             newState->SetLooped(value[index++].GetBool());
838             newState->SetWeight(value[index++].GetFloat());
839             newState->SetTime(value[index++].GetFloat());
840             newState->SetLayer((unsigned char)value[index++].GetInt());
841         }
842         else
843         {
844             // If not enough data, just add an empty animation state
845             SharedPtr<AnimationState> newState(new AnimationState(this, 0));
846             animationStates_.Push(newState);
847         }
848     }
849 
850     if (animationStates_.Size())
851     {
852         MarkAnimationDirty();
853         MarkAnimationOrderDirty();
854     }
855 }
856 
SetMorphsAttr(const PODVector<unsigned char> & value)857 void AnimatedModel::SetMorphsAttr(const PODVector<unsigned char>& value)
858 {
859     for (unsigned index = 0; index < value.Size(); ++index)
860         SetMorphWeight(index, (float)value[index] / 255.0f);
861 }
862 
GetModelAttr() const863 ResourceRef AnimatedModel::GetModelAttr() const
864 {
865     return GetResourceRef(model_, Model::GetTypeStatic());
866 }
867 
GetBonesEnabledAttr() const868 VariantVector AnimatedModel::GetBonesEnabledAttr() const
869 {
870     VariantVector ret;
871     const Vector<Bone>& bones = skeleton_.GetBones();
872     ret.Reserve(bones.Size());
873     for (Vector<Bone>::ConstIterator i = bones.Begin(); i != bones.End(); ++i)
874         ret.Push(i->animated_);
875     return ret;
876 }
877 
GetAnimationStatesAttr() const878 VariantVector AnimatedModel::GetAnimationStatesAttr() const
879 {
880     VariantVector ret;
881     ret.Reserve(animationStates_.Size() * 6 + 1);
882     ret.Push(animationStates_.Size());
883     for (Vector<SharedPtr<AnimationState> >::ConstIterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
884     {
885         AnimationState* state = *i;
886         Animation* animation = state->GetAnimation();
887         Bone* startBone = state->GetStartBone();
888         ret.Push(GetResourceRef(animation, Animation::GetTypeStatic()));
889         ret.Push(startBone ? startBone->name_ : String::EMPTY);
890         ret.Push(state->IsLooped());
891         ret.Push(state->GetWeight());
892         ret.Push(state->GetTime());
893         ret.Push((int)state->GetLayer());
894     }
895     return ret;
896 }
897 
GetMorphsAttr() const898 const PODVector<unsigned char>& AnimatedModel::GetMorphsAttr() const
899 {
900     attrBuffer_.Clear();
901     for (Vector<ModelMorph>::ConstIterator i = morphs_.Begin(); i != morphs_.End(); ++i)
902         attrBuffer_.WriteUByte((unsigned char)(i->weight_ * 255.0f));
903 
904     return attrBuffer_.GetBuffer();
905 }
906 
UpdateBoneBoundingBox()907 void AnimatedModel::UpdateBoneBoundingBox()
908 {
909     if (skeleton_.GetNumBones())
910     {
911         // The bone bounding box is in local space, so need the node's inverse transform
912         boneBoundingBox_.Clear();
913         Matrix3x4 inverseNodeTransform = node_->GetWorldTransform().Inverse();
914 
915         const Vector<Bone>& bones = skeleton_.GetBones();
916         for (Vector<Bone>::ConstIterator i = bones.Begin(); i != bones.End(); ++i)
917         {
918             Node* boneNode = i->node_;
919             if (!boneNode)
920                 continue;
921 
922             // Use hitbox if available. If not, use only half of the sphere radius
923             /// \todo The sphere radius should be multiplied with bone scale
924             if (i->collisionMask_ & BONECOLLISION_BOX)
925                 boneBoundingBox_.Merge(i->boundingBox_.Transformed(inverseNodeTransform * boneNode->GetWorldTransform()));
926             else if (i->collisionMask_ & BONECOLLISION_SPHERE)
927                 boneBoundingBox_.Merge(Sphere(inverseNodeTransform * boneNode->GetWorldPosition(), i->radius_ * 0.5f));
928         }
929     }
930 
931     boneBoundingBoxDirty_ = false;
932     worldBoundingBoxDirty_ = true;
933 }
934 
OnNodeSet(Node * node)935 void AnimatedModel::OnNodeSet(Node* node)
936 {
937     Drawable::OnNodeSet(node);
938 
939     if (node)
940     {
941         // If this AnimatedModel is the first in the node, it is the master which controls animation & morphs
942         isMaster_ = GetComponent<AnimatedModel>() == this;
943     }
944 }
945 
OnMarkedDirty(Node * node)946 void AnimatedModel::OnMarkedDirty(Node* node)
947 {
948     Drawable::OnMarkedDirty(node);
949 
950     // If the scene node or any of the bone nodes move, mark skinning dirty
951     if (skeleton_.GetNumBones())
952     {
953         skinningDirty_ = true;
954         // Bone bounding box doesn't need to be marked dirty when only the base scene node moves
955         if (node != node_)
956             boneBoundingBoxDirty_ = true;
957     }
958 }
959 
OnWorldBoundingBoxUpdate()960 void AnimatedModel::OnWorldBoundingBoxUpdate()
961 {
962     if (isMaster_)
963     {
964         // Note: do not update bone bounding box here, instead do it in either of the threaded updates
965         worldBoundingBox_ = boneBoundingBox_.Transformed(node_->GetWorldTransform());
966     }
967     else
968     {
969         // Non-master animated models get the bounding box from the master
970         /// \todo If it's a skinned attachment that does not cover the whole body, it will have unnecessarily large bounds
971         AnimatedModel* master = node_->GetComponent<AnimatedModel>();
972         // Check if we've become the new master model in case the original was deleted
973         if (master == this)
974             isMaster_ = true;
975         if (master)
976             worldBoundingBox_ = master->GetWorldBoundingBox();
977     }
978 }
979 
AssignBoneNodes()980 void AnimatedModel::AssignBoneNodes()
981 {
982     assignBonesPending_ = false;
983 
984     if (!node_)
985         return;
986 
987     // Find the bone nodes from the node hierarchy and add listeners
988     Vector<Bone>& bones = skeleton_.GetModifiableBones();
989     bool boneFound = false;
990     for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i)
991     {
992         Node* boneNode = node_->GetChild(i->name_, true);
993         if (boneNode)
994         {
995             boneFound = true;
996             boneNode->AddListener(this);
997         }
998         i->node_ = boneNode;
999     }
1000 
1001     // If no bones found, this may be a prefab where the bone information was left out.
1002     // In that case reassign the skeleton now if possible
1003     if (!boneFound && model_)
1004         SetSkeleton(model_->GetSkeleton(), true);
1005 
1006     // Re-assign the same start bone to animations to get the proper bone node this time
1007     for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
1008     {
1009         AnimationState* state = *i;
1010         state->SetStartBone(state->GetStartBone());
1011     }
1012 }
1013 
FinalizeBoneBoundingBoxes()1014 void AnimatedModel::FinalizeBoneBoundingBoxes()
1015 {
1016     Vector<Bone>& bones = skeleton_.GetModifiableBones();
1017     PODVector<AnimatedModel*> models;
1018     GetComponents<AnimatedModel>(models);
1019 
1020     if (models.Size() > 1)
1021     {
1022         // Reset first to the model resource's original bone bounding information if available (should be)
1023         if (model_)
1024         {
1025             const Vector<Bone>& modelBones = model_->GetSkeleton().GetBones();
1026             for (unsigned i = 0; i < bones.Size() && i < modelBones.Size(); ++i)
1027             {
1028                 bones[i].collisionMask_ = modelBones[i].collisionMask_;
1029                 bones[i].radius_ = modelBones[i].radius_;
1030                 bones[i].boundingBox_ = modelBones[i].boundingBox_;
1031             }
1032         }
1033 
1034         // Get matching bones from all non-master models and merge their bone bounding information
1035         // to prevent culling errors (master model may not have geometry in all bones, or the bounds are smaller)
1036         for (PODVector<AnimatedModel*>::Iterator i = models.Begin(); i != models.End(); ++i)
1037         {
1038             if ((*i) == this)
1039                 continue;
1040 
1041             Skeleton& otherSkeleton = (*i)->GetSkeleton();
1042             for (Vector<Bone>::Iterator j = bones.Begin(); j != bones.End(); ++j)
1043             {
1044                 Bone* otherBone = otherSkeleton.GetBone(j->nameHash_);
1045                 if (otherBone)
1046                 {
1047                     if (otherBone->collisionMask_ & BONECOLLISION_SPHERE)
1048                     {
1049                         j->collisionMask_ |= BONECOLLISION_SPHERE;
1050                         j->radius_ = Max(j->radius_, otherBone->radius_);
1051                     }
1052                     if (otherBone->collisionMask_ & BONECOLLISION_BOX)
1053                     {
1054                         j->collisionMask_ |= BONECOLLISION_BOX;
1055                         if (j->boundingBox_.Defined())
1056                             j->boundingBox_.Merge(otherBone->boundingBox_);
1057                         else
1058                             j->boundingBox_.Define(otherBone->boundingBox_);
1059                     }
1060                 }
1061             }
1062         }
1063     }
1064 
1065     // Remove collision information from dummy bones that do not affect skinning, to prevent them from being merged
1066     // to the bounding box and making it artificially large
1067     for (Vector<Bone>::Iterator i = bones.Begin(); i != bones.End(); ++i)
1068     {
1069         if (i->collisionMask_ & BONECOLLISION_BOX && i->boundingBox_.Size().Length() < M_EPSILON)
1070             i->collisionMask_ &= ~BONECOLLISION_BOX;
1071         if (i->collisionMask_ & BONECOLLISION_SPHERE && i->radius_ < M_EPSILON)
1072             i->collisionMask_ &= ~BONECOLLISION_SPHERE;
1073     }
1074 }
1075 
RemoveRootBone()1076 void AnimatedModel::RemoveRootBone()
1077 {
1078     Bone* rootBone = skeleton_.GetRootBone();
1079     if (rootBone && rootBone->node_)
1080         rootBone->node_->Remove();
1081 }
1082 
MarkAnimationDirty()1083 void AnimatedModel::MarkAnimationDirty()
1084 {
1085     if (isMaster_)
1086     {
1087         animationDirty_ = true;
1088         MarkForUpdate();
1089     }
1090 }
1091 
MarkAnimationOrderDirty()1092 void AnimatedModel::MarkAnimationOrderDirty()
1093 {
1094     if (isMaster_)
1095     {
1096         animationOrderDirty_ = true;
1097         MarkForUpdate();
1098     }
1099 }
1100 
MarkMorphsDirty()1101 void AnimatedModel::MarkMorphsDirty()
1102 {
1103     morphsDirty_ = true;
1104 }
1105 
CloneGeometries()1106 void AnimatedModel::CloneGeometries()
1107 {
1108     const Vector<SharedPtr<VertexBuffer> >& originalVertexBuffers = model_->GetVertexBuffers();
1109     HashMap<VertexBuffer*, SharedPtr<VertexBuffer> > clonedVertexBuffers;
1110     morphVertexBuffers_.Resize(originalVertexBuffers.Size());
1111 
1112     for (unsigned i = 0; i < originalVertexBuffers.Size(); ++i)
1113     {
1114         VertexBuffer* original = originalVertexBuffers[i];
1115         if (model_->GetMorphRangeCount(i))
1116         {
1117             SharedPtr<VertexBuffer> clone(new VertexBuffer(context_));
1118             clone->SetShadowed(true);
1119             clone->SetSize(original->GetVertexCount(), morphElementMask_ & original->GetElementMask(), true);
1120             void* dest = clone->Lock(0, original->GetVertexCount());
1121             if (dest)
1122             {
1123                 CopyMorphVertices(dest, original->GetShadowData(), original->GetVertexCount(), clone, original);
1124                 clone->Unlock();
1125             }
1126             clonedVertexBuffers[original] = clone;
1127             morphVertexBuffers_[i] = clone;
1128         }
1129         else
1130             morphVertexBuffers_[i].Reset();
1131     }
1132 
1133     // Geometries will always be cloned fully. They contain only references to buffer, so they are relatively light
1134     for (unsigned i = 0; i < geometries_.Size(); ++i)
1135     {
1136         for (unsigned j = 0; j < geometries_[i].Size(); ++j)
1137         {
1138             SharedPtr<Geometry> original = geometries_[i][j];
1139             SharedPtr<Geometry> clone(new Geometry(context_));
1140 
1141             // Add an additional vertex stream into the clone, which supplies only the morphable vertex data, while the static
1142             // data comes from the original vertex buffer(s)
1143             const Vector<SharedPtr<VertexBuffer> >& originalBuffers = original->GetVertexBuffers();
1144             unsigned totalBuf = originalBuffers.Size();
1145             for (unsigned k = 0; k < originalBuffers.Size(); ++k)
1146             {
1147                 VertexBuffer* originalBuffer = originalBuffers[k];
1148                 if (clonedVertexBuffers.Contains(originalBuffer))
1149                     ++totalBuf;
1150             }
1151             clone->SetNumVertexBuffers(totalBuf);
1152 
1153             unsigned l = 0;
1154             for (unsigned k = 0; k < originalBuffers.Size(); ++k)
1155             {
1156                 VertexBuffer* originalBuffer = originalBuffers[k];
1157 
1158                 if (clonedVertexBuffers.Contains(originalBuffer))
1159                 {
1160                     VertexBuffer* clonedBuffer = clonedVertexBuffers[originalBuffer];
1161                     clone->SetVertexBuffer(l++, originalBuffer);
1162                     // Specify the morph buffer at a greater index to override the model's original positions/normals/tangents
1163                     clone->SetVertexBuffer(l++, clonedBuffer);
1164                 }
1165                 else
1166                     clone->SetVertexBuffer(l++, originalBuffer);
1167             }
1168 
1169             clone->SetIndexBuffer(original->GetIndexBuffer());
1170             clone->SetDrawRange(original->GetPrimitiveType(), original->GetIndexStart(), original->GetIndexCount());
1171             clone->SetLodDistance(original->GetLodDistance());
1172 
1173             geometries_[i][j] = clone;
1174         }
1175     }
1176 
1177     // Make sure the rendering batches use the new cloned geometries
1178     ResetLodLevels();
1179     MarkMorphsDirty();
1180 }
1181 
CopyMorphVertices(void * destVertexData,void * srcVertexData,unsigned vertexCount,VertexBuffer * destBuffer,VertexBuffer * srcBuffer)1182 void AnimatedModel::CopyMorphVertices(void* destVertexData, void* srcVertexData, unsigned vertexCount, VertexBuffer* destBuffer,
1183     VertexBuffer* srcBuffer)
1184 {
1185     unsigned mask = destBuffer->GetElementMask() & srcBuffer->GetElementMask();
1186     unsigned normalOffset = srcBuffer->GetElementOffset(SEM_NORMAL);
1187     unsigned tangentOffset = srcBuffer->GetElementOffset(SEM_TANGENT);
1188     unsigned vertexSize = srcBuffer->GetVertexSize();
1189     float* dest = (float*)destVertexData;
1190     unsigned char* src = (unsigned char*)srcVertexData;
1191 
1192     while (vertexCount--)
1193     {
1194         if (mask & MASK_POSITION)
1195         {
1196             float* posSrc = (float*)src;
1197             dest[0] = posSrc[0];
1198             dest[1] = posSrc[1];
1199             dest[2] = posSrc[2];
1200             dest += 3;
1201         }
1202         if (mask & MASK_NORMAL)
1203         {
1204             float* normalSrc = (float*)(src + normalOffset);
1205             dest[0] = normalSrc[0];
1206             dest[1] = normalSrc[1];
1207             dest[2] = normalSrc[2];
1208             dest += 3;
1209         }
1210         if (mask & MASK_TANGENT)
1211         {
1212             float* tangentSrc = (float*)(src + tangentOffset);
1213             dest[0] = tangentSrc[0];
1214             dest[1] = tangentSrc[1];
1215             dest[2] = tangentSrc[2];
1216             dest[3] = tangentSrc[3];
1217             dest += 4;
1218         }
1219 
1220         src += vertexSize;
1221     }
1222 }
1223 
SetGeometryBoneMappings()1224 void AnimatedModel::SetGeometryBoneMappings()
1225 {
1226     geometrySkinMatrices_.Clear();
1227     geometrySkinMatrixPtrs_.Clear();
1228 
1229     if (!geometryBoneMappings_.Size())
1230         return;
1231 
1232     // Check if all mappings are empty, then we do not need to use mapped skinning
1233     bool allEmpty = true;
1234     for (unsigned i = 0; i < geometryBoneMappings_.Size(); ++i)
1235         if (geometryBoneMappings_[i].Size())
1236             allEmpty = false;
1237 
1238     if (allEmpty)
1239         return;
1240 
1241     // Reserve space for per-geometry skinning matrices
1242     geometrySkinMatrices_.Resize(geometryBoneMappings_.Size());
1243     for (unsigned i = 0; i < geometryBoneMappings_.Size(); ++i)
1244         geometrySkinMatrices_[i].Resize(geometryBoneMappings_[i].Size());
1245 
1246     // Build original-to-skinindex matrix pointer mapping for fast copying
1247     // Note: at this point layout of geometrySkinMatrices_ cannot be modified or pointers become invalid
1248     geometrySkinMatrixPtrs_.Resize(skeleton_.GetNumBones());
1249     for (unsigned i = 0; i < geometryBoneMappings_.Size(); ++i)
1250     {
1251         for (unsigned j = 0; j < geometryBoneMappings_[i].Size(); ++j)
1252             geometrySkinMatrixPtrs_[geometryBoneMappings_[i][j]].Push(&geometrySkinMatrices_[i][j]);
1253     }
1254 }
1255 
UpdateAnimation(const FrameInfo & frame)1256 void AnimatedModel::UpdateAnimation(const FrameInfo& frame)
1257 {
1258     // If using animation LOD, accumulate time and see if it is time to update
1259     if (animationLodBias_ > 0.0f && animationLodDistance_ > 0.0f)
1260     {
1261         // Perform the first update always regardless of LOD timer
1262         if (animationLodTimer_ >= 0.0f)
1263         {
1264             animationLodTimer_ += animationLodBias_ * frame.timeStep_ * ANIMATION_LOD_BASESCALE;
1265             if (animationLodTimer_ >= animationLodDistance_)
1266                 animationLodTimer_ = fmodf(animationLodTimer_, animationLodDistance_);
1267             else
1268                 return;
1269         }
1270         else
1271             animationLodTimer_ = 0.0f;
1272     }
1273 
1274     ApplyAnimation();
1275 }
1276 
ApplyAnimation()1277 void AnimatedModel::ApplyAnimation()
1278 {
1279     // Make sure animations are in ascending priority order
1280     if (animationOrderDirty_)
1281     {
1282         Sort(animationStates_.Begin(), animationStates_.End(), CompareAnimationOrder);
1283         animationOrderDirty_ = false;
1284     }
1285 
1286     // Reset skeleton, apply all animations, calculate bones' bounding box. Make sure this is only done for the master model
1287     // (first AnimatedModel in a node)
1288     if (isMaster_)
1289     {
1290         skeleton_.ResetSilent();
1291         for (Vector<SharedPtr<AnimationState> >::Iterator i = animationStates_.Begin(); i != animationStates_.End(); ++i)
1292             (*i)->Apply();
1293 
1294         // Skeleton reset and animations apply the node transforms "silently" to avoid repeated marking dirty. Mark dirty now
1295         node_->MarkDirty();
1296 
1297         // Calculate new bone bounding box
1298         UpdateBoneBoundingBox();
1299     }
1300 
1301     animationDirty_ = false;
1302 }
1303 
UpdateSkinning()1304 void AnimatedModel::UpdateSkinning()
1305 {
1306     // Note: the model's world transform will be baked in the skin matrices
1307     const Vector<Bone>& bones = skeleton_.GetBones();
1308     // Use model's world transform in case a bone is missing
1309     const Matrix3x4& worldTransform = node_->GetWorldTransform();
1310 
1311     // Skinning with global matrices only
1312     if (!geometrySkinMatrices_.Size())
1313     {
1314         for (unsigned i = 0; i < bones.Size(); ++i)
1315         {
1316             const Bone& bone = bones[i];
1317             if (bone.node_)
1318                 skinMatrices_[i] = bone.node_->GetWorldTransform() * bone.offsetMatrix_;
1319             else
1320                 skinMatrices_[i] = worldTransform;
1321         }
1322     }
1323     // Skinning with per-geometry matrices
1324     else
1325     {
1326         for (unsigned i = 0; i < bones.Size(); ++i)
1327         {
1328             const Bone& bone = bones[i];
1329             if (bone.node_)
1330                 skinMatrices_[i] = bone.node_->GetWorldTransform() * bone.offsetMatrix_;
1331             else
1332                 skinMatrices_[i] = worldTransform;
1333 
1334             // Copy the skin matrix to per-geometry matrices as needed
1335             for (unsigned j = 0; j < geometrySkinMatrixPtrs_[i].Size(); ++j)
1336                 *geometrySkinMatrixPtrs_[i][j] = skinMatrices_[i];
1337         }
1338     }
1339 
1340     skinningDirty_ = false;
1341 }
1342 
UpdateMorphs()1343 void AnimatedModel::UpdateMorphs()
1344 {
1345     Graphics* graphics = GetSubsystem<Graphics>();
1346     if (!graphics)
1347         return;
1348 
1349     if (morphs_.Size())
1350     {
1351         // Reset the morph data range from all morphable vertex buffers, then apply morphs
1352         for (unsigned i = 0; i < morphVertexBuffers_.Size(); ++i)
1353         {
1354             VertexBuffer* buffer = morphVertexBuffers_[i];
1355             if (buffer)
1356             {
1357                 VertexBuffer* originalBuffer = model_->GetVertexBuffers()[i];
1358                 unsigned morphStart = model_->GetMorphRangeStart(i);
1359                 unsigned morphCount = model_->GetMorphRangeCount(i);
1360 
1361                 void* dest = buffer->Lock(morphStart, morphCount);
1362                 if (dest)
1363                 {
1364                     // Reset morph range by copying data from the original vertex buffer
1365                     CopyMorphVertices(dest, originalBuffer->GetShadowData() + morphStart * originalBuffer->GetVertexSize(),
1366                         morphCount, buffer, originalBuffer);
1367 
1368                     for (unsigned j = 0; j < morphs_.Size(); ++j)
1369                     {
1370                         if (morphs_[j].weight_ != 0.0f)
1371                         {
1372                             HashMap<unsigned, VertexBufferMorph>::Iterator k = morphs_[j].buffers_.Find(i);
1373                             if (k != morphs_[j].buffers_.End())
1374                                 ApplyMorph(buffer, dest, morphStart, k->second_, morphs_[j].weight_);
1375                         }
1376                     }
1377 
1378                     buffer->Unlock();
1379                 }
1380             }
1381         }
1382     }
1383 
1384     morphsDirty_ = false;
1385 }
1386 
ApplyMorph(VertexBuffer * buffer,void * destVertexData,unsigned morphRangeStart,const VertexBufferMorph & morph,float weight)1387 void AnimatedModel::ApplyMorph(VertexBuffer* buffer, void* destVertexData, unsigned morphRangeStart, const VertexBufferMorph& morph,
1388     float weight)
1389 {
1390     unsigned elementMask = morph.elementMask_ & buffer->GetElementMask();
1391     unsigned vertexCount = morph.vertexCount_;
1392     unsigned normalOffset = buffer->GetElementOffset(SEM_NORMAL);
1393     unsigned tangentOffset = buffer->GetElementOffset(SEM_TANGENT);
1394     unsigned vertexSize = buffer->GetVertexSize();
1395 
1396     unsigned char* srcData = morph.morphData_;
1397     unsigned char* destData = (unsigned char*)destVertexData;
1398 
1399     while (vertexCount--)
1400     {
1401         unsigned vertexIndex = *((unsigned*)srcData) - morphRangeStart;
1402         srcData += sizeof(unsigned);
1403 
1404         if (elementMask & MASK_POSITION)
1405         {
1406             float* dest = (float*)(destData + vertexIndex * vertexSize);
1407             float* src = (float*)srcData;
1408             dest[0] += src[0] * weight;
1409             dest[1] += src[1] * weight;
1410             dest[2] += src[2] * weight;
1411             srcData += 3 * sizeof(float);
1412         }
1413         if (elementMask & MASK_NORMAL)
1414         {
1415             float* dest = (float*)(destData + vertexIndex * vertexSize + normalOffset);
1416             float* src = (float*)srcData;
1417             dest[0] += src[0] * weight;
1418             dest[1] += src[1] * weight;
1419             dest[2] += src[2] * weight;
1420             srcData += 3 * sizeof(float);
1421         }
1422         if (elementMask & MASK_TANGENT)
1423         {
1424             float* dest = (float*)(destData + vertexIndex * vertexSize + tangentOffset);
1425             float* src = (float*)srcData;
1426             dest[0] += src[0] * weight;
1427             dest[1] += src[1] * weight;
1428             dest[2] += src[2] * weight;
1429             srcData += 3 * sizeof(float);
1430         }
1431     }
1432 }
1433 
HandleModelReloadFinished(StringHash eventType,VariantMap & eventData)1434 void AnimatedModel::HandleModelReloadFinished(StringHash eventType, VariantMap& eventData)
1435 {
1436     Model* currentModel = model_;
1437     model_.Reset(); // Set null to allow to be re-set
1438     SetModel(currentModel);
1439 }
1440 
1441 }
1442