aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/KeyframeMotion.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/KeyframeMotion.cs765
1 files changed, 765 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
new file mode 100644
index 0000000..6dc6504
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
@@ -0,0 +1,765 @@
1// Proprietary code of Avination Virtual Limited
2// (c) 2012 Melanie Thielker
3//
4
5using System;
6using System.Timers;
7using System.Collections;
8using System.Collections.Generic;
9using System.IO;
10using System.Diagnostics;
11using System.Reflection;
12using System.Threading;
13using OpenMetaverse;
14using OpenSim.Framework;
15using OpenSim.Region.Framework.Interfaces;
16using OpenSim.Region.Physics.Manager;
17using OpenSim.Region.Framework.Scenes.Serialization;
18using System.Runtime.Serialization.Formatters.Binary;
19using System.Runtime.Serialization;
20using Timer = System.Timers.Timer;
21using log4net;
22
23namespace OpenSim.Region.Framework.Scenes
24{
25 public class KeyframeTimer
26 {
27 private static Dictionary<Scene, KeyframeTimer>m_timers =
28 new Dictionary<Scene, KeyframeTimer>();
29
30 private Timer m_timer;
31 private Dictionary<KeyframeMotion, object> m_motions = new Dictionary<KeyframeMotion, object>();
32 private object m_lockObject = new object();
33 private object m_timerLock = new object();
34 private const double m_tickDuration = 50.0;
35 private Scene m_scene;
36
37 public double TickDuration
38 {
39 get { return m_tickDuration; }
40 }
41
42 public KeyframeTimer(Scene scene)
43 {
44 m_timer = new Timer();
45 m_timer.Interval = TickDuration;
46 m_timer.AutoReset = true;
47 m_timer.Elapsed += OnTimer;
48
49 m_scene = scene;
50
51 m_timer.Start();
52 }
53
54 private void OnTimer(object sender, ElapsedEventArgs ea)
55 {
56 if (!Monitor.TryEnter(m_timerLock))
57 return;
58
59 try
60 {
61 List<KeyframeMotion> motions;
62
63 lock (m_lockObject)
64 {
65 motions = new List<KeyframeMotion>(m_motions.Keys);
66 }
67
68 foreach (KeyframeMotion m in motions)
69 {
70 try
71 {
72 m.OnTimer(TickDuration);
73 }
74 catch (Exception inner)
75 {
76 // Don't stop processing
77 }
78 }
79 }
80 catch (Exception e)
81 {
82 // Keep running no matter what
83 }
84 finally
85 {
86 Monitor.Exit(m_timerLock);
87 }
88 }
89
90 public static void Add(KeyframeMotion motion)
91 {
92 KeyframeTimer timer;
93
94 if (motion.Scene == null)
95 return;
96
97 lock (m_timers)
98 {
99 if (!m_timers.TryGetValue(motion.Scene, out timer))
100 {
101 timer = new KeyframeTimer(motion.Scene);
102 m_timers[motion.Scene] = timer;
103 }
104 }
105
106 lock (timer.m_lockObject)
107 {
108 timer.m_motions[motion] = null;
109 }
110 }
111
112 public static void Remove(KeyframeMotion motion)
113 {
114 KeyframeTimer timer;
115
116 if (motion.Scene == null)
117 return;
118
119 lock (m_timers)
120 {
121 if (!m_timers.TryGetValue(motion.Scene, out timer))
122 {
123 return;
124 }
125 }
126
127 lock (timer.m_lockObject)
128 {
129 timer.m_motions.Remove(motion);
130 }
131 }
132 }
133
134 [Serializable]
135 public class KeyframeMotion
136 {
137 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
138
139 public enum PlayMode : int
140 {
141 Forward = 0,
142 Reverse = 1,
143 Loop = 2,
144 PingPong = 3
145 };
146
147 [Flags]
148 public enum DataFormat : int
149 {
150 Translation = 2,
151 Rotation = 1
152 }
153
154 [Serializable]
155 public struct Keyframe
156 {
157 public Vector3? Position;
158 public Quaternion? Rotation;
159 public Quaternion StartRotation;
160 public int TimeMS;
161 public int TimeTotal;
162 public Vector3 AngularVelocity;
163 };
164
165 private Vector3 m_serializedPosition;
166 private Vector3 m_basePosition;
167 private Quaternion m_baseRotation;
168
169 private Keyframe m_currentFrame;
170
171 private List<Keyframe> m_frames = new List<Keyframe>();
172
173 private Keyframe[] m_keyframes;
174
175 // skip timer events.
176 //timer.stop doesn't assure there aren't event threads still being fired
177 [NonSerialized()]
178 private bool m_timerStopped;
179
180 [NonSerialized()]
181 private bool m_isCrossing;
182
183 [NonSerialized()]
184 private bool m_waitingCrossing;
185
186 // retry position for cross fail
187 [NonSerialized()]
188 private Vector3 m_nextPosition;
189
190 [NonSerialized()]
191 private SceneObjectGroup m_group;
192
193 private PlayMode m_mode = PlayMode.Forward;
194 private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation;
195
196 private bool m_running = false;
197
198 [NonSerialized()]
199 private bool m_selected = false;
200
201 private int m_iterations = 0;
202
203 private int m_skipLoops = 0;
204
205 [NonSerialized()]
206 private Scene m_scene;
207
208 public Scene Scene
209 {
210 get { return m_scene; }
211 }
212
213 public DataFormat Data
214 {
215 get { return m_data; }
216 }
217
218 public bool Selected
219 {
220 set
221 {
222 if (m_group != null)
223 {
224 if (!value)
225 {
226 // Once we're let go, recompute positions
227 if (m_selected)
228 UpdateSceneObject(m_group);
229 }
230 else
231 {
232 // Save selection position in case we get moved
233 if (!m_selected)
234 {
235 StopTimer();
236 m_serializedPosition = m_group.AbsolutePosition;
237 }
238 }
239 }
240 m_isCrossing = false;
241 m_waitingCrossing = false;
242 m_selected = value;
243 }
244 }
245
246 private void StartTimer()
247 {
248 KeyframeTimer.Add(this);
249 m_timerStopped = false;
250 }
251
252 private void StopTimer()
253 {
254 m_timerStopped = true;
255 KeyframeTimer.Remove(this);
256 }
257
258 public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data)
259 {
260 KeyframeMotion newMotion = null;
261
262 try
263 {
264 MemoryStream ms = new MemoryStream(data);
265 BinaryFormatter fmt = new BinaryFormatter();
266
267 newMotion = (KeyframeMotion)fmt.Deserialize(ms);
268
269 newMotion.m_group = grp;
270
271 if (grp != null)
272 {
273 newMotion.m_scene = grp.Scene;
274 if (grp.IsSelected)
275 newMotion.m_selected = true;
276 }
277
278 newMotion.m_timerStopped = false;
279 newMotion.m_isCrossing = false;
280 newMotion.m_waitingCrossing = false;
281 }
282 catch
283 {
284 newMotion = null;
285 }
286
287 return newMotion;
288 }
289
290 public void UpdateSceneObject(SceneObjectGroup grp)
291 {
292 m_isCrossing = false;
293 m_waitingCrossing = false;
294 StopTimer();
295
296 if (grp == null)
297 return;
298
299 m_group = grp;
300 m_scene = grp.Scene;
301
302 Vector3 grppos = grp.AbsolutePosition;
303 Vector3 offset = grppos - m_serializedPosition;
304 // avoid doing it more than once
305 // current this will happen draging a prim to other region
306 m_serializedPosition = grppos;
307
308 m_basePosition += offset;
309 m_currentFrame.Position += offset;
310
311 m_nextPosition += offset;
312
313 for (int i = 0; i < m_frames.Count; i++)
314 {
315 Keyframe k = m_frames[i];
316 k.Position += offset;
317 m_frames[i]=k;
318 }
319
320 if (m_running)
321 Start();
322 }
323
324 public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data)
325 {
326 m_mode = mode;
327 m_data = data;
328
329 m_group = grp;
330 if (grp != null)
331 {
332 m_basePosition = grp.AbsolutePosition;
333 m_baseRotation = grp.GroupRotation;
334 m_scene = grp.Scene;
335 }
336
337 m_timerStopped = true;
338 m_isCrossing = false;
339 m_waitingCrossing = false;
340 }
341
342 public void SetKeyframes(Keyframe[] frames)
343 {
344 m_keyframes = frames;
345 }
346
347 public KeyframeMotion Copy(SceneObjectGroup newgrp)
348 {
349 StopTimer();
350
351 KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data);
352
353 newmotion.m_group = newgrp;
354 newmotion.m_scene = newgrp.Scene;
355
356 if (m_keyframes != null)
357 {
358 newmotion.m_keyframes = new Keyframe[m_keyframes.Length];
359 m_keyframes.CopyTo(newmotion.m_keyframes, 0);
360 }
361
362 newmotion.m_frames = new List<Keyframe>(m_frames);
363
364 newmotion.m_basePosition = m_basePosition;
365 newmotion.m_baseRotation = m_baseRotation;
366
367 if (m_selected)
368 newmotion.m_serializedPosition = m_serializedPosition;
369 else
370 {
371 if (m_group != null)
372 newmotion.m_serializedPosition = m_group.AbsolutePosition;
373 else
374 newmotion.m_serializedPosition = m_serializedPosition;
375 }
376
377 newmotion.m_currentFrame = m_currentFrame;
378
379 newmotion.m_iterations = m_iterations;
380 newmotion.m_running = m_running;
381
382 if (m_running && !m_waitingCrossing)
383 StartTimer();
384
385 return newmotion;
386 }
387
388 public void Delete()
389 {
390 m_running = false;
391 StopTimer();
392 m_isCrossing = false;
393 m_waitingCrossing = false;
394 m_frames.Clear();
395 m_keyframes = null;
396 }
397
398 public void Start()
399 {
400 m_isCrossing = false;
401 m_waitingCrossing = false;
402 if (m_keyframes != null && m_group != null && m_keyframes.Length > 0)
403 {
404 StartTimer();
405 m_running = true;
406 }
407 else
408 {
409 m_running = false;
410 StopTimer();
411 }
412 }
413
414 public void Stop()
415 {
416 m_running = false;
417 m_isCrossing = false;
418 m_waitingCrossing = false;
419
420 StopTimer();
421
422 m_basePosition = m_group.AbsolutePosition;
423 m_baseRotation = m_group.GroupRotation;
424
425 m_group.RootPart.Velocity = Vector3.Zero;
426 m_group.RootPart.AngularVelocity = Vector3.Zero;
427 m_group.SendGroupRootTerseUpdate();
428// m_group.RootPart.ScheduleTerseUpdate();
429 m_frames.Clear();
430 }
431
432 public void Pause()
433 {
434 m_running = false;
435 StopTimer();
436
437 m_group.RootPart.Velocity = Vector3.Zero;
438 m_group.RootPart.AngularVelocity = Vector3.Zero;
439 m_group.SendGroupRootTerseUpdate();
440// m_group.RootPart.ScheduleTerseUpdate();
441
442 }
443
444 private void GetNextList()
445 {
446 m_frames.Clear();
447 Vector3 pos = m_basePosition;
448 Quaternion rot = m_baseRotation;
449
450 if (m_mode == PlayMode.Loop || m_mode == PlayMode.PingPong || m_iterations == 0)
451 {
452 int direction = 1;
453 if (m_mode == PlayMode.Reverse || ((m_mode == PlayMode.PingPong) && ((m_iterations & 1) != 0)))
454 direction = -1;
455
456 int start = 0;
457 int end = m_keyframes.Length;
458
459 if (direction < 0)
460 {
461 start = m_keyframes.Length - 1;
462 end = -1;
463 }
464
465 for (int i = start; i != end ; i += direction)
466 {
467 Keyframe k = m_keyframes[i];
468
469 if (k.Position.HasValue)
470 {
471 k.Position = (k.Position * direction);
472// k.Velocity = (Vector3)k.Position / (k.TimeMS / 1000.0f);
473 k.Position += pos;
474 }
475 else
476 {
477 k.Position = pos;
478// k.Velocity = Vector3.Zero;
479 }
480
481 k.StartRotation = rot;
482 if (k.Rotation.HasValue)
483 {
484 if (direction == -1)
485 k.Rotation = Quaternion.Conjugate((Quaternion)k.Rotation);
486 k.Rotation = rot * k.Rotation;
487 }
488 else
489 {
490 k.Rotation = rot;
491 }
492
493/* ang vel not in use for now
494
495 float angle = 0;
496
497 float aa = k.StartRotation.X * k.StartRotation.X + k.StartRotation.Y * k.StartRotation.Y + k.StartRotation.Z * k.StartRotation.Z + k.StartRotation.W * k.StartRotation.W;
498 float bb = ((Quaternion)k.Rotation).X * ((Quaternion)k.Rotation).X + ((Quaternion)k.Rotation).Y * ((Quaternion)k.Rotation).Y + ((Quaternion)k.Rotation).Z * ((Quaternion)k.Rotation).Z + ((Quaternion)k.Rotation).W * ((Quaternion)k.Rotation).W;
499 float aa_bb = aa * bb;
500
501 if (aa_bb == 0)
502 {
503 angle = 0;
504 }
505 else
506 {
507 float ab = k.StartRotation.X * ((Quaternion)k.Rotation).X +
508 k.StartRotation.Y * ((Quaternion)k.Rotation).Y +
509 k.StartRotation.Z * ((Quaternion)k.Rotation).Z +
510 k.StartRotation.W * ((Quaternion)k.Rotation).W;
511 float q = (ab * ab) / aa_bb;
512
513 if (q > 1.0f)
514 {
515 angle = 0;
516 }
517 else
518 {
519 angle = (float)Math.Acos(2 * q - 1);
520 }
521 }
522
523 k.AngularVelocity = (new Vector3(0, 0, 1) * (Quaternion)k.Rotation) * (angle / (k.TimeMS / 1000));
524 */
525 k.TimeTotal = k.TimeMS;
526
527 m_frames.Add(k);
528
529 pos = (Vector3)k.Position;
530 rot = (Quaternion)k.Rotation;
531 }
532
533 m_basePosition = pos;
534 m_baseRotation = rot;
535
536 m_iterations++;
537 }
538 }
539
540 public void OnTimer(double tickDuration)
541 {
542 if (m_skipLoops > 0)
543 {
544 m_skipLoops--;
545 return;
546 }
547
548 if (m_timerStopped) // trap events still in air even after a timer.stop
549 return;
550
551 if (m_group == null)
552 return;
553
554 bool update = false;
555
556 if (m_selected)
557 {
558 if (m_group.RootPart.Velocity != Vector3.Zero)
559 {
560 m_group.RootPart.Velocity = Vector3.Zero;
561 m_group.SendGroupRootTerseUpdate();
562
563 }
564 return;
565 }
566
567 if (m_isCrossing)
568 {
569 // if crossing and timer running then cross failed
570 // wait some time then
571 // retry to set the position that evtually caused the outbound
572 // if still outside region this will call startCrossing below
573 m_isCrossing = false;
574 m_group.AbsolutePosition = m_nextPosition;
575 if (!m_isCrossing)
576 {
577 StopTimer();
578 StartTimer();
579 }
580 return;
581 }
582
583 if (m_frames.Count == 0)
584 {
585 GetNextList();
586
587 if (m_frames.Count == 0)
588 {
589 Stop();
590 Scene scene = m_group.Scene;
591
592 IScriptModule[] scriptModules = scene.RequestModuleInterfaces<IScriptModule>();
593 foreach (IScriptModule m in scriptModules)
594 {
595 if (m == null)
596 continue;
597 m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]);
598 }
599
600 return;
601 }
602
603 m_currentFrame = m_frames[0];
604 m_currentFrame.TimeMS += (int)tickDuration;
605
606 //force a update on a keyframe transition
607 update = true;
608 }
609
610 m_currentFrame.TimeMS -= (int)tickDuration;
611
612 // Do the frame processing
613 double steps = (double)m_currentFrame.TimeMS / tickDuration;
614
615 if (steps <= 0.0)
616 {
617 m_group.RootPart.Velocity = Vector3.Zero;
618 m_group.RootPart.AngularVelocity = Vector3.Zero;
619
620 m_nextPosition = (Vector3)m_currentFrame.Position;
621 m_group.AbsolutePosition = m_nextPosition;
622
623 // we are sending imediate updates, no doing force a extra terseUpdate
624 // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation);
625
626 m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation;
627 m_frames.RemoveAt(0);
628 if (m_frames.Count > 0)
629 m_currentFrame = m_frames[0];
630
631 update = true;
632 }
633 else
634 {
635 float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal;
636
637 Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition;
638 Vector3 motionThisFrame = v / (float)steps;
639 v = v * 1000 / m_currentFrame.TimeMS;
640
641 if (Vector3.Mag(motionThisFrame) >= 0.05f)
642 {
643 // m_group.AbsolutePosition += motionThisFrame;
644 m_nextPosition = m_group.AbsolutePosition + motionThisFrame;
645 m_group.AbsolutePosition = m_nextPosition;
646
647 m_group.RootPart.Velocity = v;
648 update = true;
649 }
650
651 if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation)
652 {
653 Quaternion current = m_group.GroupRotation;
654
655 Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete);
656 step.Normalize();
657/* use simpler change detection
658* float angle = 0;
659
660 float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W;
661 float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W;
662 float aa_bb = aa * bb;
663
664 if (aa_bb == 0)
665 {
666 angle = 0;
667 }
668 else
669 {
670 float ab = current.X * step.X +
671 current.Y * step.Y +
672 current.Z * step.Z +
673 current.W * step.W;
674 float q = (ab * ab) / aa_bb;
675
676 if (q > 1.0f)
677 {
678 angle = 0;
679 }
680 else
681 {
682 angle = (float)Math.Acos(2 * q - 1);
683 }
684 }
685
686 if (angle > 0.01f)
687*/
688 if(Math.Abs(step.X - current.X) > 0.001f
689 || Math.Abs(step.Y - current.Y) > 0.001f
690 || Math.Abs(step.Z - current.Z) > 0.001f)
691 // assuming w is a dependente var
692
693 {
694// m_group.UpdateGroupRotationR(step);
695 m_group.RootPart.RotationOffset = step;
696
697 //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2);
698 update = true;
699 }
700 }
701 }
702
703 if (update)
704 {
705 m_group.SendGroupRootTerseUpdate();
706 }
707 }
708
709 public Byte[] Serialize()
710 {
711 StopTimer();
712 MemoryStream ms = new MemoryStream();
713
714 BinaryFormatter fmt = new BinaryFormatter();
715 SceneObjectGroup tmp = m_group;
716 m_group = null;
717 if (!m_selected && tmp != null)
718 m_serializedPosition = tmp.AbsolutePosition;
719 fmt.Serialize(ms, this);
720 m_group = tmp;
721 if (m_running && !m_waitingCrossing)
722 StartTimer();
723
724 return ms.ToArray();
725 }
726
727 public void StartCrossingCheck()
728 {
729 // timer will be restart by crossingFailure
730 // or never since crossing worked and this
731 // should be deleted
732 StopTimer();
733
734 m_isCrossing = true;
735 m_waitingCrossing = true;
736
737 // to remove / retune to smoth crossings
738 if (m_group.RootPart.Velocity != Vector3.Zero)
739 {
740 m_group.RootPart.Velocity = Vector3.Zero;
741 m_group.SendGroupRootTerseUpdate();
742// m_group.RootPart.ScheduleTerseUpdate();
743 }
744 }
745
746 public void CrossingFailure()
747 {
748 m_waitingCrossing = false;
749
750 if (m_group != null)
751 {
752 m_group.RootPart.Velocity = Vector3.Zero;
753 m_group.SendGroupRootTerseUpdate();
754// m_group.RootPart.ScheduleTerseUpdate();
755
756 if (m_running)
757 {
758 StopTimer();
759 m_skipLoops = 1200; // 60 seconds
760 StartTimer();
761 }
762 }
763 }
764 }
765}