opensim-development – Blame information for rev 1

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