diff options
Diffstat (limited to 'OpenSim/Region')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | 5 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 465 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/ScenePresence.cs | 121 |
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 | ||
23 | namespace OpenSim.Region.Framework.Scenes | 23 | namespace 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 |