aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs5
-rw-r--r--OpenSim/Region/Framework/Scenes/KeyframeMotion.cs465
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs121
3 files changed, 353 insertions, 238 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index fd82db7..f2b0160 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -4963,8 +4963,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4963 // in that direction, even though we don't model this on the server. Implementing this in the future 4963 // in that direction, even though we don't model this on the server. Implementing this in the future
4964 // may improve movement smoothness. 4964 // may improve movement smoothness.
4965// acceleration = new Vector3(1, 0, 0); 4965// acceleration = new Vector3(1, 0, 0);
4966 4966
4967 angularVelocity = Vector3.Zero; 4967 angularVelocity = presence.AngularVelocity;
4968 rotation = presence.Rotation;
4968 4969
4969 if (sendTexture) 4970 if (sendTexture)
4970 textureEntry = presence.Appearance.Texture.GetBytes(); 4971 textureEntry = presence.Appearance.Texture.GetBytes();
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 }
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index a9195f7..471caa2 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -204,6 +204,11 @@ namespace OpenSim.Region.Framework.Scenes
204 204
205 private const int LAND_VELOCITYMAG_MAX = 12; 205 private const int LAND_VELOCITYMAG_MAX = 12;
206 206
207 private const float FLY_ROLL_MAX_RADIANS = 1.1f;
208
209 private const float FLY_ROLL_RADIANS_PER_UPDATE = 0.06f;
210 private const float FLY_ROLL_RESET_RADIANS_PER_UPDATE = 0.02f;
211
207 private float m_health = 100f; 212 private float m_health = 100f;
208 213
209 protected ulong crossingFromRegion; 214 protected ulong crossingFromRegion;
@@ -606,6 +611,14 @@ namespace OpenSim.Region.Framework.Scenes
606 } 611 }
607 } 612 }
608 613
614 // Used for limited viewer 'fake' user rotations.
615 private Vector3 m_AngularVelocity = Vector3.Zero;
616
617 public Vector3 AngularVelocity
618 {
619 get { return m_AngularVelocity; }
620 }
621
609 public bool IsChildAgent { get; set; } 622 public bool IsChildAgent { get; set; }
610 public bool IsLoggingIn { get; set; } 623 public bool IsLoggingIn { get; set; }
611 624
@@ -736,6 +749,8 @@ namespace OpenSim.Region.Framework.Scenes
736 749
737 #endregion 750 #endregion
738 751
752
753
739 #region Constructor(s) 754 #region Constructor(s)
740 755
741 public ScenePresence( 756 public ScenePresence(
@@ -1225,6 +1240,85 @@ namespace OpenSim.Region.Framework.Scenes
1225 ControllingClient.StopFlying(this); 1240 ControllingClient.StopFlying(this);
1226 } 1241 }
1227 1242
1243 /// <summary>
1244 /// Applies a roll accumulator to the avatar's angular velocity for the avatar fly roll effect.
1245 /// </summary>
1246 /// <param name="amount">Postive or negative roll amount in radians</param>
1247 private void ApplyFlyingRoll(float amount, bool PressingUp, bool PressingDown)
1248 {
1249
1250 float rollAmount = Util.Clamp(m_AngularVelocity.Z + amount, -FLY_ROLL_MAX_RADIANS, FLY_ROLL_MAX_RADIANS);
1251 m_AngularVelocity.Z = rollAmount;
1252
1253 // APPLY EXTRA consideration for flying up and flying down during this time.
1254 // if we're turning left
1255 if (amount > 0)
1256 {
1257
1258 // If we're at the max roll and pressing up, we want to swing BACK a bit
1259 // Automatically adds noise
1260 if (PressingUp)
1261 {
1262 if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS - 0.04f)
1263 m_AngularVelocity.Z -= 0.9f;
1264 }
1265 // If we're at the max roll and pressing down, we want to swing MORE a bit
1266 if (PressingDown)
1267 {
1268 if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS && m_AngularVelocity.Z < FLY_ROLL_MAX_RADIANS + 0.6f)
1269 m_AngularVelocity.Z += 0.6f;
1270 }
1271 }
1272 else // we're turning right.
1273 {
1274 // If we're at the max roll and pressing up, we want to swing BACK a bit
1275 // Automatically adds noise
1276 if (PressingUp)
1277 {
1278 if (m_AngularVelocity.Z <= (-FLY_ROLL_MAX_RADIANS))
1279 m_AngularVelocity.Z += 0.6f;
1280 }
1281 // If we're at the max roll and pressing down, we want to swing MORE a bit
1282 if (PressingDown)
1283 {
1284 if (m_AngularVelocity.Z >= -FLY_ROLL_MAX_RADIANS - 0.6f)
1285 m_AngularVelocity.Z -= 0.6f;
1286 }
1287 }
1288 }
1289
1290 /// <summary>
1291 /// incrementally sets roll amount to zero
1292 /// </summary>
1293 /// <param name="amount">Positive roll amount in radians</param>
1294 /// <returns></returns>
1295 private float CalculateFlyingRollResetToZero(float amount)
1296 {
1297 const float rollMinRadians = 0f;
1298
1299 if (m_AngularVelocity.Z > 0)
1300 {
1301
1302 float leftOverToMin = m_AngularVelocity.Z - rollMinRadians;
1303 if (amount > leftOverToMin)
1304 return -leftOverToMin;
1305 else
1306 return -amount;
1307
1308 }
1309 else
1310 {
1311
1312 float leftOverToMin = -m_AngularVelocity.Z - rollMinRadians;
1313 if (amount > leftOverToMin)
1314 return leftOverToMin;
1315 else
1316 return amount;
1317 }
1318 }
1319
1320
1321
1228 // neighbouring regions we have enabled a child agent in 1322 // neighbouring regions we have enabled a child agent in
1229 // holds the seed cap for the child agent in that region 1323 // holds the seed cap for the child agent in that region
1230 private Dictionary<ulong, string> m_knownChildRegions = new Dictionary<ulong, string>(); 1324 private Dictionary<ulong, string> m_knownChildRegions = new Dictionary<ulong, string>();
@@ -1741,6 +1835,33 @@ namespace OpenSim.Region.Framework.Scenes
1741 bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || 1835 bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
1742 ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); 1836 ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
1743 1837
1838
1839 //m_log.Debug("[CONTROL]: " +flags);
1840 // Applies a satisfying roll effect to the avatar when flying.
1841 if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0) && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0))
1842 {
1843
1844 ApplyFlyingRoll(FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0));
1845
1846
1847 }
1848 else if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0) &&
1849 ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0))
1850 {
1851 ApplyFlyingRoll(-FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0));
1852
1853
1854 }
1855 else
1856 {
1857 if (m_AngularVelocity.Z != 0)
1858 m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
1859
1860 }
1861
1862
1863
1864
1744 if (Flying && IsColliding && controlland) 1865 if (Flying && IsColliding && controlland)
1745 { 1866 {
1746 // nesting this check because LengthSquared() is expensive and we don't 1867 // nesting this check because LengthSquared() is expensive and we don't