aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs39
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs65
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs9
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs70
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs5
5 files changed, 144 insertions, 44 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index dd30a59..16a8588 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -959,7 +959,15 @@ namespace OpenSim.Region.Framework.Scenes
959 } 959 }
960 return m_angularVelocity; 960 return m_angularVelocity;
961 } 961 }
962 set { m_angularVelocity = value; } 962 set
963 {
964 m_angularVelocity = value;
965 PhysicsActor actor = PhysActor;
966 if ((actor != null) && actor.IsPhysical && ParentGroup.RootPart == this && VehicleType == (int)Vehicle.TYPE_NONE)
967 {
968 actor.RotationalVelocity = m_angularVelocity;
969 }
970 }
963 } 971 }
964 972
965 /// <summary></summary> 973 /// <summary></summary>
@@ -1845,7 +1853,7 @@ namespace OpenSim.Region.Framework.Scenes
1845 } 1853 }
1846 } 1854 }
1847 1855
1848// SetVelocity for LSL llSetVelocity.. may need revision if having other uses in future 1856 // SetVelocity for LSL llSetVelocity.. may need revision if having other uses in future
1849 public void SetVelocity(Vector3 pVel, bool localGlobalTF) 1857 public void SetVelocity(Vector3 pVel, bool localGlobalTF)
1850 { 1858 {
1851 if (ParentGroup == null || ParentGroup.IsDeleted) 1859 if (ParentGroup == null || ParentGroup.IsDeleted)
@@ -1871,6 +1879,33 @@ namespace OpenSim.Region.Framework.Scenes
1871 1879
1872 ParentGroup.Velocity = pVel; 1880 ParentGroup.Velocity = pVel;
1873 } 1881 }
1882
1883 // SetAngularVelocity for LSL llSetAngularVelocity.. may need revision if having other uses in future
1884 public void SetAngularVelocity(Vector3 pAngVel, bool localGlobalTF)
1885 {
1886 if (ParentGroup == null || ParentGroup.IsDeleted)
1887 return;
1888
1889 if (ParentGroup.IsAttachment)
1890 return; // don't work on attachments (for now ??)
1891
1892 SceneObjectPart root = ParentGroup.RootPart;
1893
1894 if (root.VehicleType != (int)Vehicle.TYPE_NONE) // don't mess with vehicles
1895 return;
1896
1897 PhysicsActor pa = root.PhysActor;
1898
1899 if (pa == null || !pa.IsPhysical)
1900 return;
1901
1902 if (localGlobalTF)
1903 {
1904 pAngVel = pAngVel * GetWorldRotation();
1905 }
1906
1907 root.AngularVelocity = pAngVel;
1908 }
1874 1909
1875 1910
1876 /// <summary> 1911 /// <summary>
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs
index 3d8e680..14e4272 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODEPrim.cs
@@ -583,8 +583,6 @@ namespace OpenSim.Region.Physics.OdePlugin
583 if (value.IsFinite()) 583 if (value.IsFinite())
584 { 584 {
585 AddChange(changes.Velocity, value); 585 AddChange(changes.Velocity, value);
586// _velocity = value;
587
588 } 586 }
589 else 587 else
590 { 588 {
@@ -676,9 +674,7 @@ namespace OpenSim.Region.Physics.OdePlugin
676 { 674 {
677 if (value.IsFinite()) 675 if (value.IsFinite())
678 { 676 {
679 m_rotationalVelocity = value; 677 AddChange(changes.AngVelocity, value);
680 if (Body != IntPtr.Zero && !d.BodyIsEnabled(Body))
681 d.BodyEnable(Body);
682 } 678 }
683 else 679 else
684 { 680 {
@@ -687,7 +683,6 @@ namespace OpenSim.Region.Physics.OdePlugin
687 } 683 }
688 } 684 }
689 685
690
691 public override float Buoyancy 686 public override float Buoyancy
692 { 687 {
693 get { return m_buoyancy; } 688 get { return m_buoyancy; }
@@ -1737,17 +1732,14 @@ namespace OpenSim.Region.Physics.OdePlugin
1737 1732
1738 d.BodySetAutoDisableFlag(Body, true); 1733 d.BodySetAutoDisableFlag(Body, true);
1739 d.BodySetAutoDisableSteps(Body, body_autodisable_frames); 1734 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1740// d.BodySetLinearDampingThreshold(Body, 0.01f); 1735 d.BodySetDamping(Body, .005f, .005f);
1741// d.BodySetAngularDampingThreshold(Body, 0.001f);
1742 d.BodySetDamping(Body, .002f, .002f);
1743
1744 if (m_targetSpace != IntPtr.Zero)
1745 {
1746 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1747 if (d.SpaceQuery(m_targetSpace, prim_geom))
1748 d.SpaceRemove(m_targetSpace, prim_geom);
1749 }
1750 1736
1737 if (m_targetSpace != IntPtr.Zero)
1738 {
1739 _parent_scene.waitForSpaceUnlock(m_targetSpace);
1740 if (d.SpaceQuery(m_targetSpace, prim_geom))
1741 d.SpaceRemove(m_targetSpace, prim_geom);
1742 }
1751 1743
1752 if (childrenPrim.Count == 0) 1744 if (childrenPrim.Count == 0)
1753 { 1745 {
@@ -3296,6 +3288,13 @@ namespace OpenSim.Region.Physics.OdePlugin
3296 3288
3297 private void changevelocity(Vector3 newVel) 3289 private void changevelocity(Vector3 newVel)
3298 { 3290 {
3291 float len = newVel.LengthSquared();
3292 if (len > 100000.0f) // limit to 100m/s
3293 {
3294 len = 100.0f / (float)Math.Sqrt(len);
3295 newVel *= len;
3296 }
3297
3299 if (!m_isSelected) 3298 if (!m_isSelected)
3300 { 3299 {
3301 if (Body != IntPtr.Zero) 3300 if (Body != IntPtr.Zero)
@@ -3312,6 +3311,33 @@ namespace OpenSim.Region.Physics.OdePlugin
3312 _velocity = newVel; 3311 _velocity = newVel;
3313 } 3312 }
3314 3313
3314
3315 private void changeangvelocity(Vector3 newAngVel)
3316 {
3317 float len = newAngVel.LengthSquared();
3318 if (len > 144.0f) // limit to 12rad/s
3319 {
3320 len = 12.0f / (float)Math.Sqrt(len);
3321 newAngVel *= len;
3322 }
3323
3324 if (!m_isSelected)
3325 {
3326 if (Body != IntPtr.Zero)
3327 {
3328 if (m_disabled)
3329 enableBodySoft();
3330 else if (!d.BodyIsEnabled(Body))
3331 d.BodyEnable(Body);
3332
3333
3334 d.BodySetAngularVel(Body, newAngVel.X, newAngVel.Y, newAngVel.Z);
3335 }
3336 //resetCollisionAccounting();
3337 }
3338 m_rotationalVelocity = newAngVel;
3339 }
3340
3315 private void changeVolumedetetion(bool newVolDtc) 3341 private void changeVolumedetetion(bool newVolDtc)
3316 { 3342 {
3317 m_isVolumeDetect = newVolDtc; 3343 m_isVolumeDetect = newVolDtc;
@@ -3948,9 +3974,10 @@ namespace OpenSim.Region.Physics.OdePlugin
3948// case changes.Acceleration: 3974// case changes.Acceleration:
3949// changeacceleration((Vector3)arg); 3975// changeacceleration((Vector3)arg);
3950// break; 3976// break;
3951// case changes.AngVelocity: 3977
3952// changeangvelocity((Vector3)arg); 3978 case changes.AngVelocity:
3953// break; 3979 changeangvelocity((Vector3)arg);
3980 break;
3954 3981
3955 case changes.Force: 3982 case changes.Force:
3956 changeForce((Vector3)arg); 3983 changeForce((Vector3)arg);
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs
index 0e4961b..2341186 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeApi.cs
@@ -1312,7 +1312,14 @@ namespace OdeAPI
1312 public static extern void GeomTriMeshSetRayCallback(IntPtr g, TriRayCallback callback); 1312 public static extern void GeomTriMeshSetRayCallback(IntPtr g, TriRayCallback callback);
1313 1313
1314 [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGetConfiguration"), SuppressUnmanagedCodeSecurity] 1314 [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGetConfiguration"), SuppressUnmanagedCodeSecurity]
1315 public static extern string GetConfiguration(string str); 1315 public static extern IntPtr iGetConfiguration();
1316
1317 public static string GetConfiguration()
1318 {
1319 IntPtr ptr = iGetConfiguration();
1320 string s = Marshal.PtrToStringAnsi(ptr);
1321 return s;
1322 }
1316 1323
1317 [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dHashSpaceCreate"), SuppressUnmanagedCodeSecurity] 1324 [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dHashSpaceCreate"), SuppressUnmanagedCodeSecurity]
1318 public static extern IntPtr HashSpaceCreate(IntPtr space); 1325 public static extern IntPtr HashSpaceCreate(IntPtr space);
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
index 4552f3f..d5938f4 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs
@@ -175,7 +175,7 @@ namespace OpenSim.Region.Physics.OdePlugin
175 175
176 const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce; 176 const d.ContactFlags comumContactFlags = d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM |d.ContactFlags.Approx1 | d.ContactFlags.Bounce;
177 const float MaxERP = 0.8f; 177 const float MaxERP = 0.8f;
178 const float minERP = 0.1f; 178 const float minERP = 0.2f;
179 const float comumContactCFM = 0.0001f; 179 const float comumContactCFM = 0.0001f;
180 180
181 float frictionMovementMult = 0.8f; 181 float frictionMovementMult = 0.8f;
@@ -268,7 +268,7 @@ namespace OpenSim.Region.Physics.OdePlugin
268 268
269 public ContactData[] m_materialContactsData = new ContactData[8]; 269 public ContactData[] m_materialContactsData = new ContactData[8];
270 270
271 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>(); 271 private readonly Dictionary<Vector3, IntPtr> RegionTerrain = new Dictionary<Vector3, IntPtr>();
272 private readonly Dictionary<IntPtr, float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>(); 272 private readonly Dictionary<IntPtr, float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
273 private readonly Dictionary<IntPtr, GCHandle> TerrainHeightFieldHeightsHandlers = new Dictionary<IntPtr, GCHandle>(); 273 private readonly Dictionary<IntPtr, GCHandle> TerrainHeightFieldHeightsHandlers = new Dictionary<IntPtr, GCHandle>();
274 274
@@ -408,8 +408,8 @@ namespace OpenSim.Region.Physics.OdePlugin
408// checkThread(); 408// checkThread();
409 mesher = meshmerizer; 409 mesher = meshmerizer;
410 m_config = config; 410 m_config = config;
411/* 411
412 string ode_config = d.GetConfiguration("ODE"); 412 string ode_config = d.GetConfiguration();
413 if (ode_config != null && ode_config != "") 413 if (ode_config != null && ode_config != "")
414 { 414 {
415 m_log.WarnFormat("ODE configuration: {0}", ode_config); 415 m_log.WarnFormat("ODE configuration: {0}", ode_config);
@@ -419,7 +419,7 @@ namespace OpenSim.Region.Physics.OdePlugin
419 OdeUbitLib = true; 419 OdeUbitLib = true;
420 } 420 }
421 } 421 }
422*/ 422
423 /* 423 /*
424 if (region != null) 424 if (region != null)
425 { 425 {
@@ -921,6 +921,8 @@ namespace OpenSim.Region.Physics.OdePlugin
921 cfm = 0.0001f / cfm; 921 cfm = 0.0001f / cfm;
922 if (cfm > 0.01f) 922 if (cfm > 0.01f)
923 cfm = 0.01f; 923 cfm = 0.01f;
924 else if (cfm < 0.0001f)
925 cfm = 0.0001f;
924 926
925 if ((Math.Abs(p2.Velocity.X - p1.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y - p1.Velocity.Y) > 0.1f)) 927 if ((Math.Abs(p2.Velocity.X - p1.Velocity.X) > 0.1f || Math.Abs(p2.Velocity.Y - p1.Velocity.Y) > 0.1f))
926 mu *= frictionMovementMult; 928 mu *= frictionMovementMult;
@@ -947,6 +949,8 @@ namespace OpenSim.Region.Physics.OdePlugin
947 cfm = 0.0001f / cfm; 949 cfm = 0.0001f / cfm;
948 if (cfm > 0.01f) 950 if (cfm > 0.01f)
949 cfm = 0.01f; 951 cfm = 0.01f;
952 else if (cfm < 0.0001f)
953 cfm = 0.0001f;
950 954
951 if (d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass) 955 if (d.GeomGetClass(g1) == d.GeomClassID.TriMeshClass)
952 { 956 {
@@ -1892,18 +1896,22 @@ namespace OpenSim.Region.Physics.OdePlugin
1892 lock (SimulationLock) 1896 lock (SimulationLock)
1893 lock(OdeLock) 1897 lock(OdeLock)
1894 { 1898 {
1899 if (world == IntPtr.Zero)
1900 return 0;
1901
1895 // adjust number of iterations per step 1902 // adjust number of iterations per step
1896 try 1903
1897 { 1904// try
1905// {
1898 d.WorldSetQuickStepNumIterations(world, curphysiteractions); 1906 d.WorldSetQuickStepNumIterations(world, curphysiteractions);
1899 } 1907/* }
1900 catch (StackOverflowException) 1908 catch (StackOverflowException)
1901 { 1909 {
1902 m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim."); 1910 m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
1903// ode.drelease(world); 1911// ode.drelease(world);
1904 base.TriggerPhysicsBasedRestart(); 1912 base.TriggerPhysicsBasedRestart();
1905 } 1913 }
1906 1914*/
1907 while (step_time > HalfOdeStep && nodeframes < 10) //limit number of steps so we don't say here for ever 1915 while (step_time > HalfOdeStep && nodeframes < 10) //limit number of steps so we don't say here for ever
1908 { 1916 {
1909 try 1917 try
@@ -2383,11 +2391,9 @@ namespace OpenSim.Region.Physics.OdePlugin
2383 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle); 2391 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
2384 d.GeomSetRotation(GroundGeom, ref R); 2392 d.GeomSetRotation(GroundGeom, ref R);
2385 d.GeomSetPosition(GroundGeom, pOffset.X + (float)Constants.RegionSize * 0.5f, pOffset.Y + (float)Constants.RegionSize * 0.5f, 0); 2393 d.GeomSetPosition(GroundGeom, pOffset.X + (float)Constants.RegionSize * 0.5f, pOffset.Y + (float)Constants.RegionSize * 0.5f, 0);
2386 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); 2394 RegionTerrain.Add(pOffset, GroundGeom);
2387// TerrainHeightFieldHeights.Add(GroundGeom, ODElandMap);
2388 TerrainHeightFieldHeights.Add(GroundGeom, _heightmap); 2395 TerrainHeightFieldHeights.Add(GroundGeom, _heightmap);
2389 TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler); 2396 TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler);
2390
2391 } 2397 }
2392 } 2398 }
2393 2399
@@ -2486,8 +2492,7 @@ namespace OpenSim.Region.Physics.OdePlugin
2486 geom_name_map[GroundGeom] = "Terrain"; 2492 geom_name_map[GroundGeom] = "Terrain";
2487 2493
2488 d.GeomSetPosition(GroundGeom, pOffset.X + (float)Constants.RegionSize * 0.5f, pOffset.Y + (float)Constants.RegionSize * 0.5f, 0); 2494 d.GeomSetPosition(GroundGeom, pOffset.X + (float)Constants.RegionSize * 0.5f, pOffset.Y + (float)Constants.RegionSize * 0.5f, 0);
2489 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom); 2495 RegionTerrain.Add(pOffset, GroundGeom);
2490 // TerrainHeightFieldHeights.Add(GroundGeom, ODElandMap);
2491 TerrainHeightFieldHeights.Add(GroundGeom, _heightmap); 2496 TerrainHeightFieldHeights.Add(GroundGeom, _heightmap);
2492 TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler); 2497 TerrainHeightFieldHeightsHandlers.Add(GroundGeom, _heightmaphandler);
2493 } 2498 }
@@ -2649,19 +2654,42 @@ namespace OpenSim.Region.Physics.OdePlugin
2649 2654
2650 public override void Dispose() 2655 public override void Dispose()
2651 { 2656 {
2652 m_rayCastManager.Dispose();
2653 m_rayCastManager = null;
2654
2655 lock (OdeLock) 2657 lock (OdeLock)
2656 { 2658 {
2659 m_rayCastManager.Dispose();
2660 m_rayCastManager = null;
2661
2657 lock (_prims) 2662 lock (_prims)
2658 { 2663 {
2664 ChangesQueue.Clear();
2659 foreach (OdePrim prm in _prims) 2665 foreach (OdePrim prm in _prims)
2660 { 2666 {
2661 RemovePrim(prm); 2667 prm.DoAChange(changes.Remove, null);
2668 _collisionEventPrim.Remove(prm);
2662 } 2669 }
2670 _prims.Clear();
2671 }
2672
2673 OdeCharacter[] chtorem;
2674 lock (_characters)
2675 {
2676 chtorem = new OdeCharacter[_characters.Count];
2677 _characters.CopyTo(chtorem);
2678 }
2679
2680 ChangesQueue.Clear();
2681 foreach (OdeCharacter ch in chtorem)
2682 ch.DoAChange(changes.Remove, null);
2683
2684
2685 foreach (IntPtr GroundGeom in RegionTerrain.Values)
2686 {
2687 if (GroundGeom != IntPtr.Zero)
2688 d.GeomDestroy(GroundGeom);
2663 } 2689 }
2664 2690
2691 RegionTerrain.Clear();
2692
2665 if (TerrainHeightFieldHeightsHandlers.Count > 0) 2693 if (TerrainHeightFieldHeightsHandlers.Count > 0)
2666 { 2694 {
2667 foreach (GCHandle gch in TerrainHeightFieldHeightsHandlers.Values) 2695 foreach (GCHandle gch in TerrainHeightFieldHeightsHandlers.Values)
@@ -2671,6 +2699,9 @@ namespace OpenSim.Region.Physics.OdePlugin
2671 } 2699 }
2672 } 2700 }
2673 2701
2702 TerrainHeightFieldHeightsHandlers.Clear();
2703 TerrainHeightFieldHeights.Clear();
2704
2674 if (WaterGeom != IntPtr.Zero) 2705 if (WaterGeom != IntPtr.Zero)
2675 { 2706 {
2676 d.GeomDestroy(WaterGeom); 2707 d.GeomDestroy(WaterGeom);
@@ -2691,6 +2722,7 @@ namespace OpenSim.Region.Physics.OdePlugin
2691 2722
2692 2723
2693 d.WorldDestroy(world); 2724 d.WorldDestroy(world);
2725 world = IntPtr.Zero;
2694 //d.CloseODE(); 2726 //d.CloseODE();
2695 } 2727 }
2696 } 2728 }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 0ee2748..05bb161 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -2597,12 +2597,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2597 return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z); 2597 return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z);
2598 } 2598 }
2599 2599
2600
2601 public void llSetAngularVelocity(LSL_Vector avel, int local) 2600 public void llSetAngularVelocity(LSL_Vector avel, int local)
2602 { 2601 {
2603 m_host.AddScriptLPS(1); 2602 m_host.AddScriptLPS(1);
2604 // Still not done !!!! 2603 m_host.SetAngularVelocity(new Vector3((float)avel.x, (float)avel.y, (float)avel.z), local != 0);
2605// m_host.SetAngularVelocity(new Vector3((float)avel.x, (float)avel.y, (float)avel.z), local != 0);
2606 } 2604 }
2607 2605
2608 public LSL_Vector llGetOmega() 2606 public LSL_Vector llGetOmega()
@@ -3806,6 +3804,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3806 3804
3807 protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain) 3805 protected void TargetOmega(SceneObjectPart part, LSL_Vector axis, double spinrate, double gain)
3808 { 3806 {
3807 spinrate *= gain;
3809 part.UpdateAngularVelocity(new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate))); 3808 part.UpdateAngularVelocity(new Vector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate)));
3810 } 3809 }
3811 3810