diff options
Diffstat (limited to '')
16 files changed, 950 insertions, 534 deletions
diff --git a/OpenSim/Data/Tests/BasicDataServiceTest.cs b/OpenSim/Data/Tests/BasicDataServiceTest.cs index d8019ba..69b79bf 100644 --- a/OpenSim/Data/Tests/BasicDataServiceTest.cs +++ b/OpenSim/Data/Tests/BasicDataServiceTest.cs | |||
@@ -44,9 +44,15 @@ namespace OpenSim.Data.Tests | |||
44 | /// <summary>This is a base class for testing any Data service for any DBMS. | 44 | /// <summary>This is a base class for testing any Data service for any DBMS. |
45 | /// Requires NUnit 2.5 or better (to support the generics). | 45 | /// Requires NUnit 2.5 or better (to support the generics). |
46 | /// </summary> | 46 | /// </summary> |
47 | /// <remarks> | ||
48 | /// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with | ||
49 | /// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true. | ||
50 | /// and similar on EstateTests, InventoryTests and RegionTests. | ||
51 | /// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts. | ||
52 | /// </remarks> | ||
47 | /// <typeparam name="TConn"></typeparam> | 53 | /// <typeparam name="TConn"></typeparam> |
48 | /// <typeparam name="TService"></typeparam> | 54 | /// <typeparam name="TService"></typeparam> |
49 | public class BasicDataServiceTest<TConn, TService> : OpenSimTestCase | 55 | public class BasicDataServiceTest<TConn, TService> |
50 | where TConn : DbConnection, new() | 56 | where TConn : DbConnection, new() |
51 | where TService : class, new() | 57 | where TService : class, new() |
52 | { | 58 | { |
diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs index af54c1a..b735c61 100644 --- a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs | |||
@@ -81,7 +81,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups | |||
81 | } | 81 | } |
82 | 82 | ||
83 | if (groupsConfig.GetString("Module", "Default") != "Default") | 83 | if (groupsConfig.GetString("Module", "Default") != "Default") |
84 | { | ||
85 | m_Enabled = false; | ||
84 | return; | 86 | return; |
87 | } | ||
85 | } | 88 | } |
86 | 89 | ||
87 | } | 90 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 3a44cc5..2d46276 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs | |||
@@ -189,20 +189,24 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
189 | { | 189 | { |
190 | foreach (GridInstantMessage im in msglist) | 190 | foreach (GridInstantMessage im in msglist) |
191 | { | 191 | { |
192 | // client.SendInstantMessage(im); | 192 | if (im.dialog == (byte)InstantMessageDialog.InventoryOffered) |
193 | 193 | // send it directly or else the item will be given twice | |
194 | // Send through scene event manager so all modules get a chance | 194 | client.SendInstantMessage(im); |
195 | // to look at this message before it gets delivered. | 195 | else |
196 | // | 196 | { |
197 | // Needed for proper state management for stored group | 197 | // Send through scene event manager so all modules get a chance |
198 | // invitations | 198 | // to look at this message before it gets delivered. |
199 | // | 199 | // |
200 | 200 | // Needed for proper state management for stored group | |
201 | im.offline = 1; | 201 | // invitations |
202 | 202 | // | |
203 | Scene s = FindScene(client.AgentId); | 203 | |
204 | if (s != null) | 204 | im.offline = 1; |
205 | s.EventManager.TriggerIncomingInstantMessage(im); | 205 | |
206 | Scene s = FindScene(client.AgentId); | ||
207 | if (s != null) | ||
208 | s.EventManager.TriggerIncomingInstantMessage(im); | ||
209 | } | ||
206 | } | 210 | } |
207 | } | 211 | } |
208 | } | 212 | } |
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs index ab8f143..7b235ae 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs | |||
@@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
365 | 365 | ||
366 | if (mainParams.Count < 4) | 366 | if (mainParams.Count < 4) |
367 | { | 367 | { |
368 | m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>"); | 368 | //m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>"); |
369 | m_console.OutputFormat("Usage: show part id <UUID-or-localID>"); | ||
369 | return; | 370 | return; |
370 | } | 371 | } |
371 | 372 | ||
@@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
405 | 406 | ||
406 | if (mainParams.Count < 5) | 407 | if (mainParams.Count < 5) |
407 | { | 408 | { |
409 | //m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>"); | ||
408 | m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>"); | 410 | m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>"); |
409 | return; | 411 | return; |
410 | } | 412 | } |
@@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
445 | 447 | ||
446 | if (mainParams.Count < 4) | 448 | if (mainParams.Count < 4) |
447 | { | 449 | { |
448 | m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>"); | 450 | m_console.OutputFormat("Usage: show part name [--regex] <name>"); |
451 | //m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>"); | ||
449 | return; | 452 | return; |
450 | } | 453 | } |
451 | 454 | ||
@@ -577,6 +580,58 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
577 | cdl.AddRow("Link number", sop.LinkNum); | 580 | cdl.AddRow("Link number", sop.LinkNum); |
578 | cdl.AddRow("Flags", sop.Flags); | 581 | cdl.AddRow("Flags", sop.Flags); |
579 | 582 | ||
583 | if (showFull) | ||
584 | { | ||
585 | PrimitiveBaseShape s = sop.Shape; | ||
586 | cdl.AddRow("FlexiDrag", s.FlexiDrag); | ||
587 | cdl.AddRow("FlexiEntry", s.FlexiEntry); | ||
588 | cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ)); | ||
589 | cdl.AddRow("FlexiGravity", s.FlexiGravity); | ||
590 | cdl.AddRow("FlexiSoftness", s.FlexiSoftness); | ||
591 | cdl.AddRow("HollowShape", s.HollowShape); | ||
592 | cdl.AddRow( | ||
593 | "LightColor", | ||
594 | string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA)); | ||
595 | cdl.AddRow("FlexiDrag", s.LightCutoff); | ||
596 | cdl.AddRow("FlexiDrag", s.LightEntry); | ||
597 | cdl.AddRow("FlexiDrag", s.LightFalloff); | ||
598 | cdl.AddRow("FlexiDrag", s.LightIntensity); | ||
599 | cdl.AddRow("FlexiDrag", s.LightRadius); | ||
600 | cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a")); | ||
601 | cdl.AddRow("PathBegin", s.PathBegin); | ||
602 | cdl.AddRow("PathEnd", s.PathEnd); | ||
603 | cdl.AddRow("PathCurve", s.PathCurve); | ||
604 | cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset); | ||
605 | cdl.AddRow("PathRevolutions", s.PathRevolutions); | ||
606 | cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY)); | ||
607 | cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY)); | ||
608 | cdl.AddRow("FlexiDrag", s.PathSkew); | ||
609 | cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY)); | ||
610 | cdl.AddRow("PathTwist", s.PathTwist); | ||
611 | cdl.AddRow("PathTwistBegin", s.PathTwistBegin); | ||
612 | cdl.AddRow("PCode", s.PCode); | ||
613 | cdl.AddRow("ProfileBegin", s.ProfileBegin); | ||
614 | cdl.AddRow("ProfileEnd", s.ProfileEnd); | ||
615 | cdl.AddRow("ProfileHollow", s.ProfileHollow); | ||
616 | cdl.AddRow("ProfileShape", s.ProfileShape); | ||
617 | cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance); | ||
618 | cdl.AddRow("ProjectionEntry", s.ProjectionEntry); | ||
619 | cdl.AddRow("ProjectionFocus", s.ProjectionFocus); | ||
620 | cdl.AddRow("ProjectionFOV", s.ProjectionFOV); | ||
621 | cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID); | ||
622 | cdl.AddRow("Scale", s.Scale); | ||
623 | cdl.AddRow( | ||
624 | "SculptData", | ||
625 | string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a")); | ||
626 | cdl.AddRow("SculptEntry", s.SculptEntry); | ||
627 | cdl.AddRow("SculptTexture", s.SculptTexture); | ||
628 | cdl.AddRow("SculptType", s.SculptType); | ||
629 | cdl.AddRow("State", s.State); | ||
630 | |||
631 | // TODO, unpack and display texture entries | ||
632 | //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures. | ||
633 | } | ||
634 | |||
580 | object itemsOutput; | 635 | object itemsOutput; |
581 | if (showFull) | 636 | if (showFull) |
582 | { | 637 | { |
@@ -588,7 +643,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands | |||
588 | itemsOutput = sop.Inventory.Count; | 643 | itemsOutput = sop.Inventory.Count; |
589 | } | 644 | } |
590 | 645 | ||
591 | |||
592 | cdl.AddRow("Items", itemsOutput); | 646 | cdl.AddRow("Items", itemsOutput); |
593 | 647 | ||
594 | return sb.Append(cdl.ToString()); | 648 | return sb.Append(cdl.ToString()); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 4c195e1..1dfc420 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -307,7 +307,7 @@ public sealed class BSCharacter : BSPhysObject | |||
307 | } | 307 | } |
308 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 308 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
309 | { | 309 | { |
310 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 310 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
311 | if (Position.Z < waterHeight) | 311 | if (Position.Z < waterHeight) |
312 | { | 312 | { |
313 | _position.Z = waterHeight; | 313 | _position.Z = waterHeight; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index dbc9039..3a73fba 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -80,10 +80,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
80 | private Quaternion m_referenceFrame = Quaternion.Identity; | 80 | private Quaternion m_referenceFrame = Quaternion.Identity; |
81 | 81 | ||
82 | // Linear properties | 82 | // Linear properties |
83 | private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); | ||
83 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | 84 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time |
84 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center | 85 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center |
85 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | 86 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL |
86 | private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body | ||
87 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | 87 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; |
88 | private float m_linearMotorDecayTimescale = 0; | 88 | private float m_linearMotorDecayTimescale = 0; |
89 | private float m_linearMotorTimescale = 0; | 89 | private float m_linearMotorTimescale = 0; |
@@ -93,6 +93,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
93 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | 93 | // private Vector3 m_linearMotorOffset = Vector3.Zero; |
94 | 94 | ||
95 | //Angular properties | 95 | //Angular properties |
96 | private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); | ||
96 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | 97 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor |
97 | // private int m_angularMotorApply = 0; // application frame counter | 98 | // private int m_angularMotorApply = 0; // application frame counter |
98 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | 99 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity |
@@ -124,6 +125,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
124 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | 125 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. |
125 | 126 | ||
126 | //Attractor properties | 127 | //Attractor properties |
128 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); | ||
127 | private float m_verticalAttractionEfficiency = 1.0f; // damped | 129 | private float m_verticalAttractionEfficiency = 1.0f; // damped |
128 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | 130 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. |
129 | 131 | ||
@@ -152,10 +154,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
152 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 154 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); |
153 | break; | 155 | break; |
154 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | 156 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: |
155 | m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); | 157 | m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); |
158 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; | ||
156 | break; | 159 | break; |
157 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | 160 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: |
158 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); | 161 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); |
162 | m_angularMotor.TimeScale = m_angularMotorTimescale; | ||
159 | break; | 163 | break; |
160 | case Vehicle.BANKING_EFFICIENCY: | 164 | case Vehicle.BANKING_EFFICIENCY: |
161 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); | 165 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); |
@@ -185,33 +189,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
185 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 189 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); |
186 | break; | 190 | break; |
187 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | 191 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: |
188 | m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); | 192 | m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); |
193 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; | ||
189 | break; | 194 | break; |
190 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | 195 | case Vehicle.LINEAR_MOTOR_TIMESCALE: |
191 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); | 196 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); |
197 | m_linearMotor.TimeScale = m_linearMotorTimescale; | ||
192 | break; | 198 | break; |
193 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | 199 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: |
194 | m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); | 200 | m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); |
201 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; | ||
195 | break; | 202 | break; |
196 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | 203 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: |
197 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); | 204 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); |
205 | m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; | ||
198 | break; | 206 | break; |
199 | 207 | ||
200 | // These are vector properties but the engine lets you use a single float value to | 208 | // These are vector properties but the engine lets you use a single float value to |
201 | // set all of the components to the same value | 209 | // set all of the components to the same value |
202 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 210 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
203 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | 211 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); |
212 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
204 | break; | 213 | break; |
205 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 214 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
206 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 215 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
207 | // m_angularMotorApply = 100; | 216 | m_angularMotor.SetTarget(m_angularMotorDirection); |
208 | break; | 217 | break; |
209 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 218 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
210 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 219 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
220 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
211 | break; | 221 | break; |
212 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 222 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
213 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 223 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
214 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | 224 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); |
225 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
215 | break; | 226 | break; |
216 | case Vehicle.LINEAR_MOTOR_OFFSET: | 227 | case Vehicle.LINEAR_MOTOR_OFFSET: |
217 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | 228 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); |
@@ -227,6 +238,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
227 | { | 238 | { |
228 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 239 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
229 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 240 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
241 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
230 | break; | 242 | break; |
231 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 243 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
232 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 244 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
@@ -234,14 +246,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
234 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); | 246 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); |
235 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); | 247 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); |
236 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 248 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
237 | // m_angularMotorApply = 100; | 249 | m_angularMotor.SetTarget(m_angularMotorDirection); |
238 | break; | 250 | break; |
239 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 251 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
240 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 252 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
253 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
241 | break; | 254 | break; |
242 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 255 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
243 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 256 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
244 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | 257 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); |
258 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
245 | break; | 259 | break; |
246 | case Vehicle.LINEAR_MOTOR_OFFSET: | 260 | case Vehicle.LINEAR_MOTOR_OFFSET: |
247 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | 261 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -303,7 +317,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
303 | m_VhoverEfficiency = 0; | 317 | m_VhoverEfficiency = 0; |
304 | m_VhoverTimescale = 0; | 318 | m_VhoverTimescale = 0; |
305 | m_VehicleBuoyancy = 0; | 319 | m_VehicleBuoyancy = 0; |
306 | 320 | ||
307 | m_linearDeflectionEfficiency = 1; | 321 | m_linearDeflectionEfficiency = 1; |
308 | m_linearDeflectionTimescale = 1; | 322 | m_linearDeflectionTimescale = 1; |
309 | 323 | ||
@@ -319,6 +333,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
319 | 333 | ||
320 | m_referenceFrame = Quaternion.Identity; | 334 | m_referenceFrame = Quaternion.Identity; |
321 | m_flags = (VehicleFlag)0; | 335 | m_flags = (VehicleFlag)0; |
336 | |||
322 | break; | 337 | break; |
323 | 338 | ||
324 | case Vehicle.TYPE_SLED: | 339 | case Vehicle.TYPE_SLED: |
@@ -351,10 +366,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
351 | m_bankingMix = 1; | 366 | m_bankingMix = 1; |
352 | 367 | ||
353 | m_referenceFrame = Quaternion.Identity; | 368 | m_referenceFrame = Quaternion.Identity; |
354 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | 369 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
355 | m_flags &= | 370 | | VehicleFlag.HOVER_TERRAIN_ONLY |
356 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | 371 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
357 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | 372 | | VehicleFlag.HOVER_UP_ONLY); |
373 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
374 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
375 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
358 | break; | 376 | break; |
359 | case Vehicle.TYPE_CAR: | 377 | case Vehicle.TYPE_CAR: |
360 | m_linearMotorDirection = Vector3.Zero; | 378 | m_linearMotorDirection = Vector3.Zero; |
@@ -427,9 +445,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
427 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | 445 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
428 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | 446 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
429 | | VehicleFlag.LIMIT_ROLL_ONLY | 447 | | VehicleFlag.LIMIT_ROLL_ONLY |
448 | | VehicleFlag.LIMIT_MOTOR_UP | ||
430 | | VehicleFlag.HOVER_UP_ONLY); | 449 | | VehicleFlag.HOVER_UP_ONLY); |
431 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | 450 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
432 | | VehicleFlag.LIMIT_MOTOR_UP | ||
433 | | VehicleFlag.HOVER_WATER_ONLY); | 451 | | VehicleFlag.HOVER_WATER_ONLY); |
434 | break; | 452 | break; |
435 | case Vehicle.TYPE_AIRPLANE: | 453 | case Vehicle.TYPE_AIRPLANE: |
@@ -510,6 +528,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
510 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | 528 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); |
511 | break; | 529 | break; |
512 | } | 530 | } |
531 | |||
532 | // Update any physical parameters based on this type. | ||
533 | Refresh(); | ||
534 | |||
535 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | ||
536 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | ||
537 | 1f); | ||
538 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
539 | |||
540 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | ||
541 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | ||
542 | 1f); | ||
543 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
544 | |||
545 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | ||
546 | BSMotor.Infinite, BSMotor.InfiniteVector, | ||
547 | m_verticalAttractionEfficiency); | ||
548 | // Z goes away and we keep X and Y | ||
549 | m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); | ||
550 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
551 | |||
552 | // m_bankingMotor = new BSVMotor("BankingMotor", ...); | ||
513 | } | 553 | } |
514 | 554 | ||
515 | // Some of the properties of this prim may have changed. | 555 | // Some of the properties of this prim may have changed. |
@@ -518,13 +558,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
518 | { | 558 | { |
519 | if (IsActive) | 559 | if (IsActive) |
520 | { | 560 | { |
521 | // Friction effects are handled by this vehicle code | 561 | m_vehicleMass = Prim.Linkset.LinksetMass; |
522 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); | ||
523 | BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); | ||
524 | |||
525 | // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); | ||
526 | 562 | ||
527 | VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); | 563 | // Friction effects are handled by this vehicle code |
564 | float friction = 0f; | ||
565 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); | ||
566 | |||
567 | // Moderate angular movement introduced by Bullet. | ||
568 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | ||
569 | // Maybe compute linear and angular factor and damping from params. | ||
570 | float angularDamping = PhysicsScene.Params.vehicleAngularDamping; | ||
571 | BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); | ||
572 | |||
573 | // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet | ||
574 | // Vector3 localInertia = new Vector3(1f, 1f, 1f); | ||
575 | Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); | ||
576 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); | ||
577 | |||
578 | VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}", | ||
579 | Prim.LocalID, friction, localInertia, angularDamping); | ||
528 | } | 580 | } |
529 | } | 581 | } |
530 | 582 | ||
@@ -551,111 +603,109 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
551 | { | 603 | { |
552 | if (!IsActive) return; | 604 | if (!IsActive) return; |
553 | 605 | ||
554 | // DEBUG | ||
555 | // Because Bullet does apply forces to the vehicle, our last computed | ||
556 | // linear and angular velocities are not what is happening now. | ||
557 | // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity; | ||
558 | // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep; | ||
559 | // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time | ||
560 | // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG: | ||
561 | // END DEBUG | ||
562 | |||
563 | m_vehicleMass = Prim.Linkset.LinksetMass; | ||
564 | |||
565 | MoveLinear(pTimestep); | 606 | MoveLinear(pTimestep); |
566 | // Commented out for debug | ||
567 | MoveAngular(pTimestep); | 607 | MoveAngular(pTimestep); |
568 | // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG | ||
569 | // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG | ||
570 | 608 | ||
571 | LimitRotation(pTimestep); | 609 | LimitRotation(pTimestep); |
572 | 610 | ||
573 | // remember the position so next step we can limit absolute movement effects | 611 | // remember the position so next step we can limit absolute movement effects |
574 | m_lastPositionVector = Prim.ForcePosition; | 612 | m_lastPositionVector = Prim.ForcePosition; |
575 | 613 | ||
576 | VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG | ||
577 | Prim.LocalID, | ||
578 | BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), | ||
579 | BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), | ||
580 | Prim.Inertia, | ||
581 | m_vehicleMass | ||
582 | ); | ||
583 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | 614 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", |
584 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); | 615 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); |
585 | }// end Step | 616 | } |
586 | 617 | ||
587 | // Apply the effect of the linear motor. | 618 | // Apply the effect of the linear motor. |
588 | // Also does hover and float. | 619 | // Also does hover and float. |
589 | private void MoveLinear(float pTimestep) | 620 | private void MoveLinear(float pTimestep) |
590 | { | 621 | { |
591 | // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates | 622 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); |
592 | // m_lastLinearVelocityVector is the current speed we are moving in that direction | 623 | |
593 | if (m_linearMotorDirection.LengthSquared() > 0.001f) | 624 | // Rotate new object velocity from vehicle relative to world coordinates |
594 | { | 625 | linearMotorContribution *= Prim.ForceOrientation; |
595 | Vector3 origDir = m_linearMotorDirection; // DEBUG | 626 | |
596 | Vector3 origVel = m_lastLinearVelocityVector; // DEBUG | 627 | // ================================================================== |
597 | // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison | 628 | // Gravity and Buoyancy |
598 | Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG | 629 | // There is some gravity, make a gravity force vector that is applied after object velocity. |
630 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
631 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); | ||
599 | 632 | ||
600 | // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete | 633 | Vector3 pos = Prim.ForcePosition; |
601 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; | 634 | float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); |
602 | m_lastLinearVelocityVector += addAmount; | ||
603 | 635 | ||
604 | float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; | 636 | Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep, ref pos, terrainHeight); |
605 | m_linearMotorDirection *= (1f - decayFactor); | ||
606 | 637 | ||
607 | // Rotate new object velocity from vehicle relative to world coordinates | 638 | Vector3 hoverContribution = ComputeLinearHover(pTimestep, ref pos, terrainHeight); |
608 | m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; | ||
609 | 639 | ||
610 | // Apply friction for next time | 640 | ComputeLinearBlockingEndPoint(pTimestep, ref pos); |
611 | Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep; | ||
612 | m_lastLinearVelocityVector *= (Vector3.One - frictionFactor); | ||
613 | 641 | ||
614 | VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", | 642 | Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep, pos, terrainHeight); |
615 | Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, | 643 | |
616 | m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); | 644 | // ================================================================== |
617 | } | 645 | Vector3 newVelocity = linearMotorContribution |
618 | else | 646 | + terrainHeightContribution |
619 | { | 647 | + hoverContribution |
620 | // if what remains of direction is very small, zero it. | 648 | + limitMotorUpContribution; |
621 | m_linearMotorDirection = Vector3.Zero; | ||
622 | m_lastLinearVelocityVector = Vector3.Zero; | ||
623 | m_newVelocity = Vector3.Zero; | ||
624 | 649 | ||
625 | VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 650 | // If not changing some axis, reduce out velocity |
651 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
652 | newVelocity.X = 0; | ||
653 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
654 | newVelocity.Y = 0; | ||
655 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
656 | newVelocity.Z = 0; | ||
657 | |||
658 | // ================================================================== | ||
659 | // Clamp REALLY high or low velocities | ||
660 | float newVelocityLengthSq = newVelocity.LengthSquared(); | ||
661 | if (newVelocityLengthSq > 1e6f) | ||
662 | { | ||
663 | newVelocity /= newVelocity.Length(); | ||
664 | newVelocity *= 1000f; | ||
626 | } | 665 | } |
666 | else if (newVelocityLengthSq < 1e-6f) | ||
667 | newVelocity = Vector3.Zero; | ||
627 | 668 | ||
628 | // m_newVelocity is velocity computed from linear motor in world coordinates | 669 | // ================================================================== |
670 | // Stuff new linear velocity into the vehicle | ||
671 | Prim.ForceVelocity = newVelocity; | ||
672 | // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG | ||
629 | 673 | ||
630 | // Gravity and Buoyancy | 674 | // Other linear forces are applied as forces. |
631 | // There is some gravity, make a gravity force vector that is applied after object velocity. | 675 | Vector3 totalDownForce = grav * m_vehicleMass; |
632 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 676 | if (totalDownForce != Vector3.Zero) |
633 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); | 677 | { |
678 | Prim.AddForce(totalDownForce, false); | ||
679 | } | ||
634 | 680 | ||
635 | /* | 681 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", |
636 | * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... | 682 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, |
637 | // Preserve the current Z velocity | 683 | newVelocity, Prim.Velocity, totalDownForce); |
638 | Vector3 vel_now = m_prim.Velocity; | ||
639 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | ||
640 | */ | ||
641 | 684 | ||
642 | Vector3 pos = Prim.ForcePosition; | 685 | } // end MoveLinear() |
643 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); | ||
644 | 686 | ||
687 | public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep, ref Vector3 pos, float terrainHeight) | ||
688 | { | ||
689 | Vector3 ret = Vector3.Zero; | ||
645 | // If below the terrain, move us above the ground a little. | 690 | // If below the terrain, move us above the ground a little. |
646 | float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
647 | // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. | 691 | // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. |
648 | // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. | 692 | // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. |
649 | // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; | 693 | // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; |
650 | // if (rotatedSize.Z < terrainHeight) | 694 | // if (rotatedSize.Z < terrainHeight) |
651 | if (pos.Z < terrainHeight) | 695 | if (pos.Z < terrainHeight) |
652 | { | 696 | { |
697 | // TODO: correct position by applying force rather than forcing position. | ||
653 | pos.Z = terrainHeight + 2; | 698 | pos.Z = terrainHeight + 2; |
654 | Prim.ForcePosition = pos; | 699 | Prim.ForcePosition = pos; |
655 | VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); | 700 | VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); |
656 | } | 701 | } |
702 | return ret; | ||
703 | } | ||
704 | |||
705 | public Vector3 ComputeLinearHover(float pTimestep, ref Vector3 pos, float terrainHeight) | ||
706 | { | ||
707 | Vector3 ret = Vector3.Zero; | ||
657 | 708 | ||
658 | // Check if hovering | ||
659 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | 709 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped |
660 | // m_VhoverTimescale: time to achieve height | 710 | // m_VhoverTimescale: time to achieve height |
661 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | 711 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) |
@@ -663,7 +713,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
663 | // We should hover, get the target height | 713 | // We should hover, get the target height |
664 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | 714 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) |
665 | { | 715 | { |
666 | m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; | 716 | m_VhoverTargetHeight = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; |
667 | } | 717 | } |
668 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | 718 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) |
669 | { | 719 | { |
@@ -680,6 +730,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
680 | if (pos.Z > m_VhoverTargetHeight) | 730 | if (pos.Z > m_VhoverTargetHeight) |
681 | m_VhoverTargetHeight = pos.Z; | 731 | m_VhoverTargetHeight = pos.Z; |
682 | } | 732 | } |
733 | |||
683 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 734 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
684 | { | 735 | { |
685 | if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) | 736 | if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) |
@@ -694,28 +745,31 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
694 | // RA: where does the 50 come from? | 745 | // RA: where does the 50 come from? |
695 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); | 746 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); |
696 | // Replace Vertical speed with correction figure if significant | 747 | // Replace Vertical speed with correction figure if significant |
697 | if (Math.Abs(verticalError) > 0.01f) | 748 | if (verticalError > 0.01f) |
698 | { | 749 | { |
699 | m_newVelocity.Z += verticalCorrectionVelocity; | 750 | ret = new Vector3(0f, 0f, verticalCorrectionVelocity); |
700 | //KF: m_VhoverEfficiency is not yet implemented | 751 | //KF: m_VhoverEfficiency is not yet implemented |
701 | } | 752 | } |
702 | else if (verticalError < -0.01) | 753 | else if (verticalError < -0.01) |
703 | { | 754 | { |
704 | m_newVelocity.Z -= verticalCorrectionVelocity; | 755 | ret = new Vector3(0f, 0f, -verticalCorrectionVelocity); |
705 | } | ||
706 | else | ||
707 | { | ||
708 | m_newVelocity.Z = 0f; | ||
709 | } | 756 | } |
710 | } | 757 | } |
711 | 758 | ||
712 | VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); | 759 | VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", |
760 | Prim.LocalID, pos, ret, m_VhoverHeight, m_VhoverTargetHeight); | ||
713 | } | 761 | } |
714 | 762 | ||
763 | return ret; | ||
764 | } | ||
765 | |||
766 | public bool ComputeLinearBlockingEndPoint(float pTimestep, ref Vector3 pos) | ||
767 | { | ||
768 | bool changed = false; | ||
769 | |||
715 | Vector3 posChange = pos - m_lastPositionVector; | 770 | Vector3 posChange = pos - m_lastPositionVector; |
716 | if (m_BlockingEndPoint != Vector3.Zero) | 771 | if (m_BlockingEndPoint != Vector3.Zero) |
717 | { | 772 | { |
718 | bool changed = false; | ||
719 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | 773 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) |
720 | { | 774 | { |
721 | pos.X -= posChange.X + 1; | 775 | pos.X -= posChange.X + 1; |
@@ -748,75 +802,53 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
748 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 802 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); |
749 | } | 803 | } |
750 | } | 804 | } |
805 | return changed; | ||
806 | } | ||
751 | 807 | ||
752 | #region downForce | 808 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
753 | Vector3 downForce = Vector3.Zero; | 809 | // Prevent ground vehicles from motoring into the sky.This flag has a subtle effect when |
754 | 810 | // used with conjunction with banking: the strength of the banking will decay when the | |
811 | // vehicle no longer experiences collisions. The decay timescale is the same as | ||
812 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | ||
813 | // when they are in mid jump. | ||
814 | // TODO: this code is wrong. Also, what should it do for boats? | ||
815 | public Vector3 ComputeLinearMotorUp(float pTimestep, Vector3 pos, float terrainHeight) | ||
816 | { | ||
817 | Vector3 ret = Vector3.Zero; | ||
755 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | 818 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) |
756 | { | 819 | { |
757 | // If the vehicle is motoring into the sky, get it going back down. | 820 | // If the vehicle is motoring into the sky, get it going back down. |
758 | // Is this an angular force or both linear and angular?? | ||
759 | float distanceAboveGround = pos.Z - terrainHeight; | 821 | float distanceAboveGround = pos.Z - terrainHeight; |
760 | if (distanceAboveGround > 2f) | 822 | if (distanceAboveGround > 1f) |
761 | { | 823 | { |
762 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); | 824 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); |
763 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | 825 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); |
764 | downForce = new Vector3(0, 0, -distanceAboveGround); | 826 | ret = new Vector3(0, 0, -distanceAboveGround); |
765 | } | 827 | } |
766 | // TODO: this calculation is all wrong. From the description at | 828 | // TODO: this calculation is wrong. From the description at |
767 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce | 829 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce |
768 | // has a decay factor. This says this force should | 830 | // has a decay factor. This says this force should |
769 | // be computed with a motor. | 831 | // be computed with a motor. |
770 | VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", | 832 | // TODO: add interaction with banking. |
771 | Prim.LocalID, distanceAboveGround, downForce); | 833 | VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", |
772 | } | 834 | Prim.LocalID, distanceAboveGround, ret); |
773 | #endregion // downForce | ||
774 | |||
775 | // If not changing some axis, reduce out velocity | ||
776 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
777 | m_newVelocity.X = 0; | ||
778 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
779 | m_newVelocity.Y = 0; | ||
780 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
781 | m_newVelocity.Z = 0; | ||
782 | |||
783 | // Clamp REALLY high or low velocities | ||
784 | if (m_newVelocity.LengthSquared() > 1e6f) | ||
785 | { | ||
786 | m_newVelocity /= m_newVelocity.Length(); | ||
787 | m_newVelocity *= 1000f; | ||
788 | } | ||
789 | else if (m_newVelocity.LengthSquared() < 1e-6f) | ||
790 | m_newVelocity = Vector3.Zero; | ||
791 | |||
792 | // Stuff new linear velocity into the vehicle | ||
793 | Prim.ForceVelocity = m_newVelocity; | ||
794 | // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG | ||
795 | |||
796 | Vector3 totalDownForce = downForce + grav; | ||
797 | if (totalDownForce != Vector3.Zero) | ||
798 | { | ||
799 | Prim.AddForce(totalDownForce * m_vehicleMass, false); | ||
800 | // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false); | ||
801 | } | 835 | } |
836 | return ret; | ||
837 | } | ||
802 | 838 | ||
803 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", | 839 | // ======================================================================= |
804 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); | ||
805 | |||
806 | } // end MoveLinear() | ||
807 | |||
808 | // ======================================================================= | 840 | // ======================================================================= |
809 | // Apply the effect of the angular motor. | 841 | // Apply the effect of the angular motor. |
810 | private void MoveAngular(float pTimestep) | 842 | private void MoveAngular(float pTimestep) |
811 | { | 843 | { |
812 | // m_angularMotorDirection // angular velocity requested by LSL motor | 844 | // m_angularMotorDirection // angular velocity requested by LSL motor |
813 | // m_angularMotorApply // application frame counter | ||
814 | // m_angularMotorVelocity // current angular motor velocity (ramps up and down) | 845 | // m_angularMotorVelocity // current angular motor velocity (ramps up and down) |
815 | // m_angularMotorTimescale // motor angular velocity ramp up rate | 846 | // m_angularMotorTimescale // motor angular velocity ramp up time |
816 | // m_angularMotorDecayTimescale // motor angular velocity decay rate | 847 | // m_angularMotorDecayTimescale // motor angular velocity decay rate |
817 | // m_angularFrictionTimescale // body angular velocity decay rate | 848 | // m_angularFrictionTimescale // body angular velocity decay rate |
818 | // m_lastAngularVelocity // what was last applied to body | 849 | // m_lastAngularVelocity // what was last applied to body |
819 | 850 | ||
851 | /* | ||
820 | if (m_angularMotorDirection.LengthSquared() > 0.0001) | 852 | if (m_angularMotorDirection.LengthSquared() > 0.0001) |
821 | { | 853 | { |
822 | Vector3 origVel = m_angularMotorVelocity; | 854 | Vector3 origVel = m_angularMotorVelocity; |
@@ -835,59 +867,157 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
835 | { | 867 | { |
836 | m_angularMotorVelocity = Vector3.Zero; | 868 | m_angularMotorVelocity = Vector3.Zero; |
837 | } | 869 | } |
870 | */ | ||
838 | 871 | ||
839 | #region Vertical attactor | 872 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); |
840 | 873 | ||
841 | Vector3 vertattr = Vector3.Zero; | 874 | // ================================================================== |
842 | Vector3 deflection = Vector3.Zero; | 875 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
843 | Vector3 banking = Vector3.Zero; | 876 | // This flag prevents linear deflection parallel to world z-axis. This is useful |
877 | // for preventing ground vehicles with large linear deflection, like bumper cars, | ||
878 | // from climbing their linear deflection into the sky. | ||
879 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | ||
880 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
881 | { | ||
882 | angularMotorContribution.X = 0f; | ||
883 | angularMotorContribution.Y = 0f; | ||
884 | VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); | ||
885 | } | ||
844 | 886 | ||
845 | // If vertical attaction timescale is reasonable and we applied an angular force last time... | 887 | Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep); |
846 | if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) | 888 | |
889 | Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep); | ||
890 | |||
891 | Vector3 bankingContribution = ComputeAngularBanking(pTimestep); | ||
892 | |||
893 | // ================================================================== | ||
894 | m_lastVertAttractor = verticalAttractionContribution; | ||
895 | |||
896 | // Sum velocities | ||
897 | m_lastAngularVelocity = angularMotorContribution | ||
898 | + verticalAttractionContribution | ||
899 | + deflectionContribution | ||
900 | + bankingContribution; | ||
901 | |||
902 | // ================================================================== | ||
903 | //Offset section | ||
904 | if (m_linearMotorOffset != Vector3.Zero) | ||
905 | { | ||
906 | //Offset of linear velocity doesn't change the linear velocity, | ||
907 | // but causes a torque to be applied, for example... | ||
908 | // | ||
909 | // IIIII >>> IIIII | ||
910 | // IIIII >>> IIIII | ||
911 | // IIIII >>> IIIII | ||
912 | // ^ | ||
913 | // | Applying a force at the arrow will cause the object to move forward, but also rotate | ||
914 | // | ||
915 | // | ||
916 | // The torque created is the linear velocity crossed with the offset | ||
917 | |||
918 | // TODO: this computation should be in the linear section | ||
919 | // because that is where we know the impulse being applied. | ||
920 | Vector3 torqueFromOffset = Vector3.Zero; | ||
921 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); | ||
922 | if (float.IsNaN(torqueFromOffset.X)) | ||
923 | torqueFromOffset.X = 0; | ||
924 | if (float.IsNaN(torqueFromOffset.Y)) | ||
925 | torqueFromOffset.Y = 0; | ||
926 | if (float.IsNaN(torqueFromOffset.Z)) | ||
927 | torqueFromOffset.Z = 0; | ||
928 | torqueFromOffset *= m_vehicleMass; | ||
929 | Prim.ApplyTorqueImpulse(torqueFromOffset, true); | ||
930 | VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | ||
931 | } | ||
932 | |||
933 | // ================================================================== | ||
934 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
935 | { | ||
936 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | ||
937 | // TODO: zeroing is good but it also sets values in unmanaged code. Remove the stores when idle. | ||
938 | VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | ||
939 | Prim.ZeroAngularMotion(true); | ||
940 | } | ||
941 | else | ||
847 | { | 942 | { |
848 | float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; | 943 | // Apply to the body. |
849 | if (Prim.IsColliding) | 944 | // The above calculates the absolute angular velocity needed. Angular velocity is massless. |
850 | VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); | 945 | // Since we are stuffing the angular velocity directly into the object, the computed |
946 | // velocity needs to be scaled by the timestep. | ||
947 | // Also remove any motion that is on the object so added motion is only from vehicle. | ||
948 | Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) | ||
949 | - Prim.ForceRotationalVelocity); | ||
950 | // Unscale the force by the angular factor so it overwhelmes the Bullet additions. | ||
951 | Prim.ForceRotationalVelocity = applyAngularForce; | ||
952 | |||
953 | VDetailLog("{0},MoveAngular,done,angMotor={1},vertAttr={2},bank={3},deflect={4},newAngForce={5},lastAngular={6}", | ||
954 | Prim.LocalID, | ||
955 | angularMotorContribution, verticalAttractionContribution, | ||
956 | bankingContribution, deflectionContribution, | ||
957 | applyAngularForce, m_lastAngularVelocity | ||
958 | ); | ||
959 | } | ||
960 | } | ||
851 | 961 | ||
852 | VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | 962 | public Vector3 ComputeAngularVerticalAttraction(float pTimestep) |
963 | { | ||
964 | Vector3 ret = Vector3.Zero; | ||
853 | 965 | ||
854 | // Create a vector of the vehicle "up" in world coordinates | 966 | // If vertical attaction timescale is reasonable and we applied an angular force last time... |
967 | if (m_verticalAttractionTimescale < 500) | ||
968 | { | ||
969 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; | ||
970 | verticalError.Normalize(); | ||
971 | m_verticalAttractionMotor.SetCurrent(verticalError); | ||
972 | m_verticalAttractionMotor.SetTarget(Vector3.UnitZ); | ||
973 | ret = m_verticalAttractionMotor.Step(pTimestep); | ||
974 | /* | ||
975 | // Take a vector pointing up and convert it from world to vehicle relative coords. | ||
855 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; | 976 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; |
856 | // verticalError.X and .Y are the World error amounts. They are 0 when there is no | 977 | verticalError.Normalize(); |
857 | // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its | 978 | |
858 | // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall | 979 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) |
859 | // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be | 980 | // is now leaning to one side (rotated around the X axis) and the Y value will |
860 | // modulated to prevent a stable inverted body. | 981 | // go from zero (nearly straight up) to one (completely to the side) or leaning |
861 | 982 | // front-to-back (rotated around the Y axis) and the value of X will be between | |
862 | // Error is 0 (no error) to +/- 2 (max error) | 983 | // zero and one. |
863 | if (verticalError.Z < 0.0f) | 984 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. |
985 | |||
986 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
987 | if (verticalError.Z < 0f) | ||
864 | { | 988 | { |
865 | verticalError.X = 2.0f - verticalError.X; | 989 | verticalError.X = 2f - verticalError.X; |
866 | verticalError.Y = 2.0f - verticalError.Y; | 990 | verticalError.Y = 2f - verticalError.Y; |
867 | } | 991 | } |
868 | // scale it by VAservo (timestep and timescale) | ||
869 | verticalError = verticalError * VAservo; | ||
870 | 992 | ||
871 | // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y | 993 | // Y error means needed rotation around X axis and visa versa. |
872 | // then .X increases, so change Body angular velocity X based on Y, and Y based on X. | 994 | verticalAttractionContribution.X = verticalError.Y; |
873 | // Z is not changed. | 995 | verticalAttractionContribution.Y = - verticalError.X; |
874 | vertattr.X = verticalError.Y; | 996 | verticalAttractionContribution.Z = 0f; |
875 | vertattr.Y = - verticalError.X; | ||
876 | vertattr.Z = 0f; | ||
877 | 997 | ||
878 | // scaling appears better usingsquare-law | 998 | // scale by the time scale and timestep |
879 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; | 999 | Vector3 unscaledContrib = verticalAttractionContribution; |
880 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | 1000 | verticalAttractionContribution /= m_verticalAttractionTimescale; |
881 | vertattr.X += bounce * angularVelocity.X; | 1001 | verticalAttractionContribution *= pTimestep; |
882 | vertattr.Y += bounce * angularVelocity.Y; | ||
883 | 1002 | ||
884 | VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", | 1003 | // apply efficiency |
885 | Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr); | 1004 | Vector3 preEfficiencyContrib = verticalAttractionContribution; |
1005 | float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency; | ||
1006 | verticalAttractionContribution *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
1007 | |||
1008 | VDetailLog("{0},MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}", | ||
1009 | Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib, | ||
1010 | m_verticalAttractionEfficiency, efficencySquared, | ||
1011 | verticalAttractionContribution); | ||
1012 | */ | ||
886 | 1013 | ||
887 | } | 1014 | } |
888 | #endregion // Vertical attactor | 1015 | return ret; |
1016 | } | ||
889 | 1017 | ||
890 | #region Deflection | 1018 | public Vector3 ComputeAngularDeflection(float pTimestep) |
1019 | { | ||
1020 | Vector3 ret = Vector3.Zero; | ||
891 | 1021 | ||
892 | if (m_angularDeflectionEfficiency != 0) | 1022 | if (m_angularDeflectionEfficiency != 0) |
893 | { | 1023 | { |
@@ -899,32 +1029,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
899 | Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); | 1029 | Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); |
900 | 1030 | ||
901 | // Scale by efficiency and timescale | 1031 | // Scale by efficiency and timescale |
902 | deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; | 1032 | ret = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; |
1033 | |||
1034 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", Prim.LocalID, preferredAxisOfMotion, ret); | ||
903 | 1035 | ||
904 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", | ||
905 | Prim.LocalID, preferredAxisOfMotion, deflection); | ||
906 | // This deflection computation is not correct. | 1036 | // This deflection computation is not correct. |
907 | deflection = Vector3.Zero; | 1037 | ret = Vector3.Zero; |
908 | } | 1038 | } |
1039 | return ret; | ||
1040 | } | ||
909 | 1041 | ||
910 | #endregion | 1042 | public Vector3 ComputeAngularBanking(float pTimestep) |
911 | 1043 | { | |
912 | #region Banking | 1044 | Vector3 ret = Vector3.Zero; |
913 | 1045 | ||
914 | if (m_bankingEfficiency != 0) | 1046 | if (m_bankingEfficiency != 0) |
915 | { | 1047 | { |
916 | Vector3 dir = Vector3.One * Prim.ForceOrientation; | 1048 | Vector3 dir = Vector3.One * Prim.ForceOrientation; |
917 | float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); | 1049 | float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1); |
918 | //Changes which way it banks in and out of turns | 1050 | //Changes which way it banks in and out of turns |
919 | 1051 | ||
920 | //Use the square of the efficiency, as it looks much more how SL banking works | 1052 | //Use the square of the efficiency, as it looks much more how SL banking works |
921 | float effSquared = (m_bankingEfficiency*m_bankingEfficiency); | 1053 | float effSquared = (m_bankingEfficiency * m_bankingEfficiency); |
922 | if (m_bankingEfficiency < 0) | 1054 | if (m_bankingEfficiency < 0) |
923 | effSquared *= -1; //Keep the negative! | 1055 | effSquared *= -1; //Keep the negative! |
924 | 1056 | ||
925 | float mix = Math.Abs(m_bankingMix); | 1057 | float mix = Math.Abs(m_bankingMix); |
926 | if (m_angularMotorVelocity.X == 0) | 1058 | if (m_angularMotorVelocity.X == 0) |
927 | { | 1059 | { |
1060 | // The vehicle is stopped | ||
928 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) | 1061 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) |
929 | { | 1062 | { |
930 | Vector3 axisAngle; | 1063 | Vector3 axisAngle; |
@@ -938,101 +1071,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
938 | }*/ | 1071 | }*/ |
939 | } | 1072 | } |
940 | else | 1073 | else |
941 | banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; | 1074 | { |
1075 | ret.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4; | ||
1076 | } | ||
1077 | |||
1078 | //If they are colliding, we probably shouldn't shove the prim around... probably | ||
942 | if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) | 1079 | if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) |
943 | //If they are colliding, we probably shouldn't shove the prim around... probably | ||
944 | { | 1080 | { |
945 | float angVelZ = m_angularMotorVelocity.X*-1; | 1081 | float angVelZ = m_angularMotorVelocity.X * -1; |
946 | /*if(angVelZ > mix) | 1082 | /*if(angVelZ > mix) |
947 | angVelZ = mix; | 1083 | angVelZ = mix; |
948 | else if(angVelZ < -mix) | 1084 | else if(angVelZ < -mix) |
949 | angVelZ = -mix;*/ | 1085 | angVelZ = -mix;*/ |
950 | //This controls how fast and how far the banking occurs | 1086 | //This controls how fast and how far the banking occurs |
951 | Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); | 1087 | Vector3 bankingRot = new Vector3(angVelZ * (effSquared * mult), 0, 0); |
952 | if (bankingRot.X > 3) | 1088 | if (bankingRot.X > 3) |
953 | bankingRot.X = 3; | 1089 | bankingRot.X = 3; |
954 | else if (bankingRot.X < -3) | 1090 | else if (bankingRot.X < -3) |
955 | bankingRot.X = -3; | 1091 | bankingRot.X = -3; |
956 | bankingRot *= Prim.ForceOrientation; | 1092 | bankingRot *= Prim.ForceOrientation; |
957 | banking += bankingRot; | 1093 | ret += bankingRot; |
958 | } | 1094 | } |
959 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; | 1095 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; |
960 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", | 1096 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}", |
961 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); | 1097 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, ret); |
962 | } | ||
963 | |||
964 | #endregion | ||
965 | |||
966 | m_lastVertAttractor = vertattr; | ||
967 | |||
968 | // Sum velocities | ||
969 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; | ||
970 | |||
971 | #region Linear Motor Offset | ||
972 | |||
973 | //Offset section | ||
974 | if (m_linearMotorOffset != Vector3.Zero) | ||
975 | { | ||
976 | //Offset of linear velocity doesn't change the linear velocity, | ||
977 | // but causes a torque to be applied, for example... | ||
978 | // | ||
979 | // IIIII >>> IIIII | ||
980 | // IIIII >>> IIIII | ||
981 | // IIIII >>> IIIII | ||
982 | // ^ | ||
983 | // | Applying a force at the arrow will cause the object to move forward, but also rotate | ||
984 | // | ||
985 | // | ||
986 | // The torque created is the linear velocity crossed with the offset | ||
987 | |||
988 | // NOTE: this computation does should be in the linear section | ||
989 | // because there we know the impulse being applied. | ||
990 | Vector3 torqueFromOffset = Vector3.Zero; | ||
991 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); | ||
992 | if (float.IsNaN(torqueFromOffset.X)) | ||
993 | torqueFromOffset.X = 0; | ||
994 | if (float.IsNaN(torqueFromOffset.Y)) | ||
995 | torqueFromOffset.Y = 0; | ||
996 | if (float.IsNaN(torqueFromOffset.Z)) | ||
997 | torqueFromOffset.Z = 0; | ||
998 | torqueFromOffset *= m_vehicleMass; | ||
999 | Prim.ApplyTorqueImpulse(torqueFromOffset, true); | ||
1000 | VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | ||
1001 | } | ||
1002 | |||
1003 | #endregion | ||
1004 | |||
1005 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
1006 | { | ||
1007 | m_lastAngularVelocity.X = 0; | ||
1008 | m_lastAngularVelocity.Y = 0; | ||
1009 | VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | ||
1010 | } | 1098 | } |
1099 | return ret; | ||
1100 | } | ||
1011 | 1101 | ||
1012 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
1013 | { | ||
1014 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | ||
1015 | Prim.ZeroAngularMotion(true); | ||
1016 | VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | ||
1017 | } | ||
1018 | else | ||
1019 | { | ||
1020 | // Apply to the body. | ||
1021 | // The above calculates the absolute angular velocity needed. Angular velocity is massless. | ||
1022 | // Since we are stuffing the angular velocity directly into the object, the computed | ||
1023 | // velocity needs to be scaled by the timestep. | ||
1024 | Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); | ||
1025 | Prim.ForceRotationalVelocity = applyAngularForce; | ||
1026 | |||
1027 | // Decay the angular movement for next time | ||
1028 | Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; | ||
1029 | m_lastAngularVelocity *= Vector3.One - decayamount; | ||
1030 | |||
1031 | VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", | ||
1032 | Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); | ||
1033 | } | ||
1034 | } //end MoveAngular | ||
1035 | 1102 | ||
1103 | // This is from previous instantiations of XXXDynamics.cs. | ||
1104 | // Applies roll reference frame. | ||
1105 | // TODO: is this the right way to separate the code to do this operation? | ||
1106 | // Should this be in MoveAngular()? | ||
1036 | internal void LimitRotation(float timestep) | 1107 | internal void LimitRotation(float timestep) |
1037 | { | 1108 | { |
1038 | Quaternion rotq = Prim.ForceOrientation; | 1109 | Quaternion rotq = Prim.ForceOrientation; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs new file mode 100755 index 0000000..663b6f4 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using System.Reflection; | ||
31 | using Nini.Config; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | |||
36 | public struct MaterialAttributes | ||
37 | { | ||
38 | // Material type values that correspond with definitions for LSL | ||
39 | public enum Material : int | ||
40 | { | ||
41 | Stone = 0, | ||
42 | Metal, | ||
43 | Glass, | ||
44 | Wood, | ||
45 | Flesh, | ||
46 | Plastic, | ||
47 | Rubber, | ||
48 | Light, | ||
49 | // Hereafter are BulletSim additions | ||
50 | Avatar, | ||
51 | NumberOfTypes // the count of types in the enum. | ||
52 | } | ||
53 | // Names must be in the order of the above enum. | ||
54 | public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", | ||
55 | "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; | ||
56 | public static string[] MaterialAttribs = { "Density", "Friction", "Restitution", | ||
57 | "ccdMotionThreshold", "ccdSweptSphereRadius" }; | ||
58 | |||
59 | public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS) | ||
60 | { | ||
61 | type = t; | ||
62 | density = d; | ||
63 | friction = f; | ||
64 | restitution = r; | ||
65 | ccdMotionThreshold = ccdM; | ||
66 | ccdSweptSphereRadius = ccdS; | ||
67 | } | ||
68 | public string type; | ||
69 | public float density; | ||
70 | public float friction; | ||
71 | public float restitution; | ||
72 | public float ccdMotionThreshold; | ||
73 | public float ccdSweptSphereRadius; | ||
74 | } | ||
75 | |||
76 | public static class BSMaterials | ||
77 | { | ||
78 | public static MaterialAttributes[] Attributes; | ||
79 | |||
80 | static BSMaterials() | ||
81 | { | ||
82 | // Attribute sets for both the non-physical and physical instances of materials. | ||
83 | Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; | ||
84 | } | ||
85 | |||
86 | // This is where all the default material attributes are defined. | ||
87 | public static void InitializeFromDefaults(ConfigurationParameters parms) | ||
88 | { | ||
89 | // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", | ||
90 | // "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; | ||
91 | float dFriction = parms.defaultFriction; | ||
92 | float dRestitution = parms.defaultRestitution; | ||
93 | float dDensity = parms.defaultDensity; | ||
94 | float dCcdM = parms.ccdMotionThreshold; | ||
95 | float dCcdS = parms.ccdSweptSphereRadius; | ||
96 | Attributes[(int)MaterialAttributes.Material.Stone] = | ||
97 | new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
98 | Attributes[(int)MaterialAttributes.Material.Metal] = | ||
99 | new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
100 | Attributes[(int)MaterialAttributes.Material.Glass] = | ||
101 | new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
102 | Attributes[(int)MaterialAttributes.Material.Wood] = | ||
103 | new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
104 | Attributes[(int)MaterialAttributes.Material.Flesh] = | ||
105 | new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
106 | Attributes[(int)MaterialAttributes.Material.Plastic] = | ||
107 | new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
108 | Attributes[(int)MaterialAttributes.Material.Rubber] = | ||
109 | new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
110 | Attributes[(int)MaterialAttributes.Material.Light] = | ||
111 | new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
112 | Attributes[(int)MaterialAttributes.Material.Avatar] = | ||
113 | new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
114 | |||
115 | Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
116 | new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
117 | Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
118 | new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
119 | Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
120 | new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
121 | Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
122 | new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
123 | Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
124 | new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
125 | Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
126 | new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
127 | Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
128 | new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
129 | Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
130 | new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
131 | Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
132 | new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | ||
133 | } | ||
134 | |||
135 | // Under the [BulletSim] section, one can change the individual material | ||
136 | // attribute values. The format of the configuration parameter is: | ||
137 | // <materialName><Attribute>["Physical"] = floatValue | ||
138 | // For instance: | ||
139 | // [BulletSim] | ||
140 | // StoneFriction = 0.2 | ||
141 | // FleshRestitutionPhysical = 0.8 | ||
142 | // Materials can have different parameters for their static and | ||
143 | // physical instantiations. When setting the non-physical value, | ||
144 | // both values are changed. Setting the physical value only changes | ||
145 | // the physical value. | ||
146 | public static void InitializefromParameters(IConfig pConfig) | ||
147 | { | ||
148 | int matType = 0; | ||
149 | foreach (string matName in MaterialAttributes.MaterialNames) | ||
150 | { | ||
151 | foreach (string attribName in MaterialAttributes.MaterialAttribs) | ||
152 | { | ||
153 | string paramName = matName + attribName; | ||
154 | if (pConfig.Contains(paramName)) | ||
155 | { | ||
156 | float paramValue = pConfig.GetFloat(paramName); | ||
157 | SetAttributeValue(matType, attribName, paramValue); | ||
158 | // set the physical value also | ||
159 | SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
160 | } | ||
161 | paramName += "Physical"; | ||
162 | if (pConfig.Contains(paramName)) | ||
163 | { | ||
164 | float paramValue = pConfig.GetFloat(paramName); | ||
165 | SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
166 | } | ||
167 | } | ||
168 | matType++; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | private static void SetAttributeValue(int matType, string attribName, float val) | ||
173 | { | ||
174 | MaterialAttributes thisAttrib = Attributes[matType]; | ||
175 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName); | ||
176 | if (fieldInfo != null) | ||
177 | { | ||
178 | fieldInfo.SetValue(thisAttrib, val); | ||
179 | Attributes[matType] = thisAttrib; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) | ||
184 | { | ||
185 | int ind = (int)type; | ||
186 | if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; | ||
187 | return Attributes[ind]; | ||
188 | } | ||
189 | |||
190 | } | ||
191 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index bc6e4c4..e91bfa8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | |||
@@ -1,104 +1,169 @@ | |||
1 | using System; | 1 | using System; |
2 | using System.Collections.Generic; | 2 | using System.Collections.Generic; |
3 | using System.Text; | 3 | using System.Text; |
4 | using OpenMetaverse; | 4 | using OpenMetaverse; |
5 | 5 | ||
6 | namespace OpenSim.Region.Physics.BulletSPlugin | 6 | namespace OpenSim.Region.Physics.BulletSPlugin |
7 | { | 7 | { |
8 | public abstract class BSMotor | 8 | public abstract class BSMotor |
9 | { | 9 | { |
10 | public virtual void Reset() { } | 10 | // Timescales and other things can be turned off by setting them to 'infinite'. |
11 | public virtual void Zero() { } | 11 | public const float Infinite = 10000f; |
12 | } | 12 | public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); |
13 | // Can all the incremental stepping be replaced with motor classes? | 13 | |
14 | public class BSVMotor : BSMotor | 14 | public BSMotor(string useName) |
15 | { | 15 | { |
16 | public Vector3 FrameOfReference { get; set; } | 16 | UseName = useName; |
17 | public Vector3 Offset { get; set; } | 17 | PhysicsScene = null; |
18 | 18 | } | |
19 | public float TimeScale { get; set; } | 19 | public virtual void Reset() { } |
20 | public float TargetValueDecayTimeScale { get; set; } | 20 | public virtual void Zero() { } |
21 | public Vector3 CurrentValueReductionTimescale { get; set; } | 21 | |
22 | public float Efficiency { get; set; } | 22 | public string UseName { get; private set; } |
23 | 23 | // Used only for outputting debug information. Might not be set so check for null. | |
24 | public Vector3 TargetValue { get; private set; } | 24 | public BSScene PhysicsScene { get; set; } |
25 | public Vector3 CurrentValue { get; private set; } | 25 | protected void MDetailLog(string msg, params Object[] parms) |
26 | 26 | { | |
27 | 27 | if (PhysicsScene != null) | |
28 | 28 | { | |
29 | BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | 29 | if (PhysicsScene.VehicleLoggingEnabled) |
30 | { | 30 | { |
31 | TimeScale = timeScale; | 31 | PhysicsScene.DetailLog(msg, parms); |
32 | TargetValueDecayTimeScale = decayTimeScale; | 32 | } |
33 | CurrentValueReductionTimescale = frictionTimeScale; | 33 | } |
34 | Efficiency = efficiency; | 34 | } |
35 | } | 35 | } |
36 | public void SetCurrent(Vector3 current) | 36 | // Can all the incremental stepping be replaced with motor classes? |
37 | { | 37 | public class BSVMotor : BSMotor |
38 | CurrentValue = current; | 38 | { |
39 | } | 39 | public Vector3 FrameOfReference { get; set; } |
40 | public void SetTarget(Vector3 target) | 40 | public Vector3 Offset { get; set; } |
41 | { | 41 | |
42 | TargetValue = target; | 42 | public float TimeScale { get; set; } |
43 | } | 43 | public float TargetValueDecayTimeScale { get; set; } |
44 | public Vector3 Step(float timeStep) | 44 | public Vector3 FrictionTimescale { get; set; } |
45 | { | 45 | public float Efficiency { get; set; } |
46 | if (CurrentValue.LengthSquared() > 0.001f) | 46 | |
47 | { | 47 | public Vector3 TargetValue { get; private set; } |
48 | // Vector3 origDir = Target; // DEBUG | 48 | public Vector3 CurrentValue { get; private set; } |
49 | // Vector3 origVel = CurrentValue; // DEBUG | 49 | |
50 | 50 | public BSVMotor(string useName) | |
51 | // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete | 51 | : base(useName) |
52 | Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; | 52 | { |
53 | CurrentValue += addAmount; | 53 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; |
54 | 54 | Efficiency = 1f; | |
55 | float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | 55 | FrictionTimescale = BSMotor.InfiniteVector; |
56 | TargetValue *= (1f - decayFactor); | 56 | CurrentValue = TargetValue = Vector3.Zero; |
57 | 57 | } | |
58 | Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; | 58 | public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) |
59 | CurrentValue *= (Vector3.One - frictionFactor); | 59 | : this(useName) |
60 | } | 60 | { |
61 | else | 61 | TimeScale = timeScale; |
62 | { | 62 | TargetValueDecayTimeScale = decayTimeScale; |
63 | // if what remains of direction is very small, zero it. | 63 | FrictionTimescale = frictionTimeScale; |
64 | TargetValue = Vector3.Zero; | 64 | Efficiency = efficiency; |
65 | CurrentValue = Vector3.Zero; | 65 | CurrentValue = TargetValue = Vector3.Zero; |
66 | 66 | } | |
67 | // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 67 | public void SetCurrent(Vector3 current) |
68 | } | 68 | { |
69 | return CurrentValue; | 69 | CurrentValue = current; |
70 | } | 70 | } |
71 | } | 71 | public void SetTarget(Vector3 target) |
72 | 72 | { | |
73 | public class BSFMotor : BSMotor | 73 | TargetValue = target; |
74 | { | 74 | } |
75 | public float TimeScale { get; set; } | 75 | public Vector3 Step(float timeStep) |
76 | public float DecayTimeScale { get; set; } | 76 | { |
77 | public float Friction { get; set; } | 77 | Vector3 returnCurrent = Vector3.Zero; |
78 | public float Efficiency { get; set; } | 78 | if (!CurrentValue.ApproxEquals(TargetValue, 0.01f)) |
79 | 79 | { | |
80 | public float Target { get; private set; } | 80 | Vector3 origTarget = TargetValue; // DEBUG |
81 | public float CurrentValue { get; private set; } | 81 | Vector3 origCurrVal = CurrentValue; // DEBUG |
82 | 82 | ||
83 | BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) | 83 | // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete |
84 | { | 84 | Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep; |
85 | } | 85 | CurrentValue += addAmount; |
86 | public void SetCurrent(float target) | 86 | |
87 | { | 87 | returnCurrent = CurrentValue; |
88 | } | 88 | |
89 | public void SetTarget(float target) | 89 | // The desired value reduces to zero which also reduces the difference with current. |
90 | { | 90 | // If the decay time is infinite, don't decay at all. |
91 | } | 91 | float decayFactor = 0f; |
92 | public float Step(float timeStep) | 92 | if (TargetValueDecayTimeScale != BSMotor.Infinite) |
93 | { | 93 | { |
94 | return 0f; | 94 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; |
95 | } | 95 | TargetValue *= (1f - decayFactor); |
96 | } | 96 | } |
97 | public class BSPIDMotor : BSMotor | 97 | |
98 | { | 98 | Vector3 frictionFactor = Vector3.Zero; |
99 | // TODO: write and use this one | 99 | if (FrictionTimescale != BSMotor.InfiniteVector) |
100 | BSPIDMotor() | 100 | { |
101 | { | 101 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; |
102 | } | 102 | frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep; |
103 | } | 103 | frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep; |
104 | } | 104 | frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep; |
105 | CurrentValue *= (Vector3.One - frictionFactor); | ||
106 | } | ||
107 | |||
108 | MDetailLog("{0},BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}", | ||
109 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
110 | timeStep, TimeScale, addAmount, | ||
111 | TargetValueDecayTimeScale, decayFactor, | ||
112 | FrictionTimescale, frictionFactor); | ||
113 | MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", | ||
114 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, | ||
115 | addAmount, decayFactor, frictionFactor, returnCurrent); | ||
116 | } | ||
117 | else | ||
118 | { | ||
119 | // Difference between what we have and target is small. Motor is done. | ||
120 | CurrentValue = Vector3.Zero; | ||
121 | TargetValue = Vector3.Zero; | ||
122 | |||
123 | MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", | ||
124 | BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); | ||
125 | |||
126 | } | ||
127 | return returnCurrent; | ||
128 | } | ||
129 | public override string ToString() | ||
130 | { | ||
131 | return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>", | ||
132 | UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | public class BSFMotor : BSMotor | ||
137 | { | ||
138 | public float TimeScale { get; set; } | ||
139 | public float DecayTimeScale { get; set; } | ||
140 | public float Friction { get; set; } | ||
141 | public float Efficiency { get; set; } | ||
142 | |||
143 | public float Target { get; private set; } | ||
144 | public float CurrentValue { get; private set; } | ||
145 | |||
146 | public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) | ||
147 | : base(useName) | ||
148 | { | ||
149 | } | ||
150 | public void SetCurrent(float target) | ||
151 | { | ||
152 | } | ||
153 | public void SetTarget(float target) | ||
154 | { | ||
155 | } | ||
156 | public float Step(float timeStep) | ||
157 | { | ||
158 | return 0f; | ||
159 | } | ||
160 | } | ||
161 | public class BSPIDMotor : BSMotor | ||
162 | { | ||
163 | // TODO: write and use this one | ||
164 | public BSPIDMotor(string useName) | ||
165 | : base(useName) | ||
166 | { | ||
167 | } | ||
168 | } | ||
169 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 2b3fa25..3fb0300 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -253,8 +253,9 @@ public sealed class BSPrim : BSPhysObject | |||
253 | // Zero some other properties in the physics engine | 253 | // Zero some other properties in the physics engine |
254 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 254 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
255 | { | 255 | { |
256 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 256 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
257 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 257 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity); |
258 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
258 | }); | 259 | }); |
259 | } | 260 | } |
260 | 261 | ||
@@ -329,7 +330,7 @@ public sealed class BSPrim : BSPhysObject | |||
329 | 330 | ||
330 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 331 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
331 | { | 332 | { |
332 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 333 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
333 | // TODO: a floating motor so object will bob in the water | 334 | // TODO: a floating motor so object will bob in the water |
334 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) | 335 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) |
335 | { | 336 | { |
@@ -342,13 +343,12 @@ public sealed class BSPrim : BSPhysObject | |||
342 | // TODO: check for out of bounds | 343 | // TODO: check for out of bounds |
343 | 344 | ||
344 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. | 345 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. |
346 | // TODO: This should be intergrated with a geneal physics action mechanism. | ||
347 | // TODO: This should be moderated with PID'ness. | ||
345 | if (ret) | 348 | if (ret) |
346 | { | 349 | { |
347 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() | 350 | // Apply upforce and overcome gravity. |
348 | { | 351 | AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime); |
349 | // Apply upforce and overcome gravity. | ||
350 | ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; | ||
351 | }); | ||
352 | } | 352 | } |
353 | return ret; | 353 | return ret; |
354 | } | 354 | } |
@@ -1381,54 +1381,16 @@ public sealed class BSPrim : BSPhysObject | |||
1381 | 1381 | ||
1382 | public override void UpdateProperties(EntityProperties entprop) | 1382 | public override void UpdateProperties(EntityProperties entprop) |
1383 | { | 1383 | { |
1384 | /* | 1384 | // Updates only for individual prims and for the root object of a linkset. |
1385 | UpdatedProperties changed = 0; | 1385 | if (Linkset.IsRoot(this)) |
1386 | // assign to the local variables so the normal set action does not happen | ||
1387 | // if (_position != entprop.Position) | ||
1388 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1389 | { | ||
1390 | _position = entprop.Position; | ||
1391 | changed |= UpdatedProperties.Position; | ||
1392 | } | ||
1393 | // if (_orientation != entprop.Rotation) | ||
1394 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1395 | { | ||
1396 | _orientation = entprop.Rotation; | ||
1397 | changed |= UpdatedProperties.Rotation; | ||
1398 | } | ||
1399 | // if (_velocity != entprop.Velocity) | ||
1400 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1401 | { | ||
1402 | _velocity = entprop.Velocity; | ||
1403 | changed |= UpdatedProperties.Velocity; | ||
1404 | } | ||
1405 | // if (_acceleration != entprop.Acceleration) | ||
1406 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1407 | { | ||
1408 | _acceleration = entprop.Acceleration; | ||
1409 | changed |= UpdatedProperties.Acceleration; | ||
1410 | } | ||
1411 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1412 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1413 | { | ||
1414 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1415 | changed |= UpdatedProperties.RotationalVel; | ||
1416 | } | ||
1417 | if (changed != 0) | ||
1418 | { | 1386 | { |
1419 | // Only update the position of single objects and linkset roots | 1387 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet |
1420 | if (Linkset.IsRoot(this)) | 1388 | // TODO: handle physics introduced by Bullet with computed vehicle physics. |
1389 | if (_vehicle.IsActive) | ||
1421 | { | 1390 | { |
1422 | base.RequestPhysicsterseUpdate(); | 1391 | entprop.RotationalVelocity = OMV.Vector3.Zero; |
1423 | } | 1392 | } |
1424 | } | ||
1425 | */ | ||
1426 | |||
1427 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | ||
1428 | 1393 | ||
1429 | // Updates only for individual prims and for the root object of a linkset. | ||
1430 | if (Linkset.IsRoot(this)) | ||
1431 | { | ||
1432 | // Assign directly to the local variables so the normal set action does not happen | 1394 | // Assign directly to the local variables so the normal set action does not happen |
1433 | _position = entprop.Position; | 1395 | _position = entprop.Position; |
1434 | _orientation = entprop.Rotation; | 1396 | _orientation = entprop.Rotation; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 27a78d1..0c80611 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -39,23 +39,10 @@ using log4net; | |||
39 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | 40 | ||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | 41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) |
42 | // Test sculpties (verified that they don't work) | ||
43 | // Compute physics FPS reasonably | ||
44 | // Based on material, set density and friction | 42 | // Based on material, set density and friction |
45 | // Don't use constraints in linksets of non-physical objects. Means having to move children manually. | ||
46 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? | ||
47 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) | ||
48 | // At the moment, physical and phantom causes object to drop through the terrain | ||
49 | // Physical phantom objects and related typing (collision options ) | ||
50 | // Check out llVolumeDetect. Must do something for that. | ||
51 | // Use collision masks for collision with terrain and phantom objects | ||
52 | // More efficient memory usage when passing hull information from BSPrim to BulletSim | 43 | // More efficient memory usage when passing hull information from BSPrim to BulletSim |
53 | // Should prim.link() and prim.delink() membership checking happen at taint time? | ||
54 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once. | ||
55 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect | 44 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect |
56 | // Implement LockAngularMotion | 45 | // Implement LockAngularMotion |
57 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) | ||
58 | // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. | ||
59 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? | 46 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? |
60 | // Check terrain size. 128 or 127? | 47 | // Check terrain size. 128 or 127? |
61 | // Raycast | 48 | // Raycast |
@@ -140,7 +127,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
140 | public const uint GROUNDPLANE_ID = 1; | 127 | public const uint GROUNDPLANE_ID = 1; |
141 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here | 128 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here |
142 | 129 | ||
143 | private float m_waterLevel; | 130 | public float SimpleWaterLevel { get; set; } |
144 | public BSTerrainManager TerrainManager { get; private set; } | 131 | public BSTerrainManager TerrainManager { get; private set; } |
145 | 132 | ||
146 | public ConfigurationParameters Params | 133 | public ConfigurationParameters Params |
@@ -195,6 +182,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
195 | private string m_physicsLoggingDir; | 182 | private string m_physicsLoggingDir; |
196 | private string m_physicsLoggingPrefix; | 183 | private string m_physicsLoggingPrefix; |
197 | private int m_physicsLoggingFileMinutes; | 184 | private int m_physicsLoggingFileMinutes; |
185 | private bool m_physicsLoggingDoFlush; | ||
198 | // 'true' of the vehicle code is to log lots of details | 186 | // 'true' of the vehicle code is to log lots of details |
199 | public bool VehicleLoggingEnabled { get; private set; } | 187 | public bool VehicleLoggingEnabled { get; private set; } |
200 | 188 | ||
@@ -234,6 +222,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
234 | if (m_physicsLoggingEnabled) | 222 | if (m_physicsLoggingEnabled) |
235 | { | 223 | { |
236 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | 224 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); |
225 | PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. | ||
237 | } | 226 | } |
238 | else | 227 | else |
239 | { | 228 | { |
@@ -302,12 +291,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
302 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | 291 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); |
303 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | 292 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); |
304 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | 293 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); |
294 | m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); | ||
305 | // Very detailed logging for vehicle debugging | 295 | // Very detailed logging for vehicle debugging |
306 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | 296 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); |
307 | 297 | ||
308 | // Do any replacements in the parameters | 298 | // Do any replacements in the parameters |
309 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | 299 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); |
310 | } | 300 | } |
301 | |||
302 | // The material characteristics. | ||
303 | BSMaterials.InitializeFromDefaults(Params); | ||
304 | if (pConfig != null) | ||
305 | { | ||
306 | BSMaterials.InitializefromParameters(pConfig); | ||
307 | } | ||
311 | } | 308 | } |
312 | } | 309 | } |
313 | 310 | ||
@@ -499,7 +496,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
499 | 496 | ||
500 | try | 497 | try |
501 | { | 498 | { |
502 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 499 | // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG |
503 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 500 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); |
504 | 501 | ||
505 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | 502 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, |
@@ -508,7 +505,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
508 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 505 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
509 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", | 506 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", |
510 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | 507 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); |
511 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 508 | // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG |
512 | } | 509 | } |
513 | catch (Exception e) | 510 | catch (Exception e) |
514 | { | 511 | { |
@@ -520,9 +517,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
520 | collidersCount = 0; | 517 | collidersCount = 0; |
521 | } | 518 | } |
522 | 519 | ||
523 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in | 520 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in. |
524 | 521 | ||
525 | // Get a value for 'now' so all the collision and update routines don't have to get their own | 522 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
526 | SimulationNowTime = Util.EnvironmentTickCount(); | 523 | SimulationNowTime = Util.EnvironmentTickCount(); |
527 | 524 | ||
528 | // If there were collisions, process them by sending the event to the prim. | 525 | // If there were collisions, process them by sending the event to the prim. |
@@ -568,6 +565,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
568 | ObjectsWithCollisions.Remove(po); | 565 | ObjectsWithCollisions.Remove(po); |
569 | ObjectsWithNoMoreCollisions.Clear(); | 566 | ObjectsWithNoMoreCollisions.Clear(); |
570 | } | 567 | } |
568 | // Done with collisions. | ||
571 | 569 | ||
572 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | 570 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine |
573 | if (updatedEntityCount > 0) | 571 | if (updatedEntityCount > 0) |
@@ -591,9 +589,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
591 | 589 | ||
592 | // The physics engine returns the number of milliseconds it simulated this call. | 590 | // The physics engine returns the number of milliseconds it simulated this call. |
593 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 591 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
594 | // We multiply by 55 to give a recognizable running rate (55 or less). | 592 | // Multiply by 55 to give a nominal frame rate of 55. |
595 | return numSubSteps * m_fixedTimeStep * 1000 * 55; | 593 | return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f; |
596 | // return timeStep * 1000 * 55; | ||
597 | } | 594 | } |
598 | 595 | ||
599 | // Something has collided | 596 | // Something has collided |
@@ -639,12 +636,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
639 | 636 | ||
640 | public override void SetWaterLevel(float baseheight) | 637 | public override void SetWaterLevel(float baseheight) |
641 | { | 638 | { |
642 | m_waterLevel = baseheight; | 639 | SimpleWaterLevel = baseheight; |
643 | } | ||
644 | // Someday.... | ||
645 | public float GetWaterLevelAtXYZ(Vector3 loc) | ||
646 | { | ||
647 | return m_waterLevel; | ||
648 | } | 640 | } |
649 | 641 | ||
650 | public override void DeleteTerrain() | 642 | public override void DeleteTerrain() |
@@ -1069,7 +1061,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1069 | (s,p,l,v) => { s.PID_P = v; } ), | 1061 | (s,p,l,v) => { s.PID_P = v; } ), |
1070 | 1062 | ||
1071 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | 1063 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", |
1072 | 0.5f, | 1064 | 0.2f, |
1073 | (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, | 1065 | (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, |
1074 | (s) => { return s.m_params[0].defaultFriction; }, | 1066 | (s) => { return s.m_params[0].defaultFriction; }, |
1075 | (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), | 1067 | (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), |
@@ -1084,7 +1076,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1084 | (s) => { return s.m_params[0].defaultRestitution; }, | 1076 | (s) => { return s.m_params[0].defaultRestitution; }, |
1085 | (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), | 1077 | (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), |
1086 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | 1078 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", |
1087 | 0f, | 1079 | 0.04f, |
1088 | (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, | 1080 | (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, |
1089 | (s) => { return s.m_params[0].collisionMargin; }, | 1081 | (s) => { return s.m_params[0].collisionMargin; }, |
1090 | (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), | 1082 | (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), |
@@ -1151,7 +1143,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1151 | (s) => { return s.m_params[0].terrainImplementation; }, | 1143 | (s) => { return s.m_params[0].terrainImplementation; }, |
1152 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), | 1144 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), |
1153 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 1145 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |
1154 | 0.5f, | 1146 | 0.3f, |
1155 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | 1147 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, |
1156 | (s) => { return s.m_params[0].terrainFriction; }, | 1148 | (s) => { return s.m_params[0].terrainFriction; }, |
1157 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), | 1149 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), |
@@ -1165,13 +1157,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1165 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | 1157 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, |
1166 | (s) => { return s.m_params[0].terrainRestitution; }, | 1158 | (s) => { return s.m_params[0].terrainRestitution; }, |
1167 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), | 1159 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), |
1160 | new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , | ||
1161 | 0.04f, | ||
1162 | (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); }, | ||
1163 | (s) => { return s.m_params[0].terrainCollisionMargin; }, | ||
1164 | (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
1165 | |||
1168 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 1166 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
1169 | 0.2f, | 1167 | 0.2f, |
1170 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | 1168 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, |
1171 | (s) => { return s.m_params[0].avatarFriction; }, | 1169 | (s) => { return s.m_params[0].avatarFriction; }, |
1172 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | 1170 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), |
1173 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | 1171 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", |
1174 | 10f, | 1172 | 10.0f, |
1175 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | 1173 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, |
1176 | (s) => { return s.m_params[0].avatarStandingFriction; }, | 1174 | (s) => { return s.m_params[0].avatarStandingFriction; }, |
1177 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | 1175 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), |
@@ -1206,6 +1204,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1206 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, | 1204 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, |
1207 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), | 1205 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), |
1208 | 1206 | ||
1207 | new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||
1208 | 0.95f, | ||
1209 | (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); }, | ||
1210 | (s) => { return s.m_params[0].vehicleAngularDamping; }, | ||
1211 | (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ), | ||
1209 | 1212 | ||
1210 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | 1213 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", |
1211 | 0f, | 1214 | 0f, |
@@ -1487,7 +1490,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1487 | { | 1490 | { |
1488 | PhysicsLogging.Write(msg, args); | 1491 | PhysicsLogging.Write(msg, args); |
1489 | // Add the Flush() if debugging crashes. Gets all the messages written out. | 1492 | // Add the Flush() if debugging crashes. Gets all the messages written out. |
1490 | // PhysicsLogging.Flush(); | 1493 | if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); |
1491 | } | 1494 | } |
1492 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 1495 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. |
1493 | public const string DetailLogZero = "0000000000"; | 1496 | public const string DetailLogZero = "0000000000"; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 3ca756c..0cb151e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs | |||
@@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
93 | { | 93 | { |
94 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, | 94 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, |
95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, | 95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, |
96 | m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); | 96 | m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin); |
97 | 97 | ||
98 | // Create the terrain shape from the mapInfo | 98 | // Create the terrain shape from the mapInfo |
99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), | 99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), |
@@ -148,7 +148,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
148 | } | 148 | } |
149 | 149 | ||
150 | // The passed position is relative to the base of the region. | 150 | // The passed position is relative to the base of the region. |
151 | public override float GetHeightAtXYZ(Vector3 pos) | 151 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
152 | { | 152 | { |
153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
154 | 154 | ||
@@ -166,5 +166,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
166 | } | 166 | } |
167 | return ret; | 167 | return ret; |
168 | } | 168 | } |
169 | |||
170 | // The passed position is relative to the base of the region. | ||
171 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
172 | { | ||
173 | return PhysicsScene.SimpleWaterLevel; | ||
174 | } | ||
169 | } | 175 | } |
170 | } | 176 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 23fcfd3..17d9536 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -62,7 +62,8 @@ public abstract class BSTerrainPhys : IDisposable | |||
62 | ID = id; | 62 | ID = id; |
63 | } | 63 | } |
64 | public abstract void Dispose(); | 64 | public abstract void Dispose(); |
65 | public abstract float GetHeightAtXYZ(Vector3 pos); | 65 | public abstract float GetTerrainHeightAtXYZ(Vector3 pos); |
66 | public abstract float GetWaterLevelAtXYZ(Vector3 pos); | ||
66 | } | 67 | } |
67 | 68 | ||
68 | // ========================================================================================== | 69 | // ========================================================================================== |
@@ -75,13 +76,12 @@ public sealed class BSTerrainManager | |||
75 | public const float HEIGHT_INITIALIZATION = 24.987f; | 76 | public const float HEIGHT_INITIALIZATION = 24.987f; |
76 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; | 77 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; |
77 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; | 78 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; |
79 | public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; | ||
78 | 80 | ||
79 | // If the min and max height are equal, we reduce the min by this | 81 | // If the min and max height are equal, we reduce the min by this |
80 | // amount to make sure that a bounding box is built for the terrain. | 82 | // amount to make sure that a bounding box is built for the terrain. |
81 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; | 83 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; |
82 | 84 | ||
83 | public const float TERRAIN_COLLISION_MARGIN = 0.0f; | ||
84 | |||
85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. | 85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. |
86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
87 | 87 | ||
@@ -129,7 +129,8 @@ public sealed class BSTerrainManager | |||
129 | { | 129 | { |
130 | // The ground plane is here to catch things that are trying to drop to negative infinity | 130 | // The ground plane is here to catch things that are trying to drop to negative infinity |
131 | BulletShape groundPlaneShape = new BulletShape( | 131 | BulletShape groundPlaneShape = new BulletShape( |
132 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), | 132 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, |
133 | PhysicsScene.Params.terrainCollisionMargin), | ||
133 | BSPhysicsShapeType.SHAPE_GROUNDPLANE); | 134 | BSPhysicsShapeType.SHAPE_GROUNDPLANE); |
134 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, | 135 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, |
135 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | 136 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, |
@@ -165,17 +166,22 @@ public sealed class BSTerrainManager | |||
165 | // Release all the terrain we have allocated | 166 | // Release all the terrain we have allocated |
166 | public void ReleaseTerrain() | 167 | public void ReleaseTerrain() |
167 | { | 168 | { |
168 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) | 169 | lock (m_terrains) |
169 | { | 170 | { |
170 | kvp.Value.Dispose(); | 171 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) |
172 | { | ||
173 | kvp.Value.Dispose(); | ||
174 | } | ||
175 | m_terrains.Clear(); | ||
171 | } | 176 | } |
172 | m_terrains.Clear(); | ||
173 | } | 177 | } |
174 | 178 | ||
175 | // The simulator wants to set a new heightmap for the terrain. | 179 | // The simulator wants to set a new heightmap for the terrain. |
176 | public void SetTerrain(float[] heightMap) { | 180 | public void SetTerrain(float[] heightMap) { |
177 | float[] localHeightMap = heightMap; | 181 | float[] localHeightMap = heightMap; |
178 | PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() | 182 | // If there are multiple requests for changes to the same terrain between ticks, |
183 | // only do that last one. | ||
184 | PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | ||
179 | { | 185 | { |
180 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | 186 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) |
181 | { | 187 | { |
@@ -211,6 +217,7 @@ public sealed class BSTerrainManager | |||
211 | // terrain shape is created and added to the body. | 217 | // terrain shape is created and added to the body. |
212 | // This call is most often used to update the heightMap and parameters of the terrain. | 218 | // This call is most often used to update the heightMap and parameters of the terrain. |
213 | // (The above does suggest that some simplification/refactoring is in order.) | 219 | // (The above does suggest that some simplification/refactoring is in order.) |
220 | // Called during taint-time. | ||
214 | private void UpdateTerrain(uint id, float[] heightMap, | 221 | private void UpdateTerrain(uint id, float[] heightMap, |
215 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | 222 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) |
216 | { | 223 | { |
@@ -220,7 +227,7 @@ public sealed class BSTerrainManager | |||
220 | // Find high and low points of passed heightmap. | 227 | // Find high and low points of passed heightmap. |
221 | // The min and max passed in is usually the area objects can be in (maximum | 228 | // The min and max passed in is usually the area objects can be in (maximum |
222 | // object height, for instance). The terrain wants the bounding box for the | 229 | // object height, for instance). The terrain wants the bounding box for the |
223 | // terrain so we replace passed min and max Z with the actual terrain min/max Z. | 230 | // terrain so replace passed min and max Z with the actual terrain min/max Z. |
224 | float minZ = float.MaxValue; | 231 | float minZ = float.MaxValue; |
225 | float maxZ = float.MinValue; | 232 | float maxZ = float.MinValue; |
226 | foreach (float height in heightMap) | 233 | foreach (float height in heightMap) |
@@ -238,15 +245,15 @@ public sealed class BSTerrainManager | |||
238 | 245 | ||
239 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); | 246 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); |
240 | 247 | ||
241 | BSTerrainPhys terrainPhys; | 248 | lock (m_terrains) |
242 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) | ||
243 | { | 249 | { |
244 | // There is already a terrain in this spot. Free the old and build the new. | 250 | BSTerrainPhys terrainPhys; |
245 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | 251 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) |
246 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
247 | |||
248 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate() | ||
249 | { | 252 | { |
253 | // There is already a terrain in this spot. Free the old and build the new. | ||
254 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | ||
255 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
256 | |||
250 | // Remove old terrain from the collection | 257 | // Remove old terrain from the collection |
251 | m_terrains.Remove(terrainRegionBase); | 258 | m_terrains.Remove(terrainRegionBase); |
252 | // Release any physical memory it may be using. | 259 | // Release any physical memory it may be using. |
@@ -271,35 +278,24 @@ public sealed class BSTerrainManager | |||
271 | // I hate doing this, but just bail | 278 | // I hate doing this, but just bail |
272 | return; | 279 | return; |
273 | } | 280 | } |
274 | }); | 281 | } |
275 | } | 282 | else |
276 | else | 283 | { |
277 | { | 284 | // We don't know about this terrain so either we are creating a new terrain or |
278 | // We don't know about this terrain so either we are creating a new terrain or | 285 | // our mega-prim child is giving us a new terrain to add to the phys world |
279 | // our mega-prim child is giving us a new terrain to add to the phys world | ||
280 | |||
281 | // if this is a child terrain, calculate a unique terrain id | ||
282 | uint newTerrainID = id; | ||
283 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
284 | newTerrainID = ++m_terrainCount; | ||
285 | |||
286 | float[] heightMapX = heightMap; | ||
287 | Vector3 minCoordsX = minCoords; | ||
288 | Vector3 maxCoordsX = maxCoords; | ||
289 | 286 | ||
290 | DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", | 287 | // if this is a child terrain, calculate a unique terrain id |
291 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 288 | uint newTerrainID = id; |
289 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
290 | newTerrainID = ++m_terrainCount; | ||
292 | 291 | ||
293 | // Code that must happen at taint-time | 292 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", |
294 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() | 293 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); |
295 | { | ||
296 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", | ||
297 | BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y); | ||
298 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 294 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
299 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 295 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
300 | 296 | ||
301 | m_terrainModified = true; | 297 | m_terrainModified = true; |
302 | }); | 298 | } |
303 | } | 299 | } |
304 | } | 300 | } |
305 | 301 | ||
@@ -349,6 +345,7 @@ public sealed class BSTerrainManager | |||
349 | // with the same parameters as last time. | 345 | // with the same parameters as last time. |
350 | if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) | 346 | if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) |
351 | return lastHeight; | 347 | return lastHeight; |
348 | m_terrainModified = false; | ||
352 | 349 | ||
353 | lastHeightTX = tX; | 350 | lastHeightTX = tX; |
354 | lastHeightTY = tY; | 351 | lastHeightTY = tY; |
@@ -358,20 +355,47 @@ public sealed class BSTerrainManager | |||
358 | int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | 355 | int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; |
359 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | 356 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); |
360 | 357 | ||
361 | BSTerrainPhys physTerrain; | 358 | lock (m_terrains) |
362 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) | ||
363 | { | 359 | { |
364 | ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); | 360 | BSTerrainPhys physTerrain; |
365 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", | 361 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) |
366 | BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); | 362 | { |
363 | ret = physTerrain.GetTerrainHeightAtXYZ(loc - terrainBaseXYZ); | ||
364 | } | ||
365 | else | ||
366 | { | ||
367 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | ||
368 | LogHeader, PhysicsScene.RegionName, tX, tY); | ||
369 | } | ||
367 | } | 370 | } |
368 | else | 371 | lastHeight = ret; |
372 | return ret; | ||
373 | } | ||
374 | |||
375 | public float GetWaterLevelAtXYZ(Vector3 pos) | ||
376 | { | ||
377 | float ret = WATER_HEIGHT_GETHEIGHT_RET; | ||
378 | |||
379 | float tX = pos.X; | ||
380 | float tY = pos.Y; | ||
381 | |||
382 | Vector3 terrainBaseXYZ = Vector3.Zero; | ||
383 | terrainBaseXYZ.X = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
384 | terrainBaseXYZ.Y = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
385 | |||
386 | lock (m_terrains) | ||
369 | { | 387 | { |
370 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | 388 | BSTerrainPhys physTerrain; |
371 | LogHeader, PhysicsScene.RegionName, tX, tY); | 389 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) |
390 | { | ||
391 | ret = physTerrain.GetWaterLevelAtXYZ(pos); | ||
392 | } | ||
393 | else | ||
394 | { | ||
395 | PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | ||
396 | LogHeader, PhysicsScene.RegionName, tX, tY); | ||
397 | } | ||
372 | } | 398 | } |
373 | m_terrainModified = false; | ||
374 | lastHeight = ret; | ||
375 | return ret; | 399 | return ret; |
376 | } | 400 | } |
377 | 401 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index dca7150..7e93ab4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs | |||
@@ -88,9 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
88 | // Something is very messed up and a crash is in our future. | 88 | // Something is very messed up and a crash is in our future. |
89 | return; | 89 | return; |
90 | } | 90 | } |
91 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", | ||
92 | ID, indicesCount, indices.Length, verticesCount, vertices.Length); | ||
91 | 93 | ||
92 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 94 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, |
93 | indicesCount, indices, verticesCount, vertices), | 95 | indicesCount, indices, verticesCount, vertices), |
94 | BSPhysicsShapeType.SHAPE_MESH); | 96 | BSPhysicsShapeType.SHAPE_MESH); |
95 | if (m_terrainShape.ptr == IntPtr.Zero) | 97 | if (m_terrainShape.ptr == IntPtr.Zero) |
96 | { | 98 | { |
@@ -122,10 +124,10 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
122 | // Static objects are not very massive. | 124 | // Static objects are not very massive. |
123 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); | 125 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); |
124 | 126 | ||
125 | // Return the new terrain to the world of physical objects | 127 | // Put the new terrain to the world of physical objects |
126 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 128 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); |
127 | 129 | ||
128 | // redo its bounding box now that it is in the world | 130 | // Redo its bounding box now that it is in the world |
129 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 131 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); |
130 | 132 | ||
131 | BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, | 133 | BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, |
@@ -146,7 +148,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
146 | } | 148 | } |
147 | } | 149 | } |
148 | 150 | ||
149 | public override float GetHeightAtXYZ(Vector3 pos) | 151 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
150 | { | 152 | { |
151 | // For the moment use the saved heightmap to get the terrain height. | 153 | // For the moment use the saved heightmap to get the terrain height. |
152 | // TODO: raycast downward to find the true terrain below the position. | 154 | // TODO: raycast downward to find the true terrain below the position. |
@@ -167,6 +169,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
167 | return ret; | 169 | return ret; |
168 | } | 170 | } |
169 | 171 | ||
172 | // The passed position is relative to the base of the region. | ||
173 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
174 | { | ||
175 | return PhysicsScene.SimpleWaterLevel; | ||
176 | } | ||
177 | |||
170 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | 178 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). |
171 | // Return 'true' if successfully created. | 179 | // Return 'true' if successfully created. |
172 | public static bool ConvertHeightmapToMesh( | 180 | public static bool ConvertHeightmapToMesh( |
@@ -188,6 +196,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
188 | // Simple mesh creation which assumes magnification == 1. | 196 | // Simple mesh creation which assumes magnification == 1. |
189 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. | 197 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. |
190 | 198 | ||
199 | // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop | ||
200 | // from zero to <= sizeX). The triangle indices are then generated as two triangles | ||
201 | // per heightmap point. There are sizeX by sizeY of these squares. The extra row and | ||
202 | // column of vertices are used to complete the triangles of the last row and column | ||
203 | // of the heightmap. | ||
191 | try | 204 | try |
192 | { | 205 | { |
193 | // One vertice per heightmap value plus the vertices off the top and bottom edge. | 206 | // One vertice per heightmap value plus the vertices off the top and bottom edge. |
@@ -200,16 +213,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
200 | float magY = (float)sizeY / extentY; | 213 | float magY = (float)sizeY / extentY; |
201 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", | 214 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", |
202 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); | 215 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); |
216 | float minHeight = float.MaxValue; | ||
203 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | 217 | // Note that sizeX+1 vertices are created since there is land between this and the next region. |
204 | for (int yy = 0; yy <= sizeY; yy++) | 218 | for (int yy = 0; yy <= sizeY; yy++) |
205 | { | 219 | { |
206 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times | 220 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times |
207 | { | 221 | { |
208 | int offset = yy * sizeX + xx; | 222 | int offset = yy * sizeX + xx; |
209 | // Extend the height from the height from the last row or column | 223 | // Extend the height with the height from the last row or column |
210 | if (yy == sizeY) offset -= sizeX; | 224 | if (yy == sizeY) offset -= sizeX; |
211 | if (xx == sizeX) offset -= 1; | 225 | if (xx == sizeX) offset -= 1; |
212 | float height = heightMap[offset]; | 226 | float height = heightMap[offset]; |
227 | minHeight = Math.Min(minHeight, height); | ||
213 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; | 228 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; |
214 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; | 229 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; |
215 | vertices[verticesCount + 2] = height + extentBase.Z; | 230 | vertices[verticesCount + 2] = height + extentBase.Z; |
@@ -217,14 +232,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
217 | } | 232 | } |
218 | } | 233 | } |
219 | verticesCount = verticesCount / 3; | 234 | verticesCount = verticesCount / 3; |
220 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}", | ||
221 | BSScene.DetailLogZero, verticesCount); | ||
222 | 235 | ||
223 | for (int yy = 0; yy < sizeY; yy++) | 236 | for (int yy = 0; yy < sizeY; yy++) |
224 | { | 237 | { |
225 | for (int xx = 0; xx < sizeX; xx++) | 238 | for (int xx = 0; xx < sizeX; xx++) |
226 | { | 239 | { |
227 | int offset = yy * sizeX + xx; | 240 | int offset = yy * (sizeX + 1) + xx; |
228 | // Each vertices is presumed to be the upper left corner of a box of two triangles | 241 | // Each vertices is presumed to be the upper left corner of a box of two triangles |
229 | indices[indicesCount + 0] = offset; | 242 | indices[indicesCount + 0] = offset; |
230 | indices[indicesCount + 1] = offset + 1; | 243 | indices[indicesCount + 1] = offset + 1; |
@@ -235,8 +248,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
235 | indicesCount += 6; | 248 | indicesCount += 6; |
236 | } | 249 | } |
237 | } | 250 | } |
238 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG | 251 | |
239 | LogHeader, indicesCount); // DEBUG | ||
240 | ret = true; | 252 | ret = true; |
241 | } | 253 | } |
242 | catch (Exception e) | 254 | catch (Exception e) |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index e60a760..1e003e6 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -287,6 +287,8 @@ public struct ConfigurationParameters | |||
287 | public float terrainFriction; | 287 | public float terrainFriction; |
288 | public float terrainHitFraction; | 288 | public float terrainHitFraction; |
289 | public float terrainRestitution; | 289 | public float terrainRestitution; |
290 | public float terrainCollisionMargin; | ||
291 | |||
290 | public float avatarFriction; | 292 | public float avatarFriction; |
291 | public float avatarStandingFriction; | 293 | public float avatarStandingFriction; |
292 | public float avatarDensity; | 294 | public float avatarDensity; |
@@ -296,6 +298,8 @@ public struct ConfigurationParameters | |||
296 | public float avatarCapsuleHeight; | 298 | public float avatarCapsuleHeight; |
297 | public float avatarContactProcessingThreshold; | 299 | public float avatarContactProcessingThreshold; |
298 | 300 | ||
301 | public float vehicleAngularDamping; | ||
302 | |||
299 | public float maxPersistantManifoldPoolSize; | 303 | public float maxPersistantManifoldPoolSize; |
300 | public float maxCollisionAlgorithmPoolSize; | 304 | public float maxCollisionAlgorithmPoolSize; |
301 | public float shouldDisableContactPoolDynamicAllocation; | 305 | public float shouldDisableContactPoolDynamicAllocation; |
@@ -353,7 +357,7 @@ public enum CollisionFlags : uint | |||
353 | CF_CHARACTER_OBJECT = 1 << 4, | 357 | CF_CHARACTER_OBJECT = 1 << 4, |
354 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | 358 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, |
355 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | 359 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, |
356 | // Following used by BulletSim to control collisions | 360 | // Following used by BulletSim to control collisions and updates |
357 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, | 361 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, |
358 | BS_FLOATS_ON_WATER = 1 << 11, | 362 | BS_FLOATS_ON_WATER = 1 << 11, |
359 | BS_NONE = 0, | 363 | BS_NONE = 0, |
@@ -482,6 +486,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData) | |||
482 | public static extern bool IsNativeShape2(IntPtr shape); | 486 | public static extern bool IsNativeShape2(IntPtr shape); |
483 | 487 | ||
484 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 488 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
489 | public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); | ||
490 | |||
491 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
485 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | 492 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); |
486 | 493 | ||
487 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 494 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index f629c4d..9262a9e 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
321 | 321 | ||
322 | if (primShape.SculptData.Length <= 0) | 322 | if (primShape.SculptData.Length <= 0) |
323 | { | 323 | { |
324 | // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this | ||
325 | // method twice - once before it has loaded sculpt data from the asset service and once afterwards. | ||
326 | // The first time will always call with unloaded SculptData if this needs to be uploaded. | ||
324 | // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); | 327 | // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); |
325 | return false; | 328 | return false; |
326 | } | 329 | } |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index a59f63f..d09aa62 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed"); | |||
3367 | _pbs.SculptData = new byte[asset.Data.Length]; | 3367 | _pbs.SculptData = new byte[asset.Data.Length]; |
3368 | asset.Data.CopyTo(_pbs.SculptData, 0); | 3368 | asset.Data.CopyTo(_pbs.SculptData, 0); |
3369 | // m_assetFailed = false; | 3369 | // m_assetFailed = false; |
3370 | |||
3371 | // m_log.DebugFormat( | ||
3372 | // "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}", | ||
3373 | // _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name); | ||
3374 | |||
3370 | m_taintshape = true; | 3375 | m_taintshape = true; |
3371 | _parent_scene.AddPhysicsActorTaint(this); | 3376 | _parent_scene.AddPhysicsActorTaint(this); |
3372 | } | 3377 | } |