aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework
diff options
context:
space:
mode:
authorMelanie2013-01-30 15:54:14 +0100
committerMelanie2013-01-30 15:54:14 +0100
commitd1ebb0a8f91ff61138831b51c04e5c14650f938c (patch)
treecd88050e622eac4d56dce5c79cfe237e80783fbd /OpenSim/Region/Framework
parentChange default avatar replacements to be ruth rather than urban male (diff)
downloadopensim-SC-d1ebb0a8f91ff61138831b51c04e5c14650f938c.zip
opensim-SC-d1ebb0a8f91ff61138831b51c04e5c14650f938c.tar.gz
opensim-SC-d1ebb0a8f91ff61138831b51c04e5c14650f938c.tar.bz2
opensim-SC-d1ebb0a8f91ff61138831b51c04e5c14650f938c.tar.xz
Change keyframe motion to use a single timer for all objects. This is required
to prevent slippage between objects that are meant to move synchronously or keep their relative positions/rotations.
Diffstat (limited to 'OpenSim/Region/Framework')
-rw-r--r--OpenSim/Region/Framework/Scenes/KeyframeMotion.cs465
1 files changed, 229 insertions, 236 deletions
diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
index 134a620..5a1fd13 100644
--- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
+++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs
@@ -22,6 +22,77 @@ using log4net;
22 22
23namespace OpenSim.Region.Framework.Scenes 23namespace OpenSim.Region.Framework.Scenes
24{ 24{
25 public static class KeyframeTimer
26 {
27 private static Timer m_timer;
28 private static Dictionary<KeyframeMotion, object> m_motions = new Dictionary<KeyframeMotion, object>();
29 private static object m_lockObject = new object();
30 private static object m_timerLock = new object();
31 public const double timerInterval = 50.0;
32
33 static KeyframeTimer()
34 {
35 m_timer = new Timer();
36 m_timer.Interval = timerInterval;
37 m_timer.AutoReset = true;
38 m_timer.Elapsed += OnTimer;
39
40 m_timer.Start();
41 }
42
43 private static void OnTimer(object sender, ElapsedEventArgs ea)
44 {
45 if (!Monitor.TryEnter(m_timerLock))
46 return;
47
48 try
49 {
50 List<KeyframeMotion> motions;
51
52 lock (m_lockObject)
53 {
54 motions = new List<KeyframeMotion>(m_motions.Keys);
55 }
56
57 foreach (KeyframeMotion m in motions)
58 {
59 try
60 {
61 m.OnTimer();
62 }
63 catch (Exception inner)
64 {
65 // Don't stop processing
66 }
67 }
68 }
69 catch (Exception e)
70 {
71 // Keep running no matter what
72 }
73 finally
74 {
75 Monitor.Exit(m_timerLock);
76 }
77 }
78
79 public static void Add(KeyframeMotion motion)
80 {
81 lock (m_lockObject)
82 {
83 m_motions[motion] = null;
84 }
85 }
86
87 public static void Remove(KeyframeMotion motion)
88 {
89 lock (m_lockObject)
90 {
91 m_motions.Remove(motion);
92 }
93 }
94 }
95
25 [Serializable] 96 [Serializable]
26 public class KeyframeMotion 97 public class KeyframeMotion
27 { 98 {
@@ -63,18 +134,6 @@ namespace OpenSim.Region.Framework.Scenes
63 134
64 private Keyframe[] m_keyframes; 135 private Keyframe[] m_keyframes;
65 136
66 [NonSerialized()]
67 protected Timer m_timer = null;
68
69 // timer lock
70 [NonSerialized()]
71 private object m_onTimerLock;
72
73 // timer overrun detect
74 // prevents overlap or timer events threads frozen on the lock
75 [NonSerialized()]
76 private bool m_inOnTimer;
77
78 // skip timer events. 137 // skip timer events.
79 //timer.stop doesn't assure there aren't event threads still being fired 138 //timer.stop doesn't assure there aren't event threads still being fired
80 [NonSerialized()] 139 [NonSerialized()]
@@ -102,7 +161,7 @@ namespace OpenSim.Region.Framework.Scenes
102 161
103 private int m_iterations = 0; 162 private int m_iterations = 0;
104 163
105 private const double timerInterval = 50.0; 164 private int m_skipLoops = 0;
106 165
107 public DataFormat Data 166 public DataFormat Data
108 { 167 {
@@ -139,31 +198,16 @@ namespace OpenSim.Region.Framework.Scenes
139 198
140 private void StartTimer() 199 private void StartTimer()
141 { 200 {
142 if (m_timer == null) 201 KeyframeTimer.Add(this);
143 return;
144 m_timerStopped = false; 202 m_timerStopped = false;
145 m_timer.Start();
146 } 203 }
147 204
148 private void StopTimer() 205 private void StopTimer()
149 { 206 {
150 if (m_timer == null || m_timerStopped)
151 return;
152 m_timerStopped = true; 207 m_timerStopped = true;
153 m_timer.Stop(); 208 KeyframeTimer.Remove(this);
154 } 209 }
155 210
156 private void RemoveTimer()
157 {
158 if (m_timer == null)
159 return;
160 m_timerStopped = true;
161 m_timer.Stop();
162 m_timer.Elapsed -= OnTimer;
163 m_timer = null;
164 }
165
166
167 public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) 211 public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data)
168 { 212 {
169 KeyframeMotion newMotion = null; 213 KeyframeMotion newMotion = null;
@@ -180,9 +224,7 @@ namespace OpenSim.Region.Framework.Scenes
180 if (grp != null && grp.IsSelected) 224 if (grp != null && grp.IsSelected)
181 newMotion.m_selected = true; 225 newMotion.m_selected = true;
182 226
183 newMotion.m_onTimerLock = new object();
184 newMotion.m_timerStopped = false; 227 newMotion.m_timerStopped = false;
185 newMotion.m_inOnTimer = false;
186 newMotion.m_isCrossing = false; 228 newMotion.m_isCrossing = false;
187 newMotion.m_waitingCrossing = false; 229 newMotion.m_waitingCrossing = false;
188 } 230 }
@@ -196,37 +238,34 @@ namespace OpenSim.Region.Framework.Scenes
196 238
197 public void UpdateSceneObject(SceneObjectGroup grp) 239 public void UpdateSceneObject(SceneObjectGroup grp)
198 { 240 {
199// lock (m_onTimerLock) 241 m_isCrossing = false;
200 { 242 m_waitingCrossing = false;
201 m_isCrossing = false; 243 StopTimer();
202 m_waitingCrossing = false;
203 StopTimer();
204
205 if (grp == null)
206 return;
207 244
208 m_group = grp; 245 if (grp == null)
209 Vector3 grppos = grp.AbsolutePosition; 246 return;
210 Vector3 offset = grppos - m_serializedPosition;
211 // avoid doing it more than once
212 // current this will happen draging a prim to other region
213 m_serializedPosition = grppos;
214 247
215 m_basePosition += offset; 248 m_group = grp;
216 m_currentFrame.Position += offset; 249 Vector3 grppos = grp.AbsolutePosition;
250 Vector3 offset = grppos - m_serializedPosition;
251 // avoid doing it more than once
252 // current this will happen draging a prim to other region
253 m_serializedPosition = grppos;
217 254
218 m_nextPosition += offset; 255 m_basePosition += offset;
256 m_currentFrame.Position += offset;
219 257
220 for (int i = 0; i < m_frames.Count; i++) 258 m_nextPosition += offset;
221 {
222 Keyframe k = m_frames[i];
223 k.Position += offset;
224 m_frames[i]=k;
225 }
226 259
227 if (m_running) 260 for (int i = 0; i < m_frames.Count; i++)
228 Start(); 261 {
262 Keyframe k = m_frames[i];
263 k.Position += offset;
264 m_frames[i]=k;
229 } 265 }
266
267 if (m_running)
268 Start();
230 } 269 }
231 270
232 public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data) 271 public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data)
@@ -241,9 +280,7 @@ namespace OpenSim.Region.Framework.Scenes
241 m_baseRotation = grp.GroupRotation; 280 m_baseRotation = grp.GroupRotation;
242 } 281 }
243 282
244 m_onTimerLock = new object();
245 m_timerStopped = true; 283 m_timerStopped = true;
246 m_inOnTimer = false;
247 m_isCrossing = false; 284 m_isCrossing = false;
248 m_waitingCrossing = false; 285 m_waitingCrossing = false;
249 } 286 }
@@ -296,7 +333,7 @@ namespace OpenSim.Region.Framework.Scenes
296 public void Delete() 333 public void Delete()
297 { 334 {
298 m_running = false; 335 m_running = false;
299 RemoveTimer(); 336 StopTimer();
300 m_isCrossing = false; 337 m_isCrossing = false;
301 m_waitingCrossing = false; 338 m_waitingCrossing = false;
302 m_frames.Clear(); 339 m_frames.Clear();
@@ -309,27 +346,13 @@ namespace OpenSim.Region.Framework.Scenes
309 m_waitingCrossing = false; 346 m_waitingCrossing = false;
310 if (m_keyframes != null && m_group != null && m_keyframes.Length > 0) 347 if (m_keyframes != null && m_group != null && m_keyframes.Length > 0)
311 { 348 {
312 if (m_timer == null)
313 {
314 m_timer = new Timer();
315 m_timer.Interval = timerInterval;
316 m_timer.AutoReset = true;
317 m_timer.Elapsed += OnTimer;
318 }
319 else
320 {
321 StopTimer();
322 m_timer.Interval = timerInterval;
323 }
324
325 m_inOnTimer = false;
326 StartTimer(); 349 StartTimer();
327 m_running = true; 350 m_running = true;
328 } 351 }
329 else 352 else
330 { 353 {
331 m_running = false; 354 m_running = false;
332 RemoveTimer(); 355 StopTimer();
333 } 356 }
334 } 357 }
335 358
@@ -339,7 +362,7 @@ namespace OpenSim.Region.Framework.Scenes
339 m_isCrossing = false; 362 m_isCrossing = false;
340 m_waitingCrossing = false; 363 m_waitingCrossing = false;
341 364
342 RemoveTimer(); 365 StopTimer();
343 366
344 m_basePosition = m_group.AbsolutePosition; 367 m_basePosition = m_group.AbsolutePosition;
345 m_baseRotation = m_group.GroupRotation; 368 m_baseRotation = m_group.GroupRotation;
@@ -354,7 +377,7 @@ namespace OpenSim.Region.Framework.Scenes
354 public void Pause() 377 public void Pause()
355 { 378 {
356 m_running = false; 379 m_running = false;
357 RemoveTimer(); 380 StopTimer();
358 381
359 m_group.RootPart.Velocity = Vector3.Zero; 382 m_group.RootPart.Velocity = Vector3.Zero;
360 m_group.RootPart.AngularVelocity = Vector3.Zero; 383 m_group.RootPart.AngularVelocity = Vector3.Zero;
@@ -377,15 +400,11 @@ namespace OpenSim.Region.Framework.Scenes
377 400
378 int start = 0; 401 int start = 0;
379 int end = m_keyframes.Length; 402 int end = m_keyframes.Length;
380// if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1)
381// end = m_keyframes.Length - 1;
382 403
383 if (direction < 0) 404 if (direction < 0)
384 { 405 {
385 start = m_keyframes.Length - 1; 406 start = m_keyframes.Length - 1;
386 end = -1; 407 end = -1;
387// if (m_mode == PlayMode.PingPong && m_keyframes.Length > 1)
388// end = 0;
389 } 408 }
390 409
391 for (int i = start; i != end ; i += direction) 410 for (int i = start; i != end ; i += direction)
@@ -463,199 +482,172 @@ namespace OpenSim.Region.Framework.Scenes
463 } 482 }
464 } 483 }
465 484
466 protected void OnTimer(object sender, ElapsedEventArgs e) 485 public void OnTimer()
467 { 486 {
468 if (m_timerStopped) // trap events still in air even after a timer.stop 487 if (m_skipLoops > 0)
469 return;
470
471 if (m_inOnTimer) // don't let overruns to happen
472 { 488 {
473 m_log.Warn("[KeyFrame]: timer overrun"); 489 m_skipLoops--;
474 return; 490 return;
475 } 491 }
476 492
493 if (m_timerStopped) // trap events still in air even after a timer.stop
494 return;
495
477 if (m_group == null) 496 if (m_group == null)
478 return; 497 return;
479 498
480 lock (m_onTimerLock) 499 bool update = false;
481 {
482 500
483 m_inOnTimer = true; 501 if (m_selected)
502 {
503 if (m_group.RootPart.Velocity != Vector3.Zero)
504 {
505 m_group.RootPart.Velocity = Vector3.Zero;
506 m_group.SendGroupRootTerseUpdate();
484 507
485 bool update = false; 508 }
509 return;
510 }
486 511
487 try 512 if (m_isCrossing)
513 {
514 // if crossing and timer running then cross failed
515 // wait some time then
516 // retry to set the position that evtually caused the outbound
517 // if still outside region this will call startCrossing below
518 m_isCrossing = false;
519 m_group.AbsolutePosition = m_nextPosition;
520 if (!m_isCrossing)
488 { 521 {
489 if (m_selected) 522 StopTimer();
490 { 523 StartTimer();
491 if (m_group.RootPart.Velocity != Vector3.Zero) 524 }
492 { 525 return;
493 m_group.RootPart.Velocity = Vector3.Zero; 526 }
494 m_group.SendGroupRootTerseUpdate();
495// m_group.RootPart.ScheduleTerseUpdate();
496 527
497 } 528 if (m_frames.Count == 0)
498 m_inOnTimer = false; 529 {
499 return; 530 GetNextList();
500 }
501 531
502 if (m_isCrossing) 532 if (m_frames.Count == 0)
503 { 533 {
504 // if crossing and timer running then cross failed 534 Stop();
505 // wait some time then 535 Scene scene = m_group.Scene;
506 // retry to set the position that evtually caused the outbound
507 // if still outside region this will call startCrossing below
508 m_isCrossing = false;
509 m_group.AbsolutePosition = m_nextPosition;
510 if (!m_isCrossing)
511 {
512 StopTimer();
513 m_timer.Interval = timerInterval;
514 StartTimer();
515 }
516 m_inOnTimer = false;
517 return;
518 }
519 536
520 if (m_frames.Count == 0) 537 IScriptModule[] scriptModules = scene.RequestModuleInterfaces<IScriptModule>();
538 foreach (IScriptModule m in scriptModules)
521 { 539 {
522 GetNextList(); 540 if (m == null)
541 continue;
542 m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]);
543 }
523 544
524 if (m_frames.Count == 0) 545 return;
525 { 546 }
526 Stop();
527 m_inOnTimer = false;
528 Scene scene = m_group.Scene;
529
530 IScriptModule[] scriptModules = scene.RequestModuleInterfaces<IScriptModule>();
531 foreach (IScriptModule m in scriptModules)
532 {
533 if (m == null)
534 continue;
535 m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]);
536 }
537
538 return;
539 }
540 547
541 m_currentFrame = m_frames[0]; 548 m_currentFrame = m_frames[0];
542 m_currentFrame.TimeMS += (int)timerInterval; 549 m_currentFrame.TimeMS += (int)KeyframeTimer.timerInterval;
543 550
544 //force a update on a keyframe transition 551 //force a update on a keyframe transition
545 update = true; 552 update = true;
546 } 553 }
547 554
548 m_currentFrame.TimeMS -= (int)timerInterval; 555 m_currentFrame.TimeMS -= (int)KeyframeTimer.timerInterval;
549 556
550 // Do the frame processing 557 // Do the frame processing
551 double steps = (double)m_currentFrame.TimeMS / timerInterval; 558 double steps = (double)m_currentFrame.TimeMS / KeyframeTimer.timerInterval;
552 559
553 if (steps <= 0.0) 560 if (steps <= 0.0)
554 { 561 {
555 m_group.RootPart.Velocity = Vector3.Zero; 562 m_group.RootPart.Velocity = Vector3.Zero;
556 m_group.RootPart.AngularVelocity = Vector3.Zero; 563 m_group.RootPart.AngularVelocity = Vector3.Zero;
557 564
558 m_nextPosition = (Vector3)m_currentFrame.Position; 565 m_nextPosition = (Vector3)m_currentFrame.Position;
559 m_group.AbsolutePosition = m_nextPosition; 566 m_group.AbsolutePosition = m_nextPosition;
560 567
561 // we are sending imediate updates, no doing force a extra terseUpdate 568 // we are sending imediate updates, no doing force a extra terseUpdate
562// m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); 569 // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation);
563 570
564 m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation; 571 m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation;
565 m_frames.RemoveAt(0); 572 m_frames.RemoveAt(0);
566 if (m_frames.Count > 0) 573 if (m_frames.Count > 0)
567 m_currentFrame = m_frames[0]; 574 m_currentFrame = m_frames[0];
568 575
569 update = true; 576 update = true;
570 } 577 }
571 else 578 else
572 { 579 {
573 float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; 580 float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal;
574 581
575 Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; 582 Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition;
576 Vector3 motionThisFrame = v / (float)steps; 583 Vector3 motionThisFrame = v / (float)steps;
577 v = v * 1000 / m_currentFrame.TimeMS; 584 v = v * 1000 / m_currentFrame.TimeMS;
578 585
579 if (Vector3.Mag(motionThisFrame) >= 0.05f) 586 if (Vector3.Mag(motionThisFrame) >= 0.05f)
580 { 587 {
581 // m_group.AbsolutePosition += motionThisFrame; 588 // m_group.AbsolutePosition += motionThisFrame;
582 m_nextPosition = m_group.AbsolutePosition + motionThisFrame; 589 m_nextPosition = m_group.AbsolutePosition + motionThisFrame;
583 m_group.AbsolutePosition = m_nextPosition; 590 m_group.AbsolutePosition = m_nextPosition;
584 591
585 m_group.RootPart.Velocity = v; 592 m_group.RootPart.Velocity = v;
586 update = true; 593 update = true;
587 } 594 }
588 595
589 if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) 596 if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation)
590 { 597 {
591 Quaternion current = m_group.GroupRotation; 598 Quaternion current = m_group.GroupRotation;
592 599
593 Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); 600 Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete);
594 step.Normalize(); 601 step.Normalize();
595/* use simpler change detection 602/* use simpler change detection
596 * float angle = 0; 603* float angle = 0;
597
598 float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W;
599 float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W;
600 float aa_bb = aa * bb;
601
602 if (aa_bb == 0)
603 {
604 angle = 0;
605 }
606 else
607 {
608 float ab = current.X * step.X +
609 current.Y * step.Y +
610 current.Z * step.Z +
611 current.W * step.W;
612 float q = (ab * ab) / aa_bb;
613
614 if (q > 1.0f)
615 {
616 angle = 0;
617 }
618 else
619 {
620 angle = (float)Math.Acos(2 * q - 1);
621 }
622 }
623
624 if (angle > 0.01f)
625 */
626 if(Math.Abs(step.X - current.X) > 0.001f
627 || Math.Abs(step.Y - current.Y) > 0.001f
628 || Math.Abs(step.Z - current.Z) > 0.001f)
629 // assuming w is a dependente var
630 604
631 { 605 float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W;
632// m_group.UpdateGroupRotationR(step); 606 float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W;
633 m_group.RootPart.RotationOffset = step; 607 float aa_bb = aa * bb;
608
609 if (aa_bb == 0)
610 {
611 angle = 0;
612 }
613 else
614 {
615 float ab = current.X * step.X +
616 current.Y * step.Y +
617 current.Z * step.Z +
618 current.W * step.W;
619 float q = (ab * ab) / aa_bb;
634 620
635 //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); 621 if (q > 1.0f)
636 update = true; 622 {
637 } 623 angle = 0;
624 }
625 else
626 {
627 angle = (float)Math.Acos(2 * q - 1);
638 } 628 }
639 } 629 }
640 630
641 if (update) 631 if (angle > 0.01f)
642 m_group.SendGroupRootTerseUpdate(); 632*/
643// m_group.RootPart.ScheduleTerseUpdate(); 633 if(Math.Abs(step.X - current.X) > 0.001f
634 || Math.Abs(step.Y - current.Y) > 0.001f
635 || Math.Abs(step.Z - current.Z) > 0.001f)
636 // assuming w is a dependente var
644 637
638 {
639// m_group.UpdateGroupRotationR(step);
640 m_group.RootPart.RotationOffset = step;
645 641
642 //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2);
643 update = true;
644 }
646 } 645 }
647 catch ( Exception ex) 646 }
648 {
649 // still happening sometimes
650 // lets try to see where
651 m_log.Warn("[KeyFrame]: timer overrun" + ex.Message);
652 }
653 647
654 finally 648 if (update)
655 { 649 {
656 // make sure we do not let this frozen 650 m_group.SendGroupRootTerseUpdate();
657 m_inOnTimer = false;
658 }
659 } 651 }
660 } 652 }
661 653
@@ -687,7 +679,7 @@ namespace OpenSim.Region.Framework.Scenes
687 m_isCrossing = true; 679 m_isCrossing = true;
688 m_waitingCrossing = true; 680 m_waitingCrossing = true;
689 681
690// to remove / retune to smoth crossings 682 // to remove / retune to smoth crossings
691 if (m_group.RootPart.Velocity != Vector3.Zero) 683 if (m_group.RootPart.Velocity != Vector3.Zero)
692 { 684 {
693 m_group.RootPart.Velocity = Vector3.Zero; 685 m_group.RootPart.Velocity = Vector3.Zero;
@@ -706,9 +698,10 @@ namespace OpenSim.Region.Framework.Scenes
706 m_group.SendGroupRootTerseUpdate(); 698 m_group.SendGroupRootTerseUpdate();
707// m_group.RootPart.ScheduleTerseUpdate(); 699// m_group.RootPart.ScheduleTerseUpdate();
708 700
709 if (m_running && m_timer != null) 701 if (m_running)
710 { 702 {
711 m_timer.Interval = 60000; 703 StopTimer();
704 m_skipLoops = 1200; // 60 seconds
712 StartTimer(); 705 StartTimer();
713 } 706 }
714 } 707 }