aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs28
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs17
-rw-r--r--OpenSim/Framework/Util.cs9
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs13
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs10
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs3
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs158
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs41
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs283
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs96
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs814
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs135
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs153
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs180
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs57
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs1377
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs329
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs397
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs316
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs200
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs347
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs559
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs346
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs81
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs1494
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs957
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs1015
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs208
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs175
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs461
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs267
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs1603
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs280
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs885
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs19
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs96
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs193
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs7
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs113
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs10
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs47
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs47
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs10
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs94
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs9
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt35
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs39
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs227
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs3
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs9
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs4
52 files changed, 1622 insertions, 12636 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 85b19c0..b24336d 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -1025,7 +1025,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1025 return buffer; 1025 return buffer;
1026 } 1026 }
1027 1027
1028 // JsonRpc (v2.0 only) 1028 // JsonRpc (v2.0 only)
1029 // Batch requests not yet supported
1029 private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response) 1030 private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response)
1030 { 1031 {
1031 Stream requestStream = request.InputStream; 1032 Stream requestStream = request.InputStream;
@@ -1065,8 +1066,26 @@ namespace OpenSim.Framework.Servers.HttpServer
1065 { 1066 {
1066 jsonRpcHandlers.TryGetValue(methodname, out method); 1067 jsonRpcHandlers.TryGetValue(methodname, out method);
1067 } 1068 }
1068 1069 bool res = false;
1069 method(jsonRpcRequest, ref jsonRpcResponse); 1070 try
1071 {
1072 res = method(jsonRpcRequest, ref jsonRpcResponse);
1073 if(!res)
1074 {
1075 // The handler sent back an unspecified error
1076 if(jsonRpcResponse.Error.Code == 0)
1077 {
1078 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1079 }
1080 }
1081 }
1082 catch (Exception e)
1083 {
1084 string ErrorMessage = string.Format("[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message);
1085 m_log.Error(ErrorMessage);
1086 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1087 jsonRpcResponse.Error.Message = ErrorMessage;
1088 }
1070 } 1089 }
1071 else // Error no hanlder defined for requested method 1090 else // Error no hanlder defined for requested method
1072 { 1091 {
@@ -1731,6 +1750,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1731 1750
1732 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events 1751 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
1733 m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); 1752 m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000);
1753 m_PollServiceManager.Start();
1734 HTTPDRunning = true; 1754 HTTPDRunning = true;
1735 1755
1736 //HttpListenerContext context; 1756 //HttpListenerContext context;
@@ -1781,6 +1801,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1781 HTTPDRunning = false; 1801 HTTPDRunning = false;
1782 try 1802 try
1783 { 1803 {
1804 m_PollServiceManager.Stop();
1805
1784 m_httpListener2.ExceptionThrown -= httpServerException; 1806 m_httpListener2.ExceptionThrown -= httpServerException;
1785 //m_httpListener2.DisconnectHandler = null; 1807 //m_httpListener2.DisconnectHandler = null;
1786 1808
diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
index 7334049..5bab508 100644
--- a/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
@@ -30,5 +30,5 @@ using OpenMetaverse.StructuredData;
30 30
31namespace OpenSim.Framework.Servers.HttpServer 31namespace OpenSim.Framework.Servers.HttpServer
32{ 32{
33 public delegate void JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response); 33 public delegate bool JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response);
34} 34}
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 8d50151..3e84c55 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -45,19 +45,26 @@ namespace OpenSim.Framework.Servers.HttpServer
45 private uint m_WorkerThreadCount = 0; 45 private uint m_WorkerThreadCount = 0;
46 private Thread[] m_workerThreads; 46 private Thread[] m_workerThreads;
47 private PollServiceWorkerThread[] m_PollServiceWorkerThreads; 47 private PollServiceWorkerThread[] m_PollServiceWorkerThreads;
48 private bool m_running = true; 48 private volatile bool m_running = true;
49 private int m_pollTimeout;
49 50
50 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) 51 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
51 { 52 {
52 m_server = pSrv; 53 m_server = pSrv;
53 m_WorkerThreadCount = pWorkerThreadCount; 54 m_WorkerThreadCount = pWorkerThreadCount;
55 m_pollTimeout = pTimeout;
56 }
57
58 public void Start()
59 {
60 m_running = true;
54 m_workerThreads = new Thread[m_WorkerThreadCount]; 61 m_workerThreads = new Thread[m_WorkerThreadCount];
55 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount]; 62 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
56 63
57 //startup worker threads 64 //startup worker threads
58 for (uint i = 0; i < m_WorkerThreadCount; i++) 65 for (uint i = 0; i < m_WorkerThreadCount; i++)
59 { 66 {
60 m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, pTimeout); 67 m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout);
61 m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent; 68 m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent;
62 69
63 m_workerThreads[i] 70 m_workerThreads[i]
@@ -136,8 +143,10 @@ namespace OpenSim.Framework.Servers.HttpServer
136 143
137 } 144 }
138 145
139 ~PollServiceRequestManager() 146 public void Stop()
140 { 147 {
148 m_running = false;
149
141 foreach (object o in m_requests) 150 foreach (object o in m_requests)
142 { 151 {
143 PollServiceHttpRequest req = (PollServiceHttpRequest) o; 152 PollServiceHttpRequest req = (PollServiceHttpRequest) o;
@@ -151,8 +160,6 @@ namespace OpenSim.Framework.Servers.HttpServer
151 { 160 {
152 t.Abort(); 161 t.Abort();
153 } 162 }
154
155 m_running = false;
156 } 163 }
157 } 164 }
158} \ No newline at end of file 165} \ No newline at end of file
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index f6c9d15..9b1e97d 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1658,8 +1658,13 @@ namespace OpenSim.Framework
1658 if (m_ThreadPool != null) 1658 if (m_ThreadPool != null)
1659 throw new InvalidOperationException("SmartThreadPool is already initialized"); 1659 throw new InvalidOperationException("SmartThreadPool is already initialized");
1660 1660
1661 m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); 1661 STPStartInfo startInfo = new STPStartInfo();
1662 m_ThreadPool.Name = "Util"; 1662 startInfo.ThreadPoolName = "Util";
1663 startInfo.IdleTimeout = 2000;
1664 startInfo.MaxWorkerThreads = maxThreads;
1665 startInfo.MinWorkerThreads = 2;
1666
1667 m_ThreadPool = new SmartThreadPool(startInfo);
1663 } 1668 }
1664 1669
1665 public static int FireAndForgetCount() 1670 public static int FireAndForgetCount()
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 5778176..f2cb117 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1983,6 +1983,19 @@ namespace OpenSim.Region.Framework.Scenes
1983 EventManager.TriggerPrimsLoaded(this); 1983 EventManager.TriggerPrimsLoaded(this);
1984 } 1984 }
1985 1985
1986 public bool SupportsRayCastFiltered()
1987 {
1988 if (PhysicsScene == null)
1989 return false;
1990 return PhysicsScene.SupportsRaycastWorldFiltered();
1991 }
1992
1993 public object RayCastFiltered(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
1994 {
1995 if (PhysicsScene == null)
1996 return null;
1997 return PhysicsScene.RaycastWorld(position, direction, length, Count,filter);
1998 }
1986 1999
1987 /// <summary> 2000 /// <summary>
1988 /// Gets a new rez location based on the raycast and the size of the object that is being rezzed. 2001 /// Gets a new rez location based on the raycast and the size of the object that is being rezzed.
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 44e8fdf..e0ea344 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -1952,6 +1952,16 @@ namespace OpenSim.Region.Framework.Scenes
1952 PhysicsActor pa = PhysActor; 1952 PhysicsActor pa = PhysActor;
1953 1953
1954 if (pa != null) 1954 if (pa != null)
1955 return new Vector3(pa.GeometricCenter.X, pa.GeometricCenter.Y, pa.GeometricCenter.Z);
1956 else
1957 return new Vector3(0, 0, 0);
1958 }
1959
1960 public Vector3 GetCenterOfMass()
1961 {
1962 PhysicsActor pa = PhysActor;
1963
1964 if (pa != null)
1955 return new Vector3(pa.CenterOfMass.X, pa.CenterOfMass.Y, pa.CenterOfMass.Z); 1965 return new Vector3(pa.CenterOfMass.X, pa.CenterOfMass.Y, pa.CenterOfMass.Z);
1956 else 1966 else
1957 return new Vector3(0, 0, 0); 1967 return new Vector3(0, 0, 0);
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index c295305..a90872e 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -1954,8 +1954,7 @@ namespace OpenSim.Region.Framework.Scenes
1954 { 1954 {
1955 if (ParentID != 0) 1955 if (ParentID != 0)
1956 { 1956 {
1957 var targetPart = m_scene.GetSceneObjectPart(targetID); 1957 if (ParentPart.UUID == targetID)
1958 if (targetPart != null && targetPart.LocalId == ParentID)
1959 return; // already sitting here, ignore 1958 return; // already sitting here, ignore
1960 1959
1961 StandUp(); 1960 StandUp();
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
index 66265d8..5a37fad 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
@@ -55,42 +55,42 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
55 // These are the IRC Connector configurable parameters with hard-wired 55 // These are the IRC Connector configurable parameters with hard-wired
56 // default values (retained for compatability). 56 // default values (retained for compatability).
57 57
58 internal string Server = null; 58 internal string Server = null;
59 internal string Password = null; 59 internal string Password = null;
60 internal string IrcChannel = null; 60 internal string IrcChannel = null;
61 internal string BaseNickname = "OSimBot"; 61 internal string BaseNickname = "OSimBot";
62 internal uint Port = 6667; 62 internal uint Port = 6667;
63 internal string User = null; 63 internal string User = null;
64 64
65 internal bool ClientReporting = true; 65 internal bool ClientReporting = true;
66 internal bool RelayChat = true; 66 internal bool RelayChat = true;
67 internal bool RelayPrivateChannels = false; 67 internal bool RelayPrivateChannels = false;
68 internal int RelayChannel = 1; 68 internal int RelayChannel = 1;
69 internal List<int> ValidInWorldChannels = new List<int>(); 69 internal List<int> ValidInWorldChannels = new List<int>();
70 70
71 // Connector agnostic parameters. These values are NOT shared with the 71 // Connector agnostic parameters. These values are NOT shared with the
72 // connector and do not differentiate at an IRC level 72 // connector and do not differentiate at an IRC level
73 73
74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}"; 74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}";
75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}"; 75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}";
76 internal int RelayChannelOut = -1; 76 internal int RelayChannelOut = -1;
77 internal bool RandomizeNickname = true; 77 internal bool RandomizeNickname = true;
78 internal bool CommandsEnabled = false; 78 internal bool CommandsEnabled = false;
79 internal int CommandChannel = -1; 79 internal int CommandChannel = -1;
80 internal int ConnectDelay = 10; 80 internal int ConnectDelay = 10;
81 internal int PingDelay = 15; 81 internal int PingDelay = 15;
82 internal string DefaultZone = "Sim"; 82 internal string DefaultZone = "Sim";
83 83
84 internal string _accessPassword = String.Empty; 84 internal string _accessPassword = String.Empty;
85 internal Regex AccessPasswordRegex = null; 85 internal Regex AccessPasswordRegex = null;
86 internal List<string> ExcludeList = new List<string>(); 86 internal List<string> ExcludeList = new List<string>();
87 internal string AccessPassword 87 internal string AccessPassword
88 { 88 {
89 get { return _accessPassword; } 89 get { return _accessPassword; }
90 set 90 set
91 { 91 {
92 _accessPassword = value; 92 _accessPassword = value;
93 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword), 93 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword),
94 RegexOptions.Compiled); 94 RegexOptions.Compiled);
95 } 95 }
96 } 96 }
@@ -99,9 +99,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
99 99
100 // IRC connector reference 100 // IRC connector reference
101 101
102 internal IRCConnector irc = null; 102 internal IRCConnector irc = null;
103 103
104 internal int idn = _idk_++; 104 internal int idn = _idk_++;
105 105
106 // List of regions dependent upon this connection 106 // List of regions dependent upon this connection
107 107
@@ -119,29 +119,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
119 119
120 internal ChannelState(ChannelState model) 120 internal ChannelState(ChannelState model)
121 { 121 {
122 Server = model.Server; 122 Server = model.Server;
123 Password = model.Password; 123 Password = model.Password;
124 IrcChannel = model.IrcChannel; 124 IrcChannel = model.IrcChannel;
125 Port = model.Port; 125 Port = model.Port;
126 BaseNickname = model.BaseNickname; 126 BaseNickname = model.BaseNickname;
127 RandomizeNickname = model.RandomizeNickname; 127 RandomizeNickname = model.RandomizeNickname;
128 User = model.User; 128 User = model.User;
129 CommandsEnabled = model.CommandsEnabled; 129 CommandsEnabled = model.CommandsEnabled;
130 CommandChannel = model.CommandChannel; 130 CommandChannel = model.CommandChannel;
131 RelayChat = model.RelayChat; 131 RelayChat = model.RelayChat;
132 RelayPrivateChannels = model.RelayPrivateChannels; 132 RelayPrivateChannels = model.RelayPrivateChannels;
133 RelayChannelOut = model.RelayChannelOut; 133 RelayChannelOut = model.RelayChannelOut;
134 RelayChannel = model.RelayChannel; 134 RelayChannel = model.RelayChannel;
135 ValidInWorldChannels = model.ValidInWorldChannels; 135 ValidInWorldChannels = model.ValidInWorldChannels;
136 PrivateMessageFormat = model.PrivateMessageFormat; 136 PrivateMessageFormat = model.PrivateMessageFormat;
137 NoticeMessageFormat = model.NoticeMessageFormat; 137 NoticeMessageFormat = model.NoticeMessageFormat;
138 ClientReporting = model.ClientReporting; 138 ClientReporting = model.ClientReporting;
139 AccessPassword = model.AccessPassword; 139 AccessPassword = model.AccessPassword;
140 DefaultZone = model.DefaultZone; 140 DefaultZone = model.DefaultZone;
141 ConnectDelay = model.ConnectDelay; 141 ConnectDelay = model.ConnectDelay;
142 PingDelay = model.PingDelay; 142 PingDelay = model.PingDelay;
143 } 143 }
144 144
145 // Read the configuration file, performing variable substitution and any 145 // Read the configuration file, performing variable substitution and any
146 // necessary aliasing. See accompanying documentation for how this works. 146 // necessary aliasing. See accompanying documentation for how this works.
147 // If you don't need variables, then this works exactly as before. 147 // If you don't need variables, then this works exactly as before.
@@ -160,54 +160,54 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
160 160
161 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region); 161 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region);
162 162
163 cs.Server = Substitute(rs, config.GetString("server", null)); 163 cs.Server = Substitute(rs, config.GetString("server", null));
164 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server); 164 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server);
165 cs.Password = Substitute(rs, config.GetString("password", null)); 165 cs.Password = Substitute(rs, config.GetString("password", null));
166 // probably not a good idea to put a password in the log file 166 // probably not a good idea to put a password in the log file
167 cs.User = Substitute(rs, config.GetString("user", null)); 167 cs.User = Substitute(rs, config.GetString("user", null));
168 cs.IrcChannel = Substitute(rs, config.GetString("channel", null)); 168 cs.IrcChannel = Substitute(rs, config.GetString("channel", null));
169 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel); 169 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel);
170 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port)))); 170 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port))));
171 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port); 171 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port);
172 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname)); 172 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname));
173 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname); 173 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname);
174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname)))); 174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname))));
175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); 175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
176 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname)))); 176 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname))));
177 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); 177 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
178 cs.User = Substitute(rs, config.GetString("username", cs.User)); 178 cs.User = Substitute(rs, config.GetString("username", cs.User));
179 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User); 179 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User);
180 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled)))); 180 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled))));
181 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled); 181 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled);
182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel)))); 182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel))));
183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); 183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
184 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel)))); 184 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel))));
185 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); 185 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
186 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat)))); 186 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat))));
187 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat); 187 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat);
188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels)))); 188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels))));
189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); 189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
190 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels)))); 190 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
191 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); 191 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
192 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut)))); 192 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut))));
193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut); 193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut);
194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel)))); 194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel))));
195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); 195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
196 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel)))); 196 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel))));
197 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); 197 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
198 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat)); 198 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat));
199 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat); 199 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat);
200 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat)); 200 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat));
201 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat); 201 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat);
202 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting?"1":"0"))) > 0; 202 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting ? "1" : "0"))) > 0;
203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); 203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
204 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting)))); 204 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting))));
205 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); 205 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
206 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone)); 206 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone));
207 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone); 207 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone);
208 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay)))); 208 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay))));
209 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay); 209 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay);
210 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay)))); 210 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay))));
211 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay); 211 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay);
212 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword)); 212 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
213 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword); 213 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
@@ -217,7 +217,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
217 { 217 {
218 cs.ExcludeList.Add(name.Trim().ToLower()); 218 cs.ExcludeList.Add(name.Trim().ToLower());
219 } 219 }
220 220
221 // Fail if fundamental information is still missing 221 // Fail if fundamental information is still missing
222 222
223 if (cs.Server == null) 223 if (cs.Server == null)
@@ -306,8 +306,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
306 306
307 IRCBridgeModule.m_channels.Add(cs); 307 IRCBridgeModule.m_channels.Add(cs);
308 308
309 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}", 309 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}",
310 cs.idn, rs.Region, cs.DefaultZone, 310 cs.idn, rs.Region, cs.DefaultZone,
311 cs.CommandsEnabled ? "enabled" : "not enabled", 311 cs.CommandsEnabled ? "enabled" : "not enabled",
312 cs.RelayPrivateChannels ? "relayed" : "not relayed"); 312 cs.RelayPrivateChannels ? "relayed" : "not relayed");
313 } 313 }
@@ -417,7 +417,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
417 private bool IsAConnectionMatchFor(ChannelState cs) 417 private bool IsAConnectionMatchFor(ChannelState cs)
418 { 418 {
419 return ( 419 return (
420 Server == cs.Server && 420 Server == cs.Server &&
421 IrcChannel == cs.IrcChannel && 421 IrcChannel == cs.IrcChannel &&
422 Port == cs.Port && 422 Port == cs.Port &&
423 BaseNickname == cs.BaseNickname && 423 BaseNickname == cs.BaseNickname &&
@@ -473,27 +473,27 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
473 { 473 {
474 474
475 string vvar = arg.Match(result).ToString(); 475 string vvar = arg.Match(result).ToString();
476 string var = vvar.Substring(1,vvar.Length-2).Trim(); 476 string var = vvar.Substring(1, vvar.Length - 2).Trim();
477 477
478 switch (var.ToLower()) 478 switch (var.ToLower())
479 { 479 {
480 case "%region" : 480 case "%region":
481 result = result.Replace(vvar, rs.Region); 481 result = result.Replace(vvar, rs.Region);
482 break; 482 break;
483 case "%host" : 483 case "%host":
484 result = result.Replace(vvar, rs.Host); 484 result = result.Replace(vvar, rs.Host);
485 break; 485 break;
486 case "%locx" : 486 case "%locx":
487 result = result.Replace(vvar, rs.LocX); 487 result = result.Replace(vvar, rs.LocX);
488 break; 488 break;
489 case "%locy" : 489 case "%locy":
490 result = result.Replace(vvar, rs.LocY); 490 result = result.Replace(vvar, rs.LocY);
491 break; 491 break;
492 case "%k" : 492 case "%k":
493 result = result.Replace(vvar, rs.IDK); 493 result = result.Replace(vvar, rs.IDK);
494 break; 494 break;
495 default : 495 default:
496 result = result.Replace(vvar, rs.config.GetString(var,var)); 496 result = result.Replace(vvar, rs.config.GetString(var, var));
497 break; 497 break;
498 } 498 }
499 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result); 499 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result);
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
index 2e1d03d..351dbfe 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
@@ -46,18 +46,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
46 { 46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 internal static bool m_pluginEnabled = false; 49 internal static bool Enabled = false;
50 internal static IConfig m_config = null; 50 internal static IConfig m_config = null;
51 51
52 internal static List<ChannelState> m_channels = new List<ChannelState>(); 52 internal static List<ChannelState> m_channels = new List<ChannelState>();
53 internal static List<RegionState> m_regions = new List<RegionState>(); 53 internal static List<RegionState> m_regions = new List<RegionState>();
54 54
55 internal static string m_password = String.Empty; 55 internal static string m_password = String.Empty;
56 internal RegionState m_region = null; 56 internal RegionState m_region = null;
57 57
58 #region INonSharedRegionModule Members 58 #region INonSharedRegionModule Members
59 59
60 public Type ReplaceableInterface 60 public Type ReplaceableInterface
61 { 61 {
62 get { return null; } 62 get { return null; }
63 } 63 }
@@ -72,13 +72,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
72 m_config = config.Configs["IRC"]; 72 m_config = config.Configs["IRC"];
73 if (m_config == null) 73 if (m_config == null)
74 { 74 {
75// m_log.InfoFormat("[IRC-Bridge] module not configured"); 75 // m_log.InfoFormat("[IRC-Bridge] module not configured");
76 return; 76 return;
77 } 77 }
78 78
79 if (!m_config.GetBoolean("enabled", false)) 79 if (!m_config.GetBoolean("enabled", false))
80 { 80 {
81// m_log.InfoFormat("[IRC-Bridge] module disabled in configuration"); 81 // m_log.InfoFormat("[IRC-Bridge] module disabled in configuration");
82 return; 82 return;
83 } 83 }
84 84
@@ -87,19 +87,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
87 m_password = config.Configs["RemoteAdmin"].GetString("access_password", m_password); 87 m_password = config.Configs["RemoteAdmin"].GetString("access_password", m_password);
88 } 88 }
89 89
90 m_pluginEnabled = true; 90 Enabled = true;
91 m_log.InfoFormat("[IRC-Bridge]: Module enabled"); 91
92 m_log.InfoFormat("[IRC-Bridge]: Module is enabled");
92 } 93 }
93 94
94 public void AddRegion(Scene scene) 95 public void AddRegion(Scene scene)
95 { 96 {
96 if (m_pluginEnabled) 97 if (Enabled)
97 { 98 {
98 try 99 try
99 { 100 {
100 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName); 101 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName);
102
101 if (!String.IsNullOrEmpty(m_password)) 103 if (!String.IsNullOrEmpty(m_password))
102 MainServer.Instance.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false); 104 MainServer.Instance.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false);
105
103 m_region = new RegionState(scene, m_config); 106 m_region = new RegionState(scene, m_config);
104 lock (m_regions) m_regions.Add(m_region); 107 lock (m_regions) m_regions.Add(m_region);
105 m_region.Open(); 108 m_region.Open();
@@ -123,7 +126,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
123 126
124 public void RemoveRegion(Scene scene) 127 public void RemoveRegion(Scene scene)
125 { 128 {
126 if (!m_pluginEnabled) 129 if (!Enabled)
127 return; 130 return;
128 131
129 if (m_region == null) 132 if (m_region == null)
@@ -150,12 +153,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
150 m_log.Debug("[IRC-Bridge]: XML RPC Admin Entry"); 153 m_log.Debug("[IRC-Bridge]: XML RPC Admin Entry");
151 154
152 XmlRpcResponse response = new XmlRpcResponse(); 155 XmlRpcResponse response = new XmlRpcResponse();
153 Hashtable responseData = new Hashtable(); 156 Hashtable responseData = new Hashtable();
154 157
155 try 158 try
156 { 159 {
157 Hashtable requestData = (Hashtable)request.Params[0]; 160 Hashtable requestData = (Hashtable)request.Params[0];
158 bool found = false; 161 bool found = false;
159 string region = String.Empty; 162 string region = String.Empty;
160 163
161 if (m_password != String.Empty) 164 if (m_password != String.Empty)
@@ -169,18 +172,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
169 if (!requestData.ContainsKey("region")) 172 if (!requestData.ContainsKey("region"))
170 throw new Exception("No region name specified"); 173 throw new Exception("No region name specified");
171 region = (string)requestData["region"]; 174 region = (string)requestData["region"];
172 175
173 foreach (RegionState rs in m_regions) 176 foreach (RegionState rs in m_regions)
174 { 177 {
175 if (rs.Region == region) 178 if (rs.Region == region)
176 { 179 {
177 responseData["server"] = rs.cs.Server; 180 responseData["server"] = rs.cs.Server;
178 responseData["port"] = (int)rs.cs.Port; 181 responseData["port"] = (int)rs.cs.Port;
179 responseData["user"] = rs.cs.User; 182 responseData["user"] = rs.cs.User;
180 responseData["channel"] = rs.cs.IrcChannel; 183 responseData["channel"] = rs.cs.IrcChannel;
181 responseData["enabled"] = rs.cs.irc.Enabled; 184 responseData["enabled"] = rs.cs.irc.Enabled;
182 responseData["connected"] = rs.cs.irc.Connected; 185 responseData["connected"] = rs.cs.irc.Connected;
183 responseData["nickname"] = rs.cs.irc.Nick; 186 responseData["nickname"] = rs.cs.irc.Nick;
184 found = true; 187 found = true;
185 break; 188 break;
186 } 189 }
@@ -195,7 +198,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
195 m_log.ErrorFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message); 198 m_log.ErrorFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message);
196 199
197 responseData["success"] = "false"; 200 responseData["success"] = "false";
198 responseData["error"] = e.Message; 201 responseData["error"] = e.Message;
199 } 202 }
200 finally 203 finally
201 { 204 {
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
index a014798..c5cba8e 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
@@ -53,16 +53,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
53 // Local constants 53 // Local constants
54 54
55 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 55 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
56 private static readonly char[] CS_SPACE = { ' ' }; 56 private static readonly char[] CS_SPACE = { ' ' };
57 57
58 private const int WD_INTERVAL = 1000; // base watchdog interval 58 private const int WD_INTERVAL = 1000; // base watchdog interval
59 private static int PING_PERIOD = 15; // WD intervals per PING 59 private static int PING_PERIOD = 15; // WD intervals per PING
60 private static int ICCD_PERIOD = 10; // WD intervals between Connects 60 private static int ICCD_PERIOD = 10; // WD intervals between Connects
61 private static int L_TIMEOUT = 25; // Login time out interval 61 private static int L_TIMEOUT = 25; // Login time out interval
62 62
63 private static int _idk_ = 0; // core connector identifier 63 private static int _idk_ = 0; // core connector identifier
64 private static int _pdk_ = 0; // ping interval counter 64 private static int _pdk_ = 0; // ping interval counter
65 private static int _icc_ = ICCD_PERIOD; // IRC connect counter 65 private static int _icc_ = ICCD_PERIOD; // IRC connect counter
66 66
67 // List of configured connectors 67 // List of configured connectors
68 68
@@ -113,7 +113,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
113 113
114 private Object msyncConnect = new Object(); 114 private Object msyncConnect = new Object();
115 115
116 internal bool m_randomizeNick = true; // add random suffix 116 internal bool m_randomizeNick = true; // add random suffix
117 internal string m_baseNick = null; // base name for randomizing 117 internal string m_baseNick = null; // base name for randomizing
118 internal string m_nick = null; // effective nickname 118 internal string m_nick = null; // effective nickname
119 119
@@ -122,7 +122,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
122 get { return m_nick; } 122 get { return m_nick; }
123 set { m_nick = value; } 123 set { m_nick = value; }
124 } 124 }
125 125
126 private bool m_enabled = false; // connector enablement 126 private bool m_enabled = false; // connector enablement
127 public bool Enabled 127 public bool Enabled
128 { 128 {
@@ -130,8 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
130 } 130 }
131 131
132 private bool m_connected = false; // connection status 132 private bool m_connected = false; // connection status
133 private bool m_pending = false; // login disposition 133 private bool m_pending = false; // login disposition
134 private int m_timeout = L_TIMEOUT; // login timeout counter 134 private int m_timeout = L_TIMEOUT; // login timeout counter
135 public bool Connected 135 public bool Connected
136 { 136 {
137 get { return m_connected; } 137 get { return m_connected; }
@@ -143,9 +143,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
143 get { return m_ircChannel; } 143 get { return m_ircChannel; }
144 set { m_ircChannel = value; } 144 set { m_ircChannel = value; }
145 } 145 }
146 146
147 private uint m_port = 6667; // session port 147 private uint m_port = 6667; // session port
148 public uint Port 148 public uint Port
149 { 149 {
150 get { return m_port; } 150 get { return m_port; }
151 set { m_port = value; } 151 set { m_port = value; }
@@ -172,10 +172,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
172 172
173 // Network interface 173 // Network interface
174 174
175 private TcpClient m_tcp; 175 private TcpClient m_tcp;
176 private NetworkStream m_stream = null; 176 private NetworkStream m_stream = null;
177 private StreamReader m_reader; 177 private StreamReader m_reader;
178 private StreamWriter m_writer; 178 private StreamWriter m_writer;
179 179
180 // Channel characteristic info (if available) 180 // Channel characteristic info (if available)
181 181
@@ -193,26 +193,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
193 193
194 // Prepare network interface 194 // Prepare network interface
195 195
196 m_tcp = null; 196 m_tcp = null;
197 m_writer = null; 197 m_writer = null;
198 m_reader = null; 198 m_reader = null;
199 199
200 // Setup IRC session parameters 200 // Setup IRC session parameters
201 201
202 m_server = cs.Server; 202 m_server = cs.Server;
203 m_password = cs.Password; 203 m_password = cs.Password;
204 m_baseNick = cs.BaseNickname; 204 m_baseNick = cs.BaseNickname;
205 m_randomizeNick = cs.RandomizeNickname; 205 m_randomizeNick = cs.RandomizeNickname;
206 m_ircChannel = cs.IrcChannel; 206 m_ircChannel = cs.IrcChannel;
207 m_port = cs.Port; 207 m_port = cs.Port;
208 m_user = cs.User; 208 m_user = cs.User;
209 209
210 if (m_watchdog == null) 210 if (m_watchdog == null)
211 { 211 {
212 // Non-differentiating 212 // Non-differentiating
213 213
214 ICCD_PERIOD = cs.ConnectDelay; 214 ICCD_PERIOD = cs.ConnectDelay;
215 PING_PERIOD = cs.PingDelay; 215 PING_PERIOD = cs.PingDelay;
216 216
217 // Smaller values are not reasonable 217 // Smaller values are not reasonable
218 218
@@ -235,7 +235,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
235 235
236 if (m_randomizeNick) 236 if (m_randomizeNick)
237 m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 237 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
238 else 238 else
239 m_nick = m_baseNick; 239 m_nick = m_baseNick;
240 240
241 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn); 241 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);
@@ -295,18 +295,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
295 m_nick, m_ircChannel, m_server)); 295 m_nick, m_ircChannel, m_server));
296 m_writer.Flush(); 296 m_writer.Flush();
297 } 297 }
298 catch (Exception) {} 298 catch (Exception) { }
299 299
300 300
301 m_connected = false; 301 m_connected = false;
302 302
303 try { m_writer.Close(); } catch (Exception) {} 303 try { m_writer.Close(); }
304 try { m_reader.Close(); } catch (Exception) {} 304 catch (Exception) { }
305 try { m_stream.Close(); } catch (Exception) {} 305 try { m_reader.Close(); }
306 try { m_tcp.Close(); } catch (Exception) {} 306 catch (Exception) { }
307 try { m_stream.Close(); }
308 catch (Exception) { }
309 try { m_tcp.Close(); }
310 catch (Exception) { }
307 311
308 } 312 }
309 313
310 lock (m_connectors) 314 lock (m_connectors)
311 m_connectors.Remove(this); 315 m_connectors.Remove(this);
312 316
@@ -347,15 +351,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
347 if (m_connected) return; 351 if (m_connected) return;
348 352
349 m_connected = true; 353 m_connected = true;
350 m_pending = true; 354 m_pending = true;
351 m_timeout = L_TIMEOUT; 355 m_timeout = L_TIMEOUT;
352 356
353 m_tcp = new TcpClient(m_server, (int)m_port); 357 m_tcp = new TcpClient(m_server, (int)m_port);
354 m_stream = m_tcp.GetStream(); 358 m_stream = m_tcp.GetStream();
355 m_reader = new StreamReader(m_stream); 359 m_reader = new StreamReader(m_stream);
356 m_writer = new StreamWriter(m_stream); 360 m_writer = new StreamWriter(m_stream);
357 361
358 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port); 362 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port);
359 363
360 m_listener = new Thread(new ThreadStart(ListenerRun)); 364 m_listener = new Thread(new ThreadStart(ListenerRun));
361 m_listener.Name = "IRCConnectorListenerThread"; 365 m_listener.Name = "IRCConnectorListenerThread";
@@ -418,12 +422,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
418 // the socket and it will disappear of its own accord, once this 422 // the socket and it will disappear of its own accord, once this
419 // processing is completed. 423 // processing is completed.
420 424
421 try { m_writer.Close(); } catch (Exception) {} 425 try { m_writer.Close(); }
422 try { m_reader.Close(); } catch (Exception) {} 426 catch (Exception) { }
423 try { m_tcp.Close(); } catch (Exception) {} 427 try { m_reader.Close(); }
428 catch (Exception) { }
429 try { m_tcp.Close(); }
430 catch (Exception) { }
424 431
425 m_connected = false; 432 m_connected = false;
426 m_pending = false; 433 m_pending = false;
427 m_resetk++; 434 m_resetk++;
428 435
429 } 436 }
@@ -495,7 +502,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
495 { 502 {
496 503
497 string inputLine; 504 string inputLine;
498 int resetk = m_resetk; 505 int resetk = m_resetk;
499 506
500 try 507 try
501 { 508 {
@@ -555,7 +562,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
555 Reconnect(); 562 Reconnect();
556 } 563 }
557 564
558 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)", 565 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)",
559 RegexOptions.Multiline); 566 RegexOptions.Multiline);
560 567
561 private Dictionary<string, string> ExtractMsg(string input) 568 private Dictionary<string, string> ExtractMsg(string input)
@@ -617,8 +624,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
617 string[] commArgs; 624 string[] commArgs;
618 string c_server = m_server; 625 string c_server = m_server;
619 626
620 string pfx = String.Empty; 627 string pfx = String.Empty;
621 string cmd = String.Empty; 628 string cmd = String.Empty;
622 string parms = String.Empty; 629 string parms = String.Empty;
623 630
624 // ":" indicates that a prefix is present 631 // ":" indicates that a prefix is present
@@ -627,15 +634,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
627 // ":" indicates that the remainder of the 634 // ":" indicates that the remainder of the
628 // line is a single parameter value. 635 // line is a single parameter value.
629 636
630 commArgs = command.Split(CS_SPACE,2); 637 commArgs = command.Split(CS_SPACE, 2);
631 638
632 if (commArgs[0].StartsWith(":")) 639 if (commArgs[0].StartsWith(":"))
633 { 640 {
634 pfx = commArgs[0].Substring(1); 641 pfx = commArgs[0].Substring(1);
635 commArgs = commArgs[1].Split(CS_SPACE,2); 642 commArgs = commArgs[1].Split(CS_SPACE, 2);
636 } 643 }
637 644
638 cmd = commArgs[0]; 645 cmd = commArgs[0];
639 parms = commArgs[1]; 646 parms = commArgs[1];
640 647
641 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd); 648 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd);
@@ -646,44 +653,44 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
646 // Messages 001-004 are always sent 653 // Messages 001-004 are always sent
647 // following signon. 654 // following signon.
648 655
649 case "001" : // Welcome ... 656 case "001": // Welcome ...
650 case "002" : // Server information 657 case "002": // Server information
651 case "003" : // Welcome ... 658 case "003": // Welcome ...
652 break; 659 break;
653 case "004" : // Server information 660 case "004": // Server information
654 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 661 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
655 commArgs = parms.Split(CS_SPACE); 662 commArgs = parms.Split(CS_SPACE);
656 c_server = commArgs[1]; 663 c_server = commArgs[1];
657 m_server = c_server; 664 m_server = c_server;
658 version = commArgs[2]; 665 version = commArgs[2];
659 usermod = commArgs[3]; 666 usermod = commArgs[3];
660 chanmod = commArgs[4]; 667 chanmod = commArgs[4];
661 break; 668 break;
662 case "005" : // Server information 669 case "005": // Server information
663 break; 670 break;
664 case "042" : 671 case "042":
665 case "250" : 672 case "250":
666 case "251" : 673 case "251":
667 case "252" : 674 case "252":
668 case "254" : 675 case "254":
669 case "255" : 676 case "255":
670 case "265" : 677 case "265":
671 case "266" : 678 case "266":
672 case "332" : // Subject 679 case "332": // Subject
673 case "333" : // Subject owner (?) 680 case "333": // Subject owner (?)
674 case "353" : // Name list 681 case "353": // Name list
675 case "366" : // End-of-Name list marker 682 case "366": // End-of-Name list marker
676 case "372" : // MOTD body 683 case "372": // MOTD body
677 case "375" : // MOTD start 684 case "375": // MOTD start
678 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 685 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
679 break; 686 break;
680 case "376" : // MOTD end 687 case "376": // MOTD end
681 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 688 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
682 motd = true; 689 motd = true;
683 break; 690 break;
684 case "451" : // Not registered 691 case "451": // Not registered
685 break; 692 break;
686 case "433" : // Nickname in use 693 case "433": // Nickname in use
687 // Gen a new name 694 // Gen a new name
688 m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 695 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
689 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick); 696 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick);
@@ -695,29 +702,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
695 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); 702 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
696 m_writer.Flush(); 703 m_writer.Flush();
697 break; 704 break;
698 case "479" : // Bad channel name, etc. This will never work, so disable the connection 705 case "479": // Bad channel name, etc. This will never work, so disable the connection
699 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 706 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]);
700 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd); 707 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd);
701 m_enabled = false; 708 m_enabled = false;
702 m_connected = false; 709 m_connected = false;
703 m_pending = false; 710 m_pending = false;
704 break; 711 break;
705 case "NOTICE" : 712 case "NOTICE":
706 // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 713 // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
707 break; 714 break;
708 case "ERROR" : 715 case "ERROR":
709 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 716 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]);
710 if (parms.Contains("reconnect too fast")) 717 if (parms.Contains("reconnect too fast"))
711 ICCD_PERIOD++; 718 ICCD_PERIOD++;
712 m_pending = false; 719 m_pending = false;
713 Reconnect(); 720 Reconnect();
714 break; 721 break;
715 case "PING" : 722 case "PING":
716 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 723 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
717 m_writer.WriteLine(String.Format("PONG {0}", parms)); 724 m_writer.WriteLine(String.Format("PONG {0}", parms));
718 m_writer.Flush(); 725 m_writer.Flush();
719 break; 726 break;
720 case "PONG" : 727 case "PONG":
721 break; 728 break;
722 case "JOIN": 729 case "JOIN":
723 if (m_pending) 730 if (m_pending)
@@ -748,19 +755,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
748 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 755 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
749 eventIrcQuit(pfx, cmd, parms); 756 eventIrcQuit(pfx, cmd, parms);
750 break; 757 break;
751 default : 758 default:
752 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms); 759 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms);
753 break; 760 break;
754 } 761 }
755 762
756 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd); 763 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd);
757 764
758 } 765 }
759 766
760 public void eventIrcJoin(string prefix, string command, string parms) 767 public void eventIrcJoin(string prefix, string command, string parms)
761 { 768 {
762 string[] args = parms.Split(CS_SPACE,2); 769 string[] args = parms.Split(CS_SPACE, 2);
763 string IrcUser = prefix.Split('!')[0]; 770 string IrcUser = prefix.Split('!')[0];
764 string IrcChannel = args[0]; 771 string IrcChannel = args[0];
765 772
766 if (IrcChannel.StartsWith(":")) 773 if (IrcChannel.StartsWith(":"))
@@ -772,8 +779,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
772 779
773 public void eventIrcPart(string prefix, string command, string parms) 780 public void eventIrcPart(string prefix, string command, string parms)
774 { 781 {
775 string[] args = parms.Split(CS_SPACE,2); 782 string[] args = parms.Split(CS_SPACE, 2);
776 string IrcUser = prefix.Split('!')[0]; 783 string IrcUser = prefix.Split('!')[0];
777 string IrcChannel = args[0]; 784 string IrcChannel = args[0];
778 785
779 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel); 786 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel);
@@ -782,7 +789,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
782 789
783 public void eventIrcMode(string prefix, string command, string parms) 790 public void eventIrcMode(string prefix, string command, string parms)
784 { 791 {
785 string[] args = parms.Split(CS_SPACE,2); 792 string[] args = parms.Split(CS_SPACE, 2);
786 string UserMode = args[1]; 793 string UserMode = args[1];
787 794
788 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel); 795 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel);
@@ -794,7 +801,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
794 801
795 public void eventIrcNickChange(string prefix, string command, string parms) 802 public void eventIrcNickChange(string prefix, string command, string parms)
796 { 803 {
797 string[] args = parms.Split(CS_SPACE,2); 804 string[] args = parms.Split(CS_SPACE, 2);
798 string UserOldNick = prefix.Split('!')[0]; 805 string UserOldNick = prefix.Split('!')[0];
799 string UserNewNick = args[0].Remove(0, 1); 806 string UserNewNick = args[0].Remove(0, 1);
800 807
@@ -804,11 +811,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
804 811
805 public void eventIrcKick(string prefix, string command, string parms) 812 public void eventIrcKick(string prefix, string command, string parms)
806 { 813 {
807 string[] args = parms.Split(CS_SPACE,3); 814 string[] args = parms.Split(CS_SPACE, 3);
808 string UserKicker = prefix.Split('!')[0]; 815 string UserKicker = prefix.Split('!')[0];
809 string IrcChannel = args[0]; 816 string IrcChannel = args[0];
810 string UserKicked = args[1]; 817 string UserKicked = args[1];
811 string KickMessage = args[2]; 818 string KickMessage = args[2];
812 819
813 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel); 820 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel);
814 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage); 821 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
@@ -822,7 +829,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
822 829
823 public void eventIrcQuit(string prefix, string command, string parms) 830 public void eventIrcQuit(string prefix, string command, string parms)
824 { 831 {
825 string IrcUser = prefix.Split('!')[0]; 832 string IrcUser = prefix.Split('!')[0];
826 string QuitMessage = parms; 833 string QuitMessage = parms;
827 834
828 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel); 835 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel);
@@ -842,65 +849,65 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
842 849
843 // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_); 850 // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_);
844 851
845 _pdk_ = (_pdk_+1)%PING_PERIOD; // cycle the ping trigger 852 _pdk_ = (_pdk_ + 1) % PING_PERIOD; // cycle the ping trigger
846 _icc_++; // increment the inter-consecutive-connect-delay counter 853 _icc_++; // increment the inter-consecutive-connect-delay counter
847 854
848 lock (m_connectors) 855 lock (m_connectors)
849 foreach (IRCConnector connector in m_connectors) 856 foreach (IRCConnector connector in m_connectors)
850 { 857 {
851 858
852 // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector); 859 // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector);
853 860
854 if (connector.Enabled) 861 if (connector.Enabled)
855 {
856 if (!connector.Connected)
857 { 862 {
858 try 863 if (!connector.Connected)
859 { 864 {
860 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel); 865 try
861 connector.Connect(); 866 {
867 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel);
868 connector.Connect();
869 }
870 catch (Exception e)
871 {
872 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
873 }
862 } 874 }
863 catch (Exception e) 875 else
864 { 876 {
865 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
866 }
867 }
868 else
869 {
870 877
871 if (connector.m_pending) 878 if (connector.m_pending)
872 {
873 if (connector.m_timeout == 0)
874 { 879 {
875 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn); 880 if (connector.m_timeout == 0)
876 connector.Reconnect(); 881 {
882 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn);
883 connector.Reconnect();
884 }
885 else
886 connector.m_timeout--;
877 } 887 }
878 else
879 connector.m_timeout--;
880 }
881 888
882 // Being marked connected is not enough to ping. Socket establishment can sometimes take a long 889 // Being marked connected is not enough to ping. Socket establishment can sometimes take a long
883 // time, in which case the watch dog might try to ping the server before the socket has been 890 // time, in which case the watch dog might try to ping the server before the socket has been
884 // set up, with nasty side-effects. 891 // set up, with nasty side-effects.
885 892
886 else if (_pdk_ == 0) 893 else if (_pdk_ == 0)
887 {
888 try
889 {
890 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
891 connector.m_writer.Flush();
892 }
893 catch (Exception e)
894 { 894 {
895 m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message); 895 try
896 m_log.Debug(e); 896 {
897 connector.Reconnect(); 897 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
898 connector.m_writer.Flush();
899 }
900 catch (Exception e)
901 {
902 m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message);
903 m_log.Debug(e);
904 connector.Reconnect();
905 }
898 } 906 }
899 }
900 907
908 }
901 } 909 }
902 } 910 }
903 }
904 911
905 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed"); 912 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed");
906 913
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
index 53b103e..d4fe5e0 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
@@ -41,49 +41,71 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
41 41
42 internal class RegionState 42 internal class RegionState
43 { 43 {
44
45 private static readonly ILog m_log = 44 private static readonly ILog m_log =
46 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 46
48 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 47 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
49 private const int DEBUG_CHANNEL = 2147483647; 48 private const int DEBUG_CHANNEL = 2147483647;
50 49
51 private static int _idk_ = 0; 50 private static int _idk_ = 0;
52 51
53 // Runtime variables; these values are assigned when the 52 // Runtime variables; these values are assigned when the
54 // IrcState is created and remain constant thereafter. 53 // IrcState is created and remain constant thereafter.
55 54
56 internal string Region = String.Empty; 55 internal string Region = String.Empty;
57 internal string Host = String.Empty; 56 internal string Host = String.Empty;
58 internal string LocX = String.Empty; 57 internal string LocX = String.Empty;
59 internal string LocY = String.Empty; 58 internal string LocY = String.Empty;
60 internal string IDK = String.Empty; 59 internal string IDK = String.Empty;
61 60
62 // System values - used only be the IRC classes themselves 61 // System values - used only be the IRC classes themselves
63 62
64 internal ChannelState cs = null; // associated IRC configuration 63 internal ChannelState cs = null; // associated IRC configuration
65 internal Scene scene = null; // associated scene 64 internal Scene scene = null; // associated scene
66 internal IConfig config = null; // configuration file reference 65 internal IConfig config = null; // configuration file reference
67 internal bool enabled = true; 66 internal bool enabled = true;
68 67
68 //AgentAlert
69 internal bool showAlert = false;
70 internal string alertMessage = String.Empty;
71 internal IDialogModule dialogModule = null;
72
69 // This list is used to keep track of who is here, and by 73 // This list is used to keep track of who is here, and by
70 // implication, who is not. 74 // implication, who is not.
71 75
72 internal List<IClientAPI> clients = new List<IClientAPI>(); 76 internal List<IClientAPI> clients = new List<IClientAPI>();
73 77
74 // Setup runtime variable values 78 // Setup runtime variable values
75 79
76 public RegionState(Scene p_scene, IConfig p_config) 80 public RegionState(Scene p_scene, IConfig p_config)
77 { 81 {
78 82 scene = p_scene;
79 scene = p_scene;
80 config = p_config; 83 config = p_config;
81 84
82 Region = scene.RegionInfo.RegionName; 85 Region = scene.RegionInfo.RegionName;
83 Host = scene.RegionInfo.ExternalHostName; 86 Host = scene.RegionInfo.ExternalHostName;
84 LocX = Convert.ToString(scene.RegionInfo.RegionLocX); 87 LocX = Convert.ToString(scene.RegionInfo.RegionLocX);
85 LocY = Convert.ToString(scene.RegionInfo.RegionLocY); 88 LocY = Convert.ToString(scene.RegionInfo.RegionLocY);
86 IDK = Convert.ToString(_idk_++); 89 IDK = Convert.ToString(_idk_++);
90
91 showAlert = config.GetBoolean("alert_show", false);
92 string alertServerInfo = String.Empty;
93
94 if (showAlert)
95 {
96 bool showAlertServerInfo = config.GetBoolean("alert_show_serverinfo", true);
97
98 if (showAlertServerInfo)
99 alertServerInfo = String.Format("\nServer: {0}\nPort: {1}\nChannel: {2}\n\n",
100 config.GetString("server", ""), config.GetString("port", ""), config.GetString("channel", ""));
101
102 string alertPreMessage = config.GetString("alert_msg_pre", "This region is linked to Irc.");
103 string alertPostMessage = config.GetString("alert_msg_post", "Everything you say in public chat can be listened.");
104
105 alertMessage = String.Format("{0}\n{1}{2}", alertPreMessage, alertServerInfo, alertPostMessage);
106
107 dialogModule = scene.RequestModuleInterface<IDialogModule>();
108 }
87 109
88 // OpenChannel conditionally establishes a connection to the 110 // OpenChannel conditionally establishes a connection to the
89 // IRC server. The request will either succeed, or it will 111 // IRC server. The request will either succeed, or it will
@@ -93,9 +115,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
93 115
94 // Connect channel to world events 116 // Connect channel to world events
95 117
96 scene.EventManager.OnChatFromWorld += OnSimChat; 118 scene.EventManager.OnChatFromWorld += OnSimChat;
97 scene.EventManager.OnChatFromClient += OnSimChat; 119 scene.EventManager.OnChatFromClient += OnSimChat;
98 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; 120 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
99 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; 121 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
100 122
101 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region); 123 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region);
@@ -106,8 +128,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
106 128
107 ~RegionState() 129 ~RegionState()
108 { 130 {
109 if (cs != null) 131 if (cs != null)
110 cs.RemoveRegion(this); 132 cs.RemoveRegion(this);
111 } 133 }
112 134
113 // Called by PostInitialize after all regions have been created 135 // Called by PostInitialize after all regions have been created
@@ -138,7 +160,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
138 { 160 {
139 if (clients.Contains(client)) 161 if (clients.Contains(client))
140 { 162 {
141 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 163 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
142 { 164 {
143 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name); 165 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name);
144 //Check if this person is excluded from IRC 166 //Check if this person is excluded from IRC
@@ -147,7 +169,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
147 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name)); 169 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name));
148 } 170 }
149 } 171 }
150 client.OnLogout -= OnClientLoggedOut; 172 client.OnLogout -= OnClientLoggedOut;
151 client.OnConnectionClosed -= OnClientLoggedOut; 173 client.OnConnectionClosed -= OnClientLoggedOut;
152 clients.Remove(client); 174 clients.Remove(client);
153 } 175 }
@@ -171,13 +193,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
171 { 193 {
172 if (clients.Contains(client)) 194 if (clients.Contains(client))
173 { 195 {
174 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 196 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
175 { 197 {
176 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); 198 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
177 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName); 199 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName);
178 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName)); 200 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName));
179 } 201 }
180 client.OnLogout -= OnClientLoggedOut; 202 client.OnLogout -= OnClientLoggedOut;
181 client.OnConnectionClosed -= OnClientLoggedOut; 203 client.OnConnectionClosed -= OnClientLoggedOut;
182 clients.Remove(client); 204 clients.Remove(client);
183 } 205 }
@@ -195,14 +217,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
195 217
196 private void OnMakeRootAgent(ScenePresence presence) 218 private void OnMakeRootAgent(ScenePresence presence)
197 { 219 {
198
199 IClientAPI client = presence.ControllingClient; 220 IClientAPI client = presence.ControllingClient;
200 221
201 try 222 try
202 { 223 {
203 if (!clients.Contains(client)) 224 if (!clients.Contains(client))
204 { 225 {
205 client.OnLogout += OnClientLoggedOut; 226 client.OnLogout += OnClientLoggedOut;
206 client.OnConnectionClosed += OnClientLoggedOut; 227 client.OnConnectionClosed += OnClientLoggedOut;
207 clients.Add(client); 228 clients.Add(client);
208 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 229 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
@@ -216,17 +237,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
216 } 237 }
217 } 238 }
218 } 239 }
240
241 if (dialogModule != null && showAlert)
242 dialogModule.SendAlertToUser(client, alertMessage, true);
219 } 243 }
220 catch (Exception ex) 244 catch (Exception ex)
221 { 245 {
222 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message); 246 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message);
223 m_log.Debug(ex); 247 m_log.Debug(ex);
224 } 248 }
225
226 } 249 }
227 250
228 // This handler detects chat events int he virtual world. 251 // This handler detects chat events int he virtual world.
229
230 public void OnSimChat(Object sender, OSChatMessage msg) 252 public void OnSimChat(Object sender, OSChatMessage msg)
231 { 253 {
232 254
@@ -317,14 +339,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
317 // that evident. 339 // that evident.
318 340
319 default: 341 default:
320 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}", 342 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}",
321 Region, msg.Message); 343 Region, msg.Message);
322 cs.irc.Send(msg.Message); 344 cs.irc.Send(msg.Message);
323 break; 345 break;
324 } 346 }
325 } 347 }
326 catch (Exception ex) 348 catch (Exception ex)
327 { 349 {
328 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}", 350 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}",
329 Region, ex.Message); 351 Region, ex.Message);
330 m_log.Debug(ex); 352 m_log.Debug(ex);
@@ -366,7 +388,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
366 388
367 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message); 389 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);
368 390
369 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL)) 391 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL))
370 { 392 {
371 string txt = msg.Message; 393 string txt = msg.Message;
372 if (txt.StartsWith("/me ")) 394 if (txt.StartsWith("/me "))
@@ -376,13 +398,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
376 return; 398 return;
377 } 399 }
378 400
379 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword && 401 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword &&
380 msg.Channel == cs.RelayChannelOut) 402 msg.Channel == cs.RelayChannelOut)
381 { 403 {
382 Match m = cs.AccessPasswordRegex.Match(msg.Message); 404 Match m = cs.AccessPasswordRegex.Match(msg.Message);
383 if (null != m) 405 if (null != m)
384 { 406 {
385 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(), 407 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(),
386 m.Groups["message"].ToString()); 408 m.Groups["message"].ToString());
387 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(), 409 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(),
388 scene.RegionInfo.RegionName, m.Groups["message"].ToString()); 410 scene.RegionInfo.RegionName, m.Groups["message"].ToString());
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs
deleted file mode 100644
index d91c47f..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs
+++ /dev/null
@@ -1,814 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using log4net;
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37public sealed class BSCharacter : BSPhysObject
38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]";
41
42 // private bool _stopped;
43 private OMV.Vector3 _size;
44 private bool _grabbed;
45 private bool _selected;
46 private OMV.Vector3 _position;
47 private float _mass;
48 private float _avatarDensity;
49 private float _avatarVolume;
50 private OMV.Vector3 _force;
51 private OMV.Vector3 _velocity;
52 private OMV.Vector3 _torque;
53 private float _collisionScore;
54 private OMV.Vector3 _acceleration;
55 private OMV.Quaternion _orientation;
56 private int _physicsActorType;
57 private bool _isPhysical;
58 private bool _flying;
59 private bool _setAlwaysRun;
60 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic;
66 private float _buoyancy;
67
68 // The friction and velocity of the avatar is modified depending on whether walking or not.
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71
72 private BSVMotor _velocityMotor;
73
74 private OMV.Vector3 _PIDTarget;
75 private bool _usePID;
76 private float _PIDTau;
77 private bool _useHoverPID;
78 private float _PIDHoverHeight;
79 private PIDHoverType _PIDHoverType;
80 private float _PIDHoverTao;
81
82 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
83 : base(parent_scene, localID, avName, "BSCharacter")
84 {
85 _physicsActorType = (int)ActorTypes.Agent;
86 _position = pos;
87
88 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
89 // replace with the default values.
90 _size = size;
91 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
92 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
93
94 // A motor to control the acceleration and deceleration of the avatar movement.
95 // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
96 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
97 // Infinite decay and timescale values so motor only changes current to target values.
98 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
99 0.2f, // time scale
100 BSMotor.Infinite, // decay time scale
101 BSMotor.InfiniteVector, // friction timescale
102 1f // efficiency
103 );
104 _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
105
106 _flying = isFlying;
107 _orientation = OMV.Quaternion.Identity;
108 _velocity = OMV.Vector3.Zero;
109 _appliedVelocity = OMV.Vector3.Zero;
110 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
111 _currentFriction = BSParam.AvatarStandingFriction;
112 _avatarDensity = BSParam.AvatarDensity;
113
114 // The dimensions of the avatar capsule are kept in the scale.
115 // Physics creates a unit capsule which is scaled by the physics engine.
116 ComputeAvatarScale(_size);
117 // set _avatarVolume and _mass based on capsule size, _density and Scale
118 ComputeAvatarVolumeAndMass();
119 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
120 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
121
122 // do actual creation in taint time
123 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
124 {
125 DetailLog("{0},BSCharacter.create,taint", LocalID);
126 // New body and shape into PhysBody and PhysShape
127 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
128
129 SetPhysicalProperties();
130 });
131 return;
132 }
133
134 // called when this character is being destroyed and the resources should be released
135 public override void Destroy()
136 {
137 base.Destroy();
138
139 DetailLog("{0},BSCharacter.Destroy", LocalID);
140 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
141 {
142 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
143 PhysBody.Clear();
144 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
145 PhysShape.Clear();
146 });
147 }
148
149 private void SetPhysicalProperties()
150 {
151 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
152
153 ZeroMotion(true);
154 ForcePosition = _position;
155 // Set the velocity and compute the proper friction
156 ForceVelocity = _velocity;
157 // Setting the current and target in the motor will cause it to start computing any deceleration.
158 _velocityMotor.Reset();
159 _velocityMotor.SetCurrent(_velocity);
160 _velocityMotor.SetTarget(_velocity);
161 _velocityMotor.Enabled = false;
162
163 // This will enable or disable the flying buoyancy of the avatar.
164 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
165 Flying = _flying;
166
167 BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution);
168 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
169 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
170 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
171 if (BSParam.CcdMotionThreshold > 0f)
172 {
173 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
174 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
175 }
176
177 UpdatePhysicalMassProperties(RawMass, false);
178
179 // Make so capsule does not fall over
180 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero);
181
182 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
183
184 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation);
185
186 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
187 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION);
188 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
189
190 // Do this after the object has been added to the world
191 PhysBody.collisionType = CollisionType.Avatar;
192 PhysBody.ApplyCollisionMask();
193 }
194
195 public override void RequestPhysicsterseUpdate()
196 {
197 base.RequestPhysicsterseUpdate();
198 }
199 // No one calls this method so I don't know what it could possibly mean
200 public override bool Stopped { get { return false; } }
201
202 public override OMV.Vector3 Size {
203 get
204 {
205 // Avatar capsule size is kept in the scale parameter.
206 return _size;
207 }
208
209 set {
210 // When an avatar's size is set, only the height is changed.
211 _size = value;
212 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
213 // replace with the default values.
214 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
215 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
216
217 ComputeAvatarScale(_size);
218 ComputeAvatarVolumeAndMass();
219 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
220 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
221
222 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
223 {
224 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
225 {
226 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
227 UpdatePhysicalMassProperties(RawMass, true);
228 // Make sure this change appears as a property update event
229 BulletSimAPI.PushUpdate2(PhysBody.ptr);
230 }
231 });
232
233 }
234 }
235
236 public override PrimitiveBaseShape Shape
237 {
238 set { BaseShape = value; }
239 }
240 // I want the physics engine to make an avatar capsule
241 public override BSPhysicsShapeType PreferredPhysicalShape
242 {
243 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
244 }
245
246 public override bool Grabbed {
247 set { _grabbed = value; }
248 }
249 public override bool Selected {
250 set { _selected = value; }
251 }
252 public override void CrossingFailure() { return; }
253 public override void link(PhysicsActor obj) { return; }
254 public override void delink() { return; }
255
256 // Set motion values to zero.
257 // Do it to the properties so the values get set in the physics engine.
258 // Push the setting of the values to the viewer.
259 // Called at taint time!
260 public override void ZeroMotion(bool inTaintTime)
261 {
262 _velocity = OMV.Vector3.Zero;
263 _acceleration = OMV.Vector3.Zero;
264 _rotationalVelocity = OMV.Vector3.Zero;
265
266 // Zero some other properties directly into the physics engine
267 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
268 {
269 if (PhysBody.HasPhysicalBody)
270 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
271 });
272 }
273 public override void ZeroAngularMotion(bool inTaintTime)
274 {
275 _rotationalVelocity = OMV.Vector3.Zero;
276
277 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
278 {
279 if (PhysBody.HasPhysicalBody)
280 {
281 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
282 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
283 // The next also get rid of applied linear force but the linear velocity is untouched.
284 BulletSimAPI.ClearForces2(PhysBody.ptr);
285 }
286 });
287 }
288
289
290 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
291
292 public override OMV.Vector3 RawPosition
293 {
294 get { return _position; }
295 set { _position = value; }
296 }
297 public override OMV.Vector3 Position {
298 get {
299 // Don't refetch the position because this function is called a zillion times
300 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
301 return _position;
302 }
303 set {
304 _position = value;
305 PositionSanityCheck();
306
307 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
308 {
309 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
310 if (PhysBody.HasPhysicalBody)
311 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
312 });
313 }
314 }
315 public override OMV.Vector3 ForcePosition {
316 get {
317 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
318 return _position;
319 }
320 set {
321 _position = value;
322 PositionSanityCheck();
323 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
324 }
325 }
326
327
328 // Check that the current position is sane and, if not, modify the position to make it so.
329 // Check for being below terrain or on water.
330 // Returns 'true' of the position was made sane by some action.
331 private bool PositionSanityCheck()
332 {
333 bool ret = false;
334
335 // TODO: check for out of bounds
336 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
337 {
338 // The character is out of the known/simulated area.
339 // Upper levels of code will handle the transition to other areas so, for
340 // the time, we just ignore the position.
341 return ret;
342 }
343
344 // If below the ground, move the avatar up
345 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
346 if (Position.Z < terrainHeight)
347 {
348 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
349 _position.Z = terrainHeight + 2.0f;
350 ret = true;
351 }
352 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
353 {
354 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
355 if (Position.Z < waterHeight)
356 {
357 _position.Z = waterHeight;
358 ret = true;
359 }
360 }
361
362 return ret;
363 }
364
365 // A version of the sanity check that also makes sure a new position value is
366 // pushed back to the physics engine. This routine would be used by anyone
367 // who is not already pushing the value.
368 private bool PositionSanityCheck(bool inTaintTime)
369 {
370 bool ret = false;
371 if (PositionSanityCheck())
372 {
373 // The new position value must be pushed into the physics engine but we can't
374 // just assign to "Position" because of potential call loops.
375 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
376 {
377 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
378 if (PhysBody.HasPhysicalBody)
379 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
380 });
381 ret = true;
382 }
383 return ret;
384 }
385
386 public override float Mass { get { return _mass; } }
387
388 // used when we only want this prim's mass and not the linkset thing
389 public override float RawMass {
390 get {return _mass; }
391 }
392 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
393 {
394 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
395 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
396 }
397
398 public override OMV.Vector3 Force {
399 get { return _force; }
400 set {
401 _force = value;
402 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
403 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
404 {
405 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
406 if (PhysBody.HasPhysicalBody)
407 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
408 });
409 }
410 }
411
412 public bool TouchingGround()
413 {
414 bool ret = BulletSimAPI.RayCastGround(PhysicsScene.World.ptr,_position,_size.Z * 0.55f, PhysBody.ptr);
415 return ret;
416 }
417 // Avatars don't do vehicles
418 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
419 public override void VehicleFloatParam(int param, float value) { }
420 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
421 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
422 public override void VehicleFlags(int param, bool remove) { }
423
424 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
425 public override void SetVolumeDetect(int param) { return; }
426
427 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
428 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
429
430 // Sets the target in the motor. This starts the changing of the avatar's velocity.
431 public override OMV.Vector3 TargetVelocity
432 {
433 get
434 {
435 return _velocityMotor.TargetValue;
436 }
437 set
438 {
439 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
440
441 if (!_flying)
442 if ((value.Z >= 0.0001f) || (value.Z <= -0.0001f) || _velocity.Z < -0.0001f)
443 if (!TouchingGround())
444 value.Z = _velocity.Z;
445 if (_setAlwaysRun)
446 value *= 1.3f;
447
448 OMV.Vector3 targetVel = value;
449
450 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
451 {
452
453 _velocityMotor.Reset();
454 _velocityMotor.SetTarget(targetVel);
455 _velocityMotor.SetCurrent(_velocity);
456 _velocityMotor.Enabled = true;
457
458 // Make sure a property update happens next step so the motor gets incorporated.
459 BulletSimAPI.PushUpdate2(PhysBody.ptr);
460 });
461 }
462 }
463 // Directly setting velocity means this is what the user really wants now.
464 public override OMV.Vector3 Velocity {
465 get { return _velocity; }
466 set {
467 _velocity = value;
468 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
469 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
470 {
471 _velocityMotor.Reset();
472 _velocityMotor.SetCurrent(_velocity);
473 _velocityMotor.SetTarget(_velocity);
474 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
475 _velocityMotor.Enabled = false;
476
477 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
478 ForceVelocity = _velocity;
479 });
480 }
481 }
482 public override OMV.Vector3 ForceVelocity {
483 get { return _velocity; }
484 set {
485 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
486
487 _velocity = value;
488 // Depending on whether the avatar is moving or not, change the friction
489 // to keep the avatar from slipping around
490 if (_velocity.Length() == 0)
491 {
492 if (_currentFriction != BSParam.AvatarStandingFriction)
493 {
494 _currentFriction = BSParam.AvatarStandingFriction;
495 if (PhysBody.HasPhysicalBody)
496 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
497 }
498 }
499 else
500 {
501 if (_currentFriction != BSParam.AvatarFriction)
502 {
503 _currentFriction = BSParam.AvatarFriction;
504 if (PhysBody.HasPhysicalBody)
505 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
506 }
507 }
508 // Remember the set velocity so we can suppress the reduction by friction, ...
509 _appliedVelocity = value;
510
511 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
512 BulletSimAPI.Activate2(PhysBody.ptr, true);
513 }
514 }
515 public override OMV.Vector3 Torque {
516 get { return _torque; }
517 set { _torque = value;
518 }
519 }
520 public override float CollisionScore {
521 get { return _collisionScore; }
522 set { _collisionScore = value;
523 }
524 }
525 public override OMV.Vector3 Acceleration {
526 get { return _acceleration; }
527 set { _acceleration = value; }
528 }
529 public override OMV.Quaternion RawOrientation
530 {
531 get { return _orientation; }
532 set { _orientation = value; }
533 }
534 public override OMV.Quaternion Orientation {
535 get { return _orientation; }
536 set {
537 _orientation = value;
538 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
539 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
540 {
541 if (PhysBody.HasPhysicalBody)
542 {
543 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
544 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
545 }
546 });
547 }
548 }
549 // Go directly to Bullet to get/set the value.
550 public override OMV.Quaternion ForceOrientation
551 {
552 get
553 {
554 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
555 return _orientation;
556 }
557 set
558 {
559 _orientation = value;
560 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
561 }
562 }
563 public override int PhysicsActorType {
564 get { return _physicsActorType; }
565 set { _physicsActorType = value;
566 }
567 }
568 public override bool IsPhysical {
569 get { return _isPhysical; }
570 set { _isPhysical = value;
571 }
572 }
573 public override bool IsSolid {
574 get { return true; }
575 }
576 public override bool IsStatic {
577 get { return false; }
578 }
579 public override bool Flying {
580 get { return _flying; }
581 set {
582 _flying = value;
583
584 // simulate flying by changing the effect of gravity
585 Buoyancy = ComputeBuoyancyFromFlying(_flying);
586 }
587 }
588 // Flying is implimented by changing the avatar's buoyancy.
589 // Would this be done better with a vehicle type?
590 private float ComputeBuoyancyFromFlying(bool ifFlying) {
591 return ifFlying ? 1f : 0f;
592 }
593 public override bool
594 SetAlwaysRun {
595 get { return _setAlwaysRun; }
596 set { _setAlwaysRun = value; }
597 }
598 public override bool ThrottleUpdates {
599 get { return _throttleUpdates; }
600 set { _throttleUpdates = value; }
601 }
602 public override bool IsColliding {
603 get { return (CollidingStep == PhysicsScene.SimulationStep); }
604 set { _isColliding = value; }
605 }
606 public override bool CollidingGround {
607 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
608 set { CollidingGround = value; }
609 }
610 public override bool CollidingObj {
611 get { return _collidingObj; }
612 set { _collidingObj = value; }
613 }
614 public override bool FloatOnWater {
615 set {
616 _floatOnWater = value;
617 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
618 {
619 if (PhysBody.HasPhysicalBody)
620 {
621 if (_floatOnWater)
622 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
623 else
624 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
625 }
626 });
627 }
628 }
629 public override OMV.Vector3 RotationalVelocity {
630 get { return _rotationalVelocity; }
631 set { _rotationalVelocity = value; }
632 }
633 public override OMV.Vector3 ForceRotationalVelocity {
634 get { return _rotationalVelocity; }
635 set { _rotationalVelocity = value; }
636 }
637 public override bool Kinematic {
638 get { return _kinematic; }
639 set { _kinematic = value; }
640 }
641 // neg=fall quickly, 0=1g, 1=0g, pos=float up
642 public override float Buoyancy {
643 get { return _buoyancy; }
644 set { _buoyancy = value;
645 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
646 {
647 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
648 ForceBuoyancy = _buoyancy;
649 });
650 }
651 }
652 public override float ForceBuoyancy {
653 get { return _buoyancy; }
654 set {
655 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
656
657 _buoyancy = value;
658 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
659 // Buoyancy is faked by changing the gravity applied to the object
660 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
661 if (PhysBody.HasPhysicalBody)
662 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
663 }
664 }
665
666 // Used for MoveTo
667 public override OMV.Vector3 PIDTarget {
668 set { _PIDTarget = value; }
669 }
670 public override bool PIDActive {
671 set { _usePID = value; }
672 }
673 public override float PIDTau {
674 set { _PIDTau = value; }
675 }
676
677 // Used for llSetHoverHeight and maybe vehicle height
678 // Hover Height will override MoveTo target's Z
679 public override bool PIDHoverActive {
680 set { _useHoverPID = value; }
681 }
682 public override float PIDHoverHeight {
683 set { _PIDHoverHeight = value; }
684 }
685 public override PIDHoverType PIDHoverType {
686 set { _PIDHoverType = value; }
687 }
688 public override float PIDHoverTau {
689 set { _PIDHoverTao = value; }
690 }
691
692 // For RotLookAt
693 public override OMV.Quaternion APIDTarget { set { return; } }
694 public override bool APIDActive { set { return; } }
695 public override float APIDStrength { set { return; } }
696 public override float APIDDamping { set { return; } }
697
698 public override void AddForce(OMV.Vector3 force, bool pushforce) {
699 if (force.IsFinite())
700 {
701 _force.X += force.X;
702 _force.Y += force.Y;
703 _force.Z += force.Z;
704 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
705 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
706 {
707 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
708 if (PhysBody.HasPhysicalBody)
709 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
710 });
711 }
712 else
713 {
714 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader);
715 }
716 //m_lastUpdateSent = false;
717 }
718
719 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
720 }
721 public override void SetMomentum(OMV.Vector3 momentum) {
722 }
723
724 private void ComputeAvatarScale(OMV.Vector3 size)
725 {
726 OMV.Vector3 newScale = size;
727 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
728 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
729
730 // From the total height, remove the capsule half spheres that are at each end
731 // The 1.15f came from ODE. Not sure what this factors in.
732 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y);
733
734 // The total scale height is the central cylindar plus the caps on the two ends.
735 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f);
736
737 // Convert diameters to radii and height to half height -- the way Bullet expects it.
738 Scale = newScale / 2f;
739 }
740
741 // set _avatarVolume and _mass based on capsule size, _density and Scale
742 private void ComputeAvatarVolumeAndMass()
743 {
744 _avatarVolume = (float)(
745 Math.PI
746 * Scale.X
747 * Scale.Y // the area of capsule cylinder
748 * Scale.Z // times height of capsule cylinder
749 + 1.33333333f
750 * Math.PI
751 * Scale.X
752 * Math.Min(Scale.X, Scale.Y)
753 * Scale.Y // plus the volume of the capsule end caps
754 );
755 _mass = _avatarDensity * _avatarVolume;
756 }
757
758 // The physics engine says that properties have updated. Update same and inform
759 // the world that things have changed.
760 public override void UpdateProperties(EntityProperties entprop)
761 {
762 _position = entprop.Position;
763 _orientation = entprop.Rotation;
764 _velocity = entprop.Velocity;
765 _acceleration = entprop.Acceleration;
766 _rotationalVelocity = entprop.RotationalVelocity;
767
768 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
769 PositionSanityCheck(true);
770
771 if (_velocityMotor.Enabled)
772 {
773 // TODO: Decide if the step parameters should be changed depending on the avatar's
774 // state (flying, colliding, ...).
775
776 OMV.Vector3 stepVelocity = _velocityMotor.Step(PhysicsScene.LastTimeStep);
777
778 // If falling, we keep the world's downward vector no matter what the other axis specify.
779 if (!Flying && !IsColliding)
780 {
781 stepVelocity.Z = entprop.Velocity.Z;
782 DetailLog("{0},BSCharacter.UpdateProperties,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
783 }
784
785 // If the user has said stop and we've stopped applying velocity correction,
786 // the motor can be turned off. Set the velocity to zero so the zero motion is sent to the viewer.
787 if (_velocityMotor.TargetValue.ApproxEquals(OMV.Vector3.Zero, 0.01f) && _velocityMotor.ErrorIsZero)
788 {
789 ZeroMotion(true);
790 stepVelocity = OMV.Vector3.Zero;
791 _velocityMotor.Enabled = false;
792 DetailLog("{0},BSCharacter.UpdateProperties,taint,disableVelocityMotor,m={1}", LocalID, _velocityMotor);
793 }
794
795 _velocity = stepVelocity;
796 entprop.Velocity = _velocity;
797 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
798 }
799
800 // remember the current and last set values
801 LastEntityProperties = CurrentEntityProperties;
802 CurrentEntityProperties = entprop;
803
804 // Tell the linkset about value changes
805 Linkset.UpdateProperties(this, true);
806
807 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
808 // base.RequestPhysicsterseUpdate();
809
810 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
811 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
812 }
813}
814}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs
deleted file mode 100644
index f1bed39..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint.cs
+++ /dev/null
@@ -1,135 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSNPlugin
33{
34
35public abstract class BSConstraint : IDisposable
36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
39 protected BulletWorld m_world;
40 protected BulletBody m_body1;
41 protected BulletBody m_body2;
42 protected BulletConstraint m_constraint;
43 protected bool m_enabled = false;
44
45 public BulletBody Body1 { get { return m_body1; } }
46 public BulletBody Body2 { get { return m_body2; } }
47 public BulletConstraint Constraint { get { return m_constraint; } }
48 public abstract ConstraintType Type { get; }
49 public bool IsEnabled { get { return m_enabled; } }
50
51 public BSConstraint()
52 {
53 }
54
55 public virtual void Dispose()
56 {
57 if (m_enabled)
58 {
59 m_enabled = false;
60 if (m_constraint.HasPhysicalConstraint)
61 {
62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
64 BSScene.DetailLogZero,
65 m_body1.ID, m_body1.ptr.ToString(),
66 m_body2.ID, m_body2.ptr.ToString(),
67 success);
68 m_constraint.Clear();
69 }
70 }
71 }
72
73 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
74 {
75 bool ret = false;
76 if (m_enabled)
77 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high);
78 return ret;
79 }
80
81 public virtual bool SetAngularLimits(Vector3 low, Vector3 high)
82 {
83 bool ret = false;
84 if (m_enabled)
85 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high);
86 return ret;
87 }
88
89 public virtual bool SetSolverIterations(float cnt)
90 {
91 bool ret = false;
92 if (m_enabled)
93 {
94 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt);
95 ret = true;
96 }
97 return ret;
98 }
99
100 public virtual bool CalculateTransforms()
101 {
102 bool ret = false;
103 if (m_enabled)
104 {
105 // Recompute the internal transforms
106 BulletSimAPI.CalculateTransforms2(m_constraint.ptr);
107 ret = true;
108 }
109 return ret;
110 }
111
112 // Reset this constraint making sure it has all its internal structures
113 // recomputed and is enabled and ready to go.
114 public virtual bool RecomputeConstraintVariables(float mass)
115 {
116 bool ret = false;
117 if (m_enabled)
118 {
119 ret = CalculateTransforms();
120 if (ret)
121 {
122 // Setting an object's mass to zero (making it static like when it's selected)
123 // automatically disables the constraints.
124 // If the link is enabled, be sure to set the constraint itself to enabled.
125 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, BSParam.NumericBool(true));
126 }
127 else
128 {
129 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
130 }
131 }
132 return ret;
133 }
134}
135}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs
deleted file mode 100644
index d1e3f55..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraint6Dof.cs
+++ /dev/null
@@ -1,153 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSNPlugin
33{
34
35public sealed class BSConstraint6Dof : BSConstraint
36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40
41 // Create a btGeneric6DofConstraint
42 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot,
44 Vector3 frame2, Quaternion frame2rot,
45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
46 {
47 m_world = world;
48 m_body1 = obj1;
49 m_body2 = obj2;
50 m_constraint = new BulletConstraint(
51 BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
52 frame1, frame1rot,
53 frame2, frame2rot,
54 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
55 m_enabled = true;
56 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
57 BSScene.DetailLogZero, world.worldID,
58 obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
59 }
60
61 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
62 Vector3 joinPoint,
63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
64 {
65 m_world = world;
66 m_body1 = obj1;
67 m_body2 = obj2;
68 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
69 {
70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
71 BSScene.DetailLogZero, world.worldID,
72 obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
75 m_enabled = false;
76 }
77 else
78 {
79 m_constraint = new BulletConstraint(
80 BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
81 joinPoint,
82 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
84 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString(),
85 obj1.ID, obj1.ptr.ToString(), obj2.ID, obj2.ptr.ToString());
86 if (!m_constraint.HasPhysicalConstraint)
87 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID);
90 m_enabled = false;
91 }
92 else
93 {
94 m_enabled = true;
95 }
96 }
97 }
98
99 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
100 {
101 bool ret = false;
102 if (m_enabled)
103 {
104 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
105 ret = true;
106 }
107 return ret;
108 }
109
110 public bool SetCFMAndERP(float cfm, float erp)
111 {
112 bool ret = false;
113 if (m_enabled)
114 {
115 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
116 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
117 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
118 ret = true;
119 }
120 return ret;
121 }
122
123 public bool UseFrameOffset(bool useOffset)
124 {
125 bool ret = false;
126 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
127 if (m_enabled)
128 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff);
129 return ret;
130 }
131
132 public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
133 {
134 bool ret = false;
135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
136 if (m_enabled)
137 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 }
142 return ret;
143 }
144
145 public bool SetBreakingImpulseThreshold(float threshold)
146 {
147 bool ret = false;
148 if (m_enabled)
149 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
150 return ret;
151 }
152}
153}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs
deleted file mode 100644
index 87d1e44..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs
+++ /dev/null
@@ -1,180 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using log4net;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35
36public sealed class BSConstraintCollection : IDisposable
37{
38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
40
41 delegate bool ConstraintAction(BSConstraint constrain);
42
43 private List<BSConstraint> m_constraints;
44 private BulletWorld m_world;
45
46 public BSConstraintCollection(BulletWorld world)
47 {
48 m_world = world;
49 m_constraints = new List<BSConstraint>();
50 }
51
52 public void Dispose()
53 {
54 this.Clear();
55 }
56
57 public void Clear()
58 {
59 lock (m_constraints)
60 {
61 foreach (BSConstraint cons in m_constraints)
62 {
63 cons.Dispose();
64 }
65 m_constraints.Clear();
66 }
67 }
68
69 public bool AddConstraint(BSConstraint cons)
70 {
71 lock (m_constraints)
72 {
73 // There is only one constraint between any bodies. Remove any old just to make sure.
74 RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
75
76 m_constraints.Add(cons);
77 }
78
79 return true;
80 }
81
82 // Get the constraint between two bodies. There can be only one.
83 // Return 'true' if a constraint was found.
84 public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
85 {
86 bool found = false;
87 BSConstraint foundConstraint = null;
88
89 uint lookingID1 = body1.ID;
90 uint lookingID2 = body2.ID;
91 lock (m_constraints)
92 {
93 foreach (BSConstraint constrain in m_constraints)
94 {
95 if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
96 || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
97 {
98 foundConstraint = constrain;
99 found = true;
100 break;
101 }
102 }
103 }
104 returnConstraint = foundConstraint;
105 return found;
106 }
107
108 // Remove any constraint between the passed bodies.
109 // Presumed there is only one such constraint possible.
110 // Return 'true' if a constraint was found and destroyed.
111 public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
112 {
113 bool ret = false;
114 lock (m_constraints)
115 {
116 BSConstraint constrain;
117 if (this.TryGetConstraint(body1, body2, out constrain))
118 {
119 // remove the constraint from our collection
120 RemoveAndDestroyConstraint(constrain);
121 ret = true;
122 }
123 }
124
125 return ret;
126 }
127
128 // The constraint MUST exist in the collection
129 public bool RemoveAndDestroyConstraint(BSConstraint constrain)
130 {
131 lock (m_constraints)
132 {
133 // remove the constraint from our collection
134 m_constraints.Remove(constrain);
135 }
136 // tell the engine that all its structures need to be freed
137 constrain.Dispose();
138 // we destroyed something
139 return true;
140 }
141
142 // Remove all constraints that reference the passed body.
143 // Return 'true' if any constraints were destroyed.
144 public bool RemoveAndDestroyConstraint(BulletBody body1)
145 {
146 List<BSConstraint> toRemove = new List<BSConstraint>();
147 uint lookingID = body1.ID;
148 lock (m_constraints)
149 {
150 foreach (BSConstraint constrain in m_constraints)
151 {
152 if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
153 {
154 toRemove.Add(constrain);
155 }
156 }
157 foreach (BSConstraint constrain in toRemove)
158 {
159 m_constraints.Remove(constrain);
160 constrain.Dispose();
161 }
162 }
163 return (toRemove.Count > 0);
164 }
165
166 public bool RecalculateAllConstraints()
167 {
168 bool ret = false;
169 lock (m_constraints)
170 {
171 foreach (BSConstraint constrain in m_constraints)
172 {
173 constrain.CalculateTransforms();
174 ret = true;
175 }
176 }
177 return ret;
178 }
179}
180}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs
deleted file mode 100644
index fbd1bc0..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs
+++ /dev/null
@@ -1,57 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSNPlugin
33{
34
35public sealed class BSConstraintHinge : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38
39 public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB,
41 Vector3 axisInA, Vector3 axisInB,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 {
44 m_world = world;
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = new BulletConstraint(
48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
49 pivotInA, pivotInB,
50 axisInA, axisInB,
51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 m_enabled = true;
53 }
54
55}
56
57}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs
deleted file mode 100644
index 415ad4f..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs
+++ /dev/null
@@ -1,1377 +0,0 @@
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 copyright
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 * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
28 * are Copyright (c) 2009 Linden Research, Inc and are used under their license
29 * of Creative Commons Attribution-Share Alike 3.0
30 * (http://creativecommons.org/licenses/by-sa/3.0/).
31 */
32
33using System;
34using System.Collections.Generic;
35using System.Reflection;
36using System.Runtime.InteropServices;
37using OpenMetaverse;
38using OpenSim.Region.Physics.Manager;
39
40namespace OpenSim.Region.Physics.BulletSNPlugin
41{
42 public sealed class BSDynamics
43 {
44 private static string LogHeader = "[BULLETSIM VEHICLE]";
45
46 private BSScene PhysicsScene { get; set; }
47 // the prim this dynamic controller belongs to
48 private BSPrim Prim { get; set; }
49
50 // mass of the vehicle fetched each time we're calles
51 private float m_vehicleMass;
52
53 // Vehicle properties
54 public Vehicle Type { get; set; }
55
56 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
57 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
58 // HOVER_TERRAIN_ONLY
59 // HOVER_GLOBAL_HEIGHT
60 // NO_DEFLECTION_UP
61 // HOVER_WATER_ONLY
62 // HOVER_UP_ONLY
63 // LIMIT_MOTOR_UP
64 // LIMIT_ROLL_ONLY
65 private Vector3 m_BlockingEndPoint = Vector3.Zero;
66 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
67 private Quaternion m_referenceFrame = Quaternion.Identity;
68
69 // Linear properties
70 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
71 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
72 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
73 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
74 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
75 private float m_linearMotorDecayTimescale = 0;
76 private float m_linearMotorTimescale = 0;
77 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
78 private Vector3 m_lastPositionVector = Vector3.Zero;
79 // private bool m_LinearMotorSetLastFrame = false;
80 // private Vector3 m_linearMotorOffset = Vector3.Zero;
81
82 //Angular properties
83 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
84 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
85 // private int m_angularMotorApply = 0; // application frame counter
86 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
87 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
88 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
89 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
90 private Vector3 m_lastAngularVelocity = Vector3.Zero;
91 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
92
93 //Deflection properties
94 private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
95 private float m_angularDeflectionEfficiency = 0;
96 private float m_angularDeflectionTimescale = 0;
97 private float m_linearDeflectionEfficiency = 0;
98 private float m_linearDeflectionTimescale = 0;
99
100 //Banking properties
101 private float m_bankingEfficiency = 0;
102 private float m_bankingMix = 0;
103 private float m_bankingTimescale = 0;
104
105 //Hover and Buoyancy properties
106 private BSVMotor m_hoverMotor = new BSVMotor("Hover");
107 private float m_VhoverHeight = 0f;
108 private float m_VhoverEfficiency = 0f;
109 private float m_VhoverTimescale = 0f;
110 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
111 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
112 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
113 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
114 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
115
116 //Attractor properties
117 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
118 private float m_verticalAttractionEfficiency = 1.0f; // damped
119 private float m_verticalAttractionCutoff = 500f; // per the documentation
120 // Timescale > cutoff means no vert attractor.
121 private float m_verticalAttractionTimescale = 510f;
122
123 // Just some recomputed constants:
124 static readonly float PIOverFour = ((float)Math.PI) / 4f;
125 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
126
127 public BSDynamics(BSScene myScene, BSPrim myPrim)
128 {
129 PhysicsScene = myScene;
130 Prim = myPrim;
131 Type = Vehicle.TYPE_NONE;
132 }
133
134 // Return 'true' if this vehicle is doing vehicle things
135 public bool IsActive
136 {
137 get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; }
138 }
139
140 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
141 {
142 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
143 switch (pParam)
144 {
145 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
146 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f);
147 break;
148 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
149 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
150 break;
151 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
152 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
153 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
154 break;
155 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
156 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
157 m_angularMotor.TimeScale = m_angularMotorTimescale;
158 break;
159 case Vehicle.BANKING_EFFICIENCY:
160 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
161 break;
162 case Vehicle.BANKING_MIX:
163 m_bankingMix = Math.Max(pValue, 0.01f);
164 break;
165 case Vehicle.BANKING_TIMESCALE:
166 m_bankingTimescale = Math.Max(pValue, 0.01f);
167 break;
168 case Vehicle.BUOYANCY:
169 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
170 break;
171 case Vehicle.HOVER_EFFICIENCY:
172 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
173 break;
174 case Vehicle.HOVER_HEIGHT:
175 m_VhoverHeight = pValue;
176 break;
177 case Vehicle.HOVER_TIMESCALE:
178 m_VhoverTimescale = Math.Max(pValue, 0.01f);
179 break;
180 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
181 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f);
182 break;
183 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
184 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
185 break;
186 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
187 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
188 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
192 m_linearMotor.TimeScale = m_linearMotorTimescale;
193 break;
194 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
195 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
196 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
197 break;
198 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
199 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
200 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
201 break;
202
203 // These are vector properties but the engine lets you use a single float value to
204 // set all of the components to the same value
205 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
206 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
207 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
208 break;
209 case Vehicle.ANGULAR_MOTOR_DIRECTION:
210 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
211 m_angularMotor.SetTarget(m_angularMotorDirection);
212 break;
213 case Vehicle.LINEAR_FRICTION_TIMESCALE:
214 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
215 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
216 break;
217 case Vehicle.LINEAR_MOTOR_DIRECTION:
218 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
219 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
220 m_linearMotor.SetTarget(m_linearMotorDirection);
221 break;
222 case Vehicle.LINEAR_MOTOR_OFFSET:
223 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
224 break;
225
226 }
227 }//end ProcessFloatVehicleParam
228
229 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
230 {
231 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
232 switch (pParam)
233 {
234 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
235 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
237 break;
238 case Vehicle.ANGULAR_MOTOR_DIRECTION:
239 // Limit requested angular speed to 2 rps= 4 pi rads/sec
240 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
241 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
242 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
243 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_angularMotor.SetTarget(m_angularMotorDirection);
245 break;
246 case Vehicle.LINEAR_FRICTION_TIMESCALE:
247 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
248 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
249 break;
250 case Vehicle.LINEAR_MOTOR_DIRECTION:
251 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
252 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
253 m_linearMotor.SetTarget(m_linearMotorDirection);
254 break;
255 case Vehicle.LINEAR_MOTOR_OFFSET:
256 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
257 break;
258 case Vehicle.BLOCK_EXIT:
259 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
260 break;
261 }
262 }//end ProcessVectorVehicleParam
263
264 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
265 {
266 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
267 switch (pParam)
268 {
269 case Vehicle.REFERENCE_FRAME:
270 m_referenceFrame = pValue;
271 break;
272 case Vehicle.ROLL_FRAME:
273 m_RollreferenceFrame = pValue;
274 break;
275 }
276 }//end ProcessRotationVehicleParam
277
278 internal void ProcessVehicleFlags(int pParam, bool remove)
279 {
280 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
281 VehicleFlag parm = (VehicleFlag)pParam;
282 if (pParam == -1)
283 m_flags = (VehicleFlag)0;
284 else
285 {
286 if (remove)
287 m_flags &= ~parm;
288 else
289 m_flags |= parm;
290 }
291 }
292
293 internal void ProcessTypeChange(Vehicle pType)
294 {
295 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
296 // Set Defaults For Type
297 Type = pType;
298 switch (pType)
299 {
300 case Vehicle.TYPE_NONE:
301 m_linearMotorDirection = Vector3.Zero;
302 m_linearMotorTimescale = 0;
303 m_linearMotorDecayTimescale = 0;
304 m_linearFrictionTimescale = new Vector3(0, 0, 0);
305
306 m_angularMotorDirection = Vector3.Zero;
307 m_angularMotorDecayTimescale = 0;
308 m_angularMotorTimescale = 0;
309 m_angularFrictionTimescale = new Vector3(0, 0, 0);
310
311 m_VhoverHeight = 0;
312 m_VhoverEfficiency = 0;
313 m_VhoverTimescale = 0;
314 m_VehicleBuoyancy = 0;
315
316 m_linearDeflectionEfficiency = 1;
317 m_linearDeflectionTimescale = 1;
318
319 m_angularDeflectionEfficiency = 0;
320 m_angularDeflectionTimescale = 1000;
321
322 m_verticalAttractionEfficiency = 0;
323 m_verticalAttractionTimescale = 0;
324
325 m_bankingEfficiency = 0;
326 m_bankingTimescale = 1000;
327 m_bankingMix = 1;
328
329 m_referenceFrame = Quaternion.Identity;
330 m_flags = (VehicleFlag)0;
331
332 break;
333
334 case Vehicle.TYPE_SLED:
335 m_linearMotorDirection = Vector3.Zero;
336 m_linearMotorTimescale = 1000;
337 m_linearMotorDecayTimescale = 120;
338 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
339
340 m_angularMotorDirection = Vector3.Zero;
341 m_angularMotorTimescale = 1000;
342 m_angularMotorDecayTimescale = 120;
343 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
344
345 m_VhoverHeight = 0;
346 m_VhoverEfficiency = 10; // TODO: this looks wrong!!
347 m_VhoverTimescale = 10;
348 m_VehicleBuoyancy = 0;
349
350 m_linearDeflectionEfficiency = 1;
351 m_linearDeflectionTimescale = 1;
352
353 m_angularDeflectionEfficiency = 1;
354 m_angularDeflectionTimescale = 1000;
355
356 m_verticalAttractionEfficiency = 0;
357 m_verticalAttractionTimescale = 0;
358
359 m_bankingEfficiency = 0;
360 m_bankingTimescale = 10;
361 m_bankingMix = 1;
362
363 m_referenceFrame = Quaternion.Identity;
364 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
365 | VehicleFlag.HOVER_TERRAIN_ONLY
366 | VehicleFlag.HOVER_GLOBAL_HEIGHT
367 | VehicleFlag.HOVER_UP_ONLY);
368 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
369 | VehicleFlag.LIMIT_ROLL_ONLY
370 | VehicleFlag.LIMIT_MOTOR_UP);
371
372 break;
373 case Vehicle.TYPE_CAR:
374 m_linearMotorDirection = Vector3.Zero;
375 m_linearMotorTimescale = 1;
376 m_linearMotorDecayTimescale = 60;
377 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
378
379 m_angularMotorDirection = Vector3.Zero;
380 m_angularMotorTimescale = 1;
381 m_angularMotorDecayTimescale = 0.8f;
382 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
383
384 m_VhoverHeight = 0;
385 m_VhoverEfficiency = 0;
386 m_VhoverTimescale = 1000;
387 m_VehicleBuoyancy = 0;
388
389 m_linearDeflectionEfficiency = 1;
390 m_linearDeflectionTimescale = 2;
391
392 m_angularDeflectionEfficiency = 0;
393 m_angularDeflectionTimescale = 10;
394
395 m_verticalAttractionEfficiency = 1f;
396 m_verticalAttractionTimescale = 10f;
397
398 m_bankingEfficiency = -0.2f;
399 m_bankingMix = 1;
400 m_bankingTimescale = 1;
401
402 m_referenceFrame = Quaternion.Identity;
403 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
404 | VehicleFlag.HOVER_TERRAIN_ONLY
405 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
406 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
407 | VehicleFlag.LIMIT_ROLL_ONLY
408 | VehicleFlag.LIMIT_MOTOR_UP
409 | VehicleFlag.HOVER_UP_ONLY);
410 break;
411 case Vehicle.TYPE_BOAT:
412 m_linearMotorDirection = Vector3.Zero;
413 m_linearMotorTimescale = 5;
414 m_linearMotorDecayTimescale = 60;
415 m_linearFrictionTimescale = new Vector3(10, 3, 2);
416
417 m_angularMotorDirection = Vector3.Zero;
418 m_angularMotorTimescale = 4;
419 m_angularMotorDecayTimescale = 4;
420 m_angularFrictionTimescale = new Vector3(10,10,10);
421
422 m_VhoverHeight = 0;
423 m_VhoverEfficiency = 0.5f;
424 m_VhoverTimescale = 2;
425 m_VehicleBuoyancy = 1;
426
427 m_linearDeflectionEfficiency = 0.5f;
428 m_linearDeflectionTimescale = 3;
429
430 m_angularDeflectionEfficiency = 0.5f;
431 m_angularDeflectionTimescale = 5;
432
433 m_verticalAttractionEfficiency = 0.5f;
434 m_verticalAttractionTimescale = 5f;
435
436 m_bankingEfficiency = -0.3f;
437 m_bankingMix = 0.8f;
438 m_bankingTimescale = 1;
439
440 m_referenceFrame = Quaternion.Identity;
441 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
442 | VehicleFlag.HOVER_GLOBAL_HEIGHT
443 | VehicleFlag.LIMIT_ROLL_ONLY
444 | VehicleFlag.HOVER_UP_ONLY);
445 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
446 | VehicleFlag.LIMIT_MOTOR_UP
447 | VehicleFlag.HOVER_WATER_ONLY);
448 break;
449 case Vehicle.TYPE_AIRPLANE:
450 m_linearMotorDirection = Vector3.Zero;
451 m_linearMotorTimescale = 2;
452 m_linearMotorDecayTimescale = 60;
453 m_linearFrictionTimescale = new Vector3(200, 10, 5);
454
455 m_angularMotorDirection = Vector3.Zero;
456 m_angularMotorTimescale = 4;
457 m_angularMotorDecayTimescale = 4;
458 m_angularFrictionTimescale = new Vector3(20, 20, 20);
459
460 m_VhoverHeight = 0;
461 m_VhoverEfficiency = 0.5f;
462 m_VhoverTimescale = 1000;
463 m_VehicleBuoyancy = 0;
464
465 m_linearDeflectionEfficiency = 0.5f;
466 m_linearDeflectionTimescale = 3;
467
468 m_angularDeflectionEfficiency = 1;
469 m_angularDeflectionTimescale = 2;
470
471 m_verticalAttractionEfficiency = 0.9f;
472 m_verticalAttractionTimescale = 2f;
473
474 m_bankingEfficiency = 1;
475 m_bankingMix = 0.7f;
476 m_bankingTimescale = 2;
477
478 m_referenceFrame = Quaternion.Identity;
479 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
480 | VehicleFlag.HOVER_TERRAIN_ONLY
481 | VehicleFlag.HOVER_GLOBAL_HEIGHT
482 | VehicleFlag.HOVER_UP_ONLY
483 | VehicleFlag.NO_DEFLECTION_UP
484 | VehicleFlag.LIMIT_MOTOR_UP);
485 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
486 break;
487 case Vehicle.TYPE_BALLOON:
488 m_linearMotorDirection = Vector3.Zero;
489 m_linearMotorTimescale = 5;
490 m_linearFrictionTimescale = new Vector3(5, 5, 5);
491 m_linearMotorDecayTimescale = 60;
492
493 m_angularMotorDirection = Vector3.Zero;
494 m_angularMotorTimescale = 6;
495 m_angularFrictionTimescale = new Vector3(10, 10, 10);
496 m_angularMotorDecayTimescale = 10;
497
498 m_VhoverHeight = 5;
499 m_VhoverEfficiency = 0.8f;
500 m_VhoverTimescale = 10;
501 m_VehicleBuoyancy = 1;
502
503 m_linearDeflectionEfficiency = 0;
504 m_linearDeflectionTimescale = 5;
505
506 m_angularDeflectionEfficiency = 0;
507 m_angularDeflectionTimescale = 5;
508
509 m_verticalAttractionEfficiency = 1f;
510 m_verticalAttractionTimescale = 100f;
511
512 m_bankingEfficiency = 0;
513 m_bankingMix = 0.7f;
514 m_bankingTimescale = 5;
515
516 m_referenceFrame = Quaternion.Identity;
517
518 m_referenceFrame = Quaternion.Identity;
519 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
520 | VehicleFlag.HOVER_TERRAIN_ONLY
521 | VehicleFlag.HOVER_UP_ONLY
522 | VehicleFlag.NO_DEFLECTION_UP
523 | VehicleFlag.LIMIT_MOTOR_UP);
524 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY
525 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
526 break;
527 }
528
529 // Update any physical parameters based on this type.
530 Refresh();
531
532 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
533 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
534 1f);
535 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
536
537 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
538 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
539 1f);
540 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
541
542 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
543 BSMotor.Infinite, BSMotor.InfiniteVector,
544 m_verticalAttractionEfficiency);
545 // Z goes away and we keep X and Y
546 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
547 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
548 }
549
550 // Some of the properties of this prim may have changed.
551 // Do any updating needed for a vehicle
552 public void Refresh()
553 {
554 if (IsActive)
555 {
556 // Remember the mass so we don't have to fetch it every step
557 m_vehicleMass = Prim.Linkset.LinksetMass;
558
559 // Friction affects are handled by this vehicle code
560 float friction = 0f;
561 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
562
563 // Moderate angular movement introduced by Bullet.
564 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
565 // Maybe compute linear and angular factor and damping from params.
566 float angularDamping = BSParam.VehicleAngularDamping;
567 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
568
569 // Vehicles report collision events so we know when it's on the ground
570 BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
571
572 Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass);
573 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
574 BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr);
575
576 Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy);
577 BulletSimAPI.SetGravity2(Prim.PhysBody.ptr, grav);
578
579 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}",
580 Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping);
581 }
582 else
583 {
584 BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
585 }
586 }
587
588 public bool RemoveBodyDependencies(BSPhysObject prim)
589 {
590 // If active, we need to add our properties back when the body is rebuilt.
591 return IsActive;
592 }
593
594 public void RestoreBodyDependencies(BSPhysObject prim)
595 {
596 if (Prim.LocalID != prim.LocalID)
597 {
598 // The call should be on us by our prim. Error if not.
599 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}",
600 LogHeader, prim.LocalID, Prim.LocalID);
601 return;
602 }
603 Refresh();
604 }
605
606 #region Known vehicle value functions
607 // Vehicle physical parameters that we buffer from constant getting and setting.
608 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
609 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
610 // This does two things: 1) saves continuious calls into unmanaged code, and
611 // 2) signals when a physics property update must happen back to the simulator
612 // to update values modified for the vehicle.
613 private int m_knownChanged;
614 private int m_knownHas;
615 private float m_knownTerrainHeight;
616 private float m_knownWaterLevel;
617 private Vector3 m_knownPosition;
618 private Vector3 m_knownVelocity;
619 private Vector3 m_knownForce;
620 private Quaternion m_knownOrientation;
621 private Vector3 m_knownRotationalVelocity;
622 private Vector3 m_knownRotationalForce;
623 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
624
625 private const int m_knownChangedPosition = 1 << 0;
626 private const int m_knownChangedVelocity = 1 << 1;
627 private const int m_knownChangedForce = 1 << 2;
628 private const int m_knownChangedOrientation = 1 << 3;
629 private const int m_knownChangedRotationalVelocity = 1 << 4;
630 private const int m_knownChangedRotationalForce = 1 << 5;
631 private const int m_knownChangedTerrainHeight = 1 << 6;
632 private const int m_knownChangedWaterLevel = 1 << 7;
633 private const int m_knownChangedForwardVelocity = 1 << 8;
634
635 private void ForgetKnownVehicleProperties()
636 {
637 m_knownHas = 0;
638 m_knownChanged = 0;
639 }
640 // Push all the changed values back into the physics engine
641 private void PushKnownChanged()
642 {
643 if (m_knownChanged != 0)
644 {
645 if ((m_knownChanged & m_knownChangedPosition) != 0)
646 Prim.ForcePosition = m_knownPosition;
647
648 if ((m_knownChanged & m_knownChangedOrientation) != 0)
649 Prim.ForceOrientation = m_knownOrientation;
650
651 if ((m_knownChanged & m_knownChangedVelocity) != 0)
652 {
653 Prim.ForceVelocity = m_knownVelocity;
654 BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity);
655 }
656
657 if ((m_knownChanged & m_knownChangedForce) != 0)
658 Prim.AddForce((Vector3)m_knownForce, false, true);
659
660 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
661 {
662 Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
663 // Fake out Bullet by making it think the velocity is the same as last time.
664 BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, m_knownRotationalVelocity);
665 }
666
667 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
668 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true);
669
670 // If we set one of the values (ie, the physics engine didn't do it) we must force
671 // an UpdateProperties event to send the changes up to the simulator.
672 BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr);
673 }
674 m_knownChanged = 0;
675 }
676
677 // Since the computation of terrain height can be a little involved, this routine
678 // is used to fetch the height only once for each vehicle simulation step.
679 private float GetTerrainHeight(Vector3 pos)
680 {
681 if ((m_knownHas & m_knownChangedTerrainHeight) == 0)
682 {
683 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
684 m_knownHas |= m_knownChangedTerrainHeight;
685 }
686 return m_knownTerrainHeight;
687 }
688
689 // Since the computation of water level can be a little involved, this routine
690 // is used ot fetch the level only once for each vehicle simulation step.
691 private float GetWaterLevel(Vector3 pos)
692 {
693 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
694 {
695 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
696 m_knownHas |= m_knownChangedWaterLevel;
697 }
698 return (float)m_knownWaterLevel;
699 }
700
701 private Vector3 VehiclePosition
702 {
703 get
704 {
705 if ((m_knownHas & m_knownChangedPosition) == 0)
706 {
707 m_knownPosition = Prim.ForcePosition;
708 m_knownHas |= m_knownChangedPosition;
709 }
710 return m_knownPosition;
711 }
712 set
713 {
714 m_knownPosition = value;
715 m_knownChanged |= m_knownChangedPosition;
716 m_knownHas |= m_knownChangedPosition;
717 }
718 }
719
720 private Quaternion VehicleOrientation
721 {
722 get
723 {
724 if ((m_knownHas & m_knownChangedOrientation) == 0)
725 {
726 m_knownOrientation = Prim.ForceOrientation;
727 m_knownHas |= m_knownChangedOrientation;
728 }
729 return m_knownOrientation;
730 }
731 set
732 {
733 m_knownOrientation = value;
734 m_knownChanged |= m_knownChangedOrientation;
735 m_knownHas |= m_knownChangedOrientation;
736 }
737 }
738
739 private Vector3 VehicleVelocity
740 {
741 get
742 {
743 if ((m_knownHas & m_knownChangedVelocity) == 0)
744 {
745 m_knownVelocity = Prim.ForceVelocity;
746 m_knownHas |= m_knownChangedVelocity;
747 }
748 return (Vector3)m_knownVelocity;
749 }
750 set
751 {
752 m_knownVelocity = value;
753 m_knownChanged |= m_knownChangedVelocity;
754 m_knownHas |= m_knownChangedVelocity;
755 }
756 }
757
758 private void VehicleAddForce(Vector3 aForce)
759 {
760 if ((m_knownHas & m_knownChangedForce) == 0)
761 {
762 m_knownForce = Vector3.Zero;
763 }
764 m_knownForce += aForce;
765 m_knownChanged |= m_knownChangedForce;
766 m_knownHas |= m_knownChangedForce;
767 }
768
769 private Vector3 VehicleRotationalVelocity
770 {
771 get
772 {
773 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
774 {
775 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
776 m_knownHas |= m_knownChangedRotationalVelocity;
777 }
778 return (Vector3)m_knownRotationalVelocity;
779 }
780 set
781 {
782 m_knownRotationalVelocity = value;
783 m_knownChanged |= m_knownChangedRotationalVelocity;
784 m_knownHas |= m_knownChangedRotationalVelocity;
785 }
786 }
787 private void VehicleAddAngularForce(Vector3 aForce)
788 {
789 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
790 {
791 m_knownRotationalForce = Vector3.Zero;
792 }
793 m_knownRotationalForce += aForce;
794 m_knownChanged |= m_knownChangedRotationalForce;
795 m_knownHas |= m_knownChangedRotationalForce;
796 }
797 // Vehicle relative forward velocity
798 private Vector3 VehicleForwardVelocity
799 {
800 get
801 {
802 if ((m_knownHas & m_knownChangedForwardVelocity) == 0)
803 {
804 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
805 m_knownHas |= m_knownChangedForwardVelocity;
806 }
807 return m_knownForwardVelocity;
808 }
809 }
810 private float VehicleForwardSpeed
811 {
812 get
813 {
814 return VehicleForwardVelocity.X;
815 }
816 }
817
818 #endregion // Known vehicle value functions
819
820 // One step of the vehicle properties for the next 'pTimestep' seconds.
821 internal void Step(float pTimestep)
822 {
823 if (!IsActive) return;
824
825 ForgetKnownVehicleProperties();
826
827 MoveLinear(pTimestep);
828 MoveAngular(pTimestep);
829
830 LimitRotation(pTimestep);
831
832 // remember the position so next step we can limit absolute movement effects
833 m_lastPositionVector = VehiclePosition;
834
835 // If we forced the changing of some vehicle parameters, update the values and
836 // for the physics engine to note the changes so an UpdateProperties event will happen.
837 PushKnownChanged();
838
839 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
840 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity);
841 }
842
843 // Apply the effect of the linear motor and other linear motions (like hover and float).
844 private void MoveLinear(float pTimestep)
845 {
846 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
847
848 // The movement computed in the linear motor is relative to the vehicle
849 // coordinates. Rotate the movement to world coordinates.
850 linearMotorContribution *= VehicleOrientation;
851
852 // ==================================================================
853 // Buoyancy: force to overcome gravity.
854 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
855 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
856 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
857
858 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
859
860 Vector3 hoverContribution = ComputeLinearHover(pTimestep);
861
862 ComputeLinearBlockingEndPoint(pTimestep);
863
864 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep);
865
866 // ==================================================================
867 Vector3 newVelocity = linearMotorContribution
868 + terrainHeightContribution
869 + hoverContribution
870 + limitMotorUpContribution;
871
872 Vector3 newForce = buoyancyContribution;
873
874 // If not changing some axis, reduce out velocity
875 if ((m_flags & (VehicleFlag.NO_X)) != 0)
876 newVelocity.X = 0;
877 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
878 newVelocity.Y = 0;
879 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
880 newVelocity.Z = 0;
881
882 // ==================================================================
883 // Clamp high or low velocities
884 float newVelocityLengthSq = newVelocity.LengthSquared();
885 if (newVelocityLengthSq > 1000f)
886 {
887 newVelocity /= newVelocity.Length();
888 newVelocity *= 1000f;
889 }
890 else if (newVelocityLengthSq < 0.001f)
891 newVelocity = Vector3.Zero;
892
893 // ==================================================================
894 // Stuff new linear velocity into the vehicle.
895 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us.
896 VehicleVelocity = newVelocity;
897
898 // Other linear forces are applied as forces.
899 Vector3 totalDownForce = newForce * m_vehicleMass;
900 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
901 {
902 VehicleAddForce(totalDownForce);
903 }
904
905 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}",
906 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding);
907 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
908 Prim.LocalID,
909 linearMotorContribution, terrainHeightContribution, hoverContribution,
910 limitMotorUpContribution, buoyancyContribution
911 );
912
913 } // end MoveLinear()
914
915 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep)
916 {
917 Vector3 ret = Vector3.Zero;
918 // If below the terrain, move us above the ground a little.
919 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
920 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
921 {
922 // TODO: correct position by applying force rather than forcing position.
923 Vector3 newPosition = VehiclePosition;
924 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
925 VehiclePosition = newPosition;
926 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
927 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
928 }
929 return ret;
930 }
931
932 public Vector3 ComputeLinearHover(float pTimestep)
933 {
934 Vector3 ret = Vector3.Zero;
935
936 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
937 // m_VhoverTimescale: time to achieve height
938 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
939 {
940 // We should hover, get the target height
941 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
942 {
943 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
944 }
945 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
946 {
947 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
948 }
949 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
950 {
951 m_VhoverTargetHeight = m_VhoverHeight;
952 }
953
954 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
955 {
956 // If body is already heigher, use its height as target height
957 if (VehiclePosition.Z > m_VhoverTargetHeight)
958 m_VhoverTargetHeight = VehiclePosition.Z;
959 }
960
961 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
962 {
963 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
964 {
965 Vector3 pos = VehiclePosition;
966 pos.Z = m_VhoverTargetHeight;
967 VehiclePosition = pos;
968 }
969 }
970 else
971 {
972 // Error is positive if below the target and negative if above.
973 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z;
974 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
975
976 // TODO: implement m_VhoverEfficiency correctly
977 if (Math.Abs(verticalError) > m_VhoverEfficiency)
978 {
979 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
980 }
981 }
982
983 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}",
984 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight);
985 }
986
987 return ret;
988 }
989
990 public bool ComputeLinearBlockingEndPoint(float pTimestep)
991 {
992 bool changed = false;
993
994 Vector3 pos = VehiclePosition;
995 Vector3 posChange = pos - m_lastPositionVector;
996 if (m_BlockingEndPoint != Vector3.Zero)
997 {
998 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
999 {
1000 pos.X -= posChange.X + 1;
1001 changed = true;
1002 }
1003 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
1004 {
1005 pos.Y -= posChange.Y + 1;
1006 changed = true;
1007 }
1008 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
1009 {
1010 pos.Z -= posChange.Z + 1;
1011 changed = true;
1012 }
1013 if (pos.X <= 0)
1014 {
1015 pos.X += posChange.X + 1;
1016 changed = true;
1017 }
1018 if (pos.Y <= 0)
1019 {
1020 pos.Y += posChange.Y + 1;
1021 changed = true;
1022 }
1023 if (changed)
1024 {
1025 VehiclePosition = pos;
1026 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1027 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
1028 }
1029 }
1030 return changed;
1031 }
1032
1033 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1034 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
1035 // used with conjunction with banking: the strength of the banking will decay when the
1036 // vehicle no longer experiences collisions. The decay timescale is the same as
1037 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1038 // when they are in mid jump.
1039 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1040 // This is just using the ground and a general collision check. Should really be using
1041 // a downward raycast to find what is below.
1042 public Vector3 ComputeLinearMotorUp(float pTimestep)
1043 {
1044 Vector3 ret = Vector3.Zero;
1045 float distanceAboveGround = 0f;
1046
1047 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1048 {
1049 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1050 distanceAboveGround = VehiclePosition.Z - targetHeight;
1051 // Not colliding if the vehicle is off the ground
1052 if (!Prim.IsColliding)
1053 {
1054 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1055 ret = new Vector3(0, 0, -distanceAboveGround);
1056 }
1057 // TODO: this calculation is wrong. From the description at
1058 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
1059 // has a decay factor. This says this force should
1060 // be computed with a motor.
1061 // TODO: add interaction with banking.
1062 }
1063 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1064 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
1065 return ret;
1066 }
1067
1068 // =======================================================================
1069 // =======================================================================
1070 // Apply the effect of the angular motor.
1071 // The 'contribution' is how much angular correction velocity each function wants.
1072 // All the contributions are added together and the resulting velocity is
1073 // set directly on the vehicle.
1074 private void MoveAngular(float pTimestep)
1075 {
1076 // The user wants this many radians per second angular change?
1077 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
1078
1079 // ==================================================================
1080 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1081 // This flag prevents linear deflection parallel to world z-axis. This is useful
1082 // for preventing ground vehicles with large linear deflection, like bumper cars,
1083 // from climbing their linear deflection into the sky.
1084 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1085 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1086 {
1087 angularMotorContribution.X = 0f;
1088 angularMotorContribution.Y = 0f;
1089 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
1090 }
1091
1092 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
1093
1094 Vector3 deflectionContribution = ComputeAngularDeflection();
1095
1096 Vector3 bankingContribution = ComputeAngularBanking();
1097
1098 // ==================================================================
1099 m_lastVertAttractor = verticalAttractionContribution;
1100
1101 m_lastAngularVelocity = angularMotorContribution
1102 + verticalAttractionContribution
1103 + deflectionContribution
1104 + bankingContribution;
1105
1106 // ==================================================================
1107 // Apply the correction velocity.
1108 // TODO: Should this be applied as an angular force (torque)?
1109 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1110 {
1111 VehicleRotationalVelocity = m_lastAngularVelocity;
1112
1113 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}",
1114 Prim.LocalID,
1115 angularMotorContribution, verticalAttractionContribution,
1116 bankingContribution, deflectionContribution,
1117 m_lastAngularVelocity
1118 );
1119 }
1120 else
1121 {
1122 // The vehicle is not adding anything angular wise.
1123 VehicleRotationalVelocity = Vector3.Zero;
1124 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
1125 }
1126
1127 // ==================================================================
1128 //Offset section
1129 if (m_linearMotorOffset != Vector3.Zero)
1130 {
1131 //Offset of linear velocity doesn't change the linear velocity,
1132 // but causes a torque to be applied, for example...
1133 //
1134 // IIIII >>> IIIII
1135 // IIIII >>> IIIII
1136 // IIIII >>> IIIII
1137 // ^
1138 // | Applying a force at the arrow will cause the object to move forward, but also rotate
1139 //
1140 //
1141 // The torque created is the linear velocity crossed with the offset
1142
1143 // TODO: this computation should be in the linear section
1144 // because that is where we know the impulse being applied.
1145 Vector3 torqueFromOffset = Vector3.Zero;
1146 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
1147 if (float.IsNaN(torqueFromOffset.X))
1148 torqueFromOffset.X = 0;
1149 if (float.IsNaN(torqueFromOffset.Y))
1150 torqueFromOffset.Y = 0;
1151 if (float.IsNaN(torqueFromOffset.Z))
1152 torqueFromOffset.Z = 0;
1153
1154 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1155 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1156 }
1157
1158 }
1159 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1160 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1161 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1162 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1163 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1164 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1165 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1166 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1167 public Vector3 ComputeAngularVerticalAttraction()
1168 {
1169 Vector3 ret = Vector3.Zero;
1170
1171 // If vertical attaction timescale is reasonable
1172 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1173 {
1174 // Take a vector pointing up and convert it from world to vehicle relative coords.
1175 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
1176
1177 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1178 // is now:
1179 // leaning to one side: rotated around the X axis with the Y value going
1180 // from zero (nearly straight up) to one (completely to the side)) or
1181 // leaning front-to-back: rotated around the Y axis with the value of X being between
1182 // zero and one.
1183 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1184
1185 // Y error means needed rotation around X axis and visa versa.
1186 // Since the error goes from zero to one, the asin is the corresponding angle.
1187 ret.X = (float)Math.Asin(verticalError.Y);
1188 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1189 ret.Y = -(float)Math.Asin(verticalError.X);
1190
1191 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1192 if (verticalError.Z < 0f)
1193 {
1194 ret.X += PIOverFour;
1195 ret.Y += PIOverFour;
1196 }
1197
1198 // 'ret' is now the necessary velocity to correct tilt in one second.
1199 // Correction happens over a number of seconds.
1200 Vector3 unscaledContrib = ret;
1201 ret /= m_verticalAttractionTimescale;
1202
1203 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1204 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret);
1205 }
1206 return ret;
1207 }
1208
1209 // Return the angular correction to correct the direction the vehicle is pointing to be
1210 // the direction is should want to be pointing.
1211 // The vehicle is moving in some direction and correct its orientation to it is pointing
1212 // in that direction.
1213 // TODO: implement reference frame.
1214 public Vector3 ComputeAngularDeflection()
1215 {
1216 Vector3 ret = Vector3.Zero;
1217 return ret; // DEBUG DEBUG DEBUG
1218 // Disable angular deflection for the moment.
1219 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1220 // approximately the same X or Y correction. When added together (when contributions are combined)
1221 // this creates an over-correction and then wabbling as the target is overshot.
1222 // TODO: rethink how the different correction computations inter-relate.
1223
1224 if (m_angularDeflectionEfficiency != 0)
1225 {
1226 // The direction the vehicle is moving
1227 Vector3 movingDirection = VehicleVelocity;
1228 movingDirection.Normalize();
1229
1230 // The direction the vehicle is pointing
1231 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1232 pointingDirection.Normalize();
1233
1234 // The difference between what is and what should be.
1235 Vector3 deflectionError = movingDirection - pointingDirection;
1236
1237 // Don't try to correct very large errors (not our job)
1238 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1239 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1240 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1241
1242 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1243
1244 // Scale the correction by recovery timescale and efficiency
1245 ret = (-deflectionError) * m_angularDeflectionEfficiency;
1246 ret /= m_angularDeflectionTimescale;
1247
1248 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1249 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
1250 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1251 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1252 }
1253 return ret;
1254 }
1255
1256 // Return an angular change to rotate the vehicle around the Z axis when the vehicle
1257 // is tipped around the X axis.
1258 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1259 // The vertical attractor feature must be enabled in order for the banking behavior to
1260 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1261 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1262 // of the yaw effect will be proportional to the
1263 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1264 // velocity along its preferred axis of motion.
1265 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1266 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1267 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1268 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1269 // Negating the banking coefficient will make it so that the vehicle leans to the
1270 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1271 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1272 // banking vehicles do what you want rather than what the laws of physics allow.
1273 // For example, consider a real motorcycle...it must be moving forward in order for
1274 // it to turn while banking, however video-game motorcycles are often configured
1275 // to turn in place when at a dead stop--because they are often easier to control
1276 // that way using the limited interface of the keyboard or game controller. The
1277 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1278 // banking by functioning as a slider between a banking that is correspondingly
1279 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1280 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1281 // to "dynamic" where the banking is also proportional to its velocity along its
1282 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1283 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1284 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1285 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1286 // make a sluggish vehicle by giving it a timescale of several seconds.
1287 public Vector3 ComputeAngularBanking()
1288 {
1289 Vector3 ret = Vector3.Zero;
1290
1291 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1292 {
1293 // This works by rotating a unit vector to the orientation of the vehicle. The
1294 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
1295 // up to one for full over).
1296 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1297
1298 // Figure out the yaw value for this much roll.
1299 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency;
1300 // Keep the sign
1301 if (rollComponents.Y < 0f)
1302 turnComponent = -turnComponent;
1303
1304 // TODO: there must be a better computation of the banking force.
1305 float bankingTurnForce = turnComponent;
1306
1307 // actual error = static turn error + dynamic turn error
1308 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed;
1309 // TODO: the banking effect should not go to infinity but what to limit it to?
1310 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f);
1311
1312 // Build the force vector to change rotation from what it is to what it should be
1313 ret.Z = -mixedBankingError;
1314
1315 // Don't do it all at once.
1316 ret /= m_bankingTimescale;
1317
1318 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}",
1319 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret);
1320 }
1321 return ret;
1322 }
1323
1324 // This is from previous instantiations of XXXDynamics.cs.
1325 // Applies roll reference frame.
1326 // TODO: is this the right way to separate the code to do this operation?
1327 // Should this be in MoveAngular()?
1328 internal void LimitRotation(float timestep)
1329 {
1330 Quaternion rotq = VehicleOrientation;
1331 Quaternion m_rot = rotq;
1332 if (m_RollreferenceFrame != Quaternion.Identity)
1333 {
1334 if (rotq.X >= m_RollreferenceFrame.X)
1335 {
1336 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
1337 }
1338 if (rotq.Y >= m_RollreferenceFrame.Y)
1339 {
1340 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
1341 }
1342 if (rotq.X <= -m_RollreferenceFrame.X)
1343 {
1344 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
1345 }
1346 if (rotq.Y <= -m_RollreferenceFrame.Y)
1347 {
1348 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
1349 }
1350 }
1351 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
1352 {
1353 m_rot.X = 0;
1354 m_rot.Y = 0;
1355 }
1356 if (rotq != m_rot)
1357 {
1358 VehicleOrientation = m_rot;
1359 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1360 }
1361
1362 }
1363
1364 private float ClampInRange(float low, float val, float high)
1365 {
1366 return Math.Max(low, Math.Min(val, high));
1367 // return Utils.Clamp(val, low, high);
1368 }
1369
1370 // Invoke the detailed logger and output something if it's enabled.
1371 private void VDetailLog(string msg, params Object[] args)
1372 {
1373 if (Prim.PhysicsScene.VehicleLoggingEnabled)
1374 Prim.PhysicsScene.DetailLog(msg, args);
1375 }
1376 }
1377}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs
deleted file mode 100644
index 845a113..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSLinkset.cs
+++ /dev/null
@@ -1,329 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35
36// A BSPrim can get individual information about its linkedness attached
37// to it through an instance of a subclass of LinksetInfo.
38// Each type of linkset will define the information needed for its type.
39public abstract class BSLinksetInfo
40{
41 public virtual void Clear() { }
42}
43
44public abstract class BSLinkset
45{
46 // private static string LogHeader = "[BULLETSIM LINKSET]";
47
48 public enum LinksetImplementation
49 {
50 Constraint = 0, // linkset tied together with constraints
51 Compound = 1, // linkset tied together as a compound object
52 Manual = 2 // linkset tied together manually (code moves all the pieces)
53 }
54 // Create the correct type of linkset for this child
55 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
56 {
57 BSLinkset ret = null;
58
59 switch ((int)BSParam.LinksetImplementation)
60 {
61 case (int)LinksetImplementation.Constraint:
62 ret = new BSLinksetConstraints(physScene, parent);
63 break;
64 case (int)LinksetImplementation.Compound:
65 ret = new BSLinksetCompound(physScene, parent);
66 break;
67 case (int)LinksetImplementation.Manual:
68 // ret = new BSLinksetManual(physScene, parent);
69 break;
70 default:
71 ret = new BSLinksetCompound(physScene, parent);
72 break;
73 }
74 return ret;
75 }
76
77 public BSPhysObject LinksetRoot { get; protected set; }
78
79 public BSScene PhysicsScene { get; private set; }
80
81 static int m_nextLinksetID = 1;
82 public int LinksetID { get; private set; }
83
84 // The children under the root in this linkset.
85 protected HashSet<BSPhysObject> m_children;
86
87 // We lock the diddling of linkset classes to prevent any badness.
88 // This locks the modification of the instances of this class. Changes
89 // to the physical representation is done via the tainting mechenism.
90 protected object m_linksetActivityLock = new Object();
91
92 // Some linksets have a preferred physical shape.
93 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
94 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
95 {
96 return BSPhysicsShapeType.SHAPE_UNKNOWN;
97 }
98
99 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
100 public float LinksetMass { get; protected set; }
101
102 public virtual bool LinksetIsColliding { get { return false; } }
103
104 public OMV.Vector3 CenterOfMass
105 {
106 get { return ComputeLinksetCenterOfMass(); }
107 }
108
109 public OMV.Vector3 GeometricCenter
110 {
111 get { return ComputeLinksetGeometricCenter(); }
112 }
113
114 protected BSLinkset(BSScene scene, BSPhysObject parent)
115 {
116 // A simple linkset of one (no children)
117 LinksetID = m_nextLinksetID++;
118 // We create LOTS of linksets.
119 if (m_nextLinksetID <= 0)
120 m_nextLinksetID = 1;
121 PhysicsScene = scene;
122 LinksetRoot = parent;
123 m_children = new HashSet<BSPhysObject>();
124 LinksetMass = parent.RawMass;
125 Rebuilding = false;
126 }
127
128 // Link to a linkset where the child knows the parent.
129 // Parent changing should not happen so do some sanity checking.
130 // We return the parent's linkset so the child can track its membership.
131 // Called at runtime.
132 public BSLinkset AddMeToLinkset(BSPhysObject child)
133 {
134 lock (m_linksetActivityLock)
135 {
136 // Don't add the root to its own linkset
137 if (!IsRoot(child))
138 AddChildToLinkset(child);
139 LinksetMass = ComputeLinksetMass();
140 }
141 return this;
142 }
143
144 // Remove a child from a linkset.
145 // Returns a new linkset for the child which is a linkset of one (just the
146 // orphened child).
147 // Called at runtime.
148 public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
149 {
150 lock (m_linksetActivityLock)
151 {
152 if (IsRoot(child))
153 {
154 // Cannot remove the root from a linkset.
155 return this;
156 }
157 RemoveChildFromLinkset(child);
158 LinksetMass = ComputeLinksetMass();
159 }
160
161 // The child is down to a linkset of just itself
162 return BSLinkset.Factory(PhysicsScene, child);
163 }
164
165 // Return 'true' if the passed object is the root object of this linkset
166 public bool IsRoot(BSPhysObject requestor)
167 {
168 return (requestor.LocalID == LinksetRoot.LocalID);
169 }
170
171 public int NumberOfChildren { get { return m_children.Count; } }
172
173 // Return 'true' if this linkset has any children (more than the root member)
174 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
175
176 // Return 'true' if this child is in this linkset
177 public bool HasChild(BSPhysObject child)
178 {
179 bool ret = false;
180 lock (m_linksetActivityLock)
181 {
182 ret = m_children.Contains(child);
183 /* Safer version but the above should work
184 foreach (BSPhysObject bp in m_children)
185 {
186 if (child.LocalID == bp.LocalID)
187 {
188 ret = true;
189 break;
190 }
191 }
192 */
193 }
194 return ret;
195 }
196
197 // Perform an action on each member of the linkset including root prim.
198 // Depends on the action on whether this should be done at taint time.
199 public delegate bool ForEachMemberAction(BSPhysObject obj);
200 public virtual bool ForEachMember(ForEachMemberAction action)
201 {
202 bool ret = false;
203 lock (m_linksetActivityLock)
204 {
205 action(LinksetRoot);
206 foreach (BSPhysObject po in m_children)
207 {
208 if (action(po))
209 break;
210 }
211 }
212 return ret;
213 }
214
215 // I am the root of a linkset and a new child is being added
216 // Called while LinkActivity is locked.
217 protected abstract void AddChildToLinkset(BSPhysObject child);
218
219 // I am the root of a linkset and one of my children is being removed.
220 // Safe to call even if the child is not really in my linkset.
221 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
222
223 // When physical properties are changed the linkset needs to recalculate
224 // its internal properties.
225 // May be called at runtime or taint-time.
226 public virtual void Refresh(BSPhysObject requestor)
227 {
228 LinksetMass = ComputeLinksetMass();
229 }
230
231 // Flag denoting the linkset is in the process of being rebuilt.
232 // Used to know not the schedule a rebuild in the middle of a rebuild.
233 protected bool Rebuilding { get; set; }
234
235 // The object is going dynamic (physical). Do any setup necessary
236 // for a dynamic linkset.
237 // Only the state of the passed object can be modified. The rest of the linkset
238 // has not yet been fully constructed.
239 // Return 'true' if any properties updated on the passed object.
240 // Called at taint-time!
241 public abstract bool MakeDynamic(BSPhysObject child);
242
243 // The object is going static (non-physical). Do any setup necessary
244 // for a static linkset.
245 // Return 'true' if any properties updated on the passed object.
246 // Called at taint-time!
247 public abstract bool MakeStatic(BSPhysObject child);
248
249 // Called when a parameter update comes from the physics engine for any object
250 // of the linkset is received.
251 // Passed flag is update came from physics engine (true) or the user (false).
252 // Called at taint-time!!
253 public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate);
254
255 // Routine used when rebuilding the body of the root of the linkset
256 // Destroy all the constraints have have been made to root.
257 // This is called when the root body is changing.
258 // Returns 'true' of something was actually removed and would need restoring
259 // Called at taint-time!!
260 public abstract bool RemoveBodyDependencies(BSPrim child);
261
262 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
263 // this routine will restore the removed constraints.
264 // Called at taint-time!!
265 public abstract void RestoreBodyDependencies(BSPrim child);
266
267 // ================================================================
268 protected virtual float ComputeLinksetMass()
269 {
270 float mass = LinksetRoot.RawMass;
271 if (HasAnyChildren)
272 {
273 lock (m_linksetActivityLock)
274 {
275 foreach (BSPhysObject bp in m_children)
276 {
277 mass += bp.RawMass;
278 }
279 }
280 }
281 return mass;
282 }
283
284 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
285 {
286 OMV.Vector3 com;
287 lock (m_linksetActivityLock)
288 {
289 com = LinksetRoot.Position * LinksetRoot.RawMass;
290 float totalMass = LinksetRoot.RawMass;
291
292 foreach (BSPhysObject bp in m_children)
293 {
294 com += bp.Position * bp.RawMass;
295 totalMass += bp.RawMass;
296 }
297 if (totalMass != 0f)
298 com /= totalMass;
299 }
300
301 return com;
302 }
303
304 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
305 {
306 OMV.Vector3 com;
307 lock (m_linksetActivityLock)
308 {
309 com = LinksetRoot.Position;
310
311 foreach (BSPhysObject bp in m_children)
312 {
313 com += bp.Position * bp.RawMass;
314 }
315 com /= (m_children.Count + 1);
316 }
317
318 return com;
319 }
320
321 // Invoke the detailed logger and output something if it's enabled.
322 protected void DetailLog(string msg, params Object[] args)
323 {
324 if (PhysicsScene.PhysicsLogging.Enabled)
325 PhysicsScene.DetailLog(msg, args);
326 }
327
328}
329}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs
deleted file mode 100644
index 9a977e6..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetCompound.cs
+++ /dev/null
@@ -1,397 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37
38// When a child is linked, the relationship position of the child to the parent
39// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo
42{
43 public OMV.Vector3 OffsetPos;
44 public OMV.Quaternion OffsetRot;
45 public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r)
46 {
47 OffsetPos = p;
48 OffsetRot = r;
49 }
50 public override void Clear()
51 {
52 OffsetPos = OMV.Vector3.Zero;
53 OffsetRot = OMV.Quaternion.Identity;
54 }
55 public override string ToString()
56 {
57 StringBuilder buff = new StringBuilder();
58 buff.Append("<p=");
59 buff.Append(OffsetPos.ToString());
60 buff.Append(",r=");
61 buff.Append(OffsetRot.ToString());
62 buff.Append(">");
63 return buff.ToString();
64 }
65};
66
67public sealed class BSLinksetCompound : BSLinkset
68{
69 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
70
71 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
72 {
73 }
74
75 // For compound implimented linksets, if there are children, use compound shape for the root.
76 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
77 {
78 // Returning 'unknown' means we don't have a preference.
79 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
80 if (IsRoot(requestor) && HasAnyChildren)
81 {
82 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
83 }
84 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
85 return ret;
86 }
87
88 // When physical properties are changed the linkset needs to recalculate
89 // its internal properties.
90 public override void Refresh(BSPhysObject requestor)
91 {
92 base.Refresh(requestor);
93
94 // Something changed so do the rebuilding thing
95 // ScheduleRebuild();
96 }
97
98 // Schedule a refresh to happen after all the other taint processing.
99 private void ScheduleRebuild(BSPhysObject requestor)
100 {
101 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1}",
102 requestor.LocalID, Rebuilding);
103 // When rebuilding, it is possible to set properties that would normally require a rebuild.
104 // If already rebuilding, don't request another rebuild.
105 if (!Rebuilding)
106 {
107 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
108 {
109 if (HasAnyChildren)
110 RecomputeLinksetCompound();
111 });
112 }
113 }
114
115 // The object is going dynamic (physical). Do any setup necessary
116 // for a dynamic linkset.
117 // Only the state of the passed object can be modified. The rest of the linkset
118 // has not yet been fully constructed.
119 // Return 'true' if any properties updated on the passed object.
120 // Called at taint-time!
121 public override bool MakeDynamic(BSPhysObject child)
122 {
123 bool ret = false;
124 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
125 if (IsRoot(child))
126 {
127 // The root is going dynamic. Make sure mass is properly set.
128 ScheduleRebuild(LinksetRoot);
129 }
130 else
131 {
132 // The origional prims are removed from the world as the shape of the root compound
133 // shape takes over.
134 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
135 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
136 // We don't want collisions from the old linkset children.
137 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
138
139 child.PhysBody.collisionType = CollisionType.LinksetChild;
140
141 ret = true;
142 }
143 return ret;
144 }
145
146 // The object is going static (non-physical). Do any setup necessary for a static linkset.
147 // Return 'true' if any properties updated on the passed object.
148 // This doesn't normally happen -- OpenSim removes the objects from the physical
149 // world if it is a static linkset.
150 // Called at taint-time!
151 public override bool MakeStatic(BSPhysObject child)
152 {
153 bool ret = false;
154 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
155 if (IsRoot(child))
156 {
157 ScheduleRebuild(LinksetRoot);
158 }
159 else
160 {
161 // The non-physical children can come back to life.
162 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
163
164 child.PhysBody.collisionType = CollisionType.LinksetChild;
165
166 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
167 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
168 ret = true;
169 }
170 return ret;
171 }
172
173 public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate)
174 {
175 // The user moving a child around requires the rebuilding of the linkset compound shape
176 // One problem is this happens when a border is crossed -- the simulator implementation
177 // is to store the position into the group which causes the move of the object
178 // but it also means all the child positions get updated.
179 // What would cause an unnecessary rebuild so we make sure the linkset is in a
180 // region before bothering to do a rebuild.
181 if (!IsRoot(updated)
182 && !physicalUpdate
183 && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
184 {
185 updated.LinksetInfo = null;
186 ScheduleRebuild(updated);
187 }
188 }
189
190 // Routine called when rebuilding the body of some member of the linkset.
191 // Since we don't keep in world relationships, do nothing unless it's a child changing.
192 // Returns 'true' of something was actually removed and would need restoring
193 // Called at taint-time!!
194 public override bool RemoveBodyDependencies(BSPrim child)
195 {
196 bool ret = false;
197
198 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
199 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), IsRoot(child));
200
201 if (!IsRoot(child))
202 {
203 // Because it is a convenient time, recompute child world position and rotation based on
204 // its position in the linkset.
205 RecomputeChildWorldPosition(child, true);
206 }
207
208 // Cannot schedule a refresh/rebuild here because this routine is called when
209 // the linkset is being rebuilt.
210 // InternalRefresh(LinksetRoot);
211
212 return ret;
213 }
214
215 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
216 // this routine will restore the removed constraints.
217 // Called at taint-time!!
218 public override void RestoreBodyDependencies(BSPrim child)
219 {
220 }
221
222 // When the linkset is built, the child shape is added to the compound shape relative to the
223 // root shape. The linkset then moves around but this does not move the actual child
224 // prim. The child prim's location must be recomputed based on the location of the root shape.
225 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
226 {
227 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
228 if (lci != null)
229 {
230 if (inTaintTime)
231 {
232 OMV.Vector3 oldPos = child.RawPosition;
233 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
234 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
235 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
236 child.LocalID, oldPos, lci, child.RawPosition);
237 }
238 else
239 {
240 // TaintedObject is not used here so the raw position is set now and not at taint-time.
241 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
242 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
243 }
244 }
245 else
246 {
247 // This happens when children have been added to the linkset but the linkset
248 // has not been constructed yet. So like, at taint time, adding children to a linkset
249 // and then changing properties of the children (makePhysical, for instance)
250 // but the post-print action of actually rebuilding the linkset has not yet happened.
251 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
252 // LogHeader, child.LocalID);
253 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
254 }
255 }
256
257 // ================================================================
258
259 // Add a new child to the linkset.
260 // Called while LinkActivity is locked.
261 protected override void AddChildToLinkset(BSPhysObject child)
262 {
263 if (!HasChild(child))
264 {
265 m_children.Add(child);
266
267 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
268
269 // Rebuild the compound shape with the new child shape included
270 ScheduleRebuild(child);
271 }
272 return;
273 }
274
275 // Remove the specified child from the linkset.
276 // Safe to call even if the child is not really in the linkset.
277 protected override void RemoveChildFromLinkset(BSPhysObject child)
278 {
279 if (m_children.Remove(child))
280 {
281 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
282 child.LocalID,
283 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(),
284 child.LocalID, child.PhysBody.ptr.ToString());
285
286 // Cause the child's body to be rebuilt and thus restored to normal operation
287 RecomputeChildWorldPosition(child, false);
288 child.ForceBodyShapeRebuild(false);
289
290 if (!HasAnyChildren)
291 {
292 // The linkset is now empty. The root needs rebuilding.
293 LinksetRoot.ForceBodyShapeRebuild(false);
294 }
295 else
296 {
297 // Rebuild the compound shape with the child removed
298 ScheduleRebuild(child);
299 }
300 }
301 return;
302 }
303
304 // Called before the simulation step to make sure the compound based linkset
305 // is all initialized.
306 // Constraint linksets are rebuilt every time.
307 // Note that this works for rebuilding just the root after a linkset is taken apart.
308 // Called at taint time!!
309 private void RecomputeLinksetCompound()
310 {
311 try
312 {
313 // Suppress rebuilding while rebuilding
314 Rebuilding = true;
315
316 // Cause the root shape to be rebuilt as a compound object with just the root in it
317 LinksetRoot.ForceBodyShapeRebuild(true);
318
319 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
320 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
321
322 // Add a shape for each of the other children in the linkset
323 ForEachMember(delegate(BSPhysObject cPrim)
324 {
325 if (!IsRoot(cPrim))
326 {
327 // Compute the displacement of the child from the root of the linkset.
328 // This info is saved in the child prim so the relationship does not
329 // change over time and the new child position can be computed
330 // when the linkset is being disassembled (the linkset may have moved).
331 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
332 if (lci == null)
333 {
334 // Each child position and rotation is given relative to the root.
335 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
336 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
337 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
338
339 // Save relative position for recomputing child's world position after moving linkset.
340 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
341 cPrim.LinksetInfo = lci;
342 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
343 }
344
345 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
346 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
347
348 if (cPrim.PhysShape.isNativeShape)
349 {
350 // A native shape is turning into a hull collision shape because native
351 // shapes are not shared so we have to hullify it so it will be tracked
352 // and freed at the correct time. This also solves the scaling problem
353 // (native shapes scaled but hull/meshes are assumed to not be).
354 // TODO: decide of the native shape can just be used in the compound shape.
355 // Use call to CreateGeomNonSpecial().
356 BulletShape saveShape = cPrim.PhysShape;
357 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
358 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
359 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
360 BulletShape newShape = cPrim.PhysShape;
361 cPrim.PhysShape = saveShape;
362 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot);
363 }
364 else
365 {
366 // For the shared shapes (meshes and hulls), just use the shape in the child.
367 // The reference count added here will be decremented when the compound shape
368 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
369 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
370 {
371 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
372 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
373 }
374 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot);
375 }
376 }
377 return false; // 'false' says to move onto the next child in the list
378 });
379
380 // With all of the linkset packed into the root prim, it has the mass of everyone.
381 LinksetMass = LinksetMass;
382 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
383 }
384 finally
385 {
386 Rebuilding = false;
387 }
388
389 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);
390
391 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets.
392 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
393 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
394
395 }
396}
397} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs
deleted file mode 100644
index 46ff99f..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSLinksetConstraints.cs
+++ /dev/null
@@ -1,316 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35public sealed class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 {
41 }
42
43 // When physical properties are changed the linkset needs to recalculate
44 // its internal properties.
45 // This is queued in the 'post taint' queue so the
46 // refresh will happen once after all the other taints are applied.
47 public override void Refresh(BSPhysObject requestor)
48 {
49 base.Refresh(requestor);
50
51 // Queue to happen after all the other taint processing
52 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
53 {
54 if (HasAnyChildren && IsRoot(requestor))
55 RecomputeLinksetConstraints();
56 });
57 }
58
59 // The object is going dynamic (physical). Do any setup necessary
60 // for a dynamic linkset.
61 // Only the state of the passed object can be modified. The rest of the linkset
62 // has not yet been fully constructed.
63 // Return 'true' if any properties updated on the passed object.
64 // Called at taint-time!
65 public override bool MakeDynamic(BSPhysObject child)
66 {
67 // What is done for each object in BSPrim is what we want.
68 return false;
69 }
70
71 // The object is going static (non-physical). Do any setup necessary for a static linkset.
72 // Return 'true' if any properties updated on the passed object.
73 // This doesn't normally happen -- OpenSim removes the objects from the physical
74 // world if it is a static linkset.
75 // Called at taint-time!
76 public override bool MakeStatic(BSPhysObject child)
77 {
78 // What is done for each object in BSPrim is what we want.
79 return false;
80 }
81
82 // Called at taint-time!!
83 public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
84 {
85 // Nothing to do for constraints on property updates
86 }
87
88 // Routine called when rebuilding the body of some member of the linkset.
89 // Destroy all the constraints have have been made to root and set
90 // up to rebuild the constraints before the next simulation step.
91 // Returns 'true' of something was actually removed and would need restoring
92 // Called at taint-time!!
93 public override bool RemoveBodyDependencies(BSPrim child)
94 {
95 bool ret = false;
96
97 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
98 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString());
99
100 lock (m_linksetActivityLock)
101 {
102 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
103 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
104 // Cause the constraints, et al to be rebuilt before the next simulation step.
105 Refresh(LinksetRoot);
106 }
107 return ret;
108 }
109
110 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
111 // this routine will restore the removed constraints.
112 // Called at taint-time!!
113 public override void RestoreBodyDependencies(BSPrim child)
114 {
115 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
116 }
117
118 // ================================================================
119
120 // Add a new child to the linkset.
121 // Called while LinkActivity is locked.
122 protected override void AddChildToLinkset(BSPhysObject child)
123 {
124 if (!HasChild(child))
125 {
126 m_children.Add(child);
127
128 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
129
130 // Cause constraints and assorted properties to be recomputed before the next simulation step.
131 Refresh(LinksetRoot);
132 }
133 return;
134 }
135
136 // Remove the specified child from the linkset.
137 // Safe to call even if the child is not really in my linkset.
138 protected override void RemoveChildFromLinkset(BSPhysObject child)
139 {
140 if (m_children.Remove(child))
141 {
142 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
143 BSPhysObject childx = child;
144
145 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
146 childx.LocalID,
147 rootx.LocalID, rootx.PhysBody.ptr.ToString(),
148 childx.LocalID, childx.PhysBody.ptr.ToString());
149
150 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
151 {
152 PhysicallyUnlinkAChildFromRoot(rootx, childx);
153 });
154 // See that the linkset parameters are recomputed at the end of the taint time.
155 Refresh(LinksetRoot);
156 }
157 else
158 {
159 // Non-fatal occurance.
160 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
161 }
162 return;
163 }
164
165 // Create a constraint between me (root of linkset) and the passed prim (the child).
166 // Called at taint time!
167 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
168 {
169 // Don't build the constraint when asked. Put it off until just before the simulation step.
170 Refresh(rootPrim);
171 }
172
173 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
174 {
175 // Zero motion for children so they don't interpolate
176 childPrim.ZeroMotion(true);
177
178 // Relative position normalized to the root prim
179 // Essentually a vector pointing from center of rootPrim to center of childPrim
180 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
181
182 // real world coordinate of midpoint between the two objects
183 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
184
185 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
186 rootPrim.LocalID,
187 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(),
188 childPrim.LocalID, childPrim.PhysBody.ptr.ToString(),
189 rootPrim.Position, childPrim.Position, midPoint);
190
191 // create a constraint that allows no freedom of movement between the two objects
192 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
193
194 BSConstraint6Dof constrain = new BSConstraint6Dof(
195 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
196 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
197
198 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
199 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
200 * of the objects.
201 * Code left for future programmers.
202 // ==================================================================================
203 // relative position normalized to the root prim
204 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
205 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
206
207 // relative rotation of the child to the parent
208 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
209 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
210
211 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
212 BS6DofConstraint constrain = new BS6DofConstraint(
213 PhysicsScene.World, rootPrim.Body, childPrim.Body,
214 OMV.Vector3.Zero,
215 OMV.Quaternion.Inverse(rootPrim.Orientation),
216 OMV.Vector3.Zero,
217 OMV.Quaternion.Inverse(childPrim.Orientation),
218 true,
219 true
220 );
221 // ==================================================================================
222 */
223
224 PhysicsScene.Constraints.AddConstraint(constrain);
225
226 // zero linear and angular limits makes the objects unable to move in relation to each other
227 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
228 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
229
230 // tweek the constraint to increase stability
231 constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
232 constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
233 BSParam.LinkConstraintTransMotorMaxVel,
234 BSParam.LinkConstraintTransMotorMaxForce);
235 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
236 if (BSParam.LinkConstraintSolverIterations != 0f)
237 {
238 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
239 }
240 return constrain;
241 }
242
243 // Remove linkage between the linkset root and a particular child
244 // The root and child bodies are passed in because we need to remove the constraint between
245 // the bodies that were present at unlink time.
246 // Called at taint time!
247 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
248 {
249 bool ret = false;
250 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
251 rootPrim.LocalID,
252 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString(),
253 childPrim.LocalID, childPrim.PhysBody.ptr.ToString());
254
255 // Find the constraint for this link and get rid of it from the overall collection and from my list
256 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
257 {
258 // Make the child refresh its location
259 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr);
260 ret = true;
261 }
262
263 return ret;
264 }
265
266 // Remove linkage between myself and any possible children I might have.
267 // Returns 'true' of any constraints were destroyed.
268 // Called at taint time!
269 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
270 {
271 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
272
273 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
274 }
275
276 // Call each of the constraints that make up this linkset and recompute the
277 // various transforms and variables. Create constraints of not created yet.
278 // Called before the simulation step to make sure the constraint based linkset
279 // is all initialized.
280 // Called at taint time!!
281 private void RecomputeLinksetConstraints()
282 {
283 float linksetMass = LinksetMass;
284 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
285
286 // DEBUG: see of inter-linkset collisions are causing problems
287 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
288 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
289 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
290 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString(), linksetMass);
291
292 foreach (BSPhysObject child in m_children)
293 {
294 // A child in the linkset physically shows the mass of the whole linkset.
295 // This allows Bullet to apply enough force on the child to move the whole linkset.
296 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
297 child.UpdatePhysicalMassProperties(linksetMass, true);
298
299 BSConstraint constrain;
300 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
301 {
302 // If constraint doesn't exist yet, create it.
303 constrain = BuildConstraint(LinksetRoot, child);
304 }
305 constrain.RecomputeConstraintVariables(linksetMass);
306
307 // DEBUG: see of inter-linkset collisions are causing problems
308 // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr,
309 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
310
311 // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG
312 }
313
314 }
315}
316}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs
deleted file mode 100644
index d7941b6..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSMaterials.cs
+++ /dev/null
@@ -1,200 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using System.Reflection;
31using Nini.Config;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35
36public 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
54 // Names must be in the order of the above enum.
55 // These names must coorespond to the lower case field names in the MaterialAttributes
56 // structure as reflection is used to select the field to put the value in.
57 public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
58
59 public MaterialAttributes(string t, float d, float f, float r)
60 {
61 type = t;
62 density = d;
63 friction = f;
64 restitution = r;
65 }
66 public string type;
67 public float density;
68 public float friction;
69 public float restitution;
70}
71
72public static class BSMaterials
73{
74 // Attributes for each material type
75 private static readonly MaterialAttributes[] Attributes;
76
77 // Map of material name to material type code
78 public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap;
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 // Map of name to type code.
86 MaterialMap = new Dictionary<string, MaterialAttributes.Material>();
87 MaterialMap.Add("Stone", MaterialAttributes.Material.Stone);
88 MaterialMap.Add("Metal", MaterialAttributes.Material.Metal);
89 MaterialMap.Add("Glass", MaterialAttributes.Material.Glass);
90 MaterialMap.Add("Wood", MaterialAttributes.Material.Wood);
91 MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh);
92 MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic);
93 MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber);
94 MaterialMap.Add("Light", MaterialAttributes.Material.Light);
95 MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar);
96 }
97
98 // This is where all the default material attributes are defined.
99 public static void InitializeFromDefaults(ConfigurationParameters parms)
100 {
101 // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
102 float dDensity = parms.defaultDensity;
103 float dFriction = parms.defaultFriction;
104 float dRestitution = parms.defaultRestitution;
105 Attributes[(int)MaterialAttributes.Material.Stone] =
106 new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
107 Attributes[(int)MaterialAttributes.Material.Metal] =
108 new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
109 Attributes[(int)MaterialAttributes.Material.Glass] =
110 new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
111 Attributes[(int)MaterialAttributes.Material.Wood] =
112 new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
113 Attributes[(int)MaterialAttributes.Material.Flesh] =
114 new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
115 Attributes[(int)MaterialAttributes.Material.Plastic] =
116 new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
117 Attributes[(int)MaterialAttributes.Material.Rubber] =
118 new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
119 Attributes[(int)MaterialAttributes.Material.Light] =
120 new MaterialAttributes("light",dDensity, dFriction, dRestitution);
121 Attributes[(int)MaterialAttributes.Material.Avatar] =
122 new MaterialAttributes("avatar",3.5f, 0.2f, 0f);
123
124 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
125 new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
126 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
127 new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f);
128 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
129 new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f);
130 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
131 new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f);
132 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
133 new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f);
134 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
135 new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f);
136 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
137 new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f);
138 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
139 new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
140 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
141 new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f);
142 }
143
144 // Under the [BulletSim] section, one can change the individual material
145 // attribute values. The format of the configuration parameter is:
146 // <materialName><Attribute>["Physical"] = floatValue
147 // For instance:
148 // [BulletSim]
149 // StoneFriction = 0.2
150 // FleshRestitutionPhysical = 0.8
151 // Materials can have different parameters for their static and
152 // physical instantiations. When setting the non-physical value,
153 // both values are changed. Setting the physical value only changes
154 // the physical value.
155 public static void InitializefromParameters(IConfig pConfig)
156 {
157 foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap)
158 {
159 string matName = kvp.Key;
160 foreach (string attribName in MaterialAttributes.MaterialAttribs)
161 {
162 string paramName = matName + attribName;
163 if (pConfig.Contains(paramName))
164 {
165 float paramValue = pConfig.GetFloat(paramName);
166 SetAttributeValue((int)kvp.Value, attribName, paramValue);
167 // set the physical value also
168 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
169 }
170 paramName += "Physical";
171 if (pConfig.Contains(paramName))
172 {
173 float paramValue = pConfig.GetFloat(paramName);
174 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
175 }
176 }
177 }
178 }
179
180 // Use reflection to set the value in the attribute structure.
181 private static void SetAttributeValue(int matType, string attribName, float val)
182 {
183 MaterialAttributes thisAttrib = Attributes[matType];
184 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
185 if (fieldInfo != null)
186 {
187 fieldInfo.SetValue(thisAttrib, val);
188 Attributes[matType] = thisAttrib;
189 }
190 }
191
192 // Given a material type, return a structure of attributes.
193 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
194 {
195 int ind = (int)type;
196 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
197 return Attributes[ind];
198 }
199}
200}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs
deleted file mode 100644
index 7abc9b2..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSMotors.cs
+++ /dev/null
@@ -1,347 +0,0 @@
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 copyright
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 */
28using System;
29using System.Collections.Generic;
30using System.Text;
31using OpenMetaverse;
32using OpenSim.Framework;
33
34namespace OpenSim.Region.Physics.BulletSNPlugin
35{
36public abstract class BSMotor
37{
38 // Timescales and other things can be turned off by setting them to 'infinite'.
39 public const float Infinite = 12345.6f;
40 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
41
42 public BSMotor(string useName)
43 {
44 UseName = useName;
45 PhysicsScene = null;
46 Enabled = true;
47 }
48 public virtual bool Enabled { get; set; }
49 public virtual void Reset() { }
50 public virtual void Zero() { }
51 public virtual void GenerateTestOutput(float timeStep) { }
52
53 // A name passed at motor creation for easily identifyable debugging messages.
54 public string UseName { get; private set; }
55
56 // Used only for outputting debug information. Might not be set so check for null.
57 public BSScene PhysicsScene { get; set; }
58 protected void MDetailLog(string msg, params Object[] parms)
59 {
60 if (PhysicsScene != null)
61 {
62 if (PhysicsScene.VehicleLoggingEnabled)
63 {
64 PhysicsScene.DetailLog(msg, parms);
65 }
66 }
67 }
68}
69
70// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
71// The TargetValue decays in TargetValueDecayTimeScale and
72// the CurrentValue will be held back by FrictionTimeScale.
73// This motor will "zero itself" over time in that the targetValue will
74// decay to zero and the currentValue will follow it to that zero.
75// The overall effect is for the returned correction value to go from large
76// values (the total difference between current and target minus friction)
77// to small and eventually zero values.
78// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
79
80// For instance, if something is moving at speed X and the desired speed is Y,
81// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
82// values of CurrentValue are returned that approach the TargetValue.
83// The feature of decaying TargetValue is so vehicles will eventually
84// come to a stop rather than run forever. This can be disabled by
85// setting TargetValueDecayTimescale to 'infinite'.
86// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
87public class BSVMotor : BSMotor
88{
89 // public Vector3 FrameOfReference { get; set; }
90 // public Vector3 Offset { get; set; }
91
92 public virtual float TimeScale { get; set; }
93 public virtual float TargetValueDecayTimeScale { get; set; }
94 public virtual Vector3 FrictionTimescale { get; set; }
95 public virtual float Efficiency { get; set; }
96
97 public virtual float ErrorZeroThreshold { get; set; }
98
99 public virtual Vector3 TargetValue { get; protected set; }
100 public virtual Vector3 CurrentValue { get; protected set; }
101 public virtual Vector3 LastError { get; protected set; }
102
103 public virtual bool ErrorIsZero
104 { get {
105 return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold);
106 }
107 }
108
109 public BSVMotor(string useName)
110 : base(useName)
111 {
112 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
113 Efficiency = 1f;
114 FrictionTimescale = BSMotor.InfiniteVector;
115 CurrentValue = TargetValue = Vector3.Zero;
116 ErrorZeroThreshold = 0.001f;
117 }
118 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
119 : this(useName)
120 {
121 TimeScale = timeScale;
122 TargetValueDecayTimeScale = decayTimeScale;
123 FrictionTimescale = frictionTimeScale;
124 Efficiency = efficiency;
125 CurrentValue = TargetValue = Vector3.Zero;
126 }
127 public void SetCurrent(Vector3 current)
128 {
129 CurrentValue = current;
130 }
131 public void SetTarget(Vector3 target)
132 {
133 TargetValue = target;
134 }
135 public override void Zero()
136 {
137 base.Zero();
138 CurrentValue = TargetValue = Vector3.Zero;
139 }
140
141 // Compute the next step and return the new current value
142 public virtual Vector3 Step(float timeStep)
143 {
144 if (!Enabled) return TargetValue;
145
146 Vector3 origTarget = TargetValue; // DEBUG
147 Vector3 origCurrVal = CurrentValue; // DEBUG
148
149 Vector3 correction = Vector3.Zero;
150 Vector3 error = TargetValue - CurrentValue;
151 if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
152 {
153 correction = Step(timeStep, error);
154
155 CurrentValue += correction;
156
157 // The desired value reduces to zero which also reduces the difference with current.
158 // If the decay time is infinite, don't decay at all.
159 float decayFactor = 0f;
160 if (TargetValueDecayTimeScale != BSMotor.Infinite)
161 {
162 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
163 TargetValue *= (1f - decayFactor);
164 }
165
166 // The amount we can correct the error is reduced by the friction
167 Vector3 frictionFactor = Vector3.Zero;
168 if (FrictionTimescale != BSMotor.InfiniteVector)
169 {
170 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
171 // Individual friction components can be 'infinite' so compute each separately.
172 frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
173 frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
174 frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
175 frictionFactor *= timeStep;
176 CurrentValue *= (Vector3.One - frictionFactor);
177 }
178
179 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
180 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
181 timeStep, error, correction);
182 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
183 BSScene.DetailLogZero, UseName,
184 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
185 TargetValue, CurrentValue);
186 }
187 else
188 {
189 // Difference between what we have and target is small. Motor is done.
190 CurrentValue = TargetValue;
191 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
192 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
193 }
194
195 return CurrentValue;
196 }
197 public virtual Vector3 Step(float timeStep, Vector3 error)
198 {
199 if (!Enabled) return Vector3.Zero;
200
201 LastError = error;
202 Vector3 returnCorrection = Vector3.Zero;
203 if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
204 {
205 // correction = error / secondsItShouldTakeToCorrect
206 Vector3 correctionAmount;
207 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
208 correctionAmount = error * timeStep;
209 else
210 correctionAmount = error / TimeScale * timeStep;
211
212 returnCorrection = correctionAmount;
213 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
214 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
215 }
216 return returnCorrection;
217 }
218
219 // The user sets all the parameters and calls this which outputs values until error is zero.
220 public override void GenerateTestOutput(float timeStep)
221 {
222 // maximum number of outputs to generate.
223 int maxOutput = 50;
224 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
225 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}",
226 BSScene.DetailLogZero, UseName,
227 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency,
228 CurrentValue, TargetValue);
229
230 LastError = BSMotor.InfiniteVector;
231 while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
232 {
233 Vector3 lastStep = Step(timeStep);
234 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
235 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
236 }
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
238
239
240 }
241
242 public override string ToString()
243 {
244 return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
245 UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale);
246 }
247}
248
249public class BSFMotor : BSMotor
250{
251 public float TimeScale { get; set; }
252 public float DecayTimeScale { get; set; }
253 public float Friction { get; set; }
254 public float Efficiency { get; set; }
255
256 public float Target { get; private set; }
257 public float CurrentValue { get; private set; }
258
259 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
260 : base(useName)
261 {
262 }
263 public void SetCurrent(float target)
264 {
265 }
266 public void SetTarget(float target)
267 {
268 }
269 public virtual float Step(float timeStep)
270 {
271 return 0f;
272 }
273}
274
275// Proportional, Integral, Derivitive Motor
276// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
277public class BSPIDVMotor : BSVMotor
278{
279 // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
280 public Vector3 proportionFactor { get; set; }
281 public Vector3 integralFactor { get; set; }
282 public Vector3 derivFactor { get; set; }
283
284 // Arbritrary factor range.
285 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
286 public float EfficiencyHigh = 0.4f;
287 public float EfficiencyLow = 4.0f;
288
289 // Running integration of the error
290 Vector3 RunningIntegration { get; set; }
291
292 public BSPIDVMotor(string useName)
293 : base(useName)
294 {
295 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
296 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
297 derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
298 RunningIntegration = Vector3.Zero;
299 LastError = Vector3.Zero;
300 }
301
302 public override void Zero()
303 {
304 base.Zero();
305 }
306
307 public override float Efficiency
308 {
309 get { return base.Efficiency; }
310 set
311 {
312 base.Efficiency = Util.Clamp(value, 0f, 1f);
313 // Compute factors based on efficiency.
314 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
315 // If efficiency is low (0f), use a factor value that overcorrects.
316 // TODO: might want to vary contribution of different factor depending on efficiency.
317 float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
318 // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
319 proportionFactor = new Vector3(factor, factor, factor);
320 integralFactor = new Vector3(factor, factor, factor);
321 derivFactor = new Vector3(factor, factor, factor);
322 }
323 }
324
325 // Ignore Current and Target Values and just advance the PID computation on this error.
326 public override Vector3 Step(float timeStep, Vector3 error)
327 {
328 if (!Enabled) return Vector3.Zero;
329
330 // Add up the error so we can integrate over the accumulated errors
331 RunningIntegration += error * timeStep;
332
333 // A simple derivitive is the rate of change from the last error.
334 Vector3 derivFactor = (error - LastError) * timeStep;
335 LastError = error;
336
337 // Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
338 Vector3 ret = -(
339 error * proportionFactor
340 + RunningIntegration * integralFactor
341 + derivFactor * derivFactor
342 );
343
344 return ret;
345 }
346}
347}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs
deleted file mode 100644
index 5e93a03..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSParam.cs
+++ /dev/null
@@ -1,559 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Region.Physics.Manager;
32
33using OpenMetaverse;
34using Nini.Config;
35
36namespace OpenSim.Region.Physics.BulletSNPlugin
37{
38public static class BSParam
39{
40 // Level of Detail values kept as float because that's what the Meshmerizer wants
41 public static float MeshLOD { get; private set; }
42 public static float MeshMegaPrimLOD { get; private set; }
43 public static float MeshMegaPrimThreshold { get; private set; }
44 public static float SculptLOD { get; private set; }
45
46 public static float MinimumObjectMass { get; private set; }
47 public static float MaximumObjectMass { get; private set; }
48
49 public static float LinearDamping { get; private set; }
50 public static float AngularDamping { get; private set; }
51 public static float DeactivationTime { get; private set; }
52 public static float LinearSleepingThreshold { get; private set; }
53 public static float AngularSleepingThreshold { get; private set; }
54 public static float CcdMotionThreshold { get; private set; }
55 public static float CcdSweptSphereRadius { get; private set; }
56 public static float ContactProcessingThreshold { get; private set; }
57
58 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
59 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
60 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
61
62 public static float TerrainImplementation { get; private set; }
63 public static float TerrainFriction { get; private set; }
64 public static float TerrainHitFraction { get; private set; }
65 public static float TerrainRestitution { get; private set; }
66 public static float TerrainCollisionMargin { get; private set; }
67
68 // Avatar parameters
69 public static float AvatarFriction { get; private set; }
70 public static float AvatarStandingFriction { get; private set; }
71 public static float AvatarDensity { get; private set; }
72 public static float AvatarRestitution { get; private set; }
73 public static float AvatarCapsuleWidth { get; private set; }
74 public static float AvatarCapsuleDepth { get; private set; }
75 public static float AvatarCapsuleHeight { get; private set; }
76 public static float AvatarContactProcessingThreshold { get; private set; }
77
78 public static float VehicleAngularDamping { get; private set; }
79
80 public static float LinksetImplementation { get; private set; }
81 public static float LinkConstraintUseFrameOffset { get; private set; }
82 public static float LinkConstraintEnableTransMotor { get; private set; }
83 public static float LinkConstraintTransMotorMaxVel { get; private set; }
84 public static float LinkConstraintTransMotorMaxForce { get; private set; }
85 public static float LinkConstraintERP { get; private set; }
86 public static float LinkConstraintCFM { get; private set; }
87 public static float LinkConstraintSolverIterations { get; private set; }
88
89 public static float PID_D { get; private set; } // derivative
90 public static float PID_P { get; private set; } // proportional
91
92 public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
93 public delegate float ParamGet(BSScene scene);
94 public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
95 public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
96
97 public struct ParameterDefn
98 {
99 public string name; // string name of the parameter
100 public string desc; // a short description of what the parameter means
101 public float defaultValue; // default value if not specified anywhere else
102 public ParamUser userParam; // get the value from the configuration file
103 public ParamGet getter; // return the current value stored for this parameter
104 public ParamSet setter; // set the current value for this parameter
105 public SetOnObject onObject; // set the value on an object in the physical domain
106 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
107 {
108 name = n;
109 desc = d;
110 defaultValue = v;
111 userParam = u;
112 getter = g;
113 setter = s;
114 onObject = null;
115 }
116 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
117 {
118 name = n;
119 desc = d;
120 defaultValue = v;
121 userParam = u;
122 getter = g;
123 setter = s;
124 onObject = o;
125 }
126 }
127
128 // List of all of the externally visible parameters.
129 // For each parameter, this table maps a text name to getter and setters.
130 // To add a new externally referencable/settable parameter, add the paramter storage
131 // location somewhere in the program and make an entry in this table with the
132 // getters and setters.
133 // It is easiest to find an existing definition and copy it.
134 // Parameter values are floats. Booleans are converted to a floating value.
135 //
136 // A ParameterDefn() takes the following parameters:
137 // -- the text name of the parameter. This is used for console input and ini file.
138 // -- a short text description of the parameter. This shows up in the console listing.
139 // -- a default value (float)
140 // -- a delegate for fetching the parameter from the ini file.
141 // Should handle fetching the right type from the ini file and converting it.
142 // -- a delegate for getting the value as a float
143 // -- a delegate for setting the value from a float
144 // -- an optional delegate to update the value in the world. Most often used to
145 // push the new value to an in-world object.
146 //
147 // The single letter parameters for the delegates are:
148 // s = BSScene
149 // o = BSPhysObject
150 // p = string parameter name
151 // l = localID of referenced object
152 // v = value (float)
153 // cf = parameter configuration class (for fetching values from ini file)
154 private static ParameterDefn[] ParameterDefinitions =
155 {
156 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
157 ConfigurationParameters.numericTrue,
158 (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
159 (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); },
160 (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ),
161 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
162 ConfigurationParameters.numericFalse,
163 (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
164 (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); },
165 (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ),
166 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
167 ConfigurationParameters.numericTrue,
168 (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
169 (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
170 (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
171
172 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
173 8f,
174 (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); },
175 (s) => { return MeshLOD; },
176 (s,p,l,v) => { MeshLOD = v; } ),
177 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
178 16f,
179 (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
180 (s) => { return MeshMegaPrimLOD; },
181 (s,p,l,v) => { MeshMegaPrimLOD = v; } ),
182 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
183 10f,
184 (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
185 (s) => { return MeshMegaPrimThreshold; },
186 (s,p,l,v) => { MeshMegaPrimThreshold = v; } ),
187 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
188 32f,
189 (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); },
190 (s) => { return SculptLOD; },
191 (s,p,l,v) => { SculptLOD = v; } ),
192
193 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
194 10f,
195 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
196 (s) => { return (float)s.m_maxSubSteps; },
197 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
198 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
199 1f / 60f,
200 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
201 (s) => { return (float)s.m_fixedTimeStep; },
202 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
203 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
204 2048f,
205 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
206 (s) => { return (float)s.m_maxCollisionsPerFrame; },
207 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
208 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
209 8000f,
210 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
211 (s) => { return (float)s.m_maxUpdatesPerFrame; },
212 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
213 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
214 500f,
215 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
216 (s) => { return (float)s.m_taintsToProcessPerStep; },
217 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
218 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
219 0.0001f,
220 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
221 (s) => { return (float)MinimumObjectMass; },
222 (s,p,l,v) => { MinimumObjectMass = v; } ),
223 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
224 10000.01f,
225 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
226 (s) => { return (float)MaximumObjectMass; },
227 (s,p,l,v) => { MaximumObjectMass = v; } ),
228
229 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
230 2200f,
231 (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); },
232 (s) => { return (float)PID_D; },
233 (s,p,l,v) => { PID_D = v; } ),
234 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
235 900f,
236 (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); },
237 (s) => { return (float)PID_P; },
238 (s,p,l,v) => { PID_P = v; } ),
239
240 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
241 0.2f,
242 (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); },
243 (s) => { return s.UnmanagedParams[0].defaultFriction; },
244 (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ),
245 new ParameterDefn("DefaultDensity", "Density for new objects" ,
246 10.000006836f, // Aluminum g/cm3
247 (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); },
248 (s) => { return s.UnmanagedParams[0].defaultDensity; },
249 (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ),
250 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
251 0f,
252 (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); },
253 (s) => { return s.UnmanagedParams[0].defaultRestitution; },
254 (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ),
255 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
256 0.04f,
257 (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); },
258 (s) => { return s.UnmanagedParams[0].collisionMargin; },
259 (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ),
260 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
261 -9.80665f,
262 (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); },
263 (s) => { return s.UnmanagedParams[0].gravity; },
264 (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); },
265 (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
266
267
268 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
269 0f,
270 (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); },
271 (s) => { return LinearDamping; },
272 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); },
273 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, AngularDamping); } ),
274 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
275 0f,
276 (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); },
277 (s) => { return AngularDamping; },
278 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); },
279 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, LinearDamping, v); } ),
280 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
281 0.2f,
282 (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); },
283 (s) => { return DeactivationTime; },
284 (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); },
285 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
286 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
287 0.8f,
288 (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); },
289 (s) => { return LinearSleepingThreshold; },
290 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); },
291 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
292 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
293 1.0f,
294 (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); },
295 (s) => { return AngularSleepingThreshold; },
296 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); },
297 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
298 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
299 0f, // set to zero to disable
300 (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); },
301 (s) => { return CcdMotionThreshold; },
302 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); },
303 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
304 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
305 0f,
306 (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); },
307 (s) => { return CcdSweptSphereRadius; },
308 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); },
309 (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
310 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
311 0.1f,
312 (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); },
313 (s) => { return ContactProcessingThreshold; },
314 (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); },
315 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
316
317 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
318 (float)BSTerrainPhys.TerrainImplementation.Heightmap,
319 (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); },
320 (s) => { return TerrainImplementation; },
321 (s,p,l,v) => { TerrainImplementation = v; } ),
322 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
323 0.3f,
324 (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); },
325 (s) => { return TerrainFriction; },
326 (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
327 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
328 0.8f,
329 (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); },
330 (s) => { return TerrainHitFraction; },
331 (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
332 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
333 0f,
334 (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); },
335 (s) => { return TerrainRestitution; },
336 (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
337 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
338 0.04f,
339 (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); },
340 (s) => { return TerrainCollisionMargin; },
341 (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
342
343 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
344 0.2f,
345 (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); },
346 (s) => { return AvatarFriction; },
347 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ),
348 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
349 10.0f,
350 (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
351 (s) => { return AvatarStandingFriction; },
352 (s,p,l,v) => { AvatarStandingFriction = v; } ),
353 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
354 3.5f,
355 (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); },
356 (s) => { return AvatarDensity; },
357 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ),
358 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
359 0f,
360 (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); },
361 (s) => { return AvatarRestitution; },
362 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ),
363 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
364 0.6f,
365 (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); },
366 (s) => { return AvatarCapsuleWidth; },
367 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ),
368 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
369 0.45f,
370 (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); },
371 (s) => { return AvatarCapsuleDepth; },
372 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ),
373 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
374 1.5f,
375 (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); },
376 (s) => { return AvatarCapsuleHeight; },
377 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ),
378 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
379 0.1f,
380 (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); },
381 (s) => { return AvatarContactProcessingThreshold; },
382 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ),
383
384 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
385 0.95f,
386 (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
387 (s) => { return VehicleAngularDamping; },
388 (s,p,l,v) => { VehicleAngularDamping = v; } ),
389
390 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
391 0f,
392 (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
393 (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; },
394 (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
395 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
396 0f,
397 (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
398 (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; },
399 (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
400 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
401 ConfigurationParameters.numericFalse,
402 (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
403 (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; },
404 (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ),
405 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
406 ConfigurationParameters.numericFalse,
407 (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
408 (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; },
409 (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ),
410 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
411 ConfigurationParameters.numericTrue,
412 (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
413 (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; },
414 (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ),
415 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
416 ConfigurationParameters.numericTrue,
417 (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
418 (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; },
419 (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ),
420 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
421 ConfigurationParameters.numericFalse,
422 (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
423 (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; },
424 (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ),
425 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
426 0f, // zero says use Bullet default
427 (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); },
428 (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; },
429 (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
430
431 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
432 (float)BSLinkset.LinksetImplementation.Compound,
433 (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); },
434 (s) => { return LinksetImplementation; },
435 (s,p,l,v) => { LinksetImplementation = v; } ),
436 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
437 ConfigurationParameters.numericFalse,
438 (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
439 (s) => { return LinkConstraintUseFrameOffset; },
440 (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ),
441 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
442 ConfigurationParameters.numericTrue,
443 (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
444 (s) => { return LinkConstraintEnableTransMotor; },
445 (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ),
446 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
447 5.0f,
448 (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
449 (s) => { return LinkConstraintTransMotorMaxVel; },
450 (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ),
451 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
452 0.1f,
453 (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
454 (s) => { return LinkConstraintTransMotorMaxForce; },
455 (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ),
456 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
457 0.1f,
458 (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); },
459 (s) => { return LinkConstraintCFM; },
460 (s,p,l,v) => { LinkConstraintCFM = v; } ),
461 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
462 0.1f,
463 (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); },
464 (s) => { return LinkConstraintERP; },
465 (s,p,l,v) => { LinkConstraintERP = v; } ),
466 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
467 40,
468 (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); },
469 (s) => { return LinkConstraintSolverIterations; },
470 (s,p,l,v) => { LinkConstraintSolverIterations = v; } ),
471
472 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
473 0f,
474 (s,cf,p,v) => { s.UnmanagedParams[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
475 (s) => { return (float)s.UnmanagedParams[0].physicsLoggingFrames; },
476 (s,p,l,v) => { s.UnmanagedParams[0].physicsLoggingFrames = (int)v; } ),
477 };
478
479 // Convert a boolean to our numeric true and false values
480 public static float NumericBool(bool b)
481 {
482 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
483 }
484
485 // Convert numeric true and false values to a boolean
486 public static bool BoolNumeric(float b)
487 {
488 return (b == ConfigurationParameters.numericTrue ? true : false);
489 }
490
491 // Search through the parameter definitions and return the matching
492 // ParameterDefn structure.
493 // Case does not matter as names are compared after converting to lower case.
494 // Returns 'false' if the parameter is not found.
495 internal static bool TryGetParameter(string paramName, out ParameterDefn defn)
496 {
497 bool ret = false;
498 ParameterDefn foundDefn = new ParameterDefn();
499 string pName = paramName.ToLower();
500
501 foreach (ParameterDefn parm in ParameterDefinitions)
502 {
503 if (pName == parm.name.ToLower())
504 {
505 foundDefn = parm;
506 ret = true;
507 break;
508 }
509 }
510 defn = foundDefn;
511 return ret;
512 }
513
514 // Pass through the settable parameters and set the default values
515 internal static void SetParameterDefaultValues(BSScene physicsScene)
516 {
517 foreach (ParameterDefn parm in ParameterDefinitions)
518 {
519 parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
520 }
521 }
522
523 // Get user set values out of the ini file.
524 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
525 {
526 foreach (ParameterDefn parm in ParameterDefinitions)
527 {
528 parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue);
529 }
530 }
531
532 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
533
534 // This creates an array in the correct format for returning the list of
535 // parameters. This is used by the 'list' option of the 'physics' command.
536 internal static void BuildParameterTable()
537 {
538 if (SettableParameters.Length < ParameterDefinitions.Length)
539 {
540 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
541 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
542 {
543 ParameterDefn pd = ParameterDefinitions[ii];
544 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
545 }
546
547 // make the list in alphabetical order for estetic reasons
548 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
549 {
550 return ppe1.name.CompareTo(ppe2.name);
551 });
552
553 SettableParameters = entries.ToArray();
554 }
555 }
556
557
558}
559}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs
deleted file mode 100644
index 689da7f..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs
+++ /dev/null
@@ -1,346 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37/*
38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant.
41 *
42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time.
47 */
48
49/*
50 * As of 20121221, the following are the call sequences (going down) for different script physical functions:
51 * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque
56 */
57
58public abstract class BSPhysObject : PhysicsActor
59{
60 protected BSPhysObject()
61 {
62 }
63 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
64 {
65 PhysicsScene = parentScene;
66 LocalID = localID;
67 PhysObjectName = name;
68 TypeName = typeName;
69
70 Linkset = BSLinkset.Factory(PhysicsScene, this);
71 LastAssetBuildFailed = false;
72
73 // Default material type
74 Material = MaterialAttributes.Material.Wood;
75
76 CollisionCollection = new CollisionEventUpdate();
77 SubscribedEventsMs = 0;
78 CollidingStep = 0;
79 CollidingGroundStep = 0;
80 }
81
82 // Tell the object to clean up.
83 public virtual void Destroy()
84 {
85 UnRegisterAllPreStepActions();
86 }
87
88 public BSScene PhysicsScene { get; protected set; }
89 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
90 public string PhysObjectName { get; protected set; }
91 public string TypeName { get; protected set; }
92
93 public BSLinkset Linkset { get; set; }
94 public BSLinksetInfo LinksetInfo { get; set; }
95
96 // Return the object mass without calculating it or having side effects
97 public abstract float RawMass { get; }
98 // Set the raw mass but also update physical mass properties (inertia, ...)
99 // 'inWorld' true if the object has already been added to the dynamic world.
100 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
101
102 // The last value calculated for the prim's inertia
103 public OMV.Vector3 Inertia { get; set; }
104
105 // Reference to the physical body (btCollisionObject) of this object
106 public BulletBody PhysBody;
107 // Reference to the physical shape (btCollisionShape) of this object
108 public BulletShape PhysShape;
109
110 // 'true' if the mesh's underlying asset failed to build.
111 // This will keep us from looping after the first time the build failed.
112 public bool LastAssetBuildFailed { get; set; }
113
114 // The objects base shape information. Null if not a prim type shape.
115 public PrimitiveBaseShape BaseShape { get; protected set; }
116 // Some types of objects have preferred physical representations.
117 // Returns SHAPE_UNKNOWN if there is no preference.
118 public virtual BSPhysicsShapeType PreferredPhysicalShape
119 {
120 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
121 }
122
123 // When the physical properties are updated, an EntityProperty holds the update values.
124 // Keep the current and last EntityProperties to enable computation of differences
125 // between the current update and the previous values.
126 public EntityProperties CurrentEntityProperties { get; set; }
127 public EntityProperties LastEntityProperties { get; set; }
128
129 public virtual OMV.Vector3 Scale { get; set; }
130 public abstract bool IsSolid { get; }
131 public abstract bool IsStatic { get; }
132
133 // Materialness
134 public MaterialAttributes.Material Material { get; private set; }
135 public override void SetMaterial(int material)
136 {
137 Material = (MaterialAttributes.Material)material;
138 }
139
140 // Stop all physical motion.
141 public abstract void ZeroMotion(bool inTaintTime);
142 public abstract void ZeroAngularMotion(bool inTaintTime);
143
144 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
145 public virtual void StepVehicle(float timeStep) { }
146
147 // Update the physical location and motion of the object. Called with data from Bullet.
148 public abstract void UpdateProperties(EntityProperties entprop);
149
150 public abstract OMV.Vector3 RawPosition { get; set; }
151 public abstract OMV.Vector3 ForcePosition { get; set; }
152
153 public abstract OMV.Quaternion RawOrientation { get; set; }
154 public abstract OMV.Quaternion ForceOrientation { get; set; }
155
156 // The system is telling us the velocity it wants to move at.
157 // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
158 public override OMV.Vector3 TargetVelocity
159 {
160 get { return m_targetVelocity; }
161 set
162 {
163 m_targetVelocity = value;
164 Velocity = value;
165 }
166 }
167 public abstract OMV.Vector3 ForceVelocity { get; set; }
168
169 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
170
171 public abstract float ForceBuoyancy { get; set; }
172
173 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
174
175 #region Collisions
176
177 // Requested number of milliseconds between collision events. Zero means disabled.
178 protected int SubscribedEventsMs { get; set; }
179 // Given subscription, the time that a collision may be passed up
180 protected int NextCollisionOkTime { get; set; }
181 // The simulation step that last had a collision
182 protected long CollidingStep { get; set; }
183 // The simulation step that last had a collision with the ground
184 protected long CollidingGroundStep { get; set; }
185 // The collision flags we think are set in Bullet
186 protected CollisionFlags CurrentCollisionFlags { get; set; }
187
188 // The collisions that have been collected this tick
189 protected CollisionEventUpdate CollisionCollection;
190
191 // The simulation step is telling this object about a collision.
192 // Return 'true' if a collision was processed and should be sent up.
193 // Called at taint time from within the Step() function
194 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
195 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
196 {
197 bool ret = false;
198
199 // The following lines make IsColliding() and IsCollidingGround() work
200 CollidingStep = PhysicsScene.SimulationStep;
201 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
202 {
203 CollidingGroundStep = PhysicsScene.SimulationStep;
204 }
205
206 // prims in the same linkset cannot collide with each other
207 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
208 {
209 return ret;
210 }
211
212 // if someone has subscribed for collision events....
213 if (SubscribedEvents()) {
214 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
215 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
216 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
217
218 ret = true;
219 }
220 return ret;
221 }
222
223 // Send the collected collisions into the simulator.
224 // Called at taint time from within the Step() function thus no locking problems
225 // with CollisionCollection and ObjectsWithNoMoreCollisions.
226 // Return 'true' if there were some actual collisions passed up
227 public virtual bool SendCollisions()
228 {
229 bool ret = true;
230 // If the 'no collision' call, force it to happen right now so quick collision_end
231 bool force = (CollisionCollection.Count == 0);
232
233 // throttle the collisions to the number of milliseconds specified in the subscription
234 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
235 {
236 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
237
238 // We are called if we previously had collisions. If there are no collisions
239 // this time, send up one last empty event so OpenSim can sense collision end.
240 if (CollisionCollection.Count == 0)
241 {
242 // If I have no collisions this time, remove me from the list of objects with collisions.
243 ret = false;
244 }
245
246 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
247 base.SendCollisionUpdate(CollisionCollection);
248
249 // The CollisionCollection instance is passed around in the simulator.
250 // Make sure we don't have a handle to that one and that a new one is used for next time.
251 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
252 // a race condition is created for the other users of this instance.
253 CollisionCollection = new CollisionEventUpdate();
254 }
255 return ret;
256 }
257
258 // Subscribe for collision events.
259 // Parameter is the millisecond rate the caller wishes collision events to occur.
260 public override void SubscribeEvents(int ms) {
261 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
262 SubscribedEventsMs = ms;
263 if (ms > 0)
264 {
265 // make sure first collision happens
266 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
267
268 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
269 {
270 if (PhysBody.HasPhysicalBody)
271 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
272 });
273 }
274 else
275 {
276 // Subscribing for zero or less is the same as unsubscribing
277 UnSubscribeEvents();
278 }
279 }
280 public override void UnSubscribeEvents() {
281 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
282 SubscribedEventsMs = 0;
283 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
284 {
285 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
286 if (PhysBody.HasPhysicalBody)
287 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
288 });
289 }
290 // Return 'true' if the simulator wants collision events
291 public override bool SubscribedEvents() {
292 return (SubscribedEventsMs > 0);
293 }
294
295 #endregion // Collisions
296
297 #region Per Simulation Step actions
298 // There are some actions that must be performed for a physical object before each simulation step.
299 // These actions are optional so, rather than scanning all the physical objects and asking them
300 // if they have anything to do, a physical object registers for an event call before the step is performed.
301 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
302 private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
303 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
304 {
305 string identifier = op + "-" + id.ToString();
306 RegisteredActions[identifier] = actn;
307 PhysicsScene.BeforeStep += actn;
308 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
309 }
310
311 // Unregister a pre step action. Safe to call if the action has not been registered.
312 protected void UnRegisterPreStepAction(string op, uint id)
313 {
314 string identifier = op + "-" + id.ToString();
315 bool removed = false;
316 if (RegisteredActions.ContainsKey(identifier))
317 {
318 PhysicsScene.BeforeStep -= RegisteredActions[identifier];
319 RegisteredActions.Remove(identifier);
320 removed = true;
321 }
322 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
323 }
324
325 protected void UnRegisterAllPreStepActions()
326 {
327 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
328 {
329 PhysicsScene.BeforeStep -= kvp.Value;
330 }
331 RegisteredActions.Clear();
332 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
333 }
334
335
336 #endregion // Per Simulation Step actions
337
338 // High performance detailed logging routine used by the physical objects.
339 protected void DetailLog(string msg, params Object[] args)
340 {
341 if (PhysicsScene.PhysicsLogging.Enabled)
342 PhysicsScene.DetailLog(msg, args);
343 }
344
345}
346}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs
deleted file mode 100644
index 75963ee..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSPlugin.cs
+++ /dev/null
@@ -1,81 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using OpenSim.Framework;
30using OpenSim.Region.Physics.Manager;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
40 /// The unmanaged library is compiled and linked statically with Bullet
41 /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit).
42 /// </summary>
43public class BSPlugin : IPhysicsPlugin
44{
45 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
46
47 private BSScene _mScene;
48
49 public BSPlugin()
50 {
51 }
52
53 public bool Init()
54 {
55 return true;
56 }
57
58 public PhysicsScene GetScene(String sceneIdentifier)
59 {
60 if (_mScene == null)
61 {
62
63 // If not Windows, loading is performed by the
64 // Mono loader as specified in
65 // "bin/Physics/OpenSim.Region.Physics.BulletSNPlugin.dll.config".
66
67 _mScene = new BSScene(sceneIdentifier);
68 }
69 return (_mScene);
70 }
71
72 public string GetName()
73 {
74 return ("BulletSimN");
75 }
76
77 public void Dispose()
78 {
79 }
80}
81}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs
deleted file mode 100644
index aadb5b2..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs
+++ /dev/null
@@ -1,1494 +0,0 @@
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
28using System;
29using System.Reflection;
30using System.Collections.Generic;
31using System.Xml;
32using log4net;
33using OMV = OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Physics.Manager;
36using OpenSim.Region.Physics.ConvexDecompositionDotNet;
37
38namespace OpenSim.Region.Physics.BulletSNPlugin
39{
40
41 [Serializable]
42public sealed class BSPrim : BSPhysObject
43{
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 private static readonly string LogHeader = "[BULLETS PRIM]";
46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
49
50 private bool _grabbed;
51 private bool _isSelected;
52 private bool _isVolumeDetect;
53 private OMV.Vector3 _position;
54 private float _mass; // the mass of this object
55 private float _density;
56 private OMV.Vector3 _force;
57 private OMV.Vector3 _velocity;
58 private OMV.Vector3 _torque;
59 private float _collisionScore;
60 private OMV.Vector3 _acceleration;
61 private OMV.Quaternion _orientation;
62 private int _physicsActorType;
63 private bool _isPhysical;
64 private bool _flying;
65 private float _friction;
66 private float _restitution;
67 private bool _setAlwaysRun;
68 private bool _throttleUpdates;
69 private bool _isColliding;
70 private bool _collidingGround;
71 private bool _collidingObj;
72 private bool _floatOnWater;
73 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic;
75 private float _buoyancy;
76
77 private BSDynamics _vehicle;
78
79 private OMV.Vector3 _PIDTarget;
80 private bool _usePID;
81 private float _PIDTau;
82 private bool _useHoverPID;
83 private float _PIDHoverHeight;
84 private PIDHoverType _PIDHoverType;
85 private float _PIDHoverTao;
86
87 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
88 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
89 : base(parent_scene, localID, primName, "BSPrim")
90 {
91 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
92 _physicsActorType = (int)ActorTypes.Prim;
93 _position = pos;
94 _size = size;
95 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
96 _orientation = rotation;
97 _buoyancy = 1f;
98 _velocity = OMV.Vector3.Zero;
99 _rotationalVelocity = OMV.Vector3.Zero;
100 BaseShape = pbs;
101 _isPhysical = pisPhysical;
102 _isVolumeDetect = false;
103
104 // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
105 // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
106 _density = PhysicsScene.Params.defaultDensity;
107 _friction = PhysicsScene.Params.defaultFriction;
108 _restitution = PhysicsScene.Params.defaultRestitution;
109
110 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
111
112 _mass = CalculateMass();
113
114 Linkset.Refresh(this);
115
116 DetailLog("{0},BSPrim.constructor,call", LocalID);
117 // do the actual object creation at taint time
118 PhysicsScene.TaintedObject("BSPrim.create", delegate()
119 {
120 CreateGeomAndObject(true);
121
122 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr);
123 });
124 }
125
126 // called when this prim is being destroyed and we should free all the resources
127 public override void Destroy()
128 {
129 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
130 base.Destroy();
131
132 // Undo any links between me and any other object
133 BSPhysObject parentBefore = Linkset.LinksetRoot;
134 int childrenBefore = Linkset.NumberOfChildren;
135
136 Linkset = Linkset.RemoveMeFromLinkset(this);
137
138 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
139 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
140
141 // Undo any vehicle properties
142 this.VehicleType = (int)Vehicle.TYPE_NONE;
143
144 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
145 {
146 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
147 // If there are physical body and shape, release my use of same.
148 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
149 PhysBody.Clear();
150 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
151 PhysShape.Clear();
152 });
153 }
154
155 // No one uses this property.
156 public override bool Stopped {
157 get { return false; }
158 }
159 public override OMV.Vector3 Size {
160 get { return _size; }
161 set {
162 // We presume the scale and size are the same. If scale must be changed for
163 // the physical shape, that is done when the geometry is built.
164 _size = value;
165 Scale = _size;
166 ForceBodyShapeRebuild(false);
167 }
168 }
169
170 public override PrimitiveBaseShape Shape {
171 set {
172 BaseShape = value;
173 ForceBodyShapeRebuild(false);
174 }
175 }
176 // Whatever the linkset wants is what I want.
177 public override BSPhysicsShapeType PreferredPhysicalShape
178 { get { return Linkset.PreferredPhysicalShape(this); } }
179
180 public override bool ForceBodyShapeRebuild(bool inTaintTime)
181 {
182 LastAssetBuildFailed = false;
183 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
184 {
185 _mass = CalculateMass(); // changing the shape changes the mass
186 CreateGeomAndObject(true);
187 });
188 return true;
189 }
190 public override bool Grabbed {
191 set { _grabbed = value;
192 }
193 }
194 public override bool Selected {
195 set
196 {
197 if (value != _isSelected)
198 {
199 _isSelected = value;
200 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
201 {
202 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
203 SetObjectDynamic(false);
204 });
205 }
206 }
207 }
208 public override void CrossingFailure() { return; }
209
210 // link me to the specified parent
211 public override void link(PhysicsActor obj) {
212 BSPrim parent = obj as BSPrim;
213 if (parent != null)
214 {
215 BSPhysObject parentBefore = Linkset.LinksetRoot;
216 int childrenBefore = Linkset.NumberOfChildren;
217
218 Linkset = parent.Linkset.AddMeToLinkset(this);
219
220 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
221 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
222 }
223 return;
224 }
225
226 // delink me from my linkset
227 public override void delink() {
228 // TODO: decide if this parent checking needs to happen at taint time
229 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
230
231 BSPhysObject parentBefore = Linkset.LinksetRoot;
232 int childrenBefore = Linkset.NumberOfChildren;
233
234 Linkset = Linkset.RemoveMeFromLinkset(this);
235
236 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
237 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
238 return;
239 }
240
241 // Set motion values to zero.
242 // Do it to the properties so the values get set in the physics engine.
243 // Push the setting of the values to the viewer.
244 // Called at taint time!
245 public override void ZeroMotion(bool inTaintTime)
246 {
247 _velocity = OMV.Vector3.Zero;
248 _acceleration = OMV.Vector3.Zero;
249 _rotationalVelocity = OMV.Vector3.Zero;
250
251 // Zero some other properties in the physics engine
252 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
253 {
254 if (PhysBody.HasPhysicalBody)
255 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
256 });
257 }
258 public override void ZeroAngularMotion(bool inTaintTime)
259 {
260 _rotationalVelocity = OMV.Vector3.Zero;
261 // Zero some other properties in the physics engine
262 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
263 {
264 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
265 if (PhysBody.HasPhysicalBody)
266 {
267 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
268 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
269 }
270 });
271 }
272
273 public override void LockAngularMotion(OMV.Vector3 axis)
274 {
275 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
276 return;
277 }
278
279 public override OMV.Vector3 RawPosition
280 {
281 get { return _position; }
282 set { _position = value; }
283 }
284 public override OMV.Vector3 Position {
285 get {
286 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
287 * and does not fetch this position info for children. Thus this is commented out.
288 // child prims move around based on their parent. Need to get the latest location
289 if (!Linkset.IsRoot(this))
290 _position = Linkset.PositionGet(this);
291 */
292
293 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
294 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
295 return _position;
296 }
297 set {
298 // If the position must be forced into the physics engine, use ForcePosition.
299 // All positions are given in world positions.
300 if (_position == value)
301 {
302 DetailLog("{0},BSPrim.setPosition,taint,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
303 return;
304 }
305 _position = value;
306 PositionSanityCheck(false);
307
308 // A linkset might need to know if a component information changed.
309 Linkset.UpdateProperties(this, false);
310
311 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
312 {
313 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
314 ForcePosition = _position;
315 });
316 }
317 }
318 public override OMV.Vector3 ForcePosition {
319 get {
320 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
321 return _position;
322 }
323 set {
324 _position = value;
325 if (PhysBody.HasPhysicalBody)
326 {
327 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
328 ActivateIfPhysical(false);
329 }
330 }
331 }
332
333 // Check that the current position is sane and, if not, modify the position to make it so.
334 // Check for being below terrain and being out of bounds.
335 // Returns 'true' of the position was made sane by some action.
336 private bool PositionSanityCheck(bool inTaintTime)
337 {
338 bool ret = false;
339
340 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
341 {
342 // The physical object is out of the known/simulated area.
343 // Upper levels of code will handle the transition to other areas so, for
344 // the time, we just ignore the position.
345 return ret;
346 }
347
348 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
349 OMV.Vector3 upForce = OMV.Vector3.Zero;
350 if (RawPosition.Z < terrainHeight)
351 {
352 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
353 float targetHeight = terrainHeight + (Size.Z / 2f);
354 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
355 upForce.Z = (terrainHeight - RawPosition.Z) * 1f;
356 ret = true;
357 }
358
359 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
360 {
361 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
362 // TODO: a floating motor so object will bob in the water
363 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
364 {
365 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
366 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
367 ret = true;
368 }
369 }
370
371 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
372 // TODO: This should be intergrated with a geneal physics action mechanism.
373 // TODO: This should be moderated with PID'ness.
374 if (ret)
375 {
376 // Apply upforce and overcome gravity.
377 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
378 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
379 AddForce(correctionForce, false, inTaintTime);
380 }
381 return ret;
382 }
383
384 // Return the effective mass of the object.
385 // The definition of this call is to return the mass of the prim.
386 // If the simulator cares about the mass of the linkset, it will sum it itself.
387 public override float Mass
388 {
389 get
390 {
391 return _mass;
392 }
393 }
394
395 // used when we only want this prim's mass and not the linkset thing
396 public override float RawMass {
397 get { return _mass; }
398 }
399 // Set the physical mass to the passed mass.
400 // Note that this does not change _mass!
401 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
402 {
403 if (PhysBody.HasPhysicalBody)
404 {
405 if (IsStatic)
406 {
407 Inertia = OMV.Vector3.Zero;
408 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia);
409 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
410 }
411 else
412 {
413 if (inWorld)
414 {
415 // Changing interesting properties doesn't change proxy and collision cache
416 // information. The Bullet solution is to re-add the object to the world
417 // after parameters are changed.
418 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
419 }
420
421 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
422 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia);
423 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
424
425 // center of mass is at the zero of the object
426 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
427 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},inWorld={3}", LocalID, physMass, Inertia, inWorld);
428
429 if (inWorld)
430 {
431 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr,_position,_orientation);
432 }
433
434 // Must set gravity after it has been added to the world because, for unknown reasons,
435 // adding the object resets the object's gravity to world gravity
436 OMV.Vector3 grav = PhysicsScene.DefaultGravity * (1f - Buoyancy);
437 BulletSimAPI.SetGravity2(PhysBody.ptr, grav);
438
439 }
440 }
441 }
442
443 // Is this used?
444 public override OMV.Vector3 CenterOfMass
445 {
446 get { return Linkset.CenterOfMass; }
447 }
448
449 // Is this used?
450 public override OMV.Vector3 GeometricCenter
451 {
452 get { return Linkset.GeometricCenter; }
453 }
454
455 public override OMV.Vector3 Force {
456 get { return _force; }
457 set {
458 _force = value;
459 if (_force != OMV.Vector3.Zero)
460 {
461 // If the force is non-zero, it must be reapplied each tick because
462 // Bullet clears the forces applied last frame.
463 RegisterPreStepAction("BSPrim.setForce", LocalID,
464 delegate(float timeStep)
465 {
466 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
467 if (PhysBody.HasPhysicalBody)
468 {
469 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, _force);
470 ActivateIfPhysical(false);
471 }
472 }
473 );
474 }
475 else
476 {
477 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
478 }
479 }
480 }
481
482 public override int VehicleType {
483 get {
484 return (int)_vehicle.Type; // if we are a vehicle, return that type
485 }
486 set {
487 Vehicle type = (Vehicle)value;
488
489 PhysicsScene.TaintedObject("setVehicleType", delegate()
490 {
491 // Done at taint time so we're sure the physics engine is not using the variables
492 // Vehicle code changes the parameters for this vehicle type.
493 _vehicle.ProcessTypeChange(type);
494 ActivateIfPhysical(false);
495
496 // If an active vehicle, register the vehicle code to be called before each step
497 if (_vehicle.Type == Vehicle.TYPE_NONE)
498 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
499 else
500 RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
501 });
502 }
503 }
504 public override void VehicleFloatParam(int param, float value)
505 {
506 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
507 {
508 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
509 ActivateIfPhysical(false);
510 });
511 }
512 public override void VehicleVectorParam(int param, OMV.Vector3 value)
513 {
514 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
515 {
516 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
517 ActivateIfPhysical(false);
518 });
519 }
520 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
521 {
522 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
523 {
524 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
525 ActivateIfPhysical(false);
526 });
527 }
528 public override void VehicleFlags(int param, bool remove)
529 {
530 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
531 {
532 _vehicle.ProcessVehicleFlags(param, remove);
533 });
534 }
535
536 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
537 public override void SetVolumeDetect(int param) {
538 bool newValue = (param != 0);
539 if (_isVolumeDetect != newValue)
540 {
541 _isVolumeDetect = newValue;
542 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
543 {
544 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
545 SetObjectDynamic(true);
546 });
547 }
548 return;
549 }
550 public override OMV.Vector3 Velocity {
551 get { return _velocity; }
552 set {
553 _velocity = value;
554 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
555 {
556 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
557 ForceVelocity = _velocity;
558 });
559 }
560 }
561 public override OMV.Vector3 ForceVelocity {
562 get { return _velocity; }
563 set {
564 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
565
566 _velocity = value;
567 if (PhysBody.HasPhysicalBody)
568 {
569 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
570 ActivateIfPhysical(false);
571 }
572 }
573 }
574 public override OMV.Vector3 Torque {
575 get { return _torque; }
576 set {
577 _torque = value;
578 if (_torque != OMV.Vector3.Zero)
579 {
580 // If the torque is non-zero, it must be reapplied each tick because
581 // Bullet clears the forces applied last frame.
582 RegisterPreStepAction("BSPrim.setTorque", LocalID,
583 delegate(float timeStep)
584 {
585 if (PhysBody.HasPhysicalBody)
586 AddAngularForce(_torque, false, true);
587 }
588 );
589 }
590 else
591 {
592 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
593 }
594 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
595 }
596 }
597 public override float CollisionScore {
598 get { return _collisionScore; }
599 set { _collisionScore = value;
600 }
601 }
602 public override OMV.Vector3 Acceleration {
603 get { return _acceleration; }
604 set { _acceleration = value; }
605 }
606 public override OMV.Quaternion RawOrientation
607 {
608 get { return _orientation; }
609 set { _orientation = value; }
610 }
611 public override OMV.Quaternion Orientation {
612 get {
613 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
614 * and does not fetch this position info for children. Thus this is commented out.
615 // Children move around because tied to parent. Get a fresh value.
616 if (!Linkset.IsRoot(this))
617 {
618 _orientation = Linkset.OrientationGet(this);
619 }
620 */
621 return _orientation;
622 }
623 set {
624 if (_orientation == value)
625 return;
626 _orientation = value;
627
628 // A linkset might need to know if a component information changed.
629 Linkset.UpdateProperties(this, false);
630
631 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
632 {
633 if (PhysBody.HasPhysicalBody)
634 {
635 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
636 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
637 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
638 }
639 });
640 }
641 }
642 // Go directly to Bullet to get/set the value.
643 public override OMV.Quaternion ForceOrientation
644 {
645 get
646 {
647 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
648 return _orientation;
649 }
650 set
651 {
652 _orientation = value;
653 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
654 }
655 }
656 public override int PhysicsActorType {
657 get { return _physicsActorType; }
658 set { _physicsActorType = value; }
659 }
660 public override bool IsPhysical {
661 get { return _isPhysical; }
662 set {
663 if (_isPhysical != value)
664 {
665 _isPhysical = value;
666 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
667 {
668 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
669 SetObjectDynamic(true);
670 // whether phys-to-static or static-to-phys, the object is not moving.
671 ZeroMotion(true);
672 });
673 }
674 }
675 }
676
677 // An object is static (does not move) if selected or not physical
678 public override bool IsStatic
679 {
680 get { return _isSelected || !IsPhysical; }
681 }
682
683 // An object is solid if it's not phantom and if it's not doing VolumeDetect
684 public override bool IsSolid
685 {
686 get { return !IsPhantom && !_isVolumeDetect; }
687 }
688
689 // Make gravity work if the object is physical and not selected
690 // Called at taint-time!!
691 private void SetObjectDynamic(bool forceRebuild)
692 {
693 // Recreate the physical object if necessary
694 CreateGeomAndObject(forceRebuild);
695 }
696
697 // Convert the simulator's physical properties into settings on BulletSim objects.
698 // There are four flags we're interested in:
699 // IsStatic: Object does not move, otherwise the object has mass and moves
700 // isSolid: other objects bounce off of this object
701 // isVolumeDetect: other objects pass through but can generate collisions
702 // collisionEvents: whether this object returns collision events
703 private void UpdatePhysicalParameters()
704 {
705 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
706
707 // Mangling all the physical properties requires the object not be in the physical world.
708 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
709 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
710
711 // Set up the object physicalness (does gravity and collisions move this object)
712 MakeDynamic(IsStatic);
713
714 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
715 _vehicle.Refresh();
716
717 // Arrange for collision events if the simulator wants them
718 EnableCollisions(SubscribedEvents());
719
720 // Make solid or not (do things bounce off or pass through this object).
721 MakeSolid(IsSolid);
722
723 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation);
724
725 // Rebuild its shape
726 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
727
728 // Collision filter can be set only when the object is in the world
729 PhysBody.ApplyCollisionMask();
730
731 // Recompute any linkset parameters.
732 // When going from non-physical to physical, this re-enables the constraints that
733 // had been automatically disabled when the mass was set to zero.
734 // For compound based linksets, this enables and disables interactions of the children.
735 Linkset.Refresh(this);
736
737 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
738 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape);
739 }
740
741 // "Making dynamic" means changing to and from static.
742 // When static, gravity does not effect the object and it is fixed in space.
743 // When dynamic, the object can fall and be pushed by others.
744 // This is independent of its 'solidness' which controls what passes through
745 // this object and what interacts with it.
746 private void MakeDynamic(bool makeStatic)
747 {
748 if (makeStatic)
749 {
750 // Become a Bullet 'static' object type
751 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
752 // Stop all movement
753 ZeroMotion(true);
754
755 // Set various physical properties so other object interact properly
756 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
757 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
758 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
759
760 // Mass is zero which disables a bunch of physics stuff in Bullet
761 UpdatePhysicalMassProperties(0f, false);
762 // Set collision detection parameters
763 if (BSParam.CcdMotionThreshold > 0f)
764 {
765 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
766 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
767 }
768
769 // The activation state is 'disabled' so Bullet will not try to act on it.
770 // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
771 // Start it out sleeping and physical actions could wake it up.
772 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING);
773
774 // This collides like a static object
775 PhysBody.collisionType = CollisionType.Static;
776
777 // There can be special things needed for implementing linksets
778 Linkset.MakeStatic(this);
779 }
780 else
781 {
782 // Not a Bullet static object
783 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
784
785 // Set various physical properties so other object interact properly
786 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
787 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
788 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
789
790 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
791 // Since this can be called multiple times, only zero forces when becoming physical
792 // BulletSimAPI.ClearAllForces2(BSBody.ptr);
793
794 // For good measure, make sure the transform is set through to the motion state
795 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
796
797 // Center of mass is at the center of the object
798 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
799
800 // A dynamic object has mass
801 UpdatePhysicalMassProperties(RawMass, false);
802
803 // Set collision detection parameters
804 if (BSParam.CcdMotionThreshold > 0f)
805 {
806 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
807 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
808 }
809
810 // Various values for simulation limits
811 BulletSimAPI.SetDamping2(PhysBody.ptr, BSParam.LinearDamping, BSParam.AngularDamping);
812 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, BSParam.DeactivationTime);
813 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
814 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
815
816 // This collides like an object.
817 PhysBody.collisionType = CollisionType.Dynamic;
818
819 // Force activation of the object so Bullet will act on it.
820 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
821 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
822
823 // There might be special things needed for implementing linksets.
824 Linkset.MakeDynamic(this);
825 }
826 }
827
828 // "Making solid" means that other object will not pass through this object.
829 // To make transparent, we create a Bullet ghost object.
830 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
831 // the functions after this one set up the state of a possibly newly created collision body.
832 private void MakeSolid(bool makeSolid)
833 {
834 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr);
835 if (makeSolid)
836 {
837 // Verify the previous code created the correct shape for this type of thing.
838 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
839 {
840 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
841 }
842 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
843 }
844 else
845 {
846 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
847 {
848 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
849 }
850 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
851
852 // Change collision info from a static object to a ghosty collision object
853 PhysBody.collisionType = CollisionType.VolumeDetect;
854 }
855 }
856
857 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
858 // they need waking up when parameters are changed.
859 // Called in taint-time!!
860 private void ActivateIfPhysical(bool forceIt)
861 {
862 if (IsPhysical && PhysBody.HasPhysicalBody)
863 BulletSimAPI.Activate2(PhysBody.ptr, forceIt);
864 }
865
866 // Turn on or off the flag controlling whether collision events are returned to the simulator.
867 private void EnableCollisions(bool wantsCollisionEvents)
868 {
869 if (wantsCollisionEvents)
870 {
871 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
872 }
873 else
874 {
875 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
876 }
877 }
878
879 // prims don't fly
880 public override bool Flying {
881 get { return _flying; }
882 set {
883 _flying = value;
884 }
885 }
886 public override bool SetAlwaysRun {
887 get { return _setAlwaysRun; }
888 set { _setAlwaysRun = value; }
889 }
890 public override bool ThrottleUpdates {
891 get { return _throttleUpdates; }
892 set { _throttleUpdates = value; }
893 }
894 public override bool IsColliding {
895 get { return (CollidingStep == PhysicsScene.SimulationStep); }
896 set { _isColliding = value; }
897 }
898 public override bool CollidingGround {
899 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
900 set { _collidingGround = value; }
901 }
902 public override bool CollidingObj {
903 get { return _collidingObj; }
904 set { _collidingObj = value; }
905 }
906 public bool IsPhantom {
907 get {
908 // SceneObjectPart removes phantom objects from the physics scene
909 // so, although we could implement touching and such, we never
910 // are invoked as a phantom object
911 return false;
912 }
913 }
914 public override bool FloatOnWater {
915 set {
916 _floatOnWater = value;
917 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
918 {
919 if (_floatOnWater)
920 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
921 else
922 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
923 });
924 }
925 }
926 public override OMV.Vector3 RotationalVelocity {
927 get {
928 return _rotationalVelocity;
929 }
930 set {
931 _rotationalVelocity = value;
932 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
933 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
934 {
935 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
936 ForceRotationalVelocity = _rotationalVelocity;
937 });
938 }
939 }
940 public override OMV.Vector3 ForceRotationalVelocity {
941 get {
942 return _rotationalVelocity;
943 }
944 set {
945 _rotationalVelocity = value;
946 if (PhysBody.HasPhysicalBody)
947 {
948 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
949 ActivateIfPhysical(false);
950 }
951 }
952 }
953 public override bool Kinematic {
954 get { return _kinematic; }
955 set { _kinematic = value;
956 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
957 }
958 }
959 public override float Buoyancy {
960 get { return _buoyancy; }
961 set {
962 _buoyancy = value;
963 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
964 {
965 ForceBuoyancy = _buoyancy;
966 });
967 }
968 }
969 public override float ForceBuoyancy {
970 get { return _buoyancy; }
971 set {
972 _buoyancy = value;
973 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
974 // Force the recalculation of the various inertia,etc variables in the object
975 UpdatePhysicalMassProperties(_mass, true);
976 ActivateIfPhysical(false);
977 }
978 }
979
980 // Used for MoveTo
981 public override OMV.Vector3 PIDTarget {
982 set { _PIDTarget = value; }
983 }
984 public override bool PIDActive {
985 set { _usePID = value; }
986 }
987 public override float PIDTau {
988 set { _PIDTau = value; }
989 }
990
991 // Used for llSetHoverHeight and maybe vehicle height
992 // Hover Height will override MoveTo target's Z
993 public override bool PIDHoverActive {
994 set { _useHoverPID = value; }
995 }
996 public override float PIDHoverHeight {
997 set { _PIDHoverHeight = value; }
998 }
999 public override PIDHoverType PIDHoverType {
1000 set { _PIDHoverType = value; }
1001 }
1002 public override float PIDHoverTau {
1003 set { _PIDHoverTao = value; }
1004 }
1005
1006 // For RotLookAt
1007 public override OMV.Quaternion APIDTarget { set { return; } }
1008 public override bool APIDActive { set { return; } }
1009 public override float APIDStrength { set { return; } }
1010 public override float APIDDamping { set { return; } }
1011
1012 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1013 // Since this force is being applied in only one step, make this a force per second.
1014 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
1015 AddForce(addForce, pushforce, false);
1016 }
1017 // Applying a force just adds this to the total force on the object.
1018 // This added force will only last the next simulation tick.
1019 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1020 // for an object, doesn't matter if force is a pushforce or not
1021 if (force.IsFinite())
1022 {
1023 float magnitude = force.Length();
1024 if (magnitude > 20000f)
1025 {
1026 // Force has a limit
1027 force = force / magnitude * 20000f;
1028 }
1029
1030 OMV.Vector3 addForce = force;
1031 DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1032
1033 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1034 {
1035 // Bullet adds this central force to the total force for this tick
1036 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1037 if (PhysBody.HasPhysicalBody)
1038 {
1039 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, addForce);
1040 ActivateIfPhysical(false);
1041 }
1042 });
1043 }
1044 else
1045 {
1046 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1047 return;
1048 }
1049 }
1050
1051 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
1052 AddAngularForce(force, pushforce, false);
1053 }
1054 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1055 {
1056 if (force.IsFinite())
1057 {
1058 OMV.Vector3 angForce = force;
1059 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
1060 {
1061 if (PhysBody.HasPhysicalBody)
1062 {
1063 BulletSimAPI.ApplyTorque2(PhysBody.ptr, angForce);
1064 ActivateIfPhysical(false);
1065 }
1066 });
1067 }
1068 else
1069 {
1070 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1071 return;
1072 }
1073 }
1074
1075 // A torque impulse.
1076 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1077 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1078 // Computed as: angularVelocity += impulse * inertia;
1079 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1080 {
1081 OMV.Vector3 applyImpulse = impulse;
1082 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1083 {
1084 if (PhysBody.HasPhysicalBody)
1085 {
1086 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
1087 ActivateIfPhysical(false);
1088 }
1089 });
1090 }
1091
1092 public override void SetMomentum(OMV.Vector3 momentum) {
1093 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1094 }
1095 #region Mass Calculation
1096
1097 private float CalculateMass()
1098 {
1099 float volume = _size.X * _size.Y * _size.Z; // default
1100 float tmp;
1101
1102 float returnMass = 0;
1103 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1104 float hollowVolume = hollowAmount * hollowAmount;
1105
1106 switch (BaseShape.ProfileShape)
1107 {
1108 case ProfileShape.Square:
1109 // default box
1110
1111 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1112 {
1113 if (hollowAmount > 0.0)
1114 {
1115 switch (BaseShape.HollowShape)
1116 {
1117 case HollowShape.Square:
1118 case HollowShape.Same:
1119 break;
1120
1121 case HollowShape.Circle:
1122
1123 hollowVolume *= 0.78539816339f;
1124 break;
1125
1126 case HollowShape.Triangle:
1127
1128 hollowVolume *= (0.5f * .5f);
1129 break;
1130
1131 default:
1132 hollowVolume = 0;
1133 break;
1134 }
1135 volume *= (1.0f - hollowVolume);
1136 }
1137 }
1138
1139 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1140 {
1141 //a tube
1142
1143 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1144 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1145 volume -= volume*tmp*tmp;
1146
1147 if (hollowAmount > 0.0)
1148 {
1149 hollowVolume *= hollowAmount;
1150
1151 switch (BaseShape.HollowShape)
1152 {
1153 case HollowShape.Square:
1154 case HollowShape.Same:
1155 break;
1156
1157 case HollowShape.Circle:
1158 hollowVolume *= 0.78539816339f;;
1159 break;
1160
1161 case HollowShape.Triangle:
1162 hollowVolume *= 0.5f * 0.5f;
1163 break;
1164 default:
1165 hollowVolume = 0;
1166 break;
1167 }
1168 volume *= (1.0f - hollowVolume);
1169 }
1170 }
1171
1172 break;
1173
1174 case ProfileShape.Circle:
1175
1176 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1177 {
1178 volume *= 0.78539816339f; // elipse base
1179
1180 if (hollowAmount > 0.0)
1181 {
1182 switch (BaseShape.HollowShape)
1183 {
1184 case HollowShape.Same:
1185 case HollowShape.Circle:
1186 break;
1187
1188 case HollowShape.Square:
1189 hollowVolume *= 0.5f * 2.5984480504799f;
1190 break;
1191
1192 case HollowShape.Triangle:
1193 hollowVolume *= .5f * 1.27323954473516f;
1194 break;
1195
1196 default:
1197 hollowVolume = 0;
1198 break;
1199 }
1200 volume *= (1.0f - hollowVolume);
1201 }
1202 }
1203
1204 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1205 {
1206 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1207 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1208 volume *= (1.0f - tmp * tmp);
1209
1210 if (hollowAmount > 0.0)
1211 {
1212
1213 // calculate the hollow volume by it's shape compared to the prim shape
1214 hollowVolume *= hollowAmount;
1215
1216 switch (BaseShape.HollowShape)
1217 {
1218 case HollowShape.Same:
1219 case HollowShape.Circle:
1220 break;
1221
1222 case HollowShape.Square:
1223 hollowVolume *= 0.5f * 2.5984480504799f;
1224 break;
1225
1226 case HollowShape.Triangle:
1227 hollowVolume *= .5f * 1.27323954473516f;
1228 break;
1229
1230 default:
1231 hollowVolume = 0;
1232 break;
1233 }
1234 volume *= (1.0f - hollowVolume);
1235 }
1236 }
1237 break;
1238
1239 case ProfileShape.HalfCircle:
1240 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1241 {
1242 volume *= 0.52359877559829887307710723054658f;
1243 }
1244 break;
1245
1246 case ProfileShape.EquilateralTriangle:
1247
1248 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1249 {
1250 volume *= 0.32475953f;
1251
1252 if (hollowAmount > 0.0)
1253 {
1254
1255 // calculate the hollow volume by it's shape compared to the prim shape
1256 switch (BaseShape.HollowShape)
1257 {
1258 case HollowShape.Same:
1259 case HollowShape.Triangle:
1260 hollowVolume *= .25f;
1261 break;
1262
1263 case HollowShape.Square:
1264 hollowVolume *= 0.499849f * 3.07920140172638f;
1265 break;
1266
1267 case HollowShape.Circle:
1268 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1269 // Cyllinder hollow volume calculation
1270
1271 hollowVolume *= 0.1963495f * 3.07920140172638f;
1272 break;
1273
1274 default:
1275 hollowVolume = 0;
1276 break;
1277 }
1278 volume *= (1.0f - hollowVolume);
1279 }
1280 }
1281 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1282 {
1283 volume *= 0.32475953f;
1284 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1285 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1286 volume *= (1.0f - tmp * tmp);
1287
1288 if (hollowAmount > 0.0)
1289 {
1290
1291 hollowVolume *= hollowAmount;
1292
1293 switch (BaseShape.HollowShape)
1294 {
1295 case HollowShape.Same:
1296 case HollowShape.Triangle:
1297 hollowVolume *= .25f;
1298 break;
1299
1300 case HollowShape.Square:
1301 hollowVolume *= 0.499849f * 3.07920140172638f;
1302 break;
1303
1304 case HollowShape.Circle:
1305
1306 hollowVolume *= 0.1963495f * 3.07920140172638f;
1307 break;
1308
1309 default:
1310 hollowVolume = 0;
1311 break;
1312 }
1313 volume *= (1.0f - hollowVolume);
1314 }
1315 }
1316 break;
1317
1318 default:
1319 break;
1320 }
1321
1322
1323
1324 float taperX1;
1325 float taperY1;
1326 float taperX;
1327 float taperY;
1328 float pathBegin;
1329 float pathEnd;
1330 float profileBegin;
1331 float profileEnd;
1332
1333 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1334 {
1335 taperX1 = BaseShape.PathScaleX * 0.01f;
1336 if (taperX1 > 1.0f)
1337 taperX1 = 2.0f - taperX1;
1338 taperX = 1.0f - taperX1;
1339
1340 taperY1 = BaseShape.PathScaleY * 0.01f;
1341 if (taperY1 > 1.0f)
1342 taperY1 = 2.0f - taperY1;
1343 taperY = 1.0f - taperY1;
1344 }
1345 else
1346 {
1347 taperX = BaseShape.PathTaperX * 0.01f;
1348 if (taperX < 0.0f)
1349 taperX = -taperX;
1350 taperX1 = 1.0f - taperX;
1351
1352 taperY = BaseShape.PathTaperY * 0.01f;
1353 if (taperY < 0.0f)
1354 taperY = -taperY;
1355 taperY1 = 1.0f - taperY;
1356
1357 }
1358
1359
1360 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1361
1362 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1363 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1364 volume *= (pathEnd - pathBegin);
1365
1366 // this is crude aproximation
1367 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1368 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1369 volume *= (profileEnd - profileBegin);
1370
1371 returnMass = _density * volume;
1372
1373 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1374 if (IsRootOfLinkset)
1375 {
1376 foreach (BSPrim prim in _childrenPrims)
1377 {
1378 returnMass += prim.CalculateMass();
1379 }
1380 }
1381 */
1382
1383 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1384
1385 return returnMass;
1386 }// end CalculateMass
1387 #endregion Mass Calculation
1388
1389 // Rebuild the geometry and object.
1390 // This is called when the shape changes so we need to recreate the mesh/hull.
1391 // Called at taint-time!!!
1392 public void CreateGeomAndObject(bool forceRebuild)
1393 {
1394 // If this prim is part of a linkset, we must remove and restore the physical
1395 // links if the body is rebuilt.
1396 bool needToRestoreLinkset = false;
1397 bool needToRestoreVehicle = false;
1398
1399 // Create the correct physical representation for this type of object.
1400 // Updates PhysBody and PhysShape with the new information.
1401 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1402 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1403 {
1404 // Called if the current prim body is about to be destroyed.
1405 // Remove all the physical dependencies on the old body.
1406 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1407 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1408 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1409 });
1410
1411 if (needToRestoreLinkset)
1412 {
1413 // If physical body dependencies were removed, restore them
1414 Linkset.RestoreBodyDependencies(this);
1415 }
1416 if (needToRestoreVehicle)
1417 {
1418 // If physical body dependencies were removed, restore them
1419 _vehicle.RestoreBodyDependencies(this);
1420 }
1421
1422 // Make sure the properties are set on the new object
1423 UpdatePhysicalParameters();
1424 return;
1425 }
1426
1427 // The physics engine says that properties have updated. Update same and inform
1428 // the world that things have changed.
1429 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1430 enum UpdatedProperties {
1431 Position = 1 << 0,
1432 Rotation = 1 << 1,
1433 Velocity = 1 << 2,
1434 Acceleration = 1 << 3,
1435 RotationalVel = 1 << 4
1436 }
1437
1438 const float ROTATION_TOLERANCE = 0.01f;
1439 const float VELOCITY_TOLERANCE = 0.001f;
1440 const float POSITION_TOLERANCE = 0.05f;
1441 const float ACCELERATION_TOLERANCE = 0.01f;
1442 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1443
1444 public override void UpdateProperties(EntityProperties entprop)
1445 {
1446 // Updates only for individual prims and for the root object of a linkset.
1447 if (Linkset.IsRoot(this))
1448 {
1449 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1450 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1451 if (_vehicle.IsActive)
1452 {
1453 entprop.RotationalVelocity = OMV.Vector3.Zero;
1454 }
1455
1456 // Assign directly to the local variables so the normal set action does not happen
1457 _position = entprop.Position;
1458 _orientation = entprop.Rotation;
1459 _velocity = entprop.Velocity;
1460 _acceleration = entprop.Acceleration;
1461 _rotationalVelocity = entprop.RotationalVelocity;
1462
1463 // The sanity check can change the velocity and/or position.
1464 if (IsPhysical && PositionSanityCheck(true))
1465 {
1466 entprop.Position = _position;
1467 entprop.Velocity = _velocity;
1468 }
1469
1470 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1471 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1472 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1473
1474 // remember the current and last set values
1475 LastEntityProperties = CurrentEntityProperties;
1476 CurrentEntityProperties = entprop;
1477
1478 base.RequestPhysicsterseUpdate();
1479 }
1480 /*
1481 else
1482 {
1483 // For debugging, report the movement of children
1484 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1485 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1486 entprop.Acceleration, entprop.RotationalVelocity);
1487 }
1488 */
1489
1490 // The linkset implimentation might want to know about this.
1491 Linkset.UpdateProperties(this, true);
1492 }
1493}
1494}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs
deleted file mode 100644
index 1a7c34b..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSScene.cs
+++ /dev/null
@@ -1,957 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Runtime.InteropServices;
30using System.Text;
31using System.Threading;
32using OpenSim.Framework;
33using OpenSim.Region.Framework;
34using OpenSim.Region.CoreModules;
35using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
36using OpenSim.Region.Physics.Manager;
37using Nini.Config;
38using log4net;
39using OpenMetaverse;
40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Based on material, set density and friction
43// More efficient memory usage when passing hull information from BSPrim to BulletSim
44// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
45// Implement LockAngularMotion
46// Add PID movement operations. What does ScenePresence.MoveToTarget do?
47// Check terrain size. 128 or 127?
48// Raycast
49//
50namespace OpenSim.Region.Physics.BulletSNPlugin
51{
52public sealed class BSScene : PhysicsScene, IPhysicsParameters
53{
54 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
55 private static readonly string LogHeader = "[BULLETS SCENE]";
56
57 // The name of the region we're working for.
58 public string RegionName { get; private set; }
59
60 public string BulletSimVersion = "?";
61
62 public Dictionary<uint, BSPhysObject> PhysObjects;
63 public BSShapeCollection Shapes;
64
65 // Keeping track of the objects with collisions so we can report begin and end of a collision
66 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
67 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
68 // Keep track of all the avatars so we can send them a collision event
69 // every tick so OpenSim will update its animation.
70 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
71
72 // let my minuions use my logger
73 public ILog Logger { get { return m_log; } }
74
75 public IMesher mesher;
76 public uint WorldID { get; private set; }
77 public BulletWorld World { get; private set; }
78
79 // All the constraints that have been allocated in this instance.
80 public BSConstraintCollection Constraints { get; private set; }
81
82 // Simulation parameters
83 internal int m_maxSubSteps;
84 internal float m_fixedTimeStep;
85 internal long m_simulationStep = 0;
86 public long SimulationStep { get { return m_simulationStep; } }
87 internal int m_taintsToProcessPerStep;
88 internal float LastTimeStep { get; private set; }
89
90 // Physical objects can register for prestep or poststep events
91 public delegate void PreStepAction(float timeStep);
92 public delegate void PostStepAction(float timeStep);
93 public event PreStepAction BeforeStep;
94 public event PreStepAction AfterStep;
95
96 // A value of the time now so all the collision and update routines do not have to get their own
97 // Set to 'now' just before all the prims and actors are called for collisions and updates
98 public int SimulationNowTime { get; private set; }
99
100 // True if initialized and ready to do simulation steps
101 private bool m_initialized = false;
102
103 // Flag which is true when processing taints.
104 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
105 public bool InTaintTime { get; private set; }
106
107 // Pinned memory used to pass step information between managed and unmanaged
108 internal int m_maxCollisionsPerFrame;
109 private List<BulletXNA.CollisionDesc> m_collisionArray;
110 //private GCHandle m_collisionArrayPinnedHandle;
111
112 internal int m_maxUpdatesPerFrame;
113 private List<BulletXNA.EntityProperties> m_updateArray;
114 //private GCHandle m_updateArrayPinnedHandle;
115
116
117 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
118 public const uint GROUNDPLANE_ID = 1;
119 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
120
121 public float SimpleWaterLevel { get; set; }
122 public BSTerrainManager TerrainManager { get; private set; }
123
124 public ConfigurationParameters Params
125 {
126 get { return UnmanagedParams[0]; }
127 }
128 public Vector3 DefaultGravity
129 {
130 get { return new Vector3(0f, 0f, Params.gravity); }
131 }
132 // Just the Z value of the gravity
133 public float DefaultGravityZ
134 {
135 get { return Params.gravity; }
136 }
137
138 // When functions in the unmanaged code must be called, it is only
139 // done at a known time just before the simulation step. The taint
140 // system saves all these function calls and executes them in
141 // order before the simulation.
142 public delegate void TaintCallback();
143 private struct TaintCallbackEntry
144 {
145 public String ident;
146 public TaintCallback callback;
147 public TaintCallbackEntry(string i, TaintCallback c)
148 {
149 ident = i;
150 callback = c;
151 }
152 }
153 private Object _taintLock = new Object(); // lock for using the next object
154 private List<TaintCallbackEntry> _taintOperations;
155 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
156 private List<TaintCallbackEntry> _postStepOperations;
157
158 // A pointer to an instance if this structure is passed to the C++ code
159 // Used to pass basic configuration values to the unmanaged code.
160 internal ConfigurationParameters[] UnmanagedParams;
161 //GCHandle m_paramsHandle;
162
163 // Handle to the callback used by the unmanaged code to call into the managed code.
164 // Used for debug logging.
165 // Need to store the handle in a persistant variable so it won't be freed.
166 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
167
168 // Sometimes you just have to log everything.
169 public Logging.LogWriter PhysicsLogging;
170 private bool m_physicsLoggingEnabled;
171 private string m_physicsLoggingDir;
172 private string m_physicsLoggingPrefix;
173 private int m_physicsLoggingFileMinutes;
174 private bool m_physicsLoggingDoFlush;
175 // 'true' of the vehicle code is to log lots of details
176 public bool VehicleLoggingEnabled { get; private set; }
177 public bool VehiclePhysicalLoggingEnabled { get; private set; }
178
179 #region Construction and Initialization
180 public BSScene(string identifier)
181 {
182 m_initialized = false;
183 // we are passed the name of the region we're working for.
184 RegionName = identifier;
185 }
186
187 public override void Initialise(IMesher meshmerizer, IConfigSource config)
188 {
189 mesher = meshmerizer;
190 _taintOperations = new List<TaintCallbackEntry>();
191 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
192 _postStepOperations = new List<TaintCallbackEntry>();
193 PhysObjects = new Dictionary<uint, BSPhysObject>();
194 Shapes = new BSShapeCollection(this);
195
196 // Allocate pinned memory to pass parameters.
197 UnmanagedParams = new ConfigurationParameters[1];
198 //m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned);
199
200 // Set default values for physics parameters plus any overrides from the ini file
201 GetInitialParameterValues(config);
202
203 // allocate more pinned memory close to the above in an attempt to get the memory all together
204 m_collisionArray = new List<BulletXNA.CollisionDesc>();
205 //m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned);
206 m_updateArray = new List<BulletXNA.EntityProperties>();
207 //m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
208
209 // Enable very detailed logging.
210 // By creating an empty logger when not logging, the log message invocation code
211 // can be left in and every call doesn't have to check for null.
212 if (m_physicsLoggingEnabled)
213 {
214 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
215 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
216 }
217 else
218 {
219 PhysicsLogging = new Logging.LogWriter();
220 }
221
222 // If Debug logging level, enable logging from the unmanaged code
223 m_DebugLogCallbackHandle = null;
224 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
225 {
226 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
227 if (PhysicsLogging.Enabled)
228 // The handle is saved in a variable to make sure it doesn't get freed after this call
229 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
230 else
231 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
232 }
233
234 // Get the version of the DLL
235 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
236 // BulletSimVersion = BulletSimAPI.GetVersion();
237 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
238
239 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
240 // a child in a mega-region.
241 // Bullet actually doesn't care about the extents of the simulated
242 // area. It tracks active objects no matter where they are.
243 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
244
245 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
246
247 World = new BulletWorld(0, this, BulletSimAPI.Initialize2(worldExtent, UnmanagedParams,
248 m_maxCollisionsPerFrame, ref m_collisionArray,
249 m_maxUpdatesPerFrame,ref m_updateArray,
250 m_DebugLogCallbackHandle));
251
252 Constraints = new BSConstraintCollection(World);
253
254 TerrainManager = new BSTerrainManager(this);
255 TerrainManager.CreateInitialGroundPlaneAndTerrain();
256
257 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
258
259 InTaintTime = false;
260 m_initialized = true;
261 }
262
263 // All default parameter values are set here. There should be no values set in the
264 // variable definitions.
265 private void GetInitialParameterValues(IConfigSource config)
266 {
267 ConfigurationParameters parms = new ConfigurationParameters();
268 UnmanagedParams[0] = parms;
269
270 BSParam.SetParameterDefaultValues(this);
271
272 if (config != null)
273 {
274 // If there are specifications in the ini file, use those values
275 IConfig pConfig = config.Configs["BulletSim"];
276 if (pConfig != null)
277 {
278 BSParam.SetParameterConfigurationValues(this, pConfig);
279
280 // Very detailed logging for physics debugging
281 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
282 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
283 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
284 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
285 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
286 // Very detailed logging for vehicle debugging
287 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
288 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
289
290 // Do any replacements in the parameters
291 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
292 }
293
294 // The material characteristics.
295 BSMaterials.InitializeFromDefaults(Params);
296 if (pConfig != null)
297 {
298 // Let the user add new and interesting material property values.
299 BSMaterials.InitializefromParameters(pConfig);
300 }
301 }
302 }
303
304 // A helper function that handles a true/false parameter and returns the proper float number encoding
305 float ParamBoolean(IConfig config, string parmName, float deflt)
306 {
307 float ret = deflt;
308 if (config.Contains(parmName))
309 {
310 ret = ConfigurationParameters.numericFalse;
311 if (config.GetBoolean(parmName, false))
312 {
313 ret = ConfigurationParameters.numericTrue;
314 }
315 }
316 return ret;
317 }
318
319 // Called directly from unmanaged code so don't do much
320 private void BulletLogger(string msg)
321 {
322 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
323 }
324
325 // Called directly from unmanaged code so don't do much
326 private void BulletLoggerPhysLog(string msg)
327 {
328 DetailLog("[BULLETS UNMANAGED]:" + msg);
329 }
330
331 public override void Dispose()
332 {
333 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
334
335 // make sure no stepping happens while we're deleting stuff
336 m_initialized = false;
337
338 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
339 {
340 kvp.Value.Destroy();
341 }
342 PhysObjects.Clear();
343
344 // Now that the prims are all cleaned up, there should be no constraints left
345 if (Constraints != null)
346 {
347 Constraints.Dispose();
348 Constraints = null;
349 }
350
351 if (Shapes != null)
352 {
353 Shapes.Dispose();
354 Shapes = null;
355 }
356
357 if (TerrainManager != null)
358 {
359 TerrainManager.ReleaseGroundPlaneAndTerrain();
360 TerrainManager.Dispose();
361 TerrainManager = null;
362 }
363
364 // Anything left in the unmanaged code should be cleaned out
365 BulletSimAPI.Shutdown2(World.ptr);
366
367 // Not logging any more
368 PhysicsLogging.Close();
369 }
370 #endregion // Construction and Initialization
371
372 #region Prim and Avatar addition and removal
373
374 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
375 {
376 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
377 return null;
378 }
379
380 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
381 {
382 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
383
384 if (!m_initialized) return null;
385
386 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
387 lock (PhysObjects) PhysObjects.Add(localID, actor);
388
389 // TODO: Remove kludge someday.
390 // We must generate a collision for avatars whether they collide or not.
391 // This is required by OpenSim to update avatar animations, etc.
392 lock (m_avatars) m_avatars.Add(actor);
393
394 return actor;
395 }
396
397 public override void RemoveAvatar(PhysicsActor actor)
398 {
399 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
400
401 if (!m_initialized) return;
402
403 BSCharacter bsactor = actor as BSCharacter;
404 if (bsactor != null)
405 {
406 try
407 {
408 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
409 // Remove kludge someday
410 lock (m_avatars) m_avatars.Remove(bsactor);
411 }
412 catch (Exception e)
413 {
414 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
415 }
416 bsactor.Destroy();
417 // bsactor.dispose();
418 }
419 }
420
421 public override void RemovePrim(PhysicsActor prim)
422 {
423 if (!m_initialized) return;
424
425 BSPrim bsprim = prim as BSPrim;
426 if (bsprim != null)
427 {
428 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
429 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
430 try
431 {
432 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
433 }
434 catch (Exception e)
435 {
436 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
437 }
438 bsprim.Destroy();
439 // bsprim.dispose();
440 }
441 else
442 {
443 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
444 }
445 }
446
447 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
448 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
449 {
450 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
451
452 if (!m_initialized) return null;
453
454 DetailLog("{0},AddPrimShape,call", localID);
455
456 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
457 lock (PhysObjects) PhysObjects.Add(localID, prim);
458 return prim;
459 }
460
461 // This is a call from the simulator saying that some physical property has been updated.
462 // The BulletSim driver senses the changing of relevant properties so this taint
463 // information call is not needed.
464 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
465
466 #endregion // Prim and Avatar addition and removal
467
468 #region Simulation
469 // Simulate one timestep
470 public override float Simulate(float timeStep)
471 {
472 // prevent simulation until we've been initialized
473 if (!m_initialized) return 5.0f;
474
475 LastTimeStep = timeStep;
476
477 int updatedEntityCount = 0;
478 //Object updatedEntitiesPtr;
479 int collidersCount = 0;
480 //Object collidersPtr;
481
482 int beforeTime = 0;
483 int simTime = 0;
484
485 // update the prim states while we know the physics engine is not busy
486 int numTaints = _taintOperations.Count;
487
488 InTaintTime = true; // Only used for debugging so locking is not necessary.
489
490 ProcessTaints();
491
492 // Some of the physical objects requre individual, pre-step calls
493 TriggerPreStepEvent(timeStep);
494
495 // the prestep actions might have added taints
496 ProcessTaints();
497
498 InTaintTime = false; // Only used for debugging so locking is not necessary.
499
500 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
501 // Only enable this in a limited test world with few objects.
502 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
503
504 // step the physical world one interval
505 m_simulationStep++;
506 int numSubSteps = 0;
507
508 try
509 {
510 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
511
512 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
513 out updatedEntityCount, out m_updateArray, out collidersCount, out m_collisionArray);
514
515 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
516 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
517 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
518 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
519 }
520 catch (Exception e)
521 {
522 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
523 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
524 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
525 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
526 updatedEntityCount = 0;
527 collidersCount = 0;
528 }
529
530 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
531
532 // Get a value for 'now' so all the collision and update routines don't have to get their own.
533 SimulationNowTime = Util.EnvironmentTickCount();
534
535 // If there were collisions, process them by sending the event to the prim.
536 // Collisions must be processed before updates.
537 if (collidersCount > 0)
538 {
539 for (int ii = 0; ii < collidersCount; ii++)
540 {
541 uint cA = m_collisionArray[ii].aID;
542 uint cB = m_collisionArray[ii].bID;
543 Vector3 point = new Vector3(m_collisionArray[ii].point.X, m_collisionArray[ii].point.Y,
544 m_collisionArray[ii].point.Z);
545 Vector3 normal = new Vector3(m_collisionArray[ii].normal.X, m_collisionArray[ii].normal.Y,
546 m_collisionArray[ii].normal.Z);
547 SendCollision(cA, cB, point, normal, 0.01f);
548 SendCollision(cB, cA, point, -normal, 0.01f);
549 }
550 }
551
552 // The above SendCollision's batch up the collisions on the objects.
553 // Now push the collisions into the simulator.
554 if (ObjectsWithCollisions.Count > 0)
555 {
556 foreach (BSPhysObject bsp in ObjectsWithCollisions)
557 if (!bsp.SendCollisions())
558 {
559 // If the object is done colliding, see that it's removed from the colliding list
560 ObjectsWithNoMoreCollisions.Add(bsp);
561 }
562 }
563
564 // This is a kludge to get avatar movement updates.
565 // The simulator expects collisions for avatars even if there are have been no collisions.
566 // The event updates avatar animations and stuff.
567 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
568 foreach (BSPhysObject bsp in m_avatars)
569 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
570 bsp.SendCollisions();
571
572 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
573 // Not done above because it is inside an iteration of ObjectWithCollisions.
574 // This complex collision processing is required to create an empty collision
575 // event call after all collisions have happened on an object. This enables
576 // the simulator to generate the 'collision end' event.
577 if (ObjectsWithNoMoreCollisions.Count > 0)
578 {
579 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
580 ObjectsWithCollisions.Remove(po);
581 ObjectsWithNoMoreCollisions.Clear();
582 }
583 // Done with collisions.
584
585 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
586 if (updatedEntityCount > 0)
587 {
588 for (int ii = 0; ii < updatedEntityCount; ii++)
589 {
590
591 BulletXNA.EntityProperties entprop = m_updateArray[ii];
592 BSPhysObject pobj;
593 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
594 {
595 EntityProperties prop = new EntityProperties()
596 {
597 Acceleration = new Vector3(entprop.Acceleration.X, entprop.Acceleration.Y, entprop.Acceleration.Z),
598 ID = entprop.ID,
599 Position = new Vector3(entprop.Position.X,entprop.Position.Y,entprop.Position.Z),
600 Rotation = new Quaternion(entprop.Rotation.X,entprop.Rotation.Y,entprop.Rotation.Z,entprop.Rotation.W),
601 RotationalVelocity = new Vector3(entprop.AngularVelocity.X,entprop.AngularVelocity.Y,entprop.AngularVelocity.Z),
602 Velocity = new Vector3(entprop.Velocity.X,entprop.Velocity.Y,entprop.Velocity.Z)
603 };
604 //m_log.Debug(pobj.Name + ":" + prop.ToString() + "\n");
605 pobj.UpdateProperties(prop);
606 }
607 }
608 }
609
610 TriggerPostStepEvent(timeStep);
611
612 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
613 // Only enable this in a limited test world with few objects.
614 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
615
616 // The physics engine returns the number of milliseconds it simulated this call.
617 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
618 // Multiply by 55 to give a nominal frame rate of 55.
619 return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
620 }
621
622 // Something has collided
623 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
624 {
625 if (localID <= TerrainManager.HighestTerrainID)
626 {
627 return; // don't send collisions to the terrain
628 }
629
630 BSPhysObject collider;
631 if (!PhysObjects.TryGetValue(localID, out collider))
632 {
633 // If the object that is colliding cannot be found, just ignore the collision.
634 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
635 return;
636 }
637
638 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
639 BSPhysObject collidee = null;
640 PhysObjects.TryGetValue(collidingWith, out collidee);
641
642 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
643
644 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
645 {
646 // If a collision was posted, remember to send it to the simulator
647 ObjectsWithCollisions.Add(collider);
648 }
649
650 return;
651 }
652
653 #endregion // Simulation
654
655 public override void GetResults() { }
656
657 #region Terrain
658
659 public override void SetTerrain(float[] heightMap) {
660 TerrainManager.SetTerrain(heightMap);
661 }
662
663 public override void SetWaterLevel(float baseheight)
664 {
665 SimpleWaterLevel = baseheight;
666 }
667
668 public override void DeleteTerrain()
669 {
670 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
671 }
672
673 // Although no one seems to check this, I do support combining.
674 public override bool SupportsCombining()
675 {
676 return TerrainManager.SupportsCombining();
677 }
678 // This call says I am a child to region zero in a mega-region. 'pScene' is that
679 // of region zero, 'offset' is my offset from regions zero's origin, and
680 // 'extents' is the largest XY that is handled in my region.
681 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
682 {
683 TerrainManager.Combine(pScene, offset, extents);
684 }
685
686 // Unhook all the combining that I know about.
687 public override void UnCombine(PhysicsScene pScene)
688 {
689 TerrainManager.UnCombine(pScene);
690 }
691
692 #endregion // Terrain
693
694 public override Dictionary<uint, float> GetTopColliders()
695 {
696 return new Dictionary<uint, float>();
697 }
698
699 public override bool IsThreaded { get { return false; } }
700
701 #region Taints
702 // The simulation execution order is:
703 // Simulate()
704 // DoOneTimeTaints
705 // TriggerPreStepEvent
706 // DoOneTimeTaints
707 // Step()
708 // ProcessAndForwardCollisions
709 // ProcessAndForwardPropertyUpdates
710 // TriggerPostStepEvent
711
712 // Calls to the PhysicsActors can't directly call into the physics engine
713 // because it might be busy. We delay changes to a known time.
714 // We rely on C#'s closure to save and restore the context for the delegate.
715 public void TaintedObject(String ident, TaintCallback callback)
716 {
717 if (!m_initialized) return;
718
719 lock (_taintLock)
720 {
721 _taintOperations.Add(new TaintCallbackEntry(ident, callback));
722 }
723
724 return;
725 }
726
727 // Sometimes a potentially tainted operation can be used in and out of taint time.
728 // This routine executes the command immediately if in taint-time otherwise it is queued.
729 public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback)
730 {
731 if (inTaintTime)
732 callback();
733 else
734 TaintedObject(ident, callback);
735 }
736
737 private void TriggerPreStepEvent(float timeStep)
738 {
739 PreStepAction actions = BeforeStep;
740 if (actions != null)
741 actions(timeStep);
742
743 }
744
745 private void TriggerPostStepEvent(float timeStep)
746 {
747 PreStepAction actions = AfterStep;
748 if (actions != null)
749 actions(timeStep);
750
751 }
752
753 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
754 // a callback into itself to do the actual property change. That callback is called
755 // here just before the physics engine is called to step the simulation.
756 public void ProcessTaints()
757 {
758 ProcessRegularTaints();
759 ProcessPostTaintTaints();
760 }
761
762 private void ProcessRegularTaints()
763 {
764 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
765 {
766 // swizzle a new list into the list location so we can process what's there
767 List<TaintCallbackEntry> oldList;
768 lock (_taintLock)
769 {
770 oldList = _taintOperations;
771 _taintOperations = new List<TaintCallbackEntry>();
772 }
773
774 foreach (TaintCallbackEntry tcbe in oldList)
775 {
776 try
777 {
778 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
779 tcbe.callback();
780 }
781 catch (Exception e)
782 {
783 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
784 }
785 }
786 oldList.Clear();
787 }
788 }
789
790 // Schedule an update to happen after all the regular taints are processed.
791 // Note that new requests for the same operation ("ident") for the same object ("ID")
792 // will replace any previous operation by the same object.
793 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
794 {
795 string uniqueIdent = ident + "-" + ID.ToString();
796 lock (_taintLock)
797 {
798 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback);
799 }
800
801 return;
802 }
803
804 // Taints that happen after the normal taint processing but before the simulation step.
805 private void ProcessPostTaintTaints()
806 {
807 if (_postTaintOperations.Count > 0)
808 {
809 Dictionary<string, TaintCallbackEntry> oldList;
810 lock (_taintLock)
811 {
812 oldList = _postTaintOperations;
813 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
814 }
815
816 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
817 {
818 try
819 {
820 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
821 kvp.Value.callback();
822 }
823 catch (Exception e)
824 {
825 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
826 }
827 }
828 oldList.Clear();
829 }
830 }
831
832 // Only used for debugging. Does not change state of anything so locking is not necessary.
833 public bool AssertInTaintTime(string whereFrom)
834 {
835 if (!InTaintTime)
836 {
837 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
838 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
839 Util.PrintCallStack(DetailLog);
840 }
841 return InTaintTime;
842 }
843
844 #endregion // Taints
845
846 #region INI and command line parameter processing
847
848 #region IPhysicsParameters
849 // Get the list of parameters this physics engine supports
850 public PhysParameterEntry[] GetParameterList()
851 {
852 BSParam.BuildParameterTable();
853 return BSParam.SettableParameters;
854 }
855
856 // Set parameter on a specific or all instances.
857 // Return 'false' if not able to set the parameter.
858 // Setting the value in the m_params block will change the value the physics engine
859 // will use the next time since it's pinned and shared memory.
860 // Some of the values require calling into the physics engine to get the new
861 // value activated ('terrainFriction' for instance).
862 public bool SetPhysicsParameter(string parm, float val, uint localID)
863 {
864 bool ret = false;
865 BSParam.ParameterDefn theParam;
866 if (BSParam.TryGetParameter(parm, out theParam))
867 {
868 theParam.setter(this, parm, localID, val);
869 ret = true;
870 }
871 return ret;
872 }
873
874 // update all the localIDs specified
875 // If the local ID is APPLY_TO_NONE, just change the default value
876 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
877 // If the localID is a specific object, apply the parameter change to only that object
878 internal delegate void AssignVal(float x);
879 internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
880 {
881 List<uint> objectIDs = new List<uint>();
882 switch (localID)
883 {
884 case PhysParameterEntry.APPLY_TO_NONE:
885 setDefault(val); // setting only the default value
886 // This will cause a call into the physical world if some operation is specified (SetOnObject).
887 objectIDs.Add(TERRAIN_ID);
888 TaintedUpdateParameter(parm, objectIDs, val);
889 break;
890 case PhysParameterEntry.APPLY_TO_ALL:
891 setDefault(val); // setting ALL also sets the default value
892 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
893 TaintedUpdateParameter(parm, objectIDs, val);
894 break;
895 default:
896 // setting only one localID
897 objectIDs.Add(localID);
898 TaintedUpdateParameter(parm, objectIDs, val);
899 break;
900 }
901 }
902
903 // schedule the actual updating of the paramter to when the phys engine is not busy
904 private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
905 {
906 float xval = val;
907 List<uint> xlIDs = lIDs;
908 string xparm = parm;
909 TaintedObject("BSScene.UpdateParameterSet", delegate() {
910 BSParam.ParameterDefn thisParam;
911 if (BSParam.TryGetParameter(xparm, out thisParam))
912 {
913 if (thisParam.onObject != null)
914 {
915 foreach (uint lID in xlIDs)
916 {
917 BSPhysObject theObject = null;
918 PhysObjects.TryGetValue(lID, out theObject);
919 thisParam.onObject(this, theObject, xval);
920 }
921 }
922 }
923 });
924 }
925
926 // Get parameter.
927 // Return 'false' if not able to get the parameter.
928 public bool GetPhysicsParameter(string parm, out float value)
929 {
930 float val = 0f;
931 bool ret = false;
932 BSParam.ParameterDefn theParam;
933 if (BSParam.TryGetParameter(parm, out theParam))
934 {
935 val = theParam.getter(this);
936 ret = true;
937 }
938 value = val;
939 return ret;
940 }
941
942 #endregion IPhysicsParameters
943
944 #endregion Runtime settable parameters
945
946 // Invoke the detailed logger and output something if it's enabled.
947 public void DetailLog(string msg, params Object[] args)
948 {
949 PhysicsLogging.Write(msg, args);
950 // Add the Flush() if debugging crashes. Gets all the messages written out.
951 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
952 }
953 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
954 public const string DetailLogZero = "0000000000";
955
956}
957}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs
deleted file mode 100644
index 47fb768..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSShapeCollection.cs
+++ /dev/null
@@ -1,1015 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37public sealed class BSShapeCollection : IDisposable
38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40
41 private BSScene PhysicsScene { get; set; }
42
43 private Object m_collectionActivityLock = new Object();
44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public Object ptr;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
52 }
53
54 // Description of a hull.
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc
57 {
58 public Object ptr;
59 public int referenceCount;
60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
62 }
63
64 // The sharable set of meshes and hulls. Indexed by their shape hash.
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67
68 private bool DDetail = false;
69
70 public BSShapeCollection(BSScene physScene)
71 {
72 PhysicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging
76 // statements can be commented/removed.
77 DDetail = true;
78 }
79
80 public void Dispose()
81 {
82 // TODO!!!!!!!!!
83 }
84
85 // Callbacks called just before either the body or shape is destroyed.
86 // Mostly used for changing bodies out from under Linksets.
87 // Useful for other cases where parameters need saving.
88 // Passing 'null' says no callback.
89 public delegate void ShapeDestructionCallback(BulletShape shape);
90 public delegate void BodyDestructionCallback(BulletBody body);
91
92 // Called to update/change the body and shape for an object.
93 // First checks the shape and updates that if necessary then makes
94 // sure the body is of the right type.
95 // Return 'true' if either the body or the shape changed.
96 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
97 // the current shape or body is destroyed. This allows the caller to remove any
98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
99 // remove the physical constraints before the body is destroyed.
100 // Called at taint-time!!
101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
103 {
104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
105
106 bool ret = false;
107
108 // This lock could probably be pushed down lower but building shouldn't take long
109 lock (m_collectionActivityLock)
110 {
111 // Do we have the correct geometry for this type of object?
112 // Updates prim.BSShape with information/pointers to shape.
113 // Returns 'true' of BSShape is changed to a new shape.
114 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback);
115 // If we had to select a new shape geometry for the object,
116 // rebuild the body around it.
117 // Updates prim.BSBody with information/pointers to requested body
118 // Returns 'true' if BSBody was changed.
119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
120 prim.PhysShape, bodyCallback);
121 ret = newGeom || newBody;
122 }
123 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
124 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
125
126 return ret;
127 }
128
129 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
130 {
131 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
132 }
133
134 // Track another user of a body.
135 // We presume the caller has allocated the body.
136 // Bodies only have one user so the body is just put into the world if not already there.
137 public void ReferenceBody(BulletBody body, bool inTaintTime)
138 {
139 lock (m_collectionActivityLock)
140 {
141 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
142 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
143 {
144 if (!BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr))
145 {
146 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
147 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
148 }
149 });
150 }
151 }
152
153 // Release the usage of a body.
154 // Called when releasing use of a BSBody. BSShape is handled separately.
155 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
156 {
157 if (!body.HasPhysicalBody)
158 return;
159
160 lock (m_collectionActivityLock)
161 {
162 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
163 {
164 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
165 body.ID, body, inTaintTime);
166 // If the caller needs to know the old body is going away, pass the event up.
167 if (bodyCallback != null) bodyCallback(body);
168
169 if (BulletSimAPI.IsInWorld2(PhysicsScene.World.ptr, body.ptr))
170 {
171 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
172 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
173 }
174
175 // Zero any reference to the shape so it is not freed when the body is deleted.
176 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, null);
177 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
178 });
179 }
180 }
181
182 // Track the datastructures and use count for a shape.
183 // When creating a hull, this is called first to reference the mesh
184 // and then again to reference the hull.
185 // Meshes and hulls for the same shape have the same hash key.
186 // NOTE that native shapes are not added to the mesh list or removed.
187 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
188 public bool ReferenceShape(BulletShape shape)
189 {
190 bool ret = false;
191 switch (shape.type)
192 {
193 case BSPhysicsShapeType.SHAPE_MESH:
194 MeshDesc meshDesc;
195 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
196 {
197 // There is an existing instance of this mesh.
198 meshDesc.referenceCount++;
199 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
200 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
201 }
202 else
203 {
204 // This is a new reference to a mesh
205 meshDesc.ptr = shape.ptr;
206 meshDesc.shapeKey = shape.shapeKey;
207 // We keep a reference to the underlying IMesh data so a hull can be built
208 meshDesc.referenceCount = 1;
209 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
210 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
211 ret = true;
212 }
213 meshDesc.lastReferenced = System.DateTime.Now;
214 Meshes[shape.shapeKey] = meshDesc;
215 break;
216 case BSPhysicsShapeType.SHAPE_HULL:
217 HullDesc hullDesc;
218 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
219 {
220 // There is an existing instance of this hull.
221 hullDesc.referenceCount++;
222 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
223 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
224 }
225 else
226 {
227 // This is a new reference to a hull
228 hullDesc.ptr = shape.ptr;
229 hullDesc.shapeKey = shape.shapeKey;
230 hullDesc.referenceCount = 1;
231 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
232 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
233 ret = true;
234
235 }
236 hullDesc.lastReferenced = System.DateTime.Now;
237 Hulls[shape.shapeKey] = hullDesc;
238 break;
239 case BSPhysicsShapeType.SHAPE_UNKNOWN:
240 break;
241 default:
242 // Native shapes are not tracked and they don't go into any list
243 break;
244 }
245 return ret;
246 }
247
248 // Release the usage of a shape.
249 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
250 {
251 if (!shape.HasPhysicalShape)
252 return;
253
254 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
255 {
256 if (shape.HasPhysicalShape)
257 {
258 if (shape.isNativeShape)
259 {
260 // Native shapes are not tracked and are released immediately
261 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
262 BSScene.DetailLogZero, shape.ptr.ToString(), inTaintTime);
263 if (shapeCallback != null) shapeCallback(shape);
264 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
265 }
266 else
267 {
268 switch (shape.type)
269 {
270 case BSPhysicsShapeType.SHAPE_HULL:
271 DereferenceHull(shape, shapeCallback);
272 break;
273 case BSPhysicsShapeType.SHAPE_MESH:
274 DereferenceMesh(shape, shapeCallback);
275 break;
276 case BSPhysicsShapeType.SHAPE_COMPOUND:
277 DereferenceCompound(shape, shapeCallback);
278 break;
279 case BSPhysicsShapeType.SHAPE_UNKNOWN:
280 break;
281 default:
282 break;
283 }
284 }
285 }
286 });
287 }
288
289 // Count down the reference count for a mesh shape
290 // Called at taint-time.
291 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
292 {
293 MeshDesc meshDesc;
294 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
295 {
296 meshDesc.referenceCount--;
297 // TODO: release the Bullet storage
298 if (shapeCallback != null) shapeCallback(shape);
299 meshDesc.lastReferenced = System.DateTime.Now;
300 Meshes[shape.shapeKey] = meshDesc;
301 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
302 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
303
304 }
305 }
306
307 // Count down the reference count for a hull shape
308 // Called at taint-time.
309 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
310 {
311 HullDesc hullDesc;
312 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
313 {
314 hullDesc.referenceCount--;
315 // TODO: release the Bullet storage (aging old entries?)
316
317 // Tell upper layers that, if they have dependencies on this shape, this link is going away
318 if (shapeCallback != null) shapeCallback(shape);
319
320 hullDesc.lastReferenced = System.DateTime.Now;
321 Hulls[shape.shapeKey] = hullDesc;
322 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
323 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
324 }
325 }
326
327 // Remove a reference to a compound shape.
328 // Taking a compound shape apart is a little tricky because if you just delete the
329 // physical shape, it will free all the underlying children. We can't do that because
330 // they could be shared. So, this removes each of the children from the compound and
331 // dereferences them separately before destroying the compound collision object itself.
332 // Called at taint-time.
333 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
334 {
335 if (!BulletSimAPI.IsCompound2(shape.ptr))
336 {
337 // Failed the sanity check!!
338 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
339 LogHeader, shape.type, shape.ptr.ToString());
340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
341 BSScene.DetailLogZero, shape.type, shape.ptr.ToString());
342 return;
343 }
344
345 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
346 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
347
348 for (int ii = numChildren - 1; ii >= 0; ii--)
349 {
350 Object childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
351 DereferenceAnonCollisionShape(childShape);
352 }
353 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
354 }
355
356 // Sometimes we have a pointer to a collision shape but don't know what type it is.
357 // Figure out type and call the correct dereference routine.
358 // Called at taint-time.
359 private void DereferenceAnonCollisionShape(Object cShape)
360 {
361 MeshDesc meshDesc;
362 HullDesc hullDesc;
363
364 BulletShape shapeInfo = new BulletShape(cShape);
365 if (TryGetMeshByPtr(cShape, out meshDesc))
366 {
367 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
368 shapeInfo.shapeKey = meshDesc.shapeKey;
369 }
370 else
371 {
372 if (TryGetHullByPtr(cShape, out hullDesc))
373 {
374 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
375 shapeInfo.shapeKey = hullDesc.shapeKey;
376 }
377 else
378 {
379 if (BulletSimAPI.IsCompound2(cShape))
380 {
381 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
382 }
383 else
384 {
385 if (BulletSimAPI.IsNativeShape2(cShape))
386 {
387 shapeInfo.isNativeShape = true;
388 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
389 }
390 }
391 }
392 }
393
394 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
395
396 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
397 {
398 DereferenceShape(shapeInfo, true, null);
399 }
400 else
401 {
402 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
403 LogHeader, PhysicsScene.RegionName, cShape.ToString());
404 }
405 }
406
407 // Create the geometry information in Bullet for later use.
408 // The objects needs a hull if it's physical otherwise a mesh is enough.
409 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
410 // shared geometries will be used. If the parameters of the existing shape are the same
411 // as this request, the shape is not rebuilt.
412 // Info in prim.BSShape is updated to the new shape.
413 // Returns 'true' if the geometry was rebuilt.
414 // Called at taint-time!
415 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
416 {
417 bool ret = false;
418 bool haveShape = false;
419
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
421 {
422 // an avatar capsule is close to a native shape (it is not shared)
423 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
424 FixedShapeKey.KEY_CAPSULE, shapeCallback);
425 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
426 ret = true;
427 haveShape = true;
428 }
429
430 // Compound shapes are handled special as they are rebuilt from scratch.
431 // This isn't too great a hardship since most of the child shapes will have already been created.
432 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
433 {
434 ret = GetReferenceToCompoundShape(prim, shapeCallback);
435 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
436 haveShape = true;
437 }
438
439 if (!haveShape)
440 {
441 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
442 }
443
444 return ret;
445 }
446
447 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
448 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
449 {
450 bool ret = false;
451 bool haveShape = false;
452 bool nativeShapePossible = true;
453 PrimitiveBaseShape pbs = prim.BaseShape;
454
455 // If the prim attributes are simple, this could be a simple Bullet native shape
456 if (!haveShape
457 && pbs != null
458 && nativeShapePossible
459 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
460 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
461 && pbs.ProfileHollow == 0
462 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
463 && pbs.PathBegin == 0 && pbs.PathEnd == 0
464 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
465 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
466 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
467 {
468 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
469 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
470 if (prim.PhysShape.HasPhysicalShape)
471 scaleOfExistingShape = BulletSimAPI.GetLocalScaling2(prim.PhysShape.ptr);
472
473 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
474 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
475
476 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
477 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
478 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
479 {
480 haveShape = true;
481 if (forceRebuild
482 || prim.Scale != scaleOfExistingShape
483 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
484 )
485 {
486 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
487 FixedShapeKey.KEY_SPHERE, shapeCallback);
488 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
489 prim.LocalID, forceRebuild, prim.PhysShape);
490 }
491 }
492 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
493 {
494 haveShape = true;
495 if (forceRebuild
496 || prim.Scale != scaleOfExistingShape
497 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
498 )
499 {
500 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
501 FixedShapeKey.KEY_BOX, shapeCallback);
502 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
503 prim.LocalID, forceRebuild, prim.PhysShape);
504 }
505 }
506 }
507
508 // If a simple shape is not happening, create a mesh and possibly a hull.
509 if (!haveShape && pbs != null)
510 {
511 ret = CreateGeomMeshOrHull(prim, shapeCallback);
512 }
513
514 return ret;
515 }
516
517 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
518 {
519
520 bool ret = false;
521 // Note that if it's a native shape, the check for physical/non-physical is not
522 // made. Native shapes work in either case.
523 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
524 {
525 // Update prim.BSShape to reference a hull of this shape.
526 ret = GetReferenceToHull(prim,shapeCallback);
527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
529 }
530 else
531 {
532 ret = GetReferenceToMesh(prim, shapeCallback);
533 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
534 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
535 }
536 return ret;
537 }
538
539 // Creates a native shape and assignes it to prim.BSShape.
540 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
541 private bool GetReferenceToNativeShape(BSPhysObject prim,
542 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
543 ShapeDestructionCallback shapeCallback)
544 {
545 // release any previous shape
546 DereferenceShape(prim.PhysShape, true, shapeCallback);
547
548 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
549
550 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
551 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
552 prim.LocalID, newShape, prim.Scale);
553
554 // native shapes are scaled by Bullet
555 prim.PhysShape = newShape;
556 return true;
557 }
558
559 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
560 FixedShapeKey shapeKey)
561 {
562 BulletShape newShape;
563 // Need to make sure the passed shape information is for the native type.
564 ShapeData nativeShapeData = new ShapeData();
565 nativeShapeData.Type = shapeType;
566 nativeShapeData.ID = prim.LocalID;
567 nativeShapeData.Scale = prim.Scale;
568 nativeShapeData.Size = prim.Scale; // unneeded, I think.
569 nativeShapeData.MeshKey = (ulong)shapeKey;
570 nativeShapeData.HullKey = (ulong)shapeKey;
571
572 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
573 {
574 // The proper scale has been calculated in the prim.
575 newShape = new BulletShape(
576 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
577 , shapeType);
578 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
579 }
580 else
581 {
582 // Native shapes are scaled in Bullet so set the scaling to the size
583 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
584 }
585 if (!newShape.HasPhysicalShape)
586 {
587 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
588 LogHeader, prim.LocalID, shapeType);
589 }
590 newShape.shapeKey = (System.UInt64)shapeKey;
591 newShape.isNativeShape = true;
592
593 return newShape;
594 }
595
596 // Builds a mesh shape in the physical world and updates prim.BSShape.
597 // Dereferences previous shape in BSShape and adds a reference for this new shape.
598 // Returns 'true' of a mesh was actually built. Otherwise .
599 // Called at taint-time!
600 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
601 {
602 BulletShape newShape = new BulletShape();
603
604 float lod;
605 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
606
607 // if this new shape is the same as last time, don't recreate the mesh
608 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
609 return false;
610
611 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
612 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
613
614 // Since we're recreating new, get rid of the reference to the previous shape
615 DereferenceShape(prim.PhysShape, true, shapeCallback);
616
617 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod);
618 // Take evasive action if the mesh was not constructed.
619 newShape = VerifyMeshCreated(newShape, prim);
620
621 ReferenceShape(newShape);
622
623 prim.PhysShape = newShape;
624
625 return true; // 'true' means a new shape has been added to this prim
626 }
627
628 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
629 {
630 IMesh meshData = null;
631 Object meshPtr = null;
632 MeshDesc meshDesc;
633 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
634 {
635 // If the mesh has already been built just use it.
636 meshPtr = meshDesc.ptr;
637 }
638 else
639 {
640 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
641
642 if (meshData != null)
643 {
644 int[] indices = meshData.getIndexListAsInt();
645 List<OMV.Vector3> vertices = meshData.getVertexList();
646
647 float[] verticesAsFloats = new float[vertices.Count * 3];
648 int vi = 0;
649 foreach (OMV.Vector3 vv in vertices)
650 {
651 verticesAsFloats[vi++] = vv.X;
652 verticesAsFloats[vi++] = vv.Y;
653 verticesAsFloats[vi++] = vv.Z;
654 }
655
656 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
657 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
658
659 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
660 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
661 }
662 }
663 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
664 newShape.shapeKey = newMeshKey;
665
666 return newShape;
667 }
668
669 // See that hull shape exists in the physical world and update prim.BSShape.
670 // We could be creating the hull because scale changed or whatever.
671 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
672 {
673 BulletShape newShape;
674
675 float lod;
676 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
677
678 // if the hull hasn't changed, don't rebuild it
679 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
680 return false;
681
682 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
683 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
684
685 // Remove usage of the previous shape.
686 DereferenceShape(prim.PhysShape, true, shapeCallback);
687
688 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
689 newShape = VerifyMeshCreated(newShape, prim);
690
691 ReferenceShape(newShape);
692
693 prim.PhysShape = newShape;
694 return true; // 'true' means a new shape has been added to this prim
695 }
696
697 List<ConvexResult> m_hulls;
698 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
699 {
700
701 Object hullPtr = null;
702 HullDesc hullDesc;
703 if (Hulls.TryGetValue(newHullKey, out hullDesc))
704 {
705 // If the hull shape already is created, just use it.
706 hullPtr = hullDesc.ptr;
707 }
708 else
709 {
710 // Build a new hull in the physical world
711 // Pass true for physicalness as this creates some sort of bounding box which we don't need
712 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
713 if (meshData != null)
714 {
715
716 int[] indices = meshData.getIndexListAsInt();
717 List<OMV.Vector3> vertices = meshData.getVertexList();
718
719 //format conversion from IMesh format to DecompDesc format
720 List<int> convIndices = new List<int>();
721 List<float3> convVertices = new List<float3>();
722 for (int ii = 0; ii < indices.GetLength(0); ii++)
723 {
724 convIndices.Add(indices[ii]);
725 }
726 foreach (OMV.Vector3 vv in vertices)
727 {
728 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
729 }
730
731 // setup and do convex hull conversion
732 m_hulls = new List<ConvexResult>();
733 DecompDesc dcomp = new DecompDesc();
734 dcomp.mIndices = convIndices;
735 dcomp.mVertices = convVertices;
736 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
737 // create the hull into the _hulls variable
738 convexBuilder.process(dcomp);
739
740 // Convert the vertices and indices for passing to unmanaged.
741 // The hull information is passed as a large floating point array.
742 // The format is:
743 // convHulls[0] = number of hulls
744 // convHulls[1] = number of vertices in first hull
745 // convHulls[2] = hull centroid X coordinate
746 // convHulls[3] = hull centroid Y coordinate
747 // convHulls[4] = hull centroid Z coordinate
748 // convHulls[5] = first hull vertex X
749 // convHulls[6] = first hull vertex Y
750 // convHulls[7] = first hull vertex Z
751 // convHulls[8] = second hull vertex X
752 // ...
753 // convHulls[n] = number of vertices in second hull
754 // convHulls[n+1] = second hull centroid X coordinate
755 // ...
756 //
757 // TODO: is is very inefficient. Someday change the convex hull generator to return
758 // data structures that do not need to be converted in order to pass to Bullet.
759 // And maybe put the values directly into pinned memory rather than marshaling.
760 int hullCount = m_hulls.Count;
761 int totalVertices = 1; // include one for the count of the hulls
762 foreach (ConvexResult cr in m_hulls)
763 {
764 totalVertices += 4; // add four for the vertex count and centroid
765 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
766 }
767 float[] convHulls = new float[totalVertices];
768
769 convHulls[0] = (float)hullCount;
770 int jj = 1;
771 foreach (ConvexResult cr in m_hulls)
772 {
773 // copy vertices for index access
774 float3[] verts = new float3[cr.HullVertices.Count];
775 int kk = 0;
776 foreach (float3 ff in cr.HullVertices)
777 {
778 verts[kk++] = ff;
779 }
780
781 // add to the array one hull's worth of data
782 convHulls[jj++] = cr.HullIndices.Count;
783 convHulls[jj++] = 0f; // centroid x,y,z
784 convHulls[jj++] = 0f;
785 convHulls[jj++] = 0f;
786 foreach (int ind in cr.HullIndices)
787 {
788 convHulls[jj++] = verts[ind].x;
789 convHulls[jj++] = verts[ind].y;
790 convHulls[jj++] = verts[ind].z;
791 }
792 }
793 // create the hull data structure in Bullet
794 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
795 }
796 }
797
798 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
799 newShape.shapeKey = newHullKey;
800
801 return newShape;
802 }
803
804 // Callback from convex hull creater with a newly created hull.
805 // Just add it to our collection of hulls for this shape.
806 private void HullReturn(ConvexResult result)
807 {
808 m_hulls.Add(result);
809 return;
810 }
811
812 // Compound shapes are always built from scratch.
813 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
814 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
815 {
816 // Remove reference to the old shape
817 // Don't need to do this as the shape is freed when the new root shape is created below.
818 // DereferenceShape(prim.PhysShape, true, shapeCallback);
819
820 BulletShape cShape = new BulletShape(
821 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
822
823 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
824 CreateGeomMeshOrHull(prim, shapeCallback);
825 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
826 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
827 prim.LocalID, cShape, prim.PhysShape);
828
829 prim.PhysShape = cShape;
830
831 return true;
832 }
833
834 // Create a hash of all the shape parameters to be used as a key
835 // for this particular shape.
836 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
837 {
838 // level of detail based on size and type of the object
839 float lod = BSParam.MeshLOD;
840 if (pbs.SculptEntry)
841 lod = BSParam.SculptLOD;
842
843 // Mega prims usually get more detail because one can interact with shape approximations at this size.
844 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
845 if (maxAxis > BSParam.MeshMegaPrimThreshold)
846 lod = BSParam.MeshMegaPrimLOD;
847
848 retLod = lod;
849 return pbs.GetMeshKey(size, lod);
850 }
851 // For those who don't want the LOD
852 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
853 {
854 float lod;
855 return ComputeShapeKey(size, pbs, out lod);
856 }
857
858 // The creation of a mesh or hull can fail if an underlying asset is not available.
859 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
860 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
861 // The first case causes the asset to be fetched. The second case requires
862 // us to not loop forever.
863 // Called after creating a physical mesh or hull. If the physical shape was created,
864 // just return.
865 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
866 {
867 // If the shape was successfully created, nothing more to do
868 if (newShape.HasPhysicalShape)
869 return newShape;
870
871 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
872 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
873 {
874 prim.LastAssetBuildFailed = true;
875 BSPhysObject xprim = prim;
876 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
877 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
878 Util.FireAndForget(delegate
879 {
880 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
881 if (assetProvider != null)
882 {
883 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
884 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
885 {
886 if (!yprim.BaseShape.SculptEntry)
887 return;
888 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
889 return;
890
891 yprim.BaseShape.SculptData = asset.Data;
892 // This will cause the prim to see that the filler shape is not the right
893 // one and try again to build the object.
894 // No race condition with the normal shape setting since the rebuild is at taint time.
895 yprim.ForceBodyShapeRebuild(false);
896
897 });
898 }
899 });
900 }
901 else
902 {
903 if (prim.LastAssetBuildFailed)
904 {
905 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
906 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
907 }
908 }
909
910 // While we figure out the real problem, stick a simple native shape on the object.
911 BulletShape fillinShape =
912 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
913
914 return fillinShape;
915 }
916
917 // Create a body object in Bullet.
918 // Updates prim.BSBody with the information about the new body if one is created.
919 // Returns 'true' if an object was actually created.
920 // Called at taint-time.
921 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape,
922 BodyDestructionCallback bodyCallback)
923 {
924 bool ret = false;
925
926 // the mesh, hull or native shape must have already been created in Bullet
927 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
928
929 // If there is an existing body, verify it's of an acceptable type.
930 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
931 if (!mustRebuild)
932 {
933 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr);
934 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
935 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
936 {
937 // If the collisionObject is not the correct type for solidness, rebuild what's there
938 mustRebuild = true;
939 }
940 }
941
942 if (mustRebuild || forceRebuild)
943 {
944 // Free any old body
945 DereferenceBody(prim.PhysBody, true, bodyCallback);
946
947 BulletBody aBody;
948 Object bodyPtr = null;
949 if (prim.IsSolid)
950 {
951 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
952 prim.LocalID, prim.RawPosition, prim.RawOrientation);
953 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString());
954 }
955 else
956 {
957 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
958 prim.LocalID, prim.RawPosition, prim.RawOrientation);
959 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString());
960 }
961 aBody = new BulletBody(prim.LocalID, bodyPtr);
962
963 ReferenceBody(aBody, true);
964
965 prim.PhysBody = aBody;
966
967 ret = true;
968 }
969
970 return ret;
971 }
972
973 private bool TryGetMeshByPtr(Object addr, out MeshDesc outDesc)
974 {
975 bool ret = false;
976 MeshDesc foundDesc = new MeshDesc();
977 foreach (MeshDesc md in Meshes.Values)
978 {
979 if (md.ptr == addr)
980 {
981 foundDesc = md;
982 ret = true;
983 break;
984 }
985
986 }
987 outDesc = foundDesc;
988 return ret;
989 }
990
991 private bool TryGetHullByPtr(Object addr, out HullDesc outDesc)
992 {
993 bool ret = false;
994 HullDesc foundDesc = new HullDesc();
995 foreach (HullDesc hd in Hulls.Values)
996 {
997 if (hd.ptr == addr)
998 {
999 foundDesc = hd;
1000 ret = true;
1001 break;
1002 }
1003
1004 }
1005 outDesc = foundDesc;
1006 return ret;
1007 }
1008
1009 private void DetailLog(string msg, params Object[] args)
1010 {
1011 if (PhysicsScene.PhysicsLogging.Enabled)
1012 PhysicsScene.DetailLog(msg, args);
1013 }
1014}
1015}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs
deleted file mode 100644
index 8ff0275..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSShapes.cs
+++ /dev/null
@@ -1,208 +0,0 @@
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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33namespace OpenSim.Region.Physics.BulletSNPlugin
34{
35public abstract class BSShape
36{
37 public Object ptr { get; set; }
38 public BSPhysicsShapeType type { get; set; }
39 public System.UInt64 key { get; set; }
40 public int referenceCount { get; set; }
41 public DateTime lastReferenced { get; set; }
42
43 public BSShape()
44 {
45 ptr = null;
46 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
47 key = 0;
48 referenceCount = 0;
49 lastReferenced = DateTime.Now;
50 }
51
52 // Get a reference to a physical shape. Create if it doesn't exist
53 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
54 {
55 BSShape ret = null;
56
57 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
58 {
59 // an avatar capsule is close to a native shape (it is not shared)
60 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
61 FixedShapeKey.KEY_CAPSULE);
62 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
63 }
64
65 // Compound shapes are handled special as they are rebuilt from scratch.
66 // This isn't too great a hardship since most of the child shapes will already been created.
67 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
68 {
69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
70 ret = BSShapeCompound.GetReference(prim);
71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
72 }
73
74 if (ret == null)
75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
76
77 return ret;
78 }
79 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
80 {
81 return null;
82 }
83 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
84 {
85 return null;
86 }
87
88 // Release the use of a physical shape.
89 public abstract void Dereference(BSScene physicsScene);
90
91 // All shapes have a static call to get a reference to the physical shape
92 // protected abstract static BSShape GetReference();
93
94 public override string ToString()
95 {
96 StringBuilder buff = new StringBuilder();
97 buff.Append("<p=");
98 buff.Append(ptr.ToString());
99 buff.Append(",s=");
100 buff.Append(type.ToString());
101 buff.Append(",k=");
102 buff.Append(key.ToString("X"));
103 buff.Append(",c=");
104 buff.Append(referenceCount.ToString());
105 buff.Append(">");
106 return buff.ToString();
107 }
108}
109
110public class BSShapeNull : BSShape
111{
112 public BSShapeNull() : base()
113 {
114 }
115 public static BSShape GetReference() { return new BSShapeNull(); }
116 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
117}
118
119public class BSShapeNative : BSShape
120{
121 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
122 public BSShapeNative() : base()
123 {
124 }
125 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
126 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
127 {
128 // Native shapes are not shared and are always built anew.
129 return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
130 }
131
132 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
133 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
134 {
135 ShapeData nativeShapeData = new ShapeData();
136 nativeShapeData.Type = shapeType;
137 nativeShapeData.ID = prim.LocalID;
138 nativeShapeData.Scale = prim.Scale;
139 nativeShapeData.Size = prim.Scale;
140 nativeShapeData.MeshKey = (ulong)shapeKey;
141 nativeShapeData.HullKey = (ulong)shapeKey;
142
143
144 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
145 {
146 ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
147 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
148 }
149 else
150 {
151 ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData);
152 }
153 if (ptr == null)
154 {
155 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
156 LogHeader, prim.LocalID, shapeType);
157 }
158 type = shapeType;
159 key = (UInt64)shapeKey;
160 }
161 // Make this reference to the physical shape go away since native shapes are not shared.
162 public override void Dereference(BSScene physicsScene)
163 {
164 // Native shapes are not tracked and are released immediately
165 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
166 BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr);
167 ptr = null;
168 // Garbage collection will free up this instance.
169 }
170}
171
172public class BSShapeMesh : BSShape
173{
174 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
175 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
176
177 public BSShapeMesh() : base()
178 {
179 }
180 public static BSShape GetReference() { return new BSShapeNull(); }
181 public override void Dereference(BSScene physicsScene) { }
182}
183
184public class BSShapeHull : BSShape
185{
186 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
187 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
188
189 public BSShapeHull() : base()
190 {
191 }
192 public static BSShape GetReference() { return new BSShapeNull(); }
193 public override void Dereference(BSScene physicsScene) { }
194}
195
196public class BSShapeCompound : BSShape
197{
198 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
199 public BSShapeCompound() : base()
200 {
201 }
202 public static BSShape GetReference(BSPhysObject prim)
203 {
204 return new BSShapeNull();
205 }
206 public override void Dereference(BSScene physicsScene) { }
207}
208}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs
deleted file mode 100644
index ba17059..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainHeightmap.cs
+++ /dev/null
@@ -1,175 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSNPlugin
42{
43public sealed class BSTerrainHeightmap : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46
47 BulletHeightMapInfo m_mapInfo = null;
48
49 // Constructor to build a default, flat heightmap terrain.
50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
51 : base(physicsScene, regionBase, id)
52 {
53 Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
54 Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
55 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
56 float[] initialMap = new float[totalHeights];
57 for (int ii = 0; ii < totalHeights; ii++)
58 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 }
61 m_mapInfo = new BulletHeightMapInfo(id, initialMap, null);
62 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase;
65 // Don't have to free any previous since we just got here.
66 BuildHeightmapTerrain();
67 }
68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id)
74 {
75 m_mapInfo = new BulletHeightMapInfo(id, initialMap, null);
76 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z;
79 m_mapInfo.maxZ = maxCoords.Z;
80 m_mapInfo.terrainRegionBase = TerrainBase;
81
82 // Don't have to free any previous since we just got here.
83 BuildHeightmapTerrain();
84 }
85
86 public override void Dispose()
87 {
88 ReleaseHeightMapTerrain();
89 }
90
91 // Using the information in m_mapInfo, create the physical representation of the heightmap.
92 private void BuildHeightmapTerrain()
93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, BSParam.TerrainCollisionMargin);
97
98 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
100 BSPhysicsShapeType.SHAPE_TERRAIN);
101
102 // The terrain object initial position is at the center of the object
103 Vector3 centerPos;
104 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
105 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
106 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f - 0.5f);
107
108 m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID,
109 BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr,
110 m_mapInfo.ID, centerPos, Quaternion.Identity));
111
112 // Set current terrain attributes
113 BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainFriction);
114 BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainHitFraction);
115 BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, BSParam.TerrainRestitution);
116 BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
117
118 // Return the new terrain to the world of physical objects
119 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr, centerPos, Quaternion.Identity);
120
121 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
123
124 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
125 m_mapInfo.terrainBody.ApplyCollisionMask();
126
127 // Make it so the terrain will not move or be considered for movement.
128 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
129
130 return;
131 }
132
133 // If there is information in m_mapInfo pointing to physical structures, release same.
134 private void ReleaseHeightMapTerrain()
135 {
136 if (m_mapInfo != null)
137 {
138 if (m_mapInfo.terrainBody.HasPhysicalBody)
139 {
140 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
141 // Frees both the body and the shape.
142 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
143 BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr);
144 }
145 }
146 m_mapInfo = null;
147 }
148
149 // The passed position is relative to the base of the region.
150 public override float GetTerrainHeightAtXYZ(Vector3 pos)
151 {
152 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
153
154 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
155 try
156 {
157 ret = m_mapInfo.heightMap[mapIndex];
158 }
159 catch
160 {
161 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
162 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
163 LogHeader, m_mapInfo.terrainRegionBase, pos);
164 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
165 }
166 return ret;
167 }
168
169 // The passed position is relative to the base of the region.
170 public override float GetWaterLevelAtXYZ(Vector3 pos)
171 {
172 return PhysicsScene.SimpleWaterLevel;
173 }
174}
175}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs
deleted file mode 100644
index 66d62f0..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainManager.cs
+++ /dev/null
@@ -1,461 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSNPlugin
42{
43
44// The physical implementation of the terrain is wrapped in this class.
45public abstract class BSTerrainPhys : IDisposable
46{
47 public enum TerrainImplementation
48 {
49 Heightmap = 0,
50 Mesh = 1
51 }
52
53 public BSScene PhysicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; }
57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 {
60 PhysicsScene = physicsScene;
61 TerrainBase = regionBase;
62 ID = id;
63 }
64 public abstract void Dispose();
65 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
66 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
67}
68
69// ==========================================================================================
70public sealed class BSTerrainManager : IDisposable
71{
72 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
73
74 // These height values are fractional so the odd values will be
75 // noticable when debugging.
76 public const float HEIGHT_INITIALIZATION = 24.987f;
77 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
78 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
79 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
80
81 // If the min and max height are equal, we reduce the min by this
82 // amount to make sure that a bounding box is built for the terrain.
83 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
84
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);
87
88 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; }
90
91 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane;
93
94 // If doing mega-regions, if we're region zero we will be managing multiple
95 // region terrains since region zero does the physics for the whole mega-region.
96 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
97
98 // Flags used to know when to recalculate the height.
99 private bool m_terrainModified = false;
100
101 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
102 // This is incremented before assigning to new region so it is the last ID allocated.
103 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
104 public uint HighestTerrainID { get {return m_terrainCount; } }
105
106 // If doing mega-regions, this holds our offset from region zero of
107 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
108 private Vector3 m_worldOffset;
109 // If the parent region (region 0), this is the extent of the combined regions
110 // relative to the origin of region zero
111 private Vector3 m_worldMax;
112 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
113
114 public BSTerrainManager(BSScene physicsScene)
115 {
116 PhysicsScene = physicsScene;
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118
119 // Assume one region of default size
120 m_worldOffset = Vector3.Zero;
121 m_worldMax = new Vector3(DefaultRegionSize);
122 MegaRegionParentPhysicsScene = null;
123 }
124
125 public void Dispose()
126 {
127 ReleaseGroundPlaneAndTerrain();
128 }
129
130 // Create the initial instance of terrain and the underlying ground plane.
131 // This is called from the initialization routine so we presume it is
132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain()
134 {
135 // The ground plane is here to catch things that are trying to drop to negative infinity
136 BulletShape groundPlaneShape = new BulletShape(
137 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
138 BSParam.TerrainCollisionMargin),
139 BSPhysicsShapeType.SHAPE_GROUNDPLANE);
140 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
141 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
142 Vector3.Zero, Quaternion.Identity));
143 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr, Vector3.Zero, Quaternion.Identity);
144 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
145 // Ground plane does not move
146 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
147 // Everything collides with the ground plane.
148 m_groundPlane.collisionType = CollisionType.Groundplane;
149 m_groundPlane.ApplyCollisionMask();
150
151 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
152 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
153 m_terrains.Add(Vector3.Zero, initialTerrain);
154 }
155
156 // Release all the terrain structures we might have allocated
157 public void ReleaseGroundPlaneAndTerrain()
158 {
159 if (m_groundPlane.HasPhysicalBody)
160 {
161 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
162 {
163 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
164 }
165 m_groundPlane.Clear();
166 }
167
168 ReleaseTerrain();
169 }
170
171 // Release all the terrain we have allocated
172 public void ReleaseTerrain()
173 {
174 lock (m_terrains)
175 {
176 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
177 {
178 kvp.Value.Dispose();
179 }
180 m_terrains.Clear();
181 }
182 }
183
184 // The simulator wants to set a new heightmap for the terrain.
185 public void SetTerrain(float[] heightMap) {
186 float[] localHeightMap = heightMap;
187 // If there are multiple requests for changes to the same terrain between ticks,
188 // only do that last one.
189 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
190 {
191 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
192 {
193 // If a child of a mega-region, we shouldn't have any terrain allocated for us
194 ReleaseGroundPlaneAndTerrain();
195 // If doing the mega-prim stuff and we are the child of the zero region,
196 // the terrain is added to our parent
197 if (MegaRegionParentPhysicsScene is BSScene)
198 {
199 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
200 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
201 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
202 BSScene.CHILDTERRAIN_ID, localHeightMap,
203 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
204 }
205 }
206 else
207 {
208 // If not doing the mega-prim thing, just change the terrain
209 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
210
211 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
212 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
213 }
214 });
215 }
216
217 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
218 // based on the passed information. The 'id' should be either the terrain id or
219 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
220 // The latter feature is for creating child terrains for mega-regions.
221 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
222 // terrain shape is created and added to the body.
223 // This call is most often used to update the heightMap and parameters of the terrain.
224 // (The above does suggest that some simplification/refactoring is in order.)
225 // Called during taint-time.
226 private void UpdateTerrain(uint id, float[] heightMap,
227 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
228 {
229 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
230 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
231
232 // Find high and low points of passed heightmap.
233 // The min and max passed in is usually the area objects can be in (maximum
234 // object height, for instance). The terrain wants the bounding box for the
235 // terrain so replace passed min and max Z with the actual terrain min/max Z.
236 float minZ = float.MaxValue;
237 float maxZ = float.MinValue;
238 foreach (float height in heightMap)
239 {
240 if (height < minZ) minZ = height;
241 if (height > maxZ) maxZ = height;
242 }
243 if (minZ == maxZ)
244 {
245 // If min and max are the same, reduce min a little bit so a good bounding box is created.
246 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
247 }
248 minCoords.Z = minZ;
249 maxCoords.Z = maxZ;
250
251 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
252
253 lock (m_terrains)
254 {
255 BSTerrainPhys terrainPhys;
256 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
257 {
258 // There is already a terrain in this spot. Free the old and build the new.
259 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
260 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
261
262 // Remove old terrain from the collection
263 m_terrains.Remove(terrainRegionBase);
264 // Release any physical memory it may be using.
265 terrainPhys.Dispose();
266
267 if (MegaRegionParentPhysicsScene == null)
268 {
269 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
270 m_terrains.Add(terrainRegionBase, newTerrainPhys);
271
272 m_terrainModified = true;
273 }
274 else
275 {
276 // It's possible that Combine() was called after this code was queued.
277 // If we are a child of combined regions, we don't create any terrain for us.
278 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
279
280 // Get rid of any terrain that may have been allocated for us.
281 ReleaseGroundPlaneAndTerrain();
282
283 // I hate doing this, but just bail
284 return;
285 }
286 }
287 else
288 {
289 // We don't know about this terrain so either we are creating a new terrain or
290 // our mega-prim child is giving us a new terrain to add to the phys world
291
292 // if this is a child terrain, calculate a unique terrain id
293 uint newTerrainID = id;
294 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
295 newTerrainID = ++m_terrainCount;
296
297 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
298 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
299 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
300 m_terrains.Add(terrainRegionBase, newTerrainPhys);
301
302 m_terrainModified = true;
303 }
304 }
305 }
306
307 // TODO: redo terrain implementation selection to allow other base types than heightMap.
308 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
309 {
310 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
311 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
312 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
313 BSTerrainPhys newTerrainPhys = null;
314 switch ((int)BSParam.TerrainImplementation)
315 {
316 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
317 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
318 heightMap, minCoords, maxCoords);
319 break;
320 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
321 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id,
322 heightMap, minCoords, maxCoords);
323 break;
324 default:
325 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
326 LogHeader,
327 (int)BSParam.TerrainImplementation,
328 BSParam.TerrainImplementation,
329 PhysicsScene.RegionName, terrainRegionBase);
330 break;
331 }
332 return newTerrainPhys;
333 }
334
335 // Return 'true' of this position is somewhere in known physical terrain space
336 public bool IsWithinKnownTerrain(Vector3 pos)
337 {
338 Vector3 terrainBaseXYZ;
339 BSTerrainPhys physTerrain;
340 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
341 }
342
343 // Given an X and Y, find the height of the terrain.
344 // Since we could be handling multiple terrains for a mega-region,
345 // the base of the region is calcuated assuming all regions are
346 // the same size and that is the default.
347 // Once the heightMapInfo is found, we have all the information to
348 // compute the offset into the array.
349 private float lastHeightTX = 999999f;
350 private float lastHeightTY = 999999f;
351 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
352 public float GetTerrainHeightAtXYZ(Vector3 pos)
353 {
354 float tX = pos.X;
355 float tY = pos.Y;
356 // You'd be surprized at the number of times this routine is called
357 // with the same parameters as last time.
358 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
359 return lastHeight;
360 m_terrainModified = false;
361
362 lastHeightTX = tX;
363 lastHeightTY = tY;
364 float ret = HEIGHT_GETHEIGHT_RET;
365
366 Vector3 terrainBaseXYZ;
367 BSTerrainPhys physTerrain;
368 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
369 {
370 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
371 }
372 else
373 {
374 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
375 LogHeader, PhysicsScene.RegionName, tX, tY);
376 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
377 BSScene.DetailLogZero, pos, terrainBaseXYZ);
378 }
379
380 lastHeight = ret;
381 return ret;
382 }
383
384 public float GetWaterLevelAtXYZ(Vector3 pos)
385 {
386 float ret = WATER_HEIGHT_GETHEIGHT_RET;
387
388 Vector3 terrainBaseXYZ;
389 BSTerrainPhys physTerrain;
390 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
391 {
392 ret = physTerrain.GetWaterLevelAtXYZ(pos);
393 }
394 else
395 {
396 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
397 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret);
398 }
399 return ret;
400 }
401
402 // Given an address, return 'true' of there is a description of that terrain and output
403 // the descriptor class and the 'base' fo the addresses therein.
404 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
405 {
406 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
407 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
408 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
409
410 BSTerrainPhys physTerrain = null;
411 lock (m_terrains)
412 {
413 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
414 }
415 outTerrainBase = terrainBaseXYZ;
416 outPhysTerrain = physTerrain;
417 return (physTerrain != null);
418 }
419
420 // Although no one seems to check this, I do support combining.
421 public bool SupportsCombining()
422 {
423 return true;
424 }
425
426 // This routine is called two ways:
427 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
428 // extent of the combined regions. This is to inform the parent of the size
429 // of the combined regions.
430 // and one with 'offset' as the offset of the child region to the base region,
431 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
432 // child of its relative base and new parent.
433 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
434 {
435 m_worldOffset = offset;
436 m_worldMax = extents;
437 MegaRegionParentPhysicsScene = pScene;
438 if (pScene != null)
439 {
440 // We are a child.
441 // We want m_worldMax to be the highest coordinate of our piece of terrain.
442 m_worldMax = offset + DefaultRegionSize;
443 }
444 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
445 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
446 }
447
448 // Unhook all the combining that I know about.
449 public void UnCombine(PhysicsScene pScene)
450 {
451 // Just like ODE, we don't do anything yet.
452 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
453 }
454
455
456 private void DetailLog(string msg, params Object[] args)
457 {
458 PhysicsScene.PhysicsLogging.Write(msg, args);
459 }
460}
461}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs
deleted file mode 100644
index 6083dd4..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSTerrainMesh.cs
+++ /dev/null
@@ -1,267 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSNPlugin
42{
43public sealed class BSTerrainMesh : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
46
47 private float[] m_savedHeightMap;
48 int m_sizeX;
49 int m_sizeY;
50
51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody;
53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id)
56 {
57 }
58
59 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
60 : base(physicsScene, regionBase, id)
61 {
62 }
63
64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id)
68 {
69 int indicesCount;
70 int[] indices;
71 int verticesCount;
72 float[] vertices;
73
74 m_savedHeightMap = initialMap;
75
76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78
79 if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
80 m_sizeX, m_sizeY,
81 (float)m_sizeX, (float)m_sizeY,
82 Vector3.Zero, 1.0f,
83 out indicesCount, out indices, out verticesCount, out vertices))
84 {
85 // DISASTER!!
86 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
87 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
88 // Something is very messed up and a crash is in our future.
89 return;
90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
93
94 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
95 indicesCount, indices, verticesCount, vertices),
96 BSPhysicsShapeType.SHAPE_MESH);
97 if (!m_terrainShape.HasPhysicalShape)
98 {
99 // DISASTER!!
100 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
101 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
102 // Something is very messed up and a crash is in our future.
103 return;
104 }
105
106 Vector3 pos = regionBase;
107 Quaternion rot = Quaternion.Identity;
108
109 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
110 if (!m_terrainBody.HasPhysicalBody)
111 {
112 // DISASTER!!
113 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
114 // Something is very messed up and a crash is in our future.
115 return;
116 }
117
118 // Set current terrain attributes
119 BulletSimAPI.SetFriction2(m_terrainBody.ptr, BSParam.TerrainFriction);
120 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, BSParam.TerrainHitFraction);
121 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, BSParam.TerrainRestitution);
122 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
123
124 // Static objects are not very massive.
125 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
126
127 // Put the new terrain to the world of physical objects
128 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr, pos, rot);
129
130 // Redo its bounding box now that it is in the world
131 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
132
133 m_terrainBody.collisionType = CollisionType.Terrain;
134 m_terrainBody.ApplyCollisionMask();
135
136 // Make it so the terrain will not move or be considered for movement.
137 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
138 }
139
140 public override void Dispose()
141 {
142 if (m_terrainBody.HasPhysicalBody)
143 {
144 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
145 // Frees both the body and the shape.
146 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr);
147 }
148 }
149
150 public override float GetTerrainHeightAtXYZ(Vector3 pos)
151 {
152 // For the moment use the saved heightmap to get the terrain height.
153 // TODO: raycast downward to find the true terrain below the position.
154 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
155
156 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
157 try
158 {
159 ret = m_savedHeightMap[mapIndex];
160 }
161 catch
162 {
163 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
164 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
165 LogHeader, TerrainBase, pos);
166 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
167 }
168 return ret;
169 }
170
171 // The passed position is relative to the base of the region.
172 public override float GetWaterLevelAtXYZ(Vector3 pos)
173 {
174 return PhysicsScene.SimpleWaterLevel;
175 }
176
177 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
178 // Return 'true' if successfully created.
179 public static bool ConvertHeightmapToMesh(
180 BSScene physicsScene,
181 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
182 float extentX, float extentY, // zero based range for output vertices
183 Vector3 extentBase, // base to be added to all vertices
184 float magnification, // number of vertices to create between heightMap coords
185 out int indicesCountO, out int[] indicesO,
186 out int verticesCountO, out float[] verticesO)
187 {
188 bool ret = false;
189
190 int indicesCount = 0;
191 int verticesCount = 0;
192 int[] indices = new int[0];
193 float[] vertices = new float[0];
194
195 // Simple mesh creation which assumes magnification == 1.
196 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
197
198 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
199 // from zero to <= sizeX). The triangle indices are then generated as two triangles
200 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
201 // column of vertices are used to complete the triangles of the last row and column
202 // of the heightmap.
203 try
204 {
205 // One vertice per heightmap value plus the vertices off the top and bottom edge.
206 int totalVertices = (sizeX + 1) * (sizeY + 1);
207 vertices = new float[totalVertices * 3];
208 int totalIndices = sizeX * sizeY * 6;
209 indices = new int[totalIndices];
210
211 float magX = (float)sizeX / extentX;
212 float magY = (float)sizeY / extentY;
213 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
214 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
215 float minHeight = float.MaxValue;
216 // Note that sizeX+1 vertices are created since there is land between this and the next region.
217 for (int yy = 0; yy <= sizeY; yy++)
218 {
219 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
220 {
221 int offset = yy * sizeX + xx;
222 // Extend the height with the height from the last row or column
223 if (yy == sizeY) offset -= sizeX;
224 if (xx == sizeX) offset -= 1;
225 float height = heightMap[offset];
226 minHeight = Math.Min(minHeight, height);
227 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
228 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
229 vertices[verticesCount + 2] = height + extentBase.Z;
230 verticesCount += 3;
231 }
232 }
233 verticesCount = verticesCount / 3;
234
235 for (int yy = 0; yy < sizeY; yy++)
236 {
237 for (int xx = 0; xx < sizeX; xx++)
238 {
239 int offset = yy * (sizeX + 1) + xx;
240 // Each vertices is presumed to be the upper left corner of a box of two triangles
241 indices[indicesCount + 0] = offset;
242 indices[indicesCount + 1] = offset + 1;
243 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
244 indices[indicesCount + 3] = offset + 1;
245 indices[indicesCount + 4] = offset + sizeX + 2;
246 indices[indicesCount + 5] = offset + sizeX + 1;
247 indicesCount += 6;
248 }
249 }
250
251 ret = true;
252 }
253 catch (Exception e)
254 {
255 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
256 LogHeader, physicsScene.RegionName, extentBase, e);
257 }
258
259 indicesCountO = indicesCount;
260 indicesO = indices;
261 verticesCountO = verticesCount;
262 verticesO = vertices;
263
264 return ret;
265 }
266}
267}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs
deleted file mode 100644
index 93643c9..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimAPI.cs
+++ /dev/null
@@ -1,1603 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.IO;
30using System.Runtime.InteropServices;
31using System.Security;
32using System.Text;
33using BulletXNA;
34using OpenMetaverse;
35using BulletXNA.LinearMath;
36using BulletXNA.BulletCollision;
37using BulletXNA.BulletDynamics;
38using BulletXNA.BulletCollision.CollisionDispatch;
39using OpenSim.Framework;
40
41namespace OpenSim.Region.Physics.BulletSNPlugin {
42
43// Classes to allow some type checking for the API
44// These hold pointers to allocated objects in the unmanaged space.
45
46
47
48 // Constraint type values as defined by Bullet
49public enum ConstraintType : int
50{
51 POINT2POINT_CONSTRAINT_TYPE = 3,
52 HINGE_CONSTRAINT_TYPE,
53 CONETWIST_CONSTRAINT_TYPE,
54 D6_CONSTRAINT_TYPE,
55 SLIDER_CONSTRAINT_TYPE,
56 CONTACT_CONSTRAINT_TYPE,
57 D6_SPRING_CONSTRAINT_TYPE,
58 MAX_CONSTRAINT_TYPE
59}
60
61// ===============================================================================
62[StructLayout(LayoutKind.Sequential)]
63public struct ConvexHull
64{
65 Vector3 Offset;
66 int VertexCount;
67 Vector3[] Vertices;
68}
69public enum BSPhysicsShapeType
70{
71 SHAPE_UNKNOWN = 0,
72 SHAPE_CAPSULE = 1,
73 SHAPE_BOX = 2,
74 SHAPE_CONE = 3,
75 SHAPE_CYLINDER = 4,
76 SHAPE_SPHERE = 5,
77 SHAPE_MESH = 6,
78 SHAPE_HULL = 7,
79 // following defined by BulletSim
80 SHAPE_GROUNDPLANE = 20,
81 SHAPE_TERRAIN = 21,
82 SHAPE_COMPOUND = 22,
83 SHAPE_HEIGHTMAP = 23,
84};
85
86// The native shapes have predefined shape hash keys
87public enum FixedShapeKey : ulong
88{
89 KEY_NONE = 0,
90 KEY_BOX = 1,
91 KEY_SPHERE = 2,
92 KEY_CONE = 3,
93 KEY_CYLINDER = 4,
94 KEY_CAPSULE = 5,
95}
96
97[StructLayout(LayoutKind.Sequential)]
98public struct ShapeData
99{
100 public uint ID;
101 public BSPhysicsShapeType Type;
102 public Vector3 Position;
103 public Quaternion Rotation;
104 public Vector3 Velocity;
105 public Vector3 Scale;
106 public float Mass;
107 public float Buoyancy;
108 public System.UInt64 HullKey;
109 public System.UInt64 MeshKey;
110 public float Friction;
111 public float Restitution;
112 public float Collidable; // true of things bump into this
113 public float Static; // true if a static object. Otherwise gravity, etc.
114 public float Solid; // true if object cannot be passed through
115 public Vector3 Size;
116
117 // note that bools are passed as floats since bool size changes by language and architecture
118 public const float numericTrue = 1f;
119 public const float numericFalse = 0f;
120}
121[StructLayout(LayoutKind.Sequential)]
122public struct SweepHit
123{
124 public uint ID;
125 public float Fraction;
126 public Vector3 Normal;
127 public Vector3 Point;
128}
129[StructLayout(LayoutKind.Sequential)]
130public struct RaycastHit
131{
132 public uint ID;
133 public float Fraction;
134 public Vector3 Normal;
135}
136[StructLayout(LayoutKind.Sequential)]
137public struct CollisionDesc
138{
139 public uint aID;
140 public uint bID;
141 public Vector3 point;
142 public Vector3 normal;
143}
144[StructLayout(LayoutKind.Sequential)]
145public struct EntityProperties
146{
147 public uint ID;
148 public Vector3 Position;
149 public Quaternion Rotation;
150 public Vector3 Velocity;
151 public Vector3 Acceleration;
152 public Vector3 RotationalVelocity;
153 public override string ToString()
154 {
155 return string.Format("ID:{0}, Pos:<{1:F},{2:F},{3:F}>, Rot:<{4:F},{5:F},{6:F},{7:F}>, LVel:<{8:F},{9:F},{10:F}>, AVel:<{11:F},{12:F},{13:F}>",
156 ID.ToString(),
157 Position.X,Position.Y,Position.Z,
158 Rotation.X,Rotation.Y,Rotation.Z,Rotation.W,
159 Velocity.X,Velocity.Y,Velocity.Z,
160 RotationalVelocity.X,RotationalVelocity.Y,RotationalVelocity.Z
161 );
162 }
163}
164
165// Format of this structure must match the definition in the C++ code
166// NOTE: adding the X causes compile breaks if used. These are unused symbols
167// that can be removed from both here and the unmanaged definition of this structure.
168[StructLayout(LayoutKind.Sequential)]
169public struct ConfigurationParameters
170{
171 public float defaultFriction;
172 public float defaultDensity;
173 public float defaultRestitution;
174 public float collisionMargin;
175 public float gravity;
176
177 public float XlinearDamping;
178 public float XangularDamping;
179 public float XdeactivationTime;
180 public float XlinearSleepingThreshold;
181 public float XangularSleepingThreshold;
182 public float XccdMotionThreshold;
183 public float XccdSweptSphereRadius;
184 public float XcontactProcessingThreshold;
185
186 public float XterrainImplementation;
187 public float XterrainFriction;
188 public float XterrainHitFraction;
189 public float XterrainRestitution;
190 public float XterrainCollisionMargin;
191
192 public float XavatarFriction;
193 public float XavatarStandingFriction;
194 public float XavatarDensity;
195 public float XavatarRestitution;
196 public float XavatarCapsuleWidth;
197 public float XavatarCapsuleDepth;
198 public float XavatarCapsuleHeight;
199 public float XavatarContactProcessingThreshold;
200
201 public float XvehicleAngularDamping;
202
203 public float maxPersistantManifoldPoolSize;
204 public float maxCollisionAlgorithmPoolSize;
205 public float shouldDisableContactPoolDynamicAllocation;
206 public float shouldForceUpdateAllAabbs;
207 public float shouldRandomizeSolverOrder;
208 public float shouldSplitSimulationIslands;
209 public float shouldEnableFrictionCaching;
210 public float numberOfSolverIterations;
211
212 public float XlinksetImplementation;
213 public float XlinkConstraintUseFrameOffset;
214 public float XlinkConstraintEnableTransMotor;
215 public float XlinkConstraintTransMotorMaxVel;
216 public float XlinkConstraintTransMotorMaxForce;
217 public float XlinkConstraintERP;
218 public float XlinkConstraintCFM;
219 public float XlinkConstraintSolverIterations;
220
221 public float physicsLoggingFrames;
222
223 public const float numericTrue = 1f;
224 public const float numericFalse = 0f;
225}
226
227
228// The states a bullet collision object can have
229
230public enum ActivationState : uint
231{
232 UNDEFINED = 0,
233 ACTIVE_TAG = 1,
234 ISLAND_SLEEPING = 2,
235 WANTS_DEACTIVATION = 3,
236 DISABLE_DEACTIVATION = 4,
237 DISABLE_SIMULATION = 5,
238}
239
240public enum CollisionObjectTypes : int
241{
242 CO_COLLISION_OBJECT = 1 << 0,
243 CO_RIGID_BODY = 1 << 1,
244 CO_GHOST_OBJECT = 1 << 2,
245 CO_SOFT_BODY = 1 << 3,
246 CO_HF_FLUID = 1 << 4,
247 CO_USER_TYPE = 1 << 5,
248}
249
250// Values used by Bullet and BulletSim to control object properties.
251// Bullet's "CollisionFlags" has more to do with operations on the
252// object (if collisions happen, if gravity effects it, ...).
253 [Flags]
254public enum CollisionFlags : uint
255{
256 CF_STATIC_OBJECT = 1 << 0,
257 CF_KINEMATIC_OBJECT = 1 << 1,
258 CF_NO_CONTACT_RESPONSE = 1 << 2,
259 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
260 CF_CHARACTER_OBJECT = 1 << 4,
261 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
262 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
263 // Following used by BulletSim to control collisions and updates
264 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
265 BS_FLOATS_ON_WATER = 1 << 11,
266 BS_VEHICLE_COLLISIONS = 1 << 12,
267 BS_NONE = 0,
268 BS_ALL = 0xFFFFFFFF,
269
270 // These are the collision flags switched depending on physical state.
271 // The other flags are used for other things and should not be fooled with.
272 BS_ACTIVE = CF_STATIC_OBJECT
273 | CF_KINEMATIC_OBJECT
274 | CF_NO_CONTACT_RESPONSE
275};
276
277// Values for collisions groups and masks
278public enum CollisionFilterGroups : uint
279{
280 // Don't use the bit definitions!! Define the use in a
281 // filter/mask definition below. This way collision interactions
282 // are more easily debugged.
283 BNoneGroup = 0,
284 BDefaultGroup = 1 << 0,
285 BStaticGroup = 1 << 1,
286 BKinematicGroup = 1 << 2,
287 BDebrisGroup = 1 << 3,
288 BSensorTrigger = 1 << 4,
289 BCharacterGroup = 1 << 5,
290 BAllGroup = 0xFFFFFFFF,
291 // Filter groups defined by BulletSim
292 BGroundPlaneGroup = 1 << 10,
293 BTerrainGroup = 1 << 11,
294 BRaycastGroup = 1 << 12,
295 BSolidGroup = 1 << 13,
296 // BLinksetGroup = xx // a linkset proper is either static or dynamic
297 BLinksetChildGroup = 1 << 14,
298 // The collsion filters and masked are defined in one place -- don't want them scattered
299 AvatarGroup = BCharacterGroup,
300 AvatarMask = BAllGroup,
301 ObjectGroup = BSolidGroup,
302 ObjectMask = BAllGroup,
303 StaticObjectGroup = BStaticGroup,
304 StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
305 LinksetGroup = BLinksetChildGroup,
306 LinksetMask = BAllGroup & ~BLinksetChildGroup, // linkset objects don't collide with each other
307 VolumeDetectGroup = BSensorTrigger,
308 VolumeDetectMask = ~BSensorTrigger,
309 TerrainGroup = BTerrainGroup,
310 TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
311 GroundPlaneGroup = BGroundPlaneGroup,
312 GroundPlaneMask = BAllGroup
313
314};
315
316// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
317// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
318public enum ConstraintParams : int
319{
320 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
321 BT_CONSTRAINT_STOP_ERP,
322 BT_CONSTRAINT_CFM,
323 BT_CONSTRAINT_STOP_CFM,
324};
325public enum ConstraintParamAxis : int
326{
327 AXIS_LINEAR_X = 0,
328 AXIS_LINEAR_Y,
329 AXIS_LINEAR_Z,
330 AXIS_ANGULAR_X,
331 AXIS_ANGULAR_Y,
332 AXIS_ANGULAR_Z,
333 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
334 AXIS_ANGULAR_ALL,
335 AXIS_ALL
336};
337
338// ===============================================================================
339static class BulletSimAPI {
340 private static int m_collisionsThisFrame;
341 public delegate void DebugLogCallback(string msg);
342 /// <summary>
343 ///
344 /// </summary>
345 /// <param name="p"></param>
346 /// <param name="p_2"></param>
347 internal static bool RemoveObjectFromWorld2(object pWorld, object pBody)
348 {
349 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
350 RigidBody body = pBody as RigidBody;
351 world.RemoveRigidBody(body);
352 return true;
353 }
354
355 internal static void SetRestitution2(object pBody, float pRestitution)
356 {
357 RigidBody body = pBody as RigidBody;
358 body.SetRestitution(pRestitution);
359 }
360
361 internal static void SetMargin2(object pShape, float pMargin)
362 {
363 CollisionShape shape = pShape as CollisionShape;
364 shape.SetMargin(pMargin);
365 }
366
367 internal static void SetLocalScaling2(object pShape, Vector3 pScale)
368 {
369 CollisionShape shape = pShape as CollisionShape;
370 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
371 shape.SetLocalScaling(ref vec);
372
373 }
374
375 internal static void SetContactProcessingThreshold2(object pBody, float contactprocessingthreshold)
376 {
377 RigidBody body = pBody as RigidBody;
378 body.SetContactProcessingThreshold(contactprocessingthreshold);
379 }
380
381 internal static void SetCcdMotionThreshold2(object pBody, float pccdMotionThreashold)
382 {
383 RigidBody body = pBody as RigidBody;
384 body.SetCcdMotionThreshold(pccdMotionThreashold);
385 }
386
387 internal static void SetCcdSweptSphereRadius2(object pBody, float pCcdSweptSphereRadius)
388 {
389 RigidBody body = pBody as RigidBody;
390 body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
391 }
392
393 internal static void SetAngularFactorV2(object pBody, Vector3 pAngularFactor)
394 {
395 RigidBody body = pBody as RigidBody;
396 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
397 }
398
399 internal static CollisionFlags AddToCollisionFlags2(object pBody, CollisionFlags pcollisionFlags)
400 {
401 CollisionObject body = pBody as CollisionObject;
402 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
403 existingcollisionFlags |= pcollisionFlags;
404 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
405 return (CollisionFlags) (uint) existingcollisionFlags;
406 }
407
408 internal static void AddObjectToWorld2(object pWorld, object pBody)
409 {
410 RigidBody body = pBody as RigidBody;
411 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
412 //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE))
413
414 world.AddRigidBody(body);
415
416 //if (body.GetBroadphaseHandle() != null)
417 // world.UpdateSingleAabb(body);
418 }
419
420 internal static void AddObjectToWorld2(object pWorld, object pBody, Vector3 _position, Quaternion _orientation)
421 {
422 RigidBody body = pBody as RigidBody;
423 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
424 //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE))
425
426 world.AddRigidBody(body);
427 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
428 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
429 _orientation.W);
430 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
431 mat._origin = vposition;
432 body.SetWorldTransform(mat);
433 //if (body.GetBroadphaseHandle() != null)
434 // world.UpdateSingleAabb(body);
435 }
436
437 internal static void ForceActivationState2(object pBody, ActivationState pActivationState)
438 {
439 CollisionObject body = pBody as CollisionObject;
440 body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
441 }
442
443 internal static void UpdateSingleAabb2(object pWorld, object pBody)
444 {
445 CollisionObject body = pBody as CollisionObject;
446 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
447 world.UpdateSingleAabb(body);
448 }
449
450 internal static bool SetCollisionGroupMask2(object pBody, uint pGroup, uint pMask)
451 {
452 RigidBody body = pBody as RigidBody;
453 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
454 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
455 if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0)
456 return false;
457 return true;
458 }
459
460 internal static void ClearAllForces2(object pBody)
461 {
462 CollisionObject body = pBody as CollisionObject;
463 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
464 body.SetInterpolationLinearVelocity(ref zeroVector);
465 body.SetInterpolationAngularVelocity(ref zeroVector);
466 IndexedMatrix bodytransform = body.GetWorldTransform();
467
468 body.SetInterpolationWorldTransform(ref bodytransform);
469
470 if (body is RigidBody)
471 {
472 RigidBody rigidbody = body as RigidBody;
473 rigidbody.SetLinearVelocity(zeroVector);
474 rigidbody.SetAngularVelocity(zeroVector);
475 rigidbody.ClearForces();
476 }
477 }
478
479 internal static void SetInterpolationAngularVelocity2(object pBody, Vector3 pVector3)
480 {
481 RigidBody body = pBody as RigidBody;
482 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
483 body.SetInterpolationAngularVelocity(ref vec);
484 }
485
486 internal static void SetAngularVelocity2(object pBody, Vector3 pVector3)
487 {
488 RigidBody body = pBody as RigidBody;
489 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
490 body.SetAngularVelocity(ref vec);
491 }
492
493 internal static void ClearForces2(object pBody)
494 {
495 RigidBody body = pBody as RigidBody;
496 body.ClearForces();
497 }
498
499 internal static void SetTranslation2(object pBody, Vector3 _position, Quaternion _orientation)
500 {
501 RigidBody body = pBody as RigidBody;
502 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
503 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
504 _orientation.W);
505 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
506 mat._origin = vposition;
507 body.SetWorldTransform(mat);
508
509 }
510
511 internal static Vector3 GetPosition2(object pBody)
512 {
513 RigidBody body = pBody as RigidBody;
514 IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin;
515 return new Vector3(pos.X, pos.Y, pos.Z);
516 }
517
518 internal static Vector3 CalculateLocalInertia2(object pShape, float pphysMass)
519 {
520 CollisionShape shape = pShape as CollisionShape;
521 IndexedVector3 inertia = IndexedVector3.Zero;
522 shape.CalculateLocalInertia(pphysMass, out inertia);
523 return new Vector3(inertia.X, inertia.Y, inertia.Z);
524 }
525
526 internal static void SetMassProps2(object pBody, float pphysMass, Vector3 plocalInertia)
527 {
528 RigidBody body = pBody as RigidBody;
529 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
530 body.SetMassProps(pphysMass, inertia);
531 }
532
533
534 internal static void SetObjectForce2(object pBody, Vector3 _force)
535 {
536 RigidBody body = pBody as RigidBody;
537 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
538 body.SetTotalForce(ref force);
539 }
540
541 internal static void SetFriction2(object pBody, float _currentFriction)
542 {
543 RigidBody body = pBody as RigidBody;
544 body.SetFriction(_currentFriction);
545 }
546
547 internal static void SetLinearVelocity2(object pBody, Vector3 _velocity)
548 {
549 RigidBody body = pBody as RigidBody;
550 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
551 body.SetLinearVelocity(velocity);
552 }
553
554 internal static void Activate2(object pBody, bool pforceactivation)
555 {
556 RigidBody body = pBody as RigidBody;
557 body.Activate(pforceactivation);
558
559 }
560
561 internal static Quaternion GetOrientation2(object pBody)
562 {
563 RigidBody body = pBody as RigidBody;
564 IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation();
565 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
566 }
567
568 internal static CollisionFlags RemoveFromCollisionFlags2(object pBody, CollisionFlags pcollisionFlags)
569 {
570 RigidBody body = pBody as RigidBody;
571 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
572 existingcollisionFlags &= ~pcollisionFlags;
573 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
574 return (CollisionFlags)(uint)existingcollisionFlags;
575 }
576
577 internal static void SetGravity2(object pBody, Vector3 pGravity)
578 {
579 RigidBody body = pBody as RigidBody;
580 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
581 body.SetGravity(gravity);
582 }
583
584 internal static bool DestroyConstraint2(object pBody, object pConstraint)
585 {
586 RigidBody body = pBody as RigidBody;
587 TypedConstraint constraint = pConstraint as TypedConstraint;
588 body.RemoveConstraintRef(constraint);
589 return true;
590 }
591
592 internal static bool SetLinearLimits2(object pConstraint, Vector3 low, Vector3 high)
593 {
594 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
595 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
596 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
597 constraint.SetLinearLowerLimit(lowlimit);
598 constraint.SetLinearUpperLimit(highlimit);
599 return true;
600 }
601
602 internal static bool SetAngularLimits2(object pConstraint, Vector3 low, Vector3 high)
603 {
604 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
605 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
606 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
607 constraint.SetAngularLowerLimit(lowlimit);
608 constraint.SetAngularUpperLimit(highlimit);
609 return true;
610 }
611
612 internal static void SetConstraintNumSolverIterations2(object pConstraint, float cnt)
613 {
614 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
615 constraint.SetOverrideNumSolverIterations((int)cnt);
616 }
617
618 internal static void CalculateTransforms2(object pConstraint)
619 {
620 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
621 constraint.CalculateTransforms();
622 }
623
624 internal static void SetConstraintEnable2(object pConstraint, float p_2)
625 {
626 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
627 constraint.SetEnabled((p_2 == 0) ? false : true);
628 }
629
630
631 //BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
632 internal static object Create6DofConstraint2(object pWorld, object pBody1, object pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
633
634 {
635 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
636 RigidBody body1 = pBody1 as RigidBody;
637 RigidBody body2 = pBody2 as RigidBody;
638 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
639 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
640 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
641 frame1._origin = frame1v;
642
643 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
644 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
645 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
646 frame2._origin = frame1v;
647
648 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
649 puseLinearReferenceFrameA);
650 consttr.CalculateTransforms();
651 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
652
653 return consttr;
654 }
655
656
657 /// <summary>
658 ///
659 /// </summary>
660 /// <param name="pWorld"></param>
661 /// <param name="pBody1"></param>
662 /// <param name="pBody2"></param>
663 /// <param name="pjoinPoint"></param>
664 /// <param name="puseLinearReferenceFrameA"></param>
665 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
666 /// <returns></returns>
667 internal static object Create6DofConstraintToPoint2(object pWorld, object pBody1, object pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
668 {
669 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
670 RigidBody body1 = pBody1 as RigidBody;
671 RigidBody body2 = pBody2 as RigidBody;
672 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
673 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
674
675 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
676 IndexedMatrix mat = IndexedMatrix.Identity;
677 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
678 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
679 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
680
681 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
682 consttr.CalculateTransforms();
683 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
684
685 return consttr;
686 }
687 //SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
688 internal static void SetFrames2(object pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
689 {
690 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
691 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
692 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
693 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
694 frame1._origin = frame1v;
695
696 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
697 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
698 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
699 frame2._origin = frame1v;
700 constraint.SetFrames(ref frame1, ref frame2);
701 }
702
703
704
705
706 internal static bool IsInWorld2(object pWorld, object pShapeObj)
707 {
708 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
709 CollisionObject shape = pShapeObj as CollisionObject;
710 return world.IsInWorld(shape);
711 }
712
713 internal static void SetInterpolationLinearVelocity2(object pBody, Vector3 VehicleVelocity)
714 {
715 RigidBody body = pBody as RigidBody;
716 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
717 body.SetInterpolationLinearVelocity(ref velocity);
718 }
719
720 internal static bool UseFrameOffset2(object pConstraint, float onOff)
721 {
722 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
723 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
724 return true;
725 }
726 //SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
727 internal static bool SetBreakingImpulseThreshold2(object pConstraint, float threshold)
728 {
729 Generic6DofConstraint constraint = pConstraint as Generic6DofConstraint;
730 constraint.SetBreakingImpulseThreshold(threshold);
731 return true;
732 }
733 //BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
734 internal static void SetAngularDamping2(object pBody, float angularDamping)
735 {
736 RigidBody body = pBody as RigidBody;
737 float lineardamping = body.GetLinearDamping();
738 body.SetDamping(lineardamping, angularDamping);
739
740 }
741
742 internal static void UpdateInertiaTensor2(object pBody)
743 {
744 RigidBody body = pBody as RigidBody;
745 body.UpdateInertiaTensor();
746 }
747
748 internal static void RecalculateCompoundShapeLocalAabb2( object pCompoundShape)
749 {
750
751 CompoundShape shape = pCompoundShape as CompoundShape;
752 shape.RecalculateLocalAabb();
753 }
754
755 //BulletSimAPI.GetCollisionFlags2(PhysBody.ptr)
756 internal static CollisionFlags GetCollisionFlags2(object pBody)
757 {
758 RigidBody body = pBody as RigidBody;
759 uint flags = (uint)body.GetCollisionFlags();
760 return (CollisionFlags) flags;
761 }
762
763 internal static void SetDamping2(object pBody, float pLinear, float pAngular)
764 {
765 RigidBody body = pBody as RigidBody;
766 body.SetDamping(pLinear, pAngular);
767 }
768 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
769 internal static void SetDeactivationTime2(object pBody, float pDeactivationTime)
770 {
771 RigidBody body = pBody as RigidBody;
772 body.SetDeactivationTime(pDeactivationTime);
773 }
774 //SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
775 internal static void SetSleepingThresholds2(object pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
776 {
777 RigidBody body = pBody as RigidBody;
778 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
779 }
780
781 internal static CollisionObjectTypes GetBodyType2(object pBody)
782 {
783 RigidBody body = pBody as RigidBody;
784 return (CollisionObjectTypes)(int) body.GetInternalType();
785 }
786
787 //BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
788 internal static void ApplyCentralForce2(object pBody, Vector3 pfSum)
789 {
790 RigidBody body = pBody as RigidBody;
791 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
792 body.ApplyCentralForce(ref fSum);
793 }
794 internal static void ApplyCentralImpulse2(object pBody, Vector3 pfSum)
795 {
796 RigidBody body = pBody as RigidBody;
797 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
798 body.ApplyCentralImpulse(ref fSum);
799 }
800 internal static void ApplyTorque2(object pBody, Vector3 pfSum)
801 {
802 RigidBody body = pBody as RigidBody;
803 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
804 body.ApplyTorque(ref fSum);
805 }
806 internal static void ApplyTorqueImpulse2(object pBody, Vector3 pfSum)
807 {
808 RigidBody body = pBody as RigidBody;
809 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
810 body.ApplyTorqueImpulse(ref fSum);
811 }
812
813 internal static void DumpRigidBody2(object p, object p_2)
814 {
815 //TODO:
816 }
817
818 internal static void DumpCollisionShape2(object p, object p_2)
819 {
820 //TODO:
821 }
822
823 internal static void DestroyObject2(object p, object p_2)
824 {
825 //TODO:
826 }
827
828 internal static void Shutdown2(object pWorld)
829 {
830 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
831 world.Cleanup();
832 }
833
834 internal static void DeleteCollisionShape2(object p, object p_2)
835 {
836 //TODO:
837 }
838 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
839
840 internal static object CreateBodyFromShape2(object pWorld, object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
841 {
842 CollisionWorld world = pWorld as CollisionWorld;
843 IndexedMatrix mat =
844 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
845 pRawOrientation.Z, pRawOrientation.W));
846 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
847 CollisionShape shape = pShape as CollisionShape;
848 //UpdateSingleAabb2(world, shape);
849 // TODO: Feed Update array into null
850 RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero);
851
852 body.SetUserPointer(pLocalID);
853 return body;
854 }
855
856
857 internal static object CreateBodyWithDefaultMotionState2( object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
858 {
859
860 IndexedMatrix mat =
861 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
862 pRawOrientation.Z, pRawOrientation.W));
863 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
864
865 CollisionShape shape = pShape as CollisionShape;
866
867 // TODO: Feed Update array into null
868 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
869 body.SetWorldTransform(mat);
870 body.SetUserPointer(pLocalID);
871 return body;
872 }
873 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
874 internal static void SetCollisionFlags2(object pBody, CollisionFlags collisionFlags)
875 {
876 RigidBody body = pBody as RigidBody;
877 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
878 }
879 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
880 internal static void SetHitFraction2(object pBody, float pHitFraction)
881 {
882 RigidBody body = pBody as RigidBody;
883 body.SetHitFraction(pHitFraction);
884 }
885 //BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
886 internal static object BuildCapsuleShape2(object pWorld, float pRadius, float pHeight, Vector3 pScale)
887 {
888 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
889 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
890 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
891 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
892 capsuleShapeZ.SetLocalScaling(ref scale);
893
894 return capsuleShapeZ;
895 }
896
897 public static object Initialize2(Vector3 worldExtent, ConfigurationParameters[] o, int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray, int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray, object mDebugLogCallbackHandle)
898 {
899 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
900
901 p.angularDamping = o[0].XangularDamping;
902 p.defaultFriction = o[0].defaultFriction;
903 p.defaultFriction = o[0].defaultFriction;
904 p.defaultDensity = o[0].defaultDensity;
905 p.defaultRestitution = o[0].defaultRestitution;
906 p.collisionMargin = o[0].collisionMargin;
907 p.gravity = o[0].gravity;
908
909 p.linearDamping = o[0].XlinearDamping;
910 p.angularDamping = o[0].XangularDamping;
911 p.deactivationTime = o[0].XdeactivationTime;
912 p.linearSleepingThreshold = o[0].XlinearSleepingThreshold;
913 p.angularSleepingThreshold = o[0].XangularSleepingThreshold;
914 p.ccdMotionThreshold = o[0].XccdMotionThreshold;
915 p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius;
916 p.contactProcessingThreshold = o[0].XcontactProcessingThreshold;
917
918 p.terrainImplementation = o[0].XterrainImplementation;
919 p.terrainFriction = o[0].XterrainFriction;
920
921 p.terrainHitFraction = o[0].XterrainHitFraction;
922 p.terrainRestitution = o[0].XterrainRestitution;
923 p.terrainCollisionMargin = o[0].XterrainCollisionMargin;
924
925 p.avatarFriction = o[0].XavatarFriction;
926 p.avatarStandingFriction = o[0].XavatarStandingFriction;
927 p.avatarDensity = o[0].XavatarDensity;
928 p.avatarRestitution = o[0].XavatarRestitution;
929 p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth;
930 p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth;
931 p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight;
932 p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold;
933
934 p.vehicleAngularDamping = o[0].XvehicleAngularDamping;
935
936 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
937 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
938 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
939 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
940 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
941 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
942 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
943 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
944
945 p.linksetImplementation = o[0].XlinksetImplementation;
946 p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset;
947 p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor;
948 p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel;
949 p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce;
950 p.linkConstraintERP = o[0].XlinkConstraintERP;
951 p.linkConstraintCFM = o[0].XlinkConstraintCFM;
952 p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations;
953 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
954 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
955
956 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
957 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
958
959
960 if (p.maxPersistantManifoldPoolSize > 0)
961 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
962 if (p.shouldDisableContactPoolDynamicAllocation !=0)
963 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
964 //if (p.maxCollisionAlgorithmPoolSize >0 )
965
966 DbvtBroadphase m_broadphase = new DbvtBroadphase();
967 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
968 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
969
970 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
971 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
972
973 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
974
975 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
976 world.UpdatedObjects = updateArray;
977 world.UpdatedCollisions = collisionArray;
978 world.WorldSettings.Params = p;
979 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
980 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
981 if (p.shouldRandomizeSolverOrder != 0)
982 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
983
984 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
985 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
986
987 if (p.shouldEnableFrictionCaching != 0)
988 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
989
990 if (p.numberOfSolverIterations > 0)
991 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
992
993
994 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
995 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
996 world.GetSolverInfo().m_globalCfm = 0.0f;
997 world.GetSolverInfo().m_tau = 0.6f;
998 world.GetSolverInfo().m_friction = 0.3f;
999 world.GetSolverInfo().m_maxErrorReduction = 20f;
1000 world.GetSolverInfo().m_numIterations = 10;
1001 world.GetSolverInfo().m_erp = 0.2f;
1002 world.GetSolverInfo().m_erp2 = 0.1f;
1003 world.GetSolverInfo().m_sor = 1.0f;
1004 world.GetSolverInfo().m_splitImpulse = false;
1005 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1006 world.GetSolverInfo().m_linearSlop = 0.0f;
1007 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1008 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1009 world.SetForceUpdateAllAabbs(true);
1010
1011
1012 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1013
1014 return world;
1015 }
1016 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1017 internal static bool SetConstraintParam2(object pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1018 {
1019 Generic6DofConstraint constrain = pConstraint as Generic6DofConstraint;
1020 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1021 {
1022 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1023 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1024 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1025 }
1026 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1027 {
1028 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1029 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1030 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1031 }
1032 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1033 {
1034 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1035 }
1036 return true;
1037 }
1038
1039 internal static bool PushUpdate2(object pCollisionObject)
1040 {
1041 bool ret = false;
1042 RigidBody rb = pCollisionObject as RigidBody;
1043 if (rb != null)
1044 {
1045 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1046 if (sms != null)
1047 {
1048 IndexedMatrix wt = IndexedMatrix.Identity;
1049 sms.GetWorldTransform(out wt);
1050 sms.SetWorldTransform(ref wt, true);
1051 ret = true;
1052 }
1053 }
1054 return ret;
1055
1056 }
1057
1058 internal static bool IsCompound2(object pShape)
1059 {
1060 CollisionShape shape = pShape as CollisionShape;
1061 return shape.IsCompound();
1062 }
1063 internal static bool IsPloyhedral2(object pShape)
1064 {
1065 CollisionShape shape = pShape as CollisionShape;
1066 return shape.IsPolyhedral();
1067 }
1068 internal static bool IsConvex2d2(object pShape)
1069 {
1070 CollisionShape shape = pShape as CollisionShape;
1071 return shape.IsConvex2d();
1072 }
1073 internal static bool IsConvex2(object pShape)
1074 {
1075 CollisionShape shape = pShape as CollisionShape;
1076 return shape.IsConvex();
1077 }
1078 internal static bool IsNonMoving2(object pShape)
1079 {
1080 CollisionShape shape = pShape as CollisionShape;
1081 return shape.IsNonMoving();
1082 }
1083 internal static bool IsConcave2(object pShape)
1084 {
1085 CollisionShape shape = pShape as CollisionShape;
1086 return shape.IsConcave();
1087 }
1088 internal static bool IsInfinite2(object pShape)
1089 {
1090 CollisionShape shape = pShape as CollisionShape;
1091 return shape.IsInfinite();
1092 }
1093 internal static bool IsNativeShape2(object pShape)
1094 {
1095 CollisionShape shape = pShape as CollisionShape;
1096 bool ret;
1097 switch (shape.GetShapeType())
1098 {
1099 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1100 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1101 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1102 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1103 ret = true;
1104 break;
1105 default:
1106 ret = false;
1107 break;
1108 }
1109 return ret;
1110 }
1111 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1112 internal static object CreateGhostFromShape2(object pWorld, object pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1113 {
1114 IndexedMatrix bodyTransform = new IndexedMatrix();
1115 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1116 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1117 GhostObject gObj = new PairCachingGhostObject();
1118 gObj.SetWorldTransform(bodyTransform);
1119 CollisionShape shape = pShape as CollisionShape;
1120 gObj.SetCollisionShape(shape);
1121 gObj.SetUserPointer(pLocalID);
1122 // TODO: Add to Special CollisionObjects!
1123 return gObj;
1124 }
1125
1126 public static void SetCollisionShape2(object pWorld, object pObj, object pShape)
1127 {
1128 var world = pWorld as DiscreteDynamicsWorld;
1129 var obj = pObj as CollisionObject;
1130 var shape = pShape as CollisionShape;
1131 obj.SetCollisionShape(shape);
1132
1133 }
1134 //(PhysicsScene.World.ptr, nativeShapeData)
1135 internal static object BuildNativeShape2(object pWorld, ShapeData pShapeData)
1136 {
1137 var world = pWorld as DiscreteDynamicsWorld;
1138 CollisionShape shape = null;
1139 switch (pShapeData.Type)
1140 {
1141 case BSPhysicsShapeType.SHAPE_BOX:
1142 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1143 break;
1144 case BSPhysicsShapeType.SHAPE_CONE:
1145 shape = new ConeShapeZ(0.5f, 1.0f);
1146 break;
1147 case BSPhysicsShapeType.SHAPE_CYLINDER:
1148 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1149 break;
1150 case BSPhysicsShapeType.SHAPE_SPHERE:
1151 shape = new SphereShape(0.5f);
1152 break;
1153
1154 }
1155 if (shape != null)
1156 {
1157 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1158 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1159 shape.SetLocalScaling(ref scaling);
1160
1161 }
1162 return shape;
1163 }
1164 //PhysicsScene.World.ptr, false
1165 internal static object CreateCompoundShape2(object pWorld, bool enableDynamicAabbTree)
1166 {
1167 return new CompoundShape(enableDynamicAabbTree);
1168 }
1169
1170 internal static int GetNumberOfCompoundChildren2(object pCompoundShape)
1171 {
1172 var compoundshape = pCompoundShape as CompoundShape;
1173 return compoundshape.GetNumChildShapes();
1174 }
1175 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1176 internal static void AddChildShapeToCompoundShape2(object pCShape, object paddShape, Vector3 displacementPos, Quaternion displacementRot)
1177 {
1178 IndexedMatrix relativeTransform = new IndexedMatrix();
1179 var compoundshape = pCShape as CompoundShape;
1180 var addshape = paddShape as CollisionShape;
1181
1182 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1183 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1184 compoundshape.AddChildShape(ref relativeTransform, addshape);
1185
1186 }
1187
1188 internal static object RemoveChildShapeFromCompoundShapeIndex2(object pCShape, int pii)
1189 {
1190 var compoundshape = pCShape as CompoundShape;
1191 CollisionShape ret = null;
1192 ret = compoundshape.GetChildShape(pii);
1193 compoundshape.RemoveChildShapeByIndex(pii);
1194 return ret;
1195 }
1196
1197 internal static object CreateGroundPlaneShape2(uint pLocalId, float pheight, float pcollisionMargin)
1198 {
1199 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1200 m_planeshape.SetMargin(pcollisionMargin);
1201 m_planeshape.SetUserPointer(pLocalId);
1202 return m_planeshape;
1203 }
1204
1205 internal static object CreateHingeConstraint2(object pWorld, object pBody1, object ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1206 {
1207 HingeConstraint constrain = null;
1208 var rb1 = pBody1 as RigidBody;
1209 var rb2 = ppBody2 as RigidBody;
1210 if (rb1 != null && rb2 != null)
1211 {
1212 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1213 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1214 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1215 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1216 var world = pWorld as DiscreteDynamicsWorld;
1217 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1218 }
1219 return constrain;
1220 }
1221
1222 internal static bool ReleaseHeightMapInfo2(object pMapInfo)
1223 {
1224 if (pMapInfo != null)
1225 {
1226 BulletHeightMapInfo mapinfo = pMapInfo as BulletHeightMapInfo;
1227 if (mapinfo.heightMap != null)
1228 mapinfo.heightMap = null;
1229
1230
1231 }
1232 return true;
1233 }
1234
1235 internal static object CreateHullShape2(object pWorld, int pHullCount, float[] pConvHulls)
1236 {
1237 CompoundShape compoundshape = new CompoundShape(false);
1238 var world = pWorld as DiscreteDynamicsWorld;
1239
1240
1241 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1242 int ii = 1;
1243
1244 for (int i = 0; i < pHullCount; i++)
1245 {
1246 int vertexCount = (int) pConvHulls[ii];
1247
1248 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
1249 IndexedMatrix childTrans = IndexedMatrix.Identity;
1250 childTrans._origin = centroid;
1251
1252 List<IndexedVector3> virts = new List<IndexedVector3>();
1253 int ender = ((ii + 4) + (vertexCount*3));
1254 for (int iii = ii + 4; iii < ender; iii+=3)
1255 {
1256
1257 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1258 }
1259 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
1260 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1261 compoundshape.AddChildShape(ref childTrans, convexShape);
1262 ii += (vertexCount*3 + 4);
1263 }
1264
1265
1266 return compoundshape;
1267 }
1268
1269 internal static object CreateMeshShape2(object pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1270 {
1271 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1272
1273 for (int iter = 0; iter < pVerticesCount; iter++)
1274 {
1275 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1276 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1277 }
1278
1279 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1280 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1281 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1282 var world = pWorld as DiscreteDynamicsWorld;
1283 IndexedMesh mesh = new IndexedMesh();
1284 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1285 mesh.m_numTriangles = pIndicesCount/3;
1286 mesh.m_numVertices = pVerticesCount;
1287 mesh.m_triangleIndexBase = indicesarr;
1288 mesh.m_vertexBase = vertices;
1289 mesh.m_vertexStride = 3;
1290 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1291 mesh.m_triangleIndexStride = 3;
1292
1293 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1294 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1295 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
1296 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1297 // world.UpdateSingleAabb(meshShape);
1298 return meshShape;
1299
1300 }
1301 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1302 {
1303
1304 String fileName = "objTest3.raw";
1305 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1306 StreamWriter sw = new StreamWriter(completePath);
1307 IndexedMesh mesh = new IndexedMesh();
1308
1309 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1310 mesh.m_numTriangles = pIndicesCount / 3;
1311 mesh.m_numVertices = pVerticesCount;
1312 mesh.m_triangleIndexBase = indices;
1313 mesh.m_vertexBase = vertices;
1314 mesh.m_vertexStride = 3;
1315 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1316 mesh.m_triangleIndexStride = 3;
1317
1318 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1319 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1320
1321
1322
1323 for (int i = 0; i < pVerticesCount; i++)
1324 {
1325
1326 string s = vertices[indices[i * 3]].ToString("0.0000");
1327 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1328 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1329
1330 sw.Write(s + "\n");
1331 }
1332
1333 sw.Close();
1334 }
1335 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
1336 {
1337
1338 String fileName = "objTest6.raw";
1339 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1340 StreamWriter sw = new StreamWriter(completePath);
1341 IndexedMesh mesh = new IndexedMesh();
1342
1343 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1344 mesh.m_numTriangles = pIndicesCount / 3;
1345 mesh.m_numVertices = pVerticesCount;
1346 mesh.m_triangleIndexBase = indices;
1347 mesh.m_vertexBase = vertices;
1348 mesh.m_vertexStride = 3;
1349 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1350 mesh.m_triangleIndexStride = 3;
1351
1352 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1353 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1354
1355
1356 sw.WriteLine("Indices");
1357 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
1358 for (int iter = 0; iter < indices.Length; iter++)
1359 {
1360 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
1361 }
1362 sw.WriteLine("VerticesFloats");
1363 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
1364 for (int iter = 0; iter < vertices.Length; iter++)
1365 {
1366 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
1367 }
1368
1369 // for (int i = 0; i < pVerticesCount; i++)
1370 // {
1371 //
1372 // string s = vertices[indices[i * 3]].ToString("0.0000");
1373 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1374 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1375 //
1376 // sw.Write(s + "\n");
1377 //}
1378
1379 sw.Close();
1380 }
1381 //PhysicsScene.World.ptr, m_mapInfo.ID, m_mapInfo.minCoords, m_mapInfo.maxCoords, m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin
1382 internal static object CreateHeightMapInfo2(object pWorld, uint pId, Vector3 pminCoords, Vector3 pmaxCoords, float[] pheightMap, float pCollisionMargin)
1383 {
1384 BulletHeightMapInfo mapInfo = new BulletHeightMapInfo(pId, pheightMap, null);
1385 mapInfo.heightMap = null;
1386 mapInfo.minCoords = pminCoords;
1387 mapInfo.maxCoords = pmaxCoords;
1388 mapInfo.sizeX = (int) (pmaxCoords.X - pminCoords.X);
1389 mapInfo.sizeY = (int) (pmaxCoords.Y - pminCoords.Y);
1390 mapInfo.ID = pId;
1391 mapInfo.minZ = pminCoords.Z;
1392 mapInfo.maxZ = pmaxCoords.Z;
1393 mapInfo.collisionMargin = pCollisionMargin;
1394 if (mapInfo.minZ == mapInfo.maxZ)
1395 mapInfo.minZ -= 0.2f;
1396 mapInfo.heightMap = pheightMap;
1397
1398 return mapInfo;
1399
1400 }
1401
1402 internal static object CreateTerrainShape2(object pMapInfo)
1403 {
1404 BulletHeightMapInfo mapinfo = pMapInfo as BulletHeightMapInfo;
1405 const int upAxis = 2;
1406 const float scaleFactor = 1.0f;
1407 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)mapinfo.sizeX, (int)mapinfo.sizeY,
1408 mapinfo.heightMap, scaleFactor,
1409 mapinfo.minZ, mapinfo.maxZ, upAxis,
1410 false);
1411 terrainShape.SetMargin(mapinfo.collisionMargin + 0.5f);
1412 terrainShape.SetUseDiamondSubdivision(true);
1413 terrainShape.SetUserPointer(mapinfo.ID);
1414 return terrainShape;
1415 }
1416
1417 internal static bool TranslationalLimitMotor2(object pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1418 {
1419 TypedConstraint tconstrain = pConstraint as TypedConstraint;
1420 bool onOff = ponOff != 0;
1421 bool ret = false;
1422
1423 switch (tconstrain.GetConstraintType())
1424 {
1425 case TypedConstraintType.D6_CONSTRAINT_TYPE:
1426 Generic6DofConstraint constrain = pConstraint as Generic6DofConstraint;
1427 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
1428 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
1429 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
1430 ret = true;
1431 break;
1432 }
1433
1434
1435 return ret;
1436
1437 }
1438
1439 internal static int PhysicsStep2(object pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc>colliders)
1440 {
1441 int epic = PhysicsStepint2(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1442 out collidersCount, out colliders);
1443 return epic;
1444 }
1445
1446 private static int PhysicsStepint2(object pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc> colliders)
1447 {
1448 int numSimSteps = 0;
1449
1450
1451 //if (updatedEntities is null)
1452 // updatedEntities = new List<BulletXNA.EntityProperties>();
1453
1454 //if (colliders is null)
1455 // colliders = new List<BulletXNA.CollisionDesc>();
1456
1457
1458 if (pWorld is DiscreteDynamicsWorld)
1459 {
1460 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
1461
1462 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1463 int updates = 0;
1464
1465 updatedEntityCount = world.UpdatedObjects.Count;
1466 updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects);
1467 updatedEntityCount = updatedEntities.Count;
1468 world.UpdatedObjects.Clear();
1469
1470
1471 collidersCount = world.UpdatedCollisions.Count;
1472 colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions);
1473
1474 world.UpdatedCollisions.Clear();
1475 m_collisionsThisFrame = 0;
1476 int numManifolds = world.GetDispatcher().GetNumManifolds();
1477 for (int j = 0; j < numManifolds; j++)
1478 {
1479 PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
1480 int numContacts = contactManifold.GetNumContacts();
1481 if (numContacts == 0)
1482 continue;
1483
1484 CollisionObject objA = contactManifold.GetBody0() as CollisionObject;
1485 CollisionObject objB = contactManifold.GetBody1() as CollisionObject;
1486
1487 ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0);
1488 IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
1489 IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
1490
1491 RecordCollision(world, objA, objB, contactPoint, contactNormal);
1492 m_collisionsThisFrame ++;
1493 if (m_collisionsThisFrame >= 9999999)
1494 break;
1495
1496
1497 }
1498
1499
1500 }
1501 else
1502 {
1503 //if (updatedEntities is null)
1504 updatedEntities = new List<BulletXNA.EntityProperties>();
1505 updatedEntityCount = 0;
1506 //if (colliders is null)
1507 colliders = new List<BulletXNA.CollisionDesc>();
1508 collidersCount = 0;
1509 }
1510 return numSimSteps;
1511 }
1512
1513 private static void RecordCollision(CollisionWorld world,CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm)
1514 {
1515
1516 IndexedVector3 contactNormal = norm;
1517 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
1518 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
1519 {
1520 return;
1521 }
1522 uint idA = (uint)objA.GetUserPointer();
1523 uint idB = (uint)objB.GetUserPointer();
1524 if (idA > idB)
1525 {
1526 uint temp = idA;
1527 idA = idB;
1528 idB = temp;
1529 contactNormal = -contactNormal;
1530 }
1531
1532 ulong collisionID = ((ulong) idA << 32) | idB;
1533
1534 BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc()
1535 {
1536 aID = idA,
1537 bID = idB,
1538 point = contact,
1539 normal = contactNormal
1540 };
1541 world.UpdatedCollisions.Add(cDesc);
1542 m_collisionsThisFrame++;
1543
1544
1545 }
1546 private static EntityProperties GetDebugProperties(object pWorld, object pBody)
1547 {
1548 EntityProperties ent = new EntityProperties();
1549 DiscreteDynamicsWorld world = pWorld as DiscreteDynamicsWorld;
1550 RigidBody body = pBody as RigidBody;
1551 IndexedMatrix transform = body.GetWorldTransform();
1552 IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity();
1553 IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity();
1554 IndexedQuaternion rotation = transform.GetRotation();
1555 ent.Acceleration = Vector3.Zero;
1556 ent.ID = (uint)body.GetUserPointer();
1557 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
1558 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
1559 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
1560 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
1561 return ent;
1562
1563
1564 }
1565
1566
1567 internal static Vector3 GetLocalScaling2(object pBody)
1568 {
1569 CollisionShape shape = pBody as CollisionShape;
1570 IndexedVector3 scale = shape.GetLocalScaling();
1571 return new Vector3(scale.X,scale.Y,scale.Z);
1572 }
1573
1574 internal static bool RayCastGround(object pWorld, Vector3 _RayOrigin, float pRayHeight, object NotMe)
1575 {
1576 DynamicsWorld world = pWorld as DynamicsWorld;
1577 if (world != null)
1578 {
1579 if (NotMe is CollisionObject || NotMe is RigidBody)
1580 {
1581 CollisionObject AvoidBody = NotMe as CollisionObject;
1582
1583 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
1584 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
1585 using (
1586 ClosestNotMeRayResultCallback rayCallback = new ClosestNotMeRayResultCallback(rOrigin,
1587 rEnd, AvoidBody)
1588 )
1589 {
1590 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
1591 if (rayCallback.HasHit())
1592 {
1593 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
1594
1595 }
1596 return rayCallback.HasHit();
1597 }
1598 }
1599 }
1600 return false;
1601 }
1602}
1603}
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs
deleted file mode 100644
index f509dc4..0000000
--- a/OpenSim/Region/Physics/BulletSNPlugin/BulletSimData.cs
+++ /dev/null
@@ -1,280 +0,0 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSNPlugin
33{
34// Classes to allow some type checking for the API
35// These hold pointers to allocated objects in the unmanaged space.
36
37// The physics engine controller class created at initialization
38public struct BulletWorld
39{
40 public BulletWorld(uint worldId, BSScene bss, object xx)
41 {
42 ptr = xx;
43 worldID = worldId;
44 physicsScene = bss;
45 }
46 public object ptr;
47 public uint worldID;
48 // The scene is only in here so very low level routines have a handle to print debug/error messages
49 public BSScene physicsScene;
50}
51
52// An allocated Bullet btRigidBody
53public struct BulletBody
54{
55 public BulletBody(uint id) : this(id, null)
56 {
57 }
58 public BulletBody(uint id, object xx)
59 {
60 ID = id;
61 ptr = xx;
62 collisionType = CollisionType.Static;
63 }
64 public object ptr;
65 public uint ID;
66 public CollisionType collisionType;
67
68 public void Clear()
69 {
70 ptr = null;
71 }
72 public bool HasPhysicalBody { get { return ptr != null; } }
73
74 // Apply the specificed collision mask into the physical world
75 public void ApplyCollisionMask()
76 {
77 // Should assert the body has been added to the physical world.
78 // (The collision masks are stored in the collision proxy cache which only exists for
79 // a collision body that is in the world.)
80 BulletSimAPI.SetCollisionGroupMask2(ptr,
81 BulletSimData.CollisionTypeMasks[collisionType].group,
82 BulletSimData.CollisionTypeMasks[collisionType].mask);
83 }
84
85 public override string ToString()
86 {
87 StringBuilder buff = new StringBuilder();
88 buff.Append("<id=");
89 buff.Append(ID.ToString());
90 buff.Append(",p=");
91 buff.Append(ptr.ToString());
92 buff.Append(",c=");
93 buff.Append(collisionType);
94 buff.Append(">");
95 return buff.ToString();
96 }
97}
98
99public struct BulletShape
100{
101 public BulletShape(object xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN)
102 {
103 }
104 public BulletShape(object xx, BSPhysicsShapeType typ)
105 {
106 ptr = xx;
107 type = typ;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false;
110 }
111 public object ptr;
112 public BSPhysicsShapeType type;
113 public System.UInt64 shapeKey;
114 public bool isNativeShape;
115
116 public void Clear()
117 {
118 ptr = null;
119 }
120 public bool HasPhysicalShape { get { return ptr != null; } }
121
122 public override string ToString()
123 {
124 StringBuilder buff = new StringBuilder();
125 buff.Append("<p=");
126 buff.Append(ptr.ToString());
127 buff.Append(",s=");
128 buff.Append(type.ToString());
129 buff.Append(",k=");
130 buff.Append(shapeKey.ToString("X"));
131 buff.Append(",n=");
132 buff.Append(isNativeShape.ToString());
133 buff.Append(">");
134 return buff.ToString();
135 }
136}
137
138// An allocated Bullet btConstraint
139public struct BulletConstraint
140{
141 public BulletConstraint(object xx)
142 {
143 ptr = xx;
144 }
145 public object ptr;
146
147 public void Clear()
148 {
149 ptr = null;
150 }
151 public bool HasPhysicalConstraint { get { return ptr != null; } }
152}
153
154// An allocated HeightMapThing which holds various heightmap info.
155// Made a class rather than a struct so there would be only one
156// instance of this and C# will pass around pointers rather
157// than making copies.
158public class BulletHeightMapInfo
159{
160 public BulletHeightMapInfo(uint id, float[] hm, object xx) {
161 ID = id;
162 Ptr = xx;
163 heightMap = hm;
164 terrainRegionBase = OMV.Vector3.Zero;
165 minCoords = new OMV.Vector3(100f, 100f, 25f);
166 maxCoords = new OMV.Vector3(101f, 101f, 26f);
167 minZ = maxZ = 0f;
168 sizeX = sizeY = 256f;
169 }
170 public uint ID;
171 public object Ptr;
172 public float[] heightMap;
173 public OMV.Vector3 terrainRegionBase;
174 public OMV.Vector3 minCoords;
175 public OMV.Vector3 maxCoords;
176 public float sizeX, sizeY;
177 public float minZ, maxZ;
178 public BulletShape terrainShape;
179 public BulletBody terrainBody;
180
181 public float collisionMargin { get; set; }
182}
183
184// The general class of collsion object.
185public enum CollisionType
186{
187 Avatar,
188 Groundplane,
189 Terrain,
190 Static,
191 Dynamic,
192 VolumeDetect,
193 // Linkset, // A linkset should be either Static or Dynamic
194 LinksetChild,
195 Unknown
196};
197
198// Hold specification of group and mask collision flags for a CollisionType
199public struct CollisionTypeFilterGroup
200{
201 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
202 {
203 type = t;
204 group = g;
205 mask = m;
206 }
207 public CollisionType type;
208 public uint group;
209 public uint mask;
210};
211
212 /* NOTE: old definitions kept for reference. Delete when things are working.
213 // The collsion filters and masked are defined in one place -- don't want them scattered
214 AvatarGroup = BCharacterGroup,
215 AvatarMask = BAllGroup,
216 ObjectGroup = BSolidGroup,
217 ObjectMask = BAllGroup,
218 StaticObjectGroup = BStaticGroup,
219 StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
220 LinksetGroup = BLinksetGroup,
221 LinksetMask = BAllGroup,
222 LinksetChildGroup = BLinksetChildGroup,
223 LinksetChildMask = BNoneGroup, // Linkset children disappear from the world
224 VolumeDetectGroup = BSensorTrigger,
225 VolumeDetectMask = ~BSensorTrigger,
226 TerrainGroup = BTerrainGroup,
227 TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
228 GroundPlaneGroup = BGroundPlaneGroup,
229 GroundPlaneMask = BAllGroup
230 */
231
232public static class BulletSimData
233{
234
235// Map of collisionTypes to flags for collision groups and masks.
236// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
237// but, instead, use references to this dictionary. Finding and debugging
238// collision flag problems will be made easier.
239public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
240 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
241{
242 { CollisionType.Avatar,
243 new CollisionTypeFilterGroup(CollisionType.Avatar,
244 (uint)CollisionFilterGroups.BCharacterGroup,
245 (uint)CollisionFilterGroups.BAllGroup)
246 },
247 { CollisionType.Groundplane,
248 new CollisionTypeFilterGroup(CollisionType.Groundplane,
249 (uint)CollisionFilterGroups.BGroundPlaneGroup,
250 (uint)CollisionFilterGroups.BAllGroup)
251 },
252 { CollisionType.Terrain,
253 new CollisionTypeFilterGroup(CollisionType.Terrain,
254 (uint)CollisionFilterGroups.BTerrainGroup,
255 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
256 },
257 { CollisionType.Static,
258 new CollisionTypeFilterGroup(CollisionType.Static,
259 (uint)CollisionFilterGroups.BStaticGroup,
260 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
261 },
262 { CollisionType.Dynamic,
263 new CollisionTypeFilterGroup(CollisionType.Dynamic,
264 (uint)CollisionFilterGroups.BSolidGroup,
265 (uint)(CollisionFilterGroups.BAllGroup))
266 },
267 { CollisionType.VolumeDetect,
268 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
269 (uint)CollisionFilterGroups.BSensorTrigger,
270 (uint)(~CollisionFilterGroups.BSensorTrigger))
271 },
272 { CollisionType.LinksetChild,
273 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
274 (uint)CollisionFilterGroups.BTerrainGroup,
275 (uint)(CollisionFilterGroups.BNoneGroup))
276 },
277};
278
279}
280}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
index b6ff52b..49b1730 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -129,7 +129,12 @@ private sealed class BulletConstraintXNA : BulletConstraint
129 get { return "XNAConstraint"; } 129 get { return "XNAConstraint"; }
130 } 130 }
131} 131}
132 internal int m_maxCollisions;
133 internal CollisionDesc[] m_collisionArray;
132 134
135 internal int m_maxUpdatesPerFrame;
136 internal EntityProperties[] m_updateArray;
137
133 private static int m_collisionsThisFrame; 138 private static int m_collisionsThisFrame;
134 private BSScene PhysicsScene { get; set; } 139 private BSScene PhysicsScene { get; set; }
135 140
@@ -148,92 +153,98 @@ private sealed class BulletConstraintXNA : BulletConstraint
148 /// <param name="p_2"></param> 153 /// <param name="p_2"></param>
149 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) 154 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
150 { 155 {
151 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 156 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
152 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 157 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
153 world.RemoveRigidBody(body); 158 world.RemoveRigidBody(body);
154 return true; 159 return true;
155 } 160 }
156 161
157 public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) 162 public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
158 { 163 {
159 /* TODO */ 164 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
160 return false; 165 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
166 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
167
168 return true;
169
161 } 170 }
162 171
163 public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) 172 public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint)
164 { 173 {
165 /* TODO */ 174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
166 return false; 175 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
176 world.RemoveConstraint(constraint);
177 return true;
167 } 178 }
168 179
169 public override void SetRestitution(BulletBody pBody, float pRestitution) 180 public override void SetRestitution(BulletBody pCollisionObject, float pRestitution)
170 { 181 {
171 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 182 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
172 body.SetRestitution(pRestitution); 183 collisionObject.SetRestitution(pRestitution);
173 } 184 }
174 185
175 public override int GetShapeType(BulletShape pShape) 186 public override int GetShapeType(BulletShape pShape)
176 { 187 {
177 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 188 CollisionShape shape = (pShape as BulletShapeXNA).shape;
178 return (int)shape.GetShapeType(); 189 return (int)shape.GetShapeType();
179 } 190 }
180 public override void SetMargin(BulletShape pShape, float pMargin) 191 public override void SetMargin(BulletShape pShape, float pMargin)
181 { 192 {
182 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 193 CollisionShape shape = (pShape as BulletShapeXNA).shape;
183 shape.SetMargin(pMargin); 194 shape.SetMargin(pMargin);
184 } 195 }
185 196
186 public override float GetMargin(BulletShape pShape) 197 public override float GetMargin(BulletShape pShape)
187 { 198 {
188 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 199 CollisionShape shape = (pShape as BulletShapeXNA).shape;
189 return shape.GetMargin(); 200 return shape.GetMargin();
190 } 201 }
191 202
192 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) 203 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
193 { 204 {
194 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 205 CollisionShape shape = (pShape as BulletShapeXNA).shape;
195 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); 206 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
196 shape.SetLocalScaling(ref vec); 207 shape.SetLocalScaling(ref vec);
197 208
198 } 209 }
199 210
200 public override void SetContactProcessingThreshold(BulletBody pBody, float contactprocessingthreshold) 211 public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold)
201 { 212 {
202 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 213 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
203 body.SetContactProcessingThreshold(contactprocessingthreshold); 214 collisionObject.SetContactProcessingThreshold(contactprocessingthreshold);
204 } 215 }
205 216
206 public override void SetCcdMotionThreshold(BulletBody pBody, float pccdMotionThreashold) 217 public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold)
207 { 218 {
208 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 219 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
209 body.SetCcdMotionThreshold(pccdMotionThreashold); 220 collisionObject.SetCcdMotionThreshold(pccdMotionThreashold);
210 } 221 }
211 222
212 public override void SetCcdSweptSphereRadius(BulletBody pBody, float pCcdSweptSphereRadius) 223 public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius)
213 { 224 {
214 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 225 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
215 body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); 226 collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
216 } 227 }
217 228
218 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) 229 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
219 { 230 {
220 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 231 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
221 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); 232 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
222 } 233 }
223 234
224 public override CollisionFlags AddToCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags) 235 public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
225 { 236 {
226 CollisionObject body = ((BulletBodyXNA)pBody).body; 237 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
227 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); 238 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
228 existingcollisionFlags |= pcollisionFlags; 239 existingcollisionFlags |= pcollisionFlags;
229 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); 240 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
230 return (CollisionFlags) (uint) existingcollisionFlags; 241 return (CollisionFlags) (uint) existingcollisionFlags;
231 } 242 }
232 243
233 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) 244 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
234 { 245 {
235 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 246 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
236 CollisionObject cbody = ((BulletBodyXNA)pBody).body; 247 CollisionObject cbody = (pBody as BulletBodyXNA).body;
237 RigidBody rbody = cbody as RigidBody; 248 RigidBody rbody = cbody as RigidBody;
238 249
239 // Bullet resets several variables when an object is added to the world. In particular, 250 // Bullet resets several variables when an object is added to the world. In particular,
@@ -259,99 +270,110 @@ private sealed class BulletConstraintXNA : BulletConstraint
259 return true; 270 return true;
260 } 271 }
261 272
262 public override void ForceActivationState(BulletBody pBody, ActivationState pActivationState) 273 public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState)
263 { 274 {
264 CollisionObject body = ((BulletBodyXNA)pBody).body; 275 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
265 body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); 276 collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
266 } 277 }
267 278
268 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pBody) 279 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject)
269 { 280 {
270 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 281 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
271 CollisionObject body = ((BulletBodyXNA)pBody).body; 282 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
272 world.UpdateSingleAabb(body); 283 world.UpdateSingleAabb(collisionObject);
273 } 284 }
274 285
275 public override void UpdateAabbs(BulletWorld world) { /* TODO */ } 286 public override void UpdateAabbs(BulletWorld pWorld) {
276 public override bool GetForceUpdateAllAabbs(BulletWorld world) { /* TODO */ return false; } 287 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
277 public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) { /* TODO */ } 288 world.UpdateAabbs();
289 }
290 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
291 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
292 return world.GetForceUpdateAllAabbs();
293
294 }
295 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
296 {
297 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
298 world.SetForceUpdateAllAabbs(pForce);
299 }
278 300
279 public override bool SetCollisionGroupMask(BulletBody pBody, uint pGroup, uint pMask) 301 public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask)
280 { 302 {
281 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 303 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
282 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; 304 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
283 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; 305 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
284 if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0) 306 if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0)
285 return false; 307 return false;
286 return true; 308 return true;
287 } 309 }
288 310
289 public override void ClearAllForces(BulletBody pBody) 311 public override void ClearAllForces(BulletBody pCollisionObject)
290 { 312 {
291 CollisionObject body = ((BulletBodyXNA)pBody).body; 313 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
292 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); 314 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
293 body.SetInterpolationLinearVelocity(ref zeroVector); 315 collisionObject.SetInterpolationLinearVelocity(ref zeroVector);
294 body.SetInterpolationAngularVelocity(ref zeroVector); 316 collisionObject.SetInterpolationAngularVelocity(ref zeroVector);
295 IndexedMatrix bodytransform = body.GetWorldTransform(); 317 IndexedMatrix bodytransform = collisionObject.GetWorldTransform();
296 318
297 body.SetInterpolationWorldTransform(ref bodytransform); 319 collisionObject.SetInterpolationWorldTransform(ref bodytransform);
298 320
299 if (body is RigidBody) 321 if (collisionObject is RigidBody)
300 { 322 {
301 RigidBody rigidbody = body as RigidBody; 323 RigidBody rigidbody = collisionObject as RigidBody;
302 rigidbody.SetLinearVelocity(zeroVector); 324 rigidbody.SetLinearVelocity(zeroVector);
303 rigidbody.SetAngularVelocity(zeroVector); 325 rigidbody.SetAngularVelocity(zeroVector);
304 rigidbody.ClearForces(); 326 rigidbody.ClearForces();
305 } 327 }
306 } 328 }
307 329
308 public override void SetInterpolationAngularVelocity(BulletBody pBody, Vector3 pVector3) 330 public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3)
309 { 331 {
310 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 332 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
311 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); 333 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
312 body.SetInterpolationAngularVelocity(ref vec); 334 collisionObject.SetInterpolationAngularVelocity(ref vec);
313 } 335 }
314 336
315 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) 337 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
316 { 338 {
317 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 339 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
318 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); 340 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
319 body.SetAngularVelocity(ref vec); 341 body.SetAngularVelocity(ref vec);
320 } 342 }
321 public override Vector3 GetTotalForce(BulletBody pBody) 343 public override Vector3 GetTotalForce(BulletBody pBody)
322 { 344 {
323 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 345 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
324 IndexedVector3 iv3 = body.GetTotalForce(); 346 IndexedVector3 iv3 = body.GetTotalForce();
325 return new Vector3(iv3.X, iv3.Y, iv3.Z); 347 return new Vector3(iv3.X, iv3.Y, iv3.Z);
326 } 348 }
327 public override Vector3 GetTotalTorque(BulletBody pBody) 349 public override Vector3 GetTotalTorque(BulletBody pBody)
328 { 350 {
329 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 351 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
330 IndexedVector3 iv3 = body.GetTotalTorque(); 352 IndexedVector3 iv3 = body.GetTotalTorque();
331 return new Vector3(iv3.X, iv3.Y, iv3.Z); 353 return new Vector3(iv3.X, iv3.Y, iv3.Z);
332 } 354 }
333 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) 355 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
334 { 356 {
335 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 357 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
336 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); 358 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
337 return new Vector3(iv3.X, iv3.Y, iv3.Z); 359 return new Vector3(iv3.X, iv3.Y, iv3.Z);
338 } 360 }
339 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) 361 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
340 { 362 {
341 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 363 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
342 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); 364 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
343 body.SetInvInertiaDiagLocal(ref iv3); 365 body.SetInvInertiaDiagLocal(ref iv3);
344 } 366 }
345 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) 367 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
346 { 368 {
347 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 369 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
348 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); 370 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
349 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); 371 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
350 body.ApplyForce(ref forceiv3, ref posiv3); 372 body.ApplyForce(ref forceiv3, ref posiv3);
351 } 373 }
352 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) 374 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
353 { 375 {
354 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 376 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
355 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); 377 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
356 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); 378 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
357 body.ApplyImpulse(ref impiv3, ref posiv3); 379 body.ApplyImpulse(ref impiv3, ref posiv3);
@@ -359,32 +381,32 @@ private sealed class BulletConstraintXNA : BulletConstraint
359 381
360 public override void ClearForces(BulletBody pBody) 382 public override void ClearForces(BulletBody pBody)
361 { 383 {
362 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 384 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
363 body.ClearForces(); 385 body.ClearForces();
364 } 386 }
365 387
366 public override void SetTranslation(BulletBody pBody, Vector3 _position, Quaternion _orientation) 388 public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation)
367 { 389 {
368 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 390 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
369 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); 391 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
370 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, 392 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
371 _orientation.W); 393 _orientation.W);
372 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); 394 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
373 mat._origin = vposition; 395 mat._origin = vposition;
374 body.SetWorldTransform(mat); 396 collisionObject.SetWorldTransform(mat);
375 397
376 } 398 }
377 399
378 public override Vector3 GetPosition(BulletBody pBody) 400 public override Vector3 GetPosition(BulletBody pCollisionObject)
379 { 401 {
380 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 402 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
381 IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin; 403 IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin;
382 return new Vector3(pos.X, pos.Y, pos.Z); 404 return new Vector3(pos.X, pos.Y, pos.Z);
383 } 405 }
384 406
385 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) 407 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
386 { 408 {
387 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 409 CollisionShape shape = (pShape as BulletShapeXNA).shape;
388 IndexedVector3 inertia = IndexedVector3.Zero; 410 IndexedVector3 inertia = IndexedVector3.Zero;
389 shape.CalculateLocalInertia(pphysMass, out inertia); 411 shape.CalculateLocalInertia(pphysMass, out inertia);
390 return new Vector3(inertia.X, inertia.Y, inertia.Z); 412 return new Vector3(inertia.X, inertia.Y, inertia.Z);
@@ -392,7 +414,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
392 414
393 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) 415 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
394 { 416 {
395 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 417 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
396 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); 418 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
397 body.SetMassProps(pphysMass, inertia); 419 body.SetMassProps(pphysMass, inertia);
398 } 420 }
@@ -400,73 +422,90 @@ private sealed class BulletConstraintXNA : BulletConstraint
400 422
401 public override void SetObjectForce(BulletBody pBody, Vector3 _force) 423 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
402 { 424 {
403 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 425 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
404 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); 426 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
405 body.SetTotalForce(ref force); 427 body.SetTotalForce(ref force);
406 } 428 }
407 429
408 public override void SetFriction(BulletBody pBody, float _currentFriction) 430 public override void SetFriction(BulletBody pCollisionObject, float _currentFriction)
409 { 431 {
410 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 432 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
411 body.SetFriction(_currentFriction); 433 collisionObject.SetFriction(_currentFriction);
412 } 434 }
413 435
414 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) 436 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
415 { 437 {
416 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 438 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
417 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); 439 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
418 body.SetLinearVelocity(velocity); 440 body.SetLinearVelocity(velocity);
419 } 441 }
420 442
421 public override void Activate(BulletBody pBody, bool pforceactivation) 443 public override void Activate(BulletBody pCollisionObject, bool pforceactivation)
422 { 444 {
423 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 445 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
424 body.Activate(pforceactivation); 446 collisionObject.Activate(pforceactivation);
425 447
426 } 448 }
427 449
428 public override Quaternion GetOrientation(BulletBody pBody) 450 public override Quaternion GetOrientation(BulletBody pCollisionObject)
429 { 451 {
430 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 452 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
431 IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation(); 453 IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation();
432 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); 454 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
433 } 455 }
434 456
435 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags) 457 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
436 { 458 {
437 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 459 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
438 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); 460 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
439 existingcollisionFlags &= ~pcollisionFlags; 461 existingcollisionFlags &= ~pcollisionFlags;
440 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); 462 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
441 return (CollisionFlags)(uint)existingcollisionFlags; 463 return (CollisionFlags)(uint)existingcollisionFlags;
442 } 464 }
443 465
444 public override float GetCcdMotionThreshold(BulletBody obj) { /* TODO */ return 0f; } 466 public override float GetCcdMotionThreshold(BulletBody pCollisionObject)
467 {
468 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
469 return collisionObject.GetCcdSquareMotionThreshold();
470 }
445 471
446 public override float GetCcdSweptSphereRadius(BulletBody obj) { /* TODO */ return 0f; } 472 public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject)
473 {
474 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
475 return collisionObject.GetCcdSweptSphereRadius();
476
477 }
447 478
448 public override IntPtr GetUserPointer(BulletBody obj) { /* TODO */ return IntPtr.Zero; } 479 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
480 {
481 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
482 return (IntPtr)shape.GetUserPointer();
483 }
449 484
450 public override void SetUserPointer(BulletBody obj, IntPtr val) { /* TODO */ } 485 public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val)
486 {
487 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
488 shape.SetUserPointer(val);
489 }
451 490
452 public override void SetGravity(BulletBody pBody, Vector3 pGravity) 491 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
453 { 492 {
454 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 493 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
455 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); 494 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
456 body.SetGravity(gravity); 495 body.SetGravity(gravity);
457 } 496 }
458 497
459 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) 498 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
460 { 499 {
461 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 500 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
462 TypedConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain; 501 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
463 world.RemoveConstraint(constraint); 502 world.RemoveConstraint(constraint);
464 return true; 503 return true;
465 } 504 }
466 505
467 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) 506 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
468 { 507 {
469 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; 508 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
470 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); 509 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
471 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); 510 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
472 constraint.SetLinearLowerLimit(lowlimit); 511 constraint.SetLinearLowerLimit(lowlimit);
@@ -476,7 +515,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
476 515
477 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) 516 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
478 { 517 {
479 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; 518 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
480 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); 519 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
481 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); 520 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
482 constraint.SetAngularLowerLimit(lowlimit); 521 constraint.SetAngularLowerLimit(lowlimit);
@@ -486,20 +525,20 @@ private sealed class BulletConstraintXNA : BulletConstraint
486 525
487 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) 526 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
488 { 527 {
489 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; 528 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
490 constraint.SetOverrideNumSolverIterations((int)cnt); 529 constraint.SetOverrideNumSolverIterations((int)cnt);
491 } 530 }
492 531
493 public override bool CalculateTransforms(BulletConstraint pConstraint) 532 public override bool CalculateTransforms(BulletConstraint pConstraint)
494 { 533 {
495 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; 534 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
496 constraint.CalculateTransforms(); 535 constraint.CalculateTransforms();
497 return true; 536 return true;
498 } 537 }
499 538
500 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) 539 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
501 { 540 {
502 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; 541 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
503 constraint.SetEnabled((p_2 == 0) ? false : true); 542 constraint.SetEnabled((p_2 == 0) ? false : true);
504 } 543 }
505 544
@@ -508,9 +547,9 @@ private sealed class BulletConstraintXNA : BulletConstraint
508 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) 547 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
509 548
510 { 549 {
511 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 550 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
512 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody; 551 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
513 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody; 552 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
514 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); 553 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
515 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); 554 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
516 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); 555 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
@@ -542,9 +581,9 @@ private sealed class BulletConstraintXNA : BulletConstraint
542 /// <returns></returns> 581 /// <returns></returns>
543 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) 582 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
544 { 583 {
545 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 584 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
546 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody; 585 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
547 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody; 586 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
548 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); 587 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
549 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); 588 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
550 589
@@ -563,7 +602,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
563 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); 602 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
564 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) 603 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
565 { 604 {
566 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; 605 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
567 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); 606 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
568 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); 607 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
569 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); 608 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
@@ -579,109 +618,110 @@ private sealed class BulletConstraintXNA : BulletConstraint
579 618
580 public override Vector3 GetLinearVelocity(BulletBody pBody) 619 public override Vector3 GetLinearVelocity(BulletBody pBody)
581 { 620 {
582 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 621 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
583 IndexedVector3 iv3 = body.GetLinearVelocity(); 622 IndexedVector3 iv3 = body.GetLinearVelocity();
584 return new Vector3(iv3.X, iv3.Y, iv3.Z); 623 return new Vector3(iv3.X, iv3.Y, iv3.Z);
585 } 624 }
586 public override Vector3 GetAngularVelocity(BulletBody pBody) 625 public override Vector3 GetAngularVelocity(BulletBody pBody)
587 { 626 {
588 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 627 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
589 IndexedVector3 iv3 = body.GetAngularVelocity(); 628 IndexedVector3 iv3 = body.GetAngularVelocity();
590 return new Vector3(iv3.X, iv3.Y, iv3.Z); 629 return new Vector3(iv3.X, iv3.Y, iv3.Z);
591 } 630 }
592 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) 631 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
593 { 632 {
594 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 633 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
595 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); 634 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
596 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); 635 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
597 return new Vector3(iv3.X, iv3.Y, iv3.Z); 636 return new Vector3(iv3.X, iv3.Y, iv3.Z);
598 } 637 }
599 public override void Translate(BulletBody pBody, Vector3 trans) 638 public override void Translate(BulletBody pCollisionObject, Vector3 trans)
600 { 639 {
601 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 640 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
641 collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z));
602 } 642 }
603 public override void UpdateDeactivation(BulletBody pBody, float timeStep) 643 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
604 { 644 {
605 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 645 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
606 body.UpdateDeactivation(timeStep); 646 body.UpdateDeactivation(timeStep);
607 } 647 }
608 648
609 public override bool WantsSleeping(BulletBody pBody) 649 public override bool WantsSleeping(BulletBody pBody)
610 { 650 {
611 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 651 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
612 return body.WantsSleeping(); 652 return body.WantsSleeping();
613 } 653 }
614 654
615 public override void SetAngularFactor(BulletBody pBody, float factor) 655 public override void SetAngularFactor(BulletBody pBody, float factor)
616 { 656 {
617 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 657 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
618 body.SetAngularFactor(factor); 658 body.SetAngularFactor(factor);
619 } 659 }
620 660
621 public override Vector3 GetAngularFactor(BulletBody pBody) 661 public override Vector3 GetAngularFactor(BulletBody pBody)
622 { 662 {
623 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 663 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
624 IndexedVector3 iv3 = body.GetAngularFactor(); 664 IndexedVector3 iv3 = body.GetAngularFactor();
625 return new Vector3(iv3.X, iv3.Y, iv3.Z); 665 return new Vector3(iv3.X, iv3.Y, iv3.Z);
626 } 666 }
627 667
628 public override bool IsInWorld(BulletWorld pWorld, BulletBody pBody) 668 public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject)
629 { 669 {
630 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 670 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
631 CollisionObject body = ((BulletBodyXNA)pBody).body; 671 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
632 return world.IsInWorld(body); 672 return world.IsInWorld(collisionObject);
633 } 673 }
634 674
635 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstrain) 675 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
636 { 676 {
637 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 677 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
638 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain; 678 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
639 body.AddConstraintRef(constrain); 679 body.AddConstraintRef(constrain);
640 } 680 }
641 681
642 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstrain) 682 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
643 { 683 {
644 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 684 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
645 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain; 685 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
646 body.RemoveConstraintRef(constrain); 686 body.RemoveConstraintRef(constrain);
647 } 687 }
648 688
649 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) 689 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
650 { 690 {
651 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 691 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
652 return new BulletConstraintXNA(body.GetConstraintRef(index)); 692 return new BulletConstraintXNA(body.GetConstraintRef(index));
653 } 693 }
654 694
655 public override int GetNumConstraintRefs(BulletBody pBody) 695 public override int GetNumConstraintRefs(BulletBody pBody)
656 { 696 {
657 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 697 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
658 return body.GetNumConstraintRefs(); 698 return body.GetNumConstraintRefs();
659 } 699 }
660 700
661 public override void SetInterpolationLinearVelocity(BulletBody pBody, Vector3 VehicleVelocity) 701 public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity)
662 { 702 {
663 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 703 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
664 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); 704 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
665 body.SetInterpolationLinearVelocity(ref velocity); 705 collisionObject.SetInterpolationLinearVelocity(ref velocity);
666 } 706 }
667 707
668 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) 708 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
669 { 709 {
670 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; 710 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
671 constraint.SetUseFrameOffset((onOff == 0) ? false : true); 711 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
672 return true; 712 return true;
673 } 713 }
674 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); 714 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
675 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) 715 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
676 { 716 {
677 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; 717 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
678 constraint.SetBreakingImpulseThreshold(threshold); 718 constraint.SetBreakingImpulseThreshold(threshold);
679 return true; 719 return true;
680 } 720 }
681 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); 721 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
682 public override void SetAngularDamping(BulletBody pBody, float angularDamping) 722 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
683 { 723 {
684 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 724 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
685 float lineardamping = body.GetLinearDamping(); 725 float lineardamping = body.GetLinearDamping();
686 body.SetDamping(lineardamping, angularDamping); 726 body.SetDamping(lineardamping, angularDamping);
687 727
@@ -689,111 +729,183 @@ private sealed class BulletConstraintXNA : BulletConstraint
689 729
690 public override void UpdateInertiaTensor(BulletBody pBody) 730 public override void UpdateInertiaTensor(BulletBody pBody)
691 { 731 {
692 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 732 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
693 body.UpdateInertiaTensor(); 733 body.UpdateInertiaTensor();
694 } 734 }
695 735
696 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) 736 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
697 { 737 {
698 CompoundShape shape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape; 738 CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
699 shape.RecalculateLocalAabb(); 739 shape.RecalculateLocalAabb();
700 } 740 }
701 741
702 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) 742 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
703 public override CollisionFlags GetCollisionFlags(BulletBody pBody) 743 public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject)
704 { 744 {
705 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 745 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
706 uint flags = (uint)body.GetCollisionFlags(); 746 uint flags = (uint)collisionObject.GetCollisionFlags();
707 return (CollisionFlags) flags; 747 return (CollisionFlags) flags;
708 } 748 }
709 749
710 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) 750 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
711 { 751 {
712 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 752 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
713 body.SetDamping(pLinear, pAngular); 753 body.SetDamping(pLinear, pAngular);
714 } 754 }
715 //PhysBody.ptr, PhysicsScene.Params.deactivationTime); 755 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
716 public override void SetDeactivationTime(BulletBody pBody, float pDeactivationTime) 756 public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime)
717 { 757 {
718 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 758 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
719 body.SetDeactivationTime(pDeactivationTime); 759 collisionObject.SetDeactivationTime(pDeactivationTime);
720 } 760 }
721 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 761 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
722 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) 762 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
723 { 763 {
724 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 764 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
725 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); 765 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
726 } 766 }
727 767
728 public override CollisionObjectTypes GetBodyType(BulletBody pBody) 768 public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject)
729 { 769 {
730 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 770 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
731 return (CollisionObjectTypes)(int) body.GetInternalType(); 771 return (CollisionObjectTypes)(int) collisionObject.GetInternalType();
732 } 772 }
733 773
734 public override void ApplyGravity(BulletBody obj) { /* TODO */ } 774 public override void ApplyGravity(BulletBody pBody)
775 {
735 776
736 public override Vector3 GetGravity(BulletBody obj) { /* TODO */ return Vector3.Zero; } 777 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
778 body.ApplyGravity();
779 }
737 780
738 public override void SetLinearDamping(BulletBody obj, float lin_damping) { /* TODO */ } 781 public override Vector3 GetGravity(BulletBody pBody)
782 {
783 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
784 IndexedVector3 gravity = body.GetGravity();
785 return new Vector3(gravity.X, gravity.Y, gravity.Z);
786 }
739 787
740 public override float GetLinearDamping(BulletBody obj) { /* TODO */ return 0f; } 788 public override void SetLinearDamping(BulletBody pBody, float lin_damping)
789 {
790 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
791 float angularDamping = body.GetAngularDamping();
792 body.SetDamping(lin_damping, angularDamping);
793 }
741 794
742 public override float GetAngularDamping(BulletBody obj) { /* TODO */ return 0f; } 795 public override float GetLinearDamping(BulletBody pBody)
796 {
797 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
798 return body.GetLinearDamping();
799 }
800
801 public override float GetAngularDamping(BulletBody pBody)
802 {
803 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
804 return body.GetAngularDamping();
805 }
743 806
744 public override float GetLinearSleepingThreshold(BulletBody obj) { /* TODO */ return 0f; } 807 public override float GetLinearSleepingThreshold(BulletBody pBody)
808 {
809 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
810 return body.GetLinearSleepingThreshold();
811 }
745 812
746 public override void ApplyDamping(BulletBody obj, float timeStep) { /* TODO */ } 813 public override void ApplyDamping(BulletBody pBody, float timeStep)
814 {
815 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
816 body.ApplyDamping(timeStep);
817 }
747 818
748 public override Vector3 GetLinearFactor(BulletBody obj) { /* TODO */ return Vector3.Zero; } 819 public override Vector3 GetLinearFactor(BulletBody pBody)
820 {
821 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
822 IndexedVector3 linearFactor = body.GetLinearFactor();
823 return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z);
824 }
749 825
750 public override void SetLinearFactor(BulletBody obj, Vector3 factor) { /* TODO */ } 826 public override void SetLinearFactor(BulletBody pBody, Vector3 factor)
827 {
828 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
829 body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z));
830 }
751 831
752 public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) { /* TODO */ } 832 public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot)
833 {
834 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
835 IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W);
836 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat);
837 mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z);
838 body.SetCenterOfMassTransform( ref mat);
839 /* TODO: double check this */
840 }
753 841
754 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); 842 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
755 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) 843 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
756 { 844 {
757 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 845 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
758 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); 846 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
759 body.ApplyCentralForce(ref fSum); 847 body.ApplyCentralForce(ref fSum);
760 } 848 }
761 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) 849 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
762 { 850 {
763 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 851 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
764 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); 852 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
765 body.ApplyCentralImpulse(ref fSum); 853 body.ApplyCentralImpulse(ref fSum);
766 } 854 }
767 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) 855 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
768 { 856 {
769 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 857 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
770 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); 858 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
771 body.ApplyTorque(ref fSum); 859 body.ApplyTorque(ref fSum);
772 } 860 }
773 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) 861 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
774 { 862 {
775 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 863 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
776 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); 864 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
777 body.ApplyTorqueImpulse(ref fSum); 865 body.ApplyTorqueImpulse(ref fSum);
778 } 866 }
779 867
780 public override void DestroyObject(BulletWorld p, BulletBody p_2) 868 public override void DestroyObject(BulletWorld pWorld, BulletBody pBody)
781 { 869 {
782 //TODO: 870 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
871 CollisionObject co = (pBody as BulletBodyXNA).rigidBody;
872 RigidBody bo = co as RigidBody;
873 if (bo == null)
874 {
875
876 if (world.IsInWorld(co))
877 {
878 world.RemoveCollisionObject(co);
879 }
880 }
881 else
882 {
883
884 if (world.IsInWorld(bo))
885 {
886 world.RemoveRigidBody(bo);
887 }
888 }
889
783 } 890 }
784 891
785 public override void Shutdown(BulletWorld pWorld) 892 public override void Shutdown(BulletWorld pWorld)
786 { 893 {
787 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 894 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
788 world.Cleanup(); 895 world.Cleanup();
789 } 896 }
790 897
791 public override BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id) 898 public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id)
792 { 899 {
793 return null; 900 CollisionShape shape1 = (pShape as BulletShapeXNA).shape;
901
902 // TODO: Turn this from a reference copy to a Value Copy.
903 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSPhysicsShapeType.SHAPE_UNKNOWN);
904
905 return shape2;
794 } 906 }
795 907
796 public override bool DeleteCollisionShape(BulletWorld p, BulletShape p_2) 908 public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape)
797 { 909 {
798 //TODO: 910 //TODO:
799 return false; 911 return false;
@@ -802,17 +914,40 @@ private sealed class BulletConstraintXNA : BulletConstraint
802 914
803 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) 915 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
804 { 916 {
805 CollisionWorld world = ((BulletWorldXNA)pWorld).world; 917 CollisionWorld world = (pWorld as BulletWorldXNA).world;
806 IndexedMatrix mat = 918 IndexedMatrix mat =
807 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, 919 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
808 pRawOrientation.Z, pRawOrientation.W)); 920 pRawOrientation.Z, pRawOrientation.W));
809 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); 921 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
810 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 922 CollisionShape shape = (pShape as BulletShapeXNA).shape;
811 //UpdateSingleAabb(world, shape); 923 //UpdateSingleAabb(world, shape);
812 // TODO: Feed Update array into null 924 // TODO: Feed Update array into null
813 RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero); 925 SimMotionState motionState = new SimMotionState(world, pLocalID, mat, null);
814 926 RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero);
927 RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, new SimMotionState(world, pLocalID, mat, null),shape,IndexedVector3.Zero)
928 {
929 m_mass = 0
930 };
931 /*
932 m_mass = mass;
933 m_motionState =motionState;
934 m_collisionShape = collisionShape;
935 m_localInertia = localInertia;
936 m_linearDamping = 0f;
937 m_angularDamping = 0f;
938 m_friction = 0.5f;
939 m_restitution = 0f;
940 m_linearSleepingThreshold = 0.8f;
941 m_angularSleepingThreshold = 1f;
942 m_additionalDamping = false;
943 m_additionalDampingFactor = 0.005f;
944 m_additionalLinearDampingThresholdSqr = 0.01f;
945 m_additionalAngularDampingThresholdSqr = 0.01f;
946 m_additionalAngularDampingFactor = 0.01f;
947 m_startWorldTransform = IndexedMatrix.Identity;
948 */
815 body.SetUserPointer(pLocalID); 949 body.SetUserPointer(pLocalID);
950
816 return new BulletBodyXNA(pLocalID, body); 951 return new BulletBodyXNA(pLocalID, body);
817 } 952 }
818 953
@@ -825,7 +960,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
825 pRawOrientation.Z, pRawOrientation.W)); 960 pRawOrientation.Z, pRawOrientation.W));
826 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); 961 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
827 962
828 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 963 CollisionShape shape = (pShape as BulletShapeXNA).shape;
829 964
830 // TODO: Feed Update array into null 965 // TODO: Feed Update array into null
831 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); 966 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
@@ -834,21 +969,43 @@ private sealed class BulletConstraintXNA : BulletConstraint
834 return new BulletBodyXNA(pLocalID, body); 969 return new BulletBodyXNA(pLocalID, body);
835 } 970 }
836 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 971 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
837 public override CollisionFlags SetCollisionFlags(BulletBody pBody, CollisionFlags collisionFlags) 972 public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags)
838 { 973 {
839 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 974 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
840 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); 975 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
841 return (CollisionFlags)body.GetCollisionFlags(); 976 return (CollisionFlags)collisionObject.GetCollisionFlags();
842 } 977 }
843 978
844 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return Vector3.Zero; } 979 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
980 {
981
982 /* TODO */
983 return Vector3.Zero;
984 }
845 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } 985 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
846 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } 986 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
847 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } 987 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
848 public override bool IsStaticObject(BulletBody pBody) { /* TODO */ return false; } 988 public override bool IsStaticObject(BulletBody pCollisionObject)
849 public override bool IsKinematicObject(BulletBody pBody) { /* TODO */ return false; } 989 {
850 public override bool IsStaticOrKinematicObject(BulletBody pBody) { /* TODO */ return false; } 990 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
851 public override bool HasContactResponse(BulletBody pBody) { /* TODO */ return false; } 991 return collisionObject.IsStaticObject();
992
993 }
994 public override bool IsKinematicObject(BulletBody pCollisionObject)
995 {
996 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
997 return collisionObject.IsKinematicObject();
998 }
999 public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject)
1000 {
1001 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1002 return collisionObject.IsStaticOrKinematicObject();
1003 }
1004 public override bool HasContactResponse(BulletBody pCollisionObject)
1005 {
1006 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1007 return collisionObject.HasContactResponse();
1008 }
852 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } 1009 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
853 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } 1010 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
854 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } 1011 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
@@ -859,15 +1016,15 @@ private sealed class BulletConstraintXNA : BulletConstraint
859 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } 1016 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
860 1017
861 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); 1018 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
862 public override void SetHitFraction(BulletBody pBody, float pHitFraction) 1019 public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction)
863 { 1020 {
864 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 1021 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
865 body.SetHitFraction(pHitFraction); 1022 collisionObject.SetHitFraction(pHitFraction);
866 } 1023 }
867 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); 1024 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
868 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) 1025 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
869 { 1026 {
870 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1027 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
871 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); 1028 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
872 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); 1029 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
873 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); 1030 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
@@ -881,14 +1038,24 @@ private sealed class BulletConstraintXNA : BulletConstraint
881 int maxUpdates, ref EntityProperties[] updateArray 1038 int maxUpdates, ref EntityProperties[] updateArray
882 ) 1039 )
883 { 1040 {
1041
1042 m_updateArray = updateArray;
1043 m_collisionArray = collisionArray;
884 /* TODO */ 1044 /* TODO */
885 return new BulletWorldXNA(1, null, null); 1045 ConfigurationParameters[] configparms = new ConfigurationParameters[1];
1046 configparms[0] = parms;
1047 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
1048 m_maxCollisions = maxCollisions;
1049 m_maxUpdatesPerFrame = maxUpdates;
1050
1051
1052 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
886 } 1053 }
887 1054
888 private static object Initialize2(Vector3 worldExtent, 1055 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
889 ConfigurationParameters[] o, 1056 ConfigurationParameters[] o,
890 int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray, 1057 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
891 int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray, 1058 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
892 object mDebugLogCallbackHandle) 1059 object mDebugLogCallbackHandle)
893 { 1060 {
894 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); 1061 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
@@ -968,8 +1135,13 @@ private sealed class BulletConstraintXNA : BulletConstraint
968 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); 1135 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
969 1136
970 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); 1137 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
971 world.UpdatedObjects = updateArray; 1138
972 world.UpdatedCollisions = collisionArray; 1139
1140 world.UpdatedObjects = BSAPIXNA.GetBulletXNAEntityStruct(BSAPIXNA.BulletSimEntityStructToByteArray(updateArray, updateArray.Length));
1141 world.UpdatedCollisions = BSAPIXNA.GetBulletXNACollisionStruct(BSAPIXNA.BulletSimCollisionStructToByteArray(collisionArray, collisionArray.Length));
1142 world.LastCollisionDesc = 0;
1143 world.LastEntityProperty = 0;
1144
973 world.WorldSettings.Params = p; 1145 world.WorldSettings.Params = p;
974 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); 1146 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
975 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; 1147 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
@@ -1003,7 +1175,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1003 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; 1175 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1004 world.SetForceUpdateAllAabbs(true); 1176 world.SetForceUpdateAllAabbs(true);
1005 1177
1006 1178 //BSParam.TerrainImplementation = 0;
1007 world.SetGravity(new IndexedVector3(0,0,p.gravity)); 1179 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1008 1180
1009 return world; 1181 return world;
@@ -1011,7 +1183,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1011 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL 1183 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1012 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) 1184 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1013 { 1185 {
1014 Generic6DofConstraint constrain = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; 1186 Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
1015 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) 1187 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1016 { 1188 {
1017 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); 1189 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
@@ -1034,7 +1206,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
1034 public override bool PushUpdate(BulletBody pCollisionObject) 1206 public override bool PushUpdate(BulletBody pCollisionObject)
1035 { 1207 {
1036 bool ret = false; 1208 bool ret = false;
1037 RigidBody rb = ((BulletBodyXNA)pCollisionObject).rigidBody; 1209 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1210 RigidBody rb = collisionObject as RigidBody;
1038 if (rb != null) 1211 if (rb != null)
1039 { 1212 {
1040 SimMotionState sms = rb.GetMotionState() as SimMotionState; 1213 SimMotionState sms = rb.GetMotionState() as SimMotionState;
@@ -1052,57 +1225,57 @@ private sealed class BulletConstraintXNA : BulletConstraint
1052 1225
1053 public override float GetAngularMotionDisc(BulletShape pShape) 1226 public override float GetAngularMotionDisc(BulletShape pShape)
1054 { 1227 {
1055 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1228 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1056 return shape.GetAngularMotionDisc(); 1229 return shape.GetAngularMotionDisc();
1057 } 1230 }
1058 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) 1231 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1059 { 1232 {
1060 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1233 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1061 return shape.GetContactBreakingThreshold(defaultFactor); 1234 return shape.GetContactBreakingThreshold(defaultFactor);
1062 } 1235 }
1063 public override bool IsCompound(BulletShape pShape) 1236 public override bool IsCompound(BulletShape pShape)
1064 { 1237 {
1065 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1238 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1066 return shape.IsCompound(); 1239 return shape.IsCompound();
1067 } 1240 }
1068 public override bool IsSoftBody(BulletShape pShape) 1241 public override bool IsSoftBody(BulletShape pShape)
1069 { 1242 {
1070 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1243 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1071 return shape.IsSoftBody(); 1244 return shape.IsSoftBody();
1072 } 1245 }
1073 public override bool IsPolyhedral(BulletShape pShape) 1246 public override bool IsPolyhedral(BulletShape pShape)
1074 { 1247 {
1075 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1248 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1076 return shape.IsPolyhedral(); 1249 return shape.IsPolyhedral();
1077 } 1250 }
1078 public override bool IsConvex2d(BulletShape pShape) 1251 public override bool IsConvex2d(BulletShape pShape)
1079 { 1252 {
1080 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1253 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1081 return shape.IsConvex2d(); 1254 return shape.IsConvex2d();
1082 } 1255 }
1083 public override bool IsConvex(BulletShape pShape) 1256 public override bool IsConvex(BulletShape pShape)
1084 { 1257 {
1085 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1258 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1086 return shape.IsConvex(); 1259 return shape.IsConvex();
1087 } 1260 }
1088 public override bool IsNonMoving(BulletShape pShape) 1261 public override bool IsNonMoving(BulletShape pShape)
1089 { 1262 {
1090 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1263 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1091 return shape.IsNonMoving(); 1264 return shape.IsNonMoving();
1092 } 1265 }
1093 public override bool IsConcave(BulletShape pShape) 1266 public override bool IsConcave(BulletShape pShape)
1094 { 1267 {
1095 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1268 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1096 return shape.IsConcave(); 1269 return shape.IsConcave();
1097 } 1270 }
1098 public override bool IsInfinite(BulletShape pShape) 1271 public override bool IsInfinite(BulletShape pShape)
1099 { 1272 {
1100 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1273 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1101 return shape.IsInfinite(); 1274 return shape.IsInfinite();
1102 } 1275 }
1103 public override bool IsNativeShape(BulletShape pShape) 1276 public override bool IsNativeShape(BulletShape pShape)
1104 { 1277 {
1105 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1278 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1106 bool ret; 1279 bool ret;
1107 switch (shape.GetShapeType()) 1280 switch (shape.GetShapeType())
1108 { 1281 {
@@ -1119,38 +1292,53 @@ private sealed class BulletConstraintXNA : BulletConstraint
1119 return ret; 1292 return ret;
1120 } 1293 }
1121 1294
1122 public override void SetShapeCollisionMargin(BulletShape shape, float margin) { /* TODO */ } 1295 public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin)
1296 {
1297 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1298 shape.SetMargin(pMargin);
1299 }
1123 1300
1124 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation 1301 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1125 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) 1302 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1126 { 1303 {
1127 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1304 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1128 IndexedMatrix bodyTransform = new IndexedMatrix(); 1305 IndexedMatrix bodyTransform = new IndexedMatrix();
1129 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); 1306 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1130 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); 1307 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1131 GhostObject gObj = new PairCachingGhostObject(); 1308 GhostObject gObj = new PairCachingGhostObject();
1132 gObj.SetWorldTransform(bodyTransform); 1309 gObj.SetWorldTransform(bodyTransform);
1133 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1310 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1134 gObj.SetCollisionShape(shape); 1311 gObj.SetCollisionShape(shape);
1135 gObj.SetUserPointer(pLocalID); 1312 gObj.SetUserPointer(pLocalID);
1136 // TODO: Add to Special CollisionObjects! 1313 // TODO: Add to Special CollisionObjects!
1137 return new BulletBodyXNA(pLocalID, gObj); 1314 return new BulletBodyXNA(pLocalID, gObj);
1138 } 1315 }
1139 1316
1140 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pObj, BulletShape pShape) 1317 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape)
1141 { 1318 {
1142 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1319 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1143 CollisionObject obj = ((BulletBodyXNA)pObj).body; 1320 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1144 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1321 if (pShape == null)
1145 obj.SetCollisionShape(shape); 1322 {
1146 1323 collisionObject.SetCollisionShape(new EmptyShape());
1324 }
1325 else
1326 {
1327 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1328 collisionObject.SetCollisionShape(shape);
1329 }
1330 }
1331 public override BulletShape GetCollisionShape(BulletBody pCollisionObject)
1332 {
1333 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1334 CollisionShape shape = collisionObject.GetCollisionShape();
1335 return new BulletShapeXNA(shape,BSPhysicsShapeType.SHAPE_UNKNOWN);
1147 } 1336 }
1148 public override BulletShape GetCollisionShape(BulletBody obj) { /* TODO */ return null; }
1149 1337
1150 //(PhysicsScene.World.ptr, nativeShapeData) 1338 //(PhysicsScene.World.ptr, nativeShapeData)
1151 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) 1339 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1152 { 1340 {
1153 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1341 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1154 CollisionShape shape = null; 1342 CollisionShape shape = null;
1155 switch (pShapeData.Type) 1343 switch (pShapeData.Type)
1156 { 1344 {
@@ -1185,15 +1373,15 @@ private sealed class BulletConstraintXNA : BulletConstraint
1185 1373
1186 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) 1374 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1187 { 1375 {
1188 CompoundShape compoundshape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape; 1376 CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
1189 return compoundshape.GetNumChildShapes(); 1377 return compoundshape.GetNumChildShapes();
1190 } 1378 }
1191 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot 1379 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1192 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) 1380 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1193 { 1381 {
1194 IndexedMatrix relativeTransform = new IndexedMatrix(); 1382 IndexedMatrix relativeTransform = new IndexedMatrix();
1195 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape; 1383 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1196 CollisionShape addshape = ((BulletShapeXNA)paddShape).shape; 1384 CollisionShape addshape = (paddShape as BulletShapeXNA).shape;
1197 1385
1198 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); 1386 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1199 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); 1387 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
@@ -1203,7 +1391,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1203 1391
1204 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) 1392 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1205 { 1393 {
1206 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape; 1394 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1207 CollisionShape ret = null; 1395 CollisionShape ret = null;
1208 ret = compoundshape.GetChildShape(pii); 1396 ret = compoundshape.GetChildShape(pii);
1209 compoundshape.RemoveChildShapeByIndex(pii); 1397 compoundshape.RemoveChildShapeByIndex(pii);
@@ -1222,12 +1410,12 @@ private sealed class BulletConstraintXNA : BulletConstraint
1222 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); 1410 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1223 } 1411 }
1224 1412
1225 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) 1413 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1226 { 1414 {
1227 HingeConstraint constrain = null; 1415 HingeConstraint constrain = null;
1228 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1416 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1229 RigidBody rb1 = ((BulletBodyXNA)pBody1).rigidBody; 1417 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1230 RigidBody rb2 = ((BulletBodyXNA)ppBody2).rigidBody; 1418 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1231 if (rb1 != null && rb2 != null) 1419 if (rb1 != null && rb2 != null)
1232 { 1420 {
1233 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); 1421 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
@@ -1241,7 +1429,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1241 1429
1242 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) 1430 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
1243 { 1431 {
1244 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1432 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1245 CompoundShape compoundshape = new CompoundShape(false); 1433 CompoundShape compoundshape = new CompoundShape(false);
1246 1434
1247 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); 1435 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
@@ -1271,7 +1459,11 @@ private sealed class BulletConstraintXNA : BulletConstraint
1271 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); 1459 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1272 } 1460 }
1273 1461
1274 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) { /* TODO */ return null; } 1462 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
1463 {
1464 /* TODO */ return null;
1465
1466 }
1275 1467
1276 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) 1468 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1277 { 1469 {
@@ -1286,7 +1478,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1286 ObjectArray<int> indicesarr = new ObjectArray<int>(indices); 1478 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1287 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); 1479 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1288 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); 1480 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1289 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1481 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1290 IndexedMesh mesh = new IndexedMesh(); 1482 IndexedMesh mesh = new IndexedMesh();
1291 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; 1483 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1292 mesh.m_numTriangles = pIndicesCount/3; 1484 mesh.m_numTriangles = pIndicesCount/3;
@@ -1402,7 +1594,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1402 1594
1403 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) 1595 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1404 { 1596 {
1405 TypedConstraint tconstrain = ((BulletConstraintXNA)pConstraint).constrain; 1597 TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain;
1406 bool onOff = ponOff != 0; 1598 bool onOff = ponOff != 0;
1407 bool ret = false; 1599 bool ret = false;
1408 1600
@@ -1428,47 +1620,45 @@ private sealed class BulletConstraintXNA : BulletConstraint
1428 /* TODO */ 1620 /* TODO */
1429 updatedEntityCount = 0; 1621 updatedEntityCount = 0;
1430 collidersCount = 0; 1622 collidersCount = 0;
1431 return 1; 1623
1624
1625 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
1626
1627 return ret;
1432 } 1628 }
1433 1629
1434 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, 1630 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1435 out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, 1631 out int updatedEntityCount, out EntityProperties[] updatedEntities,
1436 out int collidersCount, out List<BulletXNA.CollisionDesc>colliders) 1632 out int collidersCount, out CollisionDesc[] colliders)
1437 { 1633 {
1438 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, 1634 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1439 out collidersCount, out colliders); 1635 out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame);
1440 return epic; 1636 return epic;
1441 } 1637 }
1442 1638
1443 private static int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc> colliders) 1639 private static int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
1640 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
1444 { 1641 {
1445 int numSimSteps = 0; 1642 int numSimSteps = 0;
1446
1447 1643
1448 //if (updatedEntities is null) 1644 updatedEntityCount = 0;
1449 // updatedEntities = new List<BulletXNA.EntityProperties>(); 1645 collidersCount = 0;
1450
1451 //if (colliders is null)
1452 // colliders = new List<BulletXNA.CollisionDesc>();
1453 1646
1454 1647
1455 if (pWorld is BulletWorldXNA) 1648 if (pWorld is BulletWorldXNA)
1456 { 1649 {
1457 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1650 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1458 1651
1652 world.LastCollisionDesc = 0;
1653 world.LastEntityProperty = 0;
1654 world.UpdatedObjects = new BulletXNA.EntityProperties[maxUpdates];
1655 world.UpdatedCollisions = new BulletXNA.CollisionDesc[maxCollisions];
1459 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); 1656 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1460 int updates = 0; 1657 int updates = 0;
1461 1658
1462 updatedEntityCount = world.UpdatedObjects.Count; 1659
1463 updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects);
1464 updatedEntityCount = updatedEntities.Count;
1465 world.UpdatedObjects.Clear();
1466 1660
1467 1661
1468 collidersCount = world.UpdatedCollisions.Count;
1469 colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions);
1470
1471 world.UpdatedCollisions.Clear();
1472 m_collisionsThisFrame = 0; 1662 m_collisionsThisFrame = 0;
1473 int numManifolds = world.GetDispatcher().GetNumManifolds(); 1663 int numManifolds = world.GetDispatcher().GetNumManifolds();
1474 for (int j = 0; j < numManifolds; j++) 1664 for (int j = 0; j < numManifolds; j++)
@@ -1493,16 +1683,31 @@ private sealed class BulletConstraintXNA : BulletConstraint
1493 1683
1494 } 1684 }
1495 1685
1686 updatedEntityCount = world.LastEntityProperty;
1687 updatedEntities = GetBulletSimEntityStruct(BulletXNAEntityStructToByteArray(world.UpdatedObjects, world.LastEntityProperty));
1688
1689
1690
1691
1692 collidersCount = world.LastCollisionDesc;
1693 colliders =
1694 GetBulletSimCollisionStruct(BulletXNACollisionStructToByteArray(world.UpdatedCollisions, world.LastCollisionDesc));//new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions);
1496 1695
1497 } 1696 }
1498 else 1697 else
1499 { 1698 {
1500 //if (updatedEntities is null) 1699 //if (updatedEntities is null)
1501 updatedEntities = new List<BulletXNA.EntityProperties>(); 1700 //updatedEntities = new List<BulletXNA.EntityProperties>();
1502 updatedEntityCount = 0; 1701 //updatedEntityCount = 0;
1503 //if (colliders is null) 1702 //if (colliders is null)
1504 colliders = new List<BulletXNA.CollisionDesc>(); 1703 //colliders = new List<BulletXNA.CollisionDesc>();
1505 collidersCount = 0; 1704 //collidersCount = 0;
1705
1706 updatedEntities = new EntityProperties[0];
1707
1708
1709 colliders = new CollisionDesc[0];
1710
1506 } 1711 }
1507 return numSimSteps; 1712 return numSimSteps;
1508 } 1713 }
@@ -1535,22 +1740,23 @@ private sealed class BulletConstraintXNA : BulletConstraint
1535 point = contact, 1740 point = contact,
1536 normal = contactNormal 1741 normal = contactNormal
1537 }; 1742 };
1538 world.UpdatedCollisions.Add(cDesc); 1743 if (world.LastCollisionDesc < world.UpdatedCollisions.Length)
1744 world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc);
1539 m_collisionsThisFrame++; 1745 m_collisionsThisFrame++;
1540 1746
1541 1747
1542 } 1748 }
1543 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pBody) 1749 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject)
1544 { 1750 {
1545 EntityProperties ent = new EntityProperties(); 1751 EntityProperties ent = new EntityProperties();
1546 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1752 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1547 RigidBody body = ((BulletBodyXNA)pBody).rigidBody; 1753 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1548 IndexedMatrix transform = body.GetWorldTransform(); 1754 IndexedMatrix transform = collisionObject.GetWorldTransform();
1549 IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity(); 1755 IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity();
1550 IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity(); 1756 IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity();
1551 IndexedQuaternion rotation = transform.GetRotation(); 1757 IndexedQuaternion rotation = transform.GetRotation();
1552 ent.Acceleration = Vector3.Zero; 1758 ent.Acceleration = Vector3.Zero;
1553 ent.ID = (uint)body.GetUserPointer(); 1759 ent.ID = (uint)collisionObject.GetUserPointer();
1554 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); 1760 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
1555 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); 1761 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
1556 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); 1762 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
@@ -1562,19 +1768,19 @@ private sealed class BulletConstraintXNA : BulletConstraint
1562 1768
1563 public override Vector3 GetLocalScaling(BulletShape pShape) 1769 public override Vector3 GetLocalScaling(BulletShape pShape)
1564 { 1770 {
1565 CollisionShape shape = ((BulletShapeXNA)pShape).shape; 1771 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1566 IndexedVector3 scale = shape.GetLocalScaling(); 1772 IndexedVector3 scale = shape.GetLocalScaling();
1567 return new Vector3(scale.X,scale.Y,scale.Z); 1773 return new Vector3(scale.X,scale.Y,scale.Z);
1568 } 1774 }
1569 1775
1570 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) 1776 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
1571 { 1777 {
1572 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; 1778 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1573 if (world != null) 1779 if (world != null)
1574 { 1780 {
1575 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) 1781 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
1576 { 1782 {
1577 CollisionObject AvoidBody = ((BulletBodyXNA)NotMe).body; 1783 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
1578 1784
1579 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); 1785 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
1580 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); 1786 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
@@ -1594,5 +1800,160 @@ private sealed class BulletConstraintXNA : BulletConstraint
1594 } 1800 }
1595 return false; 1801 return false;
1596 } 1802 }
1803
1804 public static unsafe BulletXNA.CollisionDesc[] GetBulletXNACollisionStruct(byte[] buffer)
1805 {
1806 int count = buffer.Length/sizeof (BulletXNA.CollisionDesc);
1807 BulletXNA.CollisionDesc[] result = new BulletXNA.CollisionDesc[count];
1808 BulletXNA.CollisionDesc* ptr;
1809 fixed (byte* localBytes = new byte[buffer.Length])
1810 {
1811 for (int i = 0; i < buffer.Length; i++)
1812 {
1813 localBytes[i] = buffer[i];
1814 }
1815 for (int i=0;i<count;i++)
1816 {
1817 ptr = (BulletXNA.CollisionDesc*) (localBytes + sizeof (BulletXNA.CollisionDesc)*i);
1818 result[i] = new BulletXNA.CollisionDesc();
1819 result[i] = *ptr;
1820 }
1821 }
1822 return result;
1823 }
1824
1825 public static unsafe CollisionDesc[] GetBulletSimCollisionStruct(byte[] buffer)
1826 {
1827 int count = buffer.Length / sizeof(CollisionDesc);
1828 CollisionDesc[] result = new CollisionDesc[count];
1829 CollisionDesc* ptr;
1830 fixed (byte* localBytes = new byte[buffer.Length])
1831 {
1832 for (int i = 0; i < buffer.Length; i++)
1833 {
1834 localBytes[i] = buffer[i];
1835 }
1836 for (int i = 0; i < count; i++)
1837 {
1838 ptr = (CollisionDesc*)(localBytes + sizeof(CollisionDesc) * i);
1839 result[i] = new CollisionDesc();
1840 result[i] = *ptr;
1841 }
1842 }
1843 return result;
1844 }
1845 public static unsafe byte[] BulletSimCollisionStructToByteArray(CollisionDesc[] CollisionDescArray, int count)
1846 {
1847 int arrayLength = CollisionDescArray.Length > count ? count : CollisionDescArray.Length;
1848 byte[] byteArray = new byte[sizeof(CollisionDesc) * arrayLength];
1849 fixed (CollisionDesc* floatPointer = CollisionDescArray)
1850 {
1851 fixed (byte* bytePointer = byteArray)
1852 {
1853 CollisionDesc* read = floatPointer;
1854 CollisionDesc* write = (CollisionDesc*)bytePointer;
1855 for (int i = 0; i < arrayLength; i++)
1856 {
1857 *write++ = *read++;
1858 }
1859 }
1860 }
1861 return byteArray;
1862 }
1863 public static unsafe byte[] BulletXNACollisionStructToByteArray(BulletXNA.CollisionDesc[] CollisionDescArray, int count)
1864 {
1865 int arrayLength = CollisionDescArray.Length > count ? count : CollisionDescArray.Length;
1866 byte[] byteArray = new byte[sizeof(BulletXNA.CollisionDesc) * arrayLength];
1867 fixed (BulletXNA.CollisionDesc* floatPointer = CollisionDescArray)
1868 {
1869 fixed (byte* bytePointer = byteArray)
1870 {
1871 BulletXNA.CollisionDesc* read = floatPointer;
1872 BulletXNA.CollisionDesc* write = (BulletXNA.CollisionDesc*)bytePointer;
1873 for (int i = 0; i < arrayLength; i++)
1874 {
1875 *write++ = *read++;
1876 }
1877 }
1878 }
1879 return byteArray;
1880 }
1881 public static unsafe BulletXNA.EntityProperties[] GetBulletXNAEntityStruct(byte[] buffer)
1882 {
1883 int count = buffer.Length / sizeof(BulletXNA.EntityProperties);
1884 BulletXNA.EntityProperties[] result = new BulletXNA.EntityProperties[count];
1885 BulletXNA.EntityProperties* ptr;
1886 fixed (byte* localBytes = new byte[buffer.Length])
1887 {
1888 for (int i = 0; i < buffer.Length; i++)
1889 {
1890 localBytes[i] = buffer[i];
1891 }
1892 for (int i = 0; i < count; i++)
1893 {
1894 ptr = (BulletXNA.EntityProperties*)(localBytes + sizeof(BulletXNA.EntityProperties) * i);
1895 result[i] = new BulletXNA.EntityProperties();
1896 result[i] = *ptr;
1897 }
1898 }
1899 return result;
1900 }
1901
1902 public static unsafe EntityProperties[] GetBulletSimEntityStruct(byte[] buffer)
1903 {
1904 int count = buffer.Length / sizeof(EntityProperties);
1905 EntityProperties[] result = new EntityProperties[count];
1906 EntityProperties* ptr;
1907 fixed (byte* localBytes = new byte[buffer.Length])
1908 {
1909 for (int i = 0; i < buffer.Length; i++)
1910 {
1911 localBytes[i] = buffer[i];
1912 }
1913 for (int i = 0; i < count; i++)
1914 {
1915 ptr = (EntityProperties*)(localBytes + sizeof(EntityProperties) * i);
1916 result[i] = new EntityProperties();
1917 result[i] = *ptr;
1918 }
1919 }
1920 return result;
1921 }
1922 public static unsafe byte[] BulletSimEntityStructToByteArray(EntityProperties[] CollisionDescArray, int count)
1923 {
1924 int arrayLength = CollisionDescArray.Length > count ? count : CollisionDescArray.Length;
1925 byte[] byteArray = new byte[sizeof(EntityProperties) * arrayLength];
1926 fixed (EntityProperties* floatPointer = CollisionDescArray)
1927 {
1928 fixed (byte* bytePointer = byteArray)
1929 {
1930 EntityProperties* read = floatPointer;
1931 EntityProperties* write = (EntityProperties*)bytePointer;
1932 for (int i = 0; i < arrayLength; i++)
1933 {
1934 *write++ = *read++;
1935 }
1936 }
1937 }
1938 return byteArray;
1939 }
1940 public static unsafe byte[] BulletXNAEntityStructToByteArray(BulletXNA.EntityProperties[] CollisionDescArray, int count)
1941 {
1942 int arrayLength = CollisionDescArray.Length > count ? count : CollisionDescArray.Length;
1943 byte[] byteArray = new byte[sizeof(BulletXNA.EntityProperties) * arrayLength];
1944 fixed (BulletXNA.EntityProperties* floatPointer = CollisionDescArray)
1945 {
1946 fixed (byte* bytePointer = byteArray)
1947 {
1948 BulletXNA.EntityProperties* read = floatPointer;
1949 BulletXNA.EntityProperties* write = (BulletXNA.EntityProperties*)bytePointer;
1950 for (int i = 0; i < arrayLength; i++)
1951 {
1952 *write++ = *read++;
1953 }
1954 }
1955 }
1956 return byteArray;
1957 }
1597} 1958}
1598} 1959}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
index bc163eb..2828cab 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -140,6 +140,25 @@ public struct EntityProperties
140 public Vector3 Velocity; 140 public Vector3 Velocity;
141 public Vector3 Acceleration; 141 public Vector3 Acceleration;
142 public Vector3 RotationalVelocity; 142 public Vector3 RotationalVelocity;
143
144 public override string ToString()
145 {
146 StringBuilder buff = new StringBuilder();
147 buff.Append("<i=");
148 buff.Append(ID.ToString());
149 buff.Append(",p=");
150 buff.Append(Position.ToString());
151 buff.Append(",r=");
152 buff.Append(Rotation.ToString());
153 buff.Append(",v=");
154 buff.Append(Velocity.ToString());
155 buff.Append(",a=");
156 buff.Append(Acceleration.ToString());
157 buff.Append(",rv=");
158 buff.Append(RotationalVelocity.ToString());
159 buff.Append(">");
160 return buff.ToString();
161 }
143} 162}
144 163
145// Format of this structure must match the definition in the C++ code 164// Format of this structure must match the definition in the C++ code
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 478aeab..7603254 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -56,6 +56,7 @@ public sealed class BSCharacter : BSPhysObject
56 private int _physicsActorType; 56 private int _physicsActorType;
57 private bool _isPhysical; 57 private bool _isPhysical;
58 private bool _flying; 58 private bool _flying;
59 private bool _wasWalking; // 'true' if the avatar was walking/moving last frame
59 private bool _setAlwaysRun; 60 private bool _setAlwaysRun;
60 private bool _throttleUpdates; 61 private bool _throttleUpdates;
61 private bool _floatOnWater; 62 private bool _floatOnWater;
@@ -83,6 +84,7 @@ public sealed class BSCharacter : BSPhysObject
83 _position = pos; 84 _position = pos;
84 85
85 _flying = isFlying; 86 _flying = isFlying;
87 _wasWalking = true; // causes first step to initialize standing
86 _orientation = OMV.Quaternion.Identity; 88 _orientation = OMV.Quaternion.Identity;
87 _velocity = OMV.Vector3.Zero; 89 _velocity = OMV.Vector3.Zero;
88 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 90 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
@@ -198,25 +200,68 @@ public sealed class BSCharacter : BSPhysObject
198 // TODO: Decide if the step parameters should be changed depending on the avatar's 200 // TODO: Decide if the step parameters should be changed depending on the avatar's
199 // state (flying, colliding, ...). There is code in ODE to do this. 201 // state (flying, colliding, ...). There is code in ODE to do this.
200 202
201 OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep); 203 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
202 204 // specified for the avatar is the one that should be used. For falling, if the avatar
203 // If falling, we keep the world's downward vector no matter what the other axis specify. 205 // is not flying and is not colliding then it is presumed to be falling and the Z
204 if (!Flying && !IsColliding) 206 // component is not fooled with (thus allowing gravity to do its thing).
207 // When the avatar is standing, though, the user has specified a velocity of zero and
208 // the avatar should be standing. But if the avatar is pushed by something in the world
209 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
210 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
211 // errors can creap in and the avatar will slowly float off in some direction.
212 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
213 // from real pushing.OMV.Vector3.Zero;
214 // The code below keeps setting the velocity to zero hoping the world will keep pushing.
215
216 _velocityMotor.Step(timeStep);
217
218 // If we're not supposed to be moving, make sure things are zero.
219 if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero && IsColliding)
205 { 220 {
206 stepVelocity.Z = _velocity.Z; 221 // The avatar shouldn't be moving
207 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); 222 _velocityMotor.Zero();
223 ZeroMotion(true /* inTaintTime */);
224
225 // Standing has more friction on the ground
226 if (_currentFriction != BSParam.AvatarStandingFriction)
227 {
228 _currentFriction = BSParam.AvatarStandingFriction;
229 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
230 }
231 DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1}", LocalID, _velocityMotor.TargetValue);
232
233 _wasWalking = false;
208 } 234 }
235 else
236 {
237 OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
238
239 if (_currentFriction != BSParam.AvatarFriction)
240 {
241 // Probably starting up walking. Set friction to moving friction.
242 _currentFriction = BSParam.AvatarFriction;
243 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
244 }
245
246 // If falling, we keep the world's downward vector no matter what the other axis specify.
247 if (!Flying && !IsColliding)
248 {
249 stepVelocity.Z = _velocity.Z;
250 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
251 }
209 252
210 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. 253 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
211 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass; 254 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
212 255
213 // Should we check for move force being small and forcing velocity to zero? 256 // Should we check for move force being small and forcing velocity to zero?
214 257
215 // Add special movement force to allow avatars to walk up stepped surfaces. 258 // Add special movement force to allow avatars to walk up stepped surfaces.
216 moveForce += WalkUpStairs(); 259 moveForce += WalkUpStairs();
217 260
218 // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); 261 DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
219 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce); 262 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
263 _wasWalking = true;
264 }
220 }); 265 });
221 } 266 }
222 267
@@ -559,27 +604,6 @@ public sealed class BSCharacter : BSPhysObject
559 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); 604 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
560 605
561 _velocity = value; 606 _velocity = value;
562 // Depending on whether the avatar is moving or not, change the friction
563 // to keep the avatar from slipping around
564 if (_velocity.Length() == 0)
565 {
566 if (_currentFriction != BSParam.AvatarStandingFriction)
567 {
568 _currentFriction = BSParam.AvatarStandingFriction;
569 if (PhysBody.HasPhysicalBody)
570 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
571 }
572 }
573 else
574 {
575 if (_currentFriction != BSParam.AvatarFriction)
576 {
577 _currentFriction = BSParam.AvatarFriction;
578 if (PhysBody.HasPhysicalBody)
579 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
580 }
581 }
582
583 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); 607 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
584 PhysicsScene.PE.Activate(PhysBody, true); 608 PhysicsScene.PE.Activate(PhysBody, true);
585 } 609 }
@@ -854,7 +878,7 @@ public sealed class BSCharacter : BSPhysObject
854 _position = entprop.Position; 878 _position = entprop.Position;
855 _orientation = entprop.Rotation; 879 _orientation = entprop.Rotation;
856 880
857 // Smooth velocity. OpenSimulator is very sensitive to changes in velocity of the avatar 881 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
858 // and will send agent updates to the clients if velocity changes by more than 882 // and will send agent updates to the clients if velocity changes by more than
859 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many 883 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
860 // extra updates. 884 // extra updates.
@@ -875,7 +899,7 @@ public sealed class BSCharacter : BSPhysObject
875 CurrentEntityProperties = entprop; 899 CurrentEntityProperties = entprop;
876 900
877 // Tell the linkset about value changes 901 // Tell the linkset about value changes
878 Linkset.UpdateProperties(this, true); 902 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
879 903
880 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 904 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
881 // base.RequestPhysicsterseUpdate(); 905 // base.RequestPhysicsterseUpdate();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index f2c7cec..fe7891e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -231,6 +231,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
231 break; 231 break;
232 case Vehicle.ANGULAR_MOTOR_DIRECTION: 232 case Vehicle.ANGULAR_MOTOR_DIRECTION:
233 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 233 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
234 m_angularMotor.Zero();
234 m_angularMotor.SetTarget(m_angularMotorDirection); 235 m_angularMotor.SetTarget(m_angularMotorDirection);
235 break; 236 break;
236 case Vehicle.LINEAR_FRICTION_TIMESCALE: 237 case Vehicle.LINEAR_FRICTION_TIMESCALE:
@@ -264,6 +265,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
264 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); 265 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
265 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); 266 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
266 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 267 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
268 m_angularMotor.Zero();
267 m_angularMotor.SetTarget(m_angularMotorDirection); 269 m_angularMotor.SetTarget(m_angularMotorDirection);
268 break; 270 break;
269 case Vehicle.LINEAR_FRICTION_TIMESCALE: 271 case Vehicle.LINEAR_FRICTION_TIMESCALE:
@@ -688,7 +690,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
688 // Bullet does a bunch of smoothing for changing parameters. 690 // Bullet does a bunch of smoothing for changing parameters.
689 // Since the vehicle is demanding this setting, we override Bullet's smoothing 691 // Since the vehicle is demanding this setting, we override Bullet's smoothing
690 // by telling Bullet the value was the same last time. 692 // by telling Bullet the value was the same last time.
691 PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity); 693 // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
692 } 694 }
693 695
694 if ((m_knownChanged & m_knownChangedForce) != 0) 696 if ((m_knownChanged & m_knownChangedForce) != 0)
@@ -700,7 +702,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
700 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) 702 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
701 { 703 {
702 Prim.ForceRotationalVelocity = m_knownRotationalVelocity; 704 Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
703 PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); 705 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
704 } 706 }
705 707
706 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) 708 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
@@ -720,10 +722,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
720 722
721 // Since the computation of terrain height can be a little involved, this routine 723 // Since the computation of terrain height can be a little involved, this routine
722 // is used to fetch the height only once for each vehicle simulation step. 724 // is used to fetch the height only once for each vehicle simulation step.
725 Vector3 lastRememberedHeightPos;
723 private float GetTerrainHeight(Vector3 pos) 726 private float GetTerrainHeight(Vector3 pos)
724 { 727 {
725 if ((m_knownHas & m_knownChangedTerrainHeight) == 0) 728 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
726 { 729 {
730 lastRememberedHeightPos = pos;
727 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 731 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
728 m_knownHas |= m_knownChangedTerrainHeight; 732 m_knownHas |= m_knownChangedTerrainHeight;
729 } 733 }
@@ -943,10 +947,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
943 // ================================================================== 947 // ==================================================================
944 // Clamp high or low velocities 948 // Clamp high or low velocities
945 float newVelocityLengthSq = VehicleVelocity.LengthSquared(); 949 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
946 if (newVelocityLengthSq > 1000f) 950 if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocity)
947 { 951 {
948 VehicleVelocity /= VehicleVelocity.Length(); 952 VehicleVelocity /= VehicleVelocity.Length();
949 VehicleVelocity *= 1000f; 953 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
950 } 954 }
951 else if (newVelocityLengthSq < 0.001f) 955 else if (newVelocityLengthSq < 0.001f)
952 VehicleVelocity = Vector3.Zero; 956 VehicleVelocity = Vector3.Zero;
@@ -957,39 +961,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
957 961
958 public void ComputeLinearVelocity(float pTimestep) 962 public void ComputeLinearVelocity(float pTimestep)
959 { 963 {
960 Vector3 linearMotorStep = m_linearMotor.Step(pTimestep); 964 // Step the motor from the current value. Get the correction needed this step.
965 Vector3 currentVel = VehicleVelocity * Quaternion.Inverse(VehicleOrientation);
966 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVel);
961 967
962 // The movement computed in the linear motor is relative to the vehicle 968 // Motor is vehicle coordinates. Rotate it to world coordinates
963 // coordinates. Rotate the movement to world coordinates. 969 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation;
964 Vector3 linearMotorVelocity = linearMotorStep * VehicleOrientation;
965 970
966 // If we're a ground vehicle, don't loose any Z action (like gravity acceleration). 971 // If we're a ground vehicle, don't add any upward Z movement
967 float mixFactor = 1f; // 1 means use all linear motor Z value, 0 means use all existing Z
968 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0) 972 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
969 { 973 {
970 if (!Prim.IsColliding) 974 if (linearMotorVelocityW.Z > 0f)
971 { 975 linearMotorVelocityW.Z = 0f;
972 // If a ground vehicle and not on the ground, I want gravity effect
973 mixFactor = 0.2f;
974 }
975 }
976 else
977 {
978 // I'm not a ground vehicle but don't totally loose the effect of the environment
979 mixFactor = 0.8f;
980 } 976 }
981 linearMotorVelocity.Z = mixFactor * linearMotorVelocity.Z + (1f - mixFactor) * VehicleVelocity.Z;
982
983 // What we want to contribute to the vehicle's existing velocity
984 Vector3 linearMotorForce = linearMotorVelocity - VehicleVelocity;
985
986 // Act against the inertia of the vehicle
987 linearMotorForce *= m_vehicleMass;
988 977
989 VehicleAddForceImpulse(linearMotorForce * pTimestep); 978 // Add this correction to the velocity to make it faster/slower.
979 VehicleVelocity += linearMotorVelocityW;
990 980
991 VDetailLog("{0}, MoveLinear,velocity,vehVel={1},step={2},stepVel={3},mix={4},force={5}", 981 VDetailLog("{0}, MoveLinear,velocity,vehVel={1},correction={2},force={3}",
992 Prim.LocalID, VehicleVelocity, linearMotorStep, linearMotorVelocity, mixFactor, linearMotorForce); 982 Prim.LocalID, VehicleVelocity, linearMotorCorrectionV, linearMotorVelocityW);
993 } 983 }
994 984
995 public void ComputeLinearTerrainHeightCorrection(float pTimestep) 985 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
@@ -1133,8 +1123,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1133 // a downward raycast to find what is below. 1123 // a downward raycast to find what is below.
1134 public void ComputeLinearMotorUp(float pTimestep) 1124 public void ComputeLinearMotorUp(float pTimestep)
1135 { 1125 {
1136 Vector3 ret = Vector3.Zero;
1137
1138 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 1126 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1139 { 1127 {
1140 // This code tries to decide if the object is not on the ground and then pushing down 1128 // This code tries to decide if the object is not on the ground and then pushing down
@@ -1202,62 +1190,27 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1202 // set directly on the vehicle. 1190 // set directly on the vehicle.
1203 private void MoveAngular(float pTimestep) 1191 private void MoveAngular(float pTimestep)
1204 { 1192 {
1205 // The user wants this many radians per second angular change? 1193 // VehicleRotationalVelocity = Vector3.Zero;
1206 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
1207 1194
1208 // ================================================================== 1195 ComputeAngularTurning(pTimestep);
1209 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1210 // This flag prevents linear deflection parallel to world z-axis. This is useful
1211 // for preventing ground vehicles with large linear deflection, like bumper cars,
1212 // from climbing their linear deflection into the sky.
1213 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1214 // TODO: This is here because this is where ODE put it but documentation says it
1215 // is a linear effect. Where should this check go?
1216 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1217 {
1218 angularMotorContribution.X = 0f;
1219 angularMotorContribution.Y = 0f;
1220 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
1221 }
1222
1223 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
1224 1196
1225 Vector3 deflectionContribution = ComputeAngularDeflection(); 1197 ComputeAngularVerticalAttraction();
1226 1198
1227 Vector3 bankingContribution = ComputeAngularBanking(); 1199 ComputeAngularDeflection();
1228 1200
1229 // ================================================================== 1201 ComputeAngularBanking();
1230 m_lastVertAttractor = verticalAttractionContribution;
1231
1232 m_lastAngularVelocity = angularMotorContribution
1233 + verticalAttractionContribution
1234 + deflectionContribution
1235 + bankingContribution;
1236
1237 // Add of the above computation are made relative to vehicle coordinates.
1238 // Convert to world coordinates.
1239 m_lastAngularVelocity *= VehicleOrientation;
1240 1202
1241 // ================================================================== 1203 // ==================================================================
1242 // Apply the correction velocity. 1204 if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1243 // TODO: Should this be applied as an angular force (torque)?
1244 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1245 {
1246 VehicleRotationalVelocity = m_lastAngularVelocity;
1247
1248 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}",
1249 Prim.LocalID,
1250 angularMotorContribution, verticalAttractionContribution,
1251 bankingContribution, deflectionContribution,
1252 m_lastAngularVelocity
1253 );
1254 }
1255 else
1256 { 1205 {
1257 // The vehicle is not adding anything angular wise. 1206 // The vehicle is not adding anything angular wise.
1258 VehicleRotationalVelocity = Vector3.Zero; 1207 VehicleRotationalVelocity = Vector3.Zero;
1259 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); 1208 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
1260 } 1209 }
1210 else
1211 {
1212 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", Prim.LocalID, VehicleRotationalVelocity);
1213 }
1261 1214
1262 // ================================================================== 1215 // ==================================================================
1263 //Offset section 1216 //Offset section
@@ -1291,6 +1244,31 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1291 } 1244 }
1292 1245
1293 } 1246 }
1247
1248 private void ComputeAngularTurning(float pTimestep)
1249 {
1250 // The user wants this many radians per second angular change?
1251 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation);
1252 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1253
1254 // ==================================================================
1255 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1256 // This flag prevents linear deflection parallel to world z-axis. This is useful
1257 // for preventing ground vehicles with large linear deflection, like bumper cars,
1258 // from climbing their linear deflection into the sky.
1259 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1260 // TODO: This is here because this is where ODE put it but documentation says it
1261 // is a linear effect. Where should this check go?
1262 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1263 {
1264 angularMotorContributionV.X = 0f;
1265 angularMotorContributionV.Y = 0f;
1266 }
1267
1268 VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
1269 VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV);
1270 }
1271
1294 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1272 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1295 // Some vehicles, like boats, should always keep their up-side up. This can be done by 1273 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1296 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to 1274 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
@@ -1299,13 +1277,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1299 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An 1277 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1300 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an 1278 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1301 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. 1279 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1302 public Vector3 ComputeAngularVerticalAttraction() 1280 public void ComputeAngularVerticalAttraction()
1303 { 1281 {
1304 Vector3 ret = Vector3.Zero;
1305
1306 // If vertical attaction timescale is reasonable 1282 // If vertical attaction timescale is reasonable
1307 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1283 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1308 { 1284 {
1285 Vector3 vertContributionV = Vector3.Zero;
1286
1309 // Take a vector pointing up and convert it from world to vehicle relative coords. 1287 // Take a vector pointing up and convert it from world to vehicle relative coords.
1310 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; 1288 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
1311 1289
@@ -1319,37 +1297,36 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1319 1297
1320 // Y error means needed rotation around X axis and visa versa. 1298 // Y error means needed rotation around X axis and visa versa.
1321 // Since the error goes from zero to one, the asin is the corresponding angle. 1299 // Since the error goes from zero to one, the asin is the corresponding angle.
1322 ret.X = (float)Math.Asin(verticalError.Y); 1300 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1323 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) 1301 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1324 ret.Y = -(float)Math.Asin(verticalError.X); 1302 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1325 1303
1326 // If verticalError.Z is negative, the vehicle is upside down. Add additional push. 1304 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1327 if (verticalError.Z < 0f) 1305 if (verticalError.Z < 0f)
1328 { 1306 {
1329 ret.X += PIOverFour; 1307 vertContributionV.X += PIOverFour;
1330 ret.Y += PIOverFour; 1308 // vertContribution.Y -= PIOverFour;
1331 } 1309 }
1332 1310
1333 // 'ret' is now the necessary velocity to correct tilt in one second. 1311 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1334 // Correction happens over a number of seconds. 1312 // Correction happens over a number of seconds.
1335 Vector3 unscaledContrib = ret; 1313 Vector3 unscaledContrib = vertContributionV; // DEBUG DEBUG
1336 ret /= m_verticalAttractionTimescale; 1314 vertContributionV /= m_verticalAttractionTimescale;
1315
1316 VehicleRotationalVelocity += vertContributionV * VehicleOrientation;
1337 1317
1338 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}", 1318 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1339 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret); 1319 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1340 } 1320 }
1341 return ret;
1342 } 1321 }
1343 1322
1344 // Return the angular correction to correct the direction the vehicle is pointing to be 1323 // Angular correction to correct the direction the vehicle is pointing to be
1345 // the direction is should want to be pointing. 1324 // the direction is should want to be pointing.
1346 // The vehicle is moving in some direction and correct its orientation to it is pointing 1325 // The vehicle is moving in some direction and correct its orientation to it is pointing
1347 // in that direction. 1326 // in that direction.
1348 // TODO: implement reference frame. 1327 // TODO: implement reference frame.
1349 public Vector3 ComputeAngularDeflection() 1328 public void ComputeAngularDeflection()
1350 { 1329 {
1351 Vector3 ret = Vector3.Zero;
1352
1353 // Since angularMotorUp and angularDeflection are computed independently, they will calculate 1330 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1354 // approximately the same X or Y correction. When added together (when contributions are combined) 1331 // approximately the same X or Y correction. When added together (when contributions are combined)
1355 // this creates an over-correction and then wabbling as the target is overshot. 1332 // this creates an over-correction and then wabbling as the target is overshot.
@@ -1357,6 +1334,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1357 1334
1358 if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) 1335 if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1359 { 1336 {
1337 Vector3 deflectContributionV = Vector3.Zero;
1338
1360 // The direction the vehicle is moving 1339 // The direction the vehicle is moving
1361 Vector3 movingDirection = VehicleVelocity; 1340 Vector3 movingDirection = VehicleVelocity;
1362 movingDirection.Normalize(); 1341 movingDirection.Normalize();
@@ -1382,18 +1361,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1382 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); 1361 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1383 1362
1384 // Scale the correction by recovery timescale and efficiency 1363 // Scale the correction by recovery timescale and efficiency
1385 ret = (-deflectionError) * m_angularDeflectionEfficiency; 1364 deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency;
1386 ret /= m_angularDeflectionTimescale; 1365 deflectContributionV /= m_angularDeflectionTimescale;
1366
1367 VehicleRotationalVelocity += deflectContributionV * VehicleOrientation;
1387 1368
1388 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", 1369 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1389 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); 1370 Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1390 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", 1371 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1391 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); 1372 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1392 } 1373 }
1393 return ret;
1394 } 1374 }
1395 1375
1396 // Return an angular change to rotate the vehicle around the Z axis when the vehicle 1376 // Angular change to rotate the vehicle around the Z axis when the vehicle
1397 // is tipped around the X axis. 1377 // is tipped around the X axis.
1398 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1378 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1399 // The vertical attractor feature must be enabled in order for the banking behavior to 1379 // The vertical attractor feature must be enabled in order for the banking behavior to
@@ -1424,12 +1404,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1424 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to 1404 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1425 // bank quickly then give it a banking timescale of about a second or less, otherwise you can 1405 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1426 // make a sluggish vehicle by giving it a timescale of several seconds. 1406 // make a sluggish vehicle by giving it a timescale of several seconds.
1427 public Vector3 ComputeAngularBanking() 1407 public void ComputeAngularBanking()
1428 { 1408 {
1429 Vector3 ret = Vector3.Zero;
1430
1431 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1409 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1432 { 1410 {
1411 Vector3 bankingContributionV = Vector3.Zero;
1412
1433 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented. 1413 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1434 // As the vehicle rolls to the right or left, the Y value will increase from 1414 // As the vehicle rolls to the right or left, the Y value will increase from
1435 // zero (straight up) to 1 or -1 (full tilt right or left) 1415 // zero (straight up) to 1 or -1 (full tilt right or left)
@@ -1446,15 +1426,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1446 mixedYawAngle = ClampInRange(-20f, mixedYawAngle, 20f); 1426 mixedYawAngle = ClampInRange(-20f, mixedYawAngle, 20f);
1447 1427
1448 // Build the force vector to change rotation from what it is to what it should be 1428 // Build the force vector to change rotation from what it is to what it should be
1449 ret.Z = -mixedYawAngle; 1429 bankingContributionV.Z = -mixedYawAngle;
1450 1430
1451 // Don't do it all at once. 1431 // Don't do it all at once.
1452 ret /= m_bankingTimescale; 1432 bankingContributionV /= m_bankingTimescale;
1433
1434 VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
1453 1435
1454 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", 1436 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1455 Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, ret); 1437 Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1456 } 1438 }
1457 return ret;
1458 } 1439 }
1459 1440
1460 // This is from previous instantiations of XXXDynamics.cs. 1441 // This is from previous instantiations of XXXDynamics.cs.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index cbd160f..1e3e5d8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -252,7 +252,7 @@ public abstract class BSLinkset
252 // of the linkset is received. 252 // of the linkset is received.
253 // Passed flag is update came from physics engine (true) or the user (false). 253 // Passed flag is update came from physics engine (true) or the user (false).
254 // Called at taint-time!! 254 // Called at taint-time!!
255 public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate); 255 public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject physObject);
256 256
257 // Routine used when rebuilding the body of the root of the linkset 257 // Routine used when rebuilding the body of the root of the linkset
258 // Destroy all the constraints have have been made to root. 258 // Destroy all the constraints have have been made to root.
@@ -261,11 +261,6 @@ public abstract class BSLinkset
261 // Called at taint-time!! 261 // Called at taint-time!!
262 public abstract bool RemoveBodyDependencies(BSPrim child); 262 public abstract bool RemoveBodyDependencies(BSPrim child);
263 263
264 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
265 // this routine will restore the removed constraints.
266 // Called at taint-time!!
267 public abstract void RestoreBodyDependencies(BSPrim child);
268
269 // ================================================================ 264 // ================================================================
270 protected virtual float ComputeLinksetMass() 265 protected virtual float ComputeLinksetMass()
271 { 266 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index 8c9a774..2c8dd23 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -51,6 +51,21 @@ sealed class BSLinksetCompoundInfo : BSLinksetInfo
51 OffsetFromCenterOfMass = p; 51 OffsetFromCenterOfMass = p;
52 OffsetRot = r; 52 OffsetRot = r;
53 } 53 }
54 // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape)
55 public BSLinksetCompoundInfo(int indx, BSPhysObject root, BSPhysObject child, OMV.Vector3 centerDisplacement)
56 {
57 // Each child position and rotation is given relative to the center-of-mass.
58 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation);
59 OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation;
60 OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
61 OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation;
62
63 // Save relative position for recomputing child's world position after moving linkset.
64 Index = indx;
65 OffsetFromRoot = displacementFromRoot;
66 OffsetFromCenterOfMass = displacementFromCOM;
67 OffsetRot = displacementRot;
68 }
54 public override void Clear() 69 public override void Clear()
55 { 70 {
56 Index = 0; 71 Index = 0;
@@ -182,24 +197,71 @@ public sealed class BSLinksetCompound : BSLinkset
182 197
183 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then. 198 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
184 // Called at taint-time. 199 // Called at taint-time.
185 public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) 200 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject updated)
186 { 201 {
187 // The user moving a child around requires the rebuilding of the linkset compound shape 202 // The user moving a child around requires the rebuilding of the linkset compound shape
188 // One problem is this happens when a border is crossed -- the simulator implementation 203 // One problem is this happens when a border is crossed -- the simulator implementation
189 // is to store the position into the group which causes the move of the object 204 // stores the position into the group which causes the move of the object
190 // but it also means all the child positions get updated. 205 // but it also means all the child positions get updated.
191 // What would cause an unnecessary rebuild so we make sure the linkset is in a 206 // What would cause an unnecessary rebuild so we make sure the linkset is in a
192 // region before bothering to do a rebuild. 207 // region before bothering to do a rebuild.
193 if (!IsRoot(updated) 208 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
194 && !physicalUpdate
195 && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
196 { 209 {
197 // TODO: replace this with are calculation of the child prim's orientation and pos. 210 // If a child of the linkset is updating only the position or rotation, that can be done
198 // TODO: for the moment, don't rebuild the compound shape. 211 // without rebuilding the linkset.
199 // This is often just the car turning its wheels. When we can just reorient the one 212 // If a handle for the child can be fetch, we update the child here. If a rebuild was
200 // member shape of the compound shape, the overhead of rebuilding won't be a problem. 213 // scheduled by someone else, the rebuild will just replace this setting.
201 // updated.LinksetInfo = null; 214
202 // ScheduleRebuild(updated); 215 bool updatedChild = false;
216 // Anything other than updating position or orientation usually means a physical update
217 // and that is caused by us updating the object.
218 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
219 {
220 // Gather the child info. It might not be there if the linkset is in transition.
221 BSLinksetCompoundInfo lsi = updated.LinksetInfo as BSLinksetCompoundInfo;
222 if (LinksetRoot.PhysShape.HasPhysicalShape && lsi != null)
223 {
224 if (PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape))
225 {
226 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, lsi.Index);
227 if (linksetChildShape.HasPhysicalShape)
228 {
229 // Compute the offset from the center-of-gravity
230 BSLinksetCompoundInfo newLsi = new BSLinksetCompoundInfo(lsi.Index, LinksetRoot, updated, LinksetRoot.PositionDisplacement);
231 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, lsi.Index,
232 newLsi.OffsetFromCenterOfMass,
233 newLsi.OffsetRot,
234 true /* shouldRecalculateLocalAabb */);
235 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1}newLsi={2}",
236 updated.LocalID, whichUpdated, newLsi);
237 updated.LinksetInfo = newLsi;
238 updatedChild = true;
239 }
240 else // DEBUG DEBUG
241 { // DEBUG DEBUG
242 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
243 updated.LocalID, linksetChildShape);
244 } // DEBUG DEBUG
245 }
246 else // DEBUG DEBUG
247 { // DEBUG DEBUG
248 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,notCompound", updated.LocalID);
249 } // DEBUG DEBUG
250 }
251 else // DEBUG DEBUG
252 { // DEBUG DEBUG
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,rootPhysShape={1},lsi={2}",
254 updated.LocalID, LinksetRoot.PhysShape, lsi == null ? "NULL" : lsi.ToString());
255 } // DEBUG DEBUG
256 if (!updatedChild)
257 {
258 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
259 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
260 updated.LocalID, whichUpdated);
261 updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed.
262 ScheduleRebuild(updated);
263 }
264 }
203 } 265 }
204 } 266 }
205 267
@@ -228,13 +290,6 @@ public sealed class BSLinksetCompound : BSLinkset
228 return ret; 290 return ret;
229 } 291 }
230 292
231 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
232 // this routine will restore the removed constraints.
233 // Called at taint-time!!
234 public override void RestoreBodyDependencies(BSPrim child)
235 {
236 }
237
238 // When the linkset is built, the child shape is added to the compound shape relative to the 293 // When the linkset is built, the child shape is added to the compound shape relative to the
239 // root shape. The linkset then moves around but this does not move the actual child 294 // root shape. The linkset then moves around but this does not move the actual child
240 // prim. The child prim's location must be recomputed based on the location of the root shape. 295 // prim. The child prim's location must be recomputed based on the location of the root shape.
@@ -322,7 +377,7 @@ public sealed class BSLinksetCompound : BSLinkset
322 // Constraint linksets are rebuilt every time. 377 // Constraint linksets are rebuilt every time.
323 // Note that this works for rebuilding just the root after a linkset is taken apart. 378 // Note that this works for rebuilding just the root after a linkset is taken apart.
324 // Called at taint time!! 379 // Called at taint time!!
325 private bool disableCOM = true; // disable until we get this debugged 380 private bool disableCOM = false; // disable until we get this debugged
326 private void RecomputeLinksetCompound() 381 private void RecomputeLinksetCompound()
327 { 382 {
328 try 383 try
@@ -345,12 +400,16 @@ public sealed class BSLinksetCompound : BSLinkset
345 } // DEBUG DEBUG 400 } // DEBUG DEBUG
346 else 401 else
347 { 402 {
348 centerOfMass = ComputeLinksetGeometricCenter(); 403 centerOfMass = ComputeLinksetCenterOfMass();
349 centerDisplacement = centerOfMass - LinksetRoot.RawPosition; 404 // 'centerDisplacement' is the value to *add* to all the shape offsets
405 centerDisplacement = LinksetRoot.RawPosition - centerOfMass;
350 406
351 // Since we're displacing the center of the shape, we need to move the body in the world 407 // Since we're displacing the center of the shape, we need to move the body in the world
352 LinksetRoot.PositionDisplacement = centerDisplacement; 408 LinksetRoot.PositionDisplacement = centerDisplacement;
353 409
410 // This causes the root prim position to be set properly based on the new PositionDisplacement
411 LinksetRoot.ForcePosition = LinksetRoot.RawPosition;
412 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM
354 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0, -centerDisplacement, OMV.Quaternion.Identity, false); 413 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0, -centerDisplacement, OMV.Quaternion.Identity, false);
355 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", 414 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}",
356 LinksetRoot.LocalID, centerOfMass, LinksetRoot.RawPosition, centerDisplacement); 415 LinksetRoot.LocalID, centerOfMass, LinksetRoot.RawPosition, centerDisplacement);
@@ -372,15 +431,7 @@ public sealed class BSLinksetCompound : BSLinkset
372 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; 431 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
373 if (lci == null) 432 if (lci == null)
374 { 433 {
375 // Each child position and rotation is given relative to the center-of-mass. 434 lci = new BSLinksetCompoundInfo(memberIndex, LinksetRoot, cPrim, centerDisplacement);
376 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
377 OMV.Vector3 displacementFromRoot = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
378 OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
379 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
380
381 // Save relative position for recomputing child's world position after moving linkset.
382 lci = new BSLinksetCompoundInfo(memberIndex, displacementFromCOM, displacementRot);
383 lci.OffsetFromRoot = displacementFromRoot;
384 cPrim.LinksetInfo = lci; 435 cPrim.LinksetInfo = lci;
385 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); 436 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
386 } 437 }
@@ -390,7 +441,7 @@ public sealed class BSLinksetCompound : BSLinkset
390 441
391 if (cPrim.PhysShape.isNativeShape) 442 if (cPrim.PhysShape.isNativeShape)
392 { 443 {
393 // A native shape is turning into a hull collision shape because native 444 // A native shape is turned into a hull collision shape because native
394 // shapes are not shared so we have to hullify it so it will be tracked 445 // shapes are not shared so we have to hullify it so it will be tracked
395 // and freed at the correct time. This also solves the scaling problem 446 // and freed at the correct time. This also solves the scaling problem
396 // (native shapes scaled but hull/meshes are assumed to not be). 447 // (native shapes scaled but hull/meshes are assumed to not be).
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index d0b2a56..3011465 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -83,7 +83,7 @@ public sealed class BSLinksetConstraints : BSLinkset
83 } 83 }
84 84
85 // Called at taint-time!! 85 // Called at taint-time!!
86 public override void UpdateProperties(BSPhysObject updated, bool inTaintTime) 86 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPhysObject pObj)
87 { 87 {
88 // Nothing to do for constraints on property updates 88 // Nothing to do for constraints on property updates
89 } 89 }
@@ -110,14 +110,6 @@ public sealed class BSLinksetConstraints : BSLinkset
110 return ret; 110 return ret;
111 } 111 }
112 112
113 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
114 // this routine will restore the removed constraints.
115 // Called at taint-time!!
116 public override void RestoreBodyDependencies(BSPrim child)
117 {
118 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
119 }
120
121 // ================================================================ 113 // ================================================================
122 114
123 // Add a new child to the linkset. 115 // Add a new child to the linkset.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index 6d0db2e..9501e2d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -138,7 +138,8 @@ public class BSVMotor : BSMotor
138 CurrentValue = TargetValue = Vector3.Zero; 138 CurrentValue = TargetValue = Vector3.Zero;
139 } 139 }
140 140
141 // Compute the next step and return the new current value 141 // Compute the next step and return the new current value.
142 // Returns the correction needed to move 'current' to 'target'.
142 public virtual Vector3 Step(float timeStep) 143 public virtual Vector3 Step(float timeStep)
143 { 144 {
144 if (!Enabled) return TargetValue; 145 if (!Enabled) return TargetValue;
@@ -148,9 +149,10 @@ public class BSVMotor : BSMotor
148 149
149 Vector3 correction = Vector3.Zero; 150 Vector3 correction = Vector3.Zero;
150 Vector3 error = TargetValue - CurrentValue; 151 Vector3 error = TargetValue - CurrentValue;
152 LastError = error;
151 if (!ErrorIsZero(error)) 153 if (!ErrorIsZero(error))
152 { 154 {
153 correction = Step(timeStep, error); 155 correction = StepError(timeStep, error);
154 156
155 CurrentValue += correction; 157 CurrentValue += correction;
156 158
@@ -187,20 +189,31 @@ public class BSVMotor : BSMotor
187 else 189 else
188 { 190 {
189 // Difference between what we have and target is small. Motor is done. 191 // Difference between what we have and target is small. Motor is done.
192 if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
193 {
194 // The target can step down to nearly zero but not get there. If close to zero
195 // it is really zero.
196 TargetValue = Vector3.Zero;
197 }
190 CurrentValue = TargetValue; 198 CurrentValue = TargetValue;
191 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", 199 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
192 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); 200 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
193 } 201 }
194 202
195 return CurrentValue; 203 return correction;
204 }
205 // version of step that sets the current value before doing the step
206 public virtual Vector3 Step(float timeStep, Vector3 current)
207 {
208 CurrentValue = current;
209 return Step(timeStep);
196 } 210 }
197 public virtual Vector3 Step(float timeStep, Vector3 error) 211 public virtual Vector3 StepError(float timeStep, Vector3 error)
198 { 212 {
199 if (!Enabled) return Vector3.Zero; 213 if (!Enabled) return Vector3.Zero;
200 214
201 LastError = error;
202 Vector3 returnCorrection = Vector3.Zero; 215 Vector3 returnCorrection = Vector3.Zero;
203 if (!ErrorIsZero()) 216 if (!ErrorIsZero(error))
204 { 217 {
205 // correction = error / secondsItShouldTakeToCorrect 218 // correction = error / secondsItShouldTakeToCorrect
206 Vector3 correctionAmount; 219 Vector3 correctionAmount;
@@ -302,9 +315,10 @@ public class BSFMotor : BSMotor
302 315
303 float correction = 0f; 316 float correction = 0f;
304 float error = TargetValue - CurrentValue; 317 float error = TargetValue - CurrentValue;
318 LastError = error;
305 if (!ErrorIsZero(error)) 319 if (!ErrorIsZero(error))
306 { 320 {
307 correction = Step(timeStep, error); 321 correction = StepError(timeStep, error);
308 322
309 CurrentValue += correction; 323 CurrentValue += correction;
310 324
@@ -339,6 +353,12 @@ public class BSFMotor : BSMotor
339 else 353 else
340 { 354 {
341 // Difference between what we have and target is small. Motor is done. 355 // Difference between what we have and target is small. Motor is done.
356 if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold))
357 {
358 // The target can step down to nearly zero but not get there. If close to zero
359 // it is really zero.
360 TargetValue = 0f;
361 }
342 CurrentValue = TargetValue; 362 CurrentValue = TargetValue;
343 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", 363 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
344 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); 364 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
@@ -347,13 +367,12 @@ public class BSFMotor : BSMotor
347 return CurrentValue; 367 return CurrentValue;
348 } 368 }
349 369
350 public virtual float Step(float timeStep, float error) 370 public virtual float StepError(float timeStep, float error)
351 { 371 {
352 if (!Enabled) return 0f; 372 if (!Enabled) return 0f;
353 373
354 LastError = error;
355 float returnCorrection = 0f; 374 float returnCorrection = 0f;
356 if (!ErrorIsZero()) 375 if (!ErrorIsZero(error))
357 { 376 {
358 // correction = error / secondsItShouldTakeToCorrect 377 // correction = error / secondsItShouldTakeToCorrect
359 float correctionAmount; 378 float correctionAmount;
@@ -440,8 +459,8 @@ public class BSPIDVMotor : BSVMotor
440 } 459 }
441 } 460 }
442 461
443 // Ignore Current and Target Values and just advance the PID computation on this error. 462 // Advance the PID computation on this error.
444 public override Vector3 Step(float timeStep, Vector3 error) 463 public override Vector3 StepError(float timeStep, Vector3 error)
445 { 464 {
446 if (!Enabled) return Vector3.Zero; 465 if (!Enabled) return Vector3.Zero;
447 466
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 3e80aa4..9460daf 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -45,6 +45,9 @@ public static class BSParam
45 45
46 public static float MinimumObjectMass { get; private set; } 46 public static float MinimumObjectMass { get; private set; }
47 public static float MaximumObjectMass { get; private set; } 47 public static float MaximumObjectMass { get; private set; }
48 public static float MaxLinearVelocity { get; private set; }
49 public static float MaxAngularVelocity { get; private set; }
50 public static float MaxAddForceMagnitude { get; private set; }
48 51
49 public static float LinearDamping { get; private set; } 52 public static float LinearDamping { get; private set; }
50 public static float AngularDamping { get; private set; } 53 public static float AngularDamping { get; private set; }
@@ -79,6 +82,8 @@ public static class BSParam
79 public static float AvatarStepApproachFactor { get; private set; } 82 public static float AvatarStepApproachFactor { get; private set; }
80 public static float AvatarStepForceFactor { get; private set; } 83 public static float AvatarStepForceFactor { get; private set; }
81 84
85 public static float VehicleMaxLinearVelocity { get; private set; }
86 public static float VehicleMaxAngularVelocity { get; private set; }
82 public static float VehicleAngularDamping { get; private set; } 87 public static float VehicleAngularDamping { get; private set; }
83 public static float VehicleDebuggingEnabled { get; private set; } 88 public static float VehicleDebuggingEnabled { get; private set; }
84 89
@@ -103,7 +108,6 @@ public static class BSParam
103 public const float MaxDensity = 22587f; 108 public const float MaxDensity = 22587f;
104 public const float MinRestitution = 0f; 109 public const float MinRestitution = 0f;
105 public const float MaxRestitution = 1f; 110 public const float MaxRestitution = 1f;
106 public const float MaxAddForceMagnitude = 20f;
107 111
108 // =========================================================================== 112 // ===========================================================================
109 public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 113 public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
@@ -232,11 +236,7 @@ public static class BSParam
232 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, 236 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
233 (s) => { return (float)s.m_maxUpdatesPerFrame; }, 237 (s) => { return (float)s.m_maxUpdatesPerFrame; },
234 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 238 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
235 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", 239
236 500f,
237 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
238 (s) => { return (float)s.m_taintsToProcessPerStep; },
239 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
240 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", 240 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
241 0.0001f, 241 0.0001f,
242 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); }, 242 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
@@ -247,6 +247,22 @@ public static class BSParam
247 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); }, 247 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
248 (s) => { return (float)MaximumObjectMass; }, 248 (s) => { return (float)MaximumObjectMass; },
249 (s,p,l,v) => { MaximumObjectMass = v; } ), 249 (s,p,l,v) => { MaximumObjectMass = v; } ),
250 new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
251 1000.0f,
252 (s,cf,p,v) => { MaxLinearVelocity = cf.GetFloat(p, v); },
253 (s) => { return (float)MaxLinearVelocity; },
254 (s,p,l,v) => { MaxLinearVelocity = v; } ),
255 new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
256 1000.0f,
257 (s,cf,p,v) => { MaxAngularVelocity = cf.GetFloat(p, v); },
258 (s) => { return (float)MaxAngularVelocity; },
259 (s,p,l,v) => { MaxAngularVelocity = v; } ),
260 // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
261 new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
262 20000.0f,
263 (s,cf,p,v) => { MaxAddForceMagnitude = cf.GetFloat(p, v); },
264 (s) => { return (float)MaxAddForceMagnitude; },
265 (s,p,l,v) => { MaxAddForceMagnitude = v; } ),
250 266
251 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 267 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
252 2200f, 268 2200f,
@@ -423,8 +439,18 @@ public static class BSParam
423 (s) => { return AvatarStepForceFactor; }, 439 (s) => { return AvatarStepForceFactor; },
424 (s,p,l,v) => { AvatarStepForceFactor = v; } ), 440 (s,p,l,v) => { AvatarStepForceFactor = v; } ),
425 441
442 new ParameterDefn("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
443 1000.0f,
444 (s,cf,p,v) => { VehicleMaxLinearVelocity = cf.GetFloat(p, v); },
445 (s) => { return (float)VehicleMaxLinearVelocity; },
446 (s,p,l,v) => { VehicleMaxLinearVelocity = v; } ),
447 new ParameterDefn("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle",
448 12.0f,
449 (s,cf,p,v) => { VehicleMaxAngularVelocity = cf.GetFloat(p, v); },
450 (s) => { return (float)VehicleMaxAngularVelocity; },
451 (s,p,l,v) => { VehicleMaxAngularVelocity = v; } ),
426 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", 452 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
427 0.95f, 453 0.0f,
428 (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); }, 454 (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
429 (s) => { return VehicleAngularDamping; }, 455 (s) => { return VehicleAngularDamping; },
430 (s,p,l,v) => { VehicleAngularDamping = v; } ), 456 (s,p,l,v) => { VehicleAngularDamping = v; } ),
@@ -619,11 +645,8 @@ public static class BSParam
619 entries.Add(new PhysParameterEntry(pd.name, pd.desc)); 645 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
620 } 646 }
621 647
622 // make the list in alphabetical order for estetic reasons 648 // make the list alphabetical for estetic reasons
623 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) 649 entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); });
624 {
625 return ppe1.name.CompareTo(ppe2.name);
626 });
627 650
628 SettableParameters = entries.ToArray(); 651 SettableParameters = entries.ToArray();
629 } 652 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 5353c75..027c786 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -55,6 +55,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
55 * BS.ApplyCentralForce BS.ApplyTorque 55 * BS.ApplyCentralForce BS.ApplyTorque
56 */ 56 */
57 57
58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
59public enum UpdatedProperties : uint
60{
61 Position = 1 << 0,
62 Orientation = 1 << 1,
63 Velocity = 1 << 2,
64 Acceleration = 1 << 3,
65 RotationalVelocity = 1 << 4,
66 EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity,
67}
58public abstract class BSPhysObject : PhysicsActor 68public abstract class BSPhysObject : PhysicsActor
59{ 69{
60 protected BSPhysObject() 70 protected BSPhysObject()
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index aaa6fe5..f80084a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -311,16 +311,18 @@ public sealed class BSPrim : BSPhysObject
311 _position = value; 311 _position = value;
312 PositionSanityCheck(false); 312 PositionSanityCheck(false);
313 313
314 // A linkset might need to know if a component information changed.
315 Linkset.UpdateProperties(this, false);
316
317 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 314 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
318 { 315 {
319 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 316 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
320 ForcePosition = _position; 317 ForcePosition = _position;
318
319 // A linkset might need to know if a component information changed.
320 Linkset.UpdateProperties(UpdatedProperties.Position, this);
321
321 }); 322 });
322 } 323 }
323 } 324 }
325
324 public override OMV.Vector3 ForcePosition { 326 public override OMV.Vector3 ForcePosition {
325 get { 327 get {
326 _position = PhysicsScene.PE.GetPosition(PhysBody) - PositionDisplacement; 328 _position = PhysicsScene.PE.GetPosition(PhysBody) - PositionDisplacement;
@@ -335,25 +337,6 @@ public sealed class BSPrim : BSPhysObject
335 } 337 }
336 } 338 }
337 } 339 }
338 // Override to have position displacement immediately update the physical position.
339 // A feeble attempt to keep the sim and physical positions in sync
340 // Must be called at taint time.
341 public override OMV.Vector3 PositionDisplacement
342 {
343 get
344 {
345 return base.PositionDisplacement;
346 }
347 set
348 {
349 base.PositionDisplacement = value;
350 PhysicsScene.TaintedObject(PhysicsScene.InTaintTime, "BSPrim.setPosition", delegate()
351 {
352 if (PhysBody.HasPhysicalBody)
353 PhysicsScene.PE.SetTranslation(PhysBody, _position + base.PositionDisplacement, _orientation);
354 });
355 }
356 }
357 340
358 // Check that the current position is sane and, if not, modify the position to make it so. 341 // Check that the current position is sane and, if not, modify the position to make it so.
359 // Check for being below terrain and being out of bounds. 342 // Check for being below terrain and being out of bounds.
@@ -370,11 +353,11 @@ public sealed class BSPrim : BSPhysObject
370 return ret; 353 return ret;
371 } 354 }
372 355
373 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 356 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
374 OMV.Vector3 upForce = OMV.Vector3.Zero; 357 OMV.Vector3 upForce = OMV.Vector3.Zero;
375 if (RawPosition.Z < terrainHeight) 358 if (RawPosition.Z < terrainHeight)
376 { 359 {
377 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 360 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
378 float targetHeight = terrainHeight + (Size.Z / 2f); 361 float targetHeight = terrainHeight + (Size.Z / 2f);
379 // If the object is below ground it just has to be moved up because pushing will 362 // If the object is below ground it just has to be moved up because pushing will
380 // not get it through the terrain 363 // not get it through the terrain
@@ -682,12 +665,13 @@ public sealed class BSPrim : BSPhysObject
682 return; 665 return;
683 _orientation = value; 666 _orientation = value;
684 667
685 // A linkset might need to know if a component information changed.
686 Linkset.UpdateProperties(this, false);
687
688 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 668 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
689 { 669 {
690 ForceOrientation = _orientation; 670 ForceOrientation = _orientation;
671
672 // A linkset might need to know if a component information changed.
673 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
674
691 }); 675 });
692 } 676 }
693 } 677 }
@@ -989,10 +973,10 @@ public sealed class BSPrim : BSPhysObject
989 } 973 }
990 set { 974 set {
991 _rotationalVelocity = value; 975 _rotationalVelocity = value;
976 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
992 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 977 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
993 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 978 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
994 { 979 {
995 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
996 ForceRotationalVelocity = _rotationalVelocity; 980 ForceRotationalVelocity = _rotationalVelocity;
997 }); 981 });
998 } 982 }
@@ -1005,7 +989,9 @@ public sealed class BSPrim : BSPhysObject
1005 _rotationalVelocity = value; 989 _rotationalVelocity = value;
1006 if (PhysBody.HasPhysicalBody) 990 if (PhysBody.HasPhysicalBody)
1007 { 991 {
992 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1008 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 993 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
994 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1009 ActivateIfPhysical(false); 995 ActivateIfPhysical(false);
1010 } 996 }
1011 } 997 }
@@ -1082,7 +1068,7 @@ public sealed class BSPrim : BSPhysObject
1082 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below) 1068 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1083 1069
1084 // 'movePosition' is where we'd like the prim to be at this moment. 1070 // 'movePosition' is where we'd like the prim to be at this moment.
1085 OMV.Vector3 movePosition = _targetMotor.Step(timeStep); 1071 OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
1086 1072
1087 // If we are very close to our target, turn off the movement motor. 1073 // If we are very close to our target, turn off the movement motor.
1088 if (_targetMotor.ErrorIsZero()) 1074 if (_targetMotor.ErrorIsZero())
@@ -1193,10 +1179,14 @@ public sealed class BSPrim : BSPhysObject
1193 public override float APIDDamping { set { return; } } 1179 public override float APIDDamping { set { return; } }
1194 1180
1195 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1181 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1182 // Per documentation, max force is limited.
1183 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1184
1196 // Since this force is being applied in only one step, make this a force per second. 1185 // Since this force is being applied in only one step, make this a force per second.
1197 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 1186 addForce /= PhysicsScene.LastTimeStep;
1198 AddForce(addForce, pushforce, false); 1187 AddForce(addForce, pushforce, false /* inTaintTime */);
1199 } 1188 }
1189
1200 // Applying a force just adds this to the total force on the object. 1190 // Applying a force just adds this to the total force on the object.
1201 // This added force will only last the next simulation tick. 1191 // This added force will only last the next simulation tick.
1202 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1192 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
@@ -1205,9 +1195,9 @@ public sealed class BSPrim : BSPhysObject
1205 { 1195 {
1206 if (force.IsFinite()) 1196 if (force.IsFinite())
1207 { 1197 {
1208 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1209 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); 1198 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1210 1199
1200 OMV.Vector3 addForce = force;
1211 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() 1201 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1212 { 1202 {
1213 // Bullet adds this central force to the total force for this tick 1203 // Bullet adds this central force to the total force for this tick
@@ -1598,11 +1588,6 @@ public sealed class BSPrim : BSPhysObject
1598 // Called at taint-time!!! 1588 // Called at taint-time!!!
1599 public void CreateGeomAndObject(bool forceRebuild) 1589 public void CreateGeomAndObject(bool forceRebuild)
1600 { 1590 {
1601 // If this prim is part of a linkset, we must remove and restore the physical
1602 // links if the body is rebuilt.
1603 bool needToRestoreLinkset = false;
1604 bool needToRestoreVehicle = false;
1605
1606 // Create the correct physical representation for this type of object. 1591 // Create the correct physical representation for this type of object.
1607 // Updates PhysBody and PhysShape with the new information. 1592 // Updates PhysBody and PhysShape with the new information.
1608 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1593 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
@@ -1611,21 +1596,10 @@ public sealed class BSPrim : BSPhysObject
1611 // Called if the current prim body is about to be destroyed. 1596 // Called if the current prim body is about to be destroyed.
1612 // Remove all the physical dependencies on the old body. 1597 // Remove all the physical dependencies on the old body.
1613 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) 1598 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1614 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1599 Linkset.RemoveBodyDependencies(this);
1615 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); 1600 _vehicle.RemoveBodyDependencies(this);
1616 }); 1601 });
1617 1602
1618 if (needToRestoreLinkset)
1619 {
1620 // If physical body dependencies were removed, restore them
1621 Linkset.RestoreBodyDependencies(this);
1622 }
1623 if (needToRestoreVehicle)
1624 {
1625 // If physical body dependencies were removed, restore them
1626 _vehicle.RestoreBodyDependencies(this);
1627 }
1628
1629 // Make sure the properties are set on the new object 1603 // Make sure the properties are set on the new object
1630 UpdatePhysicalParameters(); 1604 UpdatePhysicalParameters();
1631 return; 1605 return;
@@ -1642,17 +1616,28 @@ public sealed class BSPrim : BSPhysObject
1642 // TODO: handle physics introduced by Bullet with computed vehicle physics. 1616 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1643 if (_vehicle.IsActive) 1617 if (_vehicle.IsActive)
1644 { 1618 {
1645 entprop.RotationalVelocity = OMV.Vector3.Zero; 1619 // entprop.RotationalVelocity = OMV.Vector3.Zero;
1620 }
1621
1622 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1623
1624 // Undo any center-of-mass displacement that might have been done.
1625 if (PositionDisplacement != OMV.Vector3.Zero)
1626 {
1627 // Correct for any rotation around the center-of-mass
1628 // TODO!!!
1629 entprop.Position -= PositionDisplacement;
1646 } 1630 }
1647 1631
1648 // Assign directly to the local variables so the normal set actions do not happen 1632 // Assign directly to the local variables so the normal set actions do not happen
1649 entprop.Position -= PositionDisplacement;
1650 _position = entprop.Position; 1633 _position = entprop.Position;
1651 _orientation = entprop.Rotation; 1634 _orientation = entprop.Rotation;
1652 _velocity = entprop.Velocity; 1635 _velocity = entprop.Velocity;
1653 _acceleration = entprop.Acceleration; 1636 _acceleration = entprop.Acceleration;
1654 _rotationalVelocity = entprop.RotationalVelocity; 1637 _rotationalVelocity = entprop.RotationalVelocity;
1655 1638
1639 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1640
1656 // The sanity check can change the velocity and/or position. 1641 // The sanity check can change the velocity and/or position.
1657 if (IsPhysical && PositionSanityCheck(true)) 1642 if (IsPhysical && PositionSanityCheck(true))
1658 { 1643 {
@@ -1661,8 +1646,7 @@ public sealed class BSPrim : BSPhysObject
1661 } 1646 }
1662 1647
1663 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG 1648 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1664 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", 1649 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1665 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1666 1650
1667 // remember the current and last set values 1651 // remember the current and last set values
1668 LastEntityProperties = CurrentEntityProperties; 1652 LastEntityProperties = CurrentEntityProperties;
@@ -1681,7 +1665,7 @@ public sealed class BSPrim : BSPhysObject
1681 */ 1665 */
1682 1666
1683 // The linkset implimentation might want to know about this. 1667 // The linkset implimentation might want to know about this.
1684 Linkset.UpdateProperties(this, true); 1668 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
1685 } 1669 }
1686} 1670}
1687} 1671}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index e0b4992..34fd2a0 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -81,7 +81,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
81 internal long m_simulationStep = 0; 81 internal long m_simulationStep = 0;
82 internal float NominalFrameRate { get; set; } 82 internal float NominalFrameRate { get; set; }
83 public long SimulationStep { get { return m_simulationStep; } } 83 public long SimulationStep { get { return m_simulationStep; } }
84 internal int m_taintsToProcessPerStep;
85 internal float LastTimeStep { get; private set; } 84 internal float LastTimeStep { get; private set; }
86 85
87 // Physical objects can register for prestep or poststep events 86 // Physical objects can register for prestep or poststep events
@@ -709,8 +708,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
709 // TriggerPreStepEvent 708 // TriggerPreStepEvent
710 // DoOneTimeTaints 709 // DoOneTimeTaints
711 // Step() 710 // Step()
712 // ProcessAndForwardCollisions 711 // ProcessAndSendToSimulatorCollisions
713 // ProcessAndForwardPropertyUpdates 712 // ProcessAndSendToSimulatorPropertyUpdates
714 // TriggerPostStepEvent 713 // TriggerPostStepEvent
715 714
716 // Calls to the PhysicsActors can't directly call into the physics engine 715 // Calls to the PhysicsActors can't directly call into the physics engine
@@ -847,8 +846,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
847 846
848 #endregion // Taints 847 #endregion // Taints
849 848
850 #region INI and command line parameter processing
851
852 #region IPhysicsParameters 849 #region IPhysicsParameters
853 // Get the list of parameters this physics engine supports 850 // Get the list of parameters this physics engine supports
854 public PhysParameterEntry[] GetParameterList() 851 public PhysParameterEntry[] GetParameterList()
@@ -945,8 +942,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
945 942
946 #endregion IPhysicsParameters 943 #endregion IPhysicsParameters
947 944
948 #endregion Runtime settable parameters
949
950 // Invoke the detailed logger and output something if it's enabled. 945 // Invoke the detailed logger and output something if it's enabled.
951 public void DetailLog(string msg, params Object[] args) 946 public void DetailLog(string msg, params Object[] args)
952 { 947 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
index 9bfec19..801f690 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -1,23 +1,22 @@
1CURRENT PRIORITIES 1CURRENT PRIORITIES
2================================================= 2=================================================
3Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 3Deleting a linkset while standing on the root will leave the physical shape of the root behind.
4 Msg Kayaker on OSGrid when working 4 Not sure if it is because standing on it. Done with large prim linksets.
5Child movement in linkset (don't rebuild linkset)
6Vehicle angular vertical attraction
7vehicle angular banking
8Center-of-gravity
9Vehicle angular deflection
10 Preferred orientation angular correction fix
11when should angular and linear motor targets be zeroed? when selected?
12 Need a vehicle.clear()? Or an 'else' in prestep if not physical.
5Teravus llMoveToTarget script debug 13Teravus llMoveToTarget script debug
6 Mixing of hover, buoyancy/gravity, moveToTarget, into one force 14 Mixing of hover, buoyancy/gravity, moveToTarget, into one force
7Boats floating at proper level
8Nebadon vehicles turning funny in arena 15Nebadon vehicles turning funny in arena
9limitMotorUp calibration (more down?) 16limitMotorUp calibration (more down?)
10llRotLookAt 17llRotLookAt
11llLookAt 18llLookAt
12Vehicle angular vertical attraction
13Vehicle angular deflection
14 Preferred orientation angular correction fix
15vehicle angular banking
16Avatars walking up stairs (HALF DONE) 19Avatars walking up stairs (HALF DONE)
17 Radius of the capsule affects ability to climb edges.
18Vehicle movement on terrain smoothness
19When is force introduced by SetForce removed? The prestep action could go forever.
20Boats float low in the water (DONE)
21Avatar movement 20Avatar movement
22 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) 21 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
23 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) 22 walking up stairs is not calibrated correctly (stairs out of Kepler cabin)
@@ -73,8 +72,12 @@ Incorporate inter-relationship of angular corrections. For instance, angularDefl
73 72
74GENERAL TODO LIST: 73GENERAL TODO LIST:
75================================================= 74=================================================
75llMoveToTarget objects are not effected by gravity until target is removed.
76Implement llSetPhysicalMaterial. 76Implement llSetPhysicalMaterial.
77 extend it with Center-of-mass, rolling friction, density
77Implement llSetForceAndTorque. 78Implement llSetForceAndTorque.
79Change BSPrim.moveToTarget to used forces rather than changing position
80 Changing position allows one to move through walls
78Implement an avatar mesh shape. The Bullet capsule is way too limited. 81Implement an avatar mesh shape. The Bullet capsule is way too limited.
79 Consider just hand creating a vertex/index array in a new BSShapeAvatar. 82 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
80Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain. 83Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain.
@@ -310,4 +313,12 @@ Remove HeightmapInfo from terrain specification (DONE)
310 Since C++ code does not need terrain height, this structure et al are not needed. 313 Since C++ code does not need terrain height, this structure et al are not needed.
311Surfboard go wonky when turning (DONE) 314Surfboard go wonky when turning (DONE)
312 Angular motor direction is global coordinates rather than local coordinates? 315 Angular motor direction is global coordinates rather than local coordinates?
313 (Resolution: made angular motor direction correct coordinate system) \ No newline at end of file 316 (Resolution: made angular motor direction correct coordinate system)
317Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE)
318 Msg Kayaker on OSGrid when working
319 (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the
320 same in SL as in OS/BulletSim)
321Boats float low in the water (DONE)
322Boats floating at proper level (DONE)
323When is force introduced by SetForce removed? The prestep action could go forever. (DONE)
324 (Resolution: setForce registers a prestep action which keeps applying the force) \ No newline at end of file
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index 201007b..96a9ff7 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -43,6 +43,35 @@ namespace OpenSim.Region.Physics.Manager
43 public delegate void JointDeactivated(PhysicsJoint joint); 43 public delegate void JointDeactivated(PhysicsJoint joint);
44 public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation" 44 public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation"
45 45
46 public enum RayFilterFlags:ushort
47 {
48 // the flags
49 water = 0x01,
50 land = 0x02,
51 agent = 0x04,
52 nonphysical = 0x08,
53 physical = 0x10,
54 phantom = 0x20,
55 volumedtc = 0x40,
56
57 // ray cast colision control (may only work for meshs)
58 ContactsUnImportant = 0x2000,
59 BackFaceCull = 0x4000,
60 ClosestHit = 0x8000,
61
62 // some combinations
63 LSLPhanton = phantom | volumedtc,
64 PrimsNonPhantom = nonphysical | physical,
65 PrimsNonPhantomAgents = nonphysical | physical | agent,
66
67 AllPrims = nonphysical | phantom | volumedtc | physical,
68 AllButLand = agent | nonphysical | physical | phantom | volumedtc,
69
70 ClosestAndBackCull = ClosestHit | BackFaceCull,
71
72 All = 0x3f
73 }
74
46 public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback); 75 public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback);
47 public delegate void AssetReceivedDelegate(AssetBase asset); 76 public delegate void AssetReceivedDelegate(AssetBase asset);
48 77
@@ -286,5 +315,15 @@ namespace OpenSim.Region.Physics.Manager
286 { 315 {
287 return new List<ContactResult>(); 316 return new List<ContactResult>();
288 } 317 }
318
319 public virtual object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
320 {
321 return null;
322 }
323
324 public virtual bool SupportsRaycastWorldFiltered()
325 {
326 return false;
327 }
289 } 328 }
290} 329}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index db5add1..3a7e1c7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -2738,42 +2738,40 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2738 return src.ToLower(); 2738 return src.ToLower();
2739 } 2739 }
2740 2740
2741 public LSL_Integer llGiveMoney(string destination, int amount) 2741 public void llGiveMoney(string destination, int amount)
2742 { 2742 {
2743 m_host.AddScriptLPS(1); 2743 Util.FireAndForget(x =>
2744
2745 if (m_item.PermsGranter == UUID.Zero)
2746 return 0;
2747
2748 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
2749 { 2744 {
2750 LSLError("No permissions to give money"); 2745 m_host.AddScriptLPS(1);
2751 return 0;
2752 }
2753 2746
2754 UUID toID = new UUID(); 2747 if (m_item.PermsGranter == UUID.Zero)
2748 return;
2755 2749
2756 if (!UUID.TryParse(destination, out toID)) 2750 if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
2757 { 2751 {
2758 LSLError("Bad key in llGiveMoney"); 2752 LSLError("No permissions to give money");
2759 return 0; 2753 return;
2760 } 2754 }
2761 2755
2762 IMoneyModule money = World.RequestModuleInterface<IMoneyModule>(); 2756 UUID toID = new UUID();
2763 2757
2764 if (money == null) 2758 if (!UUID.TryParse(destination, out toID))
2765 { 2759 {
2766 NotImplemented("llGiveMoney"); 2760 LSLError("Bad key in llGiveMoney");
2767 return 0; 2761 return;
2768 } 2762 }
2769 2763
2770 bool result = money.ObjectGiveMoney( 2764 IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
2771 m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
2772 2765
2773 if (result) 2766 if (money == null)
2774 return 1; 2767 {
2768 NotImplemented("llGiveMoney");
2769 return;
2770 }
2775 2771
2776 return 0; 2772 money.ObjectGiveMoney(
2773 m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
2774 });
2777 } 2775 }
2778 2776
2779 public void llMakeExplosion(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset) 2777 public void llMakeExplosion(int particles, double scale, double vel, double lifetime, double arc, string texture, LSL_Vector offset)
@@ -4923,7 +4921,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4923 public LSL_Vector llGetCenterOfMass() 4921 public LSL_Vector llGetCenterOfMass()
4924 { 4922 {
4925 m_host.AddScriptLPS(1); 4923 m_host.AddScriptLPS(1);
4926 Vector3 center = m_host.GetGeometricCenter(); 4924 Vector3 center = m_host.GetCenterOfMass();
4927 return new LSL_Vector(center.X,center.Y,center.Z); 4925 return new LSL_Vector(center.X,center.Y,center.Z);
4928 } 4926 }
4929 4927
@@ -6839,7 +6837,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6839 { 6837 {
6840 m_host.AddScriptLPS(1); 6838 m_host.AddScriptLPS(1);
6841 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); 6839 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
6842 if (xmlrpcMod.IsEnabled()) 6840 if (xmlrpcMod != null && xmlrpcMod.IsEnabled())
6843 { 6841 {
6844 UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_host.LocalId, m_item.ItemID, UUID.Zero); 6842 UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_host.LocalId, m_item.ItemID, UUID.Zero);
6845 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>(); 6843 IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface<IXmlRpcRouter>();
@@ -6871,6 +6869,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6871 m_host.AddScriptLPS(1); 6869 m_host.AddScriptLPS(1);
6872 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); 6870 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
6873 ScriptSleep(3000); 6871 ScriptSleep(3000);
6872 if (xmlrpcMod == null)
6873 return "";
6874 return (xmlrpcMod.SendRemoteData(m_host.LocalId, m_item.ItemID, channel, dest, idata, sdata)).ToString(); 6874 return (xmlrpcMod.SendRemoteData(m_host.LocalId, m_item.ItemID, channel, dest, idata, sdata)).ToString();
6875 } 6875 }
6876 6876
@@ -6878,7 +6878,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6878 { 6878 {
6879 m_host.AddScriptLPS(1); 6879 m_host.AddScriptLPS(1);
6880 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); 6880 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
6881 xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata); 6881 if (xmlrpcMod != null)
6882 xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata);
6882 ScriptSleep(3000); 6883 ScriptSleep(3000);
6883 } 6884 }
6884 6885
@@ -6893,7 +6894,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6893 } 6894 }
6894 6895
6895 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>(); 6896 IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
6896 xmlrpcMod.CloseXMLRPCChannel((UUID)channel); 6897 if (xmlrpcMod != null)
6898 xmlrpcMod.CloseXMLRPCChannel((UUID)channel);
6897 ScriptSleep(1000); 6899 ScriptSleep(1000);
6898 } 6900 }
6899 6901
@@ -11338,25 +11340,89 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11338 bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL); 11340 bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL);
11339 11341
11340 11342
11341 if (checkTerrain) 11343 if (World.SupportsRayCastFiltered())
11342 { 11344 {
11343 ContactResult? groundContact = GroundIntersection(rayStart, rayEnd); 11345 if (dist == 0)
11344 if (groundContact != null) 11346 return list;
11345 results.Add((ContactResult)groundContact); 11347
11346 } 11348 RayFilterFlags rayfilter = RayFilterFlags.ClosestAndBackCull;
11349 if (checkTerrain)
11350 rayfilter |= RayFilterFlags.land;
11351// if (checkAgents)
11352// rayfilter |= RayFilterFlags.agent;
11353 if (checkPhysical)
11354 rayfilter |= RayFilterFlags.physical;
11355 if (checkNonPhysical)
11356 rayfilter |= RayFilterFlags.nonphysical;
11357 if (detectPhantom)
11358 rayfilter |= RayFilterFlags.LSLPhanton;
11359
11360 Vector3 direction = dir * ( 1/dist);
11361
11362 if(rayfilter == 0)
11363 {
11364 list.Add(new LSL_Integer(0));
11365 return list;
11366 }
11367
11368 // get some more contacts to sort ???
11369 int physcount = 4 * count;
11370 if (physcount > 20)
11371 physcount = 20;
11372
11373 object physresults;
11374 physresults = World.RayCastFiltered(rayStart, direction, dist, physcount, rayfilter);
11375
11376 if (physresults == null)
11377 {
11378 list.Add(new LSL_Integer(-3)); // timeout error
11379 return list;
11380 }
11381
11382 results = (List<ContactResult>)physresults;
11347 11383
11348 if (checkAgents) 11384 // for now physics doesn't detect sitted avatars so do it outside physics
11385 if (checkAgents)
11386 {
11387 ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
11388 foreach (ContactResult r in agentHits)
11389 results.Add(r);
11390 }
11391
11392 // TODO: Replace this with a better solution. ObjectIntersection can only
11393 // detect nonphysical phantoms. They are detected by virtue of being
11394 // nonphysical (e.g. no PhysActor) so will not conflict with detecting
11395 // physicsl phantoms as done by the physics scene
11396 // We don't want anything else but phantoms here.
11397 if (detectPhantom)
11398 {
11399 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, false, false, true);
11400 foreach (ContactResult r in objectHits)
11401 results.Add(r);
11402 }
11403 }
11404 else
11349 { 11405 {
11350 ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd); 11406 if (checkAgents)
11351 foreach (ContactResult r in agentHits) 11407 {
11352 results.Add(r); 11408 ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
11409 foreach (ContactResult r in agentHits)
11410 results.Add(r);
11411 }
11412
11413 if (checkPhysical || checkNonPhysical || detectPhantom)
11414 {
11415 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
11416 foreach (ContactResult r in objectHits)
11417 results.Add(r);
11418 }
11353 } 11419 }
11354 11420
11355 if (checkPhysical || checkNonPhysical || detectPhantom) 11421 if (checkTerrain)
11356 { 11422 {
11357 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom); 11423 ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
11358 foreach (ContactResult r in objectHits) 11424 if (groundContact != null)
11359 results.Add(r); 11425 results.Add((ContactResult)groundContact);
11360 } 11426 }
11361 11427
11362 results.Sort(delegate(ContactResult a, ContactResult b) 11428 results.Sort(delegate(ContactResult a, ContactResult b)
@@ -11554,6 +11620,79 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
11554 NotImplemented("llGodLikeRezObject"); 11620 NotImplemented("llGodLikeRezObject");
11555 } 11621 }
11556 11622
11623 public LSL_String llTransferLindenDollars(string destination, int amount)
11624 {
11625 UUID txn = UUID.Random();
11626
11627 Util.FireAndForget(delegate(object x)
11628 {
11629 int replycode = 0;
11630 string replydata = destination + "," + amount.ToString();
11631
11632 try
11633 {
11634 TaskInventoryItem item = m_item;
11635 if (item == null)
11636 {
11637 replydata = "SERVICE_ERROR";
11638 return;
11639 }
11640
11641 m_host.AddScriptLPS(1);
11642
11643 if (item.PermsGranter == UUID.Zero)
11644 {
11645 replydata = "MISSING_PERMISSION_DEBIT";
11646 return;
11647 }
11648
11649 if ((item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0)
11650 {
11651 replydata = "MISSING_PERMISSION_DEBIT";
11652 return;
11653 }
11654
11655 UUID toID = new UUID();
11656
11657 if (!UUID.TryParse(destination, out toID))
11658 {
11659 replydata = "INVALID_AGENT";
11660 return;
11661 }
11662
11663 IMoneyModule money = World.RequestModuleInterface<IMoneyModule>();
11664
11665 if (money == null)
11666 {
11667 replydata = "TRANSFERS_DISABLED";
11668 return;
11669 }
11670
11671 bool result = money.ObjectGiveMoney(
11672 m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
11673
11674 if (result)
11675 {
11676 replycode = 1;
11677 return;
11678 }
11679
11680 replydata = "LINDENDOLLAR_INSUFFICIENTFUNDS";
11681 }
11682 finally
11683 {
11684 m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams(
11685 "transaction_result", new Object[] {
11686 new LSL_String(txn.ToString()),
11687 new LSL_Integer(replycode),
11688 new LSL_String(replydata) },
11689 new DetectParams[0]));
11690 }
11691 });
11692
11693 return txn.ToString();
11694 }
11695
11557 #endregion 11696 #endregion
11558 } 11697 }
11559 11698
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
index 98f8be7..4ac179a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs
@@ -207,7 +207,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
207 LSL_Float llGetWallclock(); 207 LSL_Float llGetWallclock();
208 void llGiveInventory(string destination, string inventory); 208 void llGiveInventory(string destination, string inventory);
209 void llGiveInventoryList(string destination, string category, LSL_List inventory); 209 void llGiveInventoryList(string destination, string category, LSL_List inventory);
210 LSL_Integer llGiveMoney(string destination, int amount); 210 void llGiveMoney(string destination, int amount);
211 LSL_String llTransferLindenDollars(string destination, int amount);
211 void llGodLikeRezObject(string inventory, LSL_Vector pos); 212 void llGodLikeRezObject(string inventory, LSL_Vector pos);
212 LSL_Float llGround(LSL_Vector offset); 213 LSL_Float llGround(LSL_Vector offset);
213 LSL_Vector llGroundContour(LSL_Vector offset); 214 LSL_Vector llGroundContour(LSL_Vector offset);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
index 36803a4..c7a7cf6 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs
@@ -869,9 +869,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
869 m_LSL_Functions.llGiveInventoryList(destination, category, inventory); 869 m_LSL_Functions.llGiveInventoryList(destination, category, inventory);
870 } 870 }
871 871
872 public LSL_Integer llGiveMoney(string destination, int amount) 872 public void llGiveMoney(string destination, int amount)
873 { 873 {
874 return m_LSL_Functions.llGiveMoney(destination, amount); 874 m_LSL_Functions.llGiveMoney(destination, amount);
875 }
876
877 public LSL_String llTransferLindenDollars(string destination, int amount)
878 {
879 return m_LSL_Functions.llTransferLindenDollars(destination, amount);
875 } 880 }
876 881
877 public void llGodLikeRezObject(string inventory, LSL_Vector pos) 882 public void llGodLikeRezObject(string inventory, LSL_Vector pos)
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index a17a018..72646f6 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -1486,7 +1486,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1486 m_MaxScriptQueue = maxScriptQueue; 1486 m_MaxScriptQueue = maxScriptQueue;
1487 1487
1488 STPStartInfo startInfo = new STPStartInfo(); 1488 STPStartInfo startInfo = new STPStartInfo();
1489 startInfo.IdleTimeout = idleTimeout*1000; // convert to seconds as stated in .ini 1489 startInfo.ThreadPoolName = "XEngine";
1490 startInfo.IdleTimeout = idleTimeout * 1000; // convert to seconds as stated in .ini
1490 startInfo.MaxWorkerThreads = maxThreads; 1491 startInfo.MaxWorkerThreads = maxThreads;
1491 startInfo.MinWorkerThreads = minThreads; 1492 startInfo.MinWorkerThreads = minThreads;
1492 startInfo.ThreadPriority = threadPriority;; 1493 startInfo.ThreadPriority = threadPriority;;
@@ -1494,7 +1495,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1494 startInfo.StartSuspended = true; 1495 startInfo.StartSuspended = true;
1495 1496
1496 m_ThreadPool = new SmartThreadPool(startInfo); 1497 m_ThreadPool = new SmartThreadPool(startInfo);
1497 m_ThreadPool.Name = "XEngine";
1498 } 1498 }
1499 1499
1500 // 1500 //