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 "../Graphics/Skeleton.h"
26 #include "../IO/Log.h"
27 
28 #include "../DebugNew.h"
29 
30 namespace Urho3D
31 {
32 
Skeleton()33 Skeleton::Skeleton() :
34     rootBoneIndex_(M_MAX_UNSIGNED)
35 {
36 }
37 
~Skeleton()38 Skeleton::~Skeleton()
39 {
40 }
41 
Load(Deserializer & source)42 bool Skeleton::Load(Deserializer& source)
43 {
44     ClearBones();
45 
46     if (source.IsEof())
47         return false;
48 
49     unsigned bones = source.ReadUInt();
50     bones_.Reserve(bones);
51 
52     for (unsigned i = 0; i < bones; ++i)
53     {
54         Bone newBone;
55         newBone.name_ = source.ReadString();
56         newBone.nameHash_ = newBone.name_;
57         newBone.parentIndex_ = source.ReadUInt();
58         newBone.initialPosition_ = source.ReadVector3();
59         newBone.initialRotation_ = source.ReadQuaternion();
60         newBone.initialScale_ = source.ReadVector3();
61         source.Read(&newBone.offsetMatrix_.m00_, sizeof(Matrix3x4));
62 
63         // Read bone collision data
64         newBone.collisionMask_ = source.ReadUByte();
65         if (newBone.collisionMask_ & BONECOLLISION_SPHERE)
66             newBone.radius_ = source.ReadFloat();
67         if (newBone.collisionMask_ & BONECOLLISION_BOX)
68             newBone.boundingBox_ = source.ReadBoundingBox();
69 
70         if (newBone.parentIndex_ == i)
71             rootBoneIndex_ = i;
72 
73         bones_.Push(newBone);
74     }
75 
76     return true;
77 }
78 
Save(Serializer & dest) const79 bool Skeleton::Save(Serializer& dest) const
80 {
81     if (!dest.WriteUInt(bones_.Size()))
82         return false;
83 
84     for (unsigned i = 0; i < bones_.Size(); ++i)
85     {
86         const Bone& bone = bones_[i];
87         dest.WriteString(bone.name_);
88         dest.WriteUInt(bone.parentIndex_);
89         dest.WriteVector3(bone.initialPosition_);
90         dest.WriteQuaternion(bone.initialRotation_);
91         dest.WriteVector3(bone.initialScale_);
92         dest.Write(bone.offsetMatrix_.Data(), sizeof(Matrix3x4));
93 
94         // Collision info
95         dest.WriteUByte(bone.collisionMask_);
96         if (bone.collisionMask_ & BONECOLLISION_SPHERE)
97             dest.WriteFloat(bone.radius_);
98         if (bone.collisionMask_ & BONECOLLISION_BOX)
99             dest.WriteBoundingBox(bone.boundingBox_);
100     }
101 
102     return true;
103 }
104 
Define(const Skeleton & src)105 void Skeleton::Define(const Skeleton& src)
106 {
107     ClearBones();
108 
109     bones_ = src.bones_;
110     // Make sure we clear node references, if they exist
111     // (AnimatedModel will create new nodes on its own)
112     for (Vector<Bone>::Iterator i = bones_.Begin(); i != bones_.End(); ++i)
113         i->node_.Reset();
114     rootBoneIndex_ = src.rootBoneIndex_;
115 }
116 
SetRootBoneIndex(unsigned index)117 void Skeleton::SetRootBoneIndex(unsigned index)
118 {
119     if (index < bones_.Size())
120         rootBoneIndex_ = index;
121     else
122         URHO3D_LOGERROR("Root bone index out of bounds");
123 }
124 
ClearBones()125 void Skeleton::ClearBones()
126 {
127     bones_.Clear();
128     rootBoneIndex_ = M_MAX_UNSIGNED;
129 }
130 
Reset()131 void Skeleton::Reset()
132 {
133     for (Vector<Bone>::Iterator i = bones_.Begin(); i != bones_.End(); ++i)
134     {
135         if (i->animated_ && i->node_)
136             i->node_->SetTransform(i->initialPosition_, i->initialRotation_, i->initialScale_);
137     }
138 }
139 
ResetSilent()140 void Skeleton::ResetSilent()
141 {
142     for (Vector<Bone>::Iterator i = bones_.Begin(); i != bones_.End(); ++i)
143     {
144         if (i->animated_ && i->node_)
145             i->node_->SetTransformSilent(i->initialPosition_, i->initialRotation_, i->initialScale_);
146     }
147 }
148 
149 
GetRootBone()150 Bone* Skeleton::GetRootBone()
151 {
152     return GetBone(rootBoneIndex_);
153 }
154 
GetBone(unsigned index)155 Bone* Skeleton::GetBone(unsigned index)
156 {
157     return index < bones_.Size() ? &bones_[index] : (Bone*)0;
158 }
159 
GetBone(const String & name)160 Bone* Skeleton::GetBone(const String& name)
161 {
162     return GetBone(StringHash(name));
163 }
164 
GetBone(const char * name)165 Bone* Skeleton::GetBone(const char* name)
166 {
167     return GetBone(StringHash(name));
168 }
169 
GetBone(StringHash nameHash)170 Bone* Skeleton::GetBone(StringHash nameHash)
171 {
172     for (Vector<Bone>::Iterator i = bones_.Begin(); i != bones_.End(); ++i)
173     {
174         if (i->nameHash_ == nameHash)
175             return &(*i);
176     }
177 
178     return 0;
179 }
180 
181 }
182