diff options
author | Melanie | 2009-11-18 06:20:21 +0000 |
---|---|---|
committer | Melanie | 2009-11-18 06:20:21 +0000 |
commit | 5d0778014df68b48abb08c8f63204cf7e077af7f (patch) | |
tree | 5f6ef28958950412130f68fa3bbe1491a456eef7 /OpenSim/Region/Framework/Scenes/Animation | |
parent | Merge branch 'master' into careminster (diff) | |
parent | Change PresenceData to PresenceInfo to remove a naming conflict in the (diff) | |
download | opensim-SC-5d0778014df68b48abb08c8f63204cf7e077af7f.zip opensim-SC-5d0778014df68b48abb08c8f63204cf7e077af7f.tar.gz opensim-SC-5d0778014df68b48abb08c8f63204cf7e077af7f.tar.bz2 opensim-SC-5d0778014df68b48abb08c8f63204cf7e077af7f.tar.xz |
Merge branch 'master' into careminster
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/Animation')
4 files changed, 1339 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs new file mode 100644 index 0000000..9176d3d --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | using Animation = OpenSim.Framework.Animation; | ||
34 | |||
35 | namespace OpenSim.Region.Framework.Scenes.Animation | ||
36 | { | ||
37 | [Serializable] | ||
38 | public class AnimationSet | ||
39 | { | ||
40 | public static AvatarAnimations Animations = new AvatarAnimations(); | ||
41 | |||
42 | private OpenSim.Framework.Animation m_defaultAnimation = new OpenSim.Framework.Animation(); | ||
43 | private List<OpenSim.Framework.Animation> m_animations = new List<OpenSim.Framework.Animation>(); | ||
44 | |||
45 | public OpenSim.Framework.Animation DefaultAnimation | ||
46 | { | ||
47 | get { return m_defaultAnimation; } | ||
48 | } | ||
49 | |||
50 | public AnimationSet() | ||
51 | { | ||
52 | ResetDefaultAnimation(); | ||
53 | } | ||
54 | |||
55 | public bool HasAnimation(UUID animID) | ||
56 | { | ||
57 | if (m_defaultAnimation.AnimID == animID) | ||
58 | return true; | ||
59 | |||
60 | for (int i = 0; i < m_animations.Count; ++i) | ||
61 | { | ||
62 | if (m_animations[i].AnimID == animID) | ||
63 | return true; | ||
64 | } | ||
65 | |||
66 | return false; | ||
67 | } | ||
68 | |||
69 | public bool Add(UUID animID, int sequenceNum, UUID objectID) | ||
70 | { | ||
71 | lock (m_animations) | ||
72 | { | ||
73 | if (!HasAnimation(animID)) | ||
74 | { | ||
75 | m_animations.Add(new OpenSim.Framework.Animation(animID, sequenceNum, objectID)); | ||
76 | return true; | ||
77 | } | ||
78 | } | ||
79 | return false; | ||
80 | } | ||
81 | |||
82 | public bool Remove(UUID animID) | ||
83 | { | ||
84 | lock (m_animations) | ||
85 | { | ||
86 | if (m_defaultAnimation.AnimID == animID) | ||
87 | { | ||
88 | ResetDefaultAnimation(); | ||
89 | } | ||
90 | else if (HasAnimation(animID)) | ||
91 | { | ||
92 | for (int i = 0; i < m_animations.Count; i++) | ||
93 | { | ||
94 | if (m_animations[i].AnimID == animID) | ||
95 | { | ||
96 | m_animations.RemoveAt(i); | ||
97 | return true; | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | return false; | ||
103 | } | ||
104 | |||
105 | public void Clear() | ||
106 | { | ||
107 | ResetDefaultAnimation(); | ||
108 | m_animations.Clear(); | ||
109 | } | ||
110 | |||
111 | /// <summary> | ||
112 | /// The default animation is reserved for "main" animations | ||
113 | /// that are mutually exclusive, e.g. flying and sitting. | ||
114 | /// </summary> | ||
115 | public bool SetDefaultAnimation(UUID animID, int sequenceNum, UUID objectID) | ||
116 | { | ||
117 | if (m_defaultAnimation.AnimID != animID) | ||
118 | { | ||
119 | m_defaultAnimation = new OpenSim.Framework.Animation(animID, sequenceNum, objectID); | ||
120 | return true; | ||
121 | } | ||
122 | return false; | ||
123 | } | ||
124 | |||
125 | protected bool ResetDefaultAnimation() | ||
126 | { | ||
127 | return TrySetDefaultAnimation("STAND", 1, UUID.Zero); | ||
128 | } | ||
129 | |||
130 | /// <summary> | ||
131 | /// Set the animation as the default animation if it's known | ||
132 | /// </summary> | ||
133 | public bool TrySetDefaultAnimation(string anim, int sequenceNum, UUID objectID) | ||
134 | { | ||
135 | if (Animations.AnimsUUID.ContainsKey(anim)) | ||
136 | { | ||
137 | return SetDefaultAnimation(Animations.AnimsUUID[anim], sequenceNum, objectID); | ||
138 | } | ||
139 | return false; | ||
140 | } | ||
141 | |||
142 | public void GetArrays(out UUID[] animIDs, out int[] sequenceNums, out UUID[] objectIDs) | ||
143 | { | ||
144 | lock (m_animations) | ||
145 | { | ||
146 | animIDs = new UUID[m_animations.Count + 1]; | ||
147 | sequenceNums = new int[m_animations.Count + 1]; | ||
148 | objectIDs = new UUID[m_animations.Count + 1]; | ||
149 | |||
150 | animIDs[0] = m_defaultAnimation.AnimID; | ||
151 | sequenceNums[0] = m_defaultAnimation.SequenceNum; | ||
152 | objectIDs[0] = m_defaultAnimation.ObjectID; | ||
153 | |||
154 | for (int i = 0; i < m_animations.Count; ++i) | ||
155 | { | ||
156 | animIDs[i + 1] = m_animations[i].AnimID; | ||
157 | sequenceNums[i + 1] = m_animations[i].SequenceNum; | ||
158 | objectIDs[i + 1] = m_animations[i].ObjectID; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | public OpenSim.Framework.Animation[] ToArray() | ||
164 | { | ||
165 | OpenSim.Framework.Animation[] theArray = new OpenSim.Framework.Animation[m_animations.Count]; | ||
166 | uint i = 0; | ||
167 | try | ||
168 | { | ||
169 | foreach (OpenSim.Framework.Animation anim in m_animations) | ||
170 | theArray[i++] = anim; | ||
171 | } | ||
172 | catch | ||
173 | { | ||
174 | /* S%^t happens. Ignore. */ | ||
175 | } | ||
176 | return theArray; | ||
177 | } | ||
178 | |||
179 | public void FromArray(OpenSim.Framework.Animation[] theArray) | ||
180 | { | ||
181 | foreach (OpenSim.Framework.Animation anim in theArray) | ||
182 | m_animations.Add(anim); | ||
183 | } | ||
184 | } | ||
185 | } | ||
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AvatarAnimations.cs b/OpenSim/Region/Framework/Scenes/Animation/AvatarAnimations.cs new file mode 100644 index 0000000..659c3a5 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Animation/AvatarAnimations.cs | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.Collections.Generic; | ||
29 | using System.Xml; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Framework.Scenes.Animation | ||
33 | { | ||
34 | public class AvatarAnimations | ||
35 | { | ||
36 | public Dictionary<string, UUID> AnimsUUID = new Dictionary<string, UUID>(); | ||
37 | public Dictionary<UUID, string> AnimsNames = new Dictionary<UUID, string>(); | ||
38 | public Dictionary<UUID, string> AnimStateNames = new Dictionary<UUID, string>(); | ||
39 | |||
40 | public AvatarAnimations() | ||
41 | { | ||
42 | using (XmlTextReader reader = new XmlTextReader("data/avataranimations.xml")) | ||
43 | { | ||
44 | XmlDocument doc = new XmlDocument(); | ||
45 | doc.Load(reader); | ||
46 | foreach (XmlNode nod in doc.DocumentElement.ChildNodes) | ||
47 | { | ||
48 | if (nod.Attributes["name"] != null) | ||
49 | { | ||
50 | string name = (string)nod.Attributes["name"].Value; | ||
51 | UUID id = (UUID)nod.InnerText; | ||
52 | string animState = (string)nod.Attributes["state"].Value; | ||
53 | |||
54 | AnimsUUID.Add(name, id); | ||
55 | AnimsNames.Add(id, name); | ||
56 | if (animState != "") | ||
57 | AnimStateNames.Add(id, animState); | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | } | ||
diff --git a/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs b/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs new file mode 100644 index 0000000..3afc87f --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Animation/BinBVHAnimation.cs | |||
@@ -0,0 +1,643 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Framework.Scenes.Animation | ||
33 | { | ||
34 | /// <summary> | ||
35 | /// Written to decode and encode a binary animation asset. | ||
36 | /// The SecondLife Client reads in a BVH file and converts | ||
37 | /// it to the format described here. This isn't | ||
38 | /// </summary> | ||
39 | public class BinBVHAnimation | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// Rotation Keyframe count (used internally) | ||
43 | /// Don't use this, use the rotationkeys.Length on each joint | ||
44 | /// </summary> | ||
45 | private int rotationkeys; | ||
46 | |||
47 | /// <summary> | ||
48 | /// Position Keyframe count (used internally) | ||
49 | /// Don't use this, use the positionkeys.Length on each joint | ||
50 | /// </summary> | ||
51 | private int positionkeys; | ||
52 | |||
53 | public UInt16 unknown0; // Always 1 | ||
54 | public UInt16 unknown1; // Always 0 | ||
55 | |||
56 | /// <summary> | ||
57 | /// Animation Priority | ||
58 | /// </summary> | ||
59 | public int Priority; | ||
60 | |||
61 | /// <summary> | ||
62 | /// The animation length in seconds. | ||
63 | /// </summary> | ||
64 | public Single Length; | ||
65 | |||
66 | /// <summary> | ||
67 | /// Expression set in the client. Null if [None] is selected | ||
68 | /// </summary> | ||
69 | public string ExpressionName; // "" (null) | ||
70 | |||
71 | /// <summary> | ||
72 | /// The time in seconds to start the animation | ||
73 | /// </summary> | ||
74 | public Single InPoint; | ||
75 | |||
76 | /// <summary> | ||
77 | /// The time in seconds to end the animation | ||
78 | /// </summary> | ||
79 | public Single OutPoint; | ||
80 | |||
81 | /// <summary> | ||
82 | /// Loop the animation | ||
83 | /// </summary> | ||
84 | public bool Loop; | ||
85 | |||
86 | /// <summary> | ||
87 | /// Meta data. Ease in Seconds. | ||
88 | /// </summary> | ||
89 | public Single EaseInTime; | ||
90 | |||
91 | /// <summary> | ||
92 | /// Meta data. Ease out seconds. | ||
93 | /// </summary> | ||
94 | public Single EaseOutTime; | ||
95 | |||
96 | /// <summary> | ||
97 | /// Meta Data for the Hand Pose | ||
98 | /// </summary> | ||
99 | public uint HandPose; | ||
100 | |||
101 | /// <summary> | ||
102 | /// Number of joints defined in the animation | ||
103 | /// Don't use this.. use joints.Length | ||
104 | /// </summary> | ||
105 | private uint m_jointCount; | ||
106 | |||
107 | |||
108 | /// <summary> | ||
109 | /// Contains an array of joints | ||
110 | /// </summary> | ||
111 | public binBVHJoint[] Joints; | ||
112 | |||
113 | |||
114 | public byte[] ToBytes() | ||
115 | { | ||
116 | byte[] outputbytes = new byte[0]; | ||
117 | |||
118 | BinaryWriter iostream = new BinaryWriter(new MemoryStream()); | ||
119 | iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown0))); | ||
120 | iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown1))); | ||
121 | iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority))); | ||
122 | iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(Length))); | ||
123 | iostream.Write(BinBVHUtil.WriteNullTerminatedString(ExpressionName)); | ||
124 | iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(InPoint))); | ||
125 | iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(OutPoint))); | ||
126 | iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Loop ? 1 : 0))); | ||
127 | iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseInTime))); | ||
128 | iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseOutTime))); | ||
129 | iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes(HandPose))); | ||
130 | iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes((uint)(Joints.Length)))); | ||
131 | |||
132 | for (int i = 0; i < Joints.Length; i++) | ||
133 | { | ||
134 | Joints[i].WriteBytesToStream(iostream, InPoint, OutPoint); | ||
135 | } | ||
136 | iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(0))); | ||
137 | MemoryStream ms = (MemoryStream)iostream.BaseStream; | ||
138 | outputbytes = ms.ToArray(); | ||
139 | ms.Close(); | ||
140 | iostream.Close(); | ||
141 | return outputbytes; | ||
142 | } | ||
143 | |||
144 | public BinBVHAnimation() | ||
145 | { | ||
146 | rotationkeys = 0; | ||
147 | positionkeys = 0; | ||
148 | unknown0 = 1; | ||
149 | unknown1 = 0; | ||
150 | Priority = 1; | ||
151 | Length = 0; | ||
152 | ExpressionName = string.Empty; | ||
153 | InPoint = 0; | ||
154 | OutPoint = 0; | ||
155 | Loop = false; | ||
156 | EaseInTime = 0; | ||
157 | EaseOutTime = 0; | ||
158 | HandPose = 1; | ||
159 | m_jointCount = 0; | ||
160 | |||
161 | Joints = new binBVHJoint[1]; | ||
162 | Joints[0] = new binBVHJoint(); | ||
163 | Joints[0].Name = "mPelvis"; | ||
164 | Joints[0].Priority = 7; | ||
165 | Joints[0].positionkeys = new binBVHJointKey[1]; | ||
166 | Joints[0].rotationkeys = new binBVHJointKey[1]; | ||
167 | Random rnd = new Random(); | ||
168 | |||
169 | Joints[0].rotationkeys[0] = new binBVHJointKey(); | ||
170 | Joints[0].rotationkeys[0].time = (0f); | ||
171 | Joints[0].rotationkeys[0].key_element.X = ((float)rnd.NextDouble() * 2 - 1); | ||
172 | Joints[0].rotationkeys[0].key_element.Y = ((float)rnd.NextDouble() * 2 - 1); | ||
173 | Joints[0].rotationkeys[0].key_element.Z = ((float)rnd.NextDouble() * 2 - 1); | ||
174 | |||
175 | Joints[0].positionkeys[0] = new binBVHJointKey(); | ||
176 | Joints[0].positionkeys[0].time = (0f); | ||
177 | Joints[0].positionkeys[0].key_element.X = ((float)rnd.NextDouble() * 2 - 1); | ||
178 | Joints[0].positionkeys[0].key_element.Y = ((float)rnd.NextDouble() * 2 - 1); | ||
179 | Joints[0].positionkeys[0].key_element.Z = ((float)rnd.NextDouble() * 2 - 1); | ||
180 | |||
181 | |||
182 | } | ||
183 | |||
184 | public BinBVHAnimation(byte[] animationdata) | ||
185 | { | ||
186 | int i = 0; | ||
187 | if (!BitConverter.IsLittleEndian) | ||
188 | { | ||
189 | unknown0 = Utils.BytesToUInt16(BinBVHUtil.EndianSwap(animationdata,i,2)); i += 2; // Always 1 | ||
190 | unknown1 = Utils.BytesToUInt16(BinBVHUtil.EndianSwap(animationdata, i, 2)); i += 2; // Always 0 | ||
191 | Priority = Utils.BytesToInt(BinBVHUtil.EndianSwap(animationdata, i, 4)); i += 4; | ||
192 | Length = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4; | ||
193 | } | ||
194 | else | ||
195 | { | ||
196 | unknown0 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 1 | ||
197 | unknown1 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 0 | ||
198 | Priority = Utils.BytesToInt(animationdata, i); i += 4; | ||
199 | Length = Utils.BytesToFloat(animationdata, i); i += 4; | ||
200 | } | ||
201 | ExpressionName = ReadBytesUntilNull(animationdata, ref i); | ||
202 | if (!BitConverter.IsLittleEndian) | ||
203 | { | ||
204 | InPoint = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4; | ||
205 | OutPoint = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4; | ||
206 | Loop = (Utils.BytesToInt(BinBVHUtil.EndianSwap(animationdata, i, 4)) != 0); i += 4; | ||
207 | EaseInTime = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4; | ||
208 | EaseOutTime = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4; | ||
209 | HandPose = Utils.BytesToUInt(BinBVHUtil.EndianSwap(animationdata, i, 4)); i += 4; // Handpose? | ||
210 | |||
211 | m_jointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count | ||
212 | } | ||
213 | else | ||
214 | { | ||
215 | InPoint = Utils.BytesToFloat(animationdata, i); i += 4; | ||
216 | OutPoint = Utils.BytesToFloat(animationdata, i); i += 4; | ||
217 | Loop = (Utils.BytesToInt(animationdata, i) != 0); i += 4; | ||
218 | EaseInTime = Utils.BytesToFloat(animationdata, i); i += 4; | ||
219 | EaseOutTime = Utils.BytesToFloat(animationdata, i); i += 4; | ||
220 | HandPose = Utils.BytesToUInt(animationdata, i); i += 4; // Handpose? | ||
221 | |||
222 | m_jointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count | ||
223 | } | ||
224 | Joints = new binBVHJoint[m_jointCount]; | ||
225 | |||
226 | // deserialize the number of joints in the animation. | ||
227 | // Joints are variable length blocks of binary data consisting of joint data and keyframes | ||
228 | for (int iter = 0; iter < m_jointCount; iter++) | ||
229 | { | ||
230 | binBVHJoint joint = readJoint(animationdata, ref i); | ||
231 | Joints[iter] = joint; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | |||
236 | /// <summary> | ||
237 | /// Variable length strings seem to be null terminated in the animation asset.. but.. | ||
238 | /// use with caution, home grown. | ||
239 | /// advances the index. | ||
240 | /// </summary> | ||
241 | /// <param name="data">The animation asset byte array</param> | ||
242 | /// <param name="i">The offset to start reading</param> | ||
243 | /// <returns>a string</returns> | ||
244 | private static string ReadBytesUntilNull(byte[] data, ref int i) | ||
245 | { | ||
246 | char nterm = '\0'; // Null terminator | ||
247 | int endpos = i; | ||
248 | int startpos = i; | ||
249 | |||
250 | // Find the null character | ||
251 | for (int j = i; j < data.Length; j++) | ||
252 | { | ||
253 | char spot = Convert.ToChar(data[j]); | ||
254 | if (spot == nterm) | ||
255 | { | ||
256 | endpos = j; | ||
257 | break; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | // if we got to the end, then it's a zero length string | ||
262 | if (i == endpos) | ||
263 | { | ||
264 | // advance the 1 null character | ||
265 | i++; | ||
266 | return string.Empty; | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | // We found the end of the string | ||
271 | // append the bytes from the beginning of the string to the end of the string | ||
272 | // advance i | ||
273 | byte[] interm = new byte[endpos-i]; | ||
274 | for (; i<endpos; i++) | ||
275 | { | ||
276 | interm[i-startpos] = data[i]; | ||
277 | } | ||
278 | i++; // advance past the null character | ||
279 | |||
280 | return Utils.BytesToString(interm); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | /// <summary> | ||
285 | /// Read in a Joint from an animation asset byte array | ||
286 | /// Variable length Joint fields, yay! | ||
287 | /// Advances the index | ||
288 | /// </summary> | ||
289 | /// <param name="data">animation asset byte array</param> | ||
290 | /// <param name="i">Byte Offset of the start of the joint</param> | ||
291 | /// <returns>The Joint data serialized into the binBVHJoint structure</returns> | ||
292 | private binBVHJoint readJoint(byte[] data, ref int i) | ||
293 | { | ||
294 | |||
295 | binBVHJointKey[] positions; | ||
296 | binBVHJointKey[] rotations; | ||
297 | |||
298 | binBVHJoint pJoint = new binBVHJoint(); | ||
299 | |||
300 | /* | ||
301 | 109 | ||
302 | 84 | ||
303 | 111 | ||
304 | 114 | ||
305 | 114 | ||
306 | 111 | ||
307 | 0 <--- Null terminator | ||
308 | */ | ||
309 | |||
310 | pJoint.Name = ReadBytesUntilNull(data, ref i); // Joint name | ||
311 | |||
312 | /* | ||
313 | 2 <- Priority Revisited | ||
314 | 0 | ||
315 | 0 | ||
316 | 0 | ||
317 | */ | ||
318 | |||
319 | /* | ||
320 | 5 <-- 5 keyframes | ||
321 | 0 | ||
322 | 0 | ||
323 | 0 | ||
324 | ... 5 Keyframe data blocks | ||
325 | */ | ||
326 | |||
327 | /* | ||
328 | 2 <-- 2 keyframes | ||
329 | 0 | ||
330 | 0 | ||
331 | 0 | ||
332 | .. 2 Keyframe data blocks | ||
333 | */ | ||
334 | if (!BitConverter.IsLittleEndian) | ||
335 | { | ||
336 | pJoint.Priority = Utils.BytesToInt(BinBVHUtil.EndianSwap(data, i, 4)); i += 4; // Joint Priority override? | ||
337 | rotationkeys = Utils.BytesToInt(BinBVHUtil.EndianSwap(data, i, 4)); i += 4; // How many rotation keyframes | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | pJoint.Priority = Utils.BytesToInt(data, i); i += 4; // Joint Priority override? | ||
342 | rotationkeys = Utils.BytesToInt(data, i); i += 4; // How many rotation keyframes | ||
343 | } | ||
344 | |||
345 | // argh! floats into two bytes!.. bad bad bad bad | ||
346 | // After fighting with it for a while.. -1, to 1 seems to give the best results | ||
347 | rotations = readKeys(data, ref i, rotationkeys, -1f, 1f); | ||
348 | for (int iter = 0; iter < rotations.Length; iter++) | ||
349 | { | ||
350 | rotations[iter].W = 1f - | ||
351 | (rotations[iter].key_element.X + rotations[iter].key_element.Y + | ||
352 | rotations[iter].key_element.Z); | ||
353 | } | ||
354 | |||
355 | |||
356 | if (!BitConverter.IsLittleEndian) | ||
357 | { | ||
358 | positionkeys = Utils.BytesToInt(BinBVHUtil.EndianSwap(data, i, 4)); i += 4; // How many position keyframes | ||
359 | } | ||
360 | else | ||
361 | { | ||
362 | positionkeys = Utils.BytesToInt(data, i); i += 4; // How many position keyframes | ||
363 | } | ||
364 | |||
365 | // Read in position keyframes | ||
366 | // argh! more floats into two bytes!.. *head desk* | ||
367 | // After fighting with it for a while.. -5, to 5 seems to give the best results | ||
368 | positions = readKeys(data, ref i, positionkeys, -5f, 5f); | ||
369 | |||
370 | pJoint.rotationkeys = rotations; | ||
371 | pJoint.positionkeys = positions; | ||
372 | |||
373 | return pJoint; | ||
374 | } | ||
375 | |||
376 | /// <summary> | ||
377 | /// Read Keyframes of a certain type | ||
378 | /// advance i | ||
379 | /// </summary> | ||
380 | /// <param name="data">Animation Byte array</param> | ||
381 | /// <param name="i">Offset in the Byte Array. Will be advanced</param> | ||
382 | /// <param name="keycount">Number of Keyframes</param> | ||
383 | /// <param name="min">Scaling Min to pass to the Uint16ToFloat method</param> | ||
384 | /// <param name="max">Scaling Max to pass to the Uint16ToFloat method</param> | ||
385 | /// <returns></returns> | ||
386 | private binBVHJointKey[] readKeys(byte[] data, ref int i, int keycount, float min, float max) | ||
387 | { | ||
388 | float x; | ||
389 | float y; | ||
390 | float z; | ||
391 | |||
392 | /* | ||
393 | 0.o, Float values in Two bytes.. this is just wrong >:( | ||
394 | 17 255 <-- Time Code | ||
395 | 17 255 <-- Time Code | ||
396 | 255 255 <-- X | ||
397 | 127 127 <-- X | ||
398 | 255 255 <-- Y | ||
399 | 127 127 <-- Y | ||
400 | 213 213 <-- Z | ||
401 | 142 142 <---Z | ||
402 | |||
403 | */ | ||
404 | |||
405 | binBVHJointKey[] m_keys = new binBVHJointKey[keycount]; | ||
406 | for (int j = 0; j < keycount; j++) | ||
407 | { | ||
408 | binBVHJointKey pJKey = new binBVHJointKey(); | ||
409 | if (!BitConverter.IsLittleEndian) | ||
410 | { | ||
411 | pJKey.time = Utils.UInt16ToFloat(BinBVHUtil.EndianSwap(data, i, 2), 0, InPoint, OutPoint); i += 2; | ||
412 | x = Utils.UInt16ToFloat(BinBVHUtil.EndianSwap(data, i, 2), 0, min, max); i += 2; | ||
413 | y = Utils.UInt16ToFloat(BinBVHUtil.EndianSwap(data, i, 2), 0, min, max); i += 2; | ||
414 | z = Utils.UInt16ToFloat(BinBVHUtil.EndianSwap(data, i, 2), 0, min, max); i += 2; | ||
415 | } | ||
416 | else | ||
417 | { | ||
418 | pJKey.time = Utils.UInt16ToFloat(data, i, InPoint, OutPoint); i += 2; | ||
419 | x = Utils.UInt16ToFloat(data, i, min, max); i += 2; | ||
420 | y = Utils.UInt16ToFloat(data, i, min, max); i += 2; | ||
421 | z = Utils.UInt16ToFloat(data, i, min, max); i += 2; | ||
422 | } | ||
423 | pJKey.key_element = new Vector3(x, y, z); | ||
424 | m_keys[j] = pJKey; | ||
425 | } | ||
426 | return m_keys; | ||
427 | } | ||
428 | |||
429 | |||
430 | |||
431 | } | ||
432 | /// <summary> | ||
433 | /// A Joint and it's associated meta data and keyframes | ||
434 | /// </summary> | ||
435 | public struct binBVHJoint | ||
436 | { | ||
437 | /// <summary> | ||
438 | /// Name of the Joint. Matches the avatar_skeleton.xml in client distros | ||
439 | /// </summary> | ||
440 | public string Name; | ||
441 | |||
442 | /// <summary> | ||
443 | /// Joint Animation Override? Was the same as the Priority in testing.. | ||
444 | /// </summary> | ||
445 | public int Priority; | ||
446 | |||
447 | /// <summary> | ||
448 | /// Array of Rotation Keyframes in order from earliest to latest | ||
449 | /// </summary> | ||
450 | public binBVHJointKey[] rotationkeys; | ||
451 | |||
452 | /// <summary> | ||
453 | /// Array of Position Keyframes in order from earliest to latest | ||
454 | /// This seems to only be for the Pelvis? | ||
455 | /// </summary> | ||
456 | public binBVHJointKey[] positionkeys; | ||
457 | |||
458 | |||
459 | |||
460 | public void WriteBytesToStream(BinaryWriter iostream, float InPoint, float OutPoint) | ||
461 | { | ||
462 | iostream.Write(BinBVHUtil.WriteNullTerminatedString(Name)); | ||
463 | iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority))); | ||
464 | iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(rotationkeys.Length))); | ||
465 | for (int i=0;i<rotationkeys.Length;i++) | ||
466 | { | ||
467 | rotationkeys[i].WriteBytesToStream(iostream, InPoint, OutPoint, -1f, 1f); | ||
468 | } | ||
469 | iostream.Write(BinBVHUtil.ES(Utils.IntToBytes((positionkeys.Length)))); | ||
470 | for (int i = 0; i < positionkeys.Length; i++) | ||
471 | { | ||
472 | positionkeys[i].WriteBytesToStream(iostream, InPoint, OutPoint, -256f, 256f); | ||
473 | } | ||
474 | } | ||
475 | } | ||
476 | |||
477 | /// <summary> | ||
478 | /// A Joint Keyframe. This is either a position or a rotation. | ||
479 | /// </summary> | ||
480 | public struct binBVHJointKey | ||
481 | { | ||
482 | // Time in seconds for this keyframe. | ||
483 | public float time; | ||
484 | |||
485 | /// <summary> | ||
486 | /// Either a Vector3 position or a Vector3 Euler rotation | ||
487 | /// </summary> | ||
488 | public Vector3 key_element; | ||
489 | |||
490 | public float W; | ||
491 | |||
492 | public void WriteBytesToStream(BinaryWriter iostream, float InPoint, float OutPoint, float min, float max) | ||
493 | { | ||
494 | iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(time, InPoint, OutPoint)))); | ||
495 | iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(key_element.X, min, max)))); | ||
496 | iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(key_element.Y, min, max)))); | ||
497 | iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(key_element.Z, min, max)))); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | /// <summary> | ||
502 | /// Poses set in the animation metadata for the hands. | ||
503 | /// </summary> | ||
504 | public enum HandPose : uint | ||
505 | { | ||
506 | Spread = 0, | ||
507 | Relaxed = 1, | ||
508 | Point_Both = 2, | ||
509 | Fist = 3, | ||
510 | Relaxed_Left = 4, | ||
511 | Point_Left = 5, | ||
512 | Fist_Left = 6, | ||
513 | Relaxed_Right = 7, | ||
514 | Point_Right = 8, | ||
515 | Fist_Right = 9, | ||
516 | Salute_Right = 10, | ||
517 | Typing = 11, | ||
518 | Peace_Right = 12 | ||
519 | } | ||
520 | public static class BinBVHUtil | ||
521 | { | ||
522 | public const float ONE_OVER_U16_MAX = 1.0f / UInt16.MaxValue; | ||
523 | |||
524 | public static UInt16 FloatToUInt16(float val, float lower, float upper) | ||
525 | { | ||
526 | UInt16 uival = 0; | ||
527 | //m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue | ||
528 | //0-1 | ||
529 | |||
530 | // float difference = upper - lower; | ||
531 | // we're trying to get a zero lower and modify all values equally so we get a percentage position | ||
532 | if (lower > 0) | ||
533 | { | ||
534 | upper -= lower; | ||
535 | val = val - lower; | ||
536 | |||
537 | // start with 500 upper and 200 lower.. subtract 200 from the upper and the value | ||
538 | } | ||
539 | else //if (lower < 0 && upper > 0) | ||
540 | { | ||
541 | // double negative, 0 minus negative 5 is 5. | ||
542 | upper += 0 - lower; | ||
543 | lower += 0 - lower; | ||
544 | val += 0 - lower; | ||
545 | } | ||
546 | |||
547 | if (upper == 0) | ||
548 | val = 0; | ||
549 | else | ||
550 | { | ||
551 | val /= upper; | ||
552 | } | ||
553 | |||
554 | uival = (UInt16)(val * UInt16.MaxValue); | ||
555 | |||
556 | return uival; | ||
557 | } | ||
558 | |||
559 | |||
560 | /// <summary> | ||
561 | /// Endian Swap | ||
562 | /// Swaps endianness if necessary | ||
563 | /// </summary> | ||
564 | /// <param name="arr">Input array</param> | ||
565 | /// <returns></returns> | ||
566 | public static byte[] ES(byte[] arr) | ||
567 | { | ||
568 | if (!BitConverter.IsLittleEndian) | ||
569 | Array.Reverse(arr); | ||
570 | return arr; | ||
571 | } | ||
572 | public static byte[] EndianSwap(byte[] arr, int offset, int len) | ||
573 | { | ||
574 | byte[] bendian = new byte[offset + len]; | ||
575 | Buffer.BlockCopy(arr, offset, bendian, 0, len); | ||
576 | Array.Reverse(bendian); | ||
577 | return bendian; | ||
578 | } | ||
579 | |||
580 | public static byte[] WriteNullTerminatedString(string str) | ||
581 | { | ||
582 | byte[] output = new byte[str.Length + 1]; | ||
583 | Char[] chr = str.ToCharArray(); | ||
584 | int i = 0; | ||
585 | for (i = 0; i < chr.Length; i++) | ||
586 | { | ||
587 | output[i] = Convert.ToByte(chr[i]); | ||
588 | |||
589 | } | ||
590 | |||
591 | output[i] = Convert.ToByte('\0'); | ||
592 | return output; | ||
593 | } | ||
594 | |||
595 | } | ||
596 | } | ||
597 | /* | ||
598 | switch (jointname) | ||
599 | { | ||
600 | case "mPelvis": | ||
601 | case "mTorso": | ||
602 | case "mNeck": | ||
603 | case "mHead": | ||
604 | case "mChest": | ||
605 | case "mHipLeft": | ||
606 | case "mHipRight": | ||
607 | case "mKneeLeft": | ||
608 | case "mKneeRight": | ||
609 | // XYZ->ZXY | ||
610 | t = x; | ||
611 | x = y; | ||
612 | y = t; | ||
613 | break; | ||
614 | case "mCollarLeft": | ||
615 | case "mCollarRight": | ||
616 | case "mElbowLeft": | ||
617 | case "mElbowRight": | ||
618 | // YZX ->ZXY | ||
619 | t = z; | ||
620 | z = x; | ||
621 | x = y; | ||
622 | y = t; | ||
623 | break; | ||
624 | case "mWristLeft": | ||
625 | case "mWristRight": | ||
626 | case "mShoulderLeft": | ||
627 | case "mShoulderRight": | ||
628 | // ZYX->ZXY | ||
629 | t = y; | ||
630 | y = z; | ||
631 | z = t; | ||
632 | |||
633 | break; | ||
634 | case "mAnkleLeft": | ||
635 | case "mAnkleRight": | ||
636 | // XYZ ->ZXY | ||
637 | t = x; | ||
638 | x = z; | ||
639 | z = y; | ||
640 | y = t; | ||
641 | break; | ||
642 | } | ||
643 | */ \ No newline at end of file | ||
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs new file mode 100644 index 0000000..cbe4118 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs | |||
@@ -0,0 +1,448 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Region.Framework.Interfaces; | ||
33 | using OpenSim.Region.Framework.Scenes; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | |||
36 | namespace OpenSim.Region.Framework.Scenes.Animation | ||
37 | { | ||
38 | /// <summary> | ||
39 | /// Handle all animation duties for a scene presence | ||
40 | /// </summary> | ||
41 | public class ScenePresenceAnimator | ||
42 | { | ||
43 | public AnimationSet Animations | ||
44 | { | ||
45 | get { return m_animations; } | ||
46 | } | ||
47 | protected AnimationSet m_animations = new AnimationSet(); | ||
48 | |||
49 | /// <value> | ||
50 | /// The current movement animation | ||
51 | /// </value> | ||
52 | public string CurrentMovementAnimation | ||
53 | { | ||
54 | get { return m_movementAnimation; } | ||
55 | } | ||
56 | protected string m_movementAnimation = "DEFAULT"; | ||
57 | |||
58 | private int m_animTickFall; | ||
59 | private int m_animTickJump; | ||
60 | |||
61 | /// <value> | ||
62 | /// The scene presence that this animator applies to | ||
63 | /// </value> | ||
64 | protected ScenePresence m_scenePresence; | ||
65 | |||
66 | public ScenePresenceAnimator(ScenePresence sp) | ||
67 | { | ||
68 | m_scenePresence = sp; | ||
69 | } | ||
70 | |||
71 | public void AddAnimation(UUID animID, UUID objectID) | ||
72 | { | ||
73 | if (m_scenePresence.IsChildAgent) | ||
74 | return; | ||
75 | |||
76 | if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) | ||
77 | SendAnimPack(); | ||
78 | } | ||
79 | |||
80 | // Called from scripts | ||
81 | public void AddAnimation(string name, UUID objectID) | ||
82 | { | ||
83 | if (m_scenePresence.IsChildAgent) | ||
84 | return; | ||
85 | |||
86 | UUID animID = m_scenePresence.ControllingClient.GetDefaultAnimation(name); | ||
87 | if (animID == UUID.Zero) | ||
88 | return; | ||
89 | |||
90 | AddAnimation(animID, objectID); | ||
91 | } | ||
92 | |||
93 | public void RemoveAnimation(UUID animID) | ||
94 | { | ||
95 | if (m_scenePresence.IsChildAgent) | ||
96 | return; | ||
97 | |||
98 | if (m_animations.Remove(animID)) | ||
99 | SendAnimPack(); | ||
100 | } | ||
101 | |||
102 | // Called from scripts | ||
103 | public void RemoveAnimation(string name) | ||
104 | { | ||
105 | if (m_scenePresence.IsChildAgent) | ||
106 | return; | ||
107 | |||
108 | UUID animID = m_scenePresence.ControllingClient.GetDefaultAnimation(name); | ||
109 | if (animID == UUID.Zero) | ||
110 | return; | ||
111 | |||
112 | RemoveAnimation(animID); | ||
113 | } | ||
114 | |||
115 | public void ResetAnimations() | ||
116 | { | ||
117 | m_animations.Clear(); | ||
118 | } | ||
119 | |||
120 | /// <summary> | ||
121 | /// The movement animation is reserved for "main" animations | ||
122 | /// that are mutually exclusive, e.g. flying and sitting. | ||
123 | /// </summary> | ||
124 | public void TrySetMovementAnimation(string anim) | ||
125 | { | ||
126 | //m_log.DebugFormat("Updating movement animation to {0}", anim); | ||
127 | |||
128 | if (!m_scenePresence.IsChildAgent) | ||
129 | { | ||
130 | if (m_animations.TrySetDefaultAnimation( | ||
131 | anim, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, UUID.Zero)) | ||
132 | { | ||
133 | // 16384 is CHANGED_ANIMATION | ||
134 | m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { 16384 }); | ||
135 | SendAnimPack(); | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | |||
140 | /// <summary> | ||
141 | /// This method determines the proper movement related animation | ||
142 | /// </summary> | ||
143 | public string GetMovementAnimation() | ||
144 | { | ||
145 | const float FALL_DELAY = 0.33f; | ||
146 | const float PREJUMP_DELAY = 0.25f; | ||
147 | |||
148 | #region Inputs | ||
149 | |||
150 | AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags; | ||
151 | PhysicsActor actor = m_scenePresence.PhysicsActor; | ||
152 | |||
153 | // Create forward and left vectors from the current avatar rotation | ||
154 | Matrix4 rotMatrix = Matrix4.CreateFromQuaternion(m_scenePresence.Rotation); | ||
155 | Vector3 fwd = Vector3.Transform(Vector3.UnitX, rotMatrix); | ||
156 | Vector3 left = Vector3.Transform(Vector3.UnitY, rotMatrix); | ||
157 | |||
158 | // Check control flags | ||
159 | bool heldForward = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_AT_POS; | ||
160 | bool heldBack = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG; | ||
161 | bool heldLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS; | ||
162 | bool heldRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG; | ||
163 | //bool heldTurnLeft = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT; | ||
164 | //bool heldTurnRight = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) == AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT; | ||
165 | bool heldUp = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) == AgentManager.ControlFlags.AGENT_CONTROL_UP_POS; | ||
166 | bool heldDown = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) == AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG; | ||
167 | //bool flying = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) == AgentManager.ControlFlags.AGENT_CONTROL_FLY; | ||
168 | //bool mouselook = (controlFlags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) == AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK; | ||
169 | |||
170 | // Direction in which the avatar is trying to move | ||
171 | Vector3 move = Vector3.Zero; | ||
172 | if (heldForward) { move.X += fwd.X; move.Y += fwd.Y; } | ||
173 | if (heldBack) { move.X -= fwd.X; move.Y -= fwd.Y; } | ||
174 | if (heldLeft) { move.X += left.X; move.Y += left.Y; } | ||
175 | if (heldRight) { move.X -= left.X; move.Y -= left.Y; } | ||
176 | if (heldUp) { move.Z += 1; } | ||
177 | if (heldDown) { move.Z -= 1; } | ||
178 | |||
179 | // Is the avatar trying to move? | ||
180 | // bool moving = (move != Vector3.Zero); | ||
181 | bool jumping = m_animTickJump != 0; | ||
182 | |||
183 | #endregion Inputs | ||
184 | |||
185 | #region Flying | ||
186 | |||
187 | if (actor != null && actor.Flying) | ||
188 | { | ||
189 | m_animTickFall = 0; | ||
190 | m_animTickJump = 0; | ||
191 | |||
192 | if (move.X != 0f || move.Y != 0f) | ||
193 | { | ||
194 | return (m_scenePresence.Scene.m_useFlySlow ? "FLYSLOW" : "FLY"); | ||
195 | } | ||
196 | else if (move.Z > 0f) | ||
197 | { | ||
198 | return "HOVER_UP"; | ||
199 | } | ||
200 | else if (move.Z < 0f) | ||
201 | { | ||
202 | if (actor != null && actor.IsColliding) | ||
203 | return "LAND"; | ||
204 | else | ||
205 | return "HOVER_DOWN"; | ||
206 | } | ||
207 | else | ||
208 | { | ||
209 | return "HOVER"; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | #endregion Flying | ||
214 | |||
215 | #region Falling/Floating/Landing | ||
216 | |||
217 | if (actor == null || !actor.IsColliding) | ||
218 | { | ||
219 | float fallElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f; | ||
220 | float fallVelocity = (actor != null) ? actor.Velocity.Z : 0.0f; | ||
221 | |||
222 | if (m_animTickFall == 0 || (fallElapsed > FALL_DELAY && fallVelocity >= 0.0f)) | ||
223 | { | ||
224 | // Just started falling | ||
225 | m_animTickFall = Environment.TickCount; | ||
226 | } | ||
227 | else if (!jumping && fallElapsed > FALL_DELAY) | ||
228 | { | ||
229 | // Falling long enough to trigger the animation | ||
230 | return "FALLDOWN"; | ||
231 | } | ||
232 | |||
233 | return m_movementAnimation; | ||
234 | } | ||
235 | |||
236 | #endregion Falling/Floating/Landing | ||
237 | |||
238 | #region Ground Movement | ||
239 | |||
240 | if (m_movementAnimation == "FALLDOWN") | ||
241 | { | ||
242 | m_animTickFall = Environment.TickCount; | ||
243 | |||
244 | // TODO: SOFT_LAND support | ||
245 | return "LAND"; | ||
246 | } | ||
247 | else if (m_movementAnimation == "LAND") | ||
248 | { | ||
249 | float landElapsed = (float)(Environment.TickCount - m_animTickFall) / 1000f; | ||
250 | |||
251 | if (landElapsed <= FALL_DELAY) | ||
252 | return "LAND"; | ||
253 | } | ||
254 | |||
255 | m_animTickFall = 0; | ||
256 | |||
257 | if (move.Z > 0f) | ||
258 | { | ||
259 | // Jumping | ||
260 | if (!jumping) | ||
261 | { | ||
262 | // Begin prejump | ||
263 | m_animTickJump = Environment.TickCount; | ||
264 | return "PREJUMP"; | ||
265 | } | ||
266 | else if (Environment.TickCount - m_animTickJump > PREJUMP_DELAY * 1000.0f) | ||
267 | { | ||
268 | // Start actual jump | ||
269 | if (m_animTickJump == -1) | ||
270 | { | ||
271 | // Already jumping! End the current jump | ||
272 | m_animTickJump = 0; | ||
273 | return "JUMP"; | ||
274 | } | ||
275 | |||
276 | m_animTickJump = -1; | ||
277 | return "JUMP"; | ||
278 | } | ||
279 | } | ||
280 | else | ||
281 | { | ||
282 | // Not jumping | ||
283 | m_animTickJump = 0; | ||
284 | |||
285 | if (move.X != 0f || move.Y != 0f) | ||
286 | { | ||
287 | // Walking / crouchwalking / running | ||
288 | if (move.Z < 0f) | ||
289 | return "CROUCHWALK"; | ||
290 | else if (m_scenePresence.SetAlwaysRun) | ||
291 | return "RUN"; | ||
292 | else | ||
293 | return "WALK"; | ||
294 | } | ||
295 | else | ||
296 | { | ||
297 | // Not walking | ||
298 | if (move.Z < 0f) | ||
299 | return "CROUCH"; | ||
300 | else | ||
301 | return "STAND"; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | #endregion Ground Movement | ||
306 | |||
307 | return m_movementAnimation; | ||
308 | } | ||
309 | |||
310 | /// <summary> | ||
311 | /// Update the movement animation of this avatar according to its current state | ||
312 | /// </summary> | ||
313 | public void UpdateMovementAnimations() | ||
314 | { | ||
315 | m_movementAnimation = GetMovementAnimation(); | ||
316 | |||
317 | if (m_movementAnimation == "PREJUMP" && !m_scenePresence.Scene.m_usePreJump) | ||
318 | { | ||
319 | // This was the previous behavior before PREJUMP | ||
320 | TrySetMovementAnimation("JUMP"); | ||
321 | } | ||
322 | else | ||
323 | { | ||
324 | TrySetMovementAnimation(m_movementAnimation); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | public UUID[] GetAnimationArray() | ||
329 | { | ||
330 | UUID[] animIDs; | ||
331 | int[] sequenceNums; | ||
332 | UUID[] objectIDs; | ||
333 | m_animations.GetArrays(out animIDs, out sequenceNums, out objectIDs); | ||
334 | return animIDs; | ||
335 | } | ||
336 | |||
337 | public BinBVHAnimation GenerateRandomAnimation() | ||
338 | { | ||
339 | int rnditerations = 3; | ||
340 | BinBVHAnimation anim = new BinBVHAnimation(); | ||
341 | List<string> parts = new List<string>(); | ||
342 | parts.Add("mPelvis");parts.Add("mHead");parts.Add("mTorso"); | ||
343 | parts.Add("mHipLeft");parts.Add("mHipRight");parts.Add("mHipLeft");parts.Add("mKneeLeft"); | ||
344 | parts.Add("mKneeRight");parts.Add("mCollarLeft");parts.Add("mCollarRight");parts.Add("mNeck"); | ||
345 | parts.Add("mElbowLeft");parts.Add("mElbowRight");parts.Add("mWristLeft");parts.Add("mWristRight"); | ||
346 | parts.Add("mShoulderLeft");parts.Add("mShoulderRight");parts.Add("mAnkleLeft");parts.Add("mAnkleRight"); | ||
347 | parts.Add("mEyeRight");parts.Add("mChest");parts.Add("mToeLeft");parts.Add("mToeRight"); | ||
348 | parts.Add("mFootLeft");parts.Add("mFootRight");parts.Add("mEyeLeft"); | ||
349 | anim.HandPose = 1; | ||
350 | anim.InPoint = 0; | ||
351 | anim.OutPoint = (rnditerations * .10f); | ||
352 | anim.Priority = 7; | ||
353 | anim.Loop = false; | ||
354 | anim.Length = (rnditerations * .10f); | ||
355 | anim.ExpressionName = "afraid"; | ||
356 | anim.EaseInTime = 0; | ||
357 | anim.EaseOutTime = 0; | ||
358 | |||
359 | string[] strjoints = parts.ToArray(); | ||
360 | anim.Joints = new binBVHJoint[strjoints.Length]; | ||
361 | for (int j = 0; j < strjoints.Length; j++) | ||
362 | { | ||
363 | anim.Joints[j] = new binBVHJoint(); | ||
364 | anim.Joints[j].Name = strjoints[j]; | ||
365 | anim.Joints[j].Priority = 7; | ||
366 | anim.Joints[j].positionkeys = new binBVHJointKey[rnditerations]; | ||
367 | anim.Joints[j].rotationkeys = new binBVHJointKey[rnditerations]; | ||
368 | Random rnd = new Random(); | ||
369 | for (int i = 0; i < rnditerations; i++) | ||
370 | { | ||
371 | anim.Joints[j].rotationkeys[i] = new binBVHJointKey(); | ||
372 | anim.Joints[j].rotationkeys[i].time = (i*.10f); | ||
373 | anim.Joints[j].rotationkeys[i].key_element.X = ((float) rnd.NextDouble()*2 - 1); | ||
374 | anim.Joints[j].rotationkeys[i].key_element.Y = ((float) rnd.NextDouble()*2 - 1); | ||
375 | anim.Joints[j].rotationkeys[i].key_element.Z = ((float) rnd.NextDouble()*2 - 1); | ||
376 | anim.Joints[j].positionkeys[i] = new binBVHJointKey(); | ||
377 | anim.Joints[j].positionkeys[i].time = (i*.10f); | ||
378 | anim.Joints[j].positionkeys[i].key_element.X = 0; | ||
379 | anim.Joints[j].positionkeys[i].key_element.Y = 0; | ||
380 | anim.Joints[j].positionkeys[i].key_element.Z = 0; | ||
381 | } | ||
382 | } | ||
383 | |||
384 | AssetBase Animasset = new AssetBase(UUID.Random(), "Random Animation", (sbyte)AssetType.Animation); | ||
385 | Animasset.Data = anim.ToBytes(); | ||
386 | Animasset.Temporary = true; | ||
387 | Animasset.Local = true; | ||
388 | Animasset.Description = "dance"; | ||
389 | //BinBVHAnimation bbvhanim = new BinBVHAnimation(Animasset.Data); | ||
390 | |||
391 | m_scenePresence.Scene.AssetService.Store(Animasset); | ||
392 | AddAnimation(Animasset.FullID, m_scenePresence.UUID); | ||
393 | return anim; | ||
394 | } | ||
395 | |||
396 | /// <summary> | ||
397 | /// | ||
398 | /// </summary> | ||
399 | /// <param name="animations"></param> | ||
400 | /// <param name="seqs"></param> | ||
401 | /// <param name="objectIDs"></param> | ||
402 | public void SendAnimPack(UUID[] animations, int[] seqs, UUID[] objectIDs) | ||
403 | { | ||
404 | if (m_scenePresence.IsChildAgent) | ||
405 | return; | ||
406 | |||
407 | m_scenePresence.Scene.ForEachClient( | ||
408 | delegate(IClientAPI client) | ||
409 | { | ||
410 | client.SendAnimations(animations, seqs, m_scenePresence.ControllingClient.AgentId, objectIDs); | ||
411 | }); | ||
412 | } | ||
413 | |||
414 | public void SendAnimPackToClient(IClientAPI client) | ||
415 | { | ||
416 | if (m_scenePresence.IsChildAgent) | ||
417 | return; | ||
418 | |||
419 | UUID[] animIDs; | ||
420 | int[] sequenceNums; | ||
421 | UUID[] objectIDs; | ||
422 | |||
423 | m_animations.GetArrays(out animIDs, out sequenceNums, out objectIDs); | ||
424 | |||
425 | m_scenePresence.ControllingClient.SendAnimations( | ||
426 | animIDs, sequenceNums, m_scenePresence.ControllingClient.AgentId, objectIDs); | ||
427 | } | ||
428 | |||
429 | /// <summary> | ||
430 | /// Send animation information about this avatar to all clients. | ||
431 | /// </summary> | ||
432 | public void SendAnimPack() | ||
433 | { | ||
434 | //m_log.Debug("Sending animation pack to all"); | ||
435 | |||
436 | if (m_scenePresence.IsChildAgent) | ||
437 | return; | ||
438 | |||
439 | UUID[] animIDs; | ||
440 | int[] sequenceNums; | ||
441 | UUID[] objectIDs; | ||
442 | |||
443 | m_animations.GetArrays(out animIDs, out sequenceNums, out objectIDs); | ||
444 | |||
445 | SendAnimPack(animIDs, sequenceNums, objectIDs); | ||
446 | } | ||
447 | } | ||
448 | } \ No newline at end of file | ||