aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/Physics
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/Physics')
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs311
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs64
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs315
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs194
-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/BSAPIUnman.cs1839
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs1622
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs662
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs827
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs138
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs151
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs180
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs55
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs1383
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs329
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs392
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs312
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs200
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs347
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs582
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs386
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs76
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1513
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs946
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs1009
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs232
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs171
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs458
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs265
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs263
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt272
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs341
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs233
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs411
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs200
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs74
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs171
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs99
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs1868
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt28
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs99
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs211
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs209
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt7
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs265
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs70
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs70
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs444
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs195
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs170
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs284
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs128
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs66
-rw-r--r--OpenSim/Region/Physics/Manager/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/Physics/Manager/CollisionLocker.cs73
-rw-r--r--OpenSim/Region/Physics/Manager/IMesher.cs70
-rwxr-xr-xOpenSim/Region/Physics/Manager/IPhysicsParameters.cs73
-rw-r--r--OpenSim/Region/Physics/Manager/NullPhysicsScene.cs121
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsActor.cs567
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsJoint.cs55
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs240
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs283
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsSensor.cs78
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsVector.cs186
-rw-r--r--OpenSim/Region/Physics/Manager/VehicleConstants.cs121
-rw-r--r--OpenSim/Region/Physics/Manager/ZeroMesher.cs83
-rw-r--r--OpenSim/Region/Physics/Meshing/HelperTypes.cs436
-rw-r--r--OpenSim/Region/Physics/Meshing/Mesh.cs333
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs761
-rw-r--r--OpenSim/Region/Physics/Meshing/PrimMesher.cs2324
-rw-r--r--OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMap.cs183
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMesh.cs646
-rw-r--r--OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODECharacter.cs1411
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEDynamics.c_comments630
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEDynamics.cs974
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs3380
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs434
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdePhysicsJoint.cs48
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdePlugin.cs90
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs4323
-rw-r--r--OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs128
-rw-r--r--OpenSim/Region/Physics/OdePlugin/drawstuff.cs98
-rw-r--r--OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSCharacter.cs340
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSPlugin.cs64
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSPrim.cs335
-rw-r--r--OpenSim/Region/Physics/POSPlugin/POSScene.cs270
114 files changed, 0 insertions, 52380 deletions
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs
deleted file mode 100644
index fb9cb66..0000000
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs
+++ /dev/null
@@ -1,58 +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.Reflection;
29using System.Runtime.InteropServices;
30
31// Information about this assembly is defined by the following
32// attributes.
33//
34// change them to the information which is associated with the assembly
35// you compile.
36
37[assembly : AssemblyTitle("BasicPhysicsPlugin")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("BasicPhysicsPlugin")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.7.5.*")]
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs
deleted file mode 100644
index e43136a..0000000
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs
+++ /dev/null
@@ -1,311 +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 Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BasicPhysicsPlugin
36{
37 public class BasicActor : PhysicsActor
38 {
39 private Vector3 _size;
40
41 public BasicActor(Vector3 size)
42 {
43 Size = size;
44 }
45
46 public override int PhysicsActorType
47 {
48 get { return (int) ActorTypes.Agent; }
49 set { return; }
50 }
51
52 public override Vector3 RotationalVelocity { get; set; }
53
54 public override bool SetAlwaysRun
55 {
56 get { return false; }
57 set { return; }
58 }
59
60 public override uint LocalID
61 {
62 set { return; }
63 }
64
65 public override bool Grabbed
66 {
67 set { return; }
68 }
69
70 public override bool Selected
71 {
72 set { return; }
73 }
74
75 public override float Buoyancy
76 {
77 get { return 0f; }
78 set { return; }
79 }
80
81 public override bool FloatOnWater
82 {
83 set { return; }
84 }
85
86 public override bool IsPhysical
87 {
88 get { return false; }
89 set { return; }
90 }
91
92 public override bool ThrottleUpdates
93 {
94 get { return false; }
95 set { return; }
96 }
97
98 public override bool Flying { get; set; }
99
100 public override bool IsColliding { get; set; }
101
102 public override bool CollidingGround
103 {
104 get { return false; }
105 set { return; }
106 }
107
108 public override bool CollidingObj
109 {
110 get { return false; }
111 set { return; }
112 }
113
114 public override bool Stopped
115 {
116 get { return false; }
117 }
118
119 public override Vector3 Position { get; set; }
120
121 public override Vector3 Size
122 {
123 get { return _size; }
124 set {
125 _size = value;
126 _size.Z = _size.Z / 2.0f;
127 }
128 }
129
130 public override PrimitiveBaseShape Shape
131 {
132 set { return; }
133 }
134
135 public override float Mass
136 {
137 get { return 0f; }
138 }
139
140 public override Vector3 Force
141 {
142 get { return Vector3.Zero; }
143 set { return; }
144 }
145
146 public override int VehicleType
147 {
148 get { return 0; }
149 set { return; }
150 }
151
152 public override void VehicleFloatParam(int param, float value)
153 {
154
155 }
156
157 public override void VehicleVectorParam(int param, Vector3 value)
158 {
159
160 }
161
162 public override void VehicleRotationParam(int param, Quaternion rotation)
163 {
164
165 }
166
167 public override void VehicleFlags(int param, bool remove)
168 {
169
170 }
171
172 public override void SetVolumeDetect(int param)
173 {
174
175 }
176
177 public override Vector3 CenterOfMass
178 {
179 get { return Vector3.Zero; }
180 }
181
182 public override Vector3 GeometricCenter
183 {
184 get { return Vector3.Zero; }
185 }
186
187 public override Vector3 Velocity { get; set; }
188
189 public override Vector3 Torque
190 {
191 get { return Vector3.Zero; }
192 set { return; }
193 }
194
195 public override float CollisionScore
196 {
197 get { return 0f; }
198 set { }
199 }
200
201 public override Quaternion Orientation
202 {
203 get { return Quaternion.Identity; }
204 set { }
205 }
206
207 public override Vector3 Acceleration { get; set; }
208
209 public override bool Kinematic
210 {
211 get { return true; }
212 set { }
213 }
214
215 public override void link(PhysicsActor obj)
216 {
217 }
218
219 public override void delink()
220 {
221 }
222
223 public override void LockAngularMotion(Vector3 axis)
224 {
225 }
226
227 public override void AddForce(Vector3 force, bool pushforce)
228 {
229 }
230
231 public override void AddAngularForce(Vector3 force, bool pushforce)
232 {
233 }
234
235 public override void SetMomentum(Vector3 momentum)
236 {
237 }
238
239 public override void CrossingFailure()
240 {
241 }
242
243 public override Vector3 PIDTarget
244 {
245 set { return; }
246 }
247
248 public override bool PIDActive
249 {
250 set { return; }
251 }
252
253 public override float PIDTau
254 {
255 set { return; }
256 }
257
258 public override float PIDHoverHeight
259 {
260 set { return; }
261 }
262
263 public override bool PIDHoverActive
264 {
265 set { return; }
266 }
267
268 public override PIDHoverType PIDHoverType
269 {
270 set { return; }
271 }
272
273 public override float PIDHoverTau
274 {
275 set { return; }
276 }
277
278 public override Quaternion APIDTarget
279 {
280 set { return; }
281 }
282
283 public override bool APIDActive
284 {
285 set { return; }
286 }
287
288 public override float APIDStrength
289 {
290 set { return; }
291 }
292
293 public override float APIDDamping
294 {
295 set { return; }
296 }
297
298 public override void SubscribeEvents(int ms)
299 {
300 }
301
302 public override void UnSubscribeEvents()
303 {
304 }
305
306 public override bool SubscribedEvents()
307 {
308 return false;
309 }
310 }
311}
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs
deleted file mode 100644
index 7ab2a03..0000000
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPlugin.cs
+++ /dev/null
@@ -1,64 +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 Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33
34namespace OpenSim.Region.Physics.BasicPhysicsPlugin
35{
36 /// <summary>
37 /// Effectively a physics plugin that simulates no physics at all.
38 /// </summary>
39 public class BasicPhysicsPlugin : IPhysicsPlugin
40 {
41 public BasicPhysicsPlugin()
42 {
43 }
44
45 public bool Init()
46 {
47 return true;
48 }
49
50 public PhysicsScene GetScene(string sceneIdentifier)
51 {
52 return new BasicScene(sceneIdentifier);
53 }
54
55 public string GetName()
56 {
57 return ("basicphysics");
58 }
59
60 public void Dispose()
61 {
62 }
63 }
64}
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs
deleted file mode 100644
index 47d7df3..0000000
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs
+++ /dev/null
@@ -1,315 +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 Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BasicPhysicsPlugin
36{
37 public class BasicPhysicsPrim : PhysicsActor
38 {
39 private Vector3 _size;
40// private PrimitiveBaseShape _shape;
41
42 public BasicPhysicsPrim(
43 string name, uint localId, Vector3 position, Vector3 size, Quaternion orientation, PrimitiveBaseShape shape)
44 {
45 Name = name;
46 LocalID = localId;
47 Position = position;
48 Size = size;
49 Orientation = orientation;
50 Shape = shape;
51 }
52
53 public override int PhysicsActorType
54 {
55 get { return (int) ActorTypes.Agent; }
56 set { return; }
57 }
58
59 public override Vector3 RotationalVelocity { get; set; }
60
61 public override bool SetAlwaysRun
62 {
63 get { return false; }
64 set { return; }
65 }
66
67 public override uint LocalID
68 {
69 set { return; }
70 }
71
72 public override bool Grabbed
73 {
74 set { return; }
75 }
76
77 public override bool Selected
78 {
79 set { return; }
80 }
81
82 public override float Buoyancy
83 {
84 get { return 0f; }
85 set { return; }
86 }
87
88 public override bool FloatOnWater
89 {
90 set { return; }
91 }
92
93 public override bool IsPhysical
94 {
95 get { return false; }
96 set { return; }
97 }
98
99 public override bool ThrottleUpdates
100 {
101 get { return false; }
102 set { return; }
103 }
104
105 public override bool Flying { get; set; }
106
107 public override bool IsColliding { get; set; }
108
109 public override bool CollidingGround
110 {
111 get { return false; }
112 set { return; }
113 }
114
115 public override bool CollidingObj
116 {
117 get { return false; }
118 set { return; }
119 }
120
121 public override bool Stopped
122 {
123 get { return false; }
124 }
125
126 public override Vector3 Position { get; set; }
127
128 public override Vector3 Size
129 {
130 get { return _size; }
131 set {
132 _size = value;
133 _size.Z = _size.Z / 2.0f;
134 }
135 }
136
137 public override PrimitiveBaseShape Shape
138 {
139// set { _shape = value; }
140 set {}
141 }
142
143 public override float Mass
144 {
145 get { return 0f; }
146 }
147
148 public override Vector3 Force
149 {
150 get { return Vector3.Zero; }
151 set { return; }
152 }
153
154 public override int VehicleType
155 {
156 get { return 0; }
157 set { return; }
158 }
159
160 public override void VehicleFloatParam(int param, float value)
161 {
162
163 }
164
165 public override void VehicleVectorParam(int param, Vector3 value)
166 {
167
168 }
169
170 public override void VehicleRotationParam(int param, Quaternion rotation)
171 {
172
173 }
174
175 public override void VehicleFlags(int param, bool remove)
176 {
177
178 }
179
180 public override void SetVolumeDetect(int param)
181 {
182
183 }
184
185 public override Vector3 CenterOfMass
186 {
187 get { return Vector3.Zero; }
188 }
189
190 public override Vector3 GeometricCenter
191 {
192 get { return Vector3.Zero; }
193 }
194
195 public override Vector3 Velocity { get; set; }
196
197 public override Vector3 Torque
198 {
199 get { return Vector3.Zero; }
200 set { return; }
201 }
202
203 public override float CollisionScore
204 {
205 get { return 0f; }
206 set { }
207 }
208
209 public override Quaternion Orientation { get; set; }
210
211 public override Vector3 Acceleration { get; set; }
212
213 public override bool Kinematic
214 {
215 get { return true; }
216 set { }
217 }
218
219 public override void link(PhysicsActor obj)
220 {
221 }
222
223 public override void delink()
224 {
225 }
226
227 public override void LockAngularMotion(Vector3 axis)
228 {
229 }
230
231 public override void AddForce(Vector3 force, bool pushforce)
232 {
233 }
234
235 public override void AddAngularForce(Vector3 force, bool pushforce)
236 {
237 }
238
239 public override void SetMomentum(Vector3 momentum)
240 {
241 }
242
243 public override void CrossingFailure()
244 {
245 }
246
247 public override Vector3 PIDTarget
248 {
249 set { return; }
250 }
251
252 public override bool PIDActive
253 {
254 set { return; }
255 }
256
257 public override float PIDTau
258 {
259 set { return; }
260 }
261
262 public override float PIDHoverHeight
263 {
264 set { return; }
265 }
266
267 public override bool PIDHoverActive
268 {
269 set { return; }
270 }
271
272 public override PIDHoverType PIDHoverType
273 {
274 set { return; }
275 }
276
277 public override float PIDHoverTau
278 {
279 set { return; }
280 }
281
282 public override Quaternion APIDTarget
283 {
284 set { return; }
285 }
286
287 public override bool APIDActive
288 {
289 set { return; }
290 }
291
292 public override float APIDStrength
293 {
294 set { return; }
295 }
296
297 public override float APIDDamping
298 {
299 set { return; }
300 }
301
302 public override void SubscribeEvents(int ms)
303 {
304 }
305
306 public override void UnSubscribeEvents()
307 {
308 }
309
310 public override bool SubscribedEvents()
311 {
312 return false;
313 }
314 }
315}
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
deleted file mode 100644
index f5826ed..0000000
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
+++ /dev/null
@@ -1,194 +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 Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BasicPhysicsPlugin
36{
37 /// <summary>
38 /// This is an incomplete extremely basic physics implementation
39 /// </summary>
40 /// <remarks>
41 /// Not useful for anything at the moment apart from some regression testing in other components where some form
42 /// of physics plugin is needed.
43 /// </remarks>
44 public class BasicScene : PhysicsScene
45 {
46 private List<BasicActor> _actors = new List<BasicActor>();
47 private List<BasicPhysicsPrim> _prims = new List<BasicPhysicsPrim>();
48 private float[] _heightMap;
49
50 //protected internal string sceneIdentifier;
51
52 public BasicScene(string _sceneIdentifier)
53 {
54 //sceneIdentifier = _sceneIdentifier;
55 }
56
57 public override void Initialise(IMesher meshmerizer, IConfigSource config)
58 {
59 }
60
61 public override void Dispose() {}
62
63 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
64 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
65 {
66 BasicPhysicsPrim prim = new BasicPhysicsPrim(primName, localid, position, size, rotation, pbs);
67 prim.IsPhysical = isPhysical;
68
69 _prims.Add(prim);
70
71 return prim;
72 }
73
74 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
75 {
76 BasicActor act = new BasicActor(size);
77 act.Position = position;
78 act.Flying = isFlying;
79 _actors.Add(act);
80 return act;
81 }
82
83 public override void RemovePrim(PhysicsActor actor)
84 {
85 BasicPhysicsPrim prim = (BasicPhysicsPrim)actor;
86 if (_prims.Contains(prim))
87 _prims.Remove(prim);
88 }
89
90 public override void RemoveAvatar(PhysicsActor actor)
91 {
92 BasicActor act = (BasicActor)actor;
93 if (_actors.Contains(act))
94 _actors.Remove(act);
95 }
96
97 public override void AddPhysicsActorTaint(PhysicsActor prim)
98 {
99 }
100
101 public override float Simulate(float timeStep)
102 {
103 float fps = 0;
104 for (int i = 0; i < _actors.Count; ++i)
105 {
106 BasicActor actor = _actors[i];
107 Vector3 actorPosition = actor.Position;
108 Vector3 actorVelocity = actor.Velocity;
109
110 actorPosition.X += actor.Velocity.X*timeStep;
111 actorPosition.Y += actor.Velocity.Y*timeStep;
112
113 if (actor.Position.Y < 0)
114 {
115 actorPosition.Y = 0.1F;
116 }
117 else if (actor.Position.Y >= Constants.RegionSize)
118 {
119 actorPosition.Y = ((int)Constants.RegionSize - 0.1f);
120 }
121
122 if (actor.Position.X < 0)
123 {
124 actorPosition.X = 0.1F;
125 }
126 else if (actor.Position.X >= Constants.RegionSize)
127 {
128 actorPosition.X = ((int)Constants.RegionSize - 0.1f);
129 }
130
131 float terrainHeight = 0;
132 if (_heightMap != null)
133 terrainHeight = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X];
134
135 float height = terrainHeight + actor.Size.Z;
136
137 if (actor.Flying)
138 {
139 if (actor.Position.Z + (actor.Velocity.Z * timeStep) < terrainHeight + 2)
140 {
141 actorPosition.Z = height;
142 actorVelocity.Z = 0;
143 actor.IsColliding = true;
144 }
145 else
146 {
147 actorPosition.Z += actor.Velocity.Z * timeStep;
148 actor.IsColliding = false;
149 }
150 }
151 else
152 {
153 actorPosition.Z = height;
154 actorVelocity.Z = 0;
155 actor.IsColliding = true;
156 }
157
158 actor.Position = actorPosition;
159 actor.Velocity = actorVelocity;
160 }
161
162 return fps;
163 }
164
165 public override void GetResults()
166 {
167 }
168
169 public override bool IsThreaded
170 {
171 get { return (false); // for now we won't be multithreaded
172 }
173 }
174
175 public override void SetTerrain(float[] heightMap)
176 {
177 _heightMap = heightMap;
178 }
179
180 public override void DeleteTerrain()
181 {
182 }
183
184 public override void SetWaterLevel(float baseheight)
185 {
186 }
187
188 public override Dictionary<uint, float> GetTopColliders()
189 {
190 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
191 return returncolliders;
192 }
193 }
194}
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/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
deleted file mode 100755
index 8c6e7d6..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
+++ /dev/null
@@ -1,1839 +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 System.Runtime.InteropServices;
31using System.Security;
32using System.Text;
33
34using OpenSim.Framework;
35
36using OpenMetaverse;
37
38namespace OpenSim.Region.Physics.BulletSPlugin
39{
40public sealed class BSAPIUnman : BSAPITemplate
41{
42
43private sealed class BulletWorldUnman : BulletWorld
44{
45 public IntPtr ptr;
46 public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx)
47 : base(id, physScene)
48 {
49 ptr = xx;
50 }
51}
52
53private sealed class BulletBodyUnman : BulletBody
54{
55 public IntPtr ptr;
56 public BulletBodyUnman(uint id, IntPtr xx)
57 : base(id)
58 {
59 ptr = xx;
60 }
61 public override bool HasPhysicalBody
62 {
63 get { return ptr != IntPtr.Zero; }
64 }
65 public override void Clear()
66 {
67 ptr = IntPtr.Zero;
68 }
69 public override string AddrString
70 {
71 get { return ptr.ToString("X"); }
72 }
73}
74
75private sealed class BulletShapeUnman : BulletShape
76{
77 public IntPtr ptr;
78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
79 : base()
80 {
81 ptr = xx;
82 type = typ;
83 }
84 public override bool HasPhysicalShape
85 {
86 get { return ptr != IntPtr.Zero; }
87 }
88 public override void Clear()
89 {
90 ptr = IntPtr.Zero;
91 }
92 public override BulletShape Clone()
93 {
94 return new BulletShapeUnman(ptr, type);
95 }
96 public override bool ReferenceSame(BulletShape other)
97 {
98 BulletShapeUnman otheru = other as BulletShapeUnman;
99 return (otheru != null) && (this.ptr == otheru.ptr);
100
101 }
102 public override string AddrString
103 {
104 get { return ptr.ToString("X"); }
105 }
106}
107private sealed class BulletConstraintUnman : BulletConstraint
108{
109 public BulletConstraintUnman(IntPtr xx) : base()
110 {
111 ptr = xx;
112 }
113 public IntPtr ptr;
114
115 public override void Clear()
116 {
117 ptr = IntPtr.Zero;
118 }
119 public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } }
120
121 // Used for log messages for a unique display of the memory/object allocated to this instance
122 public override string AddrString
123 {
124 get { return ptr.ToString("X"); }
125 }
126}
127
128// We pin the memory passed between the managed and unmanaged code.
129GCHandle m_paramsHandle;
130private GCHandle m_collisionArrayPinnedHandle;
131private GCHandle m_updateArrayPinnedHandle;
132
133// Handle to the callback used by the unmanaged code to call into the managed code.
134// Used for debug logging.
135// Need to store the handle in a persistant variable so it won't be freed.
136private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle;
137
138private BSScene PhysicsScene { get; set; }
139
140public override string BulletEngineName { get { return "BulletUnmanaged"; } }
141public override string BulletEngineVersion { get; protected set; }
142
143public BSAPIUnman(string paramName, BSScene physScene)
144{
145 PhysicsScene = physScene;
146
147 // Do something fancy with the paramName to get the right DLL implementation
148 // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc.
149 if (Util.IsWindows())
150 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
151 // If not Windows, loading is performed by the
152 // Mono loader as specified in
153 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
154}
155
156// Initialization and simulation
157public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
158 int maxCollisions, ref CollisionDesc[] collisionArray,
159 int maxUpdates, ref EntityProperties[] updateArray
160 )
161{
162 // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code
163 m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned);
164 m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned);
165 m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned);
166
167 // If Debug logging level, enable logging from the unmanaged code
168 m_DebugLogCallbackHandle = null;
169 if (BSScene.m_log.IsDebugEnabled || PhysicsScene.PhysicsLogging.Enabled)
170 {
171 BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader);
172 if (PhysicsScene.PhysicsLogging.Enabled)
173 // The handle is saved in a variable to make sure it doesn't get freed after this call
174 m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog);
175 else
176 m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger);
177 }
178
179 // Get the version of the DLL
180 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
181 // BulletEngineVersion = BulletSimAPI.GetVersion2();
182 BulletEngineVersion = "";
183
184 // Call the unmanaged code with the buffers and other information
185 return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(),
186 maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
187 maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
188 m_DebugLogCallbackHandle));
189
190}
191
192// Called directly from unmanaged code so don't do much
193private void BulletLogger(string msg)
194{
195 BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg);
196}
197
198// Called directly from unmanaged code so don't do much
199private void BulletLoggerPhysLog(string msg)
200{
201 PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg);
202}
203
204public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
205 out int updatedEntityCount, out int collidersCount)
206{
207 BulletWorldUnman worldu = world as BulletWorldUnman;
208 return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount);
209}
210
211public override void Shutdown(BulletWorld world)
212{
213 BulletWorldUnman worldu = world as BulletWorldUnman;
214 BSAPICPP.Shutdown2(worldu.ptr);
215}
216
217public override bool PushUpdate(BulletBody obj)
218{
219 BulletBodyUnman bodyu = obj as BulletBodyUnman;
220 return BSAPICPP.PushUpdate2(bodyu.ptr);
221}
222
223public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value)
224{
225 BulletWorldUnman worldu = world as BulletWorldUnman;
226 return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value);
227}
228
229// =====================================================================================
230// Mesh, hull, shape and body creation helper routines
231public override BulletShape CreateMeshShape(BulletWorld world,
232 int indicesCount, int[] indices,
233 int verticesCount, float[] vertices)
234{
235 BulletWorldUnman worldu = world as BulletWorldUnman;
236 return new BulletShapeUnman(
237 BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
238 BSPhysicsShapeType.SHAPE_MESH);
239}
240
241public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
242{
243 BulletWorldUnman worldu = world as BulletWorldUnman;
244 return new BulletShapeUnman(
245 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
246 BSPhysicsShapeType.SHAPE_HULL);
247}
248
249public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
250{
251 BulletWorldUnman worldu = world as BulletWorldUnman;
252 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
253 return new BulletShapeUnman(
254 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
255 BSPhysicsShapeType.SHAPE_HULL);
256}
257
258public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
259{
260 BulletWorldUnman worldu = world as BulletWorldUnman;
261 return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type);
262}
263
264public override bool IsNativeShape(BulletShape shape)
265{
266 BulletShapeUnman shapeu = shape as BulletShapeUnman;
267 if (shapeu != null && shapeu.HasPhysicalShape)
268 return BSAPICPP.IsNativeShape2(shapeu.ptr);
269 return false;
270}
271
272public override void SetShapeCollisionMargin(BulletShape shape, float margin)
273{
274 BulletShapeUnman shapeu = shape as BulletShapeUnman;
275 if (shapeu != null && shapeu.HasPhysicalShape)
276 BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin);
277}
278
279public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
280{
281 BulletWorldUnman worldu = world as BulletWorldUnman;
282 return new BulletShapeUnman(
283 BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale),
284 BSPhysicsShapeType.SHAPE_CAPSULE);
285}
286
287public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree)
288{
289 BulletWorldUnman worldu = world as BulletWorldUnman;
290 return new BulletShapeUnman(
291 BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree),
292 BSPhysicsShapeType.SHAPE_COMPOUND);
293
294}
295
296public override int GetNumberOfCompoundChildren(BulletShape shape)
297{
298 BulletShapeUnman shapeu = shape as BulletShapeUnman;
299 if (shapeu != null && shapeu.HasPhysicalShape)
300 return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr);
301 return 0;
302}
303
304public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot)
305{
306 BulletShapeUnman shapeu = shape as BulletShapeUnman;
307 BulletShapeUnman addShapeu = addShape as BulletShapeUnman;
308 BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot);
309}
310
311public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
312{
313 BulletShapeUnman shapeu = shape as BulletShapeUnman;
314 return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
315}
316
317public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
318{
319 BulletShapeUnman shapeu = shape as BulletShapeUnman;
320 return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
321}
322
323public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape)
324{
325 BulletShapeUnman shapeu = shape as BulletShapeUnman;
326 BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman;
327 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
328}
329
330public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
331{
332 BulletShapeUnman shapeu = shape as BulletShapeUnman;
333 BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr);
334}
335
336public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id)
337{
338 BulletWorldUnman worldu = world as BulletWorldUnman;
339 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
340 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type);
341}
342
343public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
344{
345 BulletWorldUnman worldu = world as BulletWorldUnman;
346 BulletShapeUnman shapeu = shape as BulletShapeUnman;
347 return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr);
348}
349
350public override CollisionObjectTypes GetBodyType(BulletBody obj)
351{
352 BulletBodyUnman bodyu = obj as BulletBodyUnman;
353 return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr);
354}
355
356public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
357{
358 BulletWorldUnman worldu = world as BulletWorldUnman;
359 BulletShapeUnman shapeu = shape as BulletShapeUnman;
360 return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
361}
362
363public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot)
364{
365 BulletShapeUnman shapeu = shape as BulletShapeUnman;
366 return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot));
367}
368
369public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
370{
371 BulletWorldUnman worldu = world as BulletWorldUnman;
372 BulletShapeUnman shapeu = shape as BulletShapeUnman;
373 return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
374}
375
376public override void DestroyObject(BulletWorld world, BulletBody obj)
377{
378 BulletWorldUnman worldu = world as BulletWorldUnman;
379 BulletBodyUnman bodyu = obj as BulletBodyUnman;
380 BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr);
381}
382
383// =====================================================================================
384// Terrain creation and helper routines
385public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin)
386{
387 return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE);
388}
389
390public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
391 float scaleFactor, float collisionMargin)
392{
393 return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin),
394 BSPhysicsShapeType.SHAPE_TERRAIN);
395}
396
397// =====================================================================================
398// Constraint creation and helper routines
399public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
400 Vector3 frame1loc, Quaternion frame1rot,
401 Vector3 frame2loc, Quaternion frame2rot,
402 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
403{
404 BulletWorldUnman worldu = world as BulletWorldUnman;
405 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
406 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
407 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
408 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
409}
410
411public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
412 Vector3 joinPoint,
413 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
414{
415 BulletWorldUnman worldu = world as BulletWorldUnman;
416 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
417 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
418 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
419 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
420}
421
422public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
423 Vector3 pivotinA, Vector3 pivotinB,
424 Vector3 axisInA, Vector3 axisInB,
425 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
426{
427 BulletWorldUnman worldu = world as BulletWorldUnman;
428 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
429 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
430 return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
431 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
432}
433
434public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
435{
436 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
437 BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse);
438}
439
440public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations)
441{
442 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
443 BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations);
444}
445
446public override bool SetFrames(BulletConstraint constrain,
447 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
448{
449 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
450 return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot);
451}
452
453public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
454{
455 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
456 return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi);
457}
458
459public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
460{
461 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
462 return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi);
463}
464
465public override bool UseFrameOffset(BulletConstraint constrain, float enable)
466{
467 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
468 return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable);
469}
470
471public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce)
472{
473 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
474 return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce);
475}
476
477public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold)
478{
479 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
480 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
481}
482
483public override bool CalculateTransforms(BulletConstraint constrain)
484{
485 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
486 return BSAPICPP.CalculateTransforms2(constrainu.ptr);
487}
488
489public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis)
490{
491 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
492 return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis);
493}
494
495public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain)
496{
497 BulletWorldUnman worldu = world as BulletWorldUnman;
498 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
499 return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr);
500}
501
502// =====================================================================================
503// btCollisionWorld entries
504public override void UpdateSingleAabb(BulletWorld world, BulletBody obj)
505{
506 BulletWorldUnman worldu = world as BulletWorldUnman;
507 BulletBodyUnman bodyu = obj as BulletBodyUnman;
508 BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr);
509}
510
511public override void UpdateAabbs(BulletWorld world)
512{
513 BulletWorldUnman worldu = world as BulletWorldUnman;
514 BSAPICPP.UpdateAabbs2(worldu.ptr);
515}
516
517public override bool GetForceUpdateAllAabbs(BulletWorld world)
518{
519 BulletWorldUnman worldu = world as BulletWorldUnman;
520 return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr);
521}
522
523public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
524{
525 BulletWorldUnman worldu = world as BulletWorldUnman;
526 BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force);
527}
528
529// =====================================================================================
530// btDynamicsWorld entries
531public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
532{
533 // Bullet resets several variables when an object is added to the world.
534 // Gravity is reset to world default depending on the static/dynamic
535 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
536 BulletWorldUnman worldu = world as BulletWorldUnman;
537 BulletBodyUnman bodyu = obj as BulletBodyUnman;
538
539 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
540
541 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
542
543 if (ret)
544 {
545 BSAPICPP.SetGravity2(bodyu.ptr, origGrav);
546 obj.ApplyCollisionMask(world.physicsScene);
547 }
548 return ret;
549}
550
551public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
552{
553 BulletWorldUnman worldu = world as BulletWorldUnman;
554 BulletBodyUnman bodyu = obj as BulletBodyUnman;
555 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
556}
557
558public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
559{
560 BulletWorldUnman worldu = world as BulletWorldUnman;
561 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
562 return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects);
563}
564
565public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
566{
567 BulletWorldUnman worldu = world as BulletWorldUnman;
568 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
569 return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr);
570}
571// =====================================================================================
572// btCollisionObject entries
573public override Vector3 GetAnisotripicFriction(BulletConstraint constrain)
574{
575 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
576 return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr);
577}
578
579public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict)
580{
581 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
582 return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict);
583}
584
585public override bool HasAnisotripicFriction(BulletConstraint constrain)
586{
587 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
588 return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr);
589}
590
591public override void SetContactProcessingThreshold(BulletBody obj, float val)
592{
593 BulletBodyUnman bodyu = obj as BulletBodyUnman;
594 BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val);
595}
596
597public override float GetContactProcessingThreshold(BulletBody obj)
598{
599 BulletBodyUnman bodyu = obj as BulletBodyUnman;
600 return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr);
601}
602
603public override bool IsStaticObject(BulletBody obj)
604{
605 BulletBodyUnman bodyu = obj as BulletBodyUnman;
606 return BSAPICPP.IsStaticObject2(bodyu.ptr);
607}
608
609public override bool IsKinematicObject(BulletBody obj)
610{
611 BulletBodyUnman bodyu = obj as BulletBodyUnman;
612 return BSAPICPP.IsKinematicObject2(bodyu.ptr);
613}
614
615public override bool IsStaticOrKinematicObject(BulletBody obj)
616{
617 BulletBodyUnman bodyu = obj as BulletBodyUnman;
618 return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr);
619}
620
621public override bool HasContactResponse(BulletBody obj)
622{
623 BulletBodyUnman bodyu = obj as BulletBodyUnman;
624 return BSAPICPP.HasContactResponse2(bodyu.ptr);
625}
626
627public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape)
628{
629 BulletWorldUnman worldu = world as BulletWorldUnman;
630 BulletBodyUnman bodyu = obj as BulletBodyUnman;
631 BulletShapeUnman shapeu = shape as BulletShapeUnman;
632 if (worldu != null && bodyu != null)
633 {
634 // Special case to allow the caller to zero out the reference to any physical shape
635 if (shapeu != null)
636 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr);
637 else
638 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero);
639 }
640}
641
642public override BulletShape GetCollisionShape(BulletBody obj)
643{
644 BulletBodyUnman bodyu = obj as BulletBodyUnman;
645 return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN);
646}
647
648public override int GetActivationState(BulletBody obj)
649{
650 BulletBodyUnman bodyu = obj as BulletBodyUnman;
651 return BSAPICPP.GetActivationState2(bodyu.ptr);
652}
653
654public override void SetActivationState(BulletBody obj, int state)
655{
656 BulletBodyUnman bodyu = obj as BulletBodyUnman;
657 BSAPICPP.SetActivationState2(bodyu.ptr, state);
658}
659
660public override void SetDeactivationTime(BulletBody obj, float dtime)
661{
662 BulletBodyUnman bodyu = obj as BulletBodyUnman;
663 BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime);
664}
665
666public override float GetDeactivationTime(BulletBody obj)
667{
668 BulletBodyUnman bodyu = obj as BulletBodyUnman;
669 return BSAPICPP.GetDeactivationTime2(bodyu.ptr);
670}
671
672public override void ForceActivationState(BulletBody obj, ActivationState state)
673{
674 BulletBodyUnman bodyu = obj as BulletBodyUnman;
675 BSAPICPP.ForceActivationState2(bodyu.ptr, state);
676}
677
678public override void Activate(BulletBody obj, bool forceActivation)
679{
680 BulletBodyUnman bodyu = obj as BulletBodyUnman;
681 BSAPICPP.Activate2(bodyu.ptr, forceActivation);
682}
683
684public override bool IsActive(BulletBody obj)
685{
686 BulletBodyUnman bodyu = obj as BulletBodyUnman;
687 return BSAPICPP.IsActive2(bodyu.ptr);
688}
689
690public override void SetRestitution(BulletBody obj, float val)
691{
692 BulletBodyUnman bodyu = obj as BulletBodyUnman;
693 BSAPICPP.SetRestitution2(bodyu.ptr, val);
694}
695
696public override float GetRestitution(BulletBody obj)
697{
698 BulletBodyUnman bodyu = obj as BulletBodyUnman;
699 return BSAPICPP.GetRestitution2(bodyu.ptr);
700}
701
702public override void SetFriction(BulletBody obj, float val)
703{
704 BulletBodyUnman bodyu = obj as BulletBodyUnman;
705 BSAPICPP.SetFriction2(bodyu.ptr, val);
706}
707
708public override float GetFriction(BulletBody obj)
709{
710 BulletBodyUnman bodyu = obj as BulletBodyUnman;
711 return BSAPICPP.GetFriction2(bodyu.ptr);
712}
713
714public override Vector3 GetPosition(BulletBody obj)
715{
716 BulletBodyUnman bodyu = obj as BulletBodyUnman;
717 return BSAPICPP.GetPosition2(bodyu.ptr);
718}
719
720public override Quaternion GetOrientation(BulletBody obj)
721{
722 BulletBodyUnman bodyu = obj as BulletBodyUnman;
723 return BSAPICPP.GetOrientation2(bodyu.ptr);
724}
725
726public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation)
727{
728 BulletBodyUnman bodyu = obj as BulletBodyUnman;
729 BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation);
730}
731
732 /*
733public override IntPtr GetBroadphaseHandle(BulletBody obj)
734{
735 BulletBodyUnman bodyu = obj as BulletBodyUnman;
736 return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr);
737}
738
739public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle)
740{
741 BulletBodyUnman bodyu = obj as BulletBodyUnman;
742 BSAPICPP.SetUserPointer2(bodyu.ptr, handle);
743}
744 */
745
746public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel)
747{
748 BulletBodyUnman bodyu = obj as BulletBodyUnman;
749 BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel);
750}
751
752public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel)
753{
754 BulletBodyUnman bodyu = obj as BulletBodyUnman;
755 BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel);
756}
757
758public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel)
759{
760 BulletBodyUnman bodyu = obj as BulletBodyUnman;
761 BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel);
762}
763
764public override float GetHitFraction(BulletBody obj)
765{
766 BulletBodyUnman bodyu = obj as BulletBodyUnman;
767 return BSAPICPP.GetHitFraction2(bodyu.ptr);
768}
769
770public override void SetHitFraction(BulletBody obj, float val)
771{
772 BulletBodyUnman bodyu = obj as BulletBodyUnman;
773 BSAPICPP.SetHitFraction2(bodyu.ptr, val);
774}
775
776public override CollisionFlags GetCollisionFlags(BulletBody obj)
777{
778 BulletBodyUnman bodyu = obj as BulletBodyUnman;
779 return BSAPICPP.GetCollisionFlags2(bodyu.ptr);
780}
781
782public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags)
783{
784 BulletBodyUnman bodyu = obj as BulletBodyUnman;
785 return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags);
786}
787
788public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags)
789{
790 BulletBodyUnman bodyu = obj as BulletBodyUnman;
791 return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags);
792}
793
794public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags)
795{
796 BulletBodyUnman bodyu = obj as BulletBodyUnman;
797 return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags);
798}
799
800public override float GetCcdMotionThreshold(BulletBody obj)
801{
802 BulletBodyUnman bodyu = obj as BulletBodyUnman;
803 return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr);
804}
805
806
807public override void SetCcdMotionThreshold(BulletBody obj, float val)
808{
809 BulletBodyUnman bodyu = obj as BulletBodyUnman;
810 BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val);
811}
812
813public override float GetCcdSweptSphereRadius(BulletBody obj)
814{
815 BulletBodyUnman bodyu = obj as BulletBodyUnman;
816 return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr);
817}
818
819public override void SetCcdSweptSphereRadius(BulletBody obj, float val)
820{
821 BulletBodyUnman bodyu = obj as BulletBodyUnman;
822 BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val);
823}
824
825public override IntPtr GetUserPointer(BulletBody obj)
826{
827 BulletBodyUnman bodyu = obj as BulletBodyUnman;
828 return BSAPICPP.GetUserPointer2(bodyu.ptr);
829}
830
831public override void SetUserPointer(BulletBody obj, IntPtr val)
832{
833 BulletBodyUnman bodyu = obj as BulletBodyUnman;
834 BSAPICPP.SetUserPointer2(bodyu.ptr, val);
835}
836
837// =====================================================================================
838// btRigidBody entries
839public override void ApplyGravity(BulletBody obj)
840{
841 BulletBodyUnman bodyu = obj as BulletBodyUnman;
842 BSAPICPP.ApplyGravity2(bodyu.ptr);
843}
844
845public override void SetGravity(BulletBody obj, Vector3 val)
846{
847 BulletBodyUnman bodyu = obj as BulletBodyUnman;
848 BSAPICPP.SetGravity2(bodyu.ptr, val);
849}
850
851public override Vector3 GetGravity(BulletBody obj)
852{
853 BulletBodyUnman bodyu = obj as BulletBodyUnman;
854 return BSAPICPP.GetGravity2(bodyu.ptr);
855}
856
857public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping)
858{
859 BulletBodyUnman bodyu = obj as BulletBodyUnman;
860 BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping);
861}
862
863public override void SetLinearDamping(BulletBody obj, float lin_damping)
864{
865 BulletBodyUnman bodyu = obj as BulletBodyUnman;
866 BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping);
867}
868
869public override void SetAngularDamping(BulletBody obj, float ang_damping)
870{
871 BulletBodyUnman bodyu = obj as BulletBodyUnman;
872 BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping);
873}
874
875public override float GetLinearDamping(BulletBody obj)
876{
877 BulletBodyUnman bodyu = obj as BulletBodyUnman;
878 return BSAPICPP.GetLinearDamping2(bodyu.ptr);
879}
880
881public override float GetAngularDamping(BulletBody obj)
882{
883 BulletBodyUnman bodyu = obj as BulletBodyUnman;
884 return BSAPICPP.GetAngularDamping2(bodyu.ptr);
885}
886
887public override float GetLinearSleepingThreshold(BulletBody obj)
888{
889 BulletBodyUnman bodyu = obj as BulletBodyUnman;
890 return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr);
891}
892
893public override void ApplyDamping(BulletBody obj, float timeStep)
894{
895 BulletBodyUnman bodyu = obj as BulletBodyUnman;
896 BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep);
897}
898
899public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia)
900{
901 BulletBodyUnman bodyu = obj as BulletBodyUnman;
902 BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia);
903}
904
905public override Vector3 GetLinearFactor(BulletBody obj)
906{
907 BulletBodyUnman bodyu = obj as BulletBodyUnman;
908 return BSAPICPP.GetLinearFactor2(bodyu.ptr);
909}
910
911public override void SetLinearFactor(BulletBody obj, Vector3 factor)
912{
913 BulletBodyUnman bodyu = obj as BulletBodyUnman;
914 BSAPICPP.SetLinearFactor2(bodyu.ptr, factor);
915}
916
917public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot)
918{
919 BulletBodyUnman bodyu = obj as BulletBodyUnman;
920 BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot);
921}
922
923// Add a force to the object as if its mass is one.
924public override void ApplyCentralForce(BulletBody obj, Vector3 force)
925{
926 BulletBodyUnman bodyu = obj as BulletBodyUnman;
927 BSAPICPP.ApplyCentralForce2(bodyu.ptr, force);
928}
929
930// Set the force being applied to the object as if its mass is one.
931public override void SetObjectForce(BulletBody obj, Vector3 force)
932{
933 BulletBodyUnman bodyu = obj as BulletBodyUnman;
934 BSAPICPP.SetObjectForce2(bodyu.ptr, force);
935}
936
937public override Vector3 GetTotalForce(BulletBody obj)
938{
939 BulletBodyUnman bodyu = obj as BulletBodyUnman;
940 return BSAPICPP.GetTotalForce2(bodyu.ptr);
941}
942
943public override Vector3 GetTotalTorque(BulletBody obj)
944{
945 BulletBodyUnman bodyu = obj as BulletBodyUnman;
946 return BSAPICPP.GetTotalTorque2(bodyu.ptr);
947}
948
949public override Vector3 GetInvInertiaDiagLocal(BulletBody obj)
950{
951 BulletBodyUnman bodyu = obj as BulletBodyUnman;
952 return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr);
953}
954
955public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert)
956{
957 BulletBodyUnman bodyu = obj as BulletBodyUnman;
958 BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert);
959}
960
961public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold)
962{
963 BulletBodyUnman bodyu = obj as BulletBodyUnman;
964 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
965}
966
967public override void ApplyTorque(BulletBody obj, Vector3 torque)
968{
969 BulletBodyUnman bodyu = obj as BulletBodyUnman;
970 BSAPICPP.ApplyTorque2(bodyu.ptr, torque);
971}
972
973// Apply force at the given point. Will add torque to the object.
974public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
975{
976 BulletBodyUnman bodyu = obj as BulletBodyUnman;
977 BSAPICPP.ApplyForce2(bodyu.ptr, force, pos);
978}
979
980// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
981public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
982{
983 BulletBodyUnman bodyu = obj as BulletBodyUnman;
984 BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp);
985}
986
987// Apply impulse to the object's torque. Force is scaled by object's mass.
988public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
989{
990 BulletBodyUnman bodyu = obj as BulletBodyUnman;
991 BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp);
992}
993
994// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
995public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
996{
997 BulletBodyUnman bodyu = obj as BulletBodyUnman;
998 BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos);
999}
1000
1001public override void ClearForces(BulletBody obj)
1002{
1003 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1004 BSAPICPP.ClearForces2(bodyu.ptr);
1005}
1006
1007public override void ClearAllForces(BulletBody obj)
1008{
1009 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1010 BSAPICPP.ClearAllForces2(bodyu.ptr);
1011}
1012
1013public override void UpdateInertiaTensor(BulletBody obj)
1014{
1015 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1016 BSAPICPP.UpdateInertiaTensor2(bodyu.ptr);
1017}
1018
1019public override Vector3 GetLinearVelocity(BulletBody obj)
1020{
1021 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1022 return BSAPICPP.GetLinearVelocity2(bodyu.ptr);
1023}
1024
1025public override Vector3 GetAngularVelocity(BulletBody obj)
1026{
1027 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1028 return BSAPICPP.GetAngularVelocity2(bodyu.ptr);
1029}
1030
1031public override void SetLinearVelocity(BulletBody obj, Vector3 vel)
1032{
1033 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1034 BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel);
1035}
1036
1037public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity)
1038{
1039 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1040 BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity);
1041}
1042
1043public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos)
1044{
1045 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1046 return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos);
1047}
1048
1049public override void Translate(BulletBody obj, Vector3 trans)
1050{
1051 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1052 BSAPICPP.Translate2(bodyu.ptr, trans);
1053}
1054
1055public override void UpdateDeactivation(BulletBody obj, float timeStep)
1056{
1057 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1058 BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep);
1059}
1060
1061public override bool WantsSleeping(BulletBody obj)
1062{
1063 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1064 return BSAPICPP.WantsSleeping2(bodyu.ptr);
1065}
1066
1067public override void SetAngularFactor(BulletBody obj, float factor)
1068{
1069 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1070 BSAPICPP.SetAngularFactor2(bodyu.ptr, factor);
1071}
1072
1073public override void SetAngularFactorV(BulletBody obj, Vector3 factor)
1074{
1075 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1076 BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor);
1077}
1078
1079public override Vector3 GetAngularFactor(BulletBody obj)
1080{
1081 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1082 return BSAPICPP.GetAngularFactor2(bodyu.ptr);
1083}
1084
1085public override bool IsInWorld(BulletWorld world, BulletBody obj)
1086{
1087 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1088 return BSAPICPP.IsInWorld2(bodyu.ptr);
1089}
1090
1091public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain)
1092{
1093 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1094 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1095 BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr);
1096}
1097
1098public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain)
1099{
1100 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1101 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1102 BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr);
1103}
1104
1105public override BulletConstraint GetConstraintRef(BulletBody obj, int index)
1106{
1107 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1108 return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index));
1109}
1110
1111public override int GetNumConstraintRefs(BulletBody obj)
1112{
1113 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1114 return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr);
1115}
1116
1117public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask)
1118{
1119 BulletBodyUnman bodyu = body as BulletBodyUnman;
1120 return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask);
1121}
1122
1123// =====================================================================================
1124// btCollisionShape entries
1125
1126public override float GetAngularMotionDisc(BulletShape shape)
1127{
1128 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1129 return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr);
1130}
1131
1132public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor)
1133{
1134 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1135 return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor);
1136}
1137
1138public override bool IsPolyhedral(BulletShape shape)
1139{
1140 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1141 return BSAPICPP.IsPolyhedral2(shapeu.ptr);
1142}
1143
1144public override bool IsConvex2d(BulletShape shape)
1145{
1146 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1147 return BSAPICPP.IsConvex2d2(shapeu.ptr);
1148}
1149
1150public override bool IsConvex(BulletShape shape)
1151{
1152 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1153 return BSAPICPP.IsConvex2(shapeu.ptr);
1154}
1155
1156public override bool IsNonMoving(BulletShape shape)
1157{
1158 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1159 return BSAPICPP.IsNonMoving2(shapeu.ptr);
1160}
1161
1162public override bool IsConcave(BulletShape shape)
1163{
1164 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1165 return BSAPICPP.IsConcave2(shapeu.ptr);
1166}
1167
1168public override bool IsCompound(BulletShape shape)
1169{
1170 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1171 return BSAPICPP.IsCompound2(shapeu.ptr);
1172}
1173
1174public override bool IsSoftBody(BulletShape shape)
1175{
1176 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1177 return BSAPICPP.IsSoftBody2(shapeu.ptr);
1178}
1179
1180public override bool IsInfinite(BulletShape shape)
1181{
1182 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1183 return BSAPICPP.IsInfinite2(shapeu.ptr);
1184}
1185
1186public override void SetLocalScaling(BulletShape shape, Vector3 scale)
1187{
1188 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1189 BSAPICPP.SetLocalScaling2(shapeu.ptr, scale);
1190}
1191
1192public override Vector3 GetLocalScaling(BulletShape shape)
1193{
1194 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1195 return BSAPICPP.GetLocalScaling2(shapeu.ptr);
1196}
1197
1198public override Vector3 CalculateLocalInertia(BulletShape shape, float mass)
1199{
1200 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1201 return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass);
1202}
1203
1204public override int GetShapeType(BulletShape shape)
1205{
1206 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1207 return BSAPICPP.GetShapeType2(shapeu.ptr);
1208}
1209
1210public override void SetMargin(BulletShape shape, float val)
1211{
1212 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1213 BSAPICPP.SetMargin2(shapeu.ptr, val);
1214}
1215
1216public override float GetMargin(BulletShape shape)
1217{
1218 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1219 return BSAPICPP.GetMargin2(shapeu.ptr);
1220}
1221
1222// =====================================================================================
1223// Debugging
1224public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
1225{
1226 BulletWorldUnman worldu = world as BulletWorldUnman;
1227 BulletBodyUnman bodyu = collisionObject as BulletBodyUnman;
1228 BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr);
1229}
1230
1231public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape)
1232{
1233 BulletWorldUnman worldu = world as BulletWorldUnman;
1234 BulletShapeUnman shapeu = collisionShape as BulletShapeUnman;
1235 BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr);
1236}
1237
1238public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
1239{
1240 BulletWorldUnman worldu = world as BulletWorldUnman;
1241 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1242 BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr);
1243}
1244
1245public override void DumpActivationInfo(BulletWorld world)
1246{
1247 BulletWorldUnman worldu = world as BulletWorldUnman;
1248 BSAPICPP.DumpActivationInfo2(worldu.ptr);
1249}
1250
1251public override void DumpAllInfo(BulletWorld world)
1252{
1253 BulletWorldUnman worldu = world as BulletWorldUnman;
1254 BSAPICPP.DumpAllInfo2(worldu.ptr);
1255}
1256
1257public override void DumpPhysicsStatistics(BulletWorld world)
1258{
1259 BulletWorldUnman worldu = world as BulletWorldUnman;
1260 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1261}
1262
1263// =====================================================================================
1264// =====================================================================================
1265// =====================================================================================
1266// =====================================================================================
1267// =====================================================================================
1268// The actual interface to the unmanaged code
1269static class BSAPICPP
1270{
1271// ===============================================================================
1272// Link back to the managed code for outputting log messages
1273[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1274public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
1275
1276// ===============================================================================
1277// Initialization and simulation
1278[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1279public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
1280 int maxCollisions, IntPtr collisionArray,
1281 int maxUpdates, IntPtr updateArray,
1282 DebugLogCallback logRoutine);
1283
1284[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1285public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
1286 out int updatedEntityCount, out int collidersCount);
1287
1288[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1289public static extern void Shutdown2(IntPtr sim);
1290
1291[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1292public static extern bool PushUpdate2(IntPtr obj);
1293
1294[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1295public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
1296
1297// =====================================================================================
1298// Mesh, hull, shape and body creation helper routines
1299[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1300public static extern IntPtr CreateMeshShape2(IntPtr world,
1301 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1302 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1303
1304[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1305public static extern IntPtr CreateHullShape2(IntPtr world,
1306 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1307
1308[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1309public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1310
1311[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1312public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
1313
1314[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1315public static extern bool IsNativeShape2(IntPtr shape);
1316
1317[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1318public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin);
1319
1320[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1321public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
1322
1323[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1324public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
1325
1326[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1327public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
1328
1329[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1330public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
1331
1332[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1333public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1334
1335[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1336public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1337
1338[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1339public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1340
1341[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1342public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1343
1344[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1345public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
1346
1347[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1348public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
1349
1350[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1351public static extern int GetBodyType2(IntPtr obj);
1352
1353[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1354public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1355
1356[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1357public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1358
1359[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1360public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1361
1362[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1363public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1364
1365// =====================================================================================
1366// Terrain creation and helper routines
1367[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1368public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1369
1370[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1371public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1372 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1373 float scaleFactor, float collisionMargin);
1374
1375// =====================================================================================
1376// Constraint creation and helper routines
1377[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1378public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1379 Vector3 frame1loc, Quaternion frame1rot,
1380 Vector3 frame2loc, Quaternion frame2rot,
1381 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1382
1383[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1384public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1385 Vector3 joinPoint,
1386 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1387
1388[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1389public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1390 Vector3 pivotinA, Vector3 pivotinB,
1391 Vector3 axisInA, Vector3 axisInB,
1392 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1393
1394[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1395public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1396
1397[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1398public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
1399
1400[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1401public static extern bool SetFrames2(IntPtr constrain,
1402 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
1403
1404[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1405public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1406
1407[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1408public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1409
1410[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1411public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
1412
1413[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1414public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
1415
1416[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1417public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1418
1419[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1420public static extern bool CalculateTransforms2(IntPtr constrain);
1421
1422[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1423public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
1424
1425[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1426public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
1427
1428// =====================================================================================
1429// btCollisionWorld entries
1430[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1431public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
1432
1433[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1434public static extern void UpdateAabbs2(IntPtr world);
1435
1436[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1437public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
1438
1439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1440public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
1441
1442// =====================================================================================
1443// btDynamicsWorld entries
1444[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1445public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1446
1447[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1448public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1449
1450[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1451public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1452
1453[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1454public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
1455// =====================================================================================
1456// btCollisionObject entries
1457[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1458public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
1459
1460[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1461public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
1462
1463[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1464public static extern bool HasAnisotripicFriction2(IntPtr constrain);
1465
1466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1467public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
1468
1469[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1470public static extern float GetContactProcessingThreshold2(IntPtr obj);
1471
1472[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1473public static extern bool IsStaticObject2(IntPtr obj);
1474
1475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1476public static extern bool IsKinematicObject2(IntPtr obj);
1477
1478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1479public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
1480
1481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1482public static extern bool HasContactResponse2(IntPtr obj);
1483
1484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1485public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
1486
1487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1488public static extern IntPtr GetCollisionShape2(IntPtr obj);
1489
1490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1491public static extern int GetActivationState2(IntPtr obj);
1492
1493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1494public static extern void SetActivationState2(IntPtr obj, int state);
1495
1496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1497public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
1498
1499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1500public static extern float GetDeactivationTime2(IntPtr obj);
1501
1502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1503public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
1504
1505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1506public static extern void Activate2(IntPtr obj, bool forceActivation);
1507
1508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1509public static extern bool IsActive2(IntPtr obj);
1510
1511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1512public static extern void SetRestitution2(IntPtr obj, float val);
1513
1514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1515public static extern float GetRestitution2(IntPtr obj);
1516
1517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1518public static extern void SetFriction2(IntPtr obj, float val);
1519
1520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1521public static extern float GetFriction2(IntPtr obj);
1522
1523 /* Haven't defined the type 'Transform'
1524[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1525public static extern Transform GetWorldTransform2(IntPtr obj);
1526
1527[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1528public static extern void setWorldTransform2(IntPtr obj, Transform trans);
1529 */
1530
1531[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1532public static extern Vector3 GetPosition2(IntPtr obj);
1533
1534[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1535public static extern Quaternion GetOrientation2(IntPtr obj);
1536
1537[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1538public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
1539
1540[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1541public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
1542
1543[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1544public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
1545
1546 /*
1547[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1548public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
1549
1550[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1551public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
1552 */
1553
1554[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1555public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
1556
1557[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1558public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
1559
1560[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1561public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
1562
1563[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1564public static extern float GetHitFraction2(IntPtr obj);
1565
1566[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1567public static extern void SetHitFraction2(IntPtr obj, float val);
1568
1569[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1570public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
1571
1572[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1573public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
1574
1575[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1576public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
1577
1578[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1579public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
1580
1581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1582public static extern float GetCcdMotionThreshold2(IntPtr obj);
1583
1584[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1585public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
1586
1587[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1588public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
1589
1590[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1591public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
1592
1593[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1594public static extern IntPtr GetUserPointer2(IntPtr obj);
1595
1596[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1597public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
1598
1599// =====================================================================================
1600// btRigidBody entries
1601[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1602public static extern void ApplyGravity2(IntPtr obj);
1603
1604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1605public static extern void SetGravity2(IntPtr obj, Vector3 val);
1606
1607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1608public static extern Vector3 GetGravity2(IntPtr obj);
1609
1610[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1611public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
1612
1613[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1614public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
1615
1616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1617public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
1618
1619[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1620public static extern float GetLinearDamping2(IntPtr obj);
1621
1622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1623public static extern float GetAngularDamping2(IntPtr obj);
1624
1625[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1626public static extern float GetLinearSleepingThreshold2(IntPtr obj);
1627
1628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1629public static extern float GetAngularSleepingThreshold2(IntPtr obj);
1630
1631[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1632public static extern void ApplyDamping2(IntPtr obj, float timeStep);
1633
1634[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1635public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
1636
1637[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1638public static extern Vector3 GetLinearFactor2(IntPtr obj);
1639
1640[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1641public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
1642
1643 /*
1644[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1645public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
1646 */
1647
1648[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1649public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
1650
1651// Add a force to the object as if its mass is one.
1652[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1653public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
1654
1655// Set the force being applied to the object as if its mass is one.
1656[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1657public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
1658
1659[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1660public static extern Vector3 GetTotalForce2(IntPtr obj);
1661
1662[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1663public static extern Vector3 GetTotalTorque2(IntPtr obj);
1664
1665[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1666public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
1667
1668[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1669public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
1670
1671[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1672public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
1673
1674[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1675public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
1676
1677// Apply force at the given point. Will add torque to the object.
1678[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1679public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
1680
1681// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1682[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1683public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
1684
1685// Apply impulse to the object's torque. Force is scaled by object's mass.
1686[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1687public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
1688
1689// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1690[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1691public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
1692
1693[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1694public static extern void ClearForces2(IntPtr obj);
1695
1696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1697public static extern void ClearAllForces2(IntPtr obj);
1698
1699[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1700public static extern void UpdateInertiaTensor2(IntPtr obj);
1701
1702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1703public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
1704
1705 /*
1706[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1707public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
1708 */
1709
1710[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1711public static extern Vector3 GetLinearVelocity2(IntPtr obj);
1712
1713[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1714public static extern Vector3 GetAngularVelocity2(IntPtr obj);
1715
1716[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1717public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1718
1719[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1720public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1721
1722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1723public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1724
1725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1726public static extern void Translate2(IntPtr obj, Vector3 trans);
1727
1728[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1729public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1730
1731[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1732public static extern bool WantsSleeping2(IntPtr obj);
1733
1734[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1735public static extern void SetAngularFactor2(IntPtr obj, float factor);
1736
1737[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1738public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1739
1740[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1741public static extern Vector3 GetAngularFactor2(IntPtr obj);
1742
1743[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1744public static extern bool IsInWorld2(IntPtr obj);
1745
1746[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1747public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1748
1749[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1750public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1751
1752[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1753public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1754
1755[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1756public static extern int GetNumConstraintRefs2(IntPtr obj);
1757
1758[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1759public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
1760
1761// =====================================================================================
1762// btCollisionShape entries
1763
1764[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1765public static extern float GetAngularMotionDisc2(IntPtr shape);
1766
1767[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1768public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1769
1770[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1771public static extern bool IsPolyhedral2(IntPtr shape);
1772
1773[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1774public static extern bool IsConvex2d2(IntPtr shape);
1775
1776[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1777public static extern bool IsConvex2(IntPtr shape);
1778
1779[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1780public static extern bool IsNonMoving2(IntPtr shape);
1781
1782[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1783public static extern bool IsConcave2(IntPtr shape);
1784
1785[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1786public static extern bool IsCompound2(IntPtr shape);
1787
1788[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1789public static extern bool IsSoftBody2(IntPtr shape);
1790
1791[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1792public static extern bool IsInfinite2(IntPtr shape);
1793
1794[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1795public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
1796
1797[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1798public static extern Vector3 GetLocalScaling2(IntPtr shape);
1799
1800[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1801public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
1802
1803[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1804public static extern int GetShapeType2(IntPtr shape);
1805
1806[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1807public static extern void SetMargin2(IntPtr shape, float val);
1808
1809[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1810public static extern float GetMargin2(IntPtr shape);
1811
1812// =====================================================================================
1813// Debugging
1814[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1815public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1816
1817[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1818public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1819
1820[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1821public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1822
1823[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1824public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1825
1826[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1827public static extern void DumpActivationInfo2(IntPtr sim);
1828
1829[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1830public static extern void DumpAllInfo2(IntPtr sim);
1831
1832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1833public static extern void DumpPhysicsStatistics2(IntPtr sim);
1834
1835}
1836
1837}
1838
1839}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
deleted file mode 100755
index 30a7bee..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
+++ /dev/null
@@ -1,1622 +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.Text;
31
32using OpenSim.Framework;
33
34using OpenMetaverse;
35
36using BulletXNA;
37using BulletXNA.LinearMath;
38using BulletXNA.BulletCollision;
39using BulletXNA.BulletDynamics;
40using BulletXNA.BulletCollision.CollisionDispatch;
41
42namespace OpenSim.Region.Physics.BulletSPlugin
43{
44public sealed class BSAPIXNA : BSAPITemplate
45{
46private sealed class BulletWorldXNA : BulletWorld
47{
48 public DiscreteDynamicsWorld world;
49 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
50 : base(id, physScene)
51 {
52 world = xx;
53 }
54}
55
56private sealed class BulletBodyXNA : BulletBody
57{
58 public CollisionObject body;
59 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
60
61 public BulletBodyXNA(uint id, CollisionObject xx)
62 : base(id)
63 {
64 body = xx;
65 }
66 public override bool HasPhysicalBody
67 {
68 get { return body != null; }
69 }
70 public override void Clear()
71 {
72 body = null;
73 }
74 public override string AddrString
75 {
76 get { return "XNARigidBody"; }
77 }
78}
79
80private sealed class BulletShapeXNA : BulletShape
81{
82 public CollisionShape shape;
83 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
84 : base()
85 {
86 shape = xx;
87 type = typ;
88 }
89 public override bool HasPhysicalShape
90 {
91 get { return shape != null; }
92 }
93 public override void Clear()
94 {
95 shape = null;
96 }
97 public override BulletShape Clone()
98 {
99 return new BulletShapeXNA(shape, type);
100 }
101 public override bool ReferenceSame(BulletShape other)
102 {
103 BulletShapeXNA otheru = other as BulletShapeXNA;
104 return (otheru != null) && (this.shape == otheru.shape);
105
106 }
107 public override string AddrString
108 {
109 get { return "XNACollisionShape"; }
110 }
111}
112private sealed class BulletConstraintXNA : BulletConstraint
113{
114 public TypedConstraint constrain;
115 public BulletConstraintXNA(TypedConstraint xx) : base()
116 {
117 constrain = xx;
118 }
119
120 public override void Clear()
121 {
122 constrain = null;
123 }
124 public override bool HasPhysicalConstraint { get { return constrain != null; } }
125
126 // Used for log messages for a unique display of the memory/object allocated to this instance
127 public override string AddrString
128 {
129 get { return "XNAConstraint"; }
130 }
131}
132
133 private static int m_collisionsThisFrame;
134 private BSScene PhysicsScene { get; set; }
135
136 public override string BulletEngineName { get { return "BulletXNA"; } }
137 public override string BulletEngineVersion { get; protected set; }
138
139 public BSAPIXNA(string paramName, BSScene physScene)
140 {
141 PhysicsScene = physScene;
142 }
143
144 /// <summary>
145 ///
146 /// </summary>
147 /// <param name="p"></param>
148 /// <param name="p_2"></param>
149 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
150 {
151 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
152 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
153 world.RemoveRigidBody(body);
154 return true;
155 }
156
157 public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
158 {
159 /* TODO */
160 return false;
161 }
162
163 public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
164 {
165 /* TODO */
166 return false;
167 }
168
169 public override void SetRestitution(BulletBody pBody, float pRestitution)
170 {
171 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
172 body.SetRestitution(pRestitution);
173 }
174
175 public override int GetShapeType(BulletShape pShape)
176 {
177 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
178 return (int)shape.GetShapeType();
179 }
180 public override void SetMargin(BulletShape pShape, float pMargin)
181 {
182 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
183 shape.SetMargin(pMargin);
184 }
185
186 public override float GetMargin(BulletShape pShape)
187 {
188 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
189 return shape.GetMargin();
190 }
191
192 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
193 {
194 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
195 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
196 shape.SetLocalScaling(ref vec);
197
198 }
199
200 public override void SetContactProcessingThreshold(BulletBody pBody, float contactprocessingthreshold)
201 {
202 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
203 body.SetContactProcessingThreshold(contactprocessingthreshold);
204 }
205
206 public override void SetCcdMotionThreshold(BulletBody pBody, float pccdMotionThreashold)
207 {
208 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
209 body.SetCcdMotionThreshold(pccdMotionThreashold);
210 }
211
212 public override void SetCcdSweptSphereRadius(BulletBody pBody, float pCcdSweptSphereRadius)
213 {
214 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
215 body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
216 }
217
218 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
219 {
220 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
221 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
222 }
223
224 public override CollisionFlags AddToCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags)
225 {
226 CollisionObject body = ((BulletBodyXNA)pBody).body;
227 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
228 existingcollisionFlags |= pcollisionFlags;
229 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
230 return (CollisionFlags) (uint) existingcollisionFlags;
231 }
232
233 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
234 {
235 // Bullet resets several variables when an object is added to the world. In particular,
236 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
237 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
238 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
239 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
240
241 IndexedMatrix origPos = body.GetWorldTransform();
242 IndexedVector3 origGrav = body.GetGravity();
243
244 //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE))
245
246 world.AddRigidBody(body);
247
248 body.SetWorldTransform(origPos);
249 body.SetGravity(origGrav);
250
251 pBody.ApplyCollisionMask(pWorld.physicsScene);
252
253 //if (body.GetBroadphaseHandle() != null)
254 // world.UpdateSingleAabb(body);
255 return true;
256 }
257
258 public override void ForceActivationState(BulletBody pBody, ActivationState pActivationState)
259 {
260 CollisionObject body = ((BulletBodyXNA)pBody).body;
261 body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
262 }
263
264 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pBody)
265 {
266 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
267 CollisionObject body = ((BulletBodyXNA)pBody).body;
268 world.UpdateSingleAabb(body);
269 }
270
271 public override void UpdateAabbs(BulletWorld world) { /* TODO */ }
272 public override bool GetForceUpdateAllAabbs(BulletWorld world) { /* TODO */ return false; }
273 public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) { /* TODO */ }
274
275 public override bool SetCollisionGroupMask(BulletBody pBody, uint pGroup, uint pMask)
276 {
277 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
278 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
279 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
280 if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0)
281 return false;
282 return true;
283 }
284
285 public override void ClearAllForces(BulletBody pBody)
286 {
287 CollisionObject body = ((BulletBodyXNA)pBody).body;
288 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
289 body.SetInterpolationLinearVelocity(ref zeroVector);
290 body.SetInterpolationAngularVelocity(ref zeroVector);
291 IndexedMatrix bodytransform = body.GetWorldTransform();
292
293 body.SetInterpolationWorldTransform(ref bodytransform);
294
295 if (body is RigidBody)
296 {
297 RigidBody rigidbody = body as RigidBody;
298 rigidbody.SetLinearVelocity(zeroVector);
299 rigidbody.SetAngularVelocity(zeroVector);
300 rigidbody.ClearForces();
301 }
302 }
303
304 public override void SetInterpolationAngularVelocity(BulletBody pBody, Vector3 pVector3)
305 {
306 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
307 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
308 body.SetInterpolationAngularVelocity(ref vec);
309 }
310
311 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
312 {
313 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
314 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
315 body.SetAngularVelocity(ref vec);
316 }
317 public override Vector3 GetTotalForce(BulletBody pBody)
318 {
319 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
320 IndexedVector3 iv3 = body.GetTotalForce();
321 return new Vector3(iv3.X, iv3.Y, iv3.Z);
322 }
323 public override Vector3 GetTotalTorque(BulletBody pBody)
324 {
325 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
326 IndexedVector3 iv3 = body.GetTotalTorque();
327 return new Vector3(iv3.X, iv3.Y, iv3.Z);
328 }
329 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
330 {
331 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
332 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
333 return new Vector3(iv3.X, iv3.Y, iv3.Z);
334 }
335 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
336 {
337 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
338 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
339 body.SetInvInertiaDiagLocal(ref iv3);
340 }
341 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
342 {
343 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
344 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
345 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
346 body.ApplyForce(ref forceiv3, ref posiv3);
347 }
348 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
349 {
350 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
351 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
352 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
353 body.ApplyImpulse(ref impiv3, ref posiv3);
354 }
355
356 public override void ClearForces(BulletBody pBody)
357 {
358 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
359 body.ClearForces();
360 }
361
362 public override void SetTranslation(BulletBody pBody, Vector3 _position, Quaternion _orientation)
363 {
364 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
365 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
366 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
367 _orientation.W);
368 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
369 mat._origin = vposition;
370 body.SetWorldTransform(mat);
371
372 }
373
374 public override Vector3 GetPosition(BulletBody pBody)
375 {
376 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
377 IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin;
378 return new Vector3(pos.X, pos.Y, pos.Z);
379 }
380
381 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
382 {
383 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
384 IndexedVector3 inertia = IndexedVector3.Zero;
385 shape.CalculateLocalInertia(pphysMass, out inertia);
386 return new Vector3(inertia.X, inertia.Y, inertia.Z);
387 }
388
389 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
390 {
391 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
392 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
393 body.SetMassProps(pphysMass, inertia);
394 }
395
396
397 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
398 {
399 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
400 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
401 body.SetTotalForce(ref force);
402 }
403
404 public override void SetFriction(BulletBody pBody, float _currentFriction)
405 {
406 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
407 body.SetFriction(_currentFriction);
408 }
409
410 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
411 {
412 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
413 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
414 body.SetLinearVelocity(velocity);
415 }
416
417 public override void Activate(BulletBody pBody, bool pforceactivation)
418 {
419 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
420 body.Activate(pforceactivation);
421
422 }
423
424 public override Quaternion GetOrientation(BulletBody pBody)
425 {
426 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
427 IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation();
428 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
429 }
430
431 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags)
432 {
433 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
434 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
435 existingcollisionFlags &= ~pcollisionFlags;
436 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
437 return (CollisionFlags)(uint)existingcollisionFlags;
438 }
439
440 public override float GetCcdMotionThreshold(BulletBody obj) { /* TODO */ return 0f; }
441
442 public override float GetCcdSweptSphereRadius(BulletBody obj) { /* TODO */ return 0f; }
443
444 public override IntPtr GetUserPointer(BulletBody obj) { /* TODO */ return IntPtr.Zero; }
445
446 public override void SetUserPointer(BulletBody obj, IntPtr val) { /* TODO */ }
447
448 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
449 {
450 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
451 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
452 body.SetGravity(gravity);
453 }
454
455 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
456 {
457 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
458 TypedConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain;
459 world.RemoveConstraint(constraint);
460 return true;
461 }
462
463 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
464 {
465 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
466 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
467 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
468 constraint.SetLinearLowerLimit(lowlimit);
469 constraint.SetLinearUpperLimit(highlimit);
470 return true;
471 }
472
473 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
474 {
475 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
476 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
477 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
478 constraint.SetAngularLowerLimit(lowlimit);
479 constraint.SetAngularUpperLimit(highlimit);
480 return true;
481 }
482
483 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
484 {
485 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
486 constraint.SetOverrideNumSolverIterations((int)cnt);
487 }
488
489 public override bool CalculateTransforms(BulletConstraint pConstraint)
490 {
491 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
492 constraint.CalculateTransforms();
493 return true;
494 }
495
496 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
497 {
498 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
499 constraint.SetEnabled((p_2 == 0) ? false : true);
500 }
501
502
503 //BulletSimAPI.Create6DofConstraint(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
504 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
505
506 {
507 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
508 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody;
509 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody;
510 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
511 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
512 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
513 frame1._origin = frame1v;
514
515 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
516 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
517 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
518 frame2._origin = frame1v;
519
520 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
521 puseLinearReferenceFrameA);
522 consttr.CalculateTransforms();
523 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
524
525 return new BulletConstraintXNA(consttr);
526 }
527
528
529 /// <summary>
530 ///
531 /// </summary>
532 /// <param name="pWorld"></param>
533 /// <param name="pBody1"></param>
534 /// <param name="pBody2"></param>
535 /// <param name="pjoinPoint"></param>
536 /// <param name="puseLinearReferenceFrameA"></param>
537 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
538 /// <returns></returns>
539 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
540 {
541 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
542 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody;
543 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody;
544 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
545 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
546
547 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
548 IndexedMatrix mat = IndexedMatrix.Identity;
549 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
550 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
551 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
552
553 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
554 consttr.CalculateTransforms();
555 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
556
557 return new BulletConstraintXNA(consttr);
558 }
559 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
560 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
561 {
562 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
563 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
564 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
565 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
566 frame1._origin = frame1v;
567
568 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
569 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
570 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
571 frame2._origin = frame1v;
572 constraint.SetFrames(ref frame1, ref frame2);
573 return true;
574 }
575
576 public override Vector3 GetLinearVelocity(BulletBody pBody)
577 {
578 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
579 IndexedVector3 iv3 = body.GetLinearVelocity();
580 return new Vector3(iv3.X, iv3.Y, iv3.Z);
581 }
582 public override Vector3 GetAngularVelocity(BulletBody pBody)
583 {
584 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
585 IndexedVector3 iv3 = body.GetAngularVelocity();
586 return new Vector3(iv3.X, iv3.Y, iv3.Z);
587 }
588 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
589 {
590 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
591 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
592 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
593 return new Vector3(iv3.X, iv3.Y, iv3.Z);
594 }
595 public override void Translate(BulletBody pBody, Vector3 trans)
596 {
597 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
598 }
599 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
600 {
601 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
602 body.UpdateDeactivation(timeStep);
603 }
604
605 public override bool WantsSleeping(BulletBody pBody)
606 {
607 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
608 return body.WantsSleeping();
609 }
610
611 public override void SetAngularFactor(BulletBody pBody, float factor)
612 {
613 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
614 body.SetAngularFactor(factor);
615 }
616
617 public override Vector3 GetAngularFactor(BulletBody pBody)
618 {
619 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
620 IndexedVector3 iv3 = body.GetAngularFactor();
621 return new Vector3(iv3.X, iv3.Y, iv3.Z);
622 }
623
624 public override bool IsInWorld(BulletWorld pWorld, BulletBody pBody)
625 {
626 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
627 CollisionObject body = ((BulletBodyXNA)pBody).body;
628 return world.IsInWorld(body);
629 }
630
631 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstrain)
632 {
633 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
634 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain;
635 body.AddConstraintRef(constrain);
636 }
637
638 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstrain)
639 {
640 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
641 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain;
642 body.RemoveConstraintRef(constrain);
643 }
644
645 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
646 {
647 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
648 return new BulletConstraintXNA(body.GetConstraintRef(index));
649 }
650
651 public override int GetNumConstraintRefs(BulletBody pBody)
652 {
653 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
654 return body.GetNumConstraintRefs();
655 }
656
657 public override void SetInterpolationLinearVelocity(BulletBody pBody, Vector3 VehicleVelocity)
658 {
659 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
660 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
661 body.SetInterpolationLinearVelocity(ref velocity);
662 }
663
664 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
665 {
666 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
667 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
668 return true;
669 }
670 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
671 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
672 {
673 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
674 constraint.SetBreakingImpulseThreshold(threshold);
675 return true;
676 }
677 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
678 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
679 {
680 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
681 float lineardamping = body.GetLinearDamping();
682 body.SetDamping(lineardamping, angularDamping);
683
684 }
685
686 public override void UpdateInertiaTensor(BulletBody pBody)
687 {
688 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
689 body.UpdateInertiaTensor();
690 }
691
692 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
693 {
694 CompoundShape shape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape;
695 shape.RecalculateLocalAabb();
696 }
697
698 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
699 public override CollisionFlags GetCollisionFlags(BulletBody pBody)
700 {
701 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
702 uint flags = (uint)body.GetCollisionFlags();
703 return (CollisionFlags) flags;
704 }
705
706 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
707 {
708 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
709 body.SetDamping(pLinear, pAngular);
710 }
711 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
712 public override void SetDeactivationTime(BulletBody pBody, float pDeactivationTime)
713 {
714 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
715 body.SetDeactivationTime(pDeactivationTime);
716 }
717 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
718 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
719 {
720 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
721 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
722 }
723
724 public override CollisionObjectTypes GetBodyType(BulletBody pBody)
725 {
726 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
727 return (CollisionObjectTypes)(int) body.GetInternalType();
728 }
729
730 public override void ApplyGravity(BulletBody obj) { /* TODO */ }
731
732 public override Vector3 GetGravity(BulletBody obj) { /* TODO */ return Vector3.Zero; }
733
734 public override void SetLinearDamping(BulletBody obj, float lin_damping) { /* TODO */ }
735
736 public override float GetLinearDamping(BulletBody obj) { /* TODO */ return 0f; }
737
738 public override float GetAngularDamping(BulletBody obj) { /* TODO */ return 0f; }
739
740 public override float GetLinearSleepingThreshold(BulletBody obj) { /* TODO */ return 0f; }
741
742 public override void ApplyDamping(BulletBody obj, float timeStep) { /* TODO */ }
743
744 public override Vector3 GetLinearFactor(BulletBody obj) { /* TODO */ return Vector3.Zero; }
745
746 public override void SetLinearFactor(BulletBody obj, Vector3 factor) { /* TODO */ }
747
748 public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) { /* TODO */ }
749
750 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
751 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
752 {
753 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
754 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
755 body.ApplyCentralForce(ref fSum);
756 }
757 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
758 {
759 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
760 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
761 body.ApplyCentralImpulse(ref fSum);
762 }
763 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
764 {
765 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
766 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
767 body.ApplyTorque(ref fSum);
768 }
769 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
770 {
771 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
772 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
773 body.ApplyTorqueImpulse(ref fSum);
774 }
775
776 public override void DumpRigidBody(BulletWorld p, BulletBody p_2)
777 {
778 //TODO:
779 }
780
781 public override void DumpCollisionShape(BulletWorld p, BulletShape p_2)
782 {
783 //TODO:
784 }
785 public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
786 {
787 //TODO:
788 }
789
790 public override void DumpActivationInfo(BulletWorld world)
791 {
792 //TODO:
793 }
794
795 public override void DumpAllInfo(BulletWorld world)
796 {
797 //TODO:
798 }
799
800 public override void DumpPhysicsStatistics(BulletWorld world)
801 {
802 //TODO:
803 }
804
805 public override void DestroyObject(BulletWorld p, BulletBody p_2)
806 {
807 //TODO:
808 }
809
810 public override void Shutdown(BulletWorld pWorld)
811 {
812 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
813 world.Cleanup();
814 }
815
816 public override BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id)
817 {
818 return null;
819 }
820
821 public override bool DeleteCollisionShape(BulletWorld p, BulletShape p_2)
822 {
823 //TODO:
824 return false;
825 }
826 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
827
828 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
829 {
830 CollisionWorld world = ((BulletWorldXNA)pWorld).world;
831 IndexedMatrix mat =
832 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
833 pRawOrientation.Z, pRawOrientation.W));
834 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
835 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
836 //UpdateSingleAabb(world, shape);
837 // TODO: Feed Update array into null
838 RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero);
839
840 body.SetUserPointer(pLocalID);
841 return new BulletBodyXNA(pLocalID, body);
842 }
843
844
845 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
846 {
847
848 IndexedMatrix mat =
849 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
850 pRawOrientation.Z, pRawOrientation.W));
851 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
852
853 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
854
855 // TODO: Feed Update array into null
856 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
857 body.SetWorldTransform(mat);
858 body.SetUserPointer(pLocalID);
859 return new BulletBodyXNA(pLocalID, body);
860 }
861 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
862 public override CollisionFlags SetCollisionFlags(BulletBody pBody, CollisionFlags collisionFlags)
863 {
864 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
865 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
866 return (CollisionFlags)body.GetCollisionFlags();
867 }
868
869 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return Vector3.Zero; }
870 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
871 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
872 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
873 public override bool IsStaticObject(BulletBody pBody) { /* TODO */ return false; }
874 public override bool IsKinematicObject(BulletBody pBody) { /* TODO */ return false; }
875 public override bool IsStaticOrKinematicObject(BulletBody pBody) { /* TODO */ return false; }
876 public override bool HasContactResponse(BulletBody pBody) { /* TODO */ return false; }
877 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
878 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
879 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
880 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
881 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
882 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
883 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
884 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
885
886 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
887 public override void SetHitFraction(BulletBody pBody, float pHitFraction)
888 {
889 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
890 body.SetHitFraction(pHitFraction);
891 }
892 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
893 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
894 {
895 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
896 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
897 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
898 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
899 capsuleShapeZ.SetLocalScaling(ref scale);
900
901 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
902 }
903
904 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
905 int maxCollisions, ref CollisionDesc[] collisionArray,
906 int maxUpdates, ref EntityProperties[] updateArray
907 )
908 {
909 /* TODO */
910 return new BulletWorldXNA(1, null, null);
911 }
912
913 private static object Initialize2(Vector3 worldExtent,
914 ConfigurationParameters[] o,
915 int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray,
916 int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray,
917 object mDebugLogCallbackHandle)
918 {
919 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
920
921 p.angularDamping = o[0].XangularDamping;
922 p.defaultFriction = o[0].defaultFriction;
923 p.defaultFriction = o[0].defaultFriction;
924 p.defaultDensity = o[0].defaultDensity;
925 p.defaultRestitution = o[0].defaultRestitution;
926 p.collisionMargin = o[0].collisionMargin;
927 p.gravity = o[0].gravity;
928
929 p.linearDamping = o[0].XlinearDamping;
930 p.angularDamping = o[0].XangularDamping;
931 p.deactivationTime = o[0].XdeactivationTime;
932 p.linearSleepingThreshold = o[0].XlinearSleepingThreshold;
933 p.angularSleepingThreshold = o[0].XangularSleepingThreshold;
934 p.ccdMotionThreshold = o[0].XccdMotionThreshold;
935 p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius;
936 p.contactProcessingThreshold = o[0].XcontactProcessingThreshold;
937
938 p.terrainImplementation = o[0].XterrainImplementation;
939 p.terrainFriction = o[0].XterrainFriction;
940
941 p.terrainHitFraction = o[0].XterrainHitFraction;
942 p.terrainRestitution = o[0].XterrainRestitution;
943 p.terrainCollisionMargin = o[0].XterrainCollisionMargin;
944
945 p.avatarFriction = o[0].XavatarFriction;
946 p.avatarStandingFriction = o[0].XavatarStandingFriction;
947 p.avatarDensity = o[0].XavatarDensity;
948 p.avatarRestitution = o[0].XavatarRestitution;
949 p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth;
950 p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth;
951 p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight;
952 p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold;
953
954 p.vehicleAngularDamping = o[0].XvehicleAngularDamping;
955
956 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
957 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
958 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
959 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
960 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
961 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
962 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
963 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
964
965 p.linksetImplementation = o[0].XlinksetImplementation;
966 p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset;
967 p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor;
968 p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel;
969 p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce;
970 p.linkConstraintERP = o[0].XlinkConstraintERP;
971 p.linkConstraintCFM = o[0].XlinkConstraintCFM;
972 p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations;
973 p.physicsLoggingFrames = o[0].XphysicsLoggingFrames;
974 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
975
976 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
977 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
978
979
980 if (p.maxPersistantManifoldPoolSize > 0)
981 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
982 if (p.shouldDisableContactPoolDynamicAllocation !=0)
983 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
984 //if (p.maxCollisionAlgorithmPoolSize >0 )
985
986 DbvtBroadphase m_broadphase = new DbvtBroadphase();
987 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
988 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
989
990 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
991 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
992
993 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
994
995 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
996 world.UpdatedObjects = updateArray;
997 world.UpdatedCollisions = collisionArray;
998 world.WorldSettings.Params = p;
999 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
1000 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
1001 if (p.shouldRandomizeSolverOrder != 0)
1002 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
1003
1004 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
1005 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
1006
1007 if (p.shouldEnableFrictionCaching != 0)
1008 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1009
1010 if (p.numberOfSolverIterations > 0)
1011 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
1012
1013
1014 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
1015 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
1016 world.GetSolverInfo().m_globalCfm = 0.0f;
1017 world.GetSolverInfo().m_tau = 0.6f;
1018 world.GetSolverInfo().m_friction = 0.3f;
1019 world.GetSolverInfo().m_maxErrorReduction = 20f;
1020 world.GetSolverInfo().m_numIterations = 10;
1021 world.GetSolverInfo().m_erp = 0.2f;
1022 world.GetSolverInfo().m_erp2 = 0.1f;
1023 world.GetSolverInfo().m_sor = 1.0f;
1024 world.GetSolverInfo().m_splitImpulse = false;
1025 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1026 world.GetSolverInfo().m_linearSlop = 0.0f;
1027 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1028 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1029 world.SetForceUpdateAllAabbs(true);
1030
1031
1032 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1033
1034 return world;
1035 }
1036 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1037 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1038 {
1039 Generic6DofConstraint constrain = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
1040 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1041 {
1042 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1043 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1044 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1045 }
1046 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1047 {
1048 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1049 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1050 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1051 }
1052 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1053 {
1054 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1055 }
1056 return true;
1057 }
1058
1059 public override bool PushUpdate(BulletBody pCollisionObject)
1060 {
1061 bool ret = false;
1062 RigidBody rb = ((BulletBodyXNA)pCollisionObject).rigidBody;
1063 if (rb != null)
1064 {
1065 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1066 if (sms != null)
1067 {
1068 IndexedMatrix wt = IndexedMatrix.Identity;
1069 sms.GetWorldTransform(out wt);
1070 sms.SetWorldTransform(ref wt, true);
1071 ret = true;
1072 }
1073 }
1074 return ret;
1075
1076 }
1077
1078 public override float GetAngularMotionDisc(BulletShape pShape)
1079 {
1080 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1081 return shape.GetAngularMotionDisc();
1082 }
1083 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1084 {
1085 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1086 return shape.GetContactBreakingThreshold(defaultFactor);
1087 }
1088 public override bool IsCompound(BulletShape pShape)
1089 {
1090 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1091 return shape.IsCompound();
1092 }
1093 public override bool IsSoftBody(BulletShape pShape)
1094 {
1095 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1096 return shape.IsSoftBody();
1097 }
1098 public override bool IsPolyhedral(BulletShape pShape)
1099 {
1100 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1101 return shape.IsPolyhedral();
1102 }
1103 public override bool IsConvex2d(BulletShape pShape)
1104 {
1105 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1106 return shape.IsConvex2d();
1107 }
1108 public override bool IsConvex(BulletShape pShape)
1109 {
1110 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1111 return shape.IsConvex();
1112 }
1113 public override bool IsNonMoving(BulletShape pShape)
1114 {
1115 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1116 return shape.IsNonMoving();
1117 }
1118 public override bool IsConcave(BulletShape pShape)
1119 {
1120 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1121 return shape.IsConcave();
1122 }
1123 public override bool IsInfinite(BulletShape pShape)
1124 {
1125 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1126 return shape.IsInfinite();
1127 }
1128 public override bool IsNativeShape(BulletShape pShape)
1129 {
1130 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1131 bool ret;
1132 switch (shape.GetShapeType())
1133 {
1134 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1135 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1136 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1137 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1138 ret = true;
1139 break;
1140 default:
1141 ret = false;
1142 break;
1143 }
1144 return ret;
1145 }
1146
1147 public override void SetShapeCollisionMargin(BulletShape shape, float margin) { /* TODO */ }
1148
1149 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1150 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1151 {
1152 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1153 IndexedMatrix bodyTransform = new IndexedMatrix();
1154 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1155 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1156 GhostObject gObj = new PairCachingGhostObject();
1157 gObj.SetWorldTransform(bodyTransform);
1158 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1159 gObj.SetCollisionShape(shape);
1160 gObj.SetUserPointer(pLocalID);
1161 // TODO: Add to Special CollisionObjects!
1162 return new BulletBodyXNA(pLocalID, gObj);
1163 }
1164
1165 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pObj, BulletShape pShape)
1166 {
1167 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1168 CollisionObject obj = ((BulletBodyXNA)pObj).body;
1169 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1170 obj.SetCollisionShape(shape);
1171
1172 }
1173 public override BulletShape GetCollisionShape(BulletBody obj) { /* TODO */ return null; }
1174
1175 //(PhysicsScene.World.ptr, nativeShapeData)
1176 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1177 {
1178 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1179 CollisionShape shape = null;
1180 switch (pShapeData.Type)
1181 {
1182 case BSPhysicsShapeType.SHAPE_BOX:
1183 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1184 break;
1185 case BSPhysicsShapeType.SHAPE_CONE:
1186 shape = new ConeShapeZ(0.5f, 1.0f);
1187 break;
1188 case BSPhysicsShapeType.SHAPE_CYLINDER:
1189 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1190 break;
1191 case BSPhysicsShapeType.SHAPE_SPHERE:
1192 shape = new SphereShape(0.5f);
1193 break;
1194
1195 }
1196 if (shape != null)
1197 {
1198 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1199 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1200 shape.SetLocalScaling(ref scaling);
1201
1202 }
1203 return new BulletShapeXNA(shape, pShapeData.Type);
1204 }
1205 //PhysicsScene.World.ptr, false
1206 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1207 {
1208 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1209 }
1210
1211 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1212 {
1213 CompoundShape compoundshape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape;
1214 return compoundshape.GetNumChildShapes();
1215 }
1216 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1217 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1218 {
1219 IndexedMatrix relativeTransform = new IndexedMatrix();
1220 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape;
1221 CollisionShape addshape = ((BulletShapeXNA)paddShape).shape;
1222
1223 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1224 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1225 compoundshape.AddChildShape(ref relativeTransform, addshape);
1226
1227 }
1228
1229 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1230 {
1231 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape;
1232 CollisionShape ret = null;
1233 ret = compoundshape.GetChildShape(pii);
1234 compoundshape.RemoveChildShapeByIndex(pii);
1235 return new BulletShapeXNA(ret, BSPhysicsShapeType.SHAPE_UNKNOWN);
1236 }
1237
1238 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { /* TODO */ return null; }
1239 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1240
1241 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1242 {
1243 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1244 m_planeshape.SetMargin(pcollisionMargin);
1245 m_planeshape.SetUserPointer(pLocalId);
1246 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1247 }
1248
1249 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1250 {
1251 HingeConstraint constrain = null;
1252 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1253 RigidBody rb1 = ((BulletBodyXNA)pBody1).rigidBody;
1254 RigidBody rb2 = ((BulletBodyXNA)ppBody2).rigidBody;
1255 if (rb1 != null && rb2 != null)
1256 {
1257 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1258 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1259 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1260 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1261 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1262 }
1263 return new BulletConstraintXNA(constrain);
1264 }
1265
1266 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
1267 {
1268 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1269 CompoundShape compoundshape = new CompoundShape(false);
1270
1271 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1272 int ii = 1;
1273
1274 for (int i = 0; i < pHullCount; i++)
1275 {
1276 int vertexCount = (int) pConvHulls[ii];
1277
1278 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
1279 IndexedMatrix childTrans = IndexedMatrix.Identity;
1280 childTrans._origin = centroid;
1281
1282 List<IndexedVector3> virts = new List<IndexedVector3>();
1283 int ender = ((ii + 4) + (vertexCount*3));
1284 for (int iii = ii + 4; iii < ender; iii+=3)
1285 {
1286
1287 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1288 }
1289 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
1290 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1291 compoundshape.AddChildShape(ref childTrans, convexShape);
1292 ii += (vertexCount*3 + 4);
1293 }
1294
1295 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1296 }
1297
1298 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) { /* TODO */ return null; }
1299
1300 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1301 {
1302 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1303
1304 for (int iter = 0; iter < pVerticesCount; iter++)
1305 {
1306 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1307 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1308 }
1309
1310 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1311 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1312 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1313 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1314 IndexedMesh mesh = new IndexedMesh();
1315 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1316 mesh.m_numTriangles = pIndicesCount/3;
1317 mesh.m_numVertices = pVerticesCount;
1318 mesh.m_triangleIndexBase = indicesarr;
1319 mesh.m_vertexBase = vertices;
1320 mesh.m_vertexStride = 3;
1321 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1322 mesh.m_triangleIndexStride = 3;
1323
1324 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1325 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1326 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
1327 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1328 // world.UpdateSingleAabb(meshShape);
1329 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
1330
1331 }
1332 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1333 {
1334
1335 String fileName = "objTest3.raw";
1336 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1337 StreamWriter sw = new StreamWriter(completePath);
1338 IndexedMesh mesh = new IndexedMesh();
1339
1340 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1341 mesh.m_numTriangles = pIndicesCount / 3;
1342 mesh.m_numVertices = pVerticesCount;
1343 mesh.m_triangleIndexBase = indices;
1344 mesh.m_vertexBase = vertices;
1345 mesh.m_vertexStride = 3;
1346 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1347 mesh.m_triangleIndexStride = 3;
1348
1349 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1350 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1351
1352
1353
1354 for (int i = 0; i < pVerticesCount; i++)
1355 {
1356
1357 string s = vertices[indices[i * 3]].ToString("0.0000");
1358 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1359 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1360
1361 sw.Write(s + "\n");
1362 }
1363
1364 sw.Close();
1365 }
1366 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
1367 {
1368
1369 String fileName = "objTest6.raw";
1370 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1371 StreamWriter sw = new StreamWriter(completePath);
1372 IndexedMesh mesh = new IndexedMesh();
1373
1374 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1375 mesh.m_numTriangles = pIndicesCount / 3;
1376 mesh.m_numVertices = pVerticesCount;
1377 mesh.m_triangleIndexBase = indices;
1378 mesh.m_vertexBase = vertices;
1379 mesh.m_vertexStride = 3;
1380 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1381 mesh.m_triangleIndexStride = 3;
1382
1383 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1384 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1385
1386
1387 sw.WriteLine("Indices");
1388 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
1389 for (int iter = 0; iter < indices.Length; iter++)
1390 {
1391 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
1392 }
1393 sw.WriteLine("VerticesFloats");
1394 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
1395 for (int iter = 0; iter < vertices.Length; iter++)
1396 {
1397 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
1398 }
1399
1400 // for (int i = 0; i < pVerticesCount; i++)
1401 // {
1402 //
1403 // string s = vertices[indices[i * 3]].ToString("0.0000");
1404 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1405 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1406 //
1407 // sw.Write(s + "\n");
1408 //}
1409
1410 sw.Close();
1411 }
1412
1413 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1414 float scaleFactor, float collisionMargin)
1415 {
1416 const int upAxis = 2;
1417 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
1418 heightMap, scaleFactor,
1419 minHeight, maxHeight, upAxis,
1420 false);
1421 terrainShape.SetMargin(collisionMargin + 0.5f);
1422 terrainShape.SetUseDiamondSubdivision(true);
1423 terrainShape.SetUserPointer(id);
1424 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
1425 }
1426
1427 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1428 {
1429 TypedConstraint tconstrain = ((BulletConstraintXNA)pConstraint).constrain;
1430 bool onOff = ponOff != 0;
1431 bool ret = false;
1432
1433 switch (tconstrain.GetConstraintType())
1434 {
1435 case TypedConstraintType.D6_CONSTRAINT_TYPE:
1436 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
1437 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
1438 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
1439 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
1440 ret = true;
1441 break;
1442 }
1443
1444
1445 return ret;
1446
1447 }
1448
1449 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
1450 out int updatedEntityCount, out int collidersCount)
1451 {
1452 /* TODO */
1453 updatedEntityCount = 0;
1454 collidersCount = 0;
1455 return 1;
1456 }
1457
1458 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1459 out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities,
1460 out int collidersCount, out List<BulletXNA.CollisionDesc>colliders)
1461 {
1462 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1463 out collidersCount, out colliders);
1464 return epic;
1465 }
1466
1467 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)
1468 {
1469 int numSimSteps = 0;
1470
1471
1472 //if (updatedEntities is null)
1473 // updatedEntities = new List<BulletXNA.EntityProperties>();
1474
1475 //if (colliders is null)
1476 // colliders = new List<BulletXNA.CollisionDesc>();
1477
1478
1479 if (pWorld is BulletWorldXNA)
1480 {
1481 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1482
1483 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1484 int updates = 0;
1485
1486 updatedEntityCount = world.UpdatedObjects.Count;
1487 updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects);
1488 updatedEntityCount = updatedEntities.Count;
1489 world.UpdatedObjects.Clear();
1490
1491
1492 collidersCount = world.UpdatedCollisions.Count;
1493 colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions);
1494
1495 world.UpdatedCollisions.Clear();
1496 m_collisionsThisFrame = 0;
1497 int numManifolds = world.GetDispatcher().GetNumManifolds();
1498 for (int j = 0; j < numManifolds; j++)
1499 {
1500 PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
1501 int numContacts = contactManifold.GetNumContacts();
1502 if (numContacts == 0)
1503 continue;
1504
1505 CollisionObject objA = contactManifold.GetBody0() as CollisionObject;
1506 CollisionObject objB = contactManifold.GetBody1() as CollisionObject;
1507
1508 ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0);
1509 IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
1510 IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
1511
1512 RecordCollision(world, objA, objB, contactPoint, contactNormal);
1513 m_collisionsThisFrame ++;
1514 if (m_collisionsThisFrame >= 9999999)
1515 break;
1516
1517
1518 }
1519
1520
1521 }
1522 else
1523 {
1524 //if (updatedEntities is null)
1525 updatedEntities = new List<BulletXNA.EntityProperties>();
1526 updatedEntityCount = 0;
1527 //if (colliders is null)
1528 colliders = new List<BulletXNA.CollisionDesc>();
1529 collidersCount = 0;
1530 }
1531 return numSimSteps;
1532 }
1533
1534 private static void RecordCollision(CollisionWorld world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm)
1535 {
1536
1537 IndexedVector3 contactNormal = norm;
1538 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
1539 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
1540 {
1541 return;
1542 }
1543 uint idA = (uint)objA.GetUserPointer();
1544 uint idB = (uint)objB.GetUserPointer();
1545 if (idA > idB)
1546 {
1547 uint temp = idA;
1548 idA = idB;
1549 idB = temp;
1550 contactNormal = -contactNormal;
1551 }
1552
1553 ulong collisionID = ((ulong) idA << 32) | idB;
1554
1555 BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc()
1556 {
1557 aID = idA,
1558 bID = idB,
1559 point = contact,
1560 normal = contactNormal
1561 };
1562 world.UpdatedCollisions.Add(cDesc);
1563 m_collisionsThisFrame++;
1564
1565
1566 }
1567 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pBody)
1568 {
1569 EntityProperties ent = new EntityProperties();
1570 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1571 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
1572 IndexedMatrix transform = body.GetWorldTransform();
1573 IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity();
1574 IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity();
1575 IndexedQuaternion rotation = transform.GetRotation();
1576 ent.Acceleration = Vector3.Zero;
1577 ent.ID = (uint)body.GetUserPointer();
1578 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
1579 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
1580 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
1581 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
1582 return ent;
1583 }
1584
1585 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ return false; }
1586
1587 public override Vector3 GetLocalScaling(BulletShape pShape)
1588 {
1589 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1590 IndexedVector3 scale = shape.GetLocalScaling();
1591 return new Vector3(scale.X,scale.Y,scale.Z);
1592 }
1593
1594 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
1595 {
1596 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1597 if (world != null)
1598 {
1599 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
1600 {
1601 CollisionObject AvoidBody = ((BulletBodyXNA)NotMe).body;
1602
1603 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
1604 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
1605 using (
1606 ClosestNotMeRayResultCallback rayCallback =
1607 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
1608 )
1609 {
1610 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
1611 if (rayCallback.HasHit())
1612 {
1613 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
1614 }
1615 return rayCallback.HasHit();
1616 }
1617 }
1618 }
1619 return false;
1620 }
1621}
1622}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
deleted file mode 100644
index 8ad78ca..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
+++ /dev/null
@@ -1,662 +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.Security;
31using System.Text;
32using OpenMetaverse;
33
34namespace OpenSim.Region.Physics.BulletSPlugin {
35
36 // Constraint type values as defined by Bullet
37public enum ConstraintType : int
38{
39 POINT2POINT_CONSTRAINT_TYPE = 3,
40 HINGE_CONSTRAINT_TYPE,
41 CONETWIST_CONSTRAINT_TYPE,
42 D6_CONSTRAINT_TYPE,
43 SLIDER_CONSTRAINT_TYPE,
44 CONTACT_CONSTRAINT_TYPE,
45 D6_SPRING_CONSTRAINT_TYPE,
46 MAX_CONSTRAINT_TYPE
47}
48
49// ===============================================================================
50[StructLayout(LayoutKind.Sequential)]
51public struct ConvexHull
52{
53 Vector3 Offset;
54 int VertexCount;
55 Vector3[] Vertices;
56}
57public enum BSPhysicsShapeType
58{
59 SHAPE_UNKNOWN = 0,
60 SHAPE_CAPSULE = 1,
61 SHAPE_BOX = 2,
62 SHAPE_CONE = 3,
63 SHAPE_CYLINDER = 4,
64 SHAPE_SPHERE = 5,
65 SHAPE_MESH = 6,
66 SHAPE_HULL = 7,
67 // following defined by BulletSim
68 SHAPE_GROUNDPLANE = 20,
69 SHAPE_TERRAIN = 21,
70 SHAPE_COMPOUND = 22,
71 SHAPE_HEIGHTMAP = 23,
72 SHAPE_AVATAR = 24,
73};
74
75// The native shapes have predefined shape hash keys
76public enum FixedShapeKey : ulong
77{
78 KEY_NONE = 0,
79 KEY_BOX = 1,
80 KEY_SPHERE = 2,
81 KEY_CONE = 3,
82 KEY_CYLINDER = 4,
83 KEY_CAPSULE = 5,
84 KEY_AVATAR = 6,
85}
86
87[StructLayout(LayoutKind.Sequential)]
88public struct ShapeData
89{
90 public uint ID;
91 public BSPhysicsShapeType Type;
92 public Vector3 Position;
93 public Quaternion Rotation;
94 public Vector3 Velocity;
95 public Vector3 Scale;
96 public float Mass;
97 public float Buoyancy;
98 public System.UInt64 HullKey;
99 public System.UInt64 MeshKey;
100 public float Friction;
101 public float Restitution;
102 public float Collidable; // true of things bump into this
103 public float Static; // true if a static object. Otherwise gravity, etc.
104 public float Solid; // true if object cannot be passed through
105 public Vector3 Size;
106
107 // note that bools are passed as floats since bool size changes by language and architecture
108 public const float numericTrue = 1f;
109 public const float numericFalse = 0f;
110}
111[StructLayout(LayoutKind.Sequential)]
112public struct SweepHit
113{
114 public uint ID;
115 public float Fraction;
116 public Vector3 Normal;
117 public Vector3 Point;
118}
119[StructLayout(LayoutKind.Sequential)]
120public struct RaycastHit
121{
122 public uint ID;
123 public float Fraction;
124 public Vector3 Normal;
125}
126[StructLayout(LayoutKind.Sequential)]
127public struct CollisionDesc
128{
129 public uint aID;
130 public uint bID;
131 public Vector3 point;
132 public Vector3 normal;
133}
134[StructLayout(LayoutKind.Sequential)]
135public struct EntityProperties
136{
137 public uint ID;
138 public Vector3 Position;
139 public Quaternion Rotation;
140 public Vector3 Velocity;
141 public Vector3 Acceleration;
142 public Vector3 RotationalVelocity;
143}
144
145// Format of this structure must match the definition in the C++ code
146// NOTE: adding the X causes compile breaks if used. These are unused symbols
147// that can be removed from both here and the unmanaged definition of this structure.
148[StructLayout(LayoutKind.Sequential)]
149public struct ConfigurationParameters
150{
151 public float defaultFriction;
152 public float defaultDensity;
153 public float defaultRestitution;
154 public float collisionMargin;
155 public float gravity;
156
157 public float XlinearDamping;
158 public float XangularDamping;
159 public float XdeactivationTime;
160 public float XlinearSleepingThreshold;
161 public float XangularSleepingThreshold;
162 public float XccdMotionThreshold;
163 public float XccdSweptSphereRadius;
164 public float XcontactProcessingThreshold;
165
166 public float XterrainImplementation;
167 public float XterrainFriction;
168 public float XterrainHitFraction;
169 public float XterrainRestitution;
170 public float XterrainCollisionMargin;
171
172 public float XavatarFriction;
173 public float XavatarStandingFriction;
174 public float XavatarDensity;
175 public float XavatarRestitution;
176 public float XavatarCapsuleWidth;
177 public float XavatarCapsuleDepth;
178 public float XavatarCapsuleHeight;
179 public float XavatarContactProcessingThreshold;
180
181 public float XvehicleAngularDamping;
182
183 public float maxPersistantManifoldPoolSize;
184 public float maxCollisionAlgorithmPoolSize;
185 public float shouldDisableContactPoolDynamicAllocation;
186 public float shouldForceUpdateAllAabbs;
187 public float shouldRandomizeSolverOrder;
188 public float shouldSplitSimulationIslands;
189 public float shouldEnableFrictionCaching;
190 public float numberOfSolverIterations;
191
192 public float XlinksetImplementation;
193 public float XlinkConstraintUseFrameOffset;
194 public float XlinkConstraintEnableTransMotor;
195 public float XlinkConstraintTransMotorMaxVel;
196 public float XlinkConstraintTransMotorMaxForce;
197 public float XlinkConstraintERP;
198 public float XlinkConstraintCFM;
199 public float XlinkConstraintSolverIterations;
200
201 public float XphysicsLoggingFrames;
202
203 public const float numericTrue = 1f;
204 public const float numericFalse = 0f;
205}
206
207
208// The states a bullet collision object can have
209public enum ActivationState : uint
210{
211 ACTIVE_TAG = 1,
212 ISLAND_SLEEPING,
213 WANTS_DEACTIVATION,
214 DISABLE_DEACTIVATION,
215 DISABLE_SIMULATION,
216}
217
218public enum CollisionObjectTypes : int
219{
220 CO_COLLISION_OBJECT = 1 << 0,
221 CO_RIGID_BODY = 1 << 1,
222 CO_GHOST_OBJECT = 1 << 2,
223 CO_SOFT_BODY = 1 << 3,
224 CO_HF_FLUID = 1 << 4,
225 CO_USER_TYPE = 1 << 5,
226}
227
228// Values used by Bullet and BulletSim to control object properties.
229// Bullet's "CollisionFlags" has more to do with operations on the
230// object (if collisions happen, if gravity effects it, ...).
231public enum CollisionFlags : uint
232{
233 CF_STATIC_OBJECT = 1 << 0,
234 CF_KINEMATIC_OBJECT = 1 << 1,
235 CF_NO_CONTACT_RESPONSE = 1 << 2,
236 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
237 CF_CHARACTER_OBJECT = 1 << 4,
238 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
239 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
240 // Following used by BulletSim to control collisions and updates
241 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
242 BS_FLOATS_ON_WATER = 1 << 11,
243 BS_VEHICLE_COLLISIONS = 1 << 12,
244 BS_NONE = 0,
245 BS_ALL = 0xFFFFFFFF
246};
247
248// Values f collisions groups and masks
249public enum CollisionFilterGroups : uint
250{
251 // Don't use the bit definitions!! Define the use in a
252 // filter/mask definition below. This way collision interactions
253 // are more easily found and debugged.
254 BNoneGroup = 0,
255 BDefaultGroup = 1 << 0, // 0001
256 BStaticGroup = 1 << 1, // 0002
257 BKinematicGroup = 1 << 2, // 0004
258 BDebrisGroup = 1 << 3, // 0008
259 BSensorTrigger = 1 << 4, // 0010
260 BCharacterGroup = 1 << 5, // 0020
261 BAllGroup = 0x000FFFFF,
262 // Filter groups defined by BulletSim
263 BGroundPlaneGroup = 1 << 10, // 0400
264 BTerrainGroup = 1 << 11, // 0800
265 BRaycastGroup = 1 << 12, // 1000
266 BSolidGroup = 1 << 13, // 2000
267 // BLinksetGroup = xx // a linkset proper is either static or dynamic
268 BLinksetChildGroup = 1 << 14, // 4000
269};
270
271// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
272// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
273public enum ConstraintParams : int
274{
275 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
276 BT_CONSTRAINT_STOP_ERP,
277 BT_CONSTRAINT_CFM,
278 BT_CONSTRAINT_STOP_CFM,
279};
280public enum ConstraintParamAxis : int
281{
282 AXIS_LINEAR_X = 0,
283 AXIS_LINEAR_Y,
284 AXIS_LINEAR_Z,
285 AXIS_ANGULAR_X,
286 AXIS_ANGULAR_Y,
287 AXIS_ANGULAR_Z,
288 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
289 AXIS_ANGULAR_ALL,
290 AXIS_ALL
291};
292
293public abstract class BSAPITemplate
294{
295// Returns the name of the underlying Bullet engine
296public abstract string BulletEngineName { get; }
297public abstract string BulletEngineVersion { get; protected set;}
298
299// Initialization and simulation
300public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
301 int maxCollisions, ref CollisionDesc[] collisionArray,
302 int maxUpdates, ref EntityProperties[] updateArray
303 );
304
305public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
306 out int updatedEntityCount, out int collidersCount);
307
308public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value);
309
310public abstract void Shutdown(BulletWorld sim);
311
312public abstract bool PushUpdate(BulletBody obj);
313
314// =====================================================================================
315// Mesh, hull, shape and body creation helper routines
316public abstract BulletShape CreateMeshShape(BulletWorld world,
317 int indicesCount, int[] indices,
318 int verticesCount, float[] vertices );
319
320public abstract BulletShape CreateHullShape(BulletWorld world,
321 int hullCount, float[] hulls);
322
323public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
324
325public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
326
327public abstract bool IsNativeShape(BulletShape shape);
328
329public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
330
331public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale);
332
333public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree);
334
335public abstract int GetNumberOfCompoundChildren(BulletShape cShape);
336
337public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot);
338
339public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
340
341public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
342
343public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
344
345public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
346
347public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id);
348
349public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
350
351public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
352
353public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
354
355public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot);
356
357public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
358
359public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
360
361// =====================================================================================
362public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin);
363
364public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
365 float scaleFactor, float collisionMargin);
366
367// =====================================================================================
368// Constraint creation and helper routines
369public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
370 Vector3 frame1loc, Quaternion frame1rot,
371 Vector3 frame2loc, Quaternion frame2rot,
372 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
373
374public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
375 Vector3 joinPoint,
376 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
377
378public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
379 Vector3 pivotinA, Vector3 pivotinB,
380 Vector3 axisInA, Vector3 axisInB,
381 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
382
383public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
384
385public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
386
387public abstract bool SetFrames(BulletConstraint constrain,
388 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
389
390public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
391
392public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
393
394public abstract bool UseFrameOffset(BulletConstraint constrain, float enable);
395
396public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce);
397
398public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
399
400public abstract bool CalculateTransforms(BulletConstraint constrain);
401
402public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
403
404public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain);
405
406// =====================================================================================
407// btCollisionWorld entries
408public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj);
409
410public abstract void UpdateAabbs(BulletWorld world);
411
412public abstract bool GetForceUpdateAllAabbs(BulletWorld world);
413
414public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force);
415
416// =====================================================================================
417// btDynamicsWorld entries
418// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot);
419public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
420
421public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
422
423public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
424
425public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
426// =====================================================================================
427// btCollisionObject entries
428public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain);
429
430public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict);
431
432public abstract bool HasAnisotripicFriction(BulletConstraint constrain);
433
434public abstract void SetContactProcessingThreshold(BulletBody obj, float val);
435
436public abstract float GetContactProcessingThreshold(BulletBody obj);
437
438public abstract bool IsStaticObject(BulletBody obj);
439
440public abstract bool IsKinematicObject(BulletBody obj);
441
442public abstract bool IsStaticOrKinematicObject(BulletBody obj);
443
444public abstract bool HasContactResponse(BulletBody obj);
445
446public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
447
448public abstract BulletShape GetCollisionShape(BulletBody obj);
449
450public abstract int GetActivationState(BulletBody obj);
451
452public abstract void SetActivationState(BulletBody obj, int state);
453
454public abstract void SetDeactivationTime(BulletBody obj, float dtime);
455
456public abstract float GetDeactivationTime(BulletBody obj);
457
458public abstract void ForceActivationState(BulletBody obj, ActivationState state);
459
460public abstract void Activate(BulletBody obj, bool forceActivation);
461
462public abstract bool IsActive(BulletBody obj);
463
464public abstract void SetRestitution(BulletBody obj, float val);
465
466public abstract float GetRestitution(BulletBody obj);
467
468public abstract void SetFriction(BulletBody obj, float val);
469
470public abstract float GetFriction(BulletBody obj);
471
472public abstract Vector3 GetPosition(BulletBody obj);
473
474public abstract Quaternion GetOrientation(BulletBody obj);
475
476public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation);
477
478// public abstract IntPtr GetBroadphaseHandle(BulletBody obj);
479
480// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle);
481
482public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel);
483
484public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel);
485
486public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel);
487
488public abstract float GetHitFraction(BulletBody obj);
489
490public abstract void SetHitFraction(BulletBody obj, float val);
491
492public abstract CollisionFlags GetCollisionFlags(BulletBody obj);
493
494public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags);
495
496public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags);
497
498public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags);
499
500public abstract float GetCcdMotionThreshold(BulletBody obj);
501
502public abstract void SetCcdMotionThreshold(BulletBody obj, float val);
503
504public abstract float GetCcdSweptSphereRadius(BulletBody obj);
505
506public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val);
507
508public abstract IntPtr GetUserPointer(BulletBody obj);
509
510public abstract void SetUserPointer(BulletBody obj, IntPtr val);
511
512// =====================================================================================
513// btRigidBody entries
514public abstract void ApplyGravity(BulletBody obj);
515
516public abstract void SetGravity(BulletBody obj, Vector3 val);
517
518public abstract Vector3 GetGravity(BulletBody obj);
519
520public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping);
521
522public abstract void SetLinearDamping(BulletBody obj, float lin_damping);
523
524public abstract void SetAngularDamping(BulletBody obj, float ang_damping);
525
526public abstract float GetLinearDamping(BulletBody obj);
527
528public abstract float GetAngularDamping(BulletBody obj);
529
530public abstract float GetLinearSleepingThreshold(BulletBody obj);
531
532public abstract void ApplyDamping(BulletBody obj, float timeStep);
533
534public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia);
535
536public abstract Vector3 GetLinearFactor(BulletBody obj);
537
538public abstract void SetLinearFactor(BulletBody obj, Vector3 factor);
539
540public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot);
541
542// Add a force to the object as if its mass is one.
543public abstract void ApplyCentralForce(BulletBody obj, Vector3 force);
544
545// Set the force being applied to the object as if its mass is one.
546public abstract void SetObjectForce(BulletBody obj, Vector3 force);
547
548public abstract Vector3 GetTotalForce(BulletBody obj);
549
550public abstract Vector3 GetTotalTorque(BulletBody obj);
551
552public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj);
553
554public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert);
555
556public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold);
557
558public abstract void ApplyTorque(BulletBody obj, Vector3 torque);
559
560// Apply force at the given point. Will add torque to the object.
561public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos);
562
563// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
564public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp);
565
566// Apply impulse to the object's torque. Force is scaled by object's mass.
567public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp);
568
569// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
570public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos);
571
572public abstract void ClearForces(BulletBody obj);
573
574public abstract void ClearAllForces(BulletBody obj);
575
576public abstract void UpdateInertiaTensor(BulletBody obj);
577
578public abstract Vector3 GetLinearVelocity(BulletBody obj);
579
580public abstract Vector3 GetAngularVelocity(BulletBody obj);
581
582public abstract void SetLinearVelocity(BulletBody obj, Vector3 val);
583
584public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity);
585
586public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos);
587
588public abstract void Translate(BulletBody obj, Vector3 trans);
589
590public abstract void UpdateDeactivation(BulletBody obj, float timeStep);
591
592public abstract bool WantsSleeping(BulletBody obj);
593
594public abstract void SetAngularFactor(BulletBody obj, float factor);
595
596public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor);
597
598public abstract Vector3 GetAngularFactor(BulletBody obj);
599
600public abstract bool IsInWorld(BulletWorld world, BulletBody obj);
601
602public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain);
603
604public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain);
605
606public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
607
608public abstract int GetNumConstraintRefs(BulletBody obj);
609
610public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask);
611
612// =====================================================================================
613// btCollisionShape entries
614
615public abstract float GetAngularMotionDisc(BulletShape shape);
616
617public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor);
618
619public abstract bool IsPolyhedral(BulletShape shape);
620
621public abstract bool IsConvex2d(BulletShape shape);
622
623public abstract bool IsConvex(BulletShape shape);
624
625public abstract bool IsNonMoving(BulletShape shape);
626
627public abstract bool IsConcave(BulletShape shape);
628
629public abstract bool IsCompound(BulletShape shape);
630
631public abstract bool IsSoftBody(BulletShape shape);
632
633public abstract bool IsInfinite(BulletShape shape);
634
635public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
636
637public abstract Vector3 GetLocalScaling(BulletShape shape);
638
639public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass);
640
641public abstract int GetShapeType(BulletShape shape);
642
643public abstract void SetMargin(BulletShape shape, float val);
644
645public abstract float GetMargin(BulletShape shape);
646
647// =====================================================================================
648// Debugging
649public abstract void DumpRigidBody(BulletWorld sim, BulletBody collisionObject);
650
651public abstract void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape);
652
653public abstract void DumpConstraint(BulletWorld sim, BulletConstraint constrain);
654
655public abstract void DumpActivationInfo(BulletWorld sim);
656
657public abstract void DumpAllInfo(BulletWorld sim);
658
659public abstract void DumpPhysicsStatistics(BulletWorld sim);
660
661};
662}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
deleted file mode 100644
index 103d8fc..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ /dev/null
@@ -1,827 +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.BulletSPlugin
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 float _currentFriction; // the friction currently being used (changed by setVelocity).
70
71 private BSVMotor _velocityMotor;
72
73 private OMV.Vector3 _PIDTarget;
74 private bool _usePID;
75 private float _PIDTau;
76 private bool _useHoverPID;
77 private float _PIDHoverHeight;
78 private PIDHoverType _PIDHoverType;
79 private float _PIDHoverTao;
80
81 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
82 : base(parent_scene, localID, avName, "BSCharacter")
83 {
84 _physicsActorType = (int)ActorTypes.Agent;
85 _position = pos;
86
87 _flying = isFlying;
88 _orientation = OMV.Quaternion.Identity;
89 _velocity = OMV.Vector3.Zero;
90 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
91 _currentFriction = BSParam.AvatarStandingFriction;
92 _avatarDensity = BSParam.AvatarDensity;
93
94 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
95 // replace with the default values.
96 _size = size;
97 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
98 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
99
100 // The dimensions of the physical capsule are kept in the scale.
101 // Physics creates a unit capsule which is scaled by the physics engine.
102 Scale = ComputeAvatarScale(_size);
103 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass();
105
106 SetupMovementMotor();
107
108 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
109 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
110
111 // do actual creation in taint time
112 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
113 {
114 DetailLog("{0},BSCharacter.create,taint", LocalID);
115 // New body and shape into PhysBody and PhysShape
116 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
117
118 SetPhysicalProperties();
119 });
120 return;
121 }
122
123 // called when this character is being destroyed and the resources should be released
124 public override void Destroy()
125 {
126 base.Destroy();
127
128 DetailLog("{0},BSCharacter.Destroy", LocalID);
129 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
130 {
131 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
132 PhysBody.Clear();
133 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
134 PhysShape.Clear();
135 });
136 }
137
138 private void SetPhysicalProperties()
139 {
140 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
141
142 ZeroMotion(true);
143 ForcePosition = _position;
144
145 // Set the velocity and compute the proper friction
146 _velocityMotor.Reset();
147 _velocityMotor.SetTarget(_velocity);
148 _velocityMotor.SetCurrent(_velocity);
149 ForceVelocity = _velocity;
150
151 // This will enable or disable the flying buoyancy of the avatar.
152 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
153 Flying = _flying;
154
155 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
156 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin);
157 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
158 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
159 if (BSParam.CcdMotionThreshold > 0f)
160 {
161 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
162 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
163 }
164
165 UpdatePhysicalMassProperties(RawMass, false);
166
167 // Make so capsule does not fall over
168 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
169
170 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
171
172 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
173
174 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
175 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
176 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
177
178 // Do this after the object has been added to the world
179 PhysBody.collisionType = CollisionType.Avatar;
180 PhysBody.ApplyCollisionMask(PhysicsScene);
181 }
182
183 // The avatar's movement is controlled by this motor that speeds up and slows down
184 // the avatar seeking to reach the motor's target speed.
185 // This motor runs as a prestep action for the avatar so it will keep the avatar
186 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
187 private void SetupMovementMotor()
188 {
189
190 // Someday, use a PID motor for asymmetric speed up and slow down
191 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
192
193 // Infinite decay and timescale values so motor only changes current to target values.
194 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
195 0.2f, // time scale
196 BSMotor.Infinite, // decay time scale
197 BSMotor.InfiniteVector, // friction timescale
198 1f // efficiency
199 );
200 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
201
202 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
203 {
204 // TODO: Decide if the step parameters should be changed depending on the avatar's
205 // state (flying, colliding, ...). There is code in ODE to do this.
206
207 OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
208
209 // If falling, we keep the world's downward vector no matter what the other axis specify.
210 if (!Flying && !IsColliding)
211 {
212 stepVelocity.Z = _velocity.Z;
213 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
214 }
215
216 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
217 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep;
218
219 /*
220 // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user
221 float moveForceMagnitudeSquared = moveForce.LengthSquared();
222 if (moveForceMagnitudeSquared < 0.0001)
223 {
224 DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}",
225 LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce);
226 ForceVelocity = OMV.Vector3.Zero;
227 }
228 else
229 {
230 AddForce(moveForce, false, true);
231 }
232 */
233 // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
234 AddForce(moveForce, false, true);
235 });
236 }
237
238 public override void RequestPhysicsterseUpdate()
239 {
240 base.RequestPhysicsterseUpdate();
241 }
242 // No one calls this method so I don't know what it could possibly mean
243 public override bool Stopped { get { return false; } }
244
245 public override OMV.Vector3 Size {
246 get
247 {
248 // Avatar capsule size is kept in the scale parameter.
249 return _size;
250 }
251
252 set {
253 _size = value;
254 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
255 // replace with the default values.
256 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
257 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
258
259 Scale = ComputeAvatarScale(_size);
260 ComputeAvatarVolumeAndMass();
261 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
262 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
263
264 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
265 {
266 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
267 {
268 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
269 UpdatePhysicalMassProperties(RawMass, true);
270 // Make sure this change appears as a property update event
271 PhysicsScene.PE.PushUpdate(PhysBody);
272 }
273 });
274
275 }
276 }
277
278 public override PrimitiveBaseShape Shape
279 {
280 set { BaseShape = value; }
281 }
282 // I want the physics engine to make an avatar capsule
283 public override BSPhysicsShapeType PreferredPhysicalShape
284 {
285 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
286 }
287
288 public override bool Grabbed {
289 set { _grabbed = value; }
290 }
291 public override bool Selected {
292 set { _selected = value; }
293 }
294 public override void CrossingFailure() { return; }
295 public override void link(PhysicsActor obj) { return; }
296 public override void delink() { return; }
297
298 // Set motion values to zero.
299 // Do it to the properties so the values get set in the physics engine.
300 // Push the setting of the values to the viewer.
301 // Called at taint time!
302 public override void ZeroMotion(bool inTaintTime)
303 {
304 _velocity = OMV.Vector3.Zero;
305 _acceleration = OMV.Vector3.Zero;
306 _rotationalVelocity = OMV.Vector3.Zero;
307
308 // Zero some other properties directly into the physics engine
309 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
310 {
311 if (PhysBody.HasPhysicalBody)
312 PhysicsScene.PE.ClearAllForces(PhysBody);
313 });
314 }
315 public override void ZeroAngularMotion(bool inTaintTime)
316 {
317 _rotationalVelocity = OMV.Vector3.Zero;
318
319 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
320 {
321 if (PhysBody.HasPhysicalBody)
322 {
323 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
324 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
325 // The next also get rid of applied linear force but the linear velocity is untouched.
326 PhysicsScene.PE.ClearForces(PhysBody);
327 }
328 });
329 }
330
331
332 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
333
334 public override OMV.Vector3 RawPosition
335 {
336 get { return _position; }
337 set { _position = value; }
338 }
339 public override OMV.Vector3 Position {
340 get {
341 // Don't refetch the position because this function is called a zillion times
342 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
343 return _position;
344 }
345 set {
346 _position = value;
347 PositionSanityCheck();
348
349 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
350 {
351 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
352 if (PhysBody.HasPhysicalBody)
353 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
354 });
355 }
356 }
357 public override OMV.Vector3 ForcePosition {
358 get {
359 _position = PhysicsScene.PE.GetPosition(PhysBody);
360 return _position;
361 }
362 set {
363 _position = value;
364 PositionSanityCheck();
365 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
366 }
367 }
368
369
370 // Check that the current position is sane and, if not, modify the position to make it so.
371 // Check for being below terrain or on water.
372 // Returns 'true' of the position was made sane by some action.
373 private bool PositionSanityCheck()
374 {
375 bool ret = false;
376
377 // TODO: check for out of bounds
378 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
379 {
380 // The character is out of the known/simulated area.
381 // Upper levels of code will handle the transition to other areas so, for
382 // the time, we just ignore the position.
383 return ret;
384 }
385
386 // If below the ground, move the avatar up
387 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
388 if (Position.Z < terrainHeight)
389 {
390 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
391 _position.Z = terrainHeight + 2.0f;
392 ret = true;
393 }
394 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
395 {
396 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
397 if (Position.Z < waterHeight)
398 {
399 _position.Z = waterHeight;
400 ret = true;
401 }
402 }
403
404 return ret;
405 }
406
407 // A version of the sanity check that also makes sure a new position value is
408 // pushed back to the physics engine. This routine would be used by anyone
409 // who is not already pushing the value.
410 private bool PositionSanityCheck(bool inTaintTime)
411 {
412 bool ret = false;
413 if (PositionSanityCheck())
414 {
415 // The new position value must be pushed into the physics engine but we can't
416 // just assign to "Position" because of potential call loops.
417 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
418 {
419 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
420 if (PhysBody.HasPhysicalBody)
421 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
422 });
423 ret = true;
424 }
425 return ret;
426 }
427
428 public override float Mass { get { return _mass; } }
429
430 // used when we only want this prim's mass and not the linkset thing
431 public override float RawMass {
432 get {return _mass; }
433 }
434 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
435 {
436 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
437 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia);
438 }
439
440 public override OMV.Vector3 Force {
441 get { return _force; }
442 set {
443 _force = value;
444 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
445 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
446 {
447 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
448 if (PhysBody.HasPhysicalBody)
449 PhysicsScene.PE.SetObjectForce(PhysBody, _force);
450 });
451 }
452 }
453
454 // Avatars don't do vehicles
455 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
456 public override void VehicleFloatParam(int param, float value) { }
457 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
458 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
459 public override void VehicleFlags(int param, bool remove) { }
460
461 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
462 public override void SetVolumeDetect(int param) { return; }
463
464 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
465 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
466
467 // Sets the target in the motor. This starts the changing of the avatar's velocity.
468 public override OMV.Vector3 TargetVelocity
469 {
470 get
471 {
472 return _velocityMotor.TargetValue;
473 }
474 set
475 {
476 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
477 OMV.Vector3 targetVel = value;
478 if (_setAlwaysRun)
479 targetVel *= BSParam.AvatarAlwaysRunFactor;
480
481 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
482 {
483 _velocityMotor.Reset();
484 _velocityMotor.SetTarget(targetVel);
485 _velocityMotor.SetCurrent(_velocity);
486 _velocityMotor.Enabled = true;
487 });
488 }
489 }
490 // Directly setting velocity means this is what the user really wants now.
491 public override OMV.Vector3 Velocity {
492 get { return _velocity; }
493 set {
494 _velocity = value;
495 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
496 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
497 {
498 _velocityMotor.Reset();
499 _velocityMotor.SetCurrent(_velocity);
500 _velocityMotor.SetTarget(_velocity);
501 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
502 _velocityMotor.Enabled = false;
503
504 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
505 ForceVelocity = _velocity;
506 });
507 }
508 }
509 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; }
511 set {
512 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
513
514 _velocity = value;
515 // Depending on whether the avatar is moving or not, change the friction
516 // to keep the avatar from slipping around
517 if (_velocity.Length() == 0)
518 {
519 if (_currentFriction != BSParam.AvatarStandingFriction)
520 {
521 _currentFriction = BSParam.AvatarStandingFriction;
522 if (PhysBody.HasPhysicalBody)
523 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
524 }
525 }
526 else
527 {
528 if (_currentFriction != BSParam.AvatarFriction)
529 {
530 _currentFriction = BSParam.AvatarFriction;
531 if (PhysBody.HasPhysicalBody)
532 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
533 }
534 }
535
536 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
537 PhysicsScene.PE.Activate(PhysBody, true);
538 }
539 }
540 public override OMV.Vector3 Torque {
541 get { return _torque; }
542 set { _torque = value;
543 }
544 }
545 public override float CollisionScore {
546 get { return _collisionScore; }
547 set { _collisionScore = value;
548 }
549 }
550 public override OMV.Vector3 Acceleration {
551 get { return _acceleration; }
552 set { _acceleration = value; }
553 }
554 public override OMV.Quaternion RawOrientation
555 {
556 get { return _orientation; }
557 set { _orientation = value; }
558 }
559 public override OMV.Quaternion Orientation {
560 get { return _orientation; }
561 set {
562 // Orientation is set zillions of times when an avatar is walking. It's like
563 // the viewer doesn't trust us.
564 if (_orientation != value)
565 {
566 _orientation = value;
567 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
568 {
569 ForceOrientation = _orientation;
570 });
571 }
572 }
573 }
574 // Go directly to Bullet to get/set the value.
575 public override OMV.Quaternion ForceOrientation
576 {
577 get
578 {
579 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
580 return _orientation;
581 }
582 set
583 {
584 _orientation = value;
585 if (PhysBody.HasPhysicalBody)
586 {
587 // _position = PhysicsScene.PE.GetPosition(BSBody);
588 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
589 }
590 }
591 }
592 public override int PhysicsActorType {
593 get { return _physicsActorType; }
594 set { _physicsActorType = value;
595 }
596 }
597 public override bool IsPhysical {
598 get { return _isPhysical; }
599 set { _isPhysical = value;
600 }
601 }
602 public override bool IsSolid {
603 get { return true; }
604 }
605 public override bool IsStatic {
606 get { return false; }
607 }
608 public override bool Flying {
609 get { return _flying; }
610 set {
611 _flying = value;
612
613 // simulate flying by changing the effect of gravity
614 Buoyancy = ComputeBuoyancyFromFlying(_flying);
615 }
616 }
617 // Flying is implimented by changing the avatar's buoyancy.
618 // Would this be done better with a vehicle type?
619 private float ComputeBuoyancyFromFlying(bool ifFlying) {
620 return ifFlying ? 1f : 0f;
621 }
622 public override bool
623 SetAlwaysRun {
624 get { return _setAlwaysRun; }
625 set { _setAlwaysRun = value; }
626 }
627 public override bool ThrottleUpdates {
628 get { return _throttleUpdates; }
629 set { _throttleUpdates = value; }
630 }
631 public override bool FloatOnWater {
632 set {
633 _floatOnWater = value;
634 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
635 {
636 if (PhysBody.HasPhysicalBody)
637 {
638 if (_floatOnWater)
639 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
640 else
641 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
642 }
643 });
644 }
645 }
646 public override OMV.Vector3 RotationalVelocity {
647 get { return _rotationalVelocity; }
648 set { _rotationalVelocity = value; }
649 }
650 public override OMV.Vector3 ForceRotationalVelocity {
651 get { return _rotationalVelocity; }
652 set { _rotationalVelocity = value; }
653 }
654 public override bool Kinematic {
655 get { return _kinematic; }
656 set { _kinematic = value; }
657 }
658 // neg=fall quickly, 0=1g, 1=0g, pos=float up
659 public override float Buoyancy {
660 get { return _buoyancy; }
661 set { _buoyancy = value;
662 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
663 {
664 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
665 ForceBuoyancy = _buoyancy;
666 });
667 }
668 }
669 public override float ForceBuoyancy {
670 get { return _buoyancy; }
671 set {
672 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
673
674 _buoyancy = value;
675 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
676 // Buoyancy is faked by changing the gravity applied to the object
677 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
678 if (PhysBody.HasPhysicalBody)
679 PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav));
680 }
681 }
682
683 // Used for MoveTo
684 public override OMV.Vector3 PIDTarget {
685 set { _PIDTarget = value; }
686 }
687 public override bool PIDActive {
688 set { _usePID = value; }
689 }
690 public override float PIDTau {
691 set { _PIDTau = value; }
692 }
693
694 // Used for llSetHoverHeight and maybe vehicle height
695 // Hover Height will override MoveTo target's Z
696 public override bool PIDHoverActive {
697 set { _useHoverPID = value; }
698 }
699 public override float PIDHoverHeight {
700 set { _PIDHoverHeight = value; }
701 }
702 public override PIDHoverType PIDHoverType {
703 set { _PIDHoverType = value; }
704 }
705 public override float PIDHoverTau {
706 set { _PIDHoverTao = value; }
707 }
708
709 // For RotLookAt
710 public override OMV.Quaternion APIDTarget { set { return; } }
711 public override bool APIDActive { set { return; } }
712 public override float APIDStrength { set { return; } }
713 public override float APIDDamping { set { return; } }
714
715 public override void AddForce(OMV.Vector3 force, bool pushforce)
716 {
717 // Since this force is being applied in only one step, make this a force per second.
718 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
719 AddForce(addForce, pushforce, false);
720 }
721 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
722 if (force.IsFinite())
723 {
724 float magnitude = force.Length();
725 if (magnitude > BSParam.MaxAddForceMagnitude)
726 {
727 // Force has a limit
728 force = force / magnitude * BSParam.MaxAddForceMagnitude;
729 }
730
731 OMV.Vector3 addForce = force;
732 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
733
734 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
735 {
736 // Bullet adds this central force to the total force for this tick
737 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
738 if (PhysBody.HasPhysicalBody)
739 {
740 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
741 }
742 });
743 }
744 else
745 {
746 m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
747 return;
748 }
749 }
750
751 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
752 }
753 public override void SetMomentum(OMV.Vector3 momentum) {
754 }
755
756 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
757 {
758 OMV.Vector3 newScale;
759
760 // Bullet's capsule total height is the "passed height + radius * 2";
761 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
762 // The number we pass in for 'scaling' is the multiplier to get that base
763 // shape to be the size desired.
764 // So, when creating the scale for the avatar height, we take the passed height
765 // (size.Z) and remove the caps.
766 // Another oddity of the Bullet capsule implementation is that it presumes the Y
767 // dimension is the radius of the capsule. Even though some of the code allows
768 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
769
770 // Scale is multiplier of radius with one of "0.5"
771 newScale.X = size.X / 2f;
772 newScale.Y = size.Y / 2f;
773
774 // The total scale height is the central cylindar plus the caps on the two ends.
775 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
776 // If smaller than the endcaps, just fake like we're almost that small
777 if (newScale.Z < 0)
778 newScale.Z = 0.1f;
779
780 return newScale;
781 }
782
783 // set _avatarVolume and _mass based on capsule size, _density and Scale
784 private void ComputeAvatarVolumeAndMass()
785 {
786 _avatarVolume = (float)(
787 Math.PI
788 * Size.X / 2f
789 * Size.Y / 2f // the area of capsule cylinder
790 * Size.Z // times height of capsule cylinder
791 + 1.33333333f
792 * Math.PI
793 * Size.X / 2f
794 * Math.Min(Size.X, Size.Y) / 2
795 * Size.Y / 2f // plus the volume of the capsule end caps
796 );
797 _mass = _avatarDensity * _avatarVolume;
798 }
799
800 // The physics engine says that properties have updated. Update same and inform
801 // the world that things have changed.
802 public override void UpdateProperties(EntityProperties entprop)
803 {
804 _position = entprop.Position;
805 _orientation = entprop.Rotation;
806 _velocity = entprop.Velocity;
807 _acceleration = entprop.Acceleration;
808 _rotationalVelocity = entprop.RotationalVelocity;
809
810 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
811 PositionSanityCheck(true);
812
813 // remember the current and last set values
814 LastEntityProperties = CurrentEntityProperties;
815 CurrentEntityProperties = entprop;
816
817 // Tell the linkset about value changes
818 Linkset.UpdateProperties(this, true);
819
820 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
821 // base.RequestPhysicsterseUpdate();
822
823 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
824 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
825 }
826}
827}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
deleted file mode 100755
index b813974..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ /dev/null
@@ -1,138 +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.BulletSPlugin
33{
34
35public abstract class BSConstraint : IDisposable
36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
39 protected BulletWorld m_world;
40 protected BSScene PhysicsScene;
41 protected BulletBody m_body1;
42 protected BulletBody m_body2;
43 protected BulletConstraint m_constraint;
44 protected bool m_enabled = false;
45
46 public BulletBody Body1 { get { return m_body1; } }
47 public BulletBody Body2 { get { return m_body2; } }
48 public BulletConstraint Constraint { get { return m_constraint; } }
49 public abstract ConstraintType Type { get; }
50 public bool IsEnabled { get { return m_enabled; } }
51
52 public BSConstraint(BulletWorld world)
53 {
54 m_world = world;
55 PhysicsScene = m_world.physicsScene;
56 }
57
58 public virtual void Dispose()
59 {
60 if (m_enabled)
61 {
62 m_enabled = false;
63 if (m_constraint.HasPhysicalConstraint)
64 {
65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
67 BSScene.DetailLogZero,
68 m_body1.ID, m_body1.AddrString,
69 m_body2.ID, m_body2.AddrString,
70 success);
71 m_constraint.Clear();
72 }
73 }
74 }
75
76 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
77 {
78 bool ret = false;
79 if (m_enabled)
80 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
81 return ret;
82 }
83
84 public virtual bool SetAngularLimits(Vector3 low, Vector3 high)
85 {
86 bool ret = false;
87 if (m_enabled)
88 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
89 return ret;
90 }
91
92 public virtual bool SetSolverIterations(float cnt)
93 {
94 bool ret = false;
95 if (m_enabled)
96 {
97 PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt);
98 ret = true;
99 }
100 return ret;
101 }
102
103 public virtual bool CalculateTransforms()
104 {
105 bool ret = false;
106 if (m_enabled)
107 {
108 // Recompute the internal transforms
109 PhysicsScene.PE.CalculateTransforms(m_constraint);
110 ret = true;
111 }
112 return ret;
113 }
114
115 // Reset this constraint making sure it has all its internal structures
116 // recomputed and is enabled and ready to go.
117 public virtual bool RecomputeConstraintVariables(float mass)
118 {
119 bool ret = false;
120 if (m_enabled)
121 {
122 ret = CalculateTransforms();
123 if (ret)
124 {
125 // Setting an object's mass to zero (making it static like when it's selected)
126 // automatically disables the constraints.
127 // If the link is enabled, be sure to set the constraint itself to enabled.
128 PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true));
129 }
130 else
131 {
132 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
133 }
134 }
135 return ret;
136 }
137}
138}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
deleted file mode 100755
index ecb1b32..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ /dev/null
@@ -1,151 +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.BulletSPlugin
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 : base(world)
47 {
48 m_body1 = obj1;
49 m_body2 = obj2;
50 m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2,
51 frame1, frame1rot,
52 frame2, frame2rot,
53 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
54 m_enabled = true;
55 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
56 BSScene.DetailLogZero, world.worldID,
57 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
58 }
59
60 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
61 Vector3 joinPoint,
62 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
63 : base(world)
64 {
65 m_body1 = obj1;
66 m_body2 = obj2;
67 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
68 {
69 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
70 BSScene.DetailLogZero, world.worldID,
71 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
72 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
73 LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
74 m_enabled = false;
75 }
76 else
77 {
78 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
79 joinPoint,
80 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
81 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
82 BSScene.DetailLogZero, world.worldID, m_constraint.AddrString,
83 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
84 if (!m_constraint.HasPhysicalConstraint)
85 {
86 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
87 LogHeader, obj1.ID, obj2.ID);
88 m_enabled = false;
89 }
90 else
91 {
92 m_enabled = true;
93 }
94 }
95 }
96
97 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
98 {
99 bool ret = false;
100 if (m_enabled)
101 {
102 PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot);
103 ret = true;
104 }
105 return ret;
106 }
107
108 public bool SetCFMAndERP(float cfm, float erp)
109 {
110 bool ret = false;
111 if (m_enabled)
112 {
113 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
114 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
115 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
116 ret = true;
117 }
118 return ret;
119 }
120
121 public bool UseFrameOffset(bool useOffset)
122 {
123 bool ret = false;
124 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
125 if (m_enabled)
126 ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff);
127 return ret;
128 }
129
130 public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
131 {
132 bool ret = false;
133 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
134 if (m_enabled)
135 {
136 ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce);
137 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
138 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
139 }
140 return ret;
141 }
142
143 public bool SetBreakingImpulseThreshold(float threshold)
144 {
145 bool ret = false;
146 if (m_enabled)
147 ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold);
148 return ret;
149 }
150}
151}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
deleted file mode 100755
index 2aeff25..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/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.BulletSPlugin
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/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
deleted file mode 100755
index 7714a03..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
+++ /dev/null
@@ -1,55 +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.BulletSPlugin
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 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 pivotInA, pivotInB, axisInA, axisInB,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52
53}
54
55}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
deleted file mode 100644
index 13c2539..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ /dev/null
@@ -1,1383 +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.BulletSPlugin
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 PhysicsScene.PE.SetFriction(Prim.PhysBody, 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 PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, angularDamping);
568
569 // Vehicles report collision events so we know when it's on the ground
570 PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
571
572 Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass);
573 PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, localInertia);
574 PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody);
575
576 Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy);
577 PhysicsScene.PE.SetGravity(Prim.PhysBody, 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 PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, 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 PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, 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 PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, 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 PhysicsScene.PE.PushUpdate(Prim.PhysBody);
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 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
826 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
827
828 ForgetKnownVehicleProperties();
829
830 MoveLinear(pTimestep);
831 MoveAngular(pTimestep);
832
833 LimitRotation(pTimestep);
834
835 // remember the position so next step we can limit absolute movement effects
836 m_lastPositionVector = VehiclePosition;
837
838 // If we forced the changing of some vehicle parameters, update the values and
839 // for the physics engine to note the changes so an UpdateProperties event will happen.
840 PushKnownChanged();
841
842 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
843 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
844
845 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
846 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity);
847 }
848
849 // Apply the effect of the linear motor and other linear motions (like hover and float).
850 private void MoveLinear(float pTimestep)
851 {
852 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
853
854 // The movement computed in the linear motor is relative to the vehicle
855 // coordinates. Rotate the movement to world coordinates.
856 linearMotorContribution *= VehicleOrientation;
857
858 // ==================================================================
859 // Buoyancy: force to overcome gravity.
860 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
861 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
862 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
863
864 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
865
866 Vector3 hoverContribution = ComputeLinearHover(pTimestep);
867
868 ComputeLinearBlockingEndPoint(pTimestep);
869
870 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep);
871
872 // ==================================================================
873 Vector3 newVelocity = linearMotorContribution
874 + terrainHeightContribution
875 + hoverContribution
876 + limitMotorUpContribution;
877
878 Vector3 newForce = buoyancyContribution;
879
880 // If not changing some axis, reduce out velocity
881 if ((m_flags & (VehicleFlag.NO_X)) != 0)
882 newVelocity.X = 0;
883 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
884 newVelocity.Y = 0;
885 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
886 newVelocity.Z = 0;
887
888 // ==================================================================
889 // Clamp high or low velocities
890 float newVelocityLengthSq = newVelocity.LengthSquared();
891 if (newVelocityLengthSq > 1000f)
892 {
893 newVelocity /= newVelocity.Length();
894 newVelocity *= 1000f;
895 }
896 else if (newVelocityLengthSq < 0.001f)
897 newVelocity = Vector3.Zero;
898
899 // ==================================================================
900 // Stuff new linear velocity into the vehicle.
901 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us.
902 VehicleVelocity = newVelocity;
903
904 // Other linear forces are applied as forces.
905 Vector3 totalDownForce = newForce * m_vehicleMass;
906 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
907 {
908 VehicleAddForce(totalDownForce);
909 }
910
911 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}",
912 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding);
913 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
914 Prim.LocalID,
915 linearMotorContribution, terrainHeightContribution, hoverContribution,
916 limitMotorUpContribution, buoyancyContribution
917 );
918
919 } // end MoveLinear()
920
921 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep)
922 {
923 Vector3 ret = Vector3.Zero;
924 // If below the terrain, move us above the ground a little.
925 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
926 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
927 {
928 // TODO: correct position by applying force rather than forcing position.
929 Vector3 newPosition = VehiclePosition;
930 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
931 VehiclePosition = newPosition;
932 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
933 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
934 }
935 return ret;
936 }
937
938 public Vector3 ComputeLinearHover(float pTimestep)
939 {
940 Vector3 ret = Vector3.Zero;
941
942 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
943 // m_VhoverTimescale: time to achieve height
944 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
945 {
946 // We should hover, get the target height
947 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
948 {
949 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
950 }
951 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
952 {
953 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
954 }
955 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
956 {
957 m_VhoverTargetHeight = m_VhoverHeight;
958 }
959
960 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
961 {
962 // If body is already heigher, use its height as target height
963 if (VehiclePosition.Z > m_VhoverTargetHeight)
964 m_VhoverTargetHeight = VehiclePosition.Z;
965 }
966
967 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
968 {
969 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
970 {
971 Vector3 pos = VehiclePosition;
972 pos.Z = m_VhoverTargetHeight;
973 VehiclePosition = pos;
974 }
975 }
976 else
977 {
978 // Error is positive if below the target and negative if above.
979 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z;
980 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
981
982 // TODO: implement m_VhoverEfficiency correctly
983 if (Math.Abs(verticalError) > m_VhoverEfficiency)
984 {
985 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
986 }
987 }
988
989 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}",
990 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight);
991 }
992
993 return ret;
994 }
995
996 public bool ComputeLinearBlockingEndPoint(float pTimestep)
997 {
998 bool changed = false;
999
1000 Vector3 pos = VehiclePosition;
1001 Vector3 posChange = pos - m_lastPositionVector;
1002 if (m_BlockingEndPoint != Vector3.Zero)
1003 {
1004 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
1005 {
1006 pos.X -= posChange.X + 1;
1007 changed = true;
1008 }
1009 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
1010 {
1011 pos.Y -= posChange.Y + 1;
1012 changed = true;
1013 }
1014 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
1015 {
1016 pos.Z -= posChange.Z + 1;
1017 changed = true;
1018 }
1019 if (pos.X <= 0)
1020 {
1021 pos.X += posChange.X + 1;
1022 changed = true;
1023 }
1024 if (pos.Y <= 0)
1025 {
1026 pos.Y += posChange.Y + 1;
1027 changed = true;
1028 }
1029 if (changed)
1030 {
1031 VehiclePosition = pos;
1032 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1033 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
1034 }
1035 }
1036 return changed;
1037 }
1038
1039 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1040 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
1041 // used with conjunction with banking: the strength of the banking will decay when the
1042 // vehicle no longer experiences collisions. The decay timescale is the same as
1043 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1044 // when they are in mid jump.
1045 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1046 // This is just using the ground and a general collision check. Should really be using
1047 // a downward raycast to find what is below.
1048 public Vector3 ComputeLinearMotorUp(float pTimestep)
1049 {
1050 Vector3 ret = Vector3.Zero;
1051 float distanceAboveGround = 0f;
1052
1053 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1054 {
1055 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1056 distanceAboveGround = VehiclePosition.Z - targetHeight;
1057 // Not colliding if the vehicle is off the ground
1058 if (!Prim.IsColliding)
1059 {
1060 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1061 ret = new Vector3(0, 0, -distanceAboveGround);
1062 }
1063 // TODO: this calculation is wrong. From the description at
1064 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
1065 // has a decay factor. This says this force should
1066 // be computed with a motor.
1067 // TODO: add interaction with banking.
1068 }
1069 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1070 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
1071 return ret;
1072 }
1073
1074 // =======================================================================
1075 // =======================================================================
1076 // Apply the effect of the angular motor.
1077 // The 'contribution' is how much angular correction velocity each function wants.
1078 // All the contributions are added together and the resulting velocity is
1079 // set directly on the vehicle.
1080 private void MoveAngular(float pTimestep)
1081 {
1082 // The user wants this many radians per second angular change?
1083 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
1084
1085 // ==================================================================
1086 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1087 // This flag prevents linear deflection parallel to world z-axis. This is useful
1088 // for preventing ground vehicles with large linear deflection, like bumper cars,
1089 // from climbing their linear deflection into the sky.
1090 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1091 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1092 {
1093 angularMotorContribution.X = 0f;
1094 angularMotorContribution.Y = 0f;
1095 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
1096 }
1097
1098 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
1099
1100 Vector3 deflectionContribution = ComputeAngularDeflection();
1101
1102 Vector3 bankingContribution = ComputeAngularBanking();
1103
1104 // ==================================================================
1105 m_lastVertAttractor = verticalAttractionContribution;
1106
1107 m_lastAngularVelocity = angularMotorContribution
1108 + verticalAttractionContribution
1109 + deflectionContribution
1110 + bankingContribution;
1111
1112 // ==================================================================
1113 // Apply the correction velocity.
1114 // TODO: Should this be applied as an angular force (torque)?
1115 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1116 {
1117 VehicleRotationalVelocity = m_lastAngularVelocity;
1118
1119 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}",
1120 Prim.LocalID,
1121 angularMotorContribution, verticalAttractionContribution,
1122 bankingContribution, deflectionContribution,
1123 m_lastAngularVelocity
1124 );
1125 }
1126 else
1127 {
1128 // The vehicle is not adding anything angular wise.
1129 VehicleRotationalVelocity = Vector3.Zero;
1130 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
1131 }
1132
1133 // ==================================================================
1134 //Offset section
1135 if (m_linearMotorOffset != Vector3.Zero)
1136 {
1137 //Offset of linear velocity doesn't change the linear velocity,
1138 // but causes a torque to be applied, for example...
1139 //
1140 // IIIII >>> IIIII
1141 // IIIII >>> IIIII
1142 // IIIII >>> IIIII
1143 // ^
1144 // | Applying a force at the arrow will cause the object to move forward, but also rotate
1145 //
1146 //
1147 // The torque created is the linear velocity crossed with the offset
1148
1149 // TODO: this computation should be in the linear section
1150 // because that is where we know the impulse being applied.
1151 Vector3 torqueFromOffset = Vector3.Zero;
1152 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
1153 if (float.IsNaN(torqueFromOffset.X))
1154 torqueFromOffset.X = 0;
1155 if (float.IsNaN(torqueFromOffset.Y))
1156 torqueFromOffset.Y = 0;
1157 if (float.IsNaN(torqueFromOffset.Z))
1158 torqueFromOffset.Z = 0;
1159
1160 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1161 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1162 }
1163
1164 }
1165 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1166 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1167 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1168 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1169 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1170 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1171 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1172 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1173 public Vector3 ComputeAngularVerticalAttraction()
1174 {
1175 Vector3 ret = Vector3.Zero;
1176
1177 // If vertical attaction timescale is reasonable
1178 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1179 {
1180 // Take a vector pointing up and convert it from world to vehicle relative coords.
1181 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
1182
1183 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1184 // is now:
1185 // leaning to one side: rotated around the X axis with the Y value going
1186 // from zero (nearly straight up) to one (completely to the side)) or
1187 // leaning front-to-back: rotated around the Y axis with the value of X being between
1188 // zero and one.
1189 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1190
1191 // Y error means needed rotation around X axis and visa versa.
1192 // Since the error goes from zero to one, the asin is the corresponding angle.
1193 ret.X = (float)Math.Asin(verticalError.Y);
1194 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1195 ret.Y = -(float)Math.Asin(verticalError.X);
1196
1197 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1198 if (verticalError.Z < 0f)
1199 {
1200 ret.X += PIOverFour;
1201 ret.Y += PIOverFour;
1202 }
1203
1204 // 'ret' is now the necessary velocity to correct tilt in one second.
1205 // Correction happens over a number of seconds.
1206 Vector3 unscaledContrib = ret;
1207 ret /= m_verticalAttractionTimescale;
1208
1209 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1210 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret);
1211 }
1212 return ret;
1213 }
1214
1215 // Return the angular correction to correct the direction the vehicle is pointing to be
1216 // the direction is should want to be pointing.
1217 // The vehicle is moving in some direction and correct its orientation to it is pointing
1218 // in that direction.
1219 // TODO: implement reference frame.
1220 public Vector3 ComputeAngularDeflection()
1221 {
1222 Vector3 ret = Vector3.Zero;
1223 return ret; // DEBUG DEBUG DEBUG
1224 // Disable angular deflection for the moment.
1225 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1226 // approximately the same X or Y correction. When added together (when contributions are combined)
1227 // this creates an over-correction and then wabbling as the target is overshot.
1228 // TODO: rethink how the different correction computations inter-relate.
1229
1230 if (m_angularDeflectionEfficiency != 0)
1231 {
1232 // The direction the vehicle is moving
1233 Vector3 movingDirection = VehicleVelocity;
1234 movingDirection.Normalize();
1235
1236 // The direction the vehicle is pointing
1237 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1238 pointingDirection.Normalize();
1239
1240 // The difference between what is and what should be.
1241 Vector3 deflectionError = movingDirection - pointingDirection;
1242
1243 // Don't try to correct very large errors (not our job)
1244 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1245 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1246 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1247
1248 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1249
1250 // Scale the correction by recovery timescale and efficiency
1251 ret = (-deflectionError) * m_angularDeflectionEfficiency;
1252 ret /= m_angularDeflectionTimescale;
1253
1254 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1255 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
1256 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1257 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1258 }
1259 return ret;
1260 }
1261
1262 // Return an angular change to rotate the vehicle around the Z axis when the vehicle
1263 // is tipped around the X axis.
1264 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1265 // The vertical attractor feature must be enabled in order for the banking behavior to
1266 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1267 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1268 // of the yaw effect will be proportional to the
1269 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1270 // velocity along its preferred axis of motion.
1271 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1272 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1273 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1274 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1275 // Negating the banking coefficient will make it so that the vehicle leans to the
1276 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1277 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1278 // banking vehicles do what you want rather than what the laws of physics allow.
1279 // For example, consider a real motorcycle...it must be moving forward in order for
1280 // it to turn while banking, however video-game motorcycles are often configured
1281 // to turn in place when at a dead stop--because they are often easier to control
1282 // that way using the limited interface of the keyboard or game controller. The
1283 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1284 // banking by functioning as a slider between a banking that is correspondingly
1285 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1286 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1287 // to "dynamic" where the banking is also proportional to its velocity along its
1288 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1289 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1290 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1291 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1292 // make a sluggish vehicle by giving it a timescale of several seconds.
1293 public Vector3 ComputeAngularBanking()
1294 {
1295 Vector3 ret = Vector3.Zero;
1296
1297 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1298 {
1299 // This works by rotating a unit vector to the orientation of the vehicle. The
1300 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
1301 // up to one for full over).
1302 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1303
1304 // Figure out the yaw value for this much roll.
1305 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency;
1306 // Keep the sign
1307 if (rollComponents.Y < 0f)
1308 turnComponent = -turnComponent;
1309
1310 // TODO: there must be a better computation of the banking force.
1311 float bankingTurnForce = turnComponent;
1312
1313 // actual error = static turn error + dynamic turn error
1314 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed;
1315 // TODO: the banking effect should not go to infinity but what to limit it to?
1316 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f);
1317
1318 // Build the force vector to change rotation from what it is to what it should be
1319 ret.Z = -mixedBankingError;
1320
1321 // Don't do it all at once.
1322 ret /= m_bankingTimescale;
1323
1324 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}",
1325 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret);
1326 }
1327 return ret;
1328 }
1329
1330 // This is from previous instantiations of XXXDynamics.cs.
1331 // Applies roll reference frame.
1332 // TODO: is this the right way to separate the code to do this operation?
1333 // Should this be in MoveAngular()?
1334 internal void LimitRotation(float timestep)
1335 {
1336 Quaternion rotq = VehicleOrientation;
1337 Quaternion m_rot = rotq;
1338 if (m_RollreferenceFrame != Quaternion.Identity)
1339 {
1340 if (rotq.X >= m_RollreferenceFrame.X)
1341 {
1342 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
1343 }
1344 if (rotq.Y >= m_RollreferenceFrame.Y)
1345 {
1346 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
1347 }
1348 if (rotq.X <= -m_RollreferenceFrame.X)
1349 {
1350 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
1351 }
1352 if (rotq.Y <= -m_RollreferenceFrame.Y)
1353 {
1354 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
1355 }
1356 }
1357 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
1358 {
1359 m_rot.X = 0;
1360 m_rot.Y = 0;
1361 }
1362 if (rotq != m_rot)
1363 {
1364 VehicleOrientation = m_rot;
1365 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1366 }
1367
1368 }
1369
1370 private float ClampInRange(float low, float val, float high)
1371 {
1372 return Math.Max(low, Math.Min(val, high));
1373 // return Utils.Clamp(val, low, high);
1374 }
1375
1376 // Invoke the detailed logger and output something if it's enabled.
1377 private void VDetailLog(string msg, params Object[] args)
1378 {
1379 if (Prim.PhysicsScene.VehicleLoggingEnabled)
1380 Prim.PhysicsScene.DetailLog(msg, args);
1381 }
1382 }
1383}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
deleted file mode 100755
index 756faed..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/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.BulletSPlugin
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/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
deleted file mode 100755
index bd03d31..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ /dev/null
@@ -1,392 +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.BulletSPlugin
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},hasChildren={2}",
102 requestor.LocalID, Rebuilding, HasAnyChildren);
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 a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
106 if (!Rebuilding && HasAnyChildren)
107 {
108 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
109 {
110 if (HasAnyChildren)
111 RecomputeLinksetCompound();
112 });
113 }
114 }
115
116 // The object is going dynamic (physical). Do any setup necessary 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. Rebuild the linkset so parts and mass get computed properly.
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 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
135 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
136 // We don't want collisions from the old linkset children.
137 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, 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 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, 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 PhysicsScene.PE.Activate(child.PhysBody, 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.AddrString, 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.AddrString,
284 child.LocalID, child.PhysBody.AddrString);
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 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, 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 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, 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 = ComputeLinksetMass();
382 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
383 }
384 finally
385 {
386 Rebuilding = false;
387 }
388
389 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
390 }
391}
392} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
deleted file mode 100755
index d0b2a56..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ /dev/null
@@ -1,312 +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.BulletSPlugin
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 if (HasAnyChildren && IsRoot(requestor))
52 {
53 // Queue to happen after all the other taint processing
54 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
55 {
56 if (HasAnyChildren && IsRoot(requestor))
57 RecomputeLinksetConstraints();
58 });
59 }
60 }
61
62 // The object is going dynamic (physical). Do any setup necessary
63 // for a dynamic linkset.
64 // Only the state of the passed object can be modified. The rest of the linkset
65 // has not yet been fully constructed.
66 // Return 'true' if any properties updated on the passed object.
67 // Called at taint-time!
68 public override bool MakeDynamic(BSPhysObject child)
69 {
70 // What is done for each object in BSPrim is what we want.
71 return false;
72 }
73
74 // The object is going static (non-physical). Do any setup necessary for a static linkset.
75 // Return 'true' if any properties updated on the passed object.
76 // This doesn't normally happen -- OpenSim removes the objects from the physical
77 // world if it is a static linkset.
78 // Called at taint-time!
79 public override bool MakeStatic(BSPhysObject child)
80 {
81 // What is done for each object in BSPrim is what we want.
82 return false;
83 }
84
85 // Called at taint-time!!
86 public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
87 {
88 // Nothing to do for constraints on property updates
89 }
90
91 // Routine called when rebuilding the body of some member of the linkset.
92 // Destroy all the constraints have have been made to root and set
93 // up to rebuild the constraints before the next simulation step.
94 // Returns 'true' of something was actually removed and would need restoring
95 // Called at taint-time!!
96 public override bool RemoveBodyDependencies(BSPrim child)
97 {
98 bool ret = false;
99
100 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
102
103 lock (m_linksetActivityLock)
104 {
105 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
106 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
107 // Cause the constraints, et al to be rebuilt before the next simulation step.
108 Refresh(LinksetRoot);
109 }
110 return ret;
111 }
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 // ================================================================
122
123 // Add a new child to the linkset.
124 // Called while LinkActivity is locked.
125 protected override void AddChildToLinkset(BSPhysObject child)
126 {
127 if (!HasChild(child))
128 {
129 m_children.Add(child);
130
131 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
132
133 // Cause constraints and assorted properties to be recomputed before the next simulation step.
134 Refresh(LinksetRoot);
135 }
136 return;
137 }
138
139 // Remove the specified child from the linkset.
140 // Safe to call even if the child is not really in my linkset.
141 protected override void RemoveChildFromLinkset(BSPhysObject child)
142 {
143 if (m_children.Remove(child))
144 {
145 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
146 BSPhysObject childx = child;
147
148 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
149 childx.LocalID,
150 rootx.LocalID, rootx.PhysBody.AddrString,
151 childx.LocalID, childx.PhysBody.AddrString);
152
153 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
154 {
155 PhysicallyUnlinkAChildFromRoot(rootx, childx);
156 });
157 // See that the linkset parameters are recomputed at the end of the taint time.
158 Refresh(LinksetRoot);
159 }
160 else
161 {
162 // Non-fatal occurance.
163 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
164 }
165 return;
166 }
167
168 // Create a constraint between me (root of linkset) and the passed prim (the child).
169 // Called at taint time!
170 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
171 {
172 // Don't build the constraint when asked. Put it off until just before the simulation step.
173 Refresh(rootPrim);
174 }
175
176 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
177 {
178 // Zero motion for children so they don't interpolate
179 childPrim.ZeroMotion(true);
180
181 // Relative position normalized to the root prim
182 // Essentually a vector pointing from center of rootPrim to center of childPrim
183 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
184
185 // real world coordinate of midpoint between the two objects
186 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
187
188 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
189 rootPrim.LocalID,
190 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
191 childPrim.LocalID, childPrim.PhysBody.AddrString,
192 rootPrim.Position, childPrim.Position, midPoint);
193
194 // create a constraint that allows no freedom of movement between the two objects
195 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
196
197 BSConstraint6Dof constrain = new BSConstraint6Dof(
198 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
199 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
200
201 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
202 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
203 * of the objects.
204 * Code left for future programmers.
205 // ==================================================================================
206 // relative position normalized to the root prim
207 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
208 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
209
210 // relative rotation of the child to the parent
211 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
212 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
213
214 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
215 BS6DofConstraint constrain = new BS6DofConstraint(
216 PhysicsScene.World, rootPrim.Body, childPrim.Body,
217 OMV.Vector3.Zero,
218 OMV.Quaternion.Inverse(rootPrim.Orientation),
219 OMV.Vector3.Zero,
220 OMV.Quaternion.Inverse(childPrim.Orientation),
221 true,
222 true
223 );
224 // ==================================================================================
225 */
226
227 PhysicsScene.Constraints.AddConstraint(constrain);
228
229 // zero linear and angular limits makes the objects unable to move in relation to each other
230 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
231 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
232
233 // tweek the constraint to increase stability
234 constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
235 constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
236 BSParam.LinkConstraintTransMotorMaxVel,
237 BSParam.LinkConstraintTransMotorMaxForce);
238 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
239 if (BSParam.LinkConstraintSolverIterations != 0f)
240 {
241 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
242 }
243 return constrain;
244 }
245
246 // Remove linkage between the linkset root and a particular child
247 // The root and child bodies are passed in because we need to remove the constraint between
248 // the bodies that were present at unlink time.
249 // Called at taint time!
250 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
251 {
252 bool ret = false;
253 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
254 rootPrim.LocalID,
255 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
256 childPrim.LocalID, childPrim.PhysBody.AddrString);
257
258 // Find the constraint for this link and get rid of it from the overall collection and from my list
259 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
260 {
261 // Make the child refresh its location
262 PhysicsScene.PE.PushUpdate(childPrim.PhysBody);
263 ret = true;
264 }
265
266 return ret;
267 }
268
269 // Remove linkage between myself and any possible children I might have.
270 // Returns 'true' of any constraints were destroyed.
271 // Called at taint time!
272 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
273 {
274 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
275
276 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
277 }
278
279 // Call each of the constraints that make up this linkset and recompute the
280 // various transforms and variables. Create constraints of not created yet.
281 // Called before the simulation step to make sure the constraint based linkset
282 // is all initialized.
283 // Called at taint time!!
284 private void RecomputeLinksetConstraints()
285 {
286 float linksetMass = LinksetMass;
287 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
288
289 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
290 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, 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 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
308 }
309
310 }
311}
312}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
deleted file mode 100755
index 92d62ff..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/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.BulletSPlugin
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/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
deleted file mode 100755
index 817a5f7..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/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.BulletSPlugin
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},lastErr={3},decayTS={4},frictTS={5}>",
245 UseName, CurrentValue, TargetValue, LastError, 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/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
deleted file mode 100755
index 69ac8cd..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ /dev/null
@@ -1,582 +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.BulletSPlugin
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 AvatarAlwaysRunFactor { get; private set; }
72 public static float AvatarDensity { get; private set; }
73 public static float AvatarRestitution { get; private set; }
74 public static float AvatarCapsuleWidth { get; private set; }
75 public static float AvatarCapsuleDepth { get; private set; }
76 public static float AvatarCapsuleHeight { get; private set; }
77 public static float AvatarContactProcessingThreshold { get; private set; }
78
79 public static float VehicleAngularDamping { get; private set; }
80
81 public static float LinksetImplementation { get; private set; }
82 public static float LinkConstraintUseFrameOffset { get; private set; }
83 public static float LinkConstraintEnableTransMotor { get; private set; }
84 public static float LinkConstraintTransMotorMaxVel { get; private set; }
85 public static float LinkConstraintTransMotorMaxForce { get; private set; }
86 public static float LinkConstraintERP { get; private set; }
87 public static float LinkConstraintCFM { get; private set; }
88 public static float LinkConstraintSolverIterations { get; private set; }
89
90 public static float PID_D { get; private set; } // derivative
91 public static float PID_P { get; private set; } // proportional
92
93 // Various constants that come from that other virtual world that shall not be named
94 public const float MinGravityZ = -1f;
95 public const float MaxGravityZ = 28f;
96 public const float MinFriction = 0f;
97 public const float MaxFriction = 255f;
98 public const float MinDensity = 0f;
99 public const float MaxDensity = 22587f;
100 public const float MinRestitution = 0f;
101 public const float MaxRestitution = 1f;
102 public const float MaxAddForceMagnitude = 20000f;
103
104 // ===========================================================================
105 public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
106 public delegate float ParamGet(BSScene scene);
107 public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
108 public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
109
110 public struct ParameterDefn
111 {
112 public string name; // string name of the parameter
113 public string desc; // a short description of what the parameter means
114 public float defaultValue; // default value if not specified anywhere else
115 public ParamUser userParam; // get the value from the configuration file
116 public ParamGet getter; // return the current value stored for this parameter
117 public ParamSet setter; // set the current value for this parameter
118 public SetOnObject onObject; // set the value on an object in the physical domain
119 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
120 {
121 name = n;
122 desc = d;
123 defaultValue = v;
124 userParam = u;
125 getter = g;
126 setter = s;
127 onObject = null;
128 }
129 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
130 {
131 name = n;
132 desc = d;
133 defaultValue = v;
134 userParam = u;
135 getter = g;
136 setter = s;
137 onObject = o;
138 }
139 }
140
141 // List of all of the externally visible parameters.
142 // For each parameter, this table maps a text name to getter and setters.
143 // To add a new externally referencable/settable parameter, add the paramter storage
144 // location somewhere in the program and make an entry in this table with the
145 // getters and setters.
146 // It is easiest to find an existing definition and copy it.
147 // Parameter values are floats. Booleans are converted to a floating value.
148 //
149 // A ParameterDefn() takes the following parameters:
150 // -- the text name of the parameter. This is used for console input and ini file.
151 // -- a short text description of the parameter. This shows up in the console listing.
152 // -- a default value (float)
153 // -- a delegate for fetching the parameter from the ini file.
154 // Should handle fetching the right type from the ini file and converting it.
155 // -- a delegate for getting the value as a float
156 // -- a delegate for setting the value from a float
157 // -- an optional delegate to update the value in the world. Most often used to
158 // push the new value to an in-world object.
159 //
160 // The single letter parameters for the delegates are:
161 // s = BSScene
162 // o = BSPhysObject
163 // p = string parameter name
164 // l = localID of referenced object
165 // v = value (float)
166 // cf = parameter configuration class (for fetching values from ini file)
167 private static ParameterDefn[] ParameterDefinitions =
168 {
169 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
170 ConfigurationParameters.numericTrue,
171 (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
172 (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); },
173 (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ),
174 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
175 ConfigurationParameters.numericFalse,
176 (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
177 (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); },
178 (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ),
179 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
180 ConfigurationParameters.numericTrue,
181 (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
182 (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
183 (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
184
185 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
186 8f,
187 (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); },
188 (s) => { return MeshLOD; },
189 (s,p,l,v) => { MeshLOD = v; } ),
190 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
191 16f,
192 (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
193 (s) => { return MeshMegaPrimLOD; },
194 (s,p,l,v) => { MeshMegaPrimLOD = v; } ),
195 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
196 10f,
197 (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
198 (s) => { return MeshMegaPrimThreshold; },
199 (s,p,l,v) => { MeshMegaPrimThreshold = v; } ),
200 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
201 32f,
202 (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); },
203 (s) => { return SculptLOD; },
204 (s,p,l,v) => { SculptLOD = v; } ),
205
206 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
207 10f,
208 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
209 (s) => { return (float)s.m_maxSubSteps; },
210 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
211 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
212 1f / 60f,
213 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
214 (s) => { return (float)s.m_fixedTimeStep; },
215 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
216 new ParameterDefn("NominalFrameRate", "The base frame rate we claim",
217 55f,
218 (s,cf,p,v) => { s.NominalFrameRate = cf.GetInt(p, (int)v); },
219 (s) => { return (float)s.NominalFrameRate; },
220 (s,p,l,v) => { s.NominalFrameRate = (int)v; } ),
221 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
222 2048f,
223 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
224 (s) => { return (float)s.m_maxCollisionsPerFrame; },
225 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
226 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
227 8000f,
228 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
229 (s) => { return (float)s.m_maxUpdatesPerFrame; },
230 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
231 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
232 500f,
233 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
234 (s) => { return (float)s.m_taintsToProcessPerStep; },
235 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
236 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
237 0.0001f,
238 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
239 (s) => { return (float)MinimumObjectMass; },
240 (s,p,l,v) => { MinimumObjectMass = v; } ),
241 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
242 10000.01f,
243 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
244 (s) => { return (float)MaximumObjectMass; },
245 (s,p,l,v) => { MaximumObjectMass = v; } ),
246
247 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
248 2200f,
249 (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); },
250 (s) => { return (float)PID_D; },
251 (s,p,l,v) => { PID_D = v; } ),
252 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
253 900f,
254 (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); },
255 (s) => { return (float)PID_P; },
256 (s,p,l,v) => { PID_P = v; } ),
257
258 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
259 0.2f,
260 (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); },
261 (s) => { return s.UnmanagedParams[0].defaultFriction; },
262 (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ),
263 new ParameterDefn("DefaultDensity", "Density for new objects" ,
264 10.000006836f, // Aluminum g/cm3
265 (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); },
266 (s) => { return s.UnmanagedParams[0].defaultDensity; },
267 (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ),
268 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
269 0f,
270 (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); },
271 (s) => { return s.UnmanagedParams[0].defaultRestitution; },
272 (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ),
273 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
274 0.04f,
275 (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); },
276 (s) => { return s.UnmanagedParams[0].collisionMargin; },
277 (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ),
278 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
279 -9.80665f,
280 (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); },
281 (s) => { return s.UnmanagedParams[0].gravity; },
282 (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); },
283 (s,o,v) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,v)); } ),
284
285
286 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
287 0f,
288 (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); },
289 (s) => { return LinearDamping; },
290 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); },
291 (s,o,v) => { s.PE.SetDamping(o.PhysBody, v, AngularDamping); } ),
292 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
293 0f,
294 (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); },
295 (s) => { return AngularDamping; },
296 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); },
297 (s,o,v) => { s.PE.SetDamping(o.PhysBody, LinearDamping, v); } ),
298 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
299 0.2f,
300 (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); },
301 (s) => { return DeactivationTime; },
302 (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); },
303 (s,o,v) => { s.PE.SetDeactivationTime(o.PhysBody, v); } ),
304 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
305 0.8f,
306 (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); },
307 (s) => { return LinearSleepingThreshold; },
308 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); },
309 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
310 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
311 1.0f,
312 (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); },
313 (s) => { return AngularSleepingThreshold; },
314 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); },
315 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
316 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
317 0f, // set to zero to disable
318 (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); },
319 (s) => { return CcdMotionThreshold; },
320 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); },
321 (s,o,v) => { s.PE.SetCcdMotionThreshold(o.PhysBody, v); } ),
322 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
323 0f,
324 (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); },
325 (s) => { return CcdSweptSphereRadius; },
326 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); },
327 (s,o,v) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, v); } ),
328 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
329 0.1f,
330 (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); },
331 (s) => { return ContactProcessingThreshold; },
332 (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); },
333 (s,o,v) => { s.PE.SetContactProcessingThreshold(o.PhysBody, v); } ),
334
335 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
336 (float)BSTerrainPhys.TerrainImplementation.Mesh,
337 (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); },
338 (s) => { return TerrainImplementation; },
339 (s,p,l,v) => { TerrainImplementation = v; } ),
340 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
341 0.3f,
342 (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); },
343 (s) => { return TerrainFriction; },
344 (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
345 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
346 0.8f,
347 (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); },
348 (s) => { return TerrainHitFraction; },
349 (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
350 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
351 0f,
352 (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); },
353 (s) => { return TerrainRestitution; },
354 (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
355 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
356 0.04f,
357 (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); },
358 (s) => { return TerrainCollisionMargin; },
359 (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
360
361 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
362 0.2f,
363 (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); },
364 (s) => { return AvatarFriction; },
365 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ),
366 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
367 10.0f,
368 (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
369 (s) => { return AvatarStandingFriction; },
370 (s,p,l,v) => { AvatarStandingFriction = v; } ),
371 new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
372 1.3f,
373 (s,cf,p,v) => { AvatarAlwaysRunFactor = cf.GetFloat(p, v); },
374 (s) => { return AvatarAlwaysRunFactor; },
375 (s,p,l,v) => { AvatarAlwaysRunFactor = v; } ),
376 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
377 3.5f,
378 (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); },
379 (s) => { return AvatarDensity; },
380 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ),
381 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
382 0f,
383 (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); },
384 (s) => { return AvatarRestitution; },
385 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ),
386 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
387 0.6f,
388 (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); },
389 (s) => { return AvatarCapsuleWidth; },
390 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ),
391 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
392 0.45f,
393 (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); },
394 (s) => { return AvatarCapsuleDepth; },
395 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ),
396 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
397 1.5f,
398 (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); },
399 (s) => { return AvatarCapsuleHeight; },
400 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ),
401 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
402 0.1f,
403 (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); },
404 (s) => { return AvatarContactProcessingThreshold; },
405 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ),
406
407 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
408 0.95f,
409 (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
410 (s) => { return VehicleAngularDamping; },
411 (s,p,l,v) => { VehicleAngularDamping = v; } ),
412
413 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
414 0f,
415 (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
416 (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; },
417 (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
418 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
419 0f,
420 (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
421 (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; },
422 (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
423 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
424 ConfigurationParameters.numericFalse,
425 (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
426 (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; },
427 (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ),
428 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
429 ConfigurationParameters.numericFalse,
430 (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
431 (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; },
432 (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ),
433 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
434 ConfigurationParameters.numericTrue,
435 (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
436 (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; },
437 (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ),
438 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
439 ConfigurationParameters.numericTrue,
440 (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
441 (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; },
442 (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ),
443 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
444 ConfigurationParameters.numericFalse,
445 (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
446 (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; },
447 (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ),
448 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
449 0f, // zero says use Bullet default
450 (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); },
451 (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; },
452 (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
453
454 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
455 (float)BSLinkset.LinksetImplementation.Compound,
456 (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); },
457 (s) => { return LinksetImplementation; },
458 (s,p,l,v) => { LinksetImplementation = v; } ),
459 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
460 ConfigurationParameters.numericFalse,
461 (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
462 (s) => { return LinkConstraintUseFrameOffset; },
463 (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ),
464 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
465 ConfigurationParameters.numericTrue,
466 (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
467 (s) => { return LinkConstraintEnableTransMotor; },
468 (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ),
469 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
470 5.0f,
471 (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
472 (s) => { return LinkConstraintTransMotorMaxVel; },
473 (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ),
474 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
475 0.1f,
476 (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
477 (s) => { return LinkConstraintTransMotorMaxForce; },
478 (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ),
479 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
480 0.1f,
481 (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); },
482 (s) => { return LinkConstraintCFM; },
483 (s,p,l,v) => { LinkConstraintCFM = v; } ),
484 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
485 0.1f,
486 (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); },
487 (s) => { return LinkConstraintERP; },
488 (s,p,l,v) => { LinkConstraintERP = v; } ),
489 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
490 40,
491 (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); },
492 (s) => { return LinkConstraintSolverIterations; },
493 (s,p,l,v) => { LinkConstraintSolverIterations = v; } ),
494
495 new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
496 0f,
497 (s,cf,p,v) => { s.PhysicsMetricDumpFrames = cf.GetFloat(p, (int)v); },
498 (s) => { return (float)s.PhysicsMetricDumpFrames; },
499 (s,p,l,v) => { s.PhysicsMetricDumpFrames = (int)v; } ),
500 };
501
502 // Convert a boolean to our numeric true and false values
503 public static float NumericBool(bool b)
504 {
505 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
506 }
507
508 // Convert numeric true and false values to a boolean
509 public static bool BoolNumeric(float b)
510 {
511 return (b == ConfigurationParameters.numericTrue ? true : false);
512 }
513
514 // Search through the parameter definitions and return the matching
515 // ParameterDefn structure.
516 // Case does not matter as names are compared after converting to lower case.
517 // Returns 'false' if the parameter is not found.
518 internal static bool TryGetParameter(string paramName, out ParameterDefn defn)
519 {
520 bool ret = false;
521 ParameterDefn foundDefn = new ParameterDefn();
522 string pName = paramName.ToLower();
523
524 foreach (ParameterDefn parm in ParameterDefinitions)
525 {
526 if (pName == parm.name.ToLower())
527 {
528 foundDefn = parm;
529 ret = true;
530 break;
531 }
532 }
533 defn = foundDefn;
534 return ret;
535 }
536
537 // Pass through the settable parameters and set the default values
538 internal static void SetParameterDefaultValues(BSScene physicsScene)
539 {
540 foreach (ParameterDefn parm in ParameterDefinitions)
541 {
542 parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
543 }
544 }
545
546 // Get user set values out of the ini file.
547 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
548 {
549 foreach (ParameterDefn parm in ParameterDefinitions)
550 {
551 parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue);
552 }
553 }
554
555 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
556
557 // This creates an array in the correct format for returning the list of
558 // parameters. This is used by the 'list' option of the 'physics' command.
559 internal static void BuildParameterTable()
560 {
561 if (SettableParameters.Length < ParameterDefinitions.Length)
562 {
563 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
564 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
565 {
566 ParameterDefn pd = ParameterDefinitions[ii];
567 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
568 }
569
570 // make the list in alphabetical order for estetic reasons
571 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
572 {
573 return ppe1.name.CompareTo(ppe2.name);
574 });
575
576 SettableParameters = entries.ToArray();
577 }
578 }
579
580
581}
582}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
deleted file mode 100755
index e7cb3e0..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ /dev/null
@@ -1,386 +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.BulletSPlugin
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 // We don't have any physical representation yet.
71 PhysBody = new BulletBody(localID);
72 PhysShape = new BulletShape();
73
74 // A linkset of just me
75 Linkset = BSLinkset.Factory(PhysicsScene, this);
76 LastAssetBuildFailed = false;
77
78 // Default material type
79 Material = MaterialAttributes.Material.Wood;
80
81 CollisionCollection = new CollisionEventUpdate();
82 SubscribedEventsMs = 0;
83 CollidingStep = 0;
84 CollidingGroundStep = 0;
85 }
86
87 // Tell the object to clean up.
88 public virtual void Destroy()
89 {
90 UnRegisterAllPreStepActions();
91 }
92
93 public BSScene PhysicsScene { get; protected set; }
94 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
95 public string PhysObjectName { get; protected set; }
96 public string TypeName { get; protected set; }
97
98 public BSLinkset Linkset { get; set; }
99 public BSLinksetInfo LinksetInfo { get; set; }
100
101 // Return the object mass without calculating it or having side effects
102 public abstract float RawMass { get; }
103 // Set the raw mass but also update physical mass properties (inertia, ...)
104 // 'inWorld' true if the object has already been added to the dynamic world.
105 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
106
107 // The last value calculated for the prim's inertia
108 public OMV.Vector3 Inertia { get; set; }
109
110 // Reference to the physical body (btCollisionObject) of this object
111 public BulletBody PhysBody;
112 // Reference to the physical shape (btCollisionShape) of this object
113 public BulletShape PhysShape;
114
115 // 'true' if the mesh's underlying asset failed to build.
116 // This will keep us from looping after the first time the build failed.
117 public bool LastAssetBuildFailed { get; set; }
118
119 // The objects base shape information. Null if not a prim type shape.
120 public PrimitiveBaseShape BaseShape { get; protected set; }
121 // Some types of objects have preferred physical representations.
122 // Returns SHAPE_UNKNOWN if there is no preference.
123 public virtual BSPhysicsShapeType PreferredPhysicalShape
124 {
125 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
126 }
127
128 // When the physical properties are updated, an EntityProperty holds the update values.
129 // Keep the current and last EntityProperties to enable computation of differences
130 // between the current update and the previous values.
131 public EntityProperties CurrentEntityProperties { get; set; }
132 public EntityProperties LastEntityProperties { get; set; }
133
134 public virtual OMV.Vector3 Scale { get; set; }
135 public abstract bool IsSolid { get; }
136 public abstract bool IsStatic { get; }
137
138 // Materialness
139 public MaterialAttributes.Material Material { get; private set; }
140 public override void SetMaterial(int material)
141 {
142 Material = (MaterialAttributes.Material)material;
143 }
144
145 // Stop all physical motion.
146 public abstract void ZeroMotion(bool inTaintTime);
147 public abstract void ZeroAngularMotion(bool inTaintTime);
148
149 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
150 public virtual void StepVehicle(float timeStep) { }
151
152 // Update the physical location and motion of the object. Called with data from Bullet.
153 public abstract void UpdateProperties(EntityProperties entprop);
154
155 public abstract OMV.Vector3 RawPosition { get; set; }
156 public abstract OMV.Vector3 ForcePosition { get; set; }
157
158 public abstract OMV.Quaternion RawOrientation { get; set; }
159 public abstract OMV.Quaternion ForceOrientation { get; set; }
160
161 // The system is telling us the velocity it wants to move at.
162 // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
163 public override OMV.Vector3 TargetVelocity
164 {
165 get { return m_targetVelocity; }
166 set
167 {
168 m_targetVelocity = value;
169 Velocity = value;
170 }
171 }
172 public abstract OMV.Vector3 ForceVelocity { get; set; }
173
174 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
175
176 public abstract float ForceBuoyancy { get; set; }
177
178 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
179
180 #region Collisions
181
182 // Requested number of milliseconds between collision events. Zero means disabled.
183 protected int SubscribedEventsMs { get; set; }
184 // Given subscription, the time that a collision may be passed up
185 protected int NextCollisionOkTime { get; set; }
186 // The simulation step that last had a collision
187 protected long CollidingStep { get; set; }
188 // The simulation step that last had a collision with the ground
189 protected long CollidingGroundStep { get; set; }
190 // The simulation step that last collided with an object
191 protected long CollidingObjectStep { get; set; }
192 // The collision flags we think are set in Bullet
193 protected CollisionFlags CurrentCollisionFlags { get; set; }
194
195 public override bool IsColliding {
196 get { return (CollidingStep == PhysicsScene.SimulationStep); }
197 set {
198 if (value)
199 CollidingStep = PhysicsScene.SimulationStep;
200 else
201 CollidingStep = 0;
202 }
203 }
204 public override bool CollidingGround {
205 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
206 set
207 {
208 if (value)
209 CollidingGroundStep = PhysicsScene.SimulationStep;
210 else
211 CollidingGroundStep = 0;
212 }
213 }
214 public override bool CollidingObj {
215 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
216 set {
217 if (value)
218 CollidingObjectStep = PhysicsScene.SimulationStep;
219 else
220 CollidingObjectStep = 0;
221 }
222 }
223
224 // The collisions that have been collected this tick
225 protected CollisionEventUpdate CollisionCollection;
226
227 // The simulation step is telling this object about a collision.
228 // Return 'true' if a collision was processed and should be sent up.
229 // Called at taint time from within the Step() function
230 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
231 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
232 {
233 bool ret = false;
234
235 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
236 CollidingStep = PhysicsScene.SimulationStep;
237 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
238 {
239 CollidingGroundStep = PhysicsScene.SimulationStep;
240 }
241 else
242 {
243 CollidingObjectStep = PhysicsScene.SimulationStep;
244 }
245
246 // prims in the same linkset cannot collide with each other
247 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
248 {
249 return ret;
250 }
251
252 // if someone has subscribed for collision events....
253 if (SubscribedEvents()) {
254 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
255 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
256 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
257
258 ret = true;
259 }
260 return ret;
261 }
262
263 // Send the collected collisions into the simulator.
264 // Called at taint time from within the Step() function thus no locking problems
265 // with CollisionCollection and ObjectsWithNoMoreCollisions.
266 // Return 'true' if there were some actual collisions passed up
267 public virtual bool SendCollisions()
268 {
269 bool ret = true;
270 // If the 'no collision' call, force it to happen right now so quick collision_end
271 bool force = (CollisionCollection.Count == 0);
272
273 // throttle the collisions to the number of milliseconds specified in the subscription
274 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
275 {
276 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
277
278 // We are called if we previously had collisions. If there are no collisions
279 // this time, send up one last empty event so OpenSim can sense collision end.
280 if (CollisionCollection.Count == 0)
281 {
282 // If I have no collisions this time, remove me from the list of objects with collisions.
283 ret = false;
284 }
285
286 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
287 base.SendCollisionUpdate(CollisionCollection);
288
289 // The CollisionCollection instance is passed around in the simulator.
290 // Make sure we don't have a handle to that one and that a new one is used for next time.
291 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
292 // a race condition is created for the other users of this instance.
293 CollisionCollection = new CollisionEventUpdate();
294 }
295 return ret;
296 }
297
298 // Subscribe for collision events.
299 // Parameter is the millisecond rate the caller wishes collision events to occur.
300 public override void SubscribeEvents(int ms) {
301 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
302 SubscribedEventsMs = ms;
303 if (ms > 0)
304 {
305 // make sure first collision happens
306 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
307
308 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
309 {
310 if (PhysBody.HasPhysicalBody)
311 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
312 });
313 }
314 else
315 {
316 // Subscribing for zero or less is the same as unsubscribing
317 UnSubscribeEvents();
318 }
319 }
320 public override void UnSubscribeEvents() {
321 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
322 SubscribedEventsMs = 0;
323 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
324 {
325 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
326 if (PhysBody.HasPhysicalBody)
327 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
328 });
329 }
330 // Return 'true' if the simulator wants collision events
331 public override bool SubscribedEvents() {
332 return (SubscribedEventsMs > 0);
333 }
334
335 #endregion // Collisions
336
337 #region Per Simulation Step actions
338 // There are some actions that must be performed for a physical object before each simulation step.
339 // These actions are optional so, rather than scanning all the physical objects and asking them
340 // if they have anything to do, a physical object registers for an event call before the step is performed.
341 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
342 private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
343 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
344 {
345 string identifier = op + "-" + id.ToString();
346 RegisteredActions[identifier] = actn;
347 PhysicsScene.BeforeStep += actn;
348 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
349 }
350
351 // Unregister a pre step action. Safe to call if the action has not been registered.
352 protected void UnRegisterPreStepAction(string op, uint id)
353 {
354 string identifier = op + "-" + id.ToString();
355 bool removed = false;
356 if (RegisteredActions.ContainsKey(identifier))
357 {
358 PhysicsScene.BeforeStep -= RegisteredActions[identifier];
359 RegisteredActions.Remove(identifier);
360 removed = true;
361 }
362 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
363 }
364
365 protected void UnRegisterAllPreStepActions()
366 {
367 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
368 {
369 PhysicsScene.BeforeStep -= kvp.Value;
370 }
371 RegisteredActions.Clear();
372 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
373 }
374
375
376 #endregion // Per Simulation Step actions
377
378 // High performance detailed logging routine used by the physical objects.
379 protected void DetailLog(string msg, params Object[] args)
380 {
381 if (PhysicsScene.PhysicsLogging.Enabled)
382 PhysicsScene.DetailLog(msg, args);
383 }
384
385}
386}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
deleted file mode 100644
index 65be52a..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ /dev/null
@@ -1,76 +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.BulletSPlugin
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 _mScene = new BSScene(sceneIdentifier);
63 }
64 return (_mScene);
65 }
66
67 public string GetName()
68 {
69 return ("BulletSim");
70 }
71
72 public void Dispose()
73 {
74 }
75}
76}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
deleted file mode 100644
index 826261c..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ /dev/null
@@ -1,1513 +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.BulletSPlugin
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 = 0f;
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 // Cause linkset variables to be initialized (like mass)
115 Linkset.Refresh(this);
116
117 DetailLog("{0},BSPrim.constructor,call", LocalID);
118 // do the actual object creation at taint time
119 PhysicsScene.TaintedObject("BSPrim.create", delegate()
120 {
121 CreateGeomAndObject(true);
122
123 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody);
124 });
125 }
126
127 // called when this prim is being destroyed and we should free all the resources
128 public override void Destroy()
129 {
130 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
131 base.Destroy();
132
133 // Undo any links between me and any other object
134 BSPhysObject parentBefore = Linkset.LinksetRoot;
135 int childrenBefore = Linkset.NumberOfChildren;
136
137 Linkset = Linkset.RemoveMeFromLinkset(this);
138
139 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
140 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
141
142 // Undo any vehicle properties
143 this.VehicleType = (int)Vehicle.TYPE_NONE;
144
145 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
146 {
147 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
148 // If there are physical body and shape, release my use of same.
149 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
150 PhysBody.Clear();
151 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
152 PhysShape.Clear();
153 });
154 }
155
156 // No one uses this property.
157 public override bool Stopped {
158 get { return false; }
159 }
160 public override OMV.Vector3 Size {
161 get { return _size; }
162 set {
163 // We presume the scale and size are the same. If scale must be changed for
164 // the physical shape, that is done when the geometry is built.
165 _size = value;
166 Scale = _size;
167 ForceBodyShapeRebuild(false);
168 }
169 }
170
171 public override PrimitiveBaseShape Shape {
172 set {
173 BaseShape = value;
174 ForceBodyShapeRebuild(false);
175 }
176 }
177 // Whatever the linkset wants is what I want.
178 public override BSPhysicsShapeType PreferredPhysicalShape
179 { get { return Linkset.PreferredPhysicalShape(this); } }
180
181 public override bool ForceBodyShapeRebuild(bool inTaintTime)
182 {
183 LastAssetBuildFailed = false;
184 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
185 {
186 _mass = CalculateMass(); // changing the shape changes the mass
187 CreateGeomAndObject(true);
188 });
189 return true;
190 }
191 public override bool Grabbed {
192 set { _grabbed = value;
193 }
194 }
195 public override bool Selected {
196 set
197 {
198 if (value != _isSelected)
199 {
200 _isSelected = value;
201 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
202 {
203 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
204 SetObjectDynamic(false);
205 });
206 }
207 }
208 }
209 public override void CrossingFailure() { return; }
210
211 // link me to the specified parent
212 public override void link(PhysicsActor obj) {
213 BSPrim parent = obj as BSPrim;
214 if (parent != null)
215 {
216 BSPhysObject parentBefore = Linkset.LinksetRoot;
217 int childrenBefore = Linkset.NumberOfChildren;
218
219 Linkset = parent.Linkset.AddMeToLinkset(this);
220
221 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
222 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
223 }
224 return;
225 }
226
227 // delink me from my linkset
228 public override void delink() {
229 // TODO: decide if this parent checking needs to happen at taint time
230 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
231
232 BSPhysObject parentBefore = Linkset.LinksetRoot;
233 int childrenBefore = Linkset.NumberOfChildren;
234
235 Linkset = Linkset.RemoveMeFromLinkset(this);
236
237 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
238 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
239 return;
240 }
241
242 // Set motion values to zero.
243 // Do it to the properties so the values get set in the physics engine.
244 // Push the setting of the values to the viewer.
245 // Called at taint time!
246 public override void ZeroMotion(bool inTaintTime)
247 {
248 _velocity = OMV.Vector3.Zero;
249 _acceleration = OMV.Vector3.Zero;
250 _rotationalVelocity = OMV.Vector3.Zero;
251
252 // Zero some other properties in the physics engine
253 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
254 {
255 if (PhysBody.HasPhysicalBody)
256 PhysicsScene.PE.ClearAllForces(PhysBody);
257 });
258 }
259 public override void ZeroAngularMotion(bool inTaintTime)
260 {
261 _rotationalVelocity = OMV.Vector3.Zero;
262 // Zero some other properties in the physics engine
263 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
264 {
265 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
266 if (PhysBody.HasPhysicalBody)
267 {
268 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
269 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
270 }
271 });
272 }
273
274 public override void LockAngularMotion(OMV.Vector3 axis)
275 {
276 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
277 return;
278 }
279
280 public override OMV.Vector3 RawPosition
281 {
282 get { return _position; }
283 set { _position = value; }
284 }
285 public override OMV.Vector3 Position {
286 get {
287 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
288 * and does not fetch this position info for children. Thus this is commented out.
289 // child prims move around based on their parent. Need to get the latest location
290 if (!Linkset.IsRoot(this))
291 _position = Linkset.PositionGet(this);
292 */
293
294 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
295 // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody);
296 return _position;
297 }
298 set {
299 // If the position must be forced into the physics engine, use ForcePosition.
300 // All positions are given in world positions.
301 if (_position == value)
302 {
303 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
304 return;
305 }
306 _position = value;
307 PositionSanityCheck(false);
308
309 // A linkset might need to know if a component information changed.
310 Linkset.UpdateProperties(this, false);
311
312 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
313 {
314 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
315 ForcePosition = _position;
316 });
317 }
318 }
319 public override OMV.Vector3 ForcePosition {
320 get {
321 _position = PhysicsScene.PE.GetPosition(PhysBody);
322 return _position;
323 }
324 set {
325 _position = value;
326 if (PhysBody.HasPhysicalBody)
327 {
328 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
329 ActivateIfPhysical(false);
330 }
331 }
332 }
333
334 // Check that the current position is sane and, if not, modify the position to make it so.
335 // Check for being below terrain and being out of bounds.
336 // Returns 'true' of the position was made sane by some action.
337 private bool PositionSanityCheck(bool inTaintTime)
338 {
339 bool ret = false;
340
341 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
342 {
343 // The physical object is out of the known/simulated area.
344 // Upper levels of code will handle the transition to other areas so, for
345 // the time, we just ignore the position.
346 return ret;
347 }
348
349 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
350 OMV.Vector3 upForce = OMV.Vector3.Zero;
351 if (RawPosition.Z < terrainHeight)
352 {
353 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
354 float targetHeight = terrainHeight + (Size.Z / 2f);
355 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
356 upForce.Z = (terrainHeight - RawPosition.Z) * 1f;
357 ret = true;
358 }
359
360 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
361 {
362 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
363 // TODO: a floating motor so object will bob in the water
364 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
365 {
366 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
367 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
368 ret = true;
369 }
370 }
371
372 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
373 // TODO: This should be intergrated with a geneal physics action mechanism.
374 // TODO: This should be moderated with PID'ness.
375 if (ret)
376 {
377 // Apply upforce and overcome gravity.
378 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
379 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
380 AddForce(correctionForce, false, inTaintTime);
381 }
382 return ret;
383 }
384
385 // Return the effective mass of the object.
386 // The definition of this call is to return the mass of the prim.
387 // If the simulator cares about the mass of the linkset, it will sum it itself.
388 public override float Mass
389 {
390 get
391 {
392 return _mass;
393 }
394 }
395
396 // used when we only want this prim's mass and not the linkset thing
397 public override float RawMass {
398 get { return _mass; }
399 }
400 // Set the physical mass to the passed mass.
401 // Note that this does not change _mass!
402 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
403 {
404 if (PhysBody.HasPhysicalBody)
405 {
406 if (IsStatic)
407 {
408 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity);
409 Inertia = OMV.Vector3.Zero;
410 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia);
411 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
412 }
413 else
414 {
415 OMV.Vector3 grav = ComputeGravity();
416
417 if (inWorld)
418 {
419 // Changing interesting properties doesn't change proxy and collision cache
420 // information. The Bullet solution is to re-add the object to the world
421 // after parameters are changed.
422 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
423 }
424
425 // The computation of mass props requires gravity to be set on the object.
426 PhysicsScene.PE.SetGravity(PhysBody, grav);
427
428 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
429 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
430 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
431
432 // center of mass is at the zero of the object
433 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation);
434 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld);
435
436 if (inWorld)
437 {
438 AddObjectToPhysicalWorld();
439 }
440
441 // Must set gravity after it has been added to the world because, for unknown reasons,
442 // adding the object resets the object's gravity to world gravity
443 PhysicsScene.PE.SetGravity(PhysBody, grav);
444
445 }
446 }
447 }
448
449 // Return what gravity should be set to this very moment
450 private OMV.Vector3 ComputeGravity()
451 {
452 OMV.Vector3 ret = PhysicsScene.DefaultGravity;
453
454 if (!IsStatic)
455 ret *= (1f - Buoyancy);
456
457 return ret;
458 }
459
460 // Is this used?
461 public override OMV.Vector3 CenterOfMass
462 {
463 get { return Linkset.CenterOfMass; }
464 }
465
466 // Is this used?
467 public override OMV.Vector3 GeometricCenter
468 {
469 get { return Linkset.GeometricCenter; }
470 }
471
472 public override OMV.Vector3 Force {
473 get { return _force; }
474 set {
475 _force = value;
476 if (_force != OMV.Vector3.Zero)
477 {
478 // If the force is non-zero, it must be reapplied each tick because
479 // Bullet clears the forces applied last frame.
480 RegisterPreStepAction("BSPrim.setForce", LocalID,
481 delegate(float timeStep)
482 {
483 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
484 if (PhysBody.HasPhysicalBody)
485 {
486 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
487 ActivateIfPhysical(false);
488 }
489 }
490 );
491 }
492 else
493 {
494 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
495 }
496 }
497 }
498
499 public override int VehicleType {
500 get {
501 return (int)_vehicle.Type; // if we are a vehicle, return that type
502 }
503 set {
504 Vehicle type = (Vehicle)value;
505
506 PhysicsScene.TaintedObject("setVehicleType", delegate()
507 {
508 // Done at taint time so we're sure the physics engine is not using the variables
509 // Vehicle code changes the parameters for this vehicle type.
510 _vehicle.ProcessTypeChange(type);
511 ActivateIfPhysical(false);
512
513 // If an active vehicle, register the vehicle code to be called before each step
514 if (_vehicle.Type == Vehicle.TYPE_NONE)
515 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
516 else
517 RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
518 });
519 }
520 }
521 public override void VehicleFloatParam(int param, float value)
522 {
523 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
524 {
525 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
526 ActivateIfPhysical(false);
527 });
528 }
529 public override void VehicleVectorParam(int param, OMV.Vector3 value)
530 {
531 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
532 {
533 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
534 ActivateIfPhysical(false);
535 });
536 }
537 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
538 {
539 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
540 {
541 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
542 ActivateIfPhysical(false);
543 });
544 }
545 public override void VehicleFlags(int param, bool remove)
546 {
547 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
548 {
549 _vehicle.ProcessVehicleFlags(param, remove);
550 });
551 }
552
553 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
554 public override void SetVolumeDetect(int param) {
555 bool newValue = (param != 0);
556 if (_isVolumeDetect != newValue)
557 {
558 _isVolumeDetect = newValue;
559 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
560 {
561 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
562 SetObjectDynamic(true);
563 });
564 }
565 return;
566 }
567 public override OMV.Vector3 Velocity {
568 get { return _velocity; }
569 set {
570 _velocity = value;
571 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
572 {
573 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
574 ForceVelocity = _velocity;
575 });
576 }
577 }
578 public override OMV.Vector3 ForceVelocity {
579 get { return _velocity; }
580 set {
581 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
582
583 _velocity = value;
584 if (PhysBody.HasPhysicalBody)
585 {
586 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
587 ActivateIfPhysical(false);
588 }
589 }
590 }
591 public override OMV.Vector3 Torque {
592 get { return _torque; }
593 set {
594 _torque = value;
595 if (_torque != OMV.Vector3.Zero)
596 {
597 // If the torque is non-zero, it must be reapplied each tick because
598 // Bullet clears the forces applied last frame.
599 RegisterPreStepAction("BSPrim.setTorque", LocalID,
600 delegate(float timeStep)
601 {
602 if (PhysBody.HasPhysicalBody)
603 AddAngularForce(_torque, false, true);
604 }
605 );
606 }
607 else
608 {
609 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
610 }
611 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
612 }
613 }
614 public override float CollisionScore {
615 get { return _collisionScore; }
616 set { _collisionScore = value;
617 }
618 }
619 public override OMV.Vector3 Acceleration {
620 get { return _acceleration; }
621 set { _acceleration = value; }
622 }
623 public override OMV.Quaternion RawOrientation
624 {
625 get { return _orientation; }
626 set { _orientation = value; }
627 }
628 public override OMV.Quaternion Orientation {
629 get {
630 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
631 * and does not fetch this position info for children. Thus this is commented out.
632 // Children move around because tied to parent. Get a fresh value.
633 if (!Linkset.IsRoot(this))
634 {
635 _orientation = Linkset.OrientationGet(this);
636 }
637 */
638 return _orientation;
639 }
640 set {
641 if (_orientation == value)
642 return;
643 _orientation = value;
644
645 // A linkset might need to know if a component information changed.
646 Linkset.UpdateProperties(this, false);
647
648 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
649 {
650 if (PhysBody.HasPhysicalBody)
651 {
652 // _position = PhysicsScene.PE.GetObjectPosition(PhysicsScene.World, BSBody);
653 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
654 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
655 }
656 });
657 }
658 }
659 // Go directly to Bullet to get/set the value.
660 public override OMV.Quaternion ForceOrientation
661 {
662 get
663 {
664 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
665 return _orientation;
666 }
667 set
668 {
669 _orientation = value;
670 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
671 }
672 }
673 public override int PhysicsActorType {
674 get { return _physicsActorType; }
675 set { _physicsActorType = value; }
676 }
677 public override bool IsPhysical {
678 get { return _isPhysical; }
679 set {
680 if (_isPhysical != value)
681 {
682 _isPhysical = value;
683 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
684 {
685 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
686 SetObjectDynamic(true);
687 // whether phys-to-static or static-to-phys, the object is not moving.
688 ZeroMotion(true);
689 });
690 }
691 }
692 }
693
694 // An object is static (does not move) if selected or not physical
695 public override bool IsStatic
696 {
697 get { return _isSelected || !IsPhysical; }
698 }
699
700 // An object is solid if it's not phantom and if it's not doing VolumeDetect
701 public override bool IsSolid
702 {
703 get { return !IsPhantom && !_isVolumeDetect; }
704 }
705
706 // Make gravity work if the object is physical and not selected
707 // Called at taint-time!!
708 private void SetObjectDynamic(bool forceRebuild)
709 {
710 // Recreate the physical object if necessary
711 CreateGeomAndObject(forceRebuild);
712 }
713
714 // Convert the simulator's physical properties into settings on BulletSim objects.
715 // There are four flags we're interested in:
716 // IsStatic: Object does not move, otherwise the object has mass and moves
717 // isSolid: other objects bounce off of this object
718 // isVolumeDetect: other objects pass through but can generate collisions
719 // collisionEvents: whether this object returns collision events
720 private void UpdatePhysicalParameters()
721 {
722 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
723
724 // Mangling all the physical properties requires the object not be in the physical world.
725 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
726 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
727
728 // Set up the object physicalness (does gravity and collisions move this object)
729 MakeDynamic(IsStatic);
730
731 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
732 _vehicle.Refresh();
733
734 // Arrange for collision events if the simulator wants them
735 EnableCollisions(SubscribedEvents());
736
737 // Make solid or not (do things bounce off or pass through this object).
738 MakeSolid(IsSolid);
739
740 AddObjectToPhysicalWorld();
741
742 // Rebuild its shape
743 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
744
745 // Recompute any linkset parameters.
746 // When going from non-physical to physical, this re-enables the constraints that
747 // had been automatically disabled when the mass was set to zero.
748 // For compound based linksets, this enables and disables interactions of the children.
749 Linkset.Refresh(this);
750
751 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
752 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
753 }
754
755 // "Making dynamic" means changing to and from static.
756 // When static, gravity does not effect the object and it is fixed in space.
757 // When dynamic, the object can fall and be pushed by others.
758 // This is independent of its 'solidness' which controls what passes through
759 // this object and what interacts with it.
760 private void MakeDynamic(bool makeStatic)
761 {
762 if (makeStatic)
763 {
764 // Become a Bullet 'static' object type
765 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
766 // Stop all movement
767 ZeroMotion(true);
768
769 // Set various physical properties so other object interact properly
770 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
771 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
772 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
773
774 // Mass is zero which disables a bunch of physics stuff in Bullet
775 UpdatePhysicalMassProperties(0f, false);
776 // Set collision detection parameters
777 if (BSParam.CcdMotionThreshold > 0f)
778 {
779 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
780 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
781 }
782
783 // The activation state is 'disabled' so Bullet will not try to act on it.
784 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
785 // Start it out sleeping and physical actions could wake it up.
786 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
787
788 // This collides like a static object
789 PhysBody.collisionType = CollisionType.Static;
790
791 // There can be special things needed for implementing linksets
792 Linkset.MakeStatic(this);
793 }
794 else
795 {
796 // Not a Bullet static object
797 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
798
799 // Set various physical properties so other object interact properly
800 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
801 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
802 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
803
804 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
805 // Since this can be called multiple times, only zero forces when becoming physical
806 // PhysicsScene.PE.ClearAllForces(BSBody);
807
808 // For good measure, make sure the transform is set through to the motion state
809 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
810
811 // Center of mass is at the center of the object
812 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation);
813
814 // A dynamic object has mass
815 UpdatePhysicalMassProperties(RawMass, false);
816
817 // Set collision detection parameters
818 if (BSParam.CcdMotionThreshold > 0f)
819 {
820 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
821 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
822 }
823
824 // Various values for simulation limits
825 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
826 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
827 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
828 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
829
830 // This collides like an object.
831 PhysBody.collisionType = CollisionType.Dynamic;
832
833 // Force activation of the object so Bullet will act on it.
834 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
835 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
836
837 // There might be special things needed for implementing linksets.
838 Linkset.MakeDynamic(this);
839 }
840 }
841
842 // "Making solid" means that other object will not pass through this object.
843 // To make transparent, we create a Bullet ghost object.
844 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
845 // the functions after this one set up the state of a possibly newly created collision body.
846 private void MakeSolid(bool makeSolid)
847 {
848 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody);
849 if (makeSolid)
850 {
851 // Verify the previous code created the correct shape for this type of thing.
852 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
853 {
854 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
855 }
856 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
857 }
858 else
859 {
860 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
861 {
862 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
863 }
864 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
865
866 // Change collision info from a static object to a ghosty collision object
867 PhysBody.collisionType = CollisionType.VolumeDetect;
868 }
869 }
870
871 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
872 // they need waking up when parameters are changed.
873 // Called in taint-time!!
874 private void ActivateIfPhysical(bool forceIt)
875 {
876 if (IsPhysical && PhysBody.HasPhysicalBody)
877 PhysicsScene.PE.Activate(PhysBody, forceIt);
878 }
879
880 // Turn on or off the flag controlling whether collision events are returned to the simulator.
881 private void EnableCollisions(bool wantsCollisionEvents)
882 {
883 if (wantsCollisionEvents)
884 {
885 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
886 }
887 else
888 {
889 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
890 }
891 }
892
893 // Add me to the physical world.
894 // Object MUST NOT already be in the world.
895 // This routine exists because some assorted properties get mangled by adding to the world.
896 internal void AddObjectToPhysicalWorld()
897 {
898 if (PhysBody.HasPhysicalBody)
899 {
900 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
901 }
902 else
903 {
904 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
905 DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
906 }
907 }
908
909 // prims don't fly
910 public override bool Flying {
911 get { return _flying; }
912 set {
913 _flying = value;
914 }
915 }
916 public override bool SetAlwaysRun {
917 get { return _setAlwaysRun; }
918 set { _setAlwaysRun = value; }
919 }
920 public override bool ThrottleUpdates {
921 get { return _throttleUpdates; }
922 set { _throttleUpdates = value; }
923 }
924 public bool IsPhantom {
925 get {
926 // SceneObjectPart removes phantom objects from the physics scene
927 // so, although we could implement touching and such, we never
928 // are invoked as a phantom object
929 return false;
930 }
931 }
932 public override bool FloatOnWater {
933 set {
934 _floatOnWater = value;
935 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
936 {
937 if (_floatOnWater)
938 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
939 else
940 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
941 });
942 }
943 }
944 public override OMV.Vector3 RotationalVelocity {
945 get {
946 return _rotationalVelocity;
947 }
948 set {
949 _rotationalVelocity = value;
950 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
951 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
952 {
953 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
954 ForceRotationalVelocity = _rotationalVelocity;
955 });
956 }
957 }
958 public override OMV.Vector3 ForceRotationalVelocity {
959 get {
960 return _rotationalVelocity;
961 }
962 set {
963 _rotationalVelocity = value;
964 if (PhysBody.HasPhysicalBody)
965 {
966 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
967 ActivateIfPhysical(false);
968 }
969 }
970 }
971 public override bool Kinematic {
972 get { return _kinematic; }
973 set { _kinematic = value;
974 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
975 }
976 }
977 public override float Buoyancy {
978 get { return _buoyancy; }
979 set {
980 _buoyancy = value;
981 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
982 {
983 ForceBuoyancy = _buoyancy;
984 });
985 }
986 }
987 public override float ForceBuoyancy {
988 get { return _buoyancy; }
989 set {
990 _buoyancy = value;
991 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
992 // Force the recalculation of the various inertia,etc variables in the object
993 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass);
994 UpdatePhysicalMassProperties(_mass, true);
995 ActivateIfPhysical(false);
996 }
997 }
998
999 // Used for MoveTo
1000 public override OMV.Vector3 PIDTarget {
1001 set { _PIDTarget = value; }
1002 }
1003 public override float PIDTau {
1004 set { _PIDTau = value; }
1005 }
1006 public override bool PIDActive {
1007 set { _usePID = value; }
1008 }
1009
1010 // Used for llSetHoverHeight and maybe vehicle height
1011 // Hover Height will override MoveTo target's Z
1012 public override bool PIDHoverActive {
1013 set { _useHoverPID = value; }
1014 }
1015 public override float PIDHoverHeight {
1016 set { _PIDHoverHeight = value; }
1017 }
1018 public override PIDHoverType PIDHoverType {
1019 set { _PIDHoverType = value; }
1020 }
1021 public override float PIDHoverTau {
1022 set { _PIDHoverTao = value; }
1023 }
1024
1025 // For RotLookAt
1026 public override OMV.Quaternion APIDTarget { set { return; } }
1027 public override bool APIDActive { set { return; } }
1028 public override float APIDStrength { set { return; } }
1029 public override float APIDDamping { set { return; } }
1030
1031 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1032 // Since this force is being applied in only one step, make this a force per second.
1033 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
1034 AddForce(addForce, pushforce, false);
1035 }
1036 // Applying a force just adds this to the total force on the object.
1037 // This added force will only last the next simulation tick.
1038 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1039 // for an object, doesn't matter if force is a pushforce or not
1040 if (force.IsFinite())
1041 {
1042 float magnitude = force.Length();
1043 if (magnitude > BSParam.MaxAddForceMagnitude)
1044 {
1045 // Force has a limit
1046 force = force / magnitude * BSParam.MaxAddForceMagnitude;
1047 }
1048
1049 OMV.Vector3 addForce = force;
1050 DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1051
1052 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1053 {
1054 // Bullet adds this central force to the total force for this tick
1055 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1056 if (PhysBody.HasPhysicalBody)
1057 {
1058 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
1059 ActivateIfPhysical(false);
1060 }
1061 });
1062 }
1063 else
1064 {
1065 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1066 return;
1067 }
1068 }
1069
1070 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
1071 AddAngularForce(force, pushforce, false);
1072 }
1073 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1074 {
1075 if (force.IsFinite())
1076 {
1077 OMV.Vector3 angForce = force;
1078 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
1079 {
1080 if (PhysBody.HasPhysicalBody)
1081 {
1082 PhysicsScene.PE.ApplyTorque(PhysBody, angForce);
1083 ActivateIfPhysical(false);
1084 }
1085 });
1086 }
1087 else
1088 {
1089 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1090 return;
1091 }
1092 }
1093
1094 // A torque impulse.
1095 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1096 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1097 // Computed as: angularVelocity += impulse * inertia;
1098 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1099 {
1100 OMV.Vector3 applyImpulse = impulse;
1101 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1102 {
1103 if (PhysBody.HasPhysicalBody)
1104 {
1105 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1106 ActivateIfPhysical(false);
1107 }
1108 });
1109 }
1110
1111 public override void SetMomentum(OMV.Vector3 momentum) {
1112 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1113 }
1114 #region Mass Calculation
1115
1116 private float CalculateMass()
1117 {
1118 float volume = _size.X * _size.Y * _size.Z; // default
1119 float tmp;
1120
1121 float returnMass = 0;
1122 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1123 float hollowVolume = hollowAmount * hollowAmount;
1124
1125 switch (BaseShape.ProfileShape)
1126 {
1127 case ProfileShape.Square:
1128 // default box
1129
1130 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1131 {
1132 if (hollowAmount > 0.0)
1133 {
1134 switch (BaseShape.HollowShape)
1135 {
1136 case HollowShape.Square:
1137 case HollowShape.Same:
1138 break;
1139
1140 case HollowShape.Circle:
1141
1142 hollowVolume *= 0.78539816339f;
1143 break;
1144
1145 case HollowShape.Triangle:
1146
1147 hollowVolume *= (0.5f * .5f);
1148 break;
1149
1150 default:
1151 hollowVolume = 0;
1152 break;
1153 }
1154 volume *= (1.0f - hollowVolume);
1155 }
1156 }
1157
1158 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1159 {
1160 //a tube
1161
1162 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1163 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1164 volume -= volume*tmp*tmp;
1165
1166 if (hollowAmount > 0.0)
1167 {
1168 hollowVolume *= hollowAmount;
1169
1170 switch (BaseShape.HollowShape)
1171 {
1172 case HollowShape.Square:
1173 case HollowShape.Same:
1174 break;
1175
1176 case HollowShape.Circle:
1177 hollowVolume *= 0.78539816339f;;
1178 break;
1179
1180 case HollowShape.Triangle:
1181 hollowVolume *= 0.5f * 0.5f;
1182 break;
1183 default:
1184 hollowVolume = 0;
1185 break;
1186 }
1187 volume *= (1.0f - hollowVolume);
1188 }
1189 }
1190
1191 break;
1192
1193 case ProfileShape.Circle:
1194
1195 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1196 {
1197 volume *= 0.78539816339f; // elipse base
1198
1199 if (hollowAmount > 0.0)
1200 {
1201 switch (BaseShape.HollowShape)
1202 {
1203 case HollowShape.Same:
1204 case HollowShape.Circle:
1205 break;
1206
1207 case HollowShape.Square:
1208 hollowVolume *= 0.5f * 2.5984480504799f;
1209 break;
1210
1211 case HollowShape.Triangle:
1212 hollowVolume *= .5f * 1.27323954473516f;
1213 break;
1214
1215 default:
1216 hollowVolume = 0;
1217 break;
1218 }
1219 volume *= (1.0f - hollowVolume);
1220 }
1221 }
1222
1223 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1224 {
1225 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1226 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1227 volume *= (1.0f - tmp * tmp);
1228
1229 if (hollowAmount > 0.0)
1230 {
1231
1232 // calculate the hollow volume by it's shape compared to the prim shape
1233 hollowVolume *= hollowAmount;
1234
1235 switch (BaseShape.HollowShape)
1236 {
1237 case HollowShape.Same:
1238 case HollowShape.Circle:
1239 break;
1240
1241 case HollowShape.Square:
1242 hollowVolume *= 0.5f * 2.5984480504799f;
1243 break;
1244
1245 case HollowShape.Triangle:
1246 hollowVolume *= .5f * 1.27323954473516f;
1247 break;
1248
1249 default:
1250 hollowVolume = 0;
1251 break;
1252 }
1253 volume *= (1.0f - hollowVolume);
1254 }
1255 }
1256 break;
1257
1258 case ProfileShape.HalfCircle:
1259 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1260 {
1261 volume *= 0.52359877559829887307710723054658f;
1262 }
1263 break;
1264
1265 case ProfileShape.EquilateralTriangle:
1266
1267 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1268 {
1269 volume *= 0.32475953f;
1270
1271 if (hollowAmount > 0.0)
1272 {
1273
1274 // calculate the hollow volume by it's shape compared to the prim shape
1275 switch (BaseShape.HollowShape)
1276 {
1277 case HollowShape.Same:
1278 case HollowShape.Triangle:
1279 hollowVolume *= .25f;
1280 break;
1281
1282 case HollowShape.Square:
1283 hollowVolume *= 0.499849f * 3.07920140172638f;
1284 break;
1285
1286 case HollowShape.Circle:
1287 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1288 // Cyllinder hollow volume calculation
1289
1290 hollowVolume *= 0.1963495f * 3.07920140172638f;
1291 break;
1292
1293 default:
1294 hollowVolume = 0;
1295 break;
1296 }
1297 volume *= (1.0f - hollowVolume);
1298 }
1299 }
1300 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1301 {
1302 volume *= 0.32475953f;
1303 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1304 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1305 volume *= (1.0f - tmp * tmp);
1306
1307 if (hollowAmount > 0.0)
1308 {
1309
1310 hollowVolume *= hollowAmount;
1311
1312 switch (BaseShape.HollowShape)
1313 {
1314 case HollowShape.Same:
1315 case HollowShape.Triangle:
1316 hollowVolume *= .25f;
1317 break;
1318
1319 case HollowShape.Square:
1320 hollowVolume *= 0.499849f * 3.07920140172638f;
1321 break;
1322
1323 case HollowShape.Circle:
1324
1325 hollowVolume *= 0.1963495f * 3.07920140172638f;
1326 break;
1327
1328 default:
1329 hollowVolume = 0;
1330 break;
1331 }
1332 volume *= (1.0f - hollowVolume);
1333 }
1334 }
1335 break;
1336
1337 default:
1338 break;
1339 }
1340
1341
1342
1343 float taperX1;
1344 float taperY1;
1345 float taperX;
1346 float taperY;
1347 float pathBegin;
1348 float pathEnd;
1349 float profileBegin;
1350 float profileEnd;
1351
1352 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1353 {
1354 taperX1 = BaseShape.PathScaleX * 0.01f;
1355 if (taperX1 > 1.0f)
1356 taperX1 = 2.0f - taperX1;
1357 taperX = 1.0f - taperX1;
1358
1359 taperY1 = BaseShape.PathScaleY * 0.01f;
1360 if (taperY1 > 1.0f)
1361 taperY1 = 2.0f - taperY1;
1362 taperY = 1.0f - taperY1;
1363 }
1364 else
1365 {
1366 taperX = BaseShape.PathTaperX * 0.01f;
1367 if (taperX < 0.0f)
1368 taperX = -taperX;
1369 taperX1 = 1.0f - taperX;
1370
1371 taperY = BaseShape.PathTaperY * 0.01f;
1372 if (taperY < 0.0f)
1373 taperY = -taperY;
1374 taperY1 = 1.0f - taperY;
1375
1376 }
1377
1378
1379 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1380
1381 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1382 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1383 volume *= (pathEnd - pathBegin);
1384
1385 // this is crude aproximation
1386 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1387 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1388 volume *= (profileEnd - profileBegin);
1389
1390 returnMass = _density * volume;
1391
1392 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1393 if (IsRootOfLinkset)
1394 {
1395 foreach (BSPrim prim in _childrenPrims)
1396 {
1397 returnMass += prim.CalculateMass();
1398 }
1399 }
1400 */
1401
1402 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1403
1404 return returnMass;
1405 }// end CalculateMass
1406 #endregion Mass Calculation
1407
1408 // Rebuild the geometry and object.
1409 // This is called when the shape changes so we need to recreate the mesh/hull.
1410 // Called at taint-time!!!
1411 public void CreateGeomAndObject(bool forceRebuild)
1412 {
1413 // If this prim is part of a linkset, we must remove and restore the physical
1414 // links if the body is rebuilt.
1415 bool needToRestoreLinkset = false;
1416 bool needToRestoreVehicle = false;
1417
1418 // Create the correct physical representation for this type of object.
1419 // Updates PhysBody and PhysShape with the new information.
1420 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1421 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1422 {
1423 // Called if the current prim body is about to be destroyed.
1424 // Remove all the physical dependencies on the old body.
1425 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1426 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1427 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1428 });
1429
1430 if (needToRestoreLinkset)
1431 {
1432 // If physical body dependencies were removed, restore them
1433 Linkset.RestoreBodyDependencies(this);
1434 }
1435 if (needToRestoreVehicle)
1436 {
1437 // If physical body dependencies were removed, restore them
1438 _vehicle.RestoreBodyDependencies(this);
1439 }
1440
1441 // Make sure the properties are set on the new object
1442 UpdatePhysicalParameters();
1443 return;
1444 }
1445
1446 // The physics engine says that properties have updated. Update same and inform
1447 // the world that things have changed.
1448 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1449 enum UpdatedProperties {
1450 Position = 1 << 0,
1451 Rotation = 1 << 1,
1452 Velocity = 1 << 2,
1453 Acceleration = 1 << 3,
1454 RotationalVel = 1 << 4
1455 }
1456
1457 const float ROTATION_TOLERANCE = 0.01f;
1458 const float VELOCITY_TOLERANCE = 0.001f;
1459 const float POSITION_TOLERANCE = 0.05f;
1460 const float ACCELERATION_TOLERANCE = 0.01f;
1461 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1462
1463 public override void UpdateProperties(EntityProperties entprop)
1464 {
1465 // Updates only for individual prims and for the root object of a linkset.
1466 if (Linkset.IsRoot(this))
1467 {
1468 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1469 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1470 if (_vehicle.IsActive)
1471 {
1472 entprop.RotationalVelocity = OMV.Vector3.Zero;
1473 }
1474
1475 // Assign directly to the local variables so the normal set action does not happen
1476 _position = entprop.Position;
1477 _orientation = entprop.Rotation;
1478 _velocity = entprop.Velocity;
1479 _acceleration = entprop.Acceleration;
1480 _rotationalVelocity = entprop.RotationalVelocity;
1481
1482 // The sanity check can change the velocity and/or position.
1483 if (IsPhysical && PositionSanityCheck(true))
1484 {
1485 entprop.Position = _position;
1486 entprop.Velocity = _velocity;
1487 }
1488
1489 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1490 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1491 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1492
1493 // remember the current and last set values
1494 LastEntityProperties = CurrentEntityProperties;
1495 CurrentEntityProperties = entprop;
1496
1497 base.RequestPhysicsterseUpdate();
1498 }
1499 /*
1500 else
1501 {
1502 // For debugging, report the movement of children
1503 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1504 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1505 entprop.Acceleration, entprop.RotationalVelocity);
1506 }
1507 */
1508
1509 // The linkset implimentation might want to know about this.
1510 Linkset.UpdateProperties(this, true);
1511 }
1512}
1513}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
deleted file mode 100644
index 7017194..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ /dev/null
@@ -1,946 +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 System.Runtime.InteropServices;
31using System.Text;
32using System.Threading;
33using OpenSim.Framework;
34using OpenSim.Region.Framework;
35using OpenSim.Region.CoreModules;
36using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
37using OpenSim.Region.Physics.Manager;
38using Nini.Config;
39using log4net;
40using OpenMetaverse;
41
42namespace OpenSim.Region.Physics.BulletSPlugin
43{
44public sealed class BSScene : PhysicsScene, IPhysicsParameters
45{
46 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
47 internal static readonly string LogHeader = "[BULLETS SCENE]";
48
49 // The name of the region we're working for.
50 public string RegionName { get; private set; }
51
52 public string BulletSimVersion = "?";
53
54 // The handle to the underlying managed or unmanaged version of Bullet being used.
55 public string BulletEngineName { get; private set; }
56 public BSAPITemplate PE;
57
58 public Dictionary<uint, BSPhysObject> PhysObjects;
59 public BSShapeCollection Shapes;
60
61 // Keeping track of the objects with collisions so we can report begin and end of a collision
62 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
63 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
64 // Keep track of all the avatars so we can send them a collision event
65 // every tick so OpenSim will update its animation.
66 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
67
68 // let my minuions use my logger
69 public ILog Logger { get { return m_log; } }
70
71 public IMesher mesher;
72 public uint WorldID { get; private set; }
73 public BulletWorld World { get; private set; }
74
75 // All the constraints that have been allocated in this instance.
76 public BSConstraintCollection Constraints { get; private set; }
77
78 // Simulation parameters
79 internal int m_maxSubSteps;
80 internal float m_fixedTimeStep;
81 internal long m_simulationStep = 0;
82 internal float NominalFrameRate { get; set; }
83 public long SimulationStep { get { return m_simulationStep; } }
84 internal int m_taintsToProcessPerStep;
85 internal float LastTimeStep { get; private set; }
86
87 // Physical objects can register for prestep or poststep events
88 public delegate void PreStepAction(float timeStep);
89 public delegate void PostStepAction(float timeStep);
90 public event PreStepAction BeforeStep;
91 public event PreStepAction AfterStep;
92
93 // A value of the time now so all the collision and update routines do not have to get their own
94 // Set to 'now' just before all the prims and actors are called for collisions and updates
95 public int SimulationNowTime { get; private set; }
96
97 // True if initialized and ready to do simulation steps
98 private bool m_initialized = false;
99
100 // Flag which is true when processing taints.
101 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
102 public bool InTaintTime { get; private set; }
103
104 // Pinned memory used to pass step information between managed and unmanaged
105 internal int m_maxCollisionsPerFrame;
106 internal CollisionDesc[] m_collisionArray;
107
108 internal int m_maxUpdatesPerFrame;
109 internal EntityProperties[] m_updateArray;
110
111 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
112 public const uint GROUNDPLANE_ID = 1;
113 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
114
115 public float SimpleWaterLevel { get; set; }
116 public BSTerrainManager TerrainManager { get; private set; }
117
118 public ConfigurationParameters Params
119 {
120 get { return UnmanagedParams[0]; }
121 }
122 public Vector3 DefaultGravity
123 {
124 get { return new Vector3(0f, 0f, Params.gravity); }
125 }
126 // Just the Z value of the gravity
127 public float DefaultGravityZ
128 {
129 get { return Params.gravity; }
130 }
131
132 // When functions in the unmanaged code must be called, it is only
133 // done at a known time just before the simulation step. The taint
134 // system saves all these function calls and executes them in
135 // order before the simulation.
136 public delegate void TaintCallback();
137 private struct TaintCallbackEntry
138 {
139 public String ident;
140 public TaintCallback callback;
141 public TaintCallbackEntry(string i, TaintCallback c)
142 {
143 ident = i;
144 callback = c;
145 }
146 }
147 private Object _taintLock = new Object(); // lock for using the next object
148 private List<TaintCallbackEntry> _taintOperations;
149 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
150 private List<TaintCallbackEntry> _postStepOperations;
151
152 // A pointer to an instance if this structure is passed to the C++ code
153 // Used to pass basic configuration values to the unmanaged code.
154 internal ConfigurationParameters[] UnmanagedParams;
155
156 // Sometimes you just have to log everything.
157 public Logging.LogWriter PhysicsLogging;
158 private bool m_physicsLoggingEnabled;
159 private string m_physicsLoggingDir;
160 private string m_physicsLoggingPrefix;
161 private int m_physicsLoggingFileMinutes;
162 private bool m_physicsLoggingDoFlush;
163 private bool m_physicsPhysicalDumpEnabled;
164 public float PhysicsMetricDumpFrames { get; set; }
165 // 'true' of the vehicle code is to log lots of details
166 public bool VehicleLoggingEnabled { get; private set; }
167 public bool VehiclePhysicalLoggingEnabled { get; private set; }
168
169 #region Construction and Initialization
170 public BSScene(string identifier)
171 {
172 m_initialized = false;
173 // we are passed the name of the region we're working for.
174 RegionName = identifier;
175 }
176
177 public override void Initialise(IMesher meshmerizer, IConfigSource config)
178 {
179 mesher = meshmerizer;
180 _taintOperations = new List<TaintCallbackEntry>();
181 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
182 _postStepOperations = new List<TaintCallbackEntry>();
183 PhysObjects = new Dictionary<uint, BSPhysObject>();
184 Shapes = new BSShapeCollection(this);
185
186 // Allocate pinned memory to pass parameters.
187 UnmanagedParams = new ConfigurationParameters[1];
188
189 // Set default values for physics parameters plus any overrides from the ini file
190 GetInitialParameterValues(config);
191
192 // Get the connection to the physics engine (could be native or one of many DLLs)
193 PE = SelectUnderlyingBulletEngine(BulletEngineName);
194
195 // Enable very detailed logging.
196 // By creating an empty logger when not logging, the log message invocation code
197 // can be left in and every call doesn't have to check for null.
198 if (m_physicsLoggingEnabled)
199 {
200 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
201 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
202 }
203 else
204 {
205 PhysicsLogging = new Logging.LogWriter();
206 }
207
208 // Allocate memory for returning of the updates and collisions from the physics engine
209 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
210 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
211
212 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
213 // a child in a mega-region.
214 // Bullet actually doesn't care about the extents of the simulated
215 // area. It tracks active objects no matter where they are.
216 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
217
218 World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
219
220 Constraints = new BSConstraintCollection(World);
221
222 TerrainManager = new BSTerrainManager(this);
223 TerrainManager.CreateInitialGroundPlaneAndTerrain();
224
225 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
226
227 InTaintTime = false;
228 m_initialized = true;
229 }
230
231 // All default parameter values are set here. There should be no values set in the
232 // variable definitions.
233 private void GetInitialParameterValues(IConfigSource config)
234 {
235 ConfigurationParameters parms = new ConfigurationParameters();
236 UnmanagedParams[0] = parms;
237
238 BSParam.SetParameterDefaultValues(this);
239
240 if (config != null)
241 {
242 // If there are specifications in the ini file, use those values
243 IConfig pConfig = config.Configs["BulletSim"];
244 if (pConfig != null)
245 {
246 BSParam.SetParameterConfigurationValues(this, pConfig);
247
248 // There are two Bullet implementations to choose from
249 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
250
251 // Very detailed logging for physics debugging
252 // TODO: the boolean values can be moved to the normal parameter processing.
253 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
254 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
255 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
256 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
257 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
258 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
259 // Very detailed logging for vehicle debugging
260 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
261 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
262
263 // Do any replacements in the parameters
264 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
265 }
266
267 // The material characteristics.
268 BSMaterials.InitializeFromDefaults(Params);
269 if (pConfig != null)
270 {
271 // Let the user add new and interesting material property values.
272 BSMaterials.InitializefromParameters(pConfig);
273 }
274 }
275 }
276
277 // A helper function that handles a true/false parameter and returns the proper float number encoding
278 float ParamBoolean(IConfig config, string parmName, float deflt)
279 {
280 float ret = deflt;
281 if (config.Contains(parmName))
282 {
283 ret = ConfigurationParameters.numericFalse;
284 if (config.GetBoolean(parmName, false))
285 {
286 ret = ConfigurationParameters.numericTrue;
287 }
288 }
289 return ret;
290 }
291
292 // Select the connection to the actual Bullet implementation.
293 // The main engine selection is the engineName up to the first hypen.
294 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
295 // is passed to the engine to do its special selection, etc.
296 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
297 {
298 // For the moment, do a simple switch statement.
299 // Someday do fancyness with looking up the interfaces in the assembly.
300 BSAPITemplate ret = null;
301
302 string selectionName = engineName.ToLower();
303 int hyphenIndex = engineName.IndexOf("-");
304 if (hyphenIndex > 0)
305 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
306
307 switch (selectionName)
308 {
309 case "bulletunmanaged":
310 ret = new BSAPIUnman(engineName, this);
311 break;
312 case "bulletxna":
313 ret = new BSAPIXNA(engineName, this);
314 break;
315 }
316
317 if (ret == null)
318 {
319 m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
320 }
321 else
322 {
323 m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
324 }
325
326 return ret;
327 }
328
329 public override void Dispose()
330 {
331 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
332
333 // make sure no stepping happens while we're deleting stuff
334 m_initialized = false;
335
336 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
337 {
338 kvp.Value.Destroy();
339 }
340 PhysObjects.Clear();
341
342 // Now that the prims are all cleaned up, there should be no constraints left
343 if (Constraints != null)
344 {
345 Constraints.Dispose();
346 Constraints = null;
347 }
348
349 if (Shapes != null)
350 {
351 Shapes.Dispose();
352 Shapes = null;
353 }
354
355 if (TerrainManager != null)
356 {
357 TerrainManager.ReleaseGroundPlaneAndTerrain();
358 TerrainManager.Dispose();
359 TerrainManager = null;
360 }
361
362 // Anything left in the unmanaged code should be cleaned out
363 PE.Shutdown(World);
364
365 // Not logging any more
366 PhysicsLogging.Close();
367 }
368 #endregion // Construction and Initialization
369
370 #region Prim and Avatar addition and removal
371
372 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
373 {
374 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
375 return null;
376 }
377
378 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
379 {
380 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
381
382 if (!m_initialized) return null;
383
384 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
385 lock (PhysObjects) PhysObjects.Add(localID, actor);
386
387 // TODO: Remove kludge someday.
388 // We must generate a collision for avatars whether they collide or not.
389 // This is required by OpenSim to update avatar animations, etc.
390 lock (m_avatars) m_avatars.Add(actor);
391
392 return actor;
393 }
394
395 public override void RemoveAvatar(PhysicsActor actor)
396 {
397 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
398
399 if (!m_initialized) return;
400
401 BSCharacter bsactor = actor as BSCharacter;
402 if (bsactor != null)
403 {
404 try
405 {
406 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
407 // Remove kludge someday
408 lock (m_avatars) m_avatars.Remove(bsactor);
409 }
410 catch (Exception e)
411 {
412 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
413 }
414 bsactor.Destroy();
415 // bsactor.dispose();
416 }
417 }
418
419 public override void RemovePrim(PhysicsActor prim)
420 {
421 if (!m_initialized) return;
422
423 BSPrim bsprim = prim as BSPrim;
424 if (bsprim != null)
425 {
426 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
427 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
428 try
429 {
430 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
431 }
432 catch (Exception e)
433 {
434 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
435 }
436 bsprim.Destroy();
437 // bsprim.dispose();
438 }
439 else
440 {
441 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
442 }
443 }
444
445 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
446 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
447 {
448 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
449
450 if (!m_initialized) return null;
451
452 DetailLog("{0},AddPrimShape,call", localID);
453
454 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
455 lock (PhysObjects) PhysObjects.Add(localID, prim);
456 return prim;
457 }
458
459 // This is a call from the simulator saying that some physical property has been updated.
460 // The BulletSim driver senses the changing of relevant properties so this taint
461 // information call is not needed.
462 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
463
464 #endregion // Prim and Avatar addition and removal
465
466 #region Simulation
467 // Simulate one timestep
468 public override float Simulate(float timeStep)
469 {
470 // prevent simulation until we've been initialized
471 if (!m_initialized) return 5.0f;
472
473 LastTimeStep = timeStep;
474
475 int updatedEntityCount = 0;
476 int collidersCount = 0;
477
478 int beforeTime = 0;
479 int simTime = 0;
480
481 // update the prim states while we know the physics engine is not busy
482 int numTaints = _taintOperations.Count;
483
484 InTaintTime = true; // Only used for debugging so locking is not necessary.
485
486 ProcessTaints();
487
488 // Some of the physical objects requre individual, pre-step calls
489 TriggerPreStepEvent(timeStep);
490
491 // the prestep actions might have added taints
492 numTaints += _taintOperations.Count;
493 ProcessTaints();
494
495 InTaintTime = false; // Only used for debugging so locking is not necessary.
496
497 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
498 // Only enable this in a limited test world with few objects.
499 if (m_physicsPhysicalDumpEnabled)
500 PE.DumpAllInfo(World);
501
502 // step the physical world one interval
503 m_simulationStep++;
504 int numSubSteps = 0;
505 try
506 {
507 if (PhysicsLogging.Enabled)
508 beforeTime = Util.EnvironmentTickCount();
509
510 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
511
512 if (PhysicsLogging.Enabled)
513 {
514 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
515 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
516 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
517 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
518 }
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 if ((m_simulationStep % PhysicsMetricDumpFrames) == 0)
531 PE.DumpPhysicsStatistics(World);
532
533 // Get a value for 'now' so all the collision and update routines don't have to get their own.
534 SimulationNowTime = Util.EnvironmentTickCount();
535
536 // If there were collisions, process them by sending the event to the prim.
537 // Collisions must be processed before updates.
538 if (collidersCount > 0)
539 {
540 for (int ii = 0; ii < collidersCount; ii++)
541 {
542 uint cA = m_collisionArray[ii].aID;
543 uint cB = m_collisionArray[ii].bID;
544 Vector3 point = m_collisionArray[ii].point;
545 Vector3 normal = m_collisionArray[ii].normal;
546 SendCollision(cA, cB, point, normal, 0.01f);
547 SendCollision(cB, cA, point, -normal, 0.01f);
548 }
549 }
550
551 // The above SendCollision's batch up the collisions on the objects.
552 // Now push the collisions into the simulator.
553 if (ObjectsWithCollisions.Count > 0)
554 {
555 foreach (BSPhysObject bsp in ObjectsWithCollisions)
556 if (!bsp.SendCollisions())
557 {
558 // If the object is done colliding, see that it's removed from the colliding list
559 ObjectsWithNoMoreCollisions.Add(bsp);
560 }
561 }
562
563 // This is a kludge to get avatar movement updates.
564 // The simulator expects collisions for avatars even if there are have been no collisions.
565 // The event updates avatar animations and stuff.
566 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
567 foreach (BSPhysObject bsp in m_avatars)
568 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
569 bsp.SendCollisions();
570
571 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
572 // Not done above because it is inside an iteration of ObjectWithCollisions.
573 // This complex collision processing is required to create an empty collision
574 // event call after all real collisions have happened on an object. This enables
575 // the simulator to generate the 'collision end' event.
576 if (ObjectsWithNoMoreCollisions.Count > 0)
577 {
578 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
579 ObjectsWithCollisions.Remove(po);
580 ObjectsWithNoMoreCollisions.Clear();
581 }
582 // Done with collisions.
583
584 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
585 if (updatedEntityCount > 0)
586 {
587 for (int ii = 0; ii < updatedEntityCount; ii++)
588 {
589 EntityProperties entprop = m_updateArray[ii];
590 BSPhysObject pobj;
591 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
592 {
593 pobj.UpdateProperties(entprop);
594 }
595 }
596 }
597
598 TriggerPostStepEvent(timeStep);
599
600 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
601 // Only enable this in a limited test world with few objects.
602 if (m_physicsPhysicalDumpEnabled)
603 PE.DumpAllInfo(World);
604
605 // The physics engine returns the number of milliseconds it simulated this call.
606 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
607 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
608 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
609 }
610
611 // Something has collided
612 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
613 {
614 if (localID <= TerrainManager.HighestTerrainID)
615 {
616 return; // don't send collisions to the terrain
617 }
618
619 BSPhysObject collider;
620 if (!PhysObjects.TryGetValue(localID, out collider))
621 {
622 // If the object that is colliding cannot be found, just ignore the collision.
623 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
624 return;
625 }
626
627 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
628 BSPhysObject collidee = null;
629 PhysObjects.TryGetValue(collidingWith, out collidee);
630
631 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
632
633 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
634 {
635 // If a collision was posted, remember to send it to the simulator
636 ObjectsWithCollisions.Add(collider);
637 }
638
639 return;
640 }
641
642 #endregion // Simulation
643
644 public override void GetResults() { }
645
646 #region Terrain
647
648 public override void SetTerrain(float[] heightMap) {
649 TerrainManager.SetTerrain(heightMap);
650 }
651
652 public override void SetWaterLevel(float baseheight)
653 {
654 SimpleWaterLevel = baseheight;
655 }
656
657 public override void DeleteTerrain()
658 {
659 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
660 }
661
662 // Although no one seems to check this, I do support combining.
663 public override bool SupportsCombining()
664 {
665 return TerrainManager.SupportsCombining();
666 }
667 // This call says I am a child to region zero in a mega-region. 'pScene' is that
668 // of region zero, 'offset' is my offset from regions zero's origin, and
669 // 'extents' is the largest XY that is handled in my region.
670 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
671 {
672 TerrainManager.Combine(pScene, offset, extents);
673 }
674
675 // Unhook all the combining that I know about.
676 public override void UnCombine(PhysicsScene pScene)
677 {
678 TerrainManager.UnCombine(pScene);
679 }
680
681 #endregion // Terrain
682
683 public override Dictionary<uint, float> GetTopColliders()
684 {
685 return new Dictionary<uint, float>();
686 }
687
688 public override bool IsThreaded { get { return false; } }
689
690 #region Taints
691 // The simulation execution order is:
692 // Simulate()
693 // DoOneTimeTaints
694 // TriggerPreStepEvent
695 // DoOneTimeTaints
696 // Step()
697 // ProcessAndForwardCollisions
698 // ProcessAndForwardPropertyUpdates
699 // TriggerPostStepEvent
700
701 // Calls to the PhysicsActors can't directly call into the physics engine
702 // because it might be busy. We delay changes to a known time.
703 // We rely on C#'s closure to save and restore the context for the delegate.
704 public void TaintedObject(String ident, TaintCallback callback)
705 {
706 if (!m_initialized) return;
707
708 lock (_taintLock)
709 {
710 _taintOperations.Add(new TaintCallbackEntry(ident, callback));
711 }
712
713 return;
714 }
715
716 // Sometimes a potentially tainted operation can be used in and out of taint time.
717 // This routine executes the command immediately if in taint-time otherwise it is queued.
718 public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback)
719 {
720 if (inTaintTime)
721 callback();
722 else
723 TaintedObject(ident, callback);
724 }
725
726 private void TriggerPreStepEvent(float timeStep)
727 {
728 PreStepAction actions = BeforeStep;
729 if (actions != null)
730 actions(timeStep);
731
732 }
733
734 private void TriggerPostStepEvent(float timeStep)
735 {
736 PreStepAction actions = AfterStep;
737 if (actions != null)
738 actions(timeStep);
739
740 }
741
742 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
743 // a callback into itself to do the actual property change. That callback is called
744 // here just before the physics engine is called to step the simulation.
745 public void ProcessTaints()
746 {
747 ProcessRegularTaints();
748 ProcessPostTaintTaints();
749 }
750
751 private void ProcessRegularTaints()
752 {
753 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
754 {
755 // swizzle a new list into the list location so we can process what's there
756 List<TaintCallbackEntry> oldList;
757 lock (_taintLock)
758 {
759 oldList = _taintOperations;
760 _taintOperations = new List<TaintCallbackEntry>();
761 }
762
763 foreach (TaintCallbackEntry tcbe in oldList)
764 {
765 try
766 {
767 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
768 tcbe.callback();
769 }
770 catch (Exception e)
771 {
772 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
773 }
774 }
775 oldList.Clear();
776 }
777 }
778
779 // Schedule an update to happen after all the regular taints are processed.
780 // Note that new requests for the same operation ("ident") for the same object ("ID")
781 // will replace any previous operation by the same object.
782 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
783 {
784 string uniqueIdent = ident + "-" + ID.ToString();
785 lock (_taintLock)
786 {
787 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback);
788 }
789
790 return;
791 }
792
793 // Taints that happen after the normal taint processing but before the simulation step.
794 private void ProcessPostTaintTaints()
795 {
796 if (_postTaintOperations.Count > 0)
797 {
798 Dictionary<string, TaintCallbackEntry> oldList;
799 lock (_taintLock)
800 {
801 oldList = _postTaintOperations;
802 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
803 }
804
805 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
806 {
807 try
808 {
809 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
810 kvp.Value.callback();
811 }
812 catch (Exception e)
813 {
814 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
815 }
816 }
817 oldList.Clear();
818 }
819 }
820
821 // Only used for debugging. Does not change state of anything so locking is not necessary.
822 public bool AssertInTaintTime(string whereFrom)
823 {
824 if (!InTaintTime)
825 {
826 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
827 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
828 Util.PrintCallStack(DetailLog);
829 }
830 return InTaintTime;
831 }
832
833 #endregion // Taints
834
835 #region INI and command line parameter processing
836
837 #region IPhysicsParameters
838 // Get the list of parameters this physics engine supports
839 public PhysParameterEntry[] GetParameterList()
840 {
841 BSParam.BuildParameterTable();
842 return BSParam.SettableParameters;
843 }
844
845 // Set parameter on a specific or all instances.
846 // Return 'false' if not able to set the parameter.
847 // Setting the value in the m_params block will change the value the physics engine
848 // will use the next time since it's pinned and shared memory.
849 // Some of the values require calling into the physics engine to get the new
850 // value activated ('terrainFriction' for instance).
851 public bool SetPhysicsParameter(string parm, float val, uint localID)
852 {
853 bool ret = false;
854 BSParam.ParameterDefn theParam;
855 if (BSParam.TryGetParameter(parm, out theParam))
856 {
857 theParam.setter(this, parm, localID, val);
858 ret = true;
859 }
860 return ret;
861 }
862
863 // update all the localIDs specified
864 // If the local ID is APPLY_TO_NONE, just change the default value
865 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
866 // If the localID is a specific object, apply the parameter change to only that object
867 internal delegate void AssignVal(float x);
868 internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
869 {
870 List<uint> objectIDs = new List<uint>();
871 switch (localID)
872 {
873 case PhysParameterEntry.APPLY_TO_NONE:
874 setDefault(val); // setting only the default value
875 // This will cause a call into the physical world if some operation is specified (SetOnObject).
876 objectIDs.Add(TERRAIN_ID);
877 TaintedUpdateParameter(parm, objectIDs, val);
878 break;
879 case PhysParameterEntry.APPLY_TO_ALL:
880 setDefault(val); // setting ALL also sets the default value
881 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
882 TaintedUpdateParameter(parm, objectIDs, val);
883 break;
884 default:
885 // setting only one localID
886 objectIDs.Add(localID);
887 TaintedUpdateParameter(parm, objectIDs, val);
888 break;
889 }
890 }
891
892 // schedule the actual updating of the paramter to when the phys engine is not busy
893 private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
894 {
895 float xval = val;
896 List<uint> xlIDs = lIDs;
897 string xparm = parm;
898 TaintedObject("BSScene.UpdateParameterSet", delegate() {
899 BSParam.ParameterDefn thisParam;
900 if (BSParam.TryGetParameter(xparm, out thisParam))
901 {
902 if (thisParam.onObject != null)
903 {
904 foreach (uint lID in xlIDs)
905 {
906 BSPhysObject theObject = null;
907 PhysObjects.TryGetValue(lID, out theObject);
908 thisParam.onObject(this, theObject, xval);
909 }
910 }
911 }
912 });
913 }
914
915 // Get parameter.
916 // Return 'false' if not able to get the parameter.
917 public bool GetPhysicsParameter(string parm, out float value)
918 {
919 float val = 0f;
920 bool ret = false;
921 BSParam.ParameterDefn theParam;
922 if (BSParam.TryGetParameter(parm, out theParam))
923 {
924 val = theParam.getter(this);
925 ret = true;
926 }
927 value = val;
928 return ret;
929 }
930
931 #endregion IPhysicsParameters
932
933 #endregion Runtime settable parameters
934
935 // Invoke the detailed logger and output something if it's enabled.
936 public void DetailLog(string msg, params Object[] args)
937 {
938 PhysicsLogging.Write(msg, args);
939 // Add the Flush() if debugging crashes. Gets all the messages written out.
940 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
941 }
942 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
943 public const string DetailLogZero = "0000000000";
944
945}
946}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
deleted file mode 100755
index d361f18..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ /dev/null
@@ -1,1009 +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.BulletSPlugin
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 BulletShape shape;
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 BulletShape shape;
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 (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
145 {
146 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
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 (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
170 {
171 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
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 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
177 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
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.shape = shape.Clone();
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.shape = shape.Clone();
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.AddrString, inTaintTime);
263 if (shapeCallback != null) shapeCallback(shape);
264 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
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 (!PhysicsScene.PE.IsCompound(shape))
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.AddrString);
340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
341 BSScene.DetailLogZero, shape.type, shape.AddrString);
342 return;
343 }
344
345 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
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 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
351 DereferenceAnonCollisionShape(childShape);
352 }
353 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
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(BulletShape shapeInfo)
360 {
361 MeshDesc meshDesc;
362 HullDesc hullDesc;
363
364 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
365 {
366 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
367 shapeInfo.shapeKey = meshDesc.shapeKey;
368 }
369 else
370 {
371 if (TryGetHullByPtr(shapeInfo, out hullDesc))
372 {
373 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
374 shapeInfo.shapeKey = hullDesc.shapeKey;
375 }
376 else
377 {
378 if (PhysicsScene.PE.IsCompound(shapeInfo))
379 {
380 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
381 }
382 else
383 {
384 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
385 {
386 shapeInfo.isNativeShape = true;
387 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
388 }
389 }
390 }
391 }
392
393 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
394
395 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
396 {
397 DereferenceShape(shapeInfo, true, null);
398 }
399 else
400 {
401 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
402 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
403 }
404 }
405
406 // Create the geometry information in Bullet for later use.
407 // The objects needs a hull if it's physical otherwise a mesh is enough.
408 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
409 // shared geometries will be used. If the parameters of the existing shape are the same
410 // as this request, the shape is not rebuilt.
411 // Info in prim.BSShape is updated to the new shape.
412 // Returns 'true' if the geometry was rebuilt.
413 // Called at taint-time!
414 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
415 {
416 bool ret = false;
417 bool haveShape = false;
418
419 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
420 {
421 // an avatar capsule is close to a native shape (it is not shared)
422 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
423 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
424 ret = true;
425 haveShape = true;
426 }
427
428 // Compound shapes are handled special as they are rebuilt from scratch.
429 // This isn't too great a hardship since most of the child shapes will have already been created.
430 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
431 {
432 ret = GetReferenceToCompoundShape(prim, shapeCallback);
433 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
434 haveShape = true;
435 }
436
437 if (!haveShape)
438 {
439 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
440 }
441
442 return ret;
443 }
444
445 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
446 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
447 {
448 bool ret = false;
449 bool haveShape = false;
450 bool nativeShapePossible = true;
451 PrimitiveBaseShape pbs = prim.BaseShape;
452
453 // If the prim attributes are simple, this could be a simple Bullet native shape
454 if (!haveShape
455 && pbs != null
456 && nativeShapePossible
457 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
458 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
459 && pbs.ProfileHollow == 0
460 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
461 && pbs.PathBegin == 0 && pbs.PathEnd == 0
462 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
463 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
464 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
465 {
466 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
467 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
468 if (prim.PhysShape.HasPhysicalShape)
469 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape);
470
471 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
472 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
473
474 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
475 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
476 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
477 {
478 haveShape = true;
479 if (forceRebuild
480 || prim.Scale != scaleOfExistingShape
481 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
482 )
483 {
484 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
485 FixedShapeKey.KEY_SPHERE, shapeCallback);
486 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
487 prim.LocalID, forceRebuild, prim.PhysShape);
488 }
489 }
490 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
491 {
492 haveShape = true;
493 if (forceRebuild
494 || prim.Scale != scaleOfExistingShape
495 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
496 )
497 {
498 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
499 FixedShapeKey.KEY_BOX, shapeCallback);
500 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
501 prim.LocalID, forceRebuild, prim.PhysShape);
502 }
503 }
504 }
505
506 // If a simple shape is not happening, create a mesh and possibly a hull.
507 if (!haveShape && pbs != null)
508 {
509 ret = CreateGeomMeshOrHull(prim, shapeCallback);
510 }
511
512 return ret;
513 }
514
515 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
516 {
517
518 bool ret = false;
519 // Note that if it's a native shape, the check for physical/non-physical is not
520 // made. Native shapes work in either case.
521 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
522 {
523 // Update prim.BSShape to reference a hull of this shape.
524 ret = GetReferenceToHull(prim,shapeCallback);
525 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
526 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
527 }
528 else
529 {
530 ret = GetReferenceToMesh(prim, shapeCallback);
531 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
532 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
533 }
534 return ret;
535 }
536
537 // Creates a native shape and assignes it to prim.BSShape.
538 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
539 private bool GetReferenceToNativeShape(BSPhysObject prim,
540 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
541 ShapeDestructionCallback shapeCallback)
542 {
543 // release any previous shape
544 DereferenceShape(prim.PhysShape, true, shapeCallback);
545
546 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
547
548 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
549 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
550 prim.LocalID, newShape, prim.Scale);
551
552 // native shapes are scaled by Bullet
553 prim.PhysShape = newShape;
554 return true;
555 }
556
557 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
558 FixedShapeKey shapeKey)
559 {
560 BulletShape newShape;
561 // Need to make sure the passed shape information is for the native type.
562 ShapeData nativeShapeData = new ShapeData();
563 nativeShapeData.Type = shapeType;
564 nativeShapeData.ID = prim.LocalID;
565 nativeShapeData.Scale = prim.Scale;
566 nativeShapeData.Size = prim.Scale; // unneeded, I think.
567 nativeShapeData.MeshKey = (ulong)shapeKey;
568 nativeShapeData.HullKey = (ulong)shapeKey;
569
570 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
571 {
572
573 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
574 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
575 }
576 else
577 {
578 // Native shapes are scaled in Bullet so set the scaling to the size
579 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
580
581 }
582 if (!newShape.HasPhysicalShape)
583 {
584 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
585 LogHeader, prim.LocalID, shapeType);
586 }
587 newShape.shapeKey = (System.UInt64)shapeKey;
588 newShape.isNativeShape = true;
589
590 return newShape;
591 }
592
593 // Builds a mesh shape in the physical world and updates prim.BSShape.
594 // Dereferences previous shape in BSShape and adds a reference for this new shape.
595 // Returns 'true' of a mesh was actually built. Otherwise .
596 // Called at taint-time!
597 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
598 {
599 BulletShape newShape = new BulletShape();
600
601 float lod;
602 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
603
604 // if this new shape is the same as last time, don't recreate the mesh
605 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
606 return false;
607
608 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
609 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
610
611 // Since we're recreating new, get rid of the reference to the previous shape
612 DereferenceShape(prim.PhysShape, true, shapeCallback);
613
614 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod);
615 // Take evasive action if the mesh was not constructed.
616 newShape = VerifyMeshCreated(newShape, prim);
617
618 ReferenceShape(newShape);
619
620 prim.PhysShape = newShape;
621
622 return true; // 'true' means a new shape has been added to this prim
623 }
624
625 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
626 {
627 BulletShape newShape = new BulletShape();
628 IMesh meshData = null;
629
630 MeshDesc meshDesc;
631 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
632 {
633 // If the mesh has already been built just use it.
634 newShape = meshDesc.shape.Clone();
635 }
636 else
637 {
638 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
639
640 if (meshData != null)
641 {
642 int[] indices = meshData.getIndexListAsInt();
643 List<OMV.Vector3> vertices = meshData.getVertexList();
644
645 float[] verticesAsFloats = new float[vertices.Count * 3];
646 int vi = 0;
647 foreach (OMV.Vector3 vv in vertices)
648 {
649 verticesAsFloats[vi++] = vv.X;
650 verticesAsFloats[vi++] = vv.Y;
651 verticesAsFloats[vi++] = vv.Z;
652 }
653
654 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
655 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
656
657 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
658 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
659 }
660 }
661 newShape.shapeKey = newMeshKey;
662
663 return newShape;
664 }
665
666 // See that hull shape exists in the physical world and update prim.BSShape.
667 // We could be creating the hull because scale changed or whatever.
668 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
669 {
670 BulletShape newShape;
671
672 float lod;
673 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
674
675 // if the hull hasn't changed, don't rebuild it
676 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
677 return false;
678
679 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
680 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
681
682 // Remove usage of the previous shape.
683 DereferenceShape(prim.PhysShape, true, shapeCallback);
684
685 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
686 newShape = VerifyMeshCreated(newShape, prim);
687
688 ReferenceShape(newShape);
689
690 prim.PhysShape = newShape;
691 return true; // 'true' means a new shape has been added to this prim
692 }
693
694 List<ConvexResult> m_hulls;
695 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
696 {
697
698 BulletShape newShape = new BulletShape();
699 IntPtr hullPtr = IntPtr.Zero;
700
701 HullDesc hullDesc;
702 if (Hulls.TryGetValue(newHullKey, out hullDesc))
703 {
704 // If the hull shape already is created, just use it.
705 newShape = hullDesc.shape.Clone();
706 }
707 else
708 {
709 // Build a new hull in the physical world
710 // Pass true for physicalness as this creates some sort of bounding box which we don't need
711 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false);
712 if (meshData != null)
713 {
714
715 int[] indices = meshData.getIndexListAsInt();
716 List<OMV.Vector3> vertices = meshData.getVertexList();
717
718 //format conversion from IMesh format to DecompDesc format
719 List<int> convIndices = new List<int>();
720 List<float3> convVertices = new List<float3>();
721 for (int ii = 0; ii < indices.GetLength(0); ii++)
722 {
723 convIndices.Add(indices[ii]);
724 }
725 foreach (OMV.Vector3 vv in vertices)
726 {
727 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
728 }
729
730 // setup and do convex hull conversion
731 m_hulls = new List<ConvexResult>();
732 DecompDesc dcomp = new DecompDesc();
733 dcomp.mIndices = convIndices;
734 dcomp.mVertices = convVertices;
735 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
736 // create the hull into the _hulls variable
737 convexBuilder.process(dcomp);
738
739 // Convert the vertices and indices for passing to unmanaged.
740 // The hull information is passed as a large floating point array.
741 // The format is:
742 // convHulls[0] = number of hulls
743 // convHulls[1] = number of vertices in first hull
744 // convHulls[2] = hull centroid X coordinate
745 // convHulls[3] = hull centroid Y coordinate
746 // convHulls[4] = hull centroid Z coordinate
747 // convHulls[5] = first hull vertex X
748 // convHulls[6] = first hull vertex Y
749 // convHulls[7] = first hull vertex Z
750 // convHulls[8] = second hull vertex X
751 // ...
752 // convHulls[n] = number of vertices in second hull
753 // convHulls[n+1] = second hull centroid X coordinate
754 // ...
755 //
756 // TODO: is is very inefficient. Someday change the convex hull generator to return
757 // data structures that do not need to be converted in order to pass to Bullet.
758 // And maybe put the values directly into pinned memory rather than marshaling.
759 int hullCount = m_hulls.Count;
760 int totalVertices = 1; // include one for the count of the hulls
761 foreach (ConvexResult cr in m_hulls)
762 {
763 totalVertices += 4; // add four for the vertex count and centroid
764 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
765 }
766 float[] convHulls = new float[totalVertices];
767
768 convHulls[0] = (float)hullCount;
769 int jj = 1;
770 foreach (ConvexResult cr in m_hulls)
771 {
772 // copy vertices for index access
773 float3[] verts = new float3[cr.HullVertices.Count];
774 int kk = 0;
775 foreach (float3 ff in cr.HullVertices)
776 {
777 verts[kk++] = ff;
778 }
779
780 // add to the array one hull's worth of data
781 convHulls[jj++] = cr.HullIndices.Count;
782 convHulls[jj++] = 0f; // centroid x,y,z
783 convHulls[jj++] = 0f;
784 convHulls[jj++] = 0f;
785 foreach (int ind in cr.HullIndices)
786 {
787 convHulls[jj++] = verts[ind].x;
788 convHulls[jj++] = verts[ind].y;
789 convHulls[jj++] = verts[ind].z;
790 }
791 }
792 // create the hull data structure in Bullet
793 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
794 }
795 }
796
797 newShape.shapeKey = newHullKey;
798
799 return newShape;
800 }
801
802 // Callback from convex hull creater with a newly created hull.
803 // Just add it to our collection of hulls for this shape.
804 private void HullReturn(ConvexResult result)
805 {
806 m_hulls.Add(result);
807 return;
808 }
809
810 // Compound shapes are always built from scratch.
811 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
812 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
813 {
814 // Remove reference to the old shape
815 // Don't need to do this as the shape is freed when the new root shape is created below.
816 // DereferenceShape(prim.PhysShape, true, shapeCallback);
817
818
819 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
820
821 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
822 CreateGeomMeshOrHull(prim, shapeCallback);
823 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
824 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
825 prim.LocalID, cShape, prim.PhysShape);
826
827 prim.PhysShape = cShape;
828
829 return true;
830 }
831
832 // Create a hash of all the shape parameters to be used as a key
833 // for this particular shape.
834 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
835 {
836 // level of detail based on size and type of the object
837 float lod = BSParam.MeshLOD;
838 if (pbs.SculptEntry)
839 lod = BSParam.SculptLOD;
840
841 // Mega prims usually get more detail because one can interact with shape approximations at this size.
842 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
843 if (maxAxis > BSParam.MeshMegaPrimThreshold)
844 lod = BSParam.MeshMegaPrimLOD;
845
846 retLod = lod;
847 return pbs.GetMeshKey(size, lod);
848 }
849 // For those who don't want the LOD
850 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
851 {
852 float lod;
853 return ComputeShapeKey(size, pbs, out lod);
854 }
855
856 // The creation of a mesh or hull can fail if an underlying asset is not available.
857 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
858 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
859 // The first case causes the asset to be fetched. The second case requires
860 // us to not loop forever.
861 // Called after creating a physical mesh or hull. If the physical shape was created,
862 // just return.
863 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
864 {
865 // If the shape was successfully created, nothing more to do
866 if (newShape.HasPhysicalShape)
867 return newShape;
868
869 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
870 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
871 {
872 prim.LastAssetBuildFailed = true;
873 BSPhysObject xprim = prim;
874 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
875 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
876 Util.FireAndForget(delegate
877 {
878 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
879 if (assetProvider != null)
880 {
881 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
882 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
883 {
884 if (!yprim.BaseShape.SculptEntry)
885 return;
886 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
887 return;
888
889 yprim.BaseShape.SculptData = asset.Data;
890 // This will cause the prim to see that the filler shape is not the right
891 // one and try again to build the object.
892 // No race condition with the normal shape setting since the rebuild is at taint time.
893 yprim.ForceBodyShapeRebuild(false);
894
895 });
896 }
897 });
898 }
899 else
900 {
901 if (prim.LastAssetBuildFailed)
902 {
903 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
904 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
905 }
906 }
907
908 // While we figure out the real problem, stick a simple native shape on the object.
909 BulletShape fillinShape =
910 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
911
912 return fillinShape;
913 }
914
915 // Create a body object in Bullet.
916 // Updates prim.BSBody with the information about the new body if one is created.
917 // Returns 'true' if an object was actually created.
918 // Called at taint-time.
919 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape,
920 BodyDestructionCallback bodyCallback)
921 {
922 bool ret = false;
923
924 // the mesh, hull or native shape must have already been created in Bullet
925 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
926
927 // If there is an existing body, verify it's of an acceptable type.
928 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
929 if (!mustRebuild)
930 {
931 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
932 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
933 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
934 {
935 // If the collisionObject is not the correct type for solidness, rebuild what's there
936 mustRebuild = true;
937 }
938 }
939
940 if (mustRebuild || forceRebuild)
941 {
942 // Free any old body
943 DereferenceBody(prim.PhysBody, true, bodyCallback);
944
945 BulletBody aBody;
946 if (prim.IsSolid)
947 {
948 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
949 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody);
950 }
951 else
952 {
953 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
954 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
955 }
956
957 ReferenceBody(aBody, true);
958
959 prim.PhysBody = aBody;
960
961 ret = true;
962 }
963
964 return ret;
965 }
966
967 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
968 {
969 bool ret = false;
970 MeshDesc foundDesc = new MeshDesc();
971 foreach (MeshDesc md in Meshes.Values)
972 {
973 if (md.shape.ReferenceSame(shape))
974 {
975 foundDesc = md;
976 ret = true;
977 break;
978 }
979
980 }
981 outDesc = foundDesc;
982 return ret;
983 }
984
985 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
986 {
987 bool ret = false;
988 HullDesc foundDesc = new HullDesc();
989 foreach (HullDesc hd in Hulls.Values)
990 {
991 if (hd.shape.ReferenceSame(shape))
992 {
993 foundDesc = hd;
994 ret = true;
995 break;
996 }
997
998 }
999 outDesc = foundDesc;
1000 return ret;
1001 }
1002
1003 private void DetailLog(string msg, params Object[] args)
1004 {
1005 if (PhysicsScene.PhysicsLogging.Enabled)
1006 PhysicsScene.DetailLog(msg, args);
1007 }
1008}
1009}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
deleted file mode 100755
index c75eb9b..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ /dev/null
@@ -1,232 +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.BulletSPlugin
34{
35public abstract class BSShape
36{
37 public IntPtr 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 = IntPtr.Zero;
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 // Returns a string for debugging that uniquily identifies the memory used by this instance
95 public string AddrString
96 {
97 get { return ptr.ToString("X"); }
98 }
99
100 public override string ToString()
101 {
102 StringBuilder buff = new StringBuilder();
103 buff.Append("<p=");
104 buff.Append(AddrString);
105 buff.Append(",s=");
106 buff.Append(type.ToString());
107 buff.Append(",k=");
108 buff.Append(key.ToString("X"));
109 buff.Append(",c=");
110 buff.Append(referenceCount.ToString());
111 buff.Append(">");
112 return buff.ToString();
113 }
114}
115
116public class BSShapeNull : BSShape
117{
118 public BSShapeNull() : base()
119 {
120 }
121 public static BSShape GetReference() { return new BSShapeNull(); }
122 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
123}
124
125public class BSShapeNative : BSShape
126{
127 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
128 public BSShapeNative() : base()
129 {
130 }
131 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
132 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
133 {
134 // Native shapes are not shared and are always built anew.
135 //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
136 return null;
137 }
138
139 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
140 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
141 {
142 ShapeData nativeShapeData = new ShapeData();
143 nativeShapeData.Type = shapeType;
144 nativeShapeData.ID = prim.LocalID;
145 nativeShapeData.Scale = prim.Scale;
146 nativeShapeData.Size = prim.Scale;
147 nativeShapeData.MeshKey = (ulong)shapeKey;
148 nativeShapeData.HullKey = (ulong)shapeKey;
149
150
151 /*
152 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
153 {
154 ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
155 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
156 }
157 else
158 {
159 ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
160 }
161 if (ptr == IntPtr.Zero)
162 {
163 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
164 LogHeader, prim.LocalID, shapeType);
165 }
166 type = shapeType;
167 key = (UInt64)shapeKey;
168 */
169 }
170 // Make this reference to the physical shape go away since native shapes are not shared.
171 public override void Dereference(BSScene physicsScene)
172 {
173 /*
174 // Native shapes are not tracked and are released immediately
175 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
176 PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this);
177 ptr = IntPtr.Zero;
178 // Garbage collection will free up this instance.
179 */
180 }
181}
182
183public class BSShapeMesh : BSShape
184{
185 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
186 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
187
188 public BSShapeMesh() : base()
189 {
190 }
191 public static BSShape GetReference() { return new BSShapeNull(); }
192 public override void Dereference(BSScene physicsScene) { }
193}
194
195public class BSShapeHull : BSShape
196{
197 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
198 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
199
200 public BSShapeHull() : base()
201 {
202 }
203 public static BSShape GetReference() { return new BSShapeNull(); }
204 public override void Dereference(BSScene physicsScene) { }
205}
206
207public class BSShapeCompound : BSShape
208{
209 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
210 public BSShapeCompound() : base()
211 {
212 }
213 public static BSShape GetReference(BSPhysObject prim)
214 {
215 return new BSShapeNull();
216 }
217 public override void Dereference(BSScene physicsScene) { }
218}
219
220public class BSShapeAvatar : BSShape
221{
222 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
223 public BSShapeAvatar() : base()
224 {
225 }
226 public static BSShape GetReference(BSPhysObject prim)
227 {
228 return new BSShapeNull();
229 }
230 public override void Dereference(BSScene physicsScene) { }
231}
232}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
deleted file mode 100755
index e4fecc3..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ /dev/null
@@ -1,171 +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.BulletSPlugin
42{
43public sealed class BSTerrainHeightmap : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46
47 BulletHMapInfo 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 BulletHMapInfo(id, initialMap);
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 BulletHMapInfo(id, initialMap);
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 // Create the terrain shape from the mapInfo
95 m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98
99
100 // The terrain object initial position is at the center of the object
101 Vector3 centerPos;
102 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
105
106 m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
107 m_mapInfo.ID, centerPos, Quaternion.Identity);
108
109 // Set current terrain attributes
110 PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
111 PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
112 PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
113 PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
114
115 // Return the new terrain to the world of physical objects
116 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody);
117
118 // redo its bounding box now that it is in the world
119 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody);
120
121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
122 m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene);
123
124 // Make it so the terrain will not move or be considered for movement.
125 PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
126
127 return;
128 }
129
130 // If there is information in m_mapInfo pointing to physical structures, release same.
131 private void ReleaseHeightMapTerrain()
132 {
133 if (m_mapInfo != null)
134 {
135 if (m_mapInfo.terrainBody.HasPhysicalBody)
136 {
137 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody);
138 // Frees both the body and the shape.
139 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody);
140 }
141 }
142 m_mapInfo = null;
143 }
144
145 // The passed position is relative to the base of the region.
146 public override float GetTerrainHeightAtXYZ(Vector3 pos)
147 {
148 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
149
150 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
151 try
152 {
153 ret = m_mapInfo.heightMap[mapIndex];
154 }
155 catch
156 {
157 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
158 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
159 LogHeader, m_mapInfo.terrainRegionBase, pos);
160 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
161 }
162 return ret;
163 }
164
165 // The passed position is relative to the base of the region.
166 public override float GetWaterLevelAtXYZ(Vector3 pos)
167 {
168 return PhysicsScene.SimpleWaterLevel;
169 }
170}
171}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
deleted file mode 100755
index 2e9db39..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ /dev/null
@@ -1,458 +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.BulletSPlugin
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 = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
137 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
138 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
139
140 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
141 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane);
142 // Ground plane does not move
143 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
144 // Everything collides with the ground plane.
145 m_groundPlane.collisionType = CollisionType.Groundplane;
146 m_groundPlane.ApplyCollisionMask(PhysicsScene);
147
148 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
150 m_terrains.Add(Vector3.Zero, initialTerrain);
151 }
152
153 // Release all the terrain structures we might have allocated
154 public void ReleaseGroundPlaneAndTerrain()
155 {
156 if (m_groundPlane.HasPhysicalBody)
157 {
158 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
159 {
160 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane);
161 }
162 m_groundPlane.Clear();
163 }
164
165 ReleaseTerrain();
166 }
167
168 // Release all the terrain we have allocated
169 public void ReleaseTerrain()
170 {
171 lock (m_terrains)
172 {
173 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
174 {
175 kvp.Value.Dispose();
176 }
177 m_terrains.Clear();
178 }
179 }
180
181 // The simulator wants to set a new heightmap for the terrain.
182 public void SetTerrain(float[] heightMap) {
183 float[] localHeightMap = heightMap;
184 // If there are multiple requests for changes to the same terrain between ticks,
185 // only do that last one.
186 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
187 {
188 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
189 {
190 // If a child of a mega-region, we shouldn't have any terrain allocated for us
191 ReleaseGroundPlaneAndTerrain();
192 // If doing the mega-prim stuff and we are the child of the zero region,
193 // the terrain is added to our parent
194 if (MegaRegionParentPhysicsScene is BSScene)
195 {
196 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
197 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
198 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
199 BSScene.CHILDTERRAIN_ID, localHeightMap,
200 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
201 }
202 }
203 else
204 {
205 // If not doing the mega-prim thing, just change the terrain
206 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
207
208 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
210 }
211 });
212 }
213
214 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
215 // based on the passed information. The 'id' should be either the terrain id or
216 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
217 // The latter feature is for creating child terrains for mega-regions.
218 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
219 // terrain shape is created and added to the body.
220 // This call is most often used to update the heightMap and parameters of the terrain.
221 // (The above does suggest that some simplification/refactoring is in order.)
222 // Called during taint-time.
223 private void UpdateTerrain(uint id, float[] heightMap,
224 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
225 {
226 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
227 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
228
229 // Find high and low points of passed heightmap.
230 // The min and max passed in is usually the area objects can be in (maximum
231 // object height, for instance). The terrain wants the bounding box for the
232 // terrain so replace passed min and max Z with the actual terrain min/max Z.
233 float minZ = float.MaxValue;
234 float maxZ = float.MinValue;
235 foreach (float height in heightMap)
236 {
237 if (height < minZ) minZ = height;
238 if (height > maxZ) maxZ = height;
239 }
240 if (minZ == maxZ)
241 {
242 // If min and max are the same, reduce min a little bit so a good bounding box is created.
243 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
244 }
245 minCoords.Z = minZ;
246 maxCoords.Z = maxZ;
247
248 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
249
250 lock (m_terrains)
251 {
252 BSTerrainPhys terrainPhys;
253 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
254 {
255 // There is already a terrain in this spot. Free the old and build the new.
256 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
257 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
258
259 // Remove old terrain from the collection
260 m_terrains.Remove(terrainRegionBase);
261 // Release any physical memory it may be using.
262 terrainPhys.Dispose();
263
264 if (MegaRegionParentPhysicsScene == null)
265 {
266 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
267 m_terrains.Add(terrainRegionBase, newTerrainPhys);
268
269 m_terrainModified = true;
270 }
271 else
272 {
273 // It's possible that Combine() was called after this code was queued.
274 // If we are a child of combined regions, we don't create any terrain for us.
275 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
276
277 // Get rid of any terrain that may have been allocated for us.
278 ReleaseGroundPlaneAndTerrain();
279
280 // I hate doing this, but just bail
281 return;
282 }
283 }
284 else
285 {
286 // We don't know about this terrain so either we are creating a new terrain or
287 // our mega-prim child is giving us a new terrain to add to the phys world
288
289 // if this is a child terrain, calculate a unique terrain id
290 uint newTerrainID = id;
291 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
292 newTerrainID = ++m_terrainCount;
293
294 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
295 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
296 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
297 m_terrains.Add(terrainRegionBase, newTerrainPhys);
298
299 m_terrainModified = true;
300 }
301 }
302 }
303
304 // TODO: redo terrain implementation selection to allow other base types than heightMap.
305 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
306 {
307 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
308 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
309 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
310 BSTerrainPhys newTerrainPhys = null;
311 switch ((int)BSParam.TerrainImplementation)
312 {
313 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
314 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
315 heightMap, minCoords, maxCoords);
316 break;
317 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
318 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id,
319 heightMap, minCoords, maxCoords);
320 break;
321 default:
322 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
323 LogHeader,
324 (int)BSParam.TerrainImplementation,
325 BSParam.TerrainImplementation,
326 PhysicsScene.RegionName, terrainRegionBase);
327 break;
328 }
329 return newTerrainPhys;
330 }
331
332 // Return 'true' of this position is somewhere in known physical terrain space
333 public bool IsWithinKnownTerrain(Vector3 pos)
334 {
335 Vector3 terrainBaseXYZ;
336 BSTerrainPhys physTerrain;
337 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
338 }
339
340 // Given an X and Y, find the height of the terrain.
341 // Since we could be handling multiple terrains for a mega-region,
342 // the base of the region is calcuated assuming all regions are
343 // the same size and that is the default.
344 // Once the heightMapInfo is found, we have all the information to
345 // compute the offset into the array.
346 private float lastHeightTX = 999999f;
347 private float lastHeightTY = 999999f;
348 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
349 public float GetTerrainHeightAtXYZ(Vector3 pos)
350 {
351 float tX = pos.X;
352 float tY = pos.Y;
353 // You'd be surprized at the number of times this routine is called
354 // with the same parameters as last time.
355 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
356 return lastHeight;
357 m_terrainModified = false;
358
359 lastHeightTX = tX;
360 lastHeightTY = tY;
361 float ret = HEIGHT_GETHEIGHT_RET;
362
363 Vector3 terrainBaseXYZ;
364 BSTerrainPhys physTerrain;
365 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
366 {
367 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
368 }
369 else
370 {
371 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
372 LogHeader, PhysicsScene.RegionName, tX, tY);
373 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
374 BSScene.DetailLogZero, pos, terrainBaseXYZ);
375 }
376
377 lastHeight = ret;
378 return ret;
379 }
380
381 public float GetWaterLevelAtXYZ(Vector3 pos)
382 {
383 float ret = WATER_HEIGHT_GETHEIGHT_RET;
384
385 Vector3 terrainBaseXYZ;
386 BSTerrainPhys physTerrain;
387 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
388 {
389 ret = physTerrain.GetWaterLevelAtXYZ(pos);
390 }
391 else
392 {
393 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
394 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret);
395 }
396 return ret;
397 }
398
399 // Given an address, return 'true' of there is a description of that terrain and output
400 // the descriptor class and the 'base' fo the addresses therein.
401 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
402 {
403 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
404 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
405 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
406
407 BSTerrainPhys physTerrain = null;
408 lock (m_terrains)
409 {
410 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
411 }
412 outTerrainBase = terrainBaseXYZ;
413 outPhysTerrain = physTerrain;
414 return (physTerrain != null);
415 }
416
417 // Although no one seems to check this, I do support combining.
418 public bool SupportsCombining()
419 {
420 return true;
421 }
422
423 // This routine is called two ways:
424 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
425 // extent of the combined regions. This is to inform the parent of the size
426 // of the combined regions.
427 // and one with 'offset' as the offset of the child region to the base region,
428 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
429 // child of its relative base and new parent.
430 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
431 {
432 m_worldOffset = offset;
433 m_worldMax = extents;
434 MegaRegionParentPhysicsScene = pScene;
435 if (pScene != null)
436 {
437 // We are a child.
438 // We want m_worldMax to be the highest coordinate of our piece of terrain.
439 m_worldMax = offset + DefaultRegionSize;
440 }
441 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
442 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
443 }
444
445 // Unhook all the combining that I know about.
446 public void UnCombine(PhysicsScene pScene)
447 {
448 // Just like ODE, we don't do anything yet.
449 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
450 }
451
452
453 private void DetailLog(string msg, params Object[] args)
454 {
455 PhysicsScene.PhysicsLogging.Write(msg, args);
456 }
457}
458}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
deleted file mode 100755
index 1d55ce3..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ /dev/null
@@ -1,265 +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.BulletSPlugin
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 = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
95 if (!m_terrainShape.HasPhysicalShape)
96 {
97 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
99 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
100 // Something is very messed up and a crash is in our future.
101 return;
102 }
103
104 Vector3 pos = regionBase;
105 Quaternion rot = Quaternion.Identity;
106
107 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
108 if (!m_terrainBody.HasPhysicalBody)
109 {
110 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
112 // Something is very messed up and a crash is in our future.
113 return;
114 }
115
116 // Set current terrain attributes
117 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
118 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
119 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
120 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
121
122 // Static objects are not very massive.
123 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
124
125 // Put the new terrain to the world of physical objects
126 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);
127
128 // Redo its bounding box now that it is in the world
129 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);
130
131 m_terrainBody.collisionType = CollisionType.Terrain;
132 m_terrainBody.ApplyCollisionMask(PhysicsScene);
133
134 // Make it so the terrain will not move or be considered for movement.
135 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
136 }
137
138 public override void Dispose()
139 {
140 if (m_terrainBody.HasPhysicalBody)
141 {
142 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody);
143 // Frees both the body and the shape.
144 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody);
145 }
146 }
147
148 public override float GetTerrainHeightAtXYZ(Vector3 pos)
149 {
150 // For the moment use the saved heightmap to get the terrain height.
151 // TODO: raycast downward to find the true terrain below the position.
152 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
153
154 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
155 try
156 {
157 ret = m_savedHeightMap[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, TerrainBase, 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 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
176 // Return 'true' if successfully created.
177 public static bool ConvertHeightmapToMesh(
178 BSScene physicsScene,
179 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
180 float extentX, float extentY, // zero based range for output vertices
181 Vector3 extentBase, // base to be added to all vertices
182 float magnification, // number of vertices to create between heightMap coords
183 out int indicesCountO, out int[] indicesO,
184 out int verticesCountO, out float[] verticesO)
185 {
186 bool ret = false;
187
188 int indicesCount = 0;
189 int verticesCount = 0;
190 int[] indices = new int[0];
191 float[] vertices = new float[0];
192
193 // Simple mesh creation which assumes magnification == 1.
194 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
195
196 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
197 // from zero to <= sizeX). The triangle indices are then generated as two triangles
198 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
199 // column of vertices are used to complete the triangles of the last row and column
200 // of the heightmap.
201 try
202 {
203 // One vertice per heightmap value plus the vertices off the top and bottom edge.
204 int totalVertices = (sizeX + 1) * (sizeY + 1);
205 vertices = new float[totalVertices * 3];
206 int totalIndices = sizeX * sizeY * 6;
207 indices = new int[totalIndices];
208
209 float magX = (float)sizeX / extentX;
210 float magY = (float)sizeY / extentY;
211 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
212 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
213 float minHeight = float.MaxValue;
214 // Note that sizeX+1 vertices are created since there is land between this and the next region.
215 for (int yy = 0; yy <= sizeY; yy++)
216 {
217 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
218 {
219 int offset = yy * sizeX + xx;
220 // Extend the height with the height from the last row or column
221 if (yy == sizeY) offset -= sizeX;
222 if (xx == sizeX) offset -= 1;
223 float height = heightMap[offset];
224 minHeight = Math.Min(minHeight, height);
225 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
226 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
227 vertices[verticesCount + 2] = height + extentBase.Z;
228 verticesCount += 3;
229 }
230 }
231 verticesCount = verticesCount / 3;
232
233 for (int yy = 0; yy < sizeY; yy++)
234 {
235 for (int xx = 0; xx < sizeX; xx++)
236 {
237 int offset = yy * (sizeX + 1) + xx;
238 // Each vertices is presumed to be the upper left corner of a box of two triangles
239 indices[indicesCount + 0] = offset;
240 indices[indicesCount + 1] = offset + 1;
241 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
242 indices[indicesCount + 3] = offset + 1;
243 indices[indicesCount + 4] = offset + sizeX + 2;
244 indices[indicesCount + 5] = offset + sizeX + 1;
245 indicesCount += 6;
246 }
247 }
248
249 ret = true;
250 }
251 catch (Exception e)
252 {
253 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
254 LogHeader, physicsScene.RegionName, extentBase, e);
255 }
256
257 indicesCountO = indicesCount;
258 indicesO = indices;
259 verticesCountO = verticesCount;
260 verticesO = vertices;
261
262 return ret;
263 }
264}
265}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
deleted file mode 100755
index 662dd68..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
+++ /dev/null
@@ -1,263 +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.BulletSPlugin
33{
34// Classes to allow some type checking for the API
35// These hold pointers to allocated objects in the unmanaged space.
36// These classes are subclassed by the various physical implementations of
37// objects. In particular, there is a version for physical instances in
38// unmanaged memory ("unman") and one for in managed memory ("XNA").
39
40// Currently, the instances of these classes are a reference to a
41// physical representation and this has no releationship to other
42// instances. Someday, refarb the usage of these classes so each instance
43// refers to a particular physical instance and this class controls reference
44// counts and such. This should be done along with adding BSShapes.
45
46public class BulletWorld
47{
48 public BulletWorld(uint worldId, BSScene bss)
49 {
50 worldID = worldId;
51 physicsScene = bss;
52 }
53 public uint worldID;
54 // The scene is only in here so very low level routines have a handle to print debug/error messages
55 public BSScene physicsScene;
56}
57
58// An allocated Bullet btRigidBody
59public class BulletBody
60{
61 public BulletBody(uint id)
62 {
63 ID = id;
64 collisionType = CollisionType.Static;
65 }
66 public uint ID;
67 public CollisionType collisionType;
68
69 public virtual void Clear() { }
70 public virtual bool HasPhysicalBody { get { return false; } }
71
72 // Apply the specificed collision mask into the physical world
73 public virtual bool ApplyCollisionMask(BSScene physicsScene)
74 {
75 // Should assert the body has been added to the physical world.
76 // (The collision masks are stored in the collision proxy cache which only exists for
77 // a collision body that is in the world.)
78 return physicsScene.PE.SetCollisionGroupMask(this,
79 BulletSimData.CollisionTypeMasks[collisionType].group,
80 BulletSimData.CollisionTypeMasks[collisionType].mask);
81 }
82
83 // Used for log messages for a unique display of the memory/object allocated to this instance
84 public virtual string AddrString
85 {
86 get { return "unknown"; }
87 }
88
89 public override string ToString()
90 {
91 StringBuilder buff = new StringBuilder();
92 buff.Append("<id=");
93 buff.Append(ID.ToString());
94 buff.Append(",p=");
95 buff.Append(AddrString);
96 buff.Append(",c=");
97 buff.Append(collisionType);
98 buff.Append(">");
99 return buff.ToString();
100 }
101}
102
103public class BulletShape
104{
105 public BulletShape()
106 {
107 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false;
110 }
111 public BSPhysicsShapeType type;
112 public System.UInt64 shapeKey;
113 public bool isNativeShape;
114
115 public virtual void Clear() { }
116 public virtual bool HasPhysicalShape { get { return false; } }
117 // Make another reference to this physical object.
118 public virtual BulletShape Clone() { return new BulletShape(); }
119 // Return 'true' if this and other refer to the same physical object
120 public virtual bool ReferenceSame(BulletShape xx) { return false; }
121
122 // Used for log messages for a unique display of the memory/object allocated to this instance
123 public virtual string AddrString
124 {
125 get { return "unknown"; }
126 }
127
128 public override string ToString()
129 {
130 StringBuilder buff = new StringBuilder();
131 buff.Append("<p=");
132 buff.Append(AddrString);
133 buff.Append(",s=");
134 buff.Append(type.ToString());
135 buff.Append(",k=");
136 buff.Append(shapeKey.ToString("X"));
137 buff.Append(",n=");
138 buff.Append(isNativeShape.ToString());
139 buff.Append(">");
140 return buff.ToString();
141 }
142}
143
144// An allocated Bullet btConstraint
145public class BulletConstraint
146{
147 public BulletConstraint()
148 {
149 }
150 public virtual void Clear() { }
151 public virtual bool HasPhysicalConstraint { get { return false; } }
152
153 // Used for log messages for a unique display of the memory/object allocated to this instance
154 public virtual string AddrString
155 {
156 get { return "unknown"; }
157 }
158}
159
160// An allocated HeightMapThing which holds various heightmap info.
161// Made a class rather than a struct so there would be only one
162// instance of this and C# will pass around pointers rather
163// than making copies.
164public class BulletHMapInfo
165{
166 public BulletHMapInfo(uint id, float[] hm) {
167 ID = id;
168 heightMap = hm;
169 terrainRegionBase = OMV.Vector3.Zero;
170 minCoords = new OMV.Vector3(100f, 100f, 25f);
171 maxCoords = new OMV.Vector3(101f, 101f, 26f);
172 minZ = maxZ = 0f;
173 sizeX = sizeY = 256f;
174 }
175 public uint ID;
176 public float[] heightMap;
177 public OMV.Vector3 terrainRegionBase;
178 public OMV.Vector3 minCoords;
179 public OMV.Vector3 maxCoords;
180 public float sizeX, sizeY;
181 public float minZ, maxZ;
182 public BulletShape terrainShape;
183 public BulletBody terrainBody;
184}
185
186// The general class of collsion object.
187public enum CollisionType
188{
189 Avatar,
190 Groundplane,
191 Terrain,
192 Static,
193 Dynamic,
194 VolumeDetect,
195 // Linkset, // A linkset should be either Static or Dynamic
196 LinksetChild,
197 Unknown
198};
199
200// Hold specification of group and mask collision flags for a CollisionType
201public struct CollisionTypeFilterGroup
202{
203 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
204 {
205 type = t;
206 group = g;
207 mask = m;
208 }
209 public CollisionType type;
210 public uint group;
211 public uint mask;
212};
213
214public static class BulletSimData
215{
216
217// Map of collisionTypes to flags for collision groups and masks.
218// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
219// but, instead, use references to this dictionary. Finding and debugging
220// collision flag problems will be made easier.
221public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
222 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
223{
224 { CollisionType.Avatar,
225 new CollisionTypeFilterGroup(CollisionType.Avatar,
226 (uint)CollisionFilterGroups.BCharacterGroup,
227 (uint)CollisionFilterGroups.BAllGroup)
228 },
229 { CollisionType.Groundplane,
230 new CollisionTypeFilterGroup(CollisionType.Groundplane,
231 (uint)CollisionFilterGroups.BGroundPlaneGroup,
232 (uint)CollisionFilterGroups.BAllGroup)
233 },
234 { CollisionType.Terrain,
235 new CollisionTypeFilterGroup(CollisionType.Terrain,
236 (uint)CollisionFilterGroups.BTerrainGroup,
237 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
238 },
239 { CollisionType.Static,
240 new CollisionTypeFilterGroup(CollisionType.Static,
241 (uint)CollisionFilterGroups.BStaticGroup,
242 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
243 },
244 { CollisionType.Dynamic,
245 new CollisionTypeFilterGroup(CollisionType.Dynamic,
246 (uint)CollisionFilterGroups.BSolidGroup,
247 (uint)(CollisionFilterGroups.BAllGroup))
248 },
249 { CollisionType.VolumeDetect,
250 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
251 (uint)CollisionFilterGroups.BSensorTrigger,
252 (uint)(~CollisionFilterGroups.BSensorTrigger))
253 },
254 { CollisionType.LinksetChild,
255 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
256 (uint)CollisionFilterGroups.BLinksetChildGroup,
257 (uint)(CollisionFilterGroups.BNoneGroup))
258 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
259 },
260};
261
262}
263}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
deleted file mode 100755
index a8a4ff5..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ /dev/null
@@ -1,272 +0,0 @@
1CURRENT PRIORITIES
2=================================================
3Redo BulletSimAPI to allow native C# implementation of Bullet option.
4Avatar movement
5 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle
6 walking up stairs is not calibrated correctly (stairs out of Kepler cabin)
7 avatar capsule rotation completed
8llMoveToTarget
9Enable vehicle border crossings (at least as poorly as ODE)
10 Terrain skirts
11 Avatar created in previous region and not new region when crossing border
12 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
13Vehicle movement on terrain smoothness
14Vehicle script tuning/debugging
15 Avanti speed script
16 Weapon shooter script
17limitMotorUp calibration (more down?)
18Boats float low in the water
19Add material densities to the material types.
20
21CRASHES
22=================================================
2320121129.1411: editting/moving phys object across region boundries causes crash
24 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
2520121128.1600: mesh object not rezzing (no physics mesh).
26 Causes many errors. Doesn't stop after first error with box shape.
27 Eventually crashes when deleting the object.
2820121206.1434: rez Sam-pan into OSGrid BulletSim11 region
29 Immediate simulator crash. Mono does not output any stacktrace and
30 log just stops after reporting taint-time linking of the linkset.
31
32VEHICLES TODO LIST:
33=================================================
34Angular motor direction is global coordinates rather than local coordinates
35Border crossing with linked vehicle causes crash
36Vehicles (Move smoothly)
37Add vehicle collisions so IsColliding is properly reported.
38 Needed for banking, limitMotorUp, movementLimiting, ...
39VehicleAddForce is not scaled by the simulation step but it is only
40 applied for one step. Should it be scaled?
41Some vehicles should not be able to turn if no speed or off ground.
42Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
43Neb car jiggling left and right
44 Happens on terrain and any other mesh object. Flat cubes are much smoother.
45 This has been reduced but not eliminated.
46Implement referenceFrame for all the motion routines.
47Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
48 Verify that angular motion specified around Z moves in the vehicle coordinates.
49Verify llGetVel() is returning a smooth and good value for vehicle movement.
50llGetVel() should return the root's velocity if requested in a child prim.
51Implement function efficiency for lineaar and angular motion.
52After getting off a vehicle, the root prim is phantom (can be walked through)
53 Need to force a position update for the root prim after compound shape destruction
54Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
55For limitMotorUp, use raycast down to find if vehicle is in the air.
56Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
57 A kludge that isn't fixing the real problem of Bullet adding extra motion.
58Incorporate inter-relationship of angular corrections. For instance, angularDeflection
59 and angularMotorUp will compute same X or Y correction. When added together
60 creates over-correction and over-shoot and wabbling.
61
62BULLETSIM TODO LIST:
63=================================================
64Implement an avatar mesh shape. The Bullet capsule is way too limited.
65 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
66Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
67Duplicating a physical prim causes old prim to jump away
68 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
69Scenes with hundred of thousands of static objects take a lot of physics CPU time.
70BSPrim.Force should set a continious force on the prim. The force should be
71 applied each tick. Some limits?
72Gun sending shooter flying.
73Collision margin (gap between physical objects lying on each other)
74Boundry checking (crashes related to crossing boundry)
75 Add check for border edge position for avatars and objects.
76 Verify the events are created for border crossings.
77Avatar rotation (check out changes to ScenePresence for physical rotation)
78Avatar running (what does phys engine need to do?)
79Small physical objects do not interact correctly
80 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
81 The chain will fall apart and pairs will dance around on ground
82 Chains of 1x1x.2 will stay connected but will dance.
83 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
84Add PID motor for avatar movement (slow to stop, ...)
85setForce should set a constant force. Different than AddImpulse.
86Implement raycast.
87Implement ShapeCollection.Dispose()
88Implement water as a plain so raycasting and collisions can happen with same.
89Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
90 Also osGetPhysicsEngineVerion() maybe.
91Linkset.Position and Linkset.Orientation requre rewrite to properly return
92 child position. LinksetConstraint acts like it's at taint time!!
93Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
94Should the different PID factors have non-equal contributions for different
95 values of Efficiency?
96Selecting and deselecting physical objects causes CPU processing time to jump
97 http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1
98 put thousand physical objects, select and deselect same. CPU time will be large.
99Re-implement buoyancy as a separate force on the object rather than diddling gravity.
100 Register a pre-step event to add the force.
101More efficient memory usage when passing hull information from BSPrim to BulletSim
102Avatar movement motor check for zero or small movement. Somehow suppress small movements
103 when avatar has stopped and is just standing. Simple test for near zero has
104 the problem of preventing starting up (increase from zero) especially when falling.
105Physical and phantom will drop through the terrain
106
107
108LINKSETS
109======================================================
110Offset the center of the linkset to be the geometric center of all the prims
111 Not quite the same as the center-of-gravity
112Linksets should allow collisions to individual children
113 Add LocalID to children shapes in LinksetCompound and create events for individuals
114LinksetCompound: when one of the children changes orientation (like tires
115 turning on a vehicle, the whole compound object is rebuilt. Optimize this
116 so orientation/position of individual children can change without a rebuild.
117Verify/think through scripts in children of linksets. What do they reference
118 and return when getting position, velocity, ...
119Confirm constraint linksets still work after making all the changes for compound linksets.
120Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
121 For compound linksets, add ability to remove or reposition individual child shapes.
122Disable activity of passive linkset children.
123 Since the linkset is a compound object, the old prims are left lying
124 around and need to be phantomized so they don't collide, ...
125Speed up creation of large physical linksets
126 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
127 REALLY bad for very large physical linksets (freezes the sim for many seconds).
128Eliminate collisions between objects in a linkset. (LinksetConstraint)
129 Have UserPointer point to struct with localID and linksetID?
130 Objects in original linkset still collide with each other?
131
132MORE
133======================================================
134Test avatar walking up stairs. How does compare with SL.
135 Radius of the capsule affects ability to climb edges.
136Debounce avatar contact so legs don't keep folding up when standing.
137Implement LSL physics controls. Like STATUS_ROTATE_X.
138Add border extensions to terrain to help region crossings and objects leaving region.
139Use a different capsule shape for avatar when sitting
140 LL uses a pyrimidal shape scaled by the avatar's bounding box
141 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
142
143Performance test with lots of avatars. Can BulletSim support a thousand?
144Optimize collisions in C++: only send up to the object subscribed to collisions.
145 Use collision subscription and remove the collsion(A,B) and collision(B,A)
146Check whether SimMotionState needs large if statement (see TODO).
147
148Implement 'top colliders' info.
149Avatar jump
150Performance measurement and changes to make quicker.
151Implement detailed physics stats (GetStats()).
152
153Measure performance improvement from hulls
154Test not using ghost objects for volume detect implementation.
155Performance of closures and delegates for taint processing
156 Are there faster ways?
157 Is any slowdown introduced by the existing implementation significant?
158Is there are more efficient method of implementing pre and post step actions?
159 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
160
161Physics Arena central pyramid: why is one side permiable?
162
163In SL, perfect spheres don't seem to have rolling friction. Add special case.
164Enforce physical parameter min/max:
165 Gravity: [-1, 28]
166 Friction: [0, 255]
167 Density: [1, 22587]
168 Restitution [0, 1]
169 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
170Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
171
172INTERNAL IMPROVEMENT/CLEANUP
173=================================================
174Create the physical wrapper classes (BulletBody, BulletShape) by methods on
175 BSAPITemplate and make their actual implementation Bullet engine specific.
176 For the short term, just call the existing functions in ShapeCollection.
177Consider moving prim/character body and shape destruction in destroy()
178 to postTimeTime rather than protecting all the potential sets that
179 might have been queued up.
180Remove unused fields from ShapeData (not used in API2)
181Remove unused fields from pinned memory shared parameter block
182 Create parameter variables in BSScene to replace same.
183Breakout code for mesh/hull/compound/native into separate BSShape* classes
184 Standardize access to building and reference code.
185 The skeleton classes are in the sources but are not complete or linked in.
186Make BSBody and BSShape real classes to centralize creation/changin/destruction
187 Convert state and parameter calls from BulletSimAPI direct calls to
188 calls on BSBody and BSShape
189Generalize Dynamics and PID with standardized motors.
190Generalize Linkset and vehicles into PropertyManagers
191 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
192 Potentially add events for shape destruction, etc.
193Complete implemention of preStepActions
194 Replace vehicle step call with prestep event.
195 Is there a need for postStepActions? postStepTaints?
196Implement linkset by setting position of children when root updated. (LinksetManual)
197 Linkset implementation using manual prim movement.
198LinkablePrim class? Would that simplify/centralize the linkset logic?
199BSScene.UpdateParameterSet() is broken. How to set params on objects?
200Remove HeightmapInfo from terrain specification
201 Since C++ code does not need terrain height, this structure et al are not needed.
202Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
203 bob at the water level. BSPrim.PositionSanityCheck().
204Should taints check for existance or activeness of target?
205 When destroying linksets/etc, taints can be generated for objects that are
206 actually gone when the taint happens. Crashes don't happen because the taint closure
207 keeps the object from being freed, but that is just an accident.
208 Possibly have and 'active' flag that is checked by the taint processor?
209Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
210Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
211There are TOO MANY interfaces from BulletSim core to Bullet itself
212 Think of something to eliminate one or more of the layers
213
214THREADING
215=================================================
216Do taint action immediately if not actually executing Bullet.
217 Add lock around Bullet execution and just do taint actions if simulation is not happening.
218
219DONE DONE DONE DONE
220=================================================
221Cleanup code in BSDynamics by using motors. (Resolution: started)
222Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
223 Would have better and adjustable resolution.
224Build terrain mesh so heighmap is height of the center of the square meter.
225 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
226Terrain as mesh. (Resolution: done)
227How are static linksets seen by the physics engine?
228 Resolution: they are not linked in physics. When moved, all the children are repositioned.
229Convert BSCharacter to use all API2 (Resolution: done)
230Avatar pushing difficult (too heavy?)
231Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
232Remove old code in DLL (all non-API2 stuff). (Resolution: done)
233Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
234Debug Bullet internal stats output (why is timing all wrong?)
235 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
236Implement meshes or just verify that they work. (Resolution: they do!)
237Do prim hash codes work for sculpties and meshes? (Resolution: yes)
238Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
239 Compound shapes will need the LocalID in the shapes and collision
240 processing to get it from there.
241Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
242Package Bullet source mods for Bullet internal stats output
243 (Resolution: move code into WorldData.h rather than relying on patches)
244Single prim vehicles don't seem to properly vehiclize.
245 (Resolution: mass was not getting set properly for single prim linksets)
246Add material type linkage and input all the material property definitions.
247 Skeleton classes and table are in the sources but are not filled or used.
248 (Resolution:
249Neb vehicle taking > 25ms of physics time!!
250 (Resolution: compound linksets were being rebuild WAY too often)
251Avatar height off after unsitting (floats off ground)
252 Editting appearance then moving restores.
253 Must not be initializing height when recreating capsule after unsit.
254 (Resolution: confusion of scale vs size for native objects removed)
255Light cycle falling over when driving (Resolution: implemented angularMotorUp)
256Should vehicle angular/linear movement friction happen after all the components
257 or does it only apply to the basic movement?
258 (Resolution: friction added before returning newly computed motor value.
259 What is expected by some vehicles (turning up friction to moderate speed))
260Tune terrain/object friction to be closer to SL.
261 (Resolution: added material type with friction and resolution)
262Smooth avatar movement with motor (DONE)
263 Should motor update be all at taint-time? (Yes, DONE)
264 Fix avatar slowly sliding when standing (zero motion when stopped) (DONE)
265 (Resolution: added BSVMotor for avatar starting and stopping)
266llApplyImpulse()
267 Compare mass/movement in OS and SL. Calibrate actions. (DONE)
268 (Resolution: tested on SL and OS. AddForce scales the force for timestep)
269llSetBuoyancy() (DONE)
270 (Resolution: Bullet resets object gravity when added to world. Moved set gravity)
271Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
272 (Resolution: set default density to 3.5 (from 60) which is closer to SL)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
deleted file mode 100644
index 0d1db3b..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,33 +0,0 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.Physics.BulletSPlugin")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("520ea11b-20cb-449d-ba05-c01015fed841")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.5.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs
deleted file mode 100644
index 4d84c44..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/CTri.cs
+++ /dev/null
@@ -1,341 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class Wpoint
34 {
35 public float3 mPoint;
36 public float mWeight;
37
38 public Wpoint(float3 p, float w)
39 {
40 mPoint = p;
41 mWeight = w;
42 }
43 }
44
45 public class CTri
46 {
47 private const int WSCALE = 4;
48
49 public float3 mP1;
50 public float3 mP2;
51 public float3 mP3;
52 public float3 mNear1;
53 public float3 mNear2;
54 public float3 mNear3;
55 public float3 mNormal;
56 public float mPlaneD;
57 public float mConcavity;
58 public float mC1;
59 public float mC2;
60 public float mC3;
61 public int mI1;
62 public int mI2;
63 public int mI3;
64 public int mProcessed; // already been added...
65
66 public CTri(float3 p1, float3 p2, float3 p3, int i1, int i2, int i3)
67 {
68 mProcessed = 0;
69 mI1 = i1;
70 mI2 = i2;
71 mI3 = i3;
72
73 mP1 = new float3(p1);
74 mP2 = new float3(p2);
75 mP3 = new float3(p3);
76
77 mNear1 = new float3();
78 mNear2 = new float3();
79 mNear3 = new float3();
80
81 mNormal = new float3();
82 mPlaneD = mNormal.ComputePlane(mP1, mP2, mP3);
83 }
84
85 public float Facing(CTri t)
86 {
87 return float3.dot(mNormal, t.mNormal);
88 }
89
90 public bool clip(float3 start, ref float3 end)
91 {
92 float3 sect = new float3();
93 bool hit = lineIntersectsTriangle(start, end, mP1, mP2, mP3, ref sect);
94
95 if (hit)
96 end = sect;
97 return hit;
98 }
99
100 public bool Concave(float3 p, ref float distance, ref float3 n)
101 {
102 n.NearestPointInTriangle(p, mP1, mP2, mP3);
103 distance = p.Distance(n);
104 return true;
105 }
106
107 public void addTri(int[] indices, int i1, int i2, int i3, ref int tcount)
108 {
109 indices[tcount * 3 + 0] = i1;
110 indices[tcount * 3 + 1] = i2;
111 indices[tcount * 3 + 2] = i3;
112 tcount++;
113 }
114
115 public float getVolume()
116 {
117 int[] indices = new int[8 * 3];
118
119 int tcount = 0;
120
121 addTri(indices, 0, 1, 2, ref tcount);
122 addTri(indices, 3, 4, 5, ref tcount);
123
124 addTri(indices, 0, 3, 4, ref tcount);
125 addTri(indices, 0, 4, 1, ref tcount);
126
127 addTri(indices, 1, 4, 5, ref tcount);
128 addTri(indices, 1, 5, 2, ref tcount);
129
130 addTri(indices, 0, 3, 5, ref tcount);
131 addTri(indices, 0, 5, 2, ref tcount);
132
133 List<float3> vertices = new List<float3> { mP1, mP2, mP3, mNear1, mNear2, mNear3 };
134 List<int> indexList = new List<int>(indices);
135
136 float v = Concavity.computeMeshVolume(vertices, indexList);
137 return v;
138 }
139
140 public float raySect(float3 p, float3 dir, ref float3 sect)
141 {
142 float4 plane = new float4();
143
144 plane.x = mNormal.x;
145 plane.y = mNormal.y;
146 plane.z = mNormal.z;
147 plane.w = mPlaneD;
148
149 float3 dest = p + dir * 100000f;
150
151 intersect(p, dest, ref sect, plane);
152
153 return sect.Distance(p); // return the intersection distance
154 }
155
156 public float planeDistance(float3 p)
157 {
158 float4 plane = new float4();
159
160 plane.x = mNormal.x;
161 plane.y = mNormal.y;
162 plane.z = mNormal.z;
163 plane.w = mPlaneD;
164
165 return DistToPt(p, plane);
166 }
167
168 public bool samePlane(CTri t)
169 {
170 const float THRESH = 0.001f;
171 float dd = Math.Abs(t.mPlaneD - mPlaneD);
172 if (dd > THRESH)
173 return false;
174 dd = Math.Abs(t.mNormal.x - mNormal.x);
175 if (dd > THRESH)
176 return false;
177 dd = Math.Abs(t.mNormal.y - mNormal.y);
178 if (dd > THRESH)
179 return false;
180 dd = Math.Abs(t.mNormal.z - mNormal.z);
181 if (dd > THRESH)
182 return false;
183 return true;
184 }
185
186 public bool hasIndex(int i)
187 {
188 if (i == mI1 || i == mI2 || i == mI3)
189 return true;
190 return false;
191 }
192
193 public bool sharesEdge(CTri t)
194 {
195 bool ret = false;
196 uint count = 0;
197
198 if (t.hasIndex(mI1))
199 count++;
200 if (t.hasIndex(mI2))
201 count++;
202 if (t.hasIndex(mI3))
203 count++;
204
205 if (count >= 2)
206 ret = true;
207
208 return ret;
209 }
210
211 public float area()
212 {
213 float a = mConcavity * mP1.Area(mP2, mP3);
214 return a;
215 }
216
217 public void addWeighted(List<Wpoint> list)
218 {
219 Wpoint p1 = new Wpoint(mP1, mC1);
220 Wpoint p2 = new Wpoint(mP2, mC2);
221 Wpoint p3 = new Wpoint(mP3, mC3);
222
223 float3 d1 = mNear1 - mP1;
224 float3 d2 = mNear2 - mP2;
225 float3 d3 = mNear3 - mP3;
226
227 d1 *= WSCALE;
228 d2 *= WSCALE;
229 d3 *= WSCALE;
230
231 d1 = d1 + mP1;
232 d2 = d2 + mP2;
233 d3 = d3 + mP3;
234
235 Wpoint p4 = new Wpoint(d1, mC1);
236 Wpoint p5 = new Wpoint(d2, mC2);
237 Wpoint p6 = new Wpoint(d3, mC3);
238
239 list.Add(p1);
240 list.Add(p2);
241 list.Add(p3);
242
243 list.Add(p4);
244 list.Add(p5);
245 list.Add(p6);
246 }
247
248 private static float DistToPt(float3 p, float4 plane)
249 {
250 float x = p.x;
251 float y = p.y;
252 float z = p.z;
253 float d = x*plane.x + y*plane.y + z*plane.z + plane.w;
254 return d;
255 }
256
257 private static void intersect(float3 p1, float3 p2, ref float3 split, float4 plane)
258 {
259 float dp1 = DistToPt(p1, plane);
260
261 float3 dir = new float3();
262 dir.x = p2[0] - p1[0];
263 dir.y = p2[1] - p1[1];
264 dir.z = p2[2] - p1[2];
265
266 float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2];
267 float dot2 = dp1 - plane[3];
268
269 float t = -(plane[3] + dot2) / dot1;
270
271 split.x = (dir[0] * t) + p1[0];
272 split.y = (dir[1] * t) + p1[1];
273 split.z = (dir[2] * t) + p1[2];
274 }
275
276 private static bool rayIntersectsTriangle(float3 p, float3 d, float3 v0, float3 v1, float3 v2, out float t)
277 {
278 t = 0f;
279
280 float3 e1, e2, h, s, q;
281 float a, f, u, v;
282
283 e1 = v1 - v0;
284 e2 = v2 - v0;
285 h = float3.cross(d, e2);
286 a = float3.dot(e1, h);
287
288 if (a > -0.00001f && a < 0.00001f)
289 return false;
290
291 f = 1f / a;
292 s = p - v0;
293 u = f * float3.dot(s, h);
294
295 if (u < 0.0f || u > 1.0f)
296 return false;
297
298 q = float3.cross(s, e1);
299 v = f * float3.dot(d, q);
300 if (v < 0.0f || u + v > 1.0f)
301 return false;
302
303 // at this stage we can compute t to find out where
304 // the intersection point is on the line
305 t = f * float3.dot(e2, q);
306 if (t > 0f) // ray intersection
307 return true;
308 else // this means that there is a line intersection but not a ray intersection
309 return false;
310 }
311
312 private static bool lineIntersectsTriangle(float3 rayStart, float3 rayEnd, float3 p1, float3 p2, float3 p3, ref float3 sect)
313 {
314 float3 dir = rayEnd - rayStart;
315
316 float d = (float)Math.Sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]);
317 float r = 1.0f / d;
318
319 dir *= r;
320
321 float t;
322 bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, out t);
323
324 if (ret)
325 {
326 if (t > d)
327 {
328 sect.x = rayStart.x + dir.x * t;
329 sect.y = rayStart.y + dir.y * t;
330 sect.z = rayStart.z + dir.z * t;
331 }
332 else
333 {
334 ret = false;
335 }
336 }
337
338 return ret;
339 }
340 }
341}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs
deleted file mode 100644
index cc6383a..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Concavity.cs
+++ /dev/null
@@ -1,233 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Text;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public static class Concavity
35 {
36 // compute's how 'concave' this object is and returns the total volume of the
37 // convex hull as well as the volume of the 'concavity' which was found.
38 public static float computeConcavity(List<float3> vertices, List<int> indices, ref float4 plane, ref float volume)
39 {
40 float cret = 0f;
41 volume = 1f;
42
43 HullResult result = new HullResult();
44 HullDesc desc = new HullDesc();
45
46 desc.MaxFaces = 256;
47 desc.MaxVertices = 256;
48 desc.SetHullFlag(HullFlag.QF_TRIANGLES);
49 desc.Vertices = vertices;
50
51 HullError ret = HullUtils.CreateConvexHull(desc, ref result);
52
53 if (ret == HullError.QE_OK)
54 {
55 volume = computeMeshVolume2(result.OutputVertices, result.Indices);
56
57 // ok..now..for each triangle on the original mesh..
58 // we extrude the points to the nearest point on the hull.
59 List<CTri> tris = new List<CTri>();
60
61 for (int i = 0; i < result.Indices.Count / 3; i++)
62 {
63 int i1 = result.Indices[i * 3 + 0];
64 int i2 = result.Indices[i * 3 + 1];
65 int i3 = result.Indices[i * 3 + 2];
66
67 float3 p1 = result.OutputVertices[i1];
68 float3 p2 = result.OutputVertices[i2];
69 float3 p3 = result.OutputVertices[i3];
70
71 CTri t = new CTri(p1, p2, p3, i1, i2, i3);
72 tris.Add(t);
73 }
74
75 // we have not pre-computed the plane equation for each triangle in the convex hull..
76 float totalVolume = 0;
77
78 List<CTri> ftris = new List<CTri>(); // 'feature' triangles.
79 List<CTri> input_mesh = new List<CTri>();
80
81 for (int i = 0; i < indices.Count / 3; i++)
82 {
83 int i1 = indices[i * 3 + 0];
84 int i2 = indices[i * 3 + 1];
85 int i3 = indices[i * 3 + 2];
86
87 float3 p1 = vertices[i1];
88 float3 p2 = vertices[i2];
89 float3 p3 = vertices[i3];
90
91 CTri t = new CTri(p1, p2, p3, i1, i2, i3);
92 input_mesh.Add(t);
93 }
94
95 for (int i = 0; i < indices.Count / 3; i++)
96 {
97 int i1 = indices[i * 3 + 0];
98 int i2 = indices[i * 3 + 1];
99 int i3 = indices[i * 3 + 2];
100
101 float3 p1 = vertices[i1];
102 float3 p2 = vertices[i2];
103 float3 p3 = vertices[i3];
104
105 CTri t = new CTri(p1, p2, p3, i1, i2, i3);
106
107 featureMatch(t, tris, input_mesh);
108
109 if (t.mConcavity > 0.05f)
110 {
111 float v = t.getVolume();
112 totalVolume += v;
113 ftris.Add(t);
114 }
115 }
116
117 SplitPlane.computeSplitPlane(vertices, indices, ref plane);
118 cret = totalVolume;
119 }
120
121 return cret;
122 }
123
124 public static bool featureMatch(CTri m, List<CTri> tris, List<CTri> input_mesh)
125 {
126 bool ret = false;
127 float neardot = 0.707f;
128 m.mConcavity = 0;
129
130 for (int i = 0; i < tris.Count; i++)
131 {
132 CTri t = tris[i];
133
134 if (t.samePlane(m))
135 {
136 ret = false;
137 break;
138 }
139
140 float dot = float3.dot(t.mNormal, m.mNormal);
141
142 if (dot > neardot)
143 {
144 float d1 = t.planeDistance(m.mP1);
145 float d2 = t.planeDistance(m.mP2);
146 float d3 = t.planeDistance(m.mP3);
147
148 if (d1 > 0.001f || d2 > 0.001f || d3 > 0.001f) // can't be near coplaner!
149 {
150 neardot = dot;
151
152 t.raySect(m.mP1, m.mNormal, ref m.mNear1);
153 t.raySect(m.mP2, m.mNormal, ref m.mNear2);
154 t.raySect(m.mP3, m.mNormal, ref m.mNear3);
155
156 ret = true;
157 }
158 }
159 }
160
161 if (ret)
162 {
163 m.mC1 = m.mP1.Distance(m.mNear1);
164 m.mC2 = m.mP2.Distance(m.mNear2);
165 m.mC3 = m.mP3.Distance(m.mNear3);
166
167 m.mConcavity = m.mC1;
168
169 if (m.mC2 > m.mConcavity)
170 m.mConcavity = m.mC2;
171 if (m.mC3 > m.mConcavity)
172 m.mConcavity = m.mC3;
173 }
174
175 return ret;
176 }
177
178 private static float det(float3 p1, float3 p2, float3 p3)
179 {
180 return p1.x * p2.y * p3.z + p2.x * p3.y * p1.z + p3.x * p1.y * p2.z - p1.x * p3.y * p2.z - p2.x * p1.y * p3.z - p3.x * p2.y * p1.z;
181 }
182
183 public static float computeMeshVolume(List<float3> vertices, List<int> indices)
184 {
185 float volume = 0f;
186
187 for (int i = 0; i < indices.Count / 3; i++)
188 {
189 float3 p1 = vertices[indices[i * 3 + 0]];
190 float3 p2 = vertices[indices[i * 3 + 1]];
191 float3 p3 = vertices[indices[i * 3 + 2]];
192
193 volume += det(p1, p2, p3); // compute the volume of the tetrahedran relative to the origin.
194 }
195
196 volume *= (1.0f / 6.0f);
197 if (volume < 0f)
198 return -volume;
199 return volume;
200 }
201
202 public static float computeMeshVolume2(List<float3> vertices, List<int> indices)
203 {
204 float volume = 0f;
205
206 float3 p0 = vertices[0];
207 for (int i = 0; i < indices.Count / 3; i++)
208 {
209 float3 p1 = vertices[indices[i * 3 + 0]];
210 float3 p2 = vertices[indices[i * 3 + 1]];
211 float3 p3 = vertices[indices[i * 3 + 2]];
212
213 volume += tetVolume(p0, p1, p2, p3); // compute the volume of the tetrahedron relative to the root vertice
214 }
215
216 return volume * (1.0f / 6.0f);
217 }
218
219 private static float tetVolume(float3 p0, float3 p1, float3 p2, float3 p3)
220 {
221 float3 a = p1 - p0;
222 float3 b = p2 - p0;
223 float3 c = p3 - p0;
224
225 float3 cross = float3.cross(b, c);
226 float volume = float3.dot(a, cross);
227
228 if (volume < 0f)
229 return -volume;
230 return volume;
231 }
232 }
233}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs
deleted file mode 100644
index dfaede1..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexBuilder.cs
+++ /dev/null
@@ -1,411 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public class DecompDesc
35 {
36 public List<float3> mVertices;
37 public List<int> mIndices;
38
39 // options
40 public uint mDepth; // depth to split, a maximum of 10, generally not over 7.
41 public float mCpercent; // the concavity threshold percentage. 0=20 is reasonable.
42 public float mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable.
43
44 // hull output limits.
45 public uint mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less.
46 public float mSkinWidth; // a skin width to apply to the output hulls.
47
48 public ConvexDecompositionCallback mCallback; // the interface to receive back the results.
49
50 public DecompDesc()
51 {
52 mDepth = 5;
53 mCpercent = 5;
54 mPpercent = 5;
55 mMaxVertices = 32;
56 }
57 }
58
59 public class CHull
60 {
61 public float[] mMin = new float[3];
62 public float[] mMax = new float[3];
63 public float mVolume;
64 public float mDiagonal;
65 public ConvexResult mResult;
66
67 public CHull(ConvexResult result)
68 {
69 mResult = new ConvexResult(result);
70 mVolume = Concavity.computeMeshVolume(result.HullVertices, result.HullIndices);
71
72 mDiagonal = getBoundingRegion(result.HullVertices, mMin, mMax);
73
74 float dx = mMax[0] - mMin[0];
75 float dy = mMax[1] - mMin[1];
76 float dz = mMax[2] - mMin[2];
77
78 dx *= 0.1f; // inflate 1/10th on each edge
79 dy *= 0.1f; // inflate 1/10th on each edge
80 dz *= 0.1f; // inflate 1/10th on each edge
81
82 mMin[0] -= dx;
83 mMin[1] -= dy;
84 mMin[2] -= dz;
85
86 mMax[0] += dx;
87 mMax[1] += dy;
88 mMax[2] += dz;
89 }
90
91 public void Dispose()
92 {
93 mResult = null;
94 }
95
96 public bool overlap(CHull h)
97 {
98 return overlapAABB(mMin, mMax, h.mMin, h.mMax);
99 }
100
101 // returns the d1Giagonal distance
102 private static float getBoundingRegion(List<float3> points, float[] bmin, float[] bmax)
103 {
104 float3 first = points[0];
105
106 bmin[0] = first.x;
107 bmin[1] = first.y;
108 bmin[2] = first.z;
109
110 bmax[0] = first.x;
111 bmax[1] = first.y;
112 bmax[2] = first.z;
113
114 for (int i = 1; i < points.Count; i++)
115 {
116 float3 p = points[i];
117
118 if (p[0] < bmin[0]) bmin[0] = p[0];
119 if (p[1] < bmin[1]) bmin[1] = p[1];
120 if (p[2] < bmin[2]) bmin[2] = p[2];
121
122 if (p[0] > bmax[0]) bmax[0] = p[0];
123 if (p[1] > bmax[1]) bmax[1] = p[1];
124 if (p[2] > bmax[2]) bmax[2] = p[2];
125 }
126
127 float dx = bmax[0] - bmin[0];
128 float dy = bmax[1] - bmin[1];
129 float dz = bmax[2] - bmin[2];
130
131 return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
132 }
133
134 // return true if the two AABB's overlap.
135 private static bool overlapAABB(float[] bmin1, float[] bmax1, float[] bmin2, float[] bmax2)
136 {
137 if (bmax2[0] < bmin1[0]) return false; // if the maximum is less than our minimum on any axis
138 if (bmax2[1] < bmin1[1]) return false;
139 if (bmax2[2] < bmin1[2]) return false;
140
141 if (bmin2[0] > bmax1[0]) return false; // if the minimum is greater than our maximum on any axis
142 if (bmin2[1] > bmax1[1]) return false; // if the minimum is greater than our maximum on any axis
143 if (bmin2[2] > bmax1[2]) return false; // if the minimum is greater than our maximum on any axis
144
145 return true; // the extents overlap
146 }
147 }
148
149 public class ConvexBuilder
150 {
151 public List<CHull> mChulls = new List<CHull>();
152 private ConvexDecompositionCallback mCallback;
153
154 private int MAXDEPTH = 8;
155 private float CONCAVE_PERCENT = 1f;
156 private float MERGE_PERCENT = 2f;
157
158 public ConvexBuilder(ConvexDecompositionCallback callback)
159 {
160 mCallback = callback;
161 }
162
163 public void Dispose()
164 {
165 int i;
166 for (i = 0; i < mChulls.Count; i++)
167 {
168 CHull cr = mChulls[i];
169 cr.Dispose();
170 }
171 }
172
173 public bool isDuplicate(uint i1, uint i2, uint i3, uint ci1, uint ci2, uint ci3)
174 {
175 uint dcount = 0;
176
177 Debug.Assert(i1 != i2 && i1 != i3 && i2 != i3);
178 Debug.Assert(ci1 != ci2 && ci1 != ci3 && ci2 != ci3);
179
180 if (i1 == ci1 || i1 == ci2 || i1 == ci3)
181 dcount++;
182 if (i2 == ci1 || i2 == ci2 || i2 == ci3)
183 dcount++;
184 if (i3 == ci1 || i3 == ci2 || i3 == ci3)
185 dcount++;
186
187 return dcount == 3;
188 }
189
190 public void getMesh(ConvexResult cr, VertexPool vc, List<int> indices)
191 {
192 List<int> src = cr.HullIndices;
193
194 for (int i = 0; i < src.Count / 3; i++)
195 {
196 int i1 = src[i * 3 + 0];
197 int i2 = src[i * 3 + 1];
198 int i3 = src[i * 3 + 2];
199
200 float3 p1 = cr.HullVertices[i1];
201 float3 p2 = cr.HullVertices[i2];
202 float3 p3 = cr.HullVertices[i3];
203
204 i1 = vc.getIndex(p1);
205 i2 = vc.getIndex(p2);
206 i3 = vc.getIndex(p3);
207 }
208 }
209
210 public CHull canMerge(CHull a, CHull b)
211 {
212 if (!a.overlap(b)) // if their AABB's (with a little slop) don't overlap, then return.
213 return null;
214
215 CHull ret = null;
216
217 // ok..we are going to combine both meshes into a single mesh
218 // and then we are going to compute the concavity...
219
220 VertexPool vc = new VertexPool();
221
222 List<int> indices = new List<int>();
223
224 getMesh(a.mResult, vc, indices);
225 getMesh(b.mResult, vc, indices);
226
227 int vcount = vc.GetSize();
228 List<float3> vertices = vc.GetVertices();
229 int tcount = indices.Count / 3;
230
231 //don't do anything if hull is empty
232 if (tcount == 0)
233 {
234 vc.Clear();
235 return null;
236 }
237
238 HullResult hresult = new HullResult();
239 HullDesc desc = new HullDesc();
240
241 desc.SetHullFlag(HullFlag.QF_TRIANGLES);
242 desc.Vertices = vertices;
243
244 HullError hret = HullUtils.CreateConvexHull(desc, ref hresult);
245
246 if (hret == HullError.QE_OK)
247 {
248 float combineVolume = Concavity.computeMeshVolume(hresult.OutputVertices, hresult.Indices);
249 float sumVolume = a.mVolume + b.mVolume;
250
251 float percent = (sumVolume * 100) / combineVolume;
252 if (percent >= (100.0f - MERGE_PERCENT))
253 {
254 ConvexResult cr = new ConvexResult(hresult.OutputVertices, hresult.Indices);
255 ret = new CHull(cr);
256 }
257 }
258
259 vc.Clear();
260 return ret;
261 }
262
263 public bool combineHulls()
264 {
265 bool combine = false;
266
267 sortChulls(mChulls); // sort the convex hulls, largest volume to least...
268
269 List<CHull> output = new List<CHull>(); // the output hulls...
270
271 int i;
272 for (i = 0; i < mChulls.Count && !combine; ++i)
273 {
274 CHull cr = mChulls[i];
275
276 int j;
277 for (j = 0; j < mChulls.Count; j++)
278 {
279 CHull match = mChulls[j];
280
281 if (cr != match) // don't try to merge a hull with itself, that be stoopid
282 {
283
284 CHull merge = canMerge(cr, match); // if we can merge these two....
285
286 if (merge != null)
287 {
288 output.Add(merge);
289
290 ++i;
291 while (i != mChulls.Count)
292 {
293 CHull cr2 = mChulls[i];
294 if (cr2 != match)
295 {
296 output.Add(cr2);
297 }
298 i++;
299 }
300
301 cr.Dispose();
302 match.Dispose();
303 combine = true;
304 break;
305 }
306 }
307 }
308
309 if (combine)
310 {
311 break;
312 }
313 else
314 {
315 output.Add(cr);
316 }
317 }
318
319 if (combine)
320 {
321 mChulls.Clear();
322 mChulls = output;
323 output.Clear();
324 }
325
326 return combine;
327 }
328
329 public int process(DecompDesc desc)
330 {
331 int ret = 0;
332
333 MAXDEPTH = (int)desc.mDepth;
334 CONCAVE_PERCENT = desc.mCpercent;
335 MERGE_PERCENT = desc.mPpercent;
336
337 ConvexDecomposition.calcConvexDecomposition(desc.mVertices, desc.mIndices, ConvexDecompResult, 0f, 0, MAXDEPTH, CONCAVE_PERCENT, MERGE_PERCENT);
338
339 while (combineHulls()) // keep combinging hulls until I can't combine any more...
340 ;
341
342 int i;
343 for (i = 0; i < mChulls.Count; i++)
344 {
345 CHull cr = mChulls[i];
346
347 // before we hand it back to the application, we need to regenerate the hull based on the
348 // limits given by the user.
349
350 ConvexResult c = cr.mResult; // the high resolution hull...
351
352 HullResult result = new HullResult();
353 HullDesc hdesc = new HullDesc();
354
355 hdesc.SetHullFlag(HullFlag.QF_TRIANGLES);
356
357 hdesc.Vertices = c.HullVertices;
358 hdesc.MaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output
359
360 if (desc.mSkinWidth != 0f)
361 {
362 hdesc.SkinWidth = desc.mSkinWidth;
363 hdesc.SetHullFlag(HullFlag.QF_SKIN_WIDTH); // do skin width computation.
364 }
365
366 HullError ret2 = HullUtils.CreateConvexHull(hdesc, ref result);
367
368 if (ret2 == HullError.QE_OK)
369 {
370 ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices);
371
372 r.mHullVolume = Concavity.computeMeshVolume(result.OutputVertices, result.Indices); // the volume of the hull.
373
374 // compute the best fit OBB
375 //computeBestFitOBB(result.mNumOutputVertices, result.mOutputVertices, sizeof(float) * 3, r.mOBBSides, r.mOBBTransform);
376
377 //r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] * r.mOBBSides[2]; // compute the OBB volume.
378
379 //fm_getTranslation(r.mOBBTransform, r.mOBBCenter); // get the translation component of the 4x4 matrix.
380
381 //fm_matrixToQuat(r.mOBBTransform, r.mOBBOrientation); // extract the orientation as a quaternion.
382
383 //r.mSphereRadius = computeBoundingSphere(result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter);
384 //r.mSphereVolume = fm_sphereVolume(r.mSphereRadius);
385
386 mCallback(r);
387 }
388
389 result = null;
390 cr.Dispose();
391 }
392
393 ret = mChulls.Count;
394
395 mChulls.Clear();
396
397 return ret;
398 }
399
400 public void ConvexDecompResult(ConvexResult result)
401 {
402 CHull ch = new CHull(result);
403 mChulls.Add(ch);
404 }
405
406 public void sortChulls(List<CHull> hulls)
407 {
408 hulls.Sort(delegate(CHull a, CHull b) { return a.mVolume.CompareTo(b.mVolume); });
409 }
410 }
411}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs
deleted file mode 100644
index 2e2bb70..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexDecomposition.cs
+++ /dev/null
@@ -1,200 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public delegate void ConvexDecompositionCallback(ConvexResult result);
35
36 public class FaceTri
37 {
38 public float3 P1;
39 public float3 P2;
40 public float3 P3;
41
42 public FaceTri() { }
43
44 public FaceTri(List<float3> vertices, int i1, int i2, int i3)
45 {
46 P1 = new float3(vertices[i1]);
47 P2 = new float3(vertices[i2]);
48 P3 = new float3(vertices[i3]);
49 }
50 }
51
52 public static class ConvexDecomposition
53 {
54 private static void addTri(VertexPool vl, List<int> list, float3 p1, float3 p2, float3 p3)
55 {
56 int i1 = vl.getIndex(p1);
57 int i2 = vl.getIndex(p2);
58 int i3 = vl.getIndex(p3);
59
60 // do *not* process degenerate triangles!
61 if ( i1 != i2 && i1 != i3 && i2 != i3 )
62 {
63 list.Add(i1);
64 list.Add(i2);
65 list.Add(i3);
66 }
67 }
68
69 public static void calcConvexDecomposition(List<float3> vertices, List<int> indices, ConvexDecompositionCallback callback, float masterVolume, int depth,
70 int maxDepth, float concavePercent, float mergePercent)
71 {
72 float4 plane = new float4();
73 bool split = false;
74
75 if (depth < maxDepth)
76 {
77 float volume = 0f;
78 float c = Concavity.computeConcavity(vertices, indices, ref plane, ref volume);
79
80 if (depth == 0)
81 {
82 masterVolume = volume;
83 }
84
85 float percent = (c * 100.0f) / masterVolume;
86
87 if (percent > concavePercent) // if great than 5% of the total volume is concave, go ahead and keep splitting.
88 {
89 split = true;
90 }
91 }
92
93 if (depth >= maxDepth || !split)
94 {
95 HullResult result = new HullResult();
96 HullDesc desc = new HullDesc();
97
98 desc.SetHullFlag(HullFlag.QF_TRIANGLES);
99
100 desc.Vertices = vertices;
101
102 HullError ret = HullUtils.CreateConvexHull(desc, ref result);
103
104 if (ret == HullError.QE_OK)
105 {
106 ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices);
107 callback(r);
108 }
109
110 return;
111 }
112
113 List<int> ifront = new List<int>();
114 List<int> iback = new List<int>();
115
116 VertexPool vfront = new VertexPool();
117 VertexPool vback = new VertexPool();
118
119 // ok..now we are going to 'split' all of the input triangles against this plane!
120 for (int i = 0; i < indices.Count / 3; i++)
121 {
122 int i1 = indices[i * 3 + 0];
123 int i2 = indices[i * 3 + 1];
124 int i3 = indices[i * 3 + 2];
125
126 FaceTri t = new FaceTri(vertices, i1, i2, i3);
127
128 float3[] front = new float3[4];
129 float3[] back = new float3[4];
130
131 int fcount = 0;
132 int bcount = 0;
133
134 PlaneTriResult result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount);
135
136 if (fcount > 4 || bcount > 4)
137 {
138 result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount);
139 }
140
141 switch (result)
142 {
143 case PlaneTriResult.PTR_FRONT:
144 Debug.Assert(fcount == 3);
145 addTri(vfront, ifront, front[0], front[1], front[2]);
146 break;
147 case PlaneTriResult.PTR_BACK:
148 Debug.Assert(bcount == 3);
149 addTri(vback, iback, back[0], back[1], back[2]);
150 break;
151 case PlaneTriResult.PTR_SPLIT:
152 Debug.Assert(fcount >= 3 && fcount <= 4);
153 Debug.Assert(bcount >= 3 && bcount <= 4);
154
155 addTri(vfront, ifront, front[0], front[1], front[2]);
156 addTri(vback, iback, back[0], back[1], back[2]);
157
158 if (fcount == 4)
159 {
160 addTri(vfront, ifront, front[0], front[2], front[3]);
161 }
162
163 if (bcount == 4)
164 {
165 addTri(vback, iback, back[0], back[2], back[3]);
166 }
167
168 break;
169 }
170 }
171
172 // ok... here we recursively call
173 if (ifront.Count > 0)
174 {
175 int vcount = vfront.GetSize();
176 List<float3> vertices2 = vfront.GetVertices();
177 for (int i = 0; i < vertices2.Count; i++)
178 vertices2[i] = new float3(vertices2[i]);
179 int tcount = ifront.Count / 3;
180
181 calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent);
182 }
183
184 ifront.Clear();
185 vfront.Clear();
186
187 if (iback.Count > 0)
188 {
189 int vcount = vback.GetSize();
190 List<float3> vertices2 = vback.GetVertices();
191 int tcount = iback.Count / 3;
192
193 calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent);
194 }
195
196 iback.Clear();
197 vback.Clear();
198 }
199 }
200}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs
deleted file mode 100644
index 87758b5..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/ConvexResult.cs
+++ /dev/null
@@ -1,74 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class ConvexResult
34 {
35 public List<float3> HullVertices;
36 public List<int> HullIndices;
37
38 public float mHullVolume; // the volume of the convex hull.
39
40 //public float[] OBBSides = new float[3]; // the width, height and breadth of the best fit OBB
41 //public float[] OBBCenter = new float[3]; // the center of the OBB
42 //public float[] OBBOrientation = new float[4]; // the quaternion rotation of the OBB.
43 //public float[] OBBTransform = new float[16]; // the 4x4 transform of the OBB.
44 //public float OBBVolume; // the volume of the OBB
45
46 //public float SphereRadius; // radius and center of best fit sphere
47 //public float[] SphereCenter = new float[3];
48 //public float SphereVolume; // volume of the best fit sphere
49
50 public ConvexResult()
51 {
52 HullVertices = new List<float3>();
53 HullIndices = new List<int>();
54 }
55
56 public ConvexResult(List<float3> hvertices, List<int> hindices)
57 {
58 HullVertices = hvertices;
59 HullIndices = hindices;
60 }
61
62 public ConvexResult(ConvexResult r)
63 {
64 HullVertices = new List<float3>(r.HullVertices);
65 HullIndices = new List<int>(r.HullIndices);
66 }
67
68 public void Dispose()
69 {
70 HullVertices = null;
71 HullIndices = null;
72 }
73 }
74}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs
deleted file mode 100644
index d81df26..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullClasses.cs
+++ /dev/null
@@ -1,171 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class HullResult
34 {
35 public bool Polygons = true; // true if indices represents polygons, false indices are triangles
36 public List<float3> OutputVertices = new List<float3>();
37 public List<int> Indices;
38
39 // If triangles, then indices are array indexes into the vertex list.
40 // If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc..
41 }
42
43 public class PHullResult
44 {
45 public List<float3> Vertices = new List<float3>();
46 public List<int> Indices = new List<int>();
47 }
48
49 [Flags]
50 public enum HullFlag : int
51 {
52 QF_DEFAULT = 0,
53 QF_TRIANGLES = (1 << 0), // report results as triangles, not polygons.
54 QF_SKIN_WIDTH = (1 << 2) // extrude hull based on this skin width
55 }
56
57 public enum HullError : int
58 {
59 QE_OK, // success!
60 QE_FAIL // failed.
61 }
62
63 public class HullDesc
64 {
65 public HullFlag Flags; // flags to use when generating the convex hull.
66 public List<float3> Vertices;
67 public float NormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on.
68 public float SkinWidth;
69 public uint MaxVertices; // maximum number of vertices to be considered for the hull!
70 public uint MaxFaces;
71
72 public HullDesc()
73 {
74 Flags = HullFlag.QF_DEFAULT;
75 Vertices = new List<float3>();
76 NormalEpsilon = 0.001f;
77 MaxVertices = 4096;
78 MaxFaces = 4096;
79 SkinWidth = 0.01f;
80 }
81
82 public HullDesc(HullFlag flags, List<float3> vertices)
83 {
84 Flags = flags;
85 Vertices = new List<float3>(vertices);
86 NormalEpsilon = 0.001f;
87 MaxVertices = 4096;
88 MaxFaces = 4096;
89 SkinWidth = 0.01f;
90 }
91
92 public bool HasHullFlag(HullFlag flag)
93 {
94 return (Flags & flag) != 0;
95 }
96
97 public void SetHullFlag(HullFlag flag)
98 {
99 Flags |= flag;
100 }
101
102 public void ClearHullFlag(HullFlag flag)
103 {
104 Flags &= ~flag;
105 }
106 }
107
108 public class ConvexH
109 {
110 public struct HalfEdge
111 {
112 public short ea; // the other half of the edge (index into edges list)
113 public byte v; // the vertex at the start of this edge (index into vertices list)
114 public byte p; // the facet on which this edge lies (index into facets list)
115
116 public HalfEdge(short _ea, byte _v, byte _p)
117 {
118 ea = _ea;
119 v = _v;
120 p = _p;
121 }
122
123 public HalfEdge(HalfEdge e)
124 {
125 ea = e.ea;
126 v = e.v;
127 p = e.p;
128 }
129 }
130
131 public List<float3> vertices = new List<float3>();
132 public List<HalfEdge> edges = new List<HalfEdge>();
133 public List<Plane> facets = new List<Plane>();
134
135 public ConvexH(int vertices_size, int edges_size, int facets_size)
136 {
137 vertices = new List<float3>(vertices_size);
138 edges = new List<HalfEdge>(edges_size);
139 facets = new List<Plane>(facets_size);
140 }
141 }
142
143 public class VertFlag
144 {
145 public byte planetest;
146 public byte junk;
147 public byte undermap;
148 public byte overmap;
149 }
150
151 public class EdgeFlag
152 {
153 public byte planetest;
154 public byte fixes;
155 public short undermap;
156 public short overmap;
157 }
158
159 public class PlaneFlag
160 {
161 public byte undermap;
162 public byte overmap;
163 }
164
165 public class Coplanar
166 {
167 public ushort ea;
168 public byte v0;
169 public byte v1;
170 }
171}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs
deleted file mode 100644
index 1119a75..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullTriangle.cs
+++ /dev/null
@@ -1,99 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public class HullTriangle : int3
35 {
36 public int3 n = new int3();
37 public int id;
38 public int vmax;
39 public float rise;
40 private List<HullTriangle> tris;
41
42 public HullTriangle(int a, int b, int c, List<HullTriangle> tris)
43 : base(a, b, c)
44 {
45 this.tris = tris;
46
47 n = new int3(-1, -1, -1);
48 id = tris.Count;
49 tris.Add(this);
50 vmax = -1;
51 rise = 0.0f;
52 }
53
54 public void Dispose()
55 {
56 Debug.Assert(tris[id] == this);
57 tris[id] = null;
58 }
59
60 public int neib(int a, int b)
61 {
62 int i;
63
64 for (i = 0; i < 3; i++)
65 {
66 int i1 = (i + 1) % 3;
67 int i2 = (i + 2) % 3;
68 if ((this)[i] == a && (this)[i1] == b)
69 return n[i2];
70 if ((this)[i] == b && (this)[i1] == a)
71 return n[i2];
72 }
73
74 Debug.Assert(false);
75 return -1;
76 }
77
78 public void setneib(int a, int b, int value)
79 {
80 int i;
81
82 for (i = 0; i < 3; i++)
83 {
84 int i1 = (i + 1) % 3;
85 int i2 = (i + 2) % 3;
86 if ((this)[i] == a && (this)[i1] == b)
87 {
88 n[i2] = value;
89 return;
90 }
91 if ((this)[i] == b && (this)[i1] == a)
92 {
93 n[i2] = value;
94 return;
95 }
96 }
97 }
98 }
99}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs
deleted file mode 100644
index c9ccfe2..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/HullUtils.cs
+++ /dev/null
@@ -1,1868 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public static class HullUtils
35 {
36 public static int argmin(float[] a, int n)
37 {
38 int r = 0;
39 for (int i = 1; i < n; i++)
40 {
41 if (a[i] < a[r])
42 {
43 r = i;
44 }
45 }
46 return r;
47 }
48
49 public static float clampf(float a)
50 {
51 return Math.Min(1.0f, Math.Max(0.0f, a));
52 }
53
54 public static float Round(float a, float precision)
55 {
56 return (float)Math.Floor(0.5f + a / precision) * precision;
57 }
58
59 public static float Interpolate(float f0, float f1, float alpha)
60 {
61 return f0 * (1 - alpha) + f1 * alpha;
62 }
63
64 public static void Swap<T>(ref T a, ref T b)
65 {
66 T tmp = a;
67 a = b;
68 b = tmp;
69 }
70
71 public static bool above(List<float3> vertices, int3 t, float3 p, float epsilon)
72 {
73 float3 vtx = vertices[t.x];
74 float3 n = TriNormal(vtx, vertices[t.y], vertices[t.z]);
75 return (float3.dot(n, p - vtx) > epsilon); // EPSILON???
76 }
77
78 public static int hasedge(int3 t, int a, int b)
79 {
80 for (int i = 0; i < 3; i++)
81 {
82 int i1 = (i + 1) % 3;
83 if (t[i] == a && t[i1] == b)
84 return 1;
85 }
86 return 0;
87 }
88
89 public static bool hasvert(int3 t, int v)
90 {
91 return (t[0] == v || t[1] == v || t[2] == v);
92 }
93
94 public static int shareedge(int3 a, int3 b)
95 {
96 int i;
97 for (i = 0; i < 3; i++)
98 {
99 int i1 = (i + 1) % 3;
100 if (hasedge(a, b[i1], b[i]) != 0)
101 return 1;
102 }
103 return 0;
104 }
105
106 public static void b2bfix(HullTriangle s, HullTriangle t, List<HullTriangle> tris)
107 {
108 int i;
109 for (i = 0; i < 3; i++)
110 {
111 int i1 = (i + 1) % 3;
112 int i2 = (i + 2) % 3;
113 int a = (s)[i1];
114 int b = (s)[i2];
115 Debug.Assert(tris[s.neib(a, b)].neib(b, a) == s.id);
116 Debug.Assert(tris[t.neib(a, b)].neib(b, a) == t.id);
117 tris[s.neib(a, b)].setneib(b, a, t.neib(b, a));
118 tris[t.neib(b, a)].setneib(a, b, s.neib(a, b));
119 }
120 }
121
122 public static void removeb2b(HullTriangle s, HullTriangle t, List<HullTriangle> tris)
123 {
124 b2bfix(s, t, tris);
125 s.Dispose();
126 t.Dispose();
127 }
128
129 public static void checkit(HullTriangle t, List<HullTriangle> tris)
130 {
131 int i;
132 Debug.Assert(tris[t.id] == t);
133 for (i = 0; i < 3; i++)
134 {
135 int i1 = (i + 1) % 3;
136 int i2 = (i + 2) % 3;
137 int a = (t)[i1];
138 int b = (t)[i2];
139 Debug.Assert(a != b);
140 Debug.Assert(tris[t.n[i]].neib(b, a) == t.id);
141 }
142 }
143
144 public static void extrude(HullTriangle t0, int v, List<HullTriangle> tris)
145 {
146 int3 t = t0;
147 int n = tris.Count;
148 HullTriangle ta = new HullTriangle(v, t[1], t[2], tris);
149 ta.n = new int3(t0.n[0], n + 1, n + 2);
150 tris[t0.n[0]].setneib(t[1], t[2], n + 0);
151 HullTriangle tb = new HullTriangle(v, t[2], t[0], tris);
152 tb.n = new int3(t0.n[1], n + 2, n + 0);
153 tris[t0.n[1]].setneib(t[2], t[0], n + 1);
154 HullTriangle tc = new HullTriangle(v, t[0], t[1], tris);
155 tc.n = new int3(t0.n[2], n + 0, n + 1);
156 tris[t0.n[2]].setneib(t[0], t[1], n + 2);
157 checkit(ta, tris);
158 checkit(tb, tris);
159 checkit(tc, tris);
160 if (hasvert(tris[ta.n[0]], v))
161 removeb2b(ta, tris[ta.n[0]], tris);
162 if (hasvert(tris[tb.n[0]], v))
163 removeb2b(tb, tris[tb.n[0]], tris);
164 if (hasvert(tris[tc.n[0]], v))
165 removeb2b(tc, tris[tc.n[0]], tris);
166 t0.Dispose();
167 }
168
169 public static HullTriangle extrudable(float epsilon, List<HullTriangle> tris)
170 {
171 int i;
172 HullTriangle t = null;
173 for (i = 0; i < tris.Count; i++)
174 {
175 if (t == null || (tris.Count > i && (object)tris[i] != null && t.rise < tris[i].rise))
176 {
177 t = tris[i];
178 }
179 }
180 return (t.rise > epsilon) ? t : null;
181 }
182
183 public static Quaternion RotationArc(float3 v0, float3 v1)
184 {
185 Quaternion q = new Quaternion();
186 v0 = float3.normalize(v0); // Comment these two lines out if you know its not needed.
187 v1 = float3.normalize(v1); // If vector is already unit length then why do it again?
188 float3 c = float3.cross(v0, v1);
189 float d = float3.dot(v0, v1);
190 if (d <= -1.0f) // 180 about x axis
191 {
192 return new Quaternion(1f, 0f, 0f, 0f);
193 }
194 float s = (float)Math.Sqrt((1 + d) * 2f);
195 q.x = c.x / s;
196 q.y = c.y / s;
197 q.z = c.z / s;
198 q.w = s / 2.0f;
199 return q;
200 }
201
202 public static float3 PlaneLineIntersection(Plane plane, float3 p0, float3 p1)
203 {
204 // returns the point where the line p0-p1 intersects the plane n&d
205 float3 dif = p1 - p0;
206 float dn = float3.dot(plane.normal, dif);
207 float t = -(plane.dist + float3.dot(plane.normal, p0)) / dn;
208 return p0 + (dif * t);
209 }
210
211 public static float3 LineProject(float3 p0, float3 p1, float3 a)
212 {
213 float3 w = new float3();
214 w = p1 - p0;
215 float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z);
216 return p0 + w * t;
217 }
218
219 public static float3 PlaneProject(Plane plane, float3 point)
220 {
221 return point - plane.normal * (float3.dot(point, plane.normal) + plane.dist);
222 }
223
224 public static float LineProjectTime(float3 p0, float3 p1, float3 a)
225 {
226 float3 w = new float3();
227 w = p1 - p0;
228 float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z);
229 return t;
230 }
231
232 public static float3 ThreePlaneIntersection(Plane p0, Plane p1, Plane p2)
233 {
234 float3x3 mp = float3x3.Transpose(new float3x3(p0.normal, p1.normal, p2.normal));
235 float3x3 mi = float3x3.Inverse(mp);
236 float3 b = new float3(p0.dist, p1.dist, p2.dist);
237 return -b * mi;
238 }
239
240 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1)
241 {
242 float3 impact = new float3();
243 float3 normal = new float3();
244 return PolyHit(vert, v0, v1, out impact, out normal);
245 }
246
247 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact)
248 {
249 float3 normal = new float3();
250 return PolyHit(vert, v0, v1, out impact, out normal);
251 }
252
253 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact, out float3 normal)
254 {
255 float3 the_point = new float3();
256
257 impact = null;
258 normal = null;
259
260 int i;
261 float3 nrml = new float3(0, 0, 0);
262 for (i = 0; i < vert.Count; i++)
263 {
264 int i1 = (i + 1) % vert.Count;
265 int i2 = (i + 2) % vert.Count;
266 nrml = nrml + float3.cross(vert[i1] - vert[i], vert[i2] - vert[i1]);
267 }
268
269 float m = float3.magnitude(nrml);
270 if (m == 0.0)
271 {
272 return false;
273 }
274 nrml = nrml * (1.0f / m);
275 float dist = -float3.dot(nrml, vert[0]);
276 float d0;
277 float d1;
278 if ((d0 = float3.dot(v0, nrml) + dist) < 0 || (d1 = float3.dot(v1, nrml) + dist) > 0)
279 {
280 return false;
281 }
282
283 // By using the cached plane distances d0 and d1
284 // we can optimize the following:
285 // the_point = planelineintersection(nrml,dist,v0,v1);
286 float a = d0 / (d0 - d1);
287 the_point = v0 * (1 - a) + v1 * a;
288
289
290 bool inside = true;
291 for (int j = 0; inside && j < vert.Count; j++)
292 {
293 // let inside = 0 if outside
294 float3 pp1 = new float3();
295 float3 pp2 = new float3();
296 float3 side = new float3();
297 pp1 = vert[j];
298 pp2 = vert[(j + 1) % vert.Count];
299 side = float3.cross((pp2 - pp1), (the_point - pp1));
300 inside = (float3.dot(nrml, side) >= 0.0);
301 }
302 if (inside)
303 {
304 if (normal != null)
305 {
306 normal = nrml;
307 }
308 if (impact != null)
309 {
310 impact = the_point;
311 }
312 }
313 return inside;
314 }
315
316 public static bool BoxInside(float3 p, float3 bmin, float3 bmax)
317 {
318 return (p.x >= bmin.x && p.x <= bmax.x && p.y >= bmin.y && p.y <= bmax.y && p.z >= bmin.z && p.z <= bmax.z);
319 }
320
321 public static bool BoxIntersect(float3 v0, float3 v1, float3 bmin, float3 bmax, float3 impact)
322 {
323 if (BoxInside(v0, bmin, bmax))
324 {
325 impact = v0;
326 return true;
327 }
328 if (v0.x <= bmin.x && v1.x >= bmin.x)
329 {
330 float a = (bmin.x - v0.x) / (v1.x - v0.x);
331 //v.x = bmin.x;
332 float vy = (1 - a) * v0.y + a * v1.y;
333 float vz = (1 - a) * v0.z + a * v1.z;
334 if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
335 {
336 impact.x = bmin.x;
337 impact.y = vy;
338 impact.z = vz;
339 return true;
340 }
341 }
342 else if (v0.x >= bmax.x && v1.x <= bmax.x)
343 {
344 float a = (bmax.x - v0.x) / (v1.x - v0.x);
345 //v.x = bmax.x;
346 float vy = (1 - a) * v0.y + a * v1.y;
347 float vz = (1 - a) * v0.z + a * v1.z;
348 if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
349 {
350 impact.x = bmax.x;
351 impact.y = vy;
352 impact.z = vz;
353 return true;
354 }
355 }
356 if (v0.y <= bmin.y && v1.y >= bmin.y)
357 {
358 float a = (bmin.y - v0.y) / (v1.y - v0.y);
359 float vx = (1 - a) * v0.x + a * v1.x;
360 //v.y = bmin.y;
361 float vz = (1 - a) * v0.z + a * v1.z;
362 if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
363 {
364 impact.x = vx;
365 impact.y = bmin.y;
366 impact.z = vz;
367 return true;
368 }
369 }
370 else if (v0.y >= bmax.y && v1.y <= bmax.y)
371 {
372 float a = (bmax.y - v0.y) / (v1.y - v0.y);
373 float vx = (1 - a) * v0.x + a * v1.x;
374 // vy = bmax.y;
375 float vz = (1 - a) * v0.z + a * v1.z;
376 if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
377 {
378 impact.x = vx;
379 impact.y = bmax.y;
380 impact.z = vz;
381 return true;
382 }
383 }
384 if (v0.z <= bmin.z && v1.z >= bmin.z)
385 {
386 float a = (bmin.z - v0.z) / (v1.z - v0.z);
387 float vx = (1 - a) * v0.x + a * v1.x;
388 float vy = (1 - a) * v0.y + a * v1.y;
389 // v.z = bmin.z;
390 if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
391 {
392 impact.x = vx;
393 impact.y = vy;
394 impact.z = bmin.z;
395 return true;
396 }
397 }
398 else if (v0.z >= bmax.z && v1.z <= bmax.z)
399 {
400 float a = (bmax.z - v0.z) / (v1.z - v0.z);
401 float vx = (1 - a) * v0.x + a * v1.x;
402 float vy = (1 - a) * v0.y + a * v1.y;
403 // v.z = bmax.z;
404 if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
405 {
406 impact.x = vx;
407 impact.y = vy;
408 impact.z = bmax.z;
409 return true;
410 }
411 }
412 return false;
413 }
414
415 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint)
416 {
417 return DistanceBetweenLines(ustart, udir, vstart, vdir, upoint, null);
418 }
419
420 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir)
421 {
422 return DistanceBetweenLines(ustart, udir, vstart, vdir, null, null);
423 }
424
425 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint, float3 vpoint)
426 {
427 float3 cp = float3.normalize(float3.cross(udir, vdir));
428
429 float distu = -float3.dot(cp, ustart);
430 float distv = -float3.dot(cp, vstart);
431 float dist = (float)Math.Abs(distu - distv);
432 if (upoint != null)
433 {
434 Plane plane = new Plane();
435 plane.normal = float3.normalize(float3.cross(vdir, cp));
436 plane.dist = -float3.dot(plane.normal, vstart);
437 upoint = PlaneLineIntersection(plane, ustart, ustart + udir);
438 }
439 if (vpoint != null)
440 {
441 Plane plane = new Plane();
442 plane.normal = float3.normalize(float3.cross(udir, cp));
443 plane.dist = -float3.dot(plane.normal, ustart);
444 vpoint = PlaneLineIntersection(plane, vstart, vstart + vdir);
445 }
446 return dist;
447 }
448
449 public static float3 TriNormal(float3 v0, float3 v1, float3 v2)
450 {
451 // return the normal of the triangle
452 // inscribed by v0, v1, and v2
453 float3 cp = float3.cross(v1 - v0, v2 - v1);
454 float m = float3.magnitude(cp);
455 if (m == 0)
456 return new float3(1, 0, 0);
457 return cp * (1.0f / m);
458 }
459
460 public static int PlaneTest(Plane p, float3 v, float planetestepsilon)
461 {
462 float a = float3.dot(v, p.normal) + p.dist;
463 int flag = (a > planetestepsilon) ? (2) : ((a < -planetestepsilon) ? (1) : (0));
464 return flag;
465 }
466
467 public static int SplitTest(ref ConvexH convex, Plane plane, float planetestepsilon)
468 {
469 int flag = 0;
470 for (int i = 0; i < convex.vertices.Count; i++)
471 {
472 flag |= PlaneTest(plane, convex.vertices[i], planetestepsilon);
473 }
474 return flag;
475 }
476
477 public static Quaternion VirtualTrackBall(float3 cop, float3 cor, float3 dir1, float3 dir2)
478 {
479 // routine taken from game programming gems.
480 // Implement track ball functionality to spin stuf on the screen
481 // cop center of projection
482 // cor center of rotation
483 // dir1 old mouse direction
484 // dir2 new mouse direction
485 // pretend there is a sphere around cor. Then find the points
486 // where dir1 and dir2 intersect that sphere. Find the
487 // rotation that takes the first point to the second.
488 float m;
489 // compute plane
490 float3 nrml = cor - cop;
491 float fudgefactor = 1.0f / (float3.magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop
492 nrml = float3.normalize(nrml);
493 float dist = -float3.dot(nrml, cor);
494 float3 u = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir1);
495 u = u - cor;
496 u = u * fudgefactor;
497 m = float3.magnitude(u);
498 if (m > 1)
499 {
500 u /= m;
501 }
502 else
503 {
504 u = u - (nrml * (float)Math.Sqrt(1 - m * m));
505 }
506 float3 v = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir2);
507 v = v - cor;
508 v = v * fudgefactor;
509 m = float3.magnitude(v);
510 if (m > 1)
511 {
512 v /= m;
513 }
514 else
515 {
516 v = v - (nrml * (float)Math.Sqrt(1 - m * m));
517 }
518 return RotationArc(u, v);
519 }
520
521 public static bool AssertIntact(ConvexH convex, float planetestepsilon)
522 {
523 int i;
524 int estart = 0;
525 for (i = 0; i < convex.edges.Count; i++)
526 {
527 if (convex.edges[estart].p != convex.edges[i].p)
528 {
529 estart = i;
530 }
531 int inext = i + 1;
532 if (inext >= convex.edges.Count || convex.edges[inext].p != convex.edges[i].p)
533 {
534 inext = estart;
535 }
536 Debug.Assert(convex.edges[inext].p == convex.edges[i].p);
537 int nb = convex.edges[i].ea;
538 Debug.Assert(nb != 255);
539 if (nb == 255 || nb == -1)
540 return false;
541 Debug.Assert(nb != -1);
542 Debug.Assert(i == convex.edges[nb].ea);
543 }
544 for (i = 0; i < convex.edges.Count; i++)
545 {
546 Debug.Assert((0) == PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon));
547 if ((0) != PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon))
548 return false;
549 if (convex.edges[estart].p != convex.edges[i].p)
550 {
551 estart = i;
552 }
553 int i1 = i + 1;
554 if (i1 >= convex.edges.Count || convex.edges[i1].p != convex.edges[i].p)
555 {
556 i1 = estart;
557 }
558 int i2 = i1 + 1;
559 if (i2 >= convex.edges.Count || convex.edges[i2].p != convex.edges[i].p)
560 {
561 i2 = estart;
562 }
563 if (i == i2) // i sliced tangent to an edge and created 2 meaningless edges
564 continue;
565 float3 localnormal = TriNormal(convex.vertices[convex.edges[i].v], convex.vertices[convex.edges[i1].v], convex.vertices[convex.edges[i2].v]);
566 Debug.Assert(float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) > 0);
567 if (float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) <= 0)
568 return false;
569 }
570 return true;
571 }
572
573 public static ConvexH test_btbq(float planetestepsilon)
574 {
575 // back to back quads
576 ConvexH convex = new ConvexH(4, 8, 2);
577 convex.vertices[0] = new float3(0, 0, 0);
578 convex.vertices[1] = new float3(1, 0, 0);
579 convex.vertices[2] = new float3(1, 1, 0);
580 convex.vertices[3] = new float3(0, 1, 0);
581 convex.facets[0] = new Plane(new float3(0, 0, 1), 0);
582 convex.facets[1] = new Plane(new float3(0, 0, -1), 0);
583 convex.edges[0] = new ConvexH.HalfEdge(7, 0, 0);
584 convex.edges[1] = new ConvexH.HalfEdge(6, 1, 0);
585 convex.edges[2] = new ConvexH.HalfEdge(5, 2, 0);
586 convex.edges[3] = new ConvexH.HalfEdge(4, 3, 0);
587
588 convex.edges[4] = new ConvexH.HalfEdge(3, 0, 1);
589 convex.edges[5] = new ConvexH.HalfEdge(2, 3, 1);
590 convex.edges[6] = new ConvexH.HalfEdge(1, 2, 1);
591 convex.edges[7] = new ConvexH.HalfEdge(0, 1, 1);
592 AssertIntact(convex, planetestepsilon);
593 return convex;
594 }
595
596 public static ConvexH test_cube()
597 {
598 ConvexH convex = new ConvexH(8, 24, 6);
599 convex.vertices[0] = new float3(0, 0, 0);
600 convex.vertices[1] = new float3(0, 0, 1);
601 convex.vertices[2] = new float3(0, 1, 0);
602 convex.vertices[3] = new float3(0, 1, 1);
603 convex.vertices[4] = new float3(1, 0, 0);
604 convex.vertices[5] = new float3(1, 0, 1);
605 convex.vertices[6] = new float3(1, 1, 0);
606 convex.vertices[7] = new float3(1, 1, 1);
607
608 convex.facets[0] = new Plane(new float3(-1, 0, 0), 0);
609 convex.facets[1] = new Plane(new float3(1, 0, 0), -1);
610 convex.facets[2] = new Plane(new float3(0, -1, 0), 0);
611 convex.facets[3] = new Plane(new float3(0, 1, 0), -1);
612 convex.facets[4] = new Plane(new float3(0, 0, -1), 0);
613 convex.facets[5] = new Plane(new float3(0, 0, 1), -1);
614
615 convex.edges[0] = new ConvexH.HalfEdge(11, 0, 0);
616 convex.edges[1] = new ConvexH.HalfEdge(23, 1, 0);
617 convex.edges[2] = new ConvexH.HalfEdge(15, 3, 0);
618 convex.edges[3] = new ConvexH.HalfEdge(16, 2, 0);
619
620 convex.edges[4] = new ConvexH.HalfEdge(13, 6, 1);
621 convex.edges[5] = new ConvexH.HalfEdge(21, 7, 1);
622 convex.edges[6] = new ConvexH.HalfEdge(9, 5, 1);
623 convex.edges[7] = new ConvexH.HalfEdge(18, 4, 1);
624
625 convex.edges[8] = new ConvexH.HalfEdge(19, 0, 2);
626 convex.edges[9] = new ConvexH.HalfEdge(6, 4, 2);
627 convex.edges[10] = new ConvexH.HalfEdge(20, 5, 2);
628 convex.edges[11] = new ConvexH.HalfEdge(0, 1, 2);
629
630 convex.edges[12] = new ConvexH.HalfEdge(22, 3, 3);
631 convex.edges[13] = new ConvexH.HalfEdge(4, 7, 3);
632 convex.edges[14] = new ConvexH.HalfEdge(17, 6, 3);
633 convex.edges[15] = new ConvexH.HalfEdge(2, 2, 3);
634
635 convex.edges[16] = new ConvexH.HalfEdge(3, 0, 4);
636 convex.edges[17] = new ConvexH.HalfEdge(14, 2, 4);
637 convex.edges[18] = new ConvexH.HalfEdge(7, 6, 4);
638 convex.edges[19] = new ConvexH.HalfEdge(8, 4, 4);
639
640 convex.edges[20] = new ConvexH.HalfEdge(10, 1, 5);
641 convex.edges[21] = new ConvexH.HalfEdge(5, 5, 5);
642 convex.edges[22] = new ConvexH.HalfEdge(12, 7, 5);
643 convex.edges[23] = new ConvexH.HalfEdge(1, 3, 5);
644
645 return convex;
646 }
647
648 public static ConvexH ConvexHMakeCube(float3 bmin, float3 bmax)
649 {
650 ConvexH convex = test_cube();
651 convex.vertices[0] = new float3(bmin.x, bmin.y, bmin.z);
652 convex.vertices[1] = new float3(bmin.x, bmin.y, bmax.z);
653 convex.vertices[2] = new float3(bmin.x, bmax.y, bmin.z);
654 convex.vertices[3] = new float3(bmin.x, bmax.y, bmax.z);
655 convex.vertices[4] = new float3(bmax.x, bmin.y, bmin.z);
656 convex.vertices[5] = new float3(bmax.x, bmin.y, bmax.z);
657 convex.vertices[6] = new float3(bmax.x, bmax.y, bmin.z);
658 convex.vertices[7] = new float3(bmax.x, bmax.y, bmax.z);
659
660 convex.facets[0] = new Plane(new float3(-1, 0, 0), bmin.x);
661 convex.facets[1] = new Plane(new float3(1, 0, 0), -bmax.x);
662 convex.facets[2] = new Plane(new float3(0, -1, 0), bmin.y);
663 convex.facets[3] = new Plane(new float3(0, 1, 0), -bmax.y);
664 convex.facets[4] = new Plane(new float3(0, 0, -1), bmin.z);
665 convex.facets[5] = new Plane(new float3(0, 0, 1), -bmax.z);
666 return convex;
667 }
668
669 public static ConvexH ConvexHCrop(ref ConvexH convex, Plane slice, float planetestepsilon)
670 {
671 int i;
672 int vertcountunder = 0;
673 int vertcountover = 0;
674 List<int> vertscoplanar = new List<int>(); // existing vertex members of convex that are coplanar
675 List<int> edgesplit = new List<int>(); // existing edges that members of convex that cross the splitplane
676
677 Debug.Assert(convex.edges.Count < 480);
678
679 EdgeFlag[] edgeflag = new EdgeFlag[512];
680 VertFlag[] vertflag = new VertFlag[256];
681 PlaneFlag[] planeflag = new PlaneFlag[128];
682 ConvexH.HalfEdge[] tmpunderedges = new ConvexH.HalfEdge[512];
683 Plane[] tmpunderplanes = new Plane[128];
684 Coplanar[] coplanaredges = new Coplanar[512];
685 int coplanaredges_num = 0;
686
687 List<float3> createdverts = new List<float3>();
688
689 // do the side-of-plane tests
690 for (i = 0; i < convex.vertices.Count; i++)
691 {
692 vertflag[i].planetest = (byte)PlaneTest(slice, convex.vertices[i], planetestepsilon);
693 if (vertflag[i].planetest == (0))
694 {
695 // ? vertscoplanar.Add(i);
696 vertflag[i].undermap = (byte)vertcountunder++;
697 vertflag[i].overmap = (byte)vertcountover++;
698 }
699 else if (vertflag[i].planetest == (1))
700 {
701 vertflag[i].undermap = (byte)vertcountunder++;
702 }
703 else
704 {
705 Debug.Assert(vertflag[i].planetest == (2));
706 vertflag[i].overmap = (byte)vertcountover++;
707 vertflag[i].undermap = 255; // for debugging purposes
708 }
709 }
710 int vertcountunderold = vertcountunder; // for debugging only
711
712 int under_edge_count = 0;
713 int underplanescount = 0;
714 int e0 = 0;
715
716 for (int currentplane = 0; currentplane < convex.facets.Count; currentplane++)
717 {
718 int estart = e0;
719 int enextface = 0;
720 int planeside = 0;
721 int e1 = e0 + 1;
722 int vout = -1;
723 int vin = -1;
724 int coplanaredge = -1;
725 do
726 {
727
728 if (e1 >= convex.edges.Count || convex.edges[e1].p != currentplane)
729 {
730 enextface = e1;
731 e1 = estart;
732 }
733 ConvexH.HalfEdge edge0 = convex.edges[e0];
734 ConvexH.HalfEdge edge1 = convex.edges[e1];
735 ConvexH.HalfEdge edgea = convex.edges[edge0.ea];
736
737 planeside |= vertflag[edge0.v].planetest;
738 //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) {
739 // assert(ecop==-1);
740 // ecop=e;
741 //}
742
743 if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (2))
744 {
745 // both endpoints over plane
746 edgeflag[e0].undermap = -1;
747 }
748 else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (1))
749 {
750 // at least one endpoint under, the other coplanar or under
751
752 edgeflag[e0].undermap = (short)under_edge_count;
753 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
754 tmpunderedges[under_edge_count].p = (byte)underplanescount;
755 if (edge0.ea < e0)
756 {
757 // connect the neighbors
758 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
759 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
760 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
761 }
762 under_edge_count++;
763 }
764 else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (0))
765 {
766 // both endpoints coplanar
767 // must check a 3rd point to see if UNDER
768 int e2 = e1 + 1;
769 if (e2 >= convex.edges.Count || convex.edges[e2].p != currentplane)
770 {
771 e2 = estart;
772 }
773 Debug.Assert(convex.edges[e2].p == currentplane);
774 ConvexH.HalfEdge edge2 = convex.edges[e2];
775 if (vertflag[edge2.v].planetest == (1))
776 {
777
778 edgeflag[e0].undermap = (short)under_edge_count;
779 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
780 tmpunderedges[under_edge_count].p = (byte)underplanescount;
781 tmpunderedges[under_edge_count].ea = -1;
782 // make sure this edge is added to the "coplanar" list
783 coplanaredge = under_edge_count;
784 vout = vertflag[edge0.v].undermap;
785 vin = vertflag[edge1.v].undermap;
786 under_edge_count++;
787 }
788 else
789 {
790 edgeflag[e0].undermap = -1;
791 }
792 }
793 else if (vertflag[edge0.v].planetest == (1) && vertflag[edge1.v].planetest == (2))
794 {
795 // first is under 2nd is over
796
797 edgeflag[e0].undermap = (short)under_edge_count;
798 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
799 tmpunderedges[under_edge_count].p = (byte)underplanescount;
800 if (edge0.ea < e0)
801 {
802 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
803 // connect the neighbors
804 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
805 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
806 vout = tmpunderedges[edgeflag[edge0.ea].undermap].v;
807 }
808 else
809 {
810 Plane p0 = convex.facets[edge0.p];
811 Plane pa = convex.facets[edgea.p];
812 createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
813 //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])));
814 //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]));
815 vout = vertcountunder++;
816 }
817 under_edge_count++;
818 /// hmmm something to think about: i might be able to output this edge regarless of
819 // wheter or not we know v-in yet. ok i;ll try this now:
820 tmpunderedges[under_edge_count].v = (byte)vout;
821 tmpunderedges[under_edge_count].p = (byte)underplanescount;
822 tmpunderedges[under_edge_count].ea = -1;
823 coplanaredge = under_edge_count;
824 under_edge_count++;
825
826 if (vin != -1)
827 {
828 // we previously processed an edge where we came under
829 // now we know about vout as well
830
831 // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
832 }
833
834 }
835 else if (vertflag[edge0.v].planetest == (0) && vertflag[edge1.v].planetest == (2))
836 {
837 // first is coplanar 2nd is over
838
839 edgeflag[e0].undermap = -1;
840 vout = vertflag[edge0.v].undermap;
841 // I hate this but i have to make sure part of this face is UNDER before ouputting this vert
842 int k = estart;
843 Debug.Assert(edge0.p == currentplane);
844 while (!((planeside & 1) != 0) && k < convex.edges.Count && convex.edges[k].p == edge0.p)
845 {
846 planeside |= vertflag[convex.edges[k].v].planetest;
847 k++;
848 }
849 if ((planeside & 1) != 0)
850 {
851 tmpunderedges[under_edge_count].v = (byte)vout;
852 tmpunderedges[under_edge_count].p = (byte)underplanescount;
853 tmpunderedges[under_edge_count].ea = -1;
854 coplanaredge = under_edge_count; // hmmm should make a note of the edge # for later on
855 under_edge_count++;
856
857 }
858 }
859 else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (1))
860 {
861 // first is over next is under
862 // new vertex!!!
863 Debug.Assert(vin == -1);
864 if (e0 < edge0.ea)
865 {
866 Plane p0 = convex.facets[edge0.p];
867 Plane pa = convex.facets[edgea.p];
868 createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
869 //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]));
870 //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])));
871 vin = vertcountunder++;
872 }
873 else
874 {
875 // find the new vertex that was created by edge[edge0.ea]
876 int nea = edgeflag[edge0.ea].undermap;
877 Debug.Assert(tmpunderedges[nea].p == tmpunderedges[nea + 1].p);
878 vin = tmpunderedges[nea + 1].v;
879 Debug.Assert(vin < vertcountunder);
880 Debug.Assert(vin >= vertcountunderold); // for debugging only
881 }
882 if (vout != -1)
883 {
884 // we previously processed an edge where we went over
885 // now we know vin too
886 // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
887 }
888 // output edge
889 tmpunderedges[under_edge_count].v = (byte)vin;
890 tmpunderedges[under_edge_count].p = (byte)underplanescount;
891 edgeflag[e0].undermap = (short)under_edge_count;
892 if (e0 > edge0.ea)
893 {
894 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
895 // connect the neighbors
896 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
897 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
898 }
899 Debug.Assert(edgeflag[e0].undermap == under_edge_count);
900 under_edge_count++;
901 }
902 else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (0))
903 {
904 // first is over next is coplanar
905
906 edgeflag[e0].undermap = -1;
907 vin = vertflag[edge1.v].undermap;
908 Debug.Assert(vin != -1);
909 if (vout != -1)
910 {
911 // we previously processed an edge where we came under
912 // now we know both endpoints
913 // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
914 }
915
916 }
917 else
918 {
919 Debug.Assert(false);
920 }
921
922
923 e0 = e1;
924 e1++; // do the modulo at the beginning of the loop
925
926 } while (e0 != estart);
927 e0 = enextface;
928 if ((planeside & 1) != 0)
929 {
930 planeflag[currentplane].undermap = (byte)underplanescount;
931 tmpunderplanes[underplanescount] = convex.facets[currentplane];
932 underplanescount++;
933 }
934 else
935 {
936 planeflag[currentplane].undermap = 0;
937 }
938 if (vout >= 0 && (planeside & 1) != 0)
939 {
940 Debug.Assert(vin >= 0);
941 Debug.Assert(coplanaredge >= 0);
942 Debug.Assert(coplanaredge != 511);
943 coplanaredges[coplanaredges_num].ea = (ushort)coplanaredge;
944 coplanaredges[coplanaredges_num].v0 = (byte)vin;
945 coplanaredges[coplanaredges_num].v1 = (byte)vout;
946 coplanaredges_num++;
947 }
948 }
949
950 // add the new plane to the mix:
951 if (coplanaredges_num > 0)
952 {
953 tmpunderplanes[underplanescount++] = slice;
954 }
955 for (i = 0; i < coplanaredges_num - 1; i++)
956 {
957 if (coplanaredges[i].v1 != coplanaredges[i + 1].v0)
958 {
959 int j = 0;
960 for (j = i + 2; j < coplanaredges_num; j++)
961 {
962 if (coplanaredges[i].v1 == coplanaredges[j].v0)
963 {
964 Coplanar tmp = coplanaredges[i + 1];
965 coplanaredges[i + 1] = coplanaredges[j];
966 coplanaredges[j] = tmp;
967 break;
968 }
969 }
970 if (j >= coplanaredges_num)
971 {
972 Debug.Assert(j < coplanaredges_num);
973 return null;
974 }
975 }
976 }
977
978 ConvexH punder = new ConvexH(vertcountunder, under_edge_count + coplanaredges_num, underplanescount);
979 ConvexH under = punder;
980
981 {
982 int k = 0;
983 for (i = 0; i < convex.vertices.Count; i++)
984 {
985 if (vertflag[i].planetest != (2))
986 {
987 under.vertices[k++] = convex.vertices[i];
988 }
989 }
990 i = 0;
991 while (k < vertcountunder)
992 {
993 under.vertices[k++] = createdverts[i++];
994 }
995 Debug.Assert(i == createdverts.Count);
996 }
997
998 for (i = 0; i < coplanaredges_num; i++)
999 {
1000 ConvexH.HalfEdge edge = under.edges[under_edge_count + i];
1001 edge.p = (byte)(underplanescount - 1);
1002 edge.ea = (short)coplanaredges[i].ea;
1003 edge.v = (byte)coplanaredges[i].v0;
1004 under.edges[under_edge_count + i] = edge;
1005
1006 tmpunderedges[coplanaredges[i].ea].ea = (short)(under_edge_count + i);
1007 }
1008
1009 under.edges = new List<ConvexH.HalfEdge>(tmpunderedges);
1010 under.facets = new List<Plane>(tmpunderplanes);
1011 return punder;
1012 }
1013
1014 public static ConvexH ConvexHDup(ConvexH src)
1015 {
1016 ConvexH dst = new ConvexH(src.vertices.Count, src.edges.Count, src.facets.Count);
1017 dst.vertices = new List<float3>(src.vertices.Count);
1018 foreach (float3 f in src.vertices)
1019 dst.vertices.Add(new float3(f));
1020 dst.edges = new List<ConvexH.HalfEdge>(src.edges.Count);
1021 foreach (ConvexH.HalfEdge e in src.edges)
1022 dst.edges.Add(new ConvexH.HalfEdge(e));
1023 dst.facets = new List<Plane>(src.facets.Count);
1024 foreach (Plane p in src.facets)
1025 dst.facets.Add(new Plane(p));
1026 return dst;
1027 }
1028
1029 public static int candidateplane(List<Plane> planes, int planes_count, ConvexH convex, float epsilon)
1030 {
1031 int p = 0;
1032 float md = 0;
1033 int i;
1034 for (i = 0; i < planes_count; i++)
1035 {
1036 float d = 0;
1037 for (int j = 0; j < convex.vertices.Count; j++)
1038 {
1039 d = Math.Max(d, float3.dot(convex.vertices[j], planes[i].normal) + planes[i].dist);
1040 }
1041 if (i == 0 || d > md)
1042 {
1043 p = i;
1044 md = d;
1045 }
1046 }
1047 return (md > epsilon) ? p : -1;
1048 }
1049
1050 public static float3 orth(float3 v)
1051 {
1052 float3 a = float3.cross(v, new float3(0f, 0f, 1f));
1053 float3 b = float3.cross(v, new float3(0f, 1f, 0f));
1054 return float3.normalize((float3.magnitude(a) > float3.magnitude(b)) ? a : b);
1055 }
1056
1057 public static int maxdir(List<float3> p, int count, float3 dir)
1058 {
1059 Debug.Assert(count != 0);
1060 int m = 0;
1061 float currDotm = float3.dot(p[0], dir);
1062 for (int i = 1; i < count; i++)
1063 {
1064 float currDoti = float3.dot(p[i], dir);
1065 if (currDoti > currDotm)
1066 {
1067 currDotm = currDoti;
1068 m = i;
1069 }
1070 }
1071 return m;
1072 }
1073
1074 public static int maxdirfiltered(List<float3> p, int count, float3 dir, byte[] allow)
1075 {
1076 //Debug.Assert(count != 0);
1077 int m = 0;
1078 float currDotm = float3.dot(p[0], dir);
1079 float currDoti;
1080
1081 while (allow[m] == 0)
1082 m++;
1083
1084 for (int i = 1; i < count; i++)
1085 {
1086 if (allow[i] != 0)
1087 {
1088 currDoti = float3.dot(p[i], dir);
1089 if (currDoti > currDotm)
1090 {
1091 currDotm = currDoti;
1092 m = i;
1093 }
1094 }
1095 }
1096 //Debug.Assert(m != -1);
1097 return m;
1098 }
1099
1100 public static int maxdirsterid(List<float3> p, int count, float3 dir, byte[] allow)
1101 {
1102 int m = -1;
1103 while (m == -1)
1104 {
1105 m = maxdirfiltered(p, count, dir, allow);
1106 if (allow[m] == 3)
1107 return m;
1108 float3 u = orth(dir);
1109 float3 v = float3.cross(u, dir);
1110 int ma = -1;
1111 for (float x = 0.0f; x <= 360.0f; x += 45.0f)
1112 {
1113 int mb;
1114 {
1115 float s = (float)Math.Sin((3.14159264f / 180.0f) * (x));
1116 float c = (float)Math.Cos((3.14159264f / 180.0f) * (x));
1117 mb = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
1118 }
1119 if (ma == m && mb == m)
1120 {
1121 allow[m] = 3;
1122 return m;
1123 }
1124 if (ma != -1 && ma != mb) // Yuck - this is really ugly
1125 {
1126 int mc = ma;
1127 for (float xx = x - 40.0f; xx <= x; xx += 5.0f)
1128 {
1129 float s = (float)Math.Sin((3.14159264f / 180.0f) * (xx));
1130 float c = (float)Math.Cos((3.14159264f / 180.0f) * (xx));
1131 int md = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
1132 if (mc == m && md == m)
1133 {
1134 allow[m] = 3;
1135 return m;
1136 }
1137 mc = md;
1138 }
1139 }
1140 ma = mb;
1141 }
1142 allow[m] = 0;
1143 m = -1;
1144 }
1145
1146 Debug.Assert(false);
1147 return m;
1148 }
1149
1150 public static int4 FindSimplex(List<float3> verts, byte[] allow)
1151 {
1152 float3[] basis = new float3[3];
1153 basis[0] = new float3(0.01f, 0.02f, 1.0f);
1154 int p0 = maxdirsterid(verts, verts.Count, basis[0], allow);
1155 int p1 = maxdirsterid(verts, verts.Count, -basis[0], allow);
1156 basis[0] = verts[p0] - verts[p1];
1157 if (p0 == p1 || basis[0] == new float3(0, 0, 0))
1158 return new int4(-1, -1, -1, -1);
1159 basis[1] = float3.cross(new float3(1, 0.02f, 0), basis[0]);
1160 basis[2] = float3.cross(new float3(-0.02f, 1, 0), basis[0]);
1161 basis[1] = float3.normalize((float3.magnitude(basis[1]) > float3.magnitude(basis[2])) ? basis[1] : basis[2]);
1162 int p2 = maxdirsterid(verts, verts.Count, basis[1], allow);
1163 if (p2 == p0 || p2 == p1)
1164 {
1165 p2 = maxdirsterid(verts, verts.Count, -basis[1], allow);
1166 }
1167 if (p2 == p0 || p2 == p1)
1168 return new int4(-1, -1, -1, -1);
1169 basis[1] = verts[p2] - verts[p0];
1170 basis[2] = float3.normalize(float3.cross(basis[1], basis[0]));
1171 int p3 = maxdirsterid(verts, verts.Count, basis[2], allow);
1172 if (p3 == p0 || p3 == p1 || p3 == p2)
1173 p3 = maxdirsterid(verts, verts.Count, -basis[2], allow);
1174 if (p3 == p0 || p3 == p1 || p3 == p2)
1175 return new int4(-1, -1, -1, -1);
1176 Debug.Assert(!(p0 == p1 || p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3 || p2 == p3));
1177 if (float3.dot(verts[p3] - verts[p0], float3.cross(verts[p1] - verts[p0], verts[p2] - verts[p0])) < 0)
1178 {
1179 Swap(ref p2, ref p3);
1180 }
1181 return new int4(p0, p1, p2, p3);
1182 }
1183
1184 public static float GetDist(float px, float py, float pz, float3 p2)
1185 {
1186 float dx = px - p2.x;
1187 float dy = py - p2.y;
1188 float dz = pz - p2.z;
1189
1190 return dx * dx + dy * dy + dz * dz;
1191 }
1192
1193 public static void ReleaseHull(PHullResult result)
1194 {
1195 if (result.Indices != null)
1196 result.Indices = null;
1197 if (result.Vertices != null)
1198 result.Vertices = null;
1199 }
1200
1201 public static int calchullgen(List<float3> verts, int vlimit, List<HullTriangle> tris)
1202 {
1203 if (verts.Count < 4)
1204 return 0;
1205 if (vlimit == 0)
1206 vlimit = 1000000000;
1207 int j;
1208 float3 bmin = new float3(verts[0]);
1209 float3 bmax = new float3(verts[0]);
1210 List<int> isextreme = new List<int>(verts.Count);
1211 byte[] allow = new byte[verts.Count];
1212 for (j = 0; j < verts.Count; j++)
1213 {
1214 allow[j] = 1;
1215 isextreme.Add(0);
1216 bmin = float3.VectorMin(bmin, verts[j]);
1217 bmax = float3.VectorMax(bmax, verts[j]);
1218 }
1219 float epsilon = float3.magnitude(bmax - bmin) * 0.001f;
1220
1221 int4 p = FindSimplex(verts, allow);
1222 if (p.x == -1) // simplex failed
1223 return 0;
1224
1225 float3 center = (verts[p[0]] + verts[p[1]] + verts[p[2]] + verts[p[3]]) / 4.0f; // a valid interior point
1226 HullTriangle t0 = new HullTriangle(p[2], p[3], p[1], tris);
1227 t0.n = new int3(2, 3, 1);
1228 HullTriangle t1 = new HullTriangle(p[3], p[2], p[0], tris);
1229 t1.n = new int3(3, 2, 0);
1230 HullTriangle t2 = new HullTriangle(p[0], p[1], p[3], tris);
1231 t2.n = new int3(0, 1, 3);
1232 HullTriangle t3 = new HullTriangle(p[1], p[0], p[2], tris);
1233 t3.n = new int3(1, 0, 2);
1234 isextreme[p[0]] = isextreme[p[1]] = isextreme[p[2]] = isextreme[p[3]] = 1;
1235 checkit(t0, tris);
1236 checkit(t1, tris);
1237 checkit(t2, tris);
1238 checkit(t3, tris);
1239
1240 for (j = 0; j < tris.Count; j++)
1241 {
1242 HullTriangle t = tris[j];
1243 Debug.Assert((object)t != null);
1244 Debug.Assert(t.vmax < 0);
1245 float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1246 t.vmax = maxdirsterid(verts, verts.Count, n, allow);
1247 t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]);
1248 }
1249 HullTriangle te;
1250 vlimit -= 4;
1251 while (vlimit > 0 && (te = extrudable(epsilon, tris)) != null)
1252 {
1253 int3 ti = te;
1254 int v = te.vmax;
1255 Debug.Assert(isextreme[v] == 0); // wtf we've already done this vertex
1256 isextreme[v] = 1;
1257 //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already
1258 j = tris.Count;
1259 while (j-- != 0)
1260 {
1261 if (tris.Count <= j || (object)tris[j] == null)
1262 continue;
1263 int3 t = tris[j];
1264 if (above(verts, t, verts[v], 0.01f * epsilon))
1265 {
1266 extrude(tris[j], v, tris);
1267 }
1268 }
1269 // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle
1270 j = tris.Count;
1271 while (j-- != 0)
1272 {
1273 if (tris.Count <= j || (object)tris[j] == null)
1274 continue;
1275 if (!hasvert(tris[j], v))
1276 break;
1277 int3 nt = tris[j];
1278 if (above(verts, nt, center, 0.01f * epsilon) || float3.magnitude(float3.cross(verts[nt[1]] - verts[nt[0]], verts[nt[2]] - verts[nt[1]])) < epsilon * epsilon * 0.1f)
1279 {
1280 HullTriangle nb = tris[tris[j].n[0]];
1281 Debug.Assert(nb != null);
1282 Debug.Assert(!hasvert(nb, v));
1283 Debug.Assert(nb.id < j);
1284 extrude(nb, v, tris);
1285 j = tris.Count;
1286 }
1287 }
1288 j = tris.Count;
1289 while (j-- != 0)
1290 {
1291 HullTriangle t = tris[j];
1292 if (t == null)
1293 continue;
1294 if (t.vmax >= 0)
1295 break;
1296 float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1297 t.vmax = maxdirsterid(verts, verts.Count, n, allow);
1298 if (isextreme[t.vmax] != 0)
1299 {
1300 t.vmax = -1; // already done that vertex - algorithm needs to be able to terminate.
1301 }
1302 else
1303 {
1304 t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]);
1305 }
1306 }
1307 vlimit--;
1308 }
1309 return 1;
1310 }
1311
1312 public static bool calchull(List<float3> verts, out List<int> tris_out, int vlimit, List<HullTriangle> tris)
1313 {
1314 tris_out = null;
1315
1316 int rc = calchullgen(verts, vlimit, tris);
1317 if (rc == 0)
1318 return false;
1319 List<int> ts = new List<int>();
1320 for (int i = 0; i < tris.Count; i++)
1321 {
1322 if ((object)tris[i] != null)
1323 {
1324 for (int j = 0; j < 3; j++)
1325 ts.Add((tris[i])[j]);
1326 tris[i] = null;
1327 }
1328 }
1329
1330 tris_out = ts;
1331 tris.Clear();
1332 return true;
1333 }
1334
1335 public static int calchullpbev(List<float3> verts, int vlimit, out List<Plane> planes, float bevangle, List<HullTriangle> tris)
1336 {
1337 int i;
1338 int j;
1339 planes = new List<Plane>();
1340 int rc = calchullgen(verts, vlimit, tris);
1341 if (rc == 0)
1342 return 0;
1343 for (i = 0; i < tris.Count; i++)
1344 {
1345 if (tris[i] != null)
1346 {
1347 Plane p = new Plane();
1348 HullTriangle t = tris[i];
1349 p.normal = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1350 p.dist = -float3.dot(p.normal, verts[(t)[0]]);
1351 planes.Add(p);
1352 for (j = 0; j < 3; j++)
1353 {
1354 if (t.n[j] < t.id)
1355 continue;
1356 HullTriangle s = tris[t.n[j]];
1357 float3 snormal = TriNormal(verts[(s)[0]], verts[(s)[1]], verts[(s)[2]]);
1358 if (float3.dot(snormal, p.normal) >= Math.Cos(bevangle * (3.14159264f / 180.0f)))
1359 continue;
1360 float3 n = float3.normalize(snormal + p.normal);
1361 planes.Add(new Plane(n, -float3.dot(n, verts[maxdir(verts, verts.Count, n)])));
1362 }
1363 }
1364 }
1365
1366 tris.Clear();
1367 return 1;
1368 }
1369
1370 public static int overhull(List<Plane> planes, List<float3> verts, int maxplanes, out List<float3> verts_out, out List<int> faces_out, float inflate)
1371 {
1372 verts_out = null;
1373 faces_out = null;
1374
1375 int i;
1376 int j;
1377 if (verts.Count < 4)
1378 return 0;
1379 maxplanes = Math.Min(maxplanes, planes.Count);
1380 float3 bmin = new float3(verts[0]);
1381 float3 bmax = new float3(verts[0]);
1382 for (i = 0; i < verts.Count; i++)
1383 {
1384 bmin = float3.VectorMin(bmin, verts[i]);
1385 bmax = float3.VectorMax(bmax, verts[i]);
1386 }
1387 // float diameter = magnitude(bmax-bmin);
1388 // inflate *=diameter; // RELATIVE INFLATION
1389 bmin -= new float3(inflate, inflate, inflate);
1390 bmax += new float3(inflate, inflate, inflate);
1391 for (i = 0; i < planes.Count; i++)
1392 {
1393 planes[i].dist -= inflate;
1394 }
1395 float3 emin = new float3(bmin);
1396 float3 emax = new float3(bmax);
1397 float epsilon = float3.magnitude(emax - emin) * 0.025f;
1398 float planetestepsilon = float3.magnitude(emax - emin) * (0.001f);
1399 // todo: add bounding cube planes to force bevel. or try instead not adding the diameter expansion ??? must think.
1400 // ConvexH *convex = ConvexHMakeCube(bmin - float3(diameter,diameter,diameter),bmax+float3(diameter,diameter,diameter));
1401 ConvexH c = ConvexHMakeCube(new float3(bmin), new float3(bmax));
1402 int k;
1403 while (maxplanes-- != 0 && (k = candidateplane(planes, planes.Count, c, epsilon)) >= 0)
1404 {
1405 ConvexH tmp = c;
1406 c = ConvexHCrop(ref tmp, planes[k], planetestepsilon);
1407 if (c == null) // might want to debug this case better!!!
1408 {
1409 c = tmp;
1410 break;
1411 }
1412 if (AssertIntact(c, planetestepsilon) == false) // might want to debug this case better too!!!
1413 {
1414 c = tmp;
1415 break;
1416 }
1417 tmp.edges = null;
1418 tmp.facets = null;
1419 tmp.vertices = null;
1420 }
1421
1422 Debug.Assert(AssertIntact(c, planetestepsilon));
1423 //return c;
1424 //C++ TO C# CONVERTER TODO TASK: The memory management function 'malloc' has no equivalent in C#:
1425 faces_out = new List<int>(); //(int)malloc(sizeof(int) * (1 + c.facets.Count + c.edges.Count)); // new int[1+c->facets.count+c->edges.count];
1426 int faces_count_out = 0;
1427 i = 0;
1428 faces_out[faces_count_out++] = -1;
1429 k = 0;
1430 while (i < c.edges.Count)
1431 {
1432 j = 1;
1433 while (j + i < c.edges.Count && c.edges[i].p == c.edges[i + j].p)
1434 {
1435 j++;
1436 }
1437 faces_out[faces_count_out++] = j;
1438 while (j-- != 0)
1439 {
1440 faces_out[faces_count_out++] = c.edges[i].v;
1441 i++;
1442 }
1443 k++;
1444 }
1445 faces_out[0] = k; // number of faces.
1446 Debug.Assert(k == c.facets.Count);
1447 Debug.Assert(faces_count_out == 1 + c.facets.Count + c.edges.Count);
1448 verts_out = c.vertices; // new float3[c->vertices.count];
1449 int verts_count_out = c.vertices.Count;
1450 for (i = 0; i < c.vertices.Count; i++)
1451 {
1452 verts_out[i] = new float3(c.vertices[i]);
1453 }
1454
1455 c.edges = null;
1456 c.facets = null;
1457 c.vertices = null;
1458 return 1;
1459 }
1460
1461 public static int overhullv(List<float3> verts, int maxplanes, out List<float3> verts_out, out List<int> faces_out, float inflate, float bevangle, int vlimit, List<HullTriangle> tris)
1462 {
1463 verts_out = null;
1464 faces_out = null;
1465
1466 if (verts.Count == 0)
1467 return 0;
1468 List<Plane> planes = new List<Plane>();
1469 int rc = calchullpbev(verts, vlimit, out planes, bevangle, tris);
1470 if (rc == 0)
1471 return 0;
1472 return overhull(planes, verts, maxplanes, out verts_out, out faces_out, inflate);
1473 }
1474
1475 public static void addPoint(ref uint vcount, List<float3> p, float x, float y, float z)
1476 {
1477 p.Add(new float3(x, y, z));
1478 vcount++;
1479 }
1480
1481 public static bool ComputeHull(List<float3> vertices, ref PHullResult result, int vlimit, float inflate)
1482 {
1483 List<HullTriangle> tris = new List<HullTriangle>();
1484 List<int> faces;
1485 List<float3> verts_out;
1486
1487 if (inflate == 0.0f)
1488 {
1489 List<int> tris_out;
1490 bool ret = calchull(vertices, out tris_out, vlimit, tris);
1491 if (ret == false)
1492 return false;
1493
1494 result.Indices = tris_out;
1495 result.Vertices = vertices;
1496 return true;
1497 }
1498 else
1499 {
1500 int ret = overhullv(vertices, 35, out verts_out, out faces, inflate, 120.0f, vlimit, tris);
1501 if (ret == 0)
1502 return false;
1503
1504 List<int3> tris2 = new List<int3>();
1505 int n = faces[0];
1506 int k = 1;
1507 for (int i = 0; i < n; i++)
1508 {
1509 int pn = faces[k++];
1510 for (int j = 2; j < pn; j++)
1511 tris2.Add(new int3(faces[k], faces[k + j - 1], faces[k + j]));
1512 k += pn;
1513 }
1514 Debug.Assert(tris2.Count == faces.Count - 1 - (n * 3));
1515
1516 result.Indices = new List<int>(tris2.Count * 3);
1517 for (int i = 0; i < tris2.Count; i++)
1518 {
1519 result.Indices.Add(tris2[i].x);
1520 result.Indices.Add(tris2[i].y);
1521 result.Indices.Add(tris2[i].z);
1522 }
1523 result.Vertices = verts_out;
1524
1525 return true;
1526 }
1527 }
1528
1529 private static bool CleanupVertices(List<float3> svertices, out List<float3> vertices, float normalepsilon, out float3 scale)
1530 {
1531 const float EPSILON = 0.000001f;
1532
1533 vertices = new List<float3>();
1534 scale = new float3(1f, 1f, 1f);
1535
1536 if (svertices.Count == 0)
1537 return false;
1538
1539 uint vcount = 0;
1540
1541 float[] recip = new float[3];
1542
1543 float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
1544 float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue };
1545
1546 for (int i = 0; i < svertices.Count; i++)
1547 {
1548 float3 p = svertices[i];
1549
1550 for (int j = 0; j < 3; j++)
1551 {
1552 if (p[j] < bmin[j])
1553 bmin[j] = p[j];
1554 if (p[j] > bmax[j])
1555 bmax[j] = p[j];
1556 }
1557 }
1558
1559 float dx = bmax[0] - bmin[0];
1560 float dy = bmax[1] - bmin[1];
1561 float dz = bmax[2] - bmin[2];
1562
1563 float3 center = new float3();
1564
1565 center.x = dx * 0.5f + bmin[0];
1566 center.y = dy * 0.5f + bmin[1];
1567 center.z = dz * 0.5f + bmin[2];
1568
1569 if (dx < EPSILON || dy < EPSILON || dz < EPSILON || svertices.Count < 3)
1570 {
1571 float len = Single.MaxValue;
1572
1573 if (dx > EPSILON && dx < len)
1574 len = dx;
1575 if (dy > EPSILON && dy < len)
1576 len = dy;
1577 if (dz > EPSILON && dz < len)
1578 len = dz;
1579
1580 if (len == Single.MaxValue)
1581 {
1582 dx = dy = dz = 0.01f; // one centimeter
1583 }
1584 else
1585 {
1586 if (dx < EPSILON) // 1/5th the shortest non-zero edge.
1587 dx = len * 0.05f;
1588 if (dy < EPSILON)
1589 dy = len * 0.05f;
1590 if (dz < EPSILON)
1591 dz = len * 0.05f;
1592 }
1593
1594 float x1 = center[0] - dx;
1595 float x2 = center[0] + dx;
1596
1597 float y1 = center[1] - dy;
1598 float y2 = center[1] + dy;
1599
1600 float z1 = center[2] - dz;
1601 float z2 = center[2] + dz;
1602
1603 addPoint(ref vcount, vertices, x1, y1, z1);
1604 addPoint(ref vcount, vertices, x2, y1, z1);
1605 addPoint(ref vcount, vertices, x2, y2, z1);
1606 addPoint(ref vcount, vertices, x1, y2, z1);
1607 addPoint(ref vcount, vertices, x1, y1, z2);
1608 addPoint(ref vcount, vertices, x2, y1, z2);
1609 addPoint(ref vcount, vertices, x2, y2, z2);
1610 addPoint(ref vcount, vertices, x1, y2, z2);
1611
1612 return true; // return cube
1613 }
1614 else
1615 {
1616 scale.x = dx;
1617 scale.y = dy;
1618 scale.z = dz;
1619
1620 recip[0] = 1f / dx;
1621 recip[1] = 1f / dy;
1622 recip[2] = 1f / dz;
1623
1624 center.x *= recip[0];
1625 center.y *= recip[1];
1626 center.z *= recip[2];
1627 }
1628
1629 for (int i = 0; i < svertices.Count; i++)
1630 {
1631 float3 p = svertices[i];
1632
1633 float px = p[0];
1634 float py = p[1];
1635 float pz = p[2];
1636
1637 px = px * recip[0]; // normalize
1638 py = py * recip[1]; // normalize
1639 pz = pz * recip[2]; // normalize
1640
1641 if (true)
1642 {
1643 int j;
1644
1645 for (j = 0; j < vcount; j++)
1646 {
1647 float3 v = vertices[j];
1648
1649 float x = v[0];
1650 float y = v[1];
1651 float z = v[2];
1652
1653 float dx1 = Math.Abs(x - px);
1654 float dy1 = Math.Abs(y - py);
1655 float dz1 = Math.Abs(z - pz);
1656
1657 if (dx1 < normalepsilon && dy1 < normalepsilon && dz1 < normalepsilon)
1658 {
1659 // ok, it is close enough to the old one
1660 // now let us see if it is further from the center of the point cloud than the one we already recorded.
1661 // in which case we keep this one instead.
1662 float dist1 = GetDist(px, py, pz, center);
1663 float dist2 = GetDist(v[0], v[1], v[2], center);
1664
1665 if (dist1 > dist2)
1666 {
1667 v.x = px;
1668 v.y = py;
1669 v.z = pz;
1670 }
1671
1672 break;
1673 }
1674 }
1675
1676 if (j == vcount)
1677 {
1678 float3 dest = new float3(px, py, pz);
1679 vertices.Add(dest);
1680 vcount++;
1681 }
1682 }
1683 }
1684
1685 // ok..now make sure we didn't prune so many vertices it is now invalid.
1686 if (true)
1687 {
1688 float[] bmin2 = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
1689 float[] bmax2 = { Single.MinValue, Single.MinValue, Single.MinValue };
1690
1691 for (int i = 0; i < vcount; i++)
1692 {
1693 float3 p = vertices[i];
1694 for (int j = 0; j < 3; j++)
1695 {
1696 if (p[j] < bmin2[j])
1697 bmin2[j] = p[j];
1698 if (p[j] > bmax2[j])
1699 bmax2[j] = p[j];
1700 }
1701 }
1702
1703 float dx2 = bmax2[0] - bmin2[0];
1704 float dy2 = bmax2[1] - bmin2[1];
1705 float dz2 = bmax2[2] - bmin2[2];
1706
1707 if (dx2 < EPSILON || dy2 < EPSILON || dz2 < EPSILON || vcount < 3)
1708 {
1709 float cx = dx2 * 0.5f + bmin2[0];
1710 float cy = dy2 * 0.5f + bmin2[1];
1711 float cz = dz2 * 0.5f + bmin2[2];
1712
1713 float len = Single.MaxValue;
1714
1715 if (dx2 >= EPSILON && dx2 < len)
1716 len = dx2;
1717 if (dy2 >= EPSILON && dy2 < len)
1718 len = dy2;
1719 if (dz2 >= EPSILON && dz2 < len)
1720 len = dz2;
1721
1722 if (len == Single.MaxValue)
1723 {
1724 dx2 = dy2 = dz2 = 0.01f; // one centimeter
1725 }
1726 else
1727 {
1728 if (dx2 < EPSILON) // 1/5th the shortest non-zero edge.
1729 dx2 = len * 0.05f;
1730 if (dy2 < EPSILON)
1731 dy2 = len * 0.05f;
1732 if (dz2 < EPSILON)
1733 dz2 = len * 0.05f;
1734 }
1735
1736 float x1 = cx - dx2;
1737 float x2 = cx + dx2;
1738
1739 float y1 = cy - dy2;
1740 float y2 = cy + dy2;
1741
1742 float z1 = cz - dz2;
1743 float z2 = cz + dz2;
1744
1745 vcount = 0; // add box
1746
1747 addPoint(ref vcount, vertices, x1, y1, z1);
1748 addPoint(ref vcount, vertices, x2, y1, z1);
1749 addPoint(ref vcount, vertices, x2, y2, z1);
1750 addPoint(ref vcount, vertices, x1, y2, z1);
1751 addPoint(ref vcount, vertices, x1, y1, z2);
1752 addPoint(ref vcount, vertices, x2, y1, z2);
1753 addPoint(ref vcount, vertices, x2, y2, z2);
1754 addPoint(ref vcount, vertices, x1, y2, z2);
1755
1756 return true;
1757 }
1758 }
1759
1760 return true;
1761 }
1762
1763 private static void BringOutYourDead(List<float3> verts, out List<float3> overts, List<int> indices)
1764 {
1765 int[] used = new int[verts.Count];
1766 int ocount = 0;
1767
1768 overts = new List<float3>();
1769
1770 for (int i = 0; i < indices.Count; i++)
1771 {
1772 int v = indices[i]; // original array index
1773
1774 Debug.Assert(v >= 0 && v < verts.Count);
1775
1776 if (used[v] != 0) // if already remapped
1777 {
1778 indices[i] = used[v] - 1; // index to new array
1779 }
1780 else
1781 {
1782 indices[i] = ocount; // new index mapping
1783
1784 overts.Add(verts[v]); // copy old vert to new vert array
1785
1786 ocount++; // increment output vert count
1787
1788 Debug.Assert(ocount >= 0 && ocount <= verts.Count);
1789
1790 used[v] = ocount; // assign new index remapping
1791 }
1792 }
1793 }
1794
1795 public static HullError CreateConvexHull(HullDesc desc, ref HullResult result)
1796 {
1797 HullError ret = HullError.QE_FAIL;
1798
1799 PHullResult hr = new PHullResult();
1800
1801 uint vcount = (uint)desc.Vertices.Count;
1802 if (vcount < 8)
1803 vcount = 8;
1804
1805 List<float3> vsource;
1806 float3 scale = new float3();
1807
1808 bool ok = CleanupVertices(desc.Vertices, out vsource, desc.NormalEpsilon, out scale); // normalize point cloud, remove duplicates!
1809
1810 if (ok)
1811 {
1812 if (true) // scale vertices back to their original size.
1813 {
1814 for (int i = 0; i < vsource.Count; i++)
1815 {
1816 float3 v = vsource[i];
1817 v.x *= scale[0];
1818 v.y *= scale[1];
1819 v.z *= scale[2];
1820 }
1821 }
1822
1823 float skinwidth = 0;
1824 if (desc.HasHullFlag(HullFlag.QF_SKIN_WIDTH))
1825 skinwidth = desc.SkinWidth;
1826
1827 ok = ComputeHull(vsource, ref hr, (int)desc.MaxVertices, skinwidth);
1828
1829 if (ok)
1830 {
1831 List<float3> vscratch;
1832 BringOutYourDead(hr.Vertices, out vscratch, hr.Indices);
1833
1834 ret = HullError.QE_OK;
1835
1836 if (desc.HasHullFlag(HullFlag.QF_TRIANGLES)) // if he wants the results as triangle!
1837 {
1838 result.Polygons = false;
1839 result.Indices = hr.Indices;
1840 result.OutputVertices = vscratch;
1841 }
1842 else
1843 {
1844 result.Polygons = true;
1845 result.OutputVertices = vscratch;
1846
1847 if (true)
1848 {
1849 List<int> source = hr.Indices;
1850 List<int> dest = new List<int>();
1851 for (int i = 0; i < hr.Indices.Count / 3; i++)
1852 {
1853 dest.Add(3);
1854 dest.Add(source[i * 3 + 0]);
1855 dest.Add(source[i * 3 + 1]);
1856 dest.Add(source[i * 3 + 2]);
1857 }
1858
1859 result.Indices = dest;
1860 }
1861 }
1862 }
1863 }
1864
1865 return ret;
1866 }
1867 }
1868}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt b/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt
deleted file mode 100644
index 714ae89..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/LICENSE.txt
+++ /dev/null
@@ -1,28 +0,0 @@
1ConvexDecompositionDotNet
2-------------------------
3
4The MIT License
5
6Copyright (c) 2010 Intel Corporation.
7All rights reserved.
8
9Based on the convexdecomposition library from
10<http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files (the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions:
18
19The above copyright notice and this permission notice shall be included in
20all copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28THE SOFTWARE.
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs
deleted file mode 100644
index d099676..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Plane.cs
+++ /dev/null
@@ -1,99 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class Plane
33 {
34 public float3 normal = new float3();
35 public float dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0
36
37 public Plane(float3 n, float d)
38 {
39 normal = new float3(n);
40 dist = d;
41 }
42
43 public Plane(Plane p)
44 {
45 normal = new float3(p.normal);
46 dist = p.dist;
47 }
48
49 public Plane()
50 {
51 dist = 0;
52 }
53
54 public void Transform(float3 position, Quaternion orientation)
55 {
56 // Transforms the plane to the space defined by the
57 // given position/orientation
58 float3 newNormal = Quaternion.Inverse(orientation) * normal;
59 float3 origin = Quaternion.Inverse(orientation) * (-normal * dist - position);
60
61 normal = newNormal;
62 dist = -float3.dot(newNormal, origin);
63 }
64
65 public override int GetHashCode()
66 {
67 return normal.GetHashCode() ^ dist.GetHashCode();
68 }
69
70 public override bool Equals(object obj)
71 {
72 Plane p = obj as Plane;
73 if (p == null)
74 return false;
75
76 return this == p;
77 }
78
79 public static bool operator ==(Plane a, Plane b)
80 {
81 return (a.normal == b.normal && a.dist == b.dist);
82 }
83
84 public static bool operator !=(Plane a, Plane b)
85 {
86 return !(a == b);
87 }
88
89 public static Plane PlaneFlip(Plane plane)
90 {
91 return new Plane(-plane.normal, -plane.dist);
92 }
93
94 public static bool coplanar(Plane a, Plane b)
95 {
96 return (a == b || a == PlaneFlip(b));
97 }
98 }
99}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs
deleted file mode 100644
index 31f0182..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/PlaneTri.cs
+++ /dev/null
@@ -1,211 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public enum PlaneTriResult : int
35 {
36 PTR_FRONT,
37 PTR_BACK,
38 PTR_SPLIT
39 }
40
41 public static class PlaneTri
42 {
43 private static float DistToPt(float3 p, float4 plane)
44 {
45 return p.x * plane.x + p.y * plane.y + p.z * plane.z + plane.w;
46 }
47
48 private static PlaneTriResult getSidePlane(float3 p, float4 plane, float epsilon)
49 {
50 float d = DistToPt(p, plane);
51
52 if ((d + epsilon) > 0f)
53 return PlaneTriResult.PTR_FRONT; // it is 'in front' within the provided epsilon value.
54
55 return PlaneTriResult.PTR_BACK;
56 }
57
58 private static void add(float3 p, float3[] dest, ref int pcount)
59 {
60 dest[pcount++] = new float3(p);
61 Debug.Assert(pcount <= 4);
62 }
63
64 // assumes that the points are on opposite sides of the plane!
65 private static void intersect(float3 p1, float3 p2, float3 split, float4 plane)
66 {
67 float dp1 = DistToPt(p1, plane);
68 float[] dir = new float[3];
69
70 dir[0] = p2[0] - p1[0];
71 dir[1] = p2[1] - p1[1];
72 dir[2] = p2[2] - p1[2];
73
74 float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2];
75 float dot2 = dp1 - plane[3];
76
77 float t = -(plane[3] + dot2) / dot1;
78
79 split.x = (dir[0] * t) + p1[0];
80 split.y = (dir[1] * t) + p1[1];
81 split.z = (dir[2] * t) + p1[2];
82 }
83
84 public static PlaneTriResult planeTriIntersection(float4 plane, FaceTri triangle, float epsilon, ref float3[] front, out int fcount, ref float3[] back, out int bcount)
85 {
86 fcount = 0;
87 bcount = 0;
88
89 // get the three vertices of the triangle.
90 float3 p1 = triangle.P1;
91 float3 p2 = triangle.P2;
92 float3 p3 = triangle.P3;
93
94 PlaneTriResult r1 = getSidePlane(p1, plane, epsilon); // compute the side of the plane each vertex is on
95 PlaneTriResult r2 = getSidePlane(p2, plane, epsilon);
96 PlaneTriResult r3 = getSidePlane(p3, plane, epsilon);
97
98 if (r1 == r2 && r1 == r3) // if all three vertices are on the same side of the plane.
99 {
100 if (r1 == PlaneTriResult.PTR_FRONT) // if all three are in front of the plane, then copy to the 'front' output triangle.
101 {
102 add(p1, front, ref fcount);
103 add(p2, front, ref fcount);
104 add(p3, front, ref fcount);
105 }
106 else
107 {
108 add(p1, back, ref bcount); // if all three are in 'back' then copy to the 'back' output triangle.
109 add(p2, back, ref bcount);
110 add(p3, back, ref bcount);
111 }
112 return r1; // if all three points are on the same side of the plane return result
113 }
114
115 // ok.. we need to split the triangle at the plane.
116
117 // First test ray segment P1 to P2
118 if (r1 == r2) // if these are both on the same side...
119 {
120 if (r1 == PlaneTriResult.PTR_FRONT)
121 {
122 add(p1, front, ref fcount);
123 add(p2, front, ref fcount);
124 }
125 else
126 {
127 add(p1, back, ref bcount);
128 add(p2, back, ref bcount);
129 }
130 }
131 else
132 {
133 float3 split = new float3();
134 intersect(p1, p2, split, plane);
135
136 if (r1 == PlaneTriResult.PTR_FRONT)
137 {
138
139 add(p1, front, ref fcount);
140 add(split, front, ref fcount);
141
142 add(split, back, ref bcount);
143 add(p2, back, ref bcount);
144
145 }
146 else
147 {
148 add(p1, back, ref bcount);
149 add(split, back, ref bcount);
150
151 add(split, front, ref fcount);
152 add(p2, front, ref fcount);
153 }
154
155 }
156
157 // Next test ray segment P2 to P3
158 if (r2 == r3) // if these are both on the same side...
159 {
160 if (r3 == PlaneTriResult.PTR_FRONT)
161 {
162 add(p3, front, ref fcount);
163 }
164 else
165 {
166 add(p3, back, ref bcount);
167 }
168 }
169 else
170 {
171 float3 split = new float3(); // split the point
172 intersect(p2, p3, split, plane);
173
174 if (r3 == PlaneTriResult.PTR_FRONT)
175 {
176 add(split, front, ref fcount);
177 add(split, back, ref bcount);
178
179 add(p3, front, ref fcount);
180 }
181 else
182 {
183 add(split, front, ref fcount);
184 add(split, back, ref bcount);
185
186 add(p3, back, ref bcount);
187 }
188 }
189
190 // Next test ray segment P3 to P1
191 if (r3 != r1) // if these are both on the same side...
192 {
193 float3 split = new float3(); // split the point
194 intersect(p3, p1, split, plane);
195
196 if (r1 == PlaneTriResult.PTR_FRONT)
197 {
198 add(split, front, ref fcount);
199 add(split, back, ref bcount);
200 }
201 else
202 {
203 add(split, front, ref fcount);
204 add(split, back, ref bcount);
205 }
206 }
207
208 return PlaneTriResult.PTR_SPLIT;
209 }
210 }
211}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
deleted file mode 100644
index 5ff945d..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("ConvexDecompositionDotNet")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("Intel Corporation")]
12[assembly: AssemblyProduct("ConvexDecompositionDotNet")]
13[assembly: AssemblyCopyright("Copyright © Intel Corporation 2010")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("2a1c9467-1a17-4c8d-bf9f-4b4d86dd0cbb")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32// You can specify all the values or you can default the Build and Revision Numbers
33// by using the '*' as shown below:
34// [assembly: AssemblyVersion("1.0.*")]
35[assembly: AssemblyVersion("0.7.5.*")]
36[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs
deleted file mode 100644
index 0ba8f17..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Quaternion.cs
+++ /dev/null
@@ -1,209 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class Quaternion : float4
33 {
34 public Quaternion()
35 {
36 x = y = z = 0.0f;
37 w = 1.0f;
38 }
39
40 public Quaternion(float3 v, float t)
41 {
42 v = float3.normalize(v);
43 w = (float)Math.Cos(t / 2.0f);
44 v = v * (float)Math.Sin(t / 2.0f);
45 x = v.x;
46 y = v.y;
47 z = v.z;
48 }
49
50 public Quaternion(float _x, float _y, float _z, float _w)
51 {
52 x = _x;
53 y = _y;
54 z = _z;
55 w = _w;
56 }
57
58 public float angle()
59 {
60 return (float)Math.Acos(w) * 2.0f;
61 }
62
63 public float3 axis()
64 {
65 float3 a = new float3(x, y, z);
66 if (Math.Abs(angle()) < 0.0000001f)
67 return new float3(1f, 0f, 0f);
68 return a * (1 / (float)Math.Sin(angle() / 2.0f));
69 }
70
71 public float3 xdir()
72 {
73 return new float3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
74 }
75
76 public float3 ydir()
77 {
78 return new float3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
79 }
80
81 public float3 zdir()
82 {
83 return new float3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
84 }
85
86 public float3x3 getmatrix()
87 {
88 return new float3x3(xdir(), ydir(), zdir());
89 }
90
91 public static implicit operator float3x3(Quaternion q)
92 {
93 return q.getmatrix();
94 }
95
96 public static Quaternion operator *(Quaternion a, Quaternion b)
97 {
98 Quaternion c = new Quaternion();
99 c.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
100 c.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
101 c.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
102 c.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
103 return c;
104 }
105
106 public static float3 operator *(Quaternion q, float3 v)
107 {
108 // The following is equivalent to:
109 //return (q.getmatrix() * v);
110 float qx2 = q.x * q.x;
111 float qy2 = q.y * q.y;
112 float qz2 = q.z * q.z;
113
114 float qxqy = q.x * q.y;
115 float qxqz = q.x * q.z;
116 float qxqw = q.x * q.w;
117 float qyqz = q.y * q.z;
118 float qyqw = q.y * q.w;
119 float qzqw = q.z * q.w;
120 return new float3((1 - 2 * (qy2 + qz2)) * v.x + (2 * (qxqy - qzqw)) * v.y + (2 * (qxqz + qyqw)) * v.z, (2 * (qxqy + qzqw)) * v.x + (1 - 2 * (qx2 + qz2)) * v.y + (2 * (qyqz - qxqw)) * v.z, (2 * (qxqz - qyqw)) * v.x + (2 * (qyqz + qxqw)) * v.y + (1 - 2 * (qx2 + qy2)) * v.z);
121 }
122
123 public static Quaternion operator +(Quaternion a, Quaternion b)
124 {
125 return new Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
126 }
127
128 public static Quaternion operator *(Quaternion a, float b)
129 {
130 return new Quaternion(a.x *b, a.y *b, a.z *b, a.w *b);
131 }
132
133 public static Quaternion normalize(Quaternion a)
134 {
135 float m = (float)Math.Sqrt(a.w * a.w + a.x * a.x + a.y * a.y + a.z * a.z);
136 if (m < 0.000000001f)
137 {
138 a.w = 1;
139 a.x = a.y = a.z = 0;
140 return a;
141 }
142 return a * (1f / m);
143 }
144
145 public static float dot(Quaternion a, Quaternion b)
146 {
147 return (a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z);
148 }
149
150 public static Quaternion slerp(Quaternion a, Quaternion b, float interp)
151 {
152 if (dot(a, b) < 0.0)
153 {
154 a.w = -a.w;
155 a.x = -a.x;
156 a.y = -a.y;
157 a.z = -a.z;
158 }
159 float d = dot(a, b);
160 if (d >= 1.0)
161 {
162 return a;
163 }
164 float theta = (float)Math.Acos(d);
165 if (theta == 0.0f)
166 {
167 return (a);
168 }
169 return a * ((float)Math.Sin(theta - interp * theta) / (float)Math.Sin(theta)) + b * ((float)Math.Sin(interp * theta) / (float)Math.Sin(theta));
170 }
171
172 public static Quaternion Interpolate(Quaternion q0, Quaternion q1, float alpha)
173 {
174 return slerp(q0, q1, alpha);
175 }
176
177 public static Quaternion Inverse(Quaternion q)
178 {
179 return new Quaternion(-q.x, -q.y, -q.z, q.w);
180 }
181
182 public static Quaternion YawPitchRoll(float yaw, float pitch, float roll)
183 {
184 roll *= (3.14159264f / 180.0f);
185 yaw *= (3.14159264f / 180.0f);
186 pitch *= (3.14159264f / 180.0f);
187 return new Quaternion(new float3(0.0f, 0.0f, 1.0f), yaw) * new Quaternion(new float3(1.0f, 0.0f, 0.0f), pitch) * new Quaternion(new float3(0.0f, 1.0f, 0.0f), roll);
188 }
189
190 public static float Yaw(Quaternion q)
191 {
192 float3 v = q.ydir();
193 return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f);
194 }
195
196 public static float Pitch(Quaternion q)
197 {
198 float3 v = q.ydir();
199 return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f);
200 }
201
202 public static float Roll(Quaternion q)
203 {
204 q = new Quaternion(new float3(0.0f, 0.0f, 1.0f), -Yaw(q) * (3.14159264f / 180.0f)) * q;
205 q = new Quaternion(new float3(1.0f, 0.0f, 0.0f), -Pitch(q) * (3.14159264f / 180.0f)) * q;
206 return (float)Math.Atan2(-q.xdir().z, q.xdir().x) * (180.0f / 3.14159264f);
207 }
208 }
209}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt b/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt
deleted file mode 100644
index fc53ae7..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/README.txt
+++ /dev/null
@@ -1,7 +0,0 @@
1ConvexDecompositionDotNet
2=========================
3
4A C# port of the ConvexDecomposition library by John W. Ratcliff and Stan Melax.
5The original C++ version is available at <http://codesuppository.googlecode.com/>.
6See the blog post at <http://codesuppository.blogspot.com/2006/08/approximate-convexdecomposition.html>
7for a thorough explanation of generating convex hulls from concave meshes.
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs
deleted file mode 100644
index 9f06a9a..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/SplitPlane.cs
+++ /dev/null
@@ -1,265 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class Rect3d
34 {
35 public float[] mMin = new float[3];
36 public float[] mMax = new float[3];
37
38 public Rect3d()
39 {
40 }
41
42 public Rect3d(float[] bmin, float[] bmax)
43 {
44 mMin[0] = bmin[0];
45 mMin[1] = bmin[1];
46 mMin[2] = bmin[2];
47
48 mMax[0] = bmax[0];
49 mMax[1] = bmax[1];
50 mMax[2] = bmax[2];
51 }
52
53 public void SetMin(float[] bmin)
54 {
55 mMin[0] = bmin[0];
56 mMin[1] = bmin[1];
57 mMin[2] = bmin[2];
58 }
59
60 public void SetMax(float[] bmax)
61 {
62 mMax[0] = bmax[0];
63 mMax[1] = bmax[1];
64 mMax[2] = bmax[2];
65 }
66
67 public void SetMin(float x, float y, float z)
68 {
69 mMin[0] = x;
70 mMin[1] = y;
71 mMin[2] = z;
72 }
73
74 public void SetMax(float x, float y, float z)
75 {
76 mMax[0] = x;
77 mMax[1] = y;
78 mMax[2] = z;
79 }
80 }
81
82 public static class SplitPlane
83 {
84 public static bool computeSplitPlane(List<float3> vertices, List<int> indices, ref float4 plane)
85 {
86 float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
87 float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue };
88
89 for (int i = 0; i < vertices.Count; i++)
90 {
91 float3 p = vertices[i];
92
93 if (p[0] < bmin[0])
94 bmin[0] = p[0];
95 if (p[1] < bmin[1])
96 bmin[1] = p[1];
97 if (p[2] < bmin[2])
98 bmin[2] = p[2];
99
100 if (p[0] > bmax[0])
101 bmax[0] = p[0];
102 if (p[1] > bmax[1])
103 bmax[1] = p[1];
104 if (p[2] > bmax[2])
105 bmax[2] = p[2];
106 }
107
108 float dx = bmax[0] - bmin[0];
109 float dy = bmax[1] - bmin[1];
110 float dz = bmax[2] - bmin[2];
111
112 float laxis = dx;
113
114 int axis = 0;
115
116 if (dy > dx)
117 {
118 axis = 1;
119 laxis = dy;
120 }
121
122 if (dz > dx && dz > dy)
123 {
124 axis = 2;
125 laxis = dz;
126 }
127
128 float[] p1 = new float[3];
129 float[] p2 = new float[3];
130 float[] p3 = new float[3];
131
132 p3[0] = p2[0] = p1[0] = bmin[0] + dx * 0.5f;
133 p3[1] = p2[1] = p1[1] = bmin[1] + dy * 0.5f;
134 p3[2] = p2[2] = p1[2] = bmin[2] + dz * 0.5f;
135
136 Rect3d b = new Rect3d(bmin, bmax);
137
138 Rect3d b1 = new Rect3d();
139 Rect3d b2 = new Rect3d();
140
141 splitRect(axis, b, b1, b2, p1);
142
143 switch (axis)
144 {
145 case 0:
146 p2[1] = bmin[1];
147 p2[2] = bmin[2];
148
149 if (dz > dy)
150 {
151 p3[1] = bmax[1];
152 p3[2] = bmin[2];
153 }
154 else
155 {
156 p3[1] = bmin[1];
157 p3[2] = bmax[2];
158 }
159
160 break;
161 case 1:
162 p2[0] = bmin[0];
163 p2[2] = bmin[2];
164
165 if (dx > dz)
166 {
167 p3[0] = bmax[0];
168 p3[2] = bmin[2];
169 }
170 else
171 {
172 p3[0] = bmin[0];
173 p3[2] = bmax[2];
174 }
175
176 break;
177 case 2:
178 p2[0] = bmin[0];
179 p2[1] = bmin[1];
180
181 if (dx > dy)
182 {
183 p3[0] = bmax[0];
184 p3[1] = bmin[1];
185 }
186 else
187 {
188 p3[0] = bmin[0];
189 p3[1] = bmax[1];
190 }
191
192 break;
193 }
194
195 computePlane(p1, p2, p3, plane);
196
197 return true;
198 }
199
200 internal static void computePlane(float[] A, float[] B, float[] C, float4 plane)
201 {
202 float vx = (B[0] - C[0]);
203 float vy = (B[1] - C[1]);
204 float vz = (B[2] - C[2]);
205
206 float wx = (A[0] - B[0]);
207 float wy = (A[1] - B[1]);
208 float wz = (A[2] - B[2]);
209
210 float vw_x = vy * wz - vz * wy;
211 float vw_y = vz * wx - vx * wz;
212 float vw_z = vx * wy - vy * wx;
213
214 float mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
215
216 if (mag < 0.000001f)
217 {
218 mag = 0;
219 }
220 else
221 {
222 mag = 1.0f / mag;
223 }
224
225 float x = vw_x * mag;
226 float y = vw_y * mag;
227 float z = vw_z * mag;
228
229 float D = 0.0f - ((x * A[0]) + (y * A[1]) + (z * A[2]));
230
231 plane.x = x;
232 plane.y = y;
233 plane.z = z;
234 plane.w = D;
235 }
236
237 public static void splitRect(int axis, Rect3d source, Rect3d b1, Rect3d b2, float[] midpoint)
238 {
239 switch (axis)
240 {
241 case 0:
242 b1.SetMin(source.mMin);
243 b1.SetMax(midpoint[0], source.mMax[1], source.mMax[2]);
244
245 b2.SetMin(midpoint[0], source.mMin[1], source.mMin[2]);
246 b2.SetMax(source.mMax);
247 break;
248 case 1:
249 b1.SetMin(source.mMin);
250 b1.SetMax(source.mMax[0], midpoint[1], source.mMax[2]);
251
252 b2.SetMin(source.mMin[0], midpoint[1], source.mMin[2]);
253 b2.SetMax(source.mMax);
254 break;
255 case 2:
256 b1.SetMin(source.mMin);
257 b1.SetMax(source.mMax[0], source.mMax[1], midpoint[2]);
258
259 b2.SetMin(source.mMin[0], source.mMin[1], midpoint[2]);
260 b2.SetMax(source.mMax);
261 break;
262 }
263 }
264 }
265}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs
deleted file mode 100644
index 6f17c9f..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/VertexLookup.cs
+++ /dev/null
@@ -1,70 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
32{
33 public class VertexPool
34 {
35 private List<float3> mVertices = new List<float3>();
36 private Dictionary<float3, int> mIndices = new Dictionary<float3, int>();
37
38 public int getIndex(float3 vtx)
39 {
40 int idx;
41 if (mIndices.TryGetValue(vtx, out idx))
42 return idx;
43
44 idx = mVertices.Count;
45 mVertices.Add(vtx);
46 mIndices.Add(vtx, idx);
47 return idx;
48 }
49
50 public float3 Get(int idx)
51 {
52 return mVertices[idx];
53 }
54
55 public int GetSize()
56 {
57 return mVertices.Count;
58 }
59
60 public List<float3> GetVertices()
61 {
62 return mVertices;
63 }
64
65 public void Clear()
66 {
67 mVertices.Clear();
68 }
69 }
70}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs
deleted file mode 100644
index ce88fc8..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float2.cs
+++ /dev/null
@@ -1,70 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class float2
33 {
34 public float x;
35 public float y;
36
37 public float2()
38 {
39 }
40
41 public float2(float _x, float _y)
42 {
43 x = _x;
44 y = _y;
45 }
46
47 public float this[int i]
48 {
49 get
50 {
51 switch (i)
52 {
53 case 0: return x;
54 case 1: return y;
55 }
56 throw new ArgumentOutOfRangeException();
57 }
58 }
59
60 public static float2 operator -(float2 a, float2 b)
61 {
62 return new float2(a.x - b.x, a.y - b.y);
63 }
64
65 public static float2 operator +(float2 a, float2 b)
66 {
67 return new float2(a.x + b.x, a.y + b.y);
68 }
69 }
70}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs
deleted file mode 100644
index 4389114..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3.cs
+++ /dev/null
@@ -1,444 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class float3 : IEquatable<float3>
33 {
34 public float x;
35 public float y;
36 public float z;
37
38 public float3()
39 {
40 x = 0;
41 y = 0;
42 z = 0;
43 }
44
45 public float3(float _x, float _y, float _z)
46 {
47 x = _x;
48 y = _y;
49 z = _z;
50 }
51
52 public float3(float3 f)
53 {
54 x = f.x;
55 y = f.y;
56 z = f.z;
57 }
58
59 public float this[int i]
60 {
61 get
62 {
63 switch (i)
64 {
65 case 0: return x;
66 case 1: return y;
67 case 2: return z;
68 }
69 throw new ArgumentOutOfRangeException();
70 }
71 }
72
73 public float Distance(float3 a)
74 {
75 float3 d = new float3(a.x - x, a.y - y, a.z - z);
76 return d.Length();
77 }
78
79 public float Distance2(float3 a)
80 {
81 float dx = a.x - x;
82 float dy = a.y - y;
83 float dz = a.z - z;
84 return dx * dx + dy * dy + dz * dz;
85 }
86
87 public float Length()
88 {
89 return (float)Math.Sqrt(x * x + y * y + z * z);
90 }
91
92 public float Area(float3 p1, float3 p2)
93 {
94 float A = Partial(p1);
95 A += p1.Partial(p2);
96 A += p2.Partial(this);
97 return A * 0.5f;
98 }
99
100 public float Partial(float3 p)
101 {
102 return (x * p.y) - (p.x * y);
103 }
104
105 // Given a point and a line (defined by two points), compute the closest point
106 // in the line. (The line is treated as infinitely long.)
107 public void NearestPointInLine(float3 point, float3 line0, float3 line1)
108 {
109 float3 nearestPoint = new float3();
110 float3 lineDelta = line1 - line0;
111
112 // Handle degenerate lines
113 if (lineDelta == float3.Zero)
114 {
115 nearestPoint = line0;
116 }
117 else
118 {
119 float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta);
120 nearestPoint = line0 + lineDelta * delta;
121 }
122
123 this.x = nearestPoint.x;
124 this.y = nearestPoint.y;
125 this.z = nearestPoint.z;
126 }
127
128 // Given a point and a line segment (defined by two points), compute the closest point
129 // in the line. Cap the point at the endpoints of the line segment.
130 public void NearestPointInLineSegment(float3 point, float3 line0, float3 line1)
131 {
132 float3 nearestPoint = new float3();
133 float3 lineDelta = line1 - line0;
134
135 // Handle degenerate lines
136 if (lineDelta == Zero)
137 {
138 nearestPoint = line0;
139 }
140 else
141 {
142 float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta);
143
144 // Clamp the point to conform to the segment's endpoints
145 if (delta < 0)
146 delta = 0;
147 else if (delta > 1)
148 delta = 1;
149
150 nearestPoint = line0 + lineDelta * delta;
151 }
152
153 this.x = nearestPoint.x;
154 this.y = nearestPoint.y;
155 this.z = nearestPoint.z;
156 }
157
158 // Given a point and a triangle (defined by three points), compute the closest point
159 // in the triangle. Clamp the point so it's confined to the area of the triangle.
160 public void NearestPointInTriangle(float3 point, float3 triangle0, float3 triangle1, float3 triangle2)
161 {
162 float3 nearestPoint = new float3();
163
164 float3 lineDelta0 = triangle1 - triangle0;
165 float3 lineDelta1 = triangle2 - triangle0;
166
167 // Handle degenerate triangles
168 if ((lineDelta0 == Zero) || (lineDelta1 == Zero))
169 {
170 nearestPoint.NearestPointInLineSegment(point, triangle1, triangle2);
171 }
172 else if (lineDelta0 == lineDelta1)
173 {
174 nearestPoint.NearestPointInLineSegment(point, triangle0, triangle1);
175 }
176 else
177 {
178 float3[] axis = new float3[3] { new float3(), new float3(), new float3() };
179 axis[0].NearestPointInLine(triangle0, triangle1, triangle2);
180 axis[1].NearestPointInLine(triangle1, triangle0, triangle2);
181 axis[2].NearestPointInLine(triangle2, triangle0, triangle1);
182
183 float3 axisDot = new float3();
184 axisDot.x = dot(triangle0 - axis[0], point - axis[0]);
185 axisDot.y = dot(triangle1 - axis[1], point - axis[1]);
186 axisDot.z = dot(triangle2 - axis[2], point - axis[2]);
187
188 bool bForce = true;
189 float bestMagnitude2 = 0;
190 float closeMagnitude2;
191 float3 closePoint = new float3();
192
193 if (axisDot.x < 0f)
194 {
195 closePoint.NearestPointInLineSegment(point, triangle1, triangle2);
196 closeMagnitude2 = point.Distance2(closePoint);
197 if (bForce || (bestMagnitude2 > closeMagnitude2))
198 {
199 bForce = false;
200 bestMagnitude2 = closeMagnitude2;
201 nearestPoint = closePoint;
202 }
203 }
204 if (axisDot.y < 0f)
205 {
206 closePoint.NearestPointInLineSegment(point, triangle0, triangle2);
207 closeMagnitude2 = point.Distance2(closePoint);
208 if (bForce || (bestMagnitude2 > closeMagnitude2))
209 {
210 bForce = false;
211 bestMagnitude2 = closeMagnitude2;
212 nearestPoint = closePoint;
213 }
214 }
215 if (axisDot.z < 0f)
216 {
217 closePoint.NearestPointInLineSegment(point, triangle0, triangle1);
218 closeMagnitude2 = point.Distance2(closePoint);
219 if (bForce || (bestMagnitude2 > closeMagnitude2))
220 {
221 bForce = false;
222 bestMagnitude2 = closeMagnitude2;
223 nearestPoint = closePoint;
224 }
225 }
226
227 // If bForce is true at this point, it means the nearest point lies
228 // inside the triangle; use the nearest-point-on-a-plane equation
229 if (bForce)
230 {
231 float3 normal;
232
233 // Get the normal of the polygon (doesn't have to be a unit vector)
234 normal = float3.cross(lineDelta0, lineDelta1);
235
236 float3 pointDelta = point - triangle0;
237 float delta = float3.dot(normal, pointDelta) / float3.dot(normal, normal);
238
239 nearestPoint = point - normal * delta;
240 }
241 }
242
243 this.x = nearestPoint.x;
244 this.y = nearestPoint.y;
245 this.z = nearestPoint.z;
246 }
247
248 public static float3 operator +(float3 a, float3 b)
249 {
250 return new float3(a.x + b.x, a.y + b.y, a.z + b.z);
251 }
252
253 public static float3 operator -(float3 a, float3 b)
254 {
255 return new float3(a.x - b.x, a.y - b.y, a.z - b.z);
256 }
257
258 public static float3 operator -(float3 a, float s)
259 {
260 return new float3(a.x - s, a.y - s, a.z - s);
261 }
262
263 public static float3 operator -(float3 v)
264 {
265 return new float3(-v.x, -v.y, -v.z);
266 }
267
268 public static float3 operator *(float3 v, float s)
269 {
270 return new float3(v.x * s, v.y * s, v.z * s);
271 }
272
273 public static float3 operator *(float s, float3 v)
274 {
275 return new float3(v.x * s, v.y * s, v.z * s);
276 }
277
278 public static float3 operator *(float3 v, float3x3 m)
279 {
280 return new float3((m.x.x * v.x + m.y.x * v.y + m.z.x * v.z), (m.x.y * v.x + m.y.y * v.y + m.z.y * v.z), (m.x.z * v.x + m.y.z * v.y + m.z.z * v.z));
281 }
282
283 public static float3 operator *(float3x3 m, float3 v)
284 {
285 return new float3(dot(m.x, v), dot(m.y, v), dot(m.z, v));
286 }
287
288 public static float3 operator /(float3 v, float s)
289 {
290 float sinv = 1.0f / s;
291 return new float3(v.x * sinv, v.y * sinv, v.z * sinv);
292 }
293
294 public bool Equals(float3 other)
295 {
296 return this == other;
297 }
298
299 public override bool Equals(object obj)
300 {
301 float3 f = obj as float3;
302 if (f == null)
303 return false;
304
305 return this == f;
306 }
307
308 public override int GetHashCode()
309 {
310 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
311 }
312
313 public static bool operator ==(float3 a, float3 b)
314 {
315 // If both are null, or both are same instance, return true.
316 if (System.Object.ReferenceEquals(a, b))
317 return true;
318 // If one is null, but not both, return false.
319 if (((object)a == null) || ((object)b == null))
320 return false;
321
322 return (a.x == b.x && a.y == b.y && a.z == b.z);
323 }
324
325 public static bool operator !=(float3 a, float3 b)
326 {
327 return (a.x != b.x || a.y != b.y || a.z != b.z);
328 }
329
330 public static float dot(float3 a, float3 b)
331 {
332 return a.x * b.x + a.y * b.y + a.z * b.z;
333 }
334
335 public static float3 cmul(float3 v1, float3 v2)
336 {
337 return new float3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
338 }
339
340 public static float3 cross(float3 a, float3 b)
341 {
342 return new float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
343 }
344
345 public static float3 Interpolate(float3 v0, float3 v1, float alpha)
346 {
347 return v0 * (1 - alpha) + v1 * alpha;
348 }
349
350 public static float3 Round(float3 a, int digits)
351 {
352 return new float3((float)Math.Round(a.x, digits), (float)Math.Round(a.y, digits), (float)Math.Round(a.z, digits));
353 }
354
355 public static float3 VectorMax(float3 a, float3 b)
356 {
357 return new float3(Math.Max(a.x, b.x), Math.Max(a.y, b.y), Math.Max(a.z, b.z));
358 }
359
360 public static float3 VectorMin(float3 a, float3 b)
361 {
362 return new float3(Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Min(a.z, b.z));
363 }
364
365 public static float3 vabs(float3 v)
366 {
367 return new float3(Math.Abs(v.x), Math.Abs(v.y), Math.Abs(v.z));
368 }
369
370 public static float magnitude(float3 v)
371 {
372 return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
373 }
374
375 public static float3 normalize(float3 v)
376 {
377 float d = magnitude(v);
378 if (d == 0)
379 d = 0.1f;
380 d = 1 / d;
381 return new float3(v.x * d, v.y * d, v.z * d);
382 }
383
384 public static float3 safenormalize(float3 v)
385 {
386 if (magnitude(v) <= 0.0f)
387 return new float3(1, 0, 0);
388 else
389 return normalize(v);
390 }
391
392 public static float Yaw(float3 v)
393 {
394 return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f);
395 }
396
397 public static float Pitch(float3 v)
398 {
399 return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f);
400 }
401
402 public float ComputePlane(float3 A, float3 B, float3 C)
403 {
404 float vx, vy, vz, wx, wy, wz, vw_x, vw_y, vw_z, mag;
405
406 vx = (B.x - C.x);
407 vy = (B.y - C.y);
408 vz = (B.z - C.z);
409
410 wx = (A.x - B.x);
411 wy = (A.y - B.y);
412 wz = (A.z - B.z);
413
414 vw_x = vy * wz - vz * wy;
415 vw_y = vz * wx - vx * wz;
416 vw_z = vx * wy - vy * wx;
417
418 mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
419
420 if (mag < 0.000001f)
421 {
422 mag = 0;
423 }
424 else
425 {
426 mag = 1.0f / mag;
427 }
428
429 x = vw_x * mag;
430 y = vw_y * mag;
431 z = vw_z * mag;
432
433 float D = 0.0f - ((x * A.x) + (y * A.y) + (z * A.z));
434 return D;
435 }
436
437 public override string ToString()
438 {
439 return String.Format("<{0}, {1}, {2}>", x, y, z);
440 }
441
442 public static readonly float3 Zero = new float3();
443 }
444}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs
deleted file mode 100644
index 76cf063..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float3x3.cs
+++ /dev/null
@@ -1,195 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31
32namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
33{
34 public class float3x3
35 {
36 public float3 x = new float3();
37 public float3 y = new float3();
38 public float3 z = new float3();
39
40 public float3x3()
41 {
42 }
43
44 public float3x3(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz)
45 {
46 x = new float3(xx, xy, xz);
47 y = new float3(yx, yy, yz);
48 z = new float3(zx, zy, zz);
49 }
50
51 public float3x3(float3 _x, float3 _y, float3 _z)
52 {
53 x = new float3(_x);
54 y = new float3(_y);
55 z = new float3(_z);
56 }
57
58 public float3 this[int i]
59 {
60 get
61 {
62 switch (i)
63 {
64 case 0: return x;
65 case 1: return y;
66 case 2: return z;
67 }
68 throw new ArgumentOutOfRangeException();
69 }
70 }
71
72 public float this[int i, int j]
73 {
74 get
75 {
76 switch (i)
77 {
78 case 0:
79 switch (j)
80 {
81 case 0: return x.x;
82 case 1: return x.y;
83 case 2: return x.z;
84 }
85 break;
86 case 1:
87 switch (j)
88 {
89 case 0: return y.x;
90 case 1: return y.y;
91 case 2: return y.z;
92 }
93 break;
94 case 2:
95 switch (j)
96 {
97 case 0: return z.x;
98 case 1: return z.y;
99 case 2: return z.z;
100 }
101 break;
102 }
103 throw new ArgumentOutOfRangeException();
104 }
105 set
106 {
107 switch (i)
108 {
109 case 0:
110 switch (j)
111 {
112 case 0: x.x = value; return;
113 case 1: x.y = value; return;
114 case 2: x.z = value; return;
115 }
116 break;
117 case 1:
118 switch (j)
119 {
120 case 0: y.x = value; return;
121 case 1: y.y = value; return;
122 case 2: y.z = value; return;
123 }
124 break;
125 case 2:
126 switch (j)
127 {
128 case 0: z.x = value; return;
129 case 1: z.y = value; return;
130 case 2: z.z = value; return;
131 }
132 break;
133 }
134 throw new ArgumentOutOfRangeException();
135 }
136 }
137
138 public static float3x3 Transpose(float3x3 m)
139 {
140 return new float3x3(new float3(m.x.x, m.y.x, m.z.x), new float3(m.x.y, m.y.y, m.z.y), new float3(m.x.z, m.y.z, m.z.z));
141 }
142
143 public static float3x3 operator *(float3x3 a, float3x3 b)
144 {
145 return new float3x3(a.x * b, a.y * b, a.z * b);
146 }
147
148 public static float3x3 operator *(float3x3 a, float s)
149 {
150 return new float3x3(a.x * s, a.y * s, a.z * s);
151 }
152
153 public static float3x3 operator /(float3x3 a, float s)
154 {
155 float t = 1f / s;
156 return new float3x3(a.x * t, a.y * t, a.z * t);
157 }
158
159 public static float3x3 operator +(float3x3 a, float3x3 b)
160 {
161 return new float3x3(a.x + b.x, a.y + b.y, a.z + b.z);
162 }
163
164 public static float3x3 operator -(float3x3 a, float3x3 b)
165 {
166 return new float3x3(a.x - b.x, a.y - b.y, a.z - b.z);
167 }
168
169 public static float Determinant(float3x3 m)
170 {
171 return m.x.x * m.y.y * m.z.z + m.y.x * m.z.y * m.x.z + m.z.x * m.x.y * m.y.z - m.x.x * m.z.y * m.y.z - m.y.x * m.x.y * m.z.z - m.z.x * m.y.y * m.x.z;
172 }
173
174 public static float3x3 Inverse(float3x3 a)
175 {
176 float3x3 b = new float3x3();
177 float d = Determinant(a);
178 Debug.Assert(d != 0);
179 for (int i = 0; i < 3; i++)
180 {
181 for (int j = 0; j < 3; j++)
182 {
183 int i1 = (i + 1) % 3;
184 int i2 = (i + 2) % 3;
185 int j1 = (j + 1) % 3;
186 int j2 = (j + 2) % 3;
187
188 // reverse indexs i&j to take transpose
189 b[i, j] = (a[i1][j1] * a[i2][j2] - a[i1][j2] * a[i2][j1]) / d;
190 }
191 }
192 return b;
193 }
194 }
195}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs
deleted file mode 100644
index fa60876..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4.cs
+++ /dev/null
@@ -1,170 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class float4
33 {
34 public float x;
35 public float y;
36 public float z;
37 public float w;
38
39 public float4()
40 {
41 x = 0;
42 y = 0;
43 z = 0;
44 w = 0;
45 }
46
47 public float4(float _x, float _y, float _z, float _w)
48 {
49 x = _x;
50 y = _y;
51 z = _z;
52 w = _w;
53 }
54
55 public float4(float3 v, float _w)
56 {
57 x = v.x;
58 y = v.y;
59 z = v.z;
60 w = _w;
61 }
62
63 public float4(float4 f)
64 {
65 x = f.x;
66 y = f.y;
67 z = f.z;
68 w = f.w;
69 }
70
71 public float this[int i]
72 {
73 get
74 {
75 switch (i)
76 {
77 case 0: return x;
78 case 1: return y;
79 case 2: return z;
80 case 3: return w;
81 }
82 throw new ArgumentOutOfRangeException();
83 }
84 }
85
86 public float3 xyz()
87 {
88 return new float3(x, y, z);
89 }
90
91 public void setxyz(float3 xyz)
92 {
93 x = xyz.x;
94 y = xyz.y;
95 z = xyz.z;
96 }
97
98 public override int GetHashCode()
99 {
100 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
101 }
102
103 public override bool Equals(object obj)
104 {
105 float4 f = obj as float4;
106 if (f == null)
107 return false;
108
109 return this == f;
110 }
111
112 public static float4 Homogenize(float3 v3)
113 {
114 return Homogenize(v3, 1.0f);
115 }
116
117 //C++ TO C# CONVERTER NOTE: C# does not allow default values for parameters. Overloaded methods are inserted above.
118 //ORIGINAL LINE: float4 Homogenize(const float3 &v3, const float &w =1.0f)
119 public static float4 Homogenize(float3 v3, float w)
120 {
121 return new float4(v3.x, v3.y, v3.z, w);
122 }
123
124 public static float4 cmul(float4 a, float4 b)
125 {
126 return new float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
127 }
128
129 public static float4 operator +(float4 a, float4 b)
130 {
131 return new float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
132 }
133 public static float4 operator -(float4 a, float4 b)
134 {
135 return new float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
136 }
137
138 public static float4 operator *(float4 v, float4x4 m)
139 {
140 return v.x * m.x + v.y * m.y + v.z * m.z + v.w * m.w; // yes this actually works
141 }
142
143 public static bool operator ==(float4 a, float4 b)
144 {
145 // If both are null, or both are same instance, return true.
146 if (System.Object.ReferenceEquals(a, b))
147 return true;
148 // If one is null, but not both, return false.
149 if (((object)a == null) || ((object)b == null))
150 return false;
151
152 return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
153 }
154
155 public static bool operator !=(float4 a, float4 b)
156 {
157 return !(a == b);
158 }
159
160 public static float4 operator *(float4 v, float s)
161 {
162 return new float4(v.x * s, v.y * s, v.z * s, v.w * s);
163 }
164
165 public static float4 operator *(float s, float4 v)
166 {
167 return new float4(v.x * s, v.y * s, v.z * s, v.w * s);
168 }
169 }
170}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs
deleted file mode 100644
index 7d1592f..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/float4x4.cs
+++ /dev/null
@@ -1,284 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
34{
35 public class float4x4
36 {
37 public float4 x = new float4();
38 public float4 y = new float4();
39 public float4 z = new float4();
40 public float4 w = new float4();
41
42 public float4x4()
43 {
44 }
45
46 public float4x4(float4 _x, float4 _y, float4 _z, float4 _w)
47 {
48 x = new float4(_x);
49 y = new float4(_y);
50 z = new float4(_z);
51 w = new float4(_w);
52 }
53
54 public float4x4(
55 float m00, float m01, float m02, float m03,
56 float m10, float m11, float m12, float m13,
57 float m20, float m21, float m22, float m23,
58 float m30, float m31, float m32, float m33)
59 {
60 x = new float4(m00, m01, m02, m03);
61 y = new float4(m10, m11, m12, m13);
62 z = new float4(m20, m21, m22, m23);
63 w = new float4(m30, m31, m32, m33);
64 }
65
66 public float4x4(float4x4 m)
67 {
68 x = new float4(m.x);
69 y = new float4(m.y);
70 z = new float4(m.z);
71 w = new float4(m.w);
72 }
73
74 public float4 this[int i]
75 {
76 get
77 {
78 switch (i)
79 {
80 case 0: return x;
81 case 1: return y;
82 case 2: return z;
83 case 3: return w;
84 }
85 throw new ArgumentOutOfRangeException();
86 }
87 set
88 {
89 switch (i)
90 {
91 case 0: x = value; return;
92 case 1: y = value; return;
93 case 2: z = value; return;
94 case 3: w = value; return;
95 }
96 throw new ArgumentOutOfRangeException();
97 }
98 }
99
100 public override int GetHashCode()
101 {
102 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
103 }
104
105 public override bool Equals(object obj)
106 {
107 float4x4 m = obj as float4x4;
108 if (m == null)
109 return false;
110
111 return this == m;
112 }
113
114 public static float4x4 operator *(float4x4 a, float4x4 b)
115 {
116 return new float4x4(a.x * b, a.y * b, a.z * b, a.w * b);
117 }
118
119 public static bool operator ==(float4x4 a, float4x4 b)
120 {
121 return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
122 }
123
124 public static bool operator !=(float4x4 a, float4x4 b)
125 {
126 return !(a == b);
127 }
128
129 public static float4x4 Inverse(float4x4 m)
130 {
131 float4x4 d = new float4x4();
132 //float dst = d.x.x;
133 float[] tmp = new float[12]; // temp array for pairs
134 float[] src = new float[16]; // array of transpose source matrix
135 float det; // determinant
136 // transpose matrix
137 for (int i = 0; i < 4; i++)
138 {
139 src[i] = m[i].x;
140 src[i + 4] = m[i].y;
141 src[i + 8] = m[i].z;
142 src[i + 12] = m[i].w;
143 }
144 // calculate pairs for first 8 elements (cofactors)
145 tmp[0] = src[10] * src[15];
146 tmp[1] = src[11] * src[14];
147 tmp[2] = src[9] * src[15];
148 tmp[3] = src[11] * src[13];
149 tmp[4] = src[9] * src[14];
150 tmp[5] = src[10] * src[13];
151 tmp[6] = src[8] * src[15];
152 tmp[7] = src[11] * src[12];
153 tmp[8] = src[8] * src[14];
154 tmp[9] = src[10] * src[12];
155 tmp[10] = src[8] * src[13];
156 tmp[11] = src[9] * src[12];
157 // calculate first 8 elements (cofactors)
158 d.x.x = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7];
159 d.x.x -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7];
160 d.x.y = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7];
161 d.x.y -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7];
162 d.x.z = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7];
163 d.x.z -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7];
164 d.x.w = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6];
165 d.x.w -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6];
166 d.y.x = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3];
167 d.y.x -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3];
168 d.y.y = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3];
169 d.y.y -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3];
170 d.y.z = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3];
171 d.y.z -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3];
172 d.y.w = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2];
173 d.y.w -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2];
174 // calculate pairs for second 8 elements (cofactors)
175 tmp[0] = src[2]*src[7];
176 tmp[1] = src[3]*src[6];
177 tmp[2] = src[1]*src[7];
178 tmp[3] = src[3]*src[5];
179 tmp[4] = src[1]*src[6];
180 tmp[5] = src[2]*src[5];
181 tmp[6] = src[0]*src[7];
182 tmp[7] = src[3]*src[4];
183 tmp[8] = src[0]*src[6];
184 tmp[9] = src[2]*src[4];
185 tmp[10] = src[0]*src[5];
186 tmp[11] = src[1]*src[4];
187 // calculate second 8 elements (cofactors)
188 d.z.x = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15];
189 d.z.x -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15];
190 d.z.y = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15];
191 d.z.y -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15];
192 d.z.z = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15];
193 d.z.z -= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15];
194 d.z.w = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14];
195 d.z.w-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14];
196 d.w.x = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9];
197 d.w.x-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10];
198 d.w.y = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10];
199 d.w.y-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8];
200 d.w.z = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8];
201 d.w.z-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9];
202 d.w.w = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9];
203 d.w.w-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8];
204 // calculate determinant
205 det = src[0] * d.x.x + src[1] * d.x.y + src[2] * d.x.z + src[3] * d.x.w;
206 // calculate matrix inverse
207 det = 1/det;
208 for (int j = 0; j < 4; j++)
209 d[j] *= det;
210 return d;
211 }
212
213 public static float4x4 MatrixRigidInverse(float4x4 m)
214 {
215 float4x4 trans_inverse = MatrixTranslation(-m.w.xyz());
216 float4x4 rot = new float4x4(m);
217 rot.w = new float4(0f, 0f, 0f, 1f);
218 return trans_inverse * MatrixTranspose(rot);
219 }
220 public static float4x4 MatrixTranspose(float4x4 m)
221 {
222 return new float4x4(m.x.x, m.y.x, m.z.x, m.w.x, m.x.y, m.y.y, m.z.y, m.w.y, m.x.z, m.y.z, m.z.z, m.w.z, m.x.w, m.y.w, m.z.w, m.w.w);
223 }
224 public static float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf)
225 {
226 float h = 1.0f / (float)Math.Tan(fovy / 2.0f); // view space height
227 float w = h / aspect; // view space width
228 return new float4x4(w, 0, 0, 0, 0, h, 0, 0, 0, 0, zf / (zn - zf), -1, 0, 0, zn * zf / (zn - zf), 0);
229 }
230 public static float4x4 MatrixTranslation(float3 t)
231 {
232 return new float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1);
233 }
234 public static float4x4 MatrixRotationZ(float angle_radians)
235 {
236 float s = (float)Math.Sin(angle_radians);
237 float c = (float)Math.Cos(angle_radians);
238 return new float4x4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
239 }
240 public static float4x4 MatrixLookAt(float3 eye, float3 at, float3 up)
241 {
242 float4x4 m = new float4x4();
243 m.w.w = 1.0f;
244 m.w.setxyz(eye);
245 m.z.setxyz(float3.normalize(eye - at));
246 m.x.setxyz(float3.normalize(float3.cross(up, m.z.xyz())));
247 m.y.setxyz(float3.cross(m.z.xyz(), m.x.xyz()));
248 return MatrixRigidInverse(m);
249 }
250
251 public static float4x4 MatrixFromQuatVec(Quaternion q, float3 v)
252 {
253 // builds a 4x4 transformation matrix based on orientation q and translation v
254 float qx2 = q.x * q.x;
255 float qy2 = q.y * q.y;
256 float qz2 = q.z * q.z;
257
258 float qxqy = q.x * q.y;
259 float qxqz = q.x * q.z;
260 float qxqw = q.x * q.w;
261 float qyqz = q.y * q.z;
262 float qyqw = q.y * q.w;
263 float qzqw = q.z * q.w;
264
265 return new float4x4(
266 1 - 2 * (qy2 + qz2),
267 2 * (qxqy + qzqw),
268 2 * (qxqz - qyqw),
269 0,
270 2 * (qxqy - qzqw),
271 1 - 2 * (qx2 + qz2),
272 2 * (qyqz + qxqw),
273 0,
274 2 * (qxqz + qyqw),
275 2 * (qyqz - qxqw),
276 1 - 2 * (qx2 + qy2),
277 0,
278 v.x,
279 v.y,
280 v.z,
281 1.0f);
282 }
283 }
284}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs
deleted file mode 100644
index 9c5760d..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int3.cs
+++ /dev/null
@@ -1,128 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class int3
33 {
34 public int x;
35 public int y;
36 public int z;
37
38 public int3()
39 {
40 }
41
42 public int3(int _x, int _y, int _z)
43 {
44 x = _x;
45 y = _y;
46 z = _z;
47 }
48
49 public int this[int i]
50 {
51 get
52 {
53 switch (i)
54 {
55 case 0: return x;
56 case 1: return y;
57 case 2: return z;
58 }
59 throw new ArgumentOutOfRangeException();
60 }
61 set
62 {
63 switch (i)
64 {
65 case 0: x = value; return;
66 case 1: y = value; return;
67 case 2: z = value; return;
68 }
69 throw new ArgumentOutOfRangeException();
70 }
71 }
72
73 public override int GetHashCode()
74 {
75 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
76 }
77
78 public override bool Equals(object obj)
79 {
80 int3 i = obj as int3;
81 if (i == null)
82 return false;
83
84 return this == i;
85 }
86
87 public static bool operator ==(int3 a, int3 b)
88 {
89 // If both are null, or both are same instance, return true.
90 if (System.Object.ReferenceEquals(a, b))
91 return true;
92 // If one is null, but not both, return false.
93 if (((object)a == null) || ((object)b == null))
94 return false;
95
96 for (int i = 0; i < 3; i++)
97 {
98 if (a[i] != b[i])
99 return false;
100 }
101 return true;
102 }
103
104 public static bool operator !=(int3 a, int3 b)
105 {
106 return !(a == b);
107 }
108
109 public static int3 roll3(int3 a)
110 {
111 int tmp = a[0];
112 a[0] = a[1];
113 a[1] = a[2];
114 a[2] = tmp;
115 return a;
116 }
117
118 public static bool isa(int3 a, int3 b)
119 {
120 return (a == b || roll3(a) == b || a == roll3(b));
121 }
122
123 public static bool b2b(int3 a, int3 b)
124 {
125 return isa(a, new int3(b[2], b[1], b[0]));
126 }
127 }
128}
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs
deleted file mode 100644
index c2b32e5..0000000
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/int4.cs
+++ /dev/null
@@ -1,66 +0,0 @@
1/* The MIT License
2 *
3 * Copyright (c) 2010 Intel Corporation.
4 * All rights reserved.
5 *
6 * Based on the convexdecomposition library from
7 * <http://codesuppository.googlecode.com> by John W. Ratcliff and Stan Melax.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Physics.ConvexDecompositionDotNet
31{
32 public class int4
33 {
34 public int x;
35 public int y;
36 public int z;
37 public int w;
38
39 public int4()
40 {
41 }
42
43 public int4(int _x, int _y, int _z, int _w)
44 {
45 x = _x;
46 y = _y;
47 z = _z;
48 w = _w;
49 }
50
51 public int this[int i]
52 {
53 get
54 {
55 switch (i)
56 {
57 case 0: return x;
58 case 1: return y;
59 case 2: return z;
60 case 3: return w;
61 }
62 throw new ArgumentOutOfRangeException();
63 }
64 }
65 }
66}
diff --git a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs
deleted file mode 100644
index 36b4235..0000000
--- a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs
+++ /dev/null
@@ -1,58 +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.Reflection;
29using System.Runtime.InteropServices;
30
31// Information about this assembly is defined by the following
32// attributes.
33//
34// change them to the information which is associated with the assembly
35// you compile.
36
37[assembly : AssemblyTitle("PhysicsManager")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("PhysicsManager")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.7.5.*")]
diff --git a/OpenSim/Region/Physics/Manager/CollisionLocker.cs b/OpenSim/Region/Physics/Manager/CollisionLocker.cs
deleted file mode 100644
index cace4e4..0000000
--- a/OpenSim/Region/Physics/Manager/CollisionLocker.cs
+++ /dev/null
@@ -1,73 +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;
30
31namespace OpenSim.Region.Physics.Manager
32{
33 public class CollisionLocker
34 {
35 private List<IntPtr> worldlock = new List<IntPtr>();
36
37 public CollisionLocker()
38 {
39
40 }
41
42 public void dlock(IntPtr world)
43 {
44 lock (worldlock)
45 {
46 worldlock.Add(world);
47 }
48
49 }
50
51 public void dunlock(IntPtr world)
52 {
53 lock (worldlock)
54 {
55 worldlock.Remove(world);
56 }
57 }
58
59 public bool lockquery()
60 {
61 return (worldlock.Count > 0);
62 }
63
64 public void drelease(IntPtr world)
65 {
66 lock (worldlock)
67 {
68 if (worldlock.Contains(world))
69 worldlock.Remove(world);
70 }
71 }
72 }
73}
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs
deleted file mode 100644
index 10c4bd3..0000000
--- a/OpenSim/Region/Physics/Manager/IMesher.cs
+++ /dev/null
@@ -1,70 +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 OpenSim.Framework;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.Manager
34{
35 public interface IMesher
36 {
37 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
39 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache);
40 }
41
42 // Values for level of detail to be passed to the mesher.
43 // Values origionally chosen for the LOD of sculpties (the sqrt(width*heigth) of sculpt texture)
44 // Lower level of detail reduces the number of vertices used to represent the meshed shape.
45 public enum LevelOfDetail
46 {
47 High = 32,
48 Medium = 16,
49 Low = 8,
50 VeryLow = 4
51 }
52
53 public interface IVertex
54 {
55 }
56
57 public interface IMesh
58 {
59 List<Vector3> getVertexList();
60 int[] getIndexListAsInt();
61 int[] getIndexListAsIntLocked();
62 float[] getVertexListAsFloatLocked();
63 void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount);
64 void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount);
65 void releaseSourceMeshData();
66 void releasePinned();
67 void Append(IMesh newMesh);
68 void TransformLinear(float[,] matrix, float[] offset);
69 }
70}
diff --git a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
deleted file mode 100755
index b8676ba..0000000
--- a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs
+++ /dev/null
@@ -1,73 +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 OpenSim.Framework;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.Manager
34{
35 public struct PhysParameterEntry
36 {
37 // flags to say to apply to all or no instances (I wish one could put consts into interfaces)
38 public const uint APPLY_TO_ALL = 0xfffffff3;
39 public const uint APPLY_TO_NONE = 0xfffffff4;
40
41 // values that denote true and false values
42 public const float NUMERIC_TRUE = 1f;
43 public const float NUMERIC_FALSE = 0f;
44
45 public string name;
46 public string desc;
47
48 public PhysParameterEntry(string n, string d)
49 {
50 name = n;
51 desc = d;
52 }
53 }
54
55 // Interface for a physics scene that implements the runtime setting and getting of physics parameters
56 public interface IPhysicsParameters
57 {
58 // Get the list of parameters this physics engine supports
59 PhysParameterEntry[] GetParameterList();
60
61 // Set parameter on a specific or all instances.
62 // Return 'false' if not able to set the parameter.
63 bool SetPhysicsParameter(string parm, float value, uint localID);
64
65 // Get parameter.
66 // Return 'false' if not able to get the parameter.
67 bool GetPhysicsParameter(string parm, out float value);
68
69 // Get parameter from a particular object
70 // TODO:
71 // bool GetPhysicsParameter(string parm, out float value, uint localID);
72 }
73}
diff --git a/OpenSim/Region/Physics/Manager/NullPhysicsScene.cs b/OpenSim/Region/Physics/Manager/NullPhysicsScene.cs
deleted file mode 100644
index 1ccf46d..0000000
--- a/OpenSim/Region/Physics/Manager/NullPhysicsScene.cs
+++ /dev/null
@@ -1,121 +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.Collections.Generic;
29using System.Reflection;
30using log4net;
31using Nini.Config;
32using OpenSim.Framework;
33using OpenMetaverse;
34
35namespace OpenSim.Region.Physics.Manager
36{
37 class NullPhysicsScene : PhysicsScene
38 {
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40
41 private static int m_workIndicator;
42
43 public override void Initialise(IMesher meshmerizer, IConfigSource config)
44 {
45 // Does nothing right now
46 }
47
48 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
49 {
50 m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddAvatar({0})", position);
51 return PhysicsActor.Null;
52 }
53
54 public override void RemoveAvatar(PhysicsActor actor)
55 {
56 }
57
58 public override void RemovePrim(PhysicsActor prim)
59 {
60 }
61 public override void SetWaterLevel(float baseheight)
62 {
63
64 }
65
66/*
67 public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation)
68 {
69 m_log.InfoFormat("NullPhysicsScene : AddPrim({0},{1})", position, size);
70 return PhysicsActor.Null;
71 }
72*/
73
74 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
75 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
76 {
77 m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddPrim({0},{1})", position, size);
78 return PhysicsActor.Null;
79 }
80
81 public override void AddPhysicsActorTaint(PhysicsActor prim)
82 {
83 }
84
85 public override float Simulate(float timeStep)
86 {
87 m_workIndicator = (m_workIndicator + 1) % 10;
88
89 return 0f;
90 }
91
92 public override void GetResults()
93 {
94 m_log.Info("[PHYSICS]: NullPhysicsScene : GetResults()");
95 }
96
97 public override void SetTerrain(float[] heightMap)
98 {
99 m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : SetTerrain({0} items)", heightMap.Length);
100 }
101
102 public override void DeleteTerrain()
103 {
104 }
105
106 public override bool IsThreaded
107 {
108 get { return false; }
109 }
110
111 public override void Dispose()
112 {
113 }
114
115 public override Dictionary<uint,float> GetTopColliders()
116 {
117 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
118 return returncolliders;
119 }
120 }
121} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
deleted file mode 100644
index d119791..0000000
--- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs
+++ /dev/null
@@ -1,567 +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 log4net;
29using System;
30using System.Collections.Generic;
31using System.Reflection;
32using OpenSim.Framework;
33using OpenMetaverse;
34
35namespace OpenSim.Region.Physics.Manager
36{
37 public delegate void PositionUpdate(Vector3 position);
38 public delegate void VelocityUpdate(Vector3 velocity);
39 public delegate void OrientationUpdate(Quaternion orientation);
40
41 public enum ActorTypes : int
42 {
43 Unknown = 0,
44 Agent = 1,
45 Prim = 2,
46 Ground = 3
47 }
48
49 public enum PIDHoverType
50 {
51 Ground,
52 GroundAndWater,
53 Water,
54 Absolute
55 }
56
57 public struct ContactPoint
58 {
59 public Vector3 Position;
60 public Vector3 SurfaceNormal;
61 public float PenetrationDepth;
62
63 public ContactPoint(Vector3 position, Vector3 surfaceNormal, float penetrationDepth)
64 {
65 Position = position;
66 SurfaceNormal = surfaceNormal;
67 PenetrationDepth = penetrationDepth;
68 }
69 }
70
71 /// <summary>
72 /// Used to pass collision information to OnCollisionUpdate listeners.
73 /// </summary>
74 public class CollisionEventUpdate : EventArgs
75 {
76 /// <summary>
77 /// Number of collision events in this update.
78 /// </summary>
79 public int Count { get { return m_objCollisionList.Count; } }
80
81 public bool CollisionsOnPreviousFrame { get; private set; }
82
83 public Dictionary<uint, ContactPoint> m_objCollisionList;
84
85 public CollisionEventUpdate(Dictionary<uint, ContactPoint> objCollisionList)
86 {
87 m_objCollisionList = objCollisionList;
88 }
89
90 public CollisionEventUpdate()
91 {
92 m_objCollisionList = new Dictionary<uint, ContactPoint>();
93 }
94
95 public void AddCollider(uint localID, ContactPoint contact)
96 {
97 if (!m_objCollisionList.ContainsKey(localID))
98 {
99 m_objCollisionList.Add(localID, contact);
100 }
101 else
102 {
103 if (m_objCollisionList[localID].PenetrationDepth < contact.PenetrationDepth)
104 m_objCollisionList[localID] = contact;
105 }
106 }
107
108 /// <summary>
109 /// Clear added collision events.
110 /// </summary>
111 public void Clear()
112 {
113 m_objCollisionList.Clear();
114 }
115 }
116
117 public abstract class PhysicsActor
118 {
119// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
120
121 public delegate void RequestTerseUpdate();
122 public delegate void CollisionUpdate(EventArgs e);
123 public delegate void OutOfBounds(Vector3 pos);
124
125// disable warning: public events
126#pragma warning disable 67
127 public event PositionUpdate OnPositionUpdate;
128 public event VelocityUpdate OnVelocityUpdate;
129 public event OrientationUpdate OnOrientationUpdate;
130 public event RequestTerseUpdate OnRequestTerseUpdate;
131
132 /// <summary>
133 /// Subscribers to this event must synchronously handle the dictionary of collisions received, since the event
134 /// object is reused in subsequent physics frames.
135 /// </summary>
136 public event CollisionUpdate OnCollisionUpdate;
137
138 public event OutOfBounds OnOutOfBounds;
139#pragma warning restore 67
140
141 public static PhysicsActor Null
142 {
143 get { return new NullPhysicsActor(); }
144 }
145
146 public abstract bool Stopped { get; }
147
148 public abstract Vector3 Size { get; set; }
149
150 public abstract PrimitiveBaseShape Shape { set; }
151
152 uint m_baseLocalID;
153 public virtual uint LocalID
154 {
155 set { m_baseLocalID = value; }
156 get { return m_baseLocalID; }
157 }
158
159 public abstract bool Grabbed { set; }
160
161 public abstract bool Selected { set; }
162
163 /// <summary>
164 /// Name of this actor.
165 /// </summary>
166 /// <remarks>
167 /// XXX: Bizarrely, this cannot be "Terrain" or "Water" right now unless it really is simulating terrain or
168 /// water. This is not a problem due to the formatting of names given by prims and avatars.
169 /// </remarks>
170 public string Name { get; protected set; }
171
172 /// <summary>
173 /// This is being used by ODE joint code.
174 /// </summary>
175 public string SOPName;
176
177 public abstract void CrossingFailure();
178
179 public abstract void link(PhysicsActor obj);
180
181 public abstract void delink();
182
183 public abstract void LockAngularMotion(Vector3 axis);
184
185 public virtual void RequestPhysicsterseUpdate()
186 {
187 // Make a temporary copy of the event to avoid possibility of
188 // a race condition if the last subscriber unsubscribes
189 // immediately after the null check and before the event is raised.
190 RequestTerseUpdate handler = OnRequestTerseUpdate;
191
192 if (handler != null)
193 {
194 handler();
195 }
196 }
197
198 public virtual void RaiseOutOfBounds(Vector3 pos)
199 {
200 // Make a temporary copy of the event to avoid possibility of
201 // a race condition if the last subscriber unsubscribes
202 // immediately after the null check and before the event is raised.
203 OutOfBounds handler = OnOutOfBounds;
204
205 if (handler != null)
206 {
207 handler(pos);
208 }
209 }
210
211 public virtual void SendCollisionUpdate(EventArgs e)
212 {
213 CollisionUpdate handler = OnCollisionUpdate;
214
215// m_log.DebugFormat("[PHYSICS ACTOR]: Sending collision for {0}", LocalID);
216
217 if (handler != null)
218 handler(e);
219 }
220
221 public virtual void SetMaterial (int material)
222 {
223 }
224
225 /// <summary>
226 /// Position of this actor.
227 /// </summary>
228 /// <remarks>
229 /// Setting this directly moves the actor to a given position.
230 /// Getting this retrieves the position calculated by physics scene updates, using factors such as velocity and
231 /// collisions.
232 /// </remarks>
233 public abstract Vector3 Position { get; set; }
234
235 public abstract float Mass { get; }
236 public abstract Vector3 Force { get; set; }
237
238 public abstract int VehicleType { get; set; }
239 public abstract void VehicleFloatParam(int param, float value);
240 public abstract void VehicleVectorParam(int param, Vector3 value);
241 public abstract void VehicleRotationParam(int param, Quaternion rotation);
242 public abstract void VehicleFlags(int param, bool remove);
243
244 /// <summary>
245 /// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
246 /// </summary>
247 public abstract void SetVolumeDetect(int param);
248
249 public abstract Vector3 GeometricCenter { get; }
250 public abstract Vector3 CenterOfMass { get; }
251
252 /// <summary>
253 /// The desired velocity of this actor.
254 /// </summary>
255 /// <remarks>
256 /// Setting this provides a target velocity for physics scene updates.
257 /// Getting this returns the last set target. Fetch Velocity to get the current velocity.
258 /// </remarks>
259 protected Vector3 m_targetVelocity;
260 public virtual Vector3 TargetVelocity
261 {
262 get { return m_targetVelocity; }
263 set {
264 m_targetVelocity = value;
265 Velocity = m_targetVelocity;
266 }
267 }
268
269 public abstract Vector3 Velocity { get; set; }
270
271 public abstract Vector3 Torque { get; set; }
272 public abstract float CollisionScore { get; set;}
273 public abstract Vector3 Acceleration { get; set; }
274 public abstract Quaternion Orientation { get; set; }
275 public abstract int PhysicsActorType { get; set; }
276 public abstract bool IsPhysical { get; set; }
277 public abstract bool Flying { get; set; }
278 public abstract bool SetAlwaysRun { get; set; }
279 public abstract bool ThrottleUpdates { get; set; }
280 public abstract bool IsColliding { get; set; }
281 public abstract bool CollidingGround { get; set; }
282 public abstract bool CollidingObj { get; set; }
283 public abstract bool FloatOnWater { set; }
284 public abstract Vector3 RotationalVelocity { get; set; }
285 public abstract bool Kinematic { get; set; }
286 public abstract float Buoyancy { get; set; }
287
288 // Used for MoveTo
289 public abstract Vector3 PIDTarget { set; }
290 public abstract bool PIDActive { set;}
291 public abstract float PIDTau { set; }
292
293 // Used for llSetHoverHeight and maybe vehicle height
294 // Hover Height will override MoveTo target's Z
295 public abstract bool PIDHoverActive { set;}
296 public abstract float PIDHoverHeight { set;}
297 public abstract PIDHoverType PIDHoverType { set;}
298 public abstract float PIDHoverTau { set;}
299
300 // For RotLookAt
301 public abstract Quaternion APIDTarget { set;}
302 public abstract bool APIDActive { set;}
303 public abstract float APIDStrength { set;}
304 public abstract float APIDDamping { set;}
305
306 public abstract void AddForce(Vector3 force, bool pushforce);
307 public abstract void AddAngularForce(Vector3 force, bool pushforce);
308 public abstract void SetMomentum(Vector3 momentum);
309 public abstract void SubscribeEvents(int ms);
310 public abstract void UnSubscribeEvents();
311 public abstract bool SubscribedEvents();
312 }
313
314 public class NullPhysicsActor : PhysicsActor
315 {
316 public override bool Stopped
317 {
318 get{ return false; }
319 }
320
321 public override Vector3 Position
322 {
323 get { return Vector3.Zero; }
324 set { return; }
325 }
326
327 public override bool SetAlwaysRun
328 {
329 get { return false; }
330 set { return; }
331 }
332
333 public override uint LocalID
334 {
335 set { return; }
336 }
337
338 public override bool Grabbed
339 {
340 set { return; }
341 }
342
343 public override bool Selected
344 {
345 set { return; }
346 }
347
348 public override float Buoyancy
349 {
350 get { return 0f; }
351 set { return; }
352 }
353
354 public override bool FloatOnWater
355 {
356 set { return; }
357 }
358
359 public override bool CollidingGround
360 {
361 get { return false; }
362 set { return; }
363 }
364
365 public override bool CollidingObj
366 {
367 get { return false; }
368 set { return; }
369 }
370
371 public override Vector3 Size
372 {
373 get { return Vector3.Zero; }
374 set { return; }
375 }
376
377 public override float Mass
378 {
379 get { return 0f; }
380 }
381
382 public override Vector3 Force
383 {
384 get { return Vector3.Zero; }
385 set { return; }
386 }
387
388 public override int VehicleType
389 {
390 get { return 0; }
391 set { return; }
392 }
393
394 public override void VehicleFloatParam(int param, float value)
395 {
396
397 }
398
399 public override void VehicleVectorParam(int param, Vector3 value)
400 {
401
402 }
403
404 public override void VehicleRotationParam(int param, Quaternion rotation)
405 {
406
407 }
408
409 public override void VehicleFlags(int param, bool remove)
410 {
411
412 }
413
414 public override void SetVolumeDetect(int param)
415 {
416
417 }
418
419 public override void SetMaterial(int material)
420 {
421
422 }
423
424 public override Vector3 CenterOfMass
425 {
426 get { return Vector3.Zero; }
427 }
428
429 public override Vector3 GeometricCenter
430 {
431 get { return Vector3.Zero; }
432 }
433
434 public override PrimitiveBaseShape Shape
435 {
436 set { return; }
437 }
438
439 public override Vector3 Velocity
440 {
441 get { return Vector3.Zero; }
442 set { return; }
443 }
444
445 public override Vector3 Torque
446 {
447 get { return Vector3.Zero; }
448 set { return; }
449 }
450
451 public override float CollisionScore
452 {
453 get { return 0f; }
454 set { }
455 }
456
457 public override void CrossingFailure()
458 {
459 }
460
461 public override Quaternion Orientation
462 {
463 get { return Quaternion.Identity; }
464 set { }
465 }
466
467 public override Vector3 Acceleration
468 {
469 get { return Vector3.Zero; }
470 set { }
471 }
472
473 public override bool IsPhysical
474 {
475 get { return false; }
476 set { return; }
477 }
478
479 public override bool Flying
480 {
481 get { return false; }
482 set { return; }
483 }
484
485 public override bool ThrottleUpdates
486 {
487 get { return false; }
488 set { return; }
489 }
490
491 public override bool IsColliding
492 {
493 get { return false; }
494 set { return; }
495 }
496
497 public override int PhysicsActorType
498 {
499 get { return (int) ActorTypes.Unknown; }
500 set { return; }
501 }
502
503 public override bool Kinematic
504 {
505 get { return true; }
506 set { return; }
507 }
508
509 public override void link(PhysicsActor obj)
510 {
511 }
512
513 public override void delink()
514 {
515 }
516
517 public override void LockAngularMotion(Vector3 axis)
518 {
519 }
520
521 public override void AddForce(Vector3 force, bool pushforce)
522 {
523 }
524
525 public override void AddAngularForce(Vector3 force, bool pushforce)
526 {
527
528 }
529
530 public override Vector3 RotationalVelocity
531 {
532 get { return Vector3.Zero; }
533 set { return; }
534 }
535
536 public override Vector3 PIDTarget { set { return; } }
537 public override bool PIDActive { set { return; } }
538 public override float PIDTau { set { return; } }
539
540 public override float PIDHoverHeight { set { return; } }
541 public override bool PIDHoverActive { set { return; } }
542 public override PIDHoverType PIDHoverType { set { return; } }
543 public override float PIDHoverTau { set { return; } }
544
545 public override Quaternion APIDTarget { set { return; } }
546 public override bool APIDActive { set { return; } }
547 public override float APIDStrength { set { return; } }
548 public override float APIDDamping { set { return; } }
549
550 public override void SetMomentum(Vector3 momentum)
551 {
552 }
553
554 public override void SubscribeEvents(int ms)
555 {
556
557 }
558 public override void UnSubscribeEvents()
559 {
560
561 }
562 public override bool SubscribedEvents()
563 {
564 return false;
565 }
566 }
567}
diff --git a/OpenSim/Region/Physics/Manager/PhysicsJoint.cs b/OpenSim/Region/Physics/Manager/PhysicsJoint.cs
deleted file mode 100644
index b685d04..0000000
--- a/OpenSim/Region/Physics/Manager/PhysicsJoint.cs
+++ /dev/null
@@ -1,55 +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 OpenSim.Framework;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.Manager
34{
35 public enum PhysicsJointType : int
36 {
37 Ball = 0,
38 Hinge = 1
39 }
40
41 public class PhysicsJoint
42 {
43 public virtual bool IsInPhysicsEngine { get { return false; } } // set internally to indicate if this joint has already been passed to the physics engine or is still pending
44 public PhysicsJointType Type;
45 public string RawParams;
46 public List<string> BodyNames = new List<string>();
47 public Vector3 Position; // global coords
48 public Quaternion Rotation; // global coords
49 public string ObjectNameInScene; // proxy object in scene that represents the joint position/orientation
50 public string TrackedBodyName; // body name that this joint is attached to (ObjectNameInScene will follow TrackedBodyName)
51 public Quaternion LocalRotation; // joint orientation relative to one of the involved bodies, the tracked body
52 public int ErrorMessageCount; // total # of error messages printed for this joint since its creation. if too many, further error messages are suppressed to prevent flooding.
53 public const int maxErrorMessages = 100; // no more than this # of error messages will be printed for each joint
54 }
55}
diff --git a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
deleted file mode 100644
index 8ccfda5..0000000
--- a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
+++ /dev/null
@@ -1,240 +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.IO;
31using System.Reflection;
32using Nini.Config;
33using log4net;
34using OpenSim.Framework;
35
36namespace OpenSim.Region.Physics.Manager
37{
38 /// <summary>
39 /// Description of MyClass.
40 /// </summary>
41 public class PhysicsPluginManager
42 {
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 private Dictionary<string, IPhysicsPlugin> _PhysPlugins = new Dictionary<string, IPhysicsPlugin>();
46 private Dictionary<string, IMeshingPlugin> _MeshPlugins = new Dictionary<string, IMeshingPlugin>();
47
48 /// <summary>
49 /// Constructor.
50 /// </summary>
51 public PhysicsPluginManager()
52 {
53 // Load "plugins", that are hard coded and not existing in form of an external lib, and hence always
54 // available
55 IMeshingPlugin plugHard;
56 plugHard = new ZeroMesherPlugin();
57 _MeshPlugins.Add(plugHard.GetName(), plugHard);
58
59 m_log.Info("[PHYSICS]: Added meshing engine: " + plugHard.GetName());
60 }
61
62 /// <summary>
63 /// Get a physics scene for the given physics engine and mesher.
64 /// </summary>
65 /// <param name="physEngineName"></param>
66 /// <param name="meshEngineName"></param>
67 /// <param name="config"></param>
68 /// <returns></returns>
69 public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName, IConfigSource config, string regionName)
70 {
71 if (String.IsNullOrEmpty(physEngineName))
72 {
73 return PhysicsScene.Null;
74 }
75
76 if (String.IsNullOrEmpty(meshEngineName))
77 {
78 return PhysicsScene.Null;
79 }
80
81 IMesher meshEngine = null;
82 if (_MeshPlugins.ContainsKey(meshEngineName))
83 {
84 m_log.Info("[PHYSICS]: creating meshing engine " + meshEngineName);
85 meshEngine = _MeshPlugins[meshEngineName].GetMesher(config);
86 }
87 else
88 {
89 m_log.WarnFormat("[PHYSICS]: couldn't find meshingEngine: {0}", meshEngineName);
90 throw new ArgumentException(String.Format("couldn't find meshingEngine: {0}", meshEngineName));
91 }
92
93 if (_PhysPlugins.ContainsKey(physEngineName))
94 {
95 m_log.Info("[PHYSICS]: creating " + physEngineName);
96 PhysicsScene result = _PhysPlugins[physEngineName].GetScene(regionName);
97 result.Initialise(meshEngine, config);
98 return result;
99 }
100 else
101 {
102 m_log.WarnFormat("[PHYSICS]: couldn't find physicsEngine: {0}", physEngineName);
103 throw new ArgumentException(String.Format("couldn't find physicsEngine: {0}", physEngineName));
104 }
105 }
106
107 /// <summary>
108 /// Load all plugins in assemblies at the given path
109 /// </summary>
110 /// <param name="pluginsPath"></param>
111 public void LoadPluginsFromAssemblies(string assembliesPath)
112 {
113 // Walk all assemblies (DLLs effectively) and see if they are home
114 // of a plugin that is of interest for us
115 string[] pluginFiles = Directory.GetFiles(assembliesPath, "*.dll");
116
117 for (int i = 0; i < pluginFiles.Length; i++)
118 {
119 LoadPluginsFromAssembly(pluginFiles[i]);
120 }
121 }
122
123 /// <summary>
124 /// Load plugins from an assembly at the given path
125 /// </summary>
126 /// <param name="assemblyPath"></param>
127 public void LoadPluginsFromAssembly(string assemblyPath)
128 {
129 // TODO / NOTE
130 // The assembly named 'OpenSim.Region.Physics.BasicPhysicsPlugin' was loaded from
131 // 'file:///C:/OpenSim/trunk2/bin/Physics/OpenSim.Region.Physics.BasicPhysicsPlugin.dll'
132 // using the LoadFrom context. The use of this context can result in unexpected behavior
133 // for serialization, casting and dependency resolution. In almost all cases, it is recommended
134 // that the LoadFrom context be avoided. This can be done by installing assemblies in the
135 // Global Assembly Cache or in the ApplicationBase directory and using Assembly.
136 // Load when explicitly loading assemblies.
137 Assembly pluginAssembly = null;
138 Type[] types = null;
139
140 try
141 {
142 pluginAssembly = Assembly.LoadFrom(assemblyPath);
143 }
144 catch (Exception ex)
145 {
146 m_log.Error("[PHYSICS]: Failed to load plugin from " + assemblyPath, ex);
147 }
148
149 if (pluginAssembly != null)
150 {
151 try
152 {
153 types = pluginAssembly.GetTypes();
154 }
155 catch (ReflectionTypeLoadException ex)
156 {
157 m_log.Error("[PHYSICS]: Failed to enumerate types in plugin from " + assemblyPath + ": " +
158 ex.LoaderExceptions[0].Message, ex);
159 }
160 catch (Exception ex)
161 {
162 m_log.Error("[PHYSICS]: Failed to enumerate types in plugin from " + assemblyPath, ex);
163 }
164
165 if (types != null)
166 {
167 foreach (Type pluginType in types)
168 {
169 if (pluginType.IsPublic)
170 {
171 if (!pluginType.IsAbstract)
172 {
173 Type physTypeInterface = pluginType.GetInterface("IPhysicsPlugin", true);
174
175 if (physTypeInterface != null)
176 {
177 IPhysicsPlugin plug =
178 (IPhysicsPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
179 plug.Init();
180 if (!_PhysPlugins.ContainsKey(plug.GetName()))
181 {
182 _PhysPlugins.Add(plug.GetName(), plug);
183 m_log.Info("[PHYSICS]: Added physics engine: " + plug.GetName());
184 }
185 }
186
187 Type meshTypeInterface = pluginType.GetInterface("IMeshingPlugin", true);
188
189 if (meshTypeInterface != null)
190 {
191 IMeshingPlugin plug =
192 (IMeshingPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
193 if (!_MeshPlugins.ContainsKey(plug.GetName()))
194 {
195 _MeshPlugins.Add(plug.GetName(), plug);
196 m_log.Info("[PHYSICS]: Added meshing engine: " + plug.GetName());
197 }
198 }
199
200 physTypeInterface = null;
201 meshTypeInterface = null;
202 }
203 }
204 }
205 }
206 }
207
208 pluginAssembly = null;
209 }
210
211 //---
212 public static void PhysicsPluginMessage(string message, bool isWarning)
213 {
214 if (isWarning)
215 {
216 m_log.Warn("[PHYSICS]: " + message);
217 }
218 else
219 {
220 m_log.Info("[PHYSICS]: " + message);
221 }
222 }
223
224 //---
225 }
226
227 public interface IPhysicsPlugin
228 {
229 bool Init();
230 PhysicsScene GetScene(String sceneIdentifier);
231 string GetName();
232 void Dispose();
233 }
234
235 public interface IMeshingPlugin
236 {
237 string GetName();
238 IMesher GetMesher(IConfigSource config);
239 }
240}
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
deleted file mode 100644
index 488900e..0000000
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ /dev/null
@@ -1,283 +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.Collections.Generic;
29using System.Reflection;
30using log4net;
31using Nini.Config;
32using OpenSim.Framework;
33using OpenMetaverse;
34
35namespace OpenSim.Region.Physics.Manager
36{
37 public delegate void physicsCrash();
38
39 public delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal);
40 public delegate void RayCallback(List<ContactResult> list);
41
42 public delegate void JointMoved(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"
45
46 public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback);
47 public delegate void AssetReceivedDelegate(AssetBase asset);
48
49 /// <summary>
50 /// Contact result from a raycast.
51 /// </summary>
52 public struct ContactResult
53 {
54 public Vector3 Pos;
55 public float Depth;
56 public uint ConsumerID;
57 public Vector3 Normal;
58 }
59
60 public abstract class PhysicsScene
61 {
62// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63
64 /// <summary>
65 /// Name of this scene. Useful in debug messages to distinguish one OdeScene instance from another.
66 /// </summary>
67 public string Name { get; protected set; }
68
69 // The only thing that should register for this event is the SceneGraph
70 // Anything else could cause problems.
71
72 public event physicsCrash OnPhysicsCrash;
73
74 public static PhysicsScene Null
75 {
76 get { return new NullPhysicsScene(); }
77 }
78
79 public RequestAssetDelegate RequestAssetMethod { get; set; }
80
81 public virtual void TriggerPhysicsBasedRestart()
82 {
83 physicsCrash handler = OnPhysicsCrash;
84 if (handler != null)
85 {
86 OnPhysicsCrash();
87 }
88 }
89
90 public abstract void Initialise(IMesher meshmerizer, IConfigSource config);
91
92 /// <summary>
93 /// Add an avatar
94 /// </summary>
95 /// <param name="avName"></param>
96 /// <param name="position"></param>
97 /// <param name="size"></param>
98 /// <param name="isFlying"></param>
99 /// <returns></returns>
100 public abstract PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying);
101
102 /// <summary>
103 /// Add an avatar
104 /// </summary>
105 /// <param name="localID"></param>
106 /// <param name="avName"></param>
107 /// <param name="position"></param>
108 /// <param name="size"></param>
109 /// <param name="isFlying"></param>
110 /// <returns></returns>
111 public virtual PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
112 {
113 PhysicsActor ret = AddAvatar(avName, position, size, isFlying);
114 if (ret != null) ret.LocalID = localID;
115 return ret;
116 }
117
118 /// <summary>
119 /// Remove an avatar.
120 /// </summary>
121 /// <param name="actor"></param>
122 public abstract void RemoveAvatar(PhysicsActor actor);
123
124 /// <summary>
125 /// Remove a prim.
126 /// </summary>
127 /// <param name="prim"></param>
128 public abstract void RemovePrim(PhysicsActor prim);
129
130 public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
131 Vector3 size, Quaternion rotation, bool isPhysical, uint localid);
132
133 public virtual float TimeDilation
134 {
135 get { return 1.0f; }
136 }
137
138 public virtual bool SupportsNINJAJoints
139 {
140 get { return false; }
141 }
142
143 public virtual PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
144 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
145 { return null; }
146
147 public virtual void RequestJointDeletion(string objectNameInScene)
148 { return; }
149
150 public virtual void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
151 { return; }
152
153 public virtual void DumpJointInfo()
154 { return; }
155
156 public event JointMoved OnJointMoved;
157
158 protected virtual void DoJointMoved(PhysicsJoint joint)
159 {
160 // We need this to allow subclasses (but not other classes) to invoke the event; C# does
161 // not allow subclasses to invoke the parent class event.
162 if (OnJointMoved != null)
163 {
164 OnJointMoved(joint);
165 }
166 }
167
168 public event JointDeactivated OnJointDeactivated;
169
170 protected virtual void DoJointDeactivated(PhysicsJoint joint)
171 {
172 // We need this to allow subclasses (but not other classes) to invoke the event; C# does
173 // not allow subclasses to invoke the parent class event.
174 if (OnJointDeactivated != null)
175 {
176 OnJointDeactivated(joint);
177 }
178 }
179
180 public event JointErrorMessage OnJointErrorMessage;
181
182 protected virtual void DoJointErrorMessage(PhysicsJoint joint, string message)
183 {
184 // We need this to allow subclasses (but not other classes) to invoke the event; C# does
185 // not allow subclasses to invoke the parent class event.
186 if (OnJointErrorMessage != null)
187 {
188 OnJointErrorMessage(joint, message);
189 }
190 }
191
192 public virtual Vector3 GetJointAnchor(PhysicsJoint joint)
193 { return Vector3.Zero; }
194
195 public virtual Vector3 GetJointAxis(PhysicsJoint joint)
196 { return Vector3.Zero; }
197
198 public abstract void AddPhysicsActorTaint(PhysicsActor prim);
199
200 /// <summary>
201 /// Perform a simulation of the current physics scene over the given timestep.
202 /// </summary>
203 /// <param name="timeStep"></param>
204 /// <returns>The number of frames simulated over that period.</returns>
205 public abstract float Simulate(float timeStep);
206
207 /// <summary>
208 /// Get statistics about this scene.
209 /// </summary>
210 /// <remarks>This facility is currently experimental and subject to change.</remarks>
211 /// <returns>
212 /// A dictionary where the key is the statistic name. If no statistics are supplied then returns null.
213 /// </returns>
214 public virtual Dictionary<string, float> GetStats() { return null; }
215
216 public abstract void GetResults();
217
218 public abstract void SetTerrain(float[] heightMap);
219
220 public abstract void SetWaterLevel(float baseheight);
221
222 public abstract void DeleteTerrain();
223
224 public abstract void Dispose();
225
226 public abstract Dictionary<uint, float> GetTopColliders();
227
228 public abstract bool IsThreaded { get; }
229
230 /// <summary>
231 /// True if the physics plugin supports raycasting against the physics scene
232 /// </summary>
233 public virtual bool SupportsRayCast()
234 {
235 return false;
236 }
237
238 public virtual bool SupportsCombining()
239 {
240 return false;
241 }
242
243 public virtual void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) {}
244
245 public virtual void UnCombine(PhysicsScene pScene) {}
246
247 /// <summary>
248 /// Queue a raycast against the physics scene.
249 /// The provided callback method will be called when the raycast is complete
250 ///
251 /// Many physics engines don't support collision testing at the same time as
252 /// manipulating the physics scene, so we queue the request up and callback
253 /// a custom method when the raycast is complete.
254 /// This allows physics engines that give an immediate result to callback immediately
255 /// and ones that don't, to callback when it gets a result back.
256 ///
257 /// ODE for example will not allow you to change the scene while collision testing or
258 /// it asserts, 'opteration not valid for locked space'. This includes adding a ray to the scene.
259 ///
260 /// This is named RayCastWorld to not conflict with modrex's Raycast method.
261 /// </summary>
262 /// <param name="position">Origin of the ray</param>
263 /// <param name="direction">Direction of the ray</param>
264 /// <param name="length">Length of ray in meters</param>
265 /// <param name="retMethod">Method to call when the raycast is complete</param>
266 public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
267 {
268 if (retMethod != null)
269 retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero);
270 }
271
272 public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
273 {
274 if (retMethod != null)
275 retMethod(new List<ContactResult>());
276 }
277
278 public virtual List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
279 {
280 return new List<ContactResult>();
281 }
282 }
283}
diff --git a/OpenSim/Region/Physics/Manager/PhysicsSensor.cs b/OpenSim/Region/Physics/Manager/PhysicsSensor.cs
deleted file mode 100644
index f480d71..0000000
--- a/OpenSim/Region/Physics/Manager/PhysicsSensor.cs
+++ /dev/null
@@ -1,78 +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.Timers;
30using OpenMetaverse;
31
32namespace OpenSim.Region.Physics.Manager
33{
34 [Flags]
35 public enum SenseType : uint
36 {
37 NONE = 0,
38 AGENT = 1,
39 ACTIVE = 2,
40 PASSIVE = 3,
41 SCRIPTED = 4
42 }
43
44 public abstract class PhysicsSensor
45 {
46 public static PhysicsSensor Null
47 {
48 get { return new NullPhysicsSensor(); }
49 }
50 public abstract Vector3 Position { get; set; }
51 public abstract void TimerCallback (object obj, ElapsedEventArgs eea);
52 public abstract float radianarc {get; set;}
53 public abstract string targetname {get; set;}
54 public abstract Guid targetKey{get;set;}
55 public abstract SenseType sensetype { get;set;}
56 public abstract float range { get;set;}
57 public abstract float rateSeconds { get;set;}
58 }
59
60 public class NullPhysicsSensor : PhysicsSensor
61 {
62 public override Vector3 Position
63 {
64 get { return Vector3.Zero; }
65 set { return; }
66 }
67 public override void TimerCallback(object obj, ElapsedEventArgs eea)
68 {
69 // don't do squat
70 }
71 public override float radianarc { get { return 0f; } set { } }
72 public override string targetname { get { return ""; } set { } }
73 public override Guid targetKey { get { return Guid.Empty; } set { } }
74 public override SenseType sensetype { get { return SenseType.NONE; } set { } }
75 public override float range { get { return 0; } set { } }
76 public override float rateSeconds { get { return 0; } set { } }
77 }
78}
diff --git a/OpenSim/Region/Physics/Manager/PhysicsVector.cs b/OpenSim/Region/Physics/Manager/PhysicsVector.cs
deleted file mode 100644
index f60a636..0000000
--- a/OpenSim/Region/Physics/Manager/PhysicsVector.cs
+++ /dev/null
@@ -1,186 +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;
29
30namespace OpenSim.Region.Physics.Manager
31{
32 /*public class PhysicsVector
33 {
34 public float X;
35 public float Y;
36 public float Z;
37
38 public Vector3()
39 {
40 }
41
42 public Vector3(float x, float y, float z)
43 {
44 X = x;
45 Y = y;
46 Z = z;
47 }
48
49 public Vector3(Vector3 pv) : this(pv.X, pv.Y, pv.Z)
50 {
51 }
52
53 public void setValues(float x, float y, float z)
54 {
55 X = x;
56 Y = y;
57 Z = z;
58 }
59
60 public static readonly PhysicsVector Zero = new PhysicsVector(0f, 0f, 0f);
61
62 public override string ToString()
63 {
64 return "<" + X + "," + Y + "," + Z + ">";
65 }
66
67 /// <summary>
68 /// These routines are the easiest way to store XYZ values in an Vector3 without requiring 3 calls.
69 /// </summary>
70 /// <returns></returns>
71 public byte[] GetBytes()
72 {
73 byte[] byteArray = new byte[12];
74
75 Buffer.BlockCopy(BitConverter.GetBytes(X), 0, byteArray, 0, 4);
76 Buffer.BlockCopy(BitConverter.GetBytes(Y), 0, byteArray, 4, 4);
77 Buffer.BlockCopy(BitConverter.GetBytes(Z), 0, byteArray, 8, 4);
78
79 if (!BitConverter.IsLittleEndian)
80 {
81 Array.Reverse(byteArray, 0, 4);
82 Array.Reverse(byteArray, 4, 4);
83 Array.Reverse(byteArray, 8, 4);
84 }
85
86 return byteArray;
87 }
88
89 public void FromBytes(byte[] byteArray, int pos)
90 {
91 byte[] conversionBuffer = null;
92 if (!BitConverter.IsLittleEndian)
93 {
94 // Big endian architecture
95 if (conversionBuffer == null)
96 conversionBuffer = new byte[12];
97
98 Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 12);
99
100 Array.Reverse(conversionBuffer, 0, 4);
101 Array.Reverse(conversionBuffer, 4, 4);
102 Array.Reverse(conversionBuffer, 8, 4);
103
104 X = BitConverter.ToSingle(conversionBuffer, 0);
105 Y = BitConverter.ToSingle(conversionBuffer, 4);
106 Z = BitConverter.ToSingle(conversionBuffer, 8);
107 }
108 else
109 {
110 // Little endian architecture
111 X = BitConverter.ToSingle(byteArray, pos);
112 Y = BitConverter.ToSingle(byteArray, pos + 4);
113 Z = BitConverter.ToSingle(byteArray, pos + 8);
114 }
115 }
116
117 // Operations
118 public static PhysicsVector operator +(Vector3 a, Vector3 b)
119 {
120 return new PhysicsVector(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
121 }
122
123 public static PhysicsVector operator -(Vector3 a, Vector3 b)
124 {
125 return new PhysicsVector(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
126 }
127
128 public static PhysicsVector cross(Vector3 a, Vector3 b)
129 {
130 return new PhysicsVector(a.Y*b.Z - a.Z*b.Y, a.Z*b.X - a.X*b.Z, a.X*b.Y - a.Y*b.X);
131 }
132
133 public float length()
134 {
135 return (float) Math.Sqrt(X*X + Y*Y + Z*Z);
136 }
137
138 public static float GetDistanceTo(Vector3 a, Vector3 b)
139 {
140 float dx = a.X - b.X;
141 float dy = a.Y - b.Y;
142 float dz = a.Z - b.Z;
143 return (float) Math.Sqrt(dx * dx + dy * dy + dz * dz);
144 }
145
146 public static PhysicsVector operator /(Vector3 v, float f)
147 {
148 return new PhysicsVector(v.X/f, v.Y/f, v.Z/f);
149 }
150
151 public static PhysicsVector operator *(Vector3 v, float f)
152 {
153 return new PhysicsVector(v.X*f, v.Y*f, v.Z*f);
154 }
155
156 public static PhysicsVector operator *(float f, Vector3 v)
157 {
158 return v*f;
159 }
160
161 public static bool isFinite(Vector3 v)
162 {
163 if (v == null)
164 return false;
165 if (Single.IsInfinity(v.X) || Single.IsNaN(v.X))
166 return false;
167 if (Single.IsInfinity(v.Y) || Single.IsNaN(v.Y))
168 return false;
169 if (Single.IsInfinity(v.Z) || Single.IsNaN(v.Z))
170 return false;
171
172 return true;
173 }
174
175 public virtual bool IsIdentical(Vector3 v, float tolerance)
176 {
177 PhysicsVector diff = this - v;
178 float d = diff.length();
179 if (d <= tolerance)
180 return true;
181
182 return false;
183 }
184
185 }*/
186}
diff --git a/OpenSim/Region/Physics/Manager/VehicleConstants.cs b/OpenSim/Region/Physics/Manager/VehicleConstants.cs
deleted file mode 100644
index f0775c1..0000000
--- a/OpenSim/Region/Physics/Manager/VehicleConstants.cs
+++ /dev/null
@@ -1,121 +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;
29
30namespace OpenSim.Region.Physics.Manager
31{
32 public enum Vehicle : int
33 {
34 /// <summary>
35 /// Turns off Vehicle Support
36 /// </summary>
37 TYPE_NONE = 0,
38
39 /// <summary>
40 /// No Angular motor, High Left right friction, No Hover, Linear Deflection 1, no angular deflection
41 /// no vertical attractor, No banking, Identity rotation frame
42 /// </summary>
43 TYPE_SLED = 1,
44
45 /// <summary>
46 /// Needs Motors to be driven by timer or control events High left/right friction, No angular friction
47 /// Linear Motor wins in a second, decays in 60 seconds. Angular motor wins in a second, decays in 8/10ths of a second
48 /// linear deflection 2 seconds
49 /// Vertical Attractor locked UP
50 /// </summary>
51 TYPE_CAR = 2,
52 TYPE_BOAT = 3,
53 TYPE_AIRPLANE = 4,
54 TYPE_BALLOON = 5,
55 LINEAR_FRICTION_TIMESCALE = 16,
56 /// <summary>
57 /// vector of timescales for exponential decay of angular velocity about three axis
58 /// </summary>
59 ANGULAR_FRICTION_TIMESCALE = 17,
60 /// <summary>
61 /// linear velocity vehicle will try for
62 /// </summary>
63 LINEAR_MOTOR_DIRECTION = 18,
64
65 /// <summary>
66 /// Offset from center of mass where linear motor forces are added
67 /// </summary>
68 LINEAR_MOTOR_OFFSET = 20,
69 /// <summary>
70 /// angular velocity that vehicle will try for
71 /// </summary>
72 ANGULAR_MOTOR_DIRECTION = 19,
73 HOVER_HEIGHT = 24,
74 HOVER_EFFICIENCY = 25,
75 HOVER_TIMESCALE = 26,
76 BUOYANCY = 27,
77 LINEAR_DEFLECTION_EFFICIENCY = 28,
78 LINEAR_DEFLECTION_TIMESCALE = 29,
79 LINEAR_MOTOR_TIMESCALE = 30,
80 LINEAR_MOTOR_DECAY_TIMESCALE = 31,
81
82 /// <summary>
83 /// slide between 0 and 1
84 /// </summary>
85 ANGULAR_DEFLECTION_EFFICIENCY = 32,
86 ANGULAR_DEFLECTION_TIMESCALE = 33,
87 ANGULAR_MOTOR_TIMESCALE = 34,
88 ANGULAR_MOTOR_DECAY_TIMESCALE = 35,
89 VERTICAL_ATTRACTION_EFFICIENCY = 36,
90 VERTICAL_ATTRACTION_TIMESCALE = 37,
91 BANKING_EFFICIENCY = 38,
92 BANKING_MIX = 39,
93 BANKING_TIMESCALE = 40,
94 REFERENCE_FRAME = 44,
95 BLOCK_EXIT = 45,
96 ROLL_FRAME = 46
97
98 }
99
100 [Flags]
101 public enum VehicleFlag
102 {
103 NO_DEFLECTION_UP = 1,
104 LIMIT_ROLL_ONLY = 2,
105 HOVER_WATER_ONLY = 4,
106 HOVER_TERRAIN_ONLY = 8,
107 HOVER_GLOBAL_HEIGHT = 16,
108 HOVER_UP_ONLY = 32,
109 LIMIT_MOTOR_UP = 64,
110 MOUSELOOK_STEER = 128,
111 MOUSELOOK_BANK = 256,
112 CAMERA_DECOUPLED = 512,
113 NO_X = 1024,
114 NO_Y = 2048,
115 NO_Z = 4096,
116 LOCK_HOVER_HEIGHT = 8192,
117 NO_DEFLECTION = 16392,
118 LOCK_ROTATION = 32784
119 }
120
121}
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs
deleted file mode 100644
index 270d2ec..0000000
--- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs
+++ /dev/null
@@ -1,83 +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 OpenSim.Framework;
30using OpenMetaverse;
31using Nini.Config;
32
33/*
34 * This is the zero mesher.
35 * Whatever you want him to mesh, he can't, telling you that by responding with a null pointer.
36 * Effectivly this is for switching off meshing and for testing as each physics machine should deal
37 * with the null pointer situation.
38 * But it's also a convenience thing, as physics machines can rely on having a mesher in any situation, even
39 * if it's a dump one like this.
40 * Note, that this mesher is *not* living in a module but in the manager itself, so
41 * it's always availabe and thus the default in case of configuration errors
42*/
43
44namespace OpenSim.Region.Physics.Manager
45{
46 public class ZeroMesherPlugin : IMeshingPlugin
47 {
48 public ZeroMesherPlugin()
49 {
50 }
51
52 public string GetName()
53 {
54 return "ZeroMesher";
55 }
56
57 public IMesher GetMesher(IConfigSource config)
58 {
59 return new ZeroMesher();
60 }
61 }
62
63 public class ZeroMesher : IMesher
64 {
65 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
66 {
67 return CreateMesh(primName, primShape, size, lod, false, false);
68 }
69
70 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
71 {
72 return CreateMesh(primName, primShape, size, lod, false, false);
73 }
74
75 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
76 {
77 // Remove the reference to the encoded JPEG2000 data so it can be GCed
78 primShape.SculptData = OpenMetaverse.Utils.EmptyBytes;
79
80 return null;
81 }
82 }
83}
diff --git a/OpenSim/Region/Physics/Meshing/HelperTypes.cs b/OpenSim/Region/Physics/Meshing/HelperTypes.cs
deleted file mode 100644
index 8cd8dcf..0000000
--- a/OpenSim/Region/Physics/Meshing/HelperTypes.cs
+++ /dev/null
@@ -1,436 +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.Diagnostics;
31using System.Globalization;
32using OpenMetaverse;
33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.Meshing;
35
36public class Vertex : IComparable<Vertex>
37{
38 Vector3 vector;
39
40 public float X
41 {
42 get { return vector.X; }
43 set { vector.X = value; }
44 }
45
46 public float Y
47 {
48 get { return vector.Y; }
49 set { vector.Y = value; }
50 }
51
52 public float Z
53 {
54 get { return vector.Z; }
55 set { vector.Z = value; }
56 }
57
58 public Vertex(float x, float y, float z)
59 {
60 vector.X = x;
61 vector.Y = y;
62 vector.Z = z;
63 }
64
65 public Vertex normalize()
66 {
67 float tlength = vector.Length();
68 if (tlength != 0f)
69 {
70 float mul = 1.0f / tlength;
71 return new Vertex(vector.X * mul, vector.Y * mul, vector.Z * mul);
72 }
73 else
74 {
75 return new Vertex(0f, 0f, 0f);
76 }
77 }
78
79 public Vertex cross(Vertex v)
80 {
81 return new Vertex(vector.Y * v.Z - vector.Z * v.Y, vector.Z * v.X - vector.X * v.Z, vector.X * v.Y - vector.Y * v.X);
82 }
83
84 // disable warning: mono compiler moans about overloading
85 // operators hiding base operator but should not according to C#
86 // language spec
87#pragma warning disable 0108
88 public static Vertex operator *(Vertex v, Quaternion q)
89 {
90 // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/
91
92 Vertex v2 = new Vertex(0f, 0f, 0f);
93
94 v2.X = q.W * q.W * v.X +
95 2f * q.Y * q.W * v.Z -
96 2f * q.Z * q.W * v.Y +
97 q.X * q.X * v.X +
98 2f * q.Y * q.X * v.Y +
99 2f * q.Z * q.X * v.Z -
100 q.Z * q.Z * v.X -
101 q.Y * q.Y * v.X;
102
103 v2.Y =
104 2f * q.X * q.Y * v.X +
105 q.Y * q.Y * v.Y +
106 2f * q.Z * q.Y * v.Z +
107 2f * q.W * q.Z * v.X -
108 q.Z * q.Z * v.Y +
109 q.W * q.W * v.Y -
110 2f * q.X * q.W * v.Z -
111 q.X * q.X * v.Y;
112
113 v2.Z =
114 2f * q.X * q.Z * v.X +
115 2f * q.Y * q.Z * v.Y +
116 q.Z * q.Z * v.Z -
117 2f * q.W * q.Y * v.X -
118 q.Y * q.Y * v.Z +
119 2f * q.W * q.X * v.Y -
120 q.X * q.X * v.Z +
121 q.W * q.W * v.Z;
122
123 return v2;
124 }
125
126 public static Vertex operator +(Vertex v1, Vertex v2)
127 {
128 return new Vertex(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
129 }
130
131 public static Vertex operator -(Vertex v1, Vertex v2)
132 {
133 return new Vertex(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
134 }
135
136 public static Vertex operator *(Vertex v1, Vertex v2)
137 {
138 return new Vertex(v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z);
139 }
140
141 public static Vertex operator +(Vertex v1, float am)
142 {
143 v1.X += am;
144 v1.Y += am;
145 v1.Z += am;
146 return v1;
147 }
148
149 public static Vertex operator -(Vertex v1, float am)
150 {
151 v1.X -= am;
152 v1.Y -= am;
153 v1.Z -= am;
154 return v1;
155 }
156
157 public static Vertex operator *(Vertex v1, float am)
158 {
159 v1.X *= am;
160 v1.Y *= am;
161 v1.Z *= am;
162 return v1;
163 }
164
165 public static Vertex operator /(Vertex v1, float am)
166 {
167 if (am == 0f)
168 {
169 return new Vertex(0f,0f,0f);
170 }
171 float mul = 1.0f / am;
172 v1.X *= mul;
173 v1.Y *= mul;
174 v1.Z *= mul;
175 return v1;
176 }
177#pragma warning restore 0108
178
179
180 public float dot(Vertex v)
181 {
182 return X * v.X + Y * v.Y + Z * v.Z;
183 }
184
185 public Vertex(Vector3 v)
186 {
187 vector = v;
188 }
189
190 public Vertex Clone()
191 {
192 return new Vertex(X, Y, Z);
193 }
194
195 public static Vertex FromAngle(double angle)
196 {
197 return new Vertex((float) Math.Cos(angle), (float) Math.Sin(angle), 0.0f);
198 }
199
200 public float Length()
201 {
202 return vector.Length();
203 }
204
205 public virtual bool Equals(Vertex v, float tolerance)
206 {
207 Vertex diff = this - v;
208 float d = diff.Length();
209 if (d < tolerance)
210 return true;
211
212 return false;
213 }
214
215
216 public int CompareTo(Vertex other)
217 {
218 if (X < other.X)
219 return -1;
220
221 if (X > other.X)
222 return 1;
223
224 if (Y < other.Y)
225 return -1;
226
227 if (Y > other.Y)
228 return 1;
229
230 if (Z < other.Z)
231 return -1;
232
233 if (Z > other.Z)
234 return 1;
235
236 return 0;
237 }
238
239 public static bool operator >(Vertex me, Vertex other)
240 {
241 return me.CompareTo(other) > 0;
242 }
243
244 public static bool operator <(Vertex me, Vertex other)
245 {
246 return me.CompareTo(other) < 0;
247 }
248
249 public String ToRaw()
250 {
251 // Why this stuff with the number formatter?
252 // Well, the raw format uses the english/US notation of numbers
253 // where the "," separates groups of 1000 while the "." marks the border between 1 and 10E-1.
254 // The german notation uses these characters exactly vice versa!
255 // The Float.ToString() routine is a localized one, giving different results depending on the country
256 // settings your machine works with. Unusable for a machine readable file format :-(
257 NumberFormatInfo nfi = new NumberFormatInfo();
258 nfi.NumberDecimalSeparator = ".";
259 nfi.NumberDecimalDigits = 3;
260
261 String s1 = X.ToString("N2", nfi) + " " + Y.ToString("N2", nfi) + " " + Z.ToString("N2", nfi);
262
263 return s1;
264 }
265}
266
267public class Triangle
268{
269 public Vertex v1;
270 public Vertex v2;
271 public Vertex v3;
272
273 private float radius_square;
274 private float cx;
275 private float cy;
276
277 public Triangle(Vertex _v1, Vertex _v2, Vertex _v3)
278 {
279 v1 = _v1;
280 v2 = _v2;
281 v3 = _v3;
282
283 CalcCircle();
284 }
285
286 public bool isInCircle(float x, float y)
287 {
288 float dx, dy;
289 float dd;
290
291 dx = x - cx;
292 dy = y - cy;
293
294 dd = dx*dx + dy*dy;
295 if (dd < radius_square)
296 return true;
297 else
298 return false;
299 }
300
301 public bool isDegraded()
302 {
303 // This means, the vertices of this triangle are somewhat strange.
304 // They either line up or at least two of them are identical
305 return (radius_square == 0.0);
306 }
307
308 private void CalcCircle()
309 {
310 // Calculate the center and the radius of a circle given by three points p1, p2, p3
311 // It is assumed, that the triangles vertices are already set correctly
312 double p1x, p2x, p1y, p2y, p3x, p3y;
313
314 // Deviation of this routine:
315 // A circle has the general equation (M-p)^2=r^2, where M and p are vectors
316 // this gives us three equations f(p)=r^2, each for one point p1, p2, p3
317 // putting respectively two equations together gives two equations
318 // f(p1)=f(p2) and f(p1)=f(p3)
319 // bringing all constant terms to one side brings them to the form
320 // M*v1=c1 resp.M*v2=c2 where v1=(p1-p2) and v2=(p1-p3) (still vectors)
321 // and c1, c2 are scalars (Naming conventions like the variables below)
322 // Now using the equations that are formed by the components of the vectors
323 // and isolate Mx lets you make one equation that only holds My
324 // The rest is straight forward and eaasy :-)
325 //
326
327 /* helping variables for temporary results */
328 double c1, c2;
329 double v1x, v1y, v2x, v2y;
330
331 double z, n;
332
333 double rx, ry;
334
335 // Readout the three points, the triangle consists of
336 p1x = v1.X;
337 p1y = v1.Y;
338
339 p2x = v2.X;
340 p2y = v2.Y;
341
342 p3x = v3.X;
343 p3y = v3.Y;
344
345 /* calc helping values first */
346 c1 = (p1x*p1x + p1y*p1y - p2x*p2x - p2y*p2y)/2;
347 c2 = (p1x*p1x + p1y*p1y - p3x*p3x - p3y*p3y)/2;
348
349 v1x = p1x - p2x;
350 v1y = p1y - p2y;
351
352 v2x = p1x - p3x;
353 v2y = p1y - p3y;
354
355 z = (c1*v2x - c2*v1x);
356 n = (v1y*v2x - v2y*v1x);
357
358 if (n == 0.0) // This is no triangle, i.e there are (at least) two points at the same location
359 {
360 radius_square = 0.0f;
361 return;
362 }
363
364 cy = (float) (z/n);
365
366 if (v2x != 0.0)
367 {
368 cx = (float) ((c2 - v2y*cy)/v2x);
369 }
370 else if (v1x != 0.0)
371 {
372 cx = (float) ((c1 - v1y*cy)/v1x);
373 }
374 else
375 {
376 Debug.Assert(false, "Malformed triangle"); /* Both terms zero means nothing good */
377 }
378
379 rx = (p1x - cx);
380 ry = (p1y - cy);
381
382 radius_square = (float) (rx*rx + ry*ry);
383 }
384
385 public override String ToString()
386 {
387 NumberFormatInfo nfi = new NumberFormatInfo();
388 nfi.CurrencyDecimalDigits = 2;
389 nfi.CurrencyDecimalSeparator = ".";
390
391 String s1 = "<" + v1.X.ToString(nfi) + "," + v1.Y.ToString(nfi) + "," + v1.Z.ToString(nfi) + ">";
392 String s2 = "<" + v2.X.ToString(nfi) + "," + v2.Y.ToString(nfi) + "," + v2.Z.ToString(nfi) + ">";
393 String s3 = "<" + v3.X.ToString(nfi) + "," + v3.Y.ToString(nfi) + "," + v3.Z.ToString(nfi) + ">";
394
395 return s1 + ";" + s2 + ";" + s3;
396 }
397
398 public Vector3 getNormal()
399 {
400 // Vertices
401
402 // Vectors for edges
403 Vector3 e1;
404 Vector3 e2;
405
406 e1 = new Vector3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
407 e2 = new Vector3(v1.X - v3.X, v1.Y - v3.Y, v1.Z - v3.Z);
408
409 // Cross product for normal
410 Vector3 n = Vector3.Cross(e1, e2);
411
412 // Length
413 float l = n.Length();
414
415 // Normalized "normal"
416 n = n/l;
417
418 return n;
419 }
420
421 public void invertNormal()
422 {
423 Vertex vt;
424 vt = v1;
425 v1 = v2;
426 v2 = vt;
427 }
428
429 // Dumps a triangle in the "raw faces" format, blender can import. This is for visualisation and
430 // debugging purposes
431 public String ToStringRaw()
432 {
433 String output = v1.ToRaw() + " " + v2.ToRaw() + " " + v3.ToRaw();
434 return output;
435 }
436}
diff --git a/OpenSim/Region/Physics/Meshing/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs
deleted file mode 100644
index f781ff9..0000000
--- a/OpenSim/Region/Physics/Meshing/Mesh.cs
+++ /dev/null
@@ -1,333 +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.IO;
31using System.Runtime.InteropServices;
32using OpenSim.Region.Physics.Manager;
33using PrimMesher;
34using OpenMetaverse;
35
36namespace OpenSim.Region.Physics.Meshing
37{
38 public class Mesh : IMesh
39 {
40 private Dictionary<Vertex, int> m_vertices;
41 private List<Triangle> m_triangles;
42 GCHandle m_pinnedVertexes;
43 GCHandle m_pinnedIndex;
44 IntPtr m_verticesPtr = IntPtr.Zero;
45 int m_vertexCount = 0;
46 IntPtr m_indicesPtr = IntPtr.Zero;
47 int m_indexCount = 0;
48 public float[] m_normals;
49
50 public Mesh()
51 {
52 m_vertices = new Dictionary<Vertex, int>();
53 m_triangles = new List<Triangle>();
54 }
55
56 public Mesh Clone()
57 {
58 Mesh result = new Mesh();
59
60 foreach (Triangle t in m_triangles)
61 {
62 result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone()));
63 }
64
65 return result;
66 }
67
68 public void Add(Triangle triangle)
69 {
70 if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
71 throw new NotSupportedException("Attempt to Add to a pinned Mesh");
72 // If a vertex of the triangle is not yet in the vertices list,
73 // add it and set its index to the current index count
74 if (!m_vertices.ContainsKey(triangle.v1))
75 m_vertices[triangle.v1] = m_vertices.Count;
76 if (!m_vertices.ContainsKey(triangle.v2))
77 m_vertices[triangle.v2] = m_vertices.Count;
78 if (!m_vertices.ContainsKey(triangle.v3))
79 m_vertices[triangle.v3] = m_vertices.Count;
80 m_triangles.Add(triangle);
81 }
82
83 public void CalcNormals()
84 {
85 int iTriangles = m_triangles.Count;
86
87 this.m_normals = new float[iTriangles * 3];
88
89 int i = 0;
90 foreach (Triangle t in m_triangles)
91 {
92 float ux, uy, uz;
93 float vx, vy, vz;
94 float wx, wy, wz;
95
96 ux = t.v1.X;
97 uy = t.v1.Y;
98 uz = t.v1.Z;
99
100 vx = t.v2.X;
101 vy = t.v2.Y;
102 vz = t.v2.Z;
103
104 wx = t.v3.X;
105 wy = t.v3.Y;
106 wz = t.v3.Z;
107
108
109 // Vectors for edges
110 float e1x, e1y, e1z;
111 float e2x, e2y, e2z;
112
113 e1x = ux - vx;
114 e1y = uy - vy;
115 e1z = uz - vz;
116
117 e2x = ux - wx;
118 e2y = uy - wy;
119 e2z = uz - wz;
120
121
122 // Cross product for normal
123 float nx, ny, nz;
124 nx = e1y * e2z - e1z * e2y;
125 ny = e1z * e2x - e1x * e2z;
126 nz = e1x * e2y - e1y * e2x;
127
128 // Length
129 float l = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz);
130 float lReciprocal = 1.0f / l;
131
132 // Normalized "normal"
133 //nx /= l;
134 //ny /= l;
135 //nz /= l;
136
137 m_normals[i] = nx * lReciprocal;
138 m_normals[i + 1] = ny * lReciprocal;
139 m_normals[i + 2] = nz * lReciprocal;
140
141 i += 3;
142 }
143 }
144
145 public List<Vector3> getVertexList()
146 {
147 List<Vector3> result = new List<Vector3>();
148 foreach (Vertex v in m_vertices.Keys)
149 {
150 result.Add(new Vector3(v.X, v.Y, v.Z));
151 }
152 return result;
153 }
154
155 private float[] getVertexListAsFloat()
156 {
157 if (m_vertices == null)
158 throw new NotSupportedException();
159 float[] result = new float[m_vertices.Count * 3];
160 foreach (KeyValuePair<Vertex, int> kvp in m_vertices)
161 {
162 Vertex v = kvp.Key;
163 int i = kvp.Value;
164 result[3 * i + 0] = v.X;
165 result[3 * i + 1] = v.Y;
166 result[3 * i + 2] = v.Z;
167 }
168 return result;
169 }
170
171 public float[] getVertexListAsFloatLocked()
172 {
173 if (m_pinnedVertexes.IsAllocated)
174 return (float[])(m_pinnedVertexes.Target);
175
176 float[] result = getVertexListAsFloat();
177 m_pinnedVertexes = GCHandle.Alloc(result, GCHandleType.Pinned);
178 // Inform the garbage collector of this unmanaged allocation so it can schedule
179 // the next GC round more intelligently
180 GC.AddMemoryPressure(Buffer.ByteLength(result));
181
182 return result;
183 }
184
185 public void getVertexListAsPtrToFloatArray(out IntPtr vertices, out int vertexStride, out int vertexCount)
186 {
187 // A vertex is 3 floats
188 vertexStride = 3 * sizeof(float);
189
190 // If there isn't an unmanaged array allocated yet, do it now
191 if (m_verticesPtr == IntPtr.Zero)
192 {
193 float[] vertexList = getVertexListAsFloat();
194 // Each vertex is 3 elements (floats)
195 m_vertexCount = vertexList.Length / 3;
196 int byteCount = m_vertexCount * vertexStride;
197 m_verticesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount);
198 System.Runtime.InteropServices.Marshal.Copy(vertexList, 0, m_verticesPtr, m_vertexCount * 3);
199 }
200 vertices = m_verticesPtr;
201 vertexCount = m_vertexCount;
202 }
203
204 public int[] getIndexListAsInt()
205 {
206 if (m_triangles == null)
207 throw new NotSupportedException();
208 int[] result = new int[m_triangles.Count * 3];
209 for (int i = 0; i < m_triangles.Count; i++)
210 {
211 Triangle t = m_triangles[i];
212 result[3 * i + 0] = m_vertices[t.v1];
213 result[3 * i + 1] = m_vertices[t.v2];
214 result[3 * i + 2] = m_vertices[t.v3];
215 }
216 return result;
217 }
218
219 /// <summary>
220 /// creates a list of index values that defines triangle faces. THIS METHOD FREES ALL NON-PINNED MESH DATA
221 /// </summary>
222 /// <returns></returns>
223 public int[] getIndexListAsIntLocked()
224 {
225 if (m_pinnedIndex.IsAllocated)
226 return (int[])(m_pinnedIndex.Target);
227
228 int[] result = getIndexListAsInt();
229 m_pinnedIndex = GCHandle.Alloc(result, GCHandleType.Pinned);
230 // Inform the garbage collector of this unmanaged allocation so it can schedule
231 // the next GC round more intelligently
232 GC.AddMemoryPressure(Buffer.ByteLength(result));
233
234 return result;
235 }
236
237 public void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount)
238 {
239 // If there isn't an unmanaged array allocated yet, do it now
240 if (m_indicesPtr == IntPtr.Zero)
241 {
242 int[] indexList = getIndexListAsInt();
243 m_indexCount = indexList.Length;
244 int byteCount = m_indexCount * sizeof(int);
245 m_indicesPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(byteCount);
246 System.Runtime.InteropServices.Marshal.Copy(indexList, 0, m_indicesPtr, m_indexCount);
247 }
248 // A triangle is 3 ints (indices)
249 triStride = 3 * sizeof(int);
250 indices = m_indicesPtr;
251 indexCount = m_indexCount;
252 }
253
254 public void releasePinned()
255 {
256 if (m_pinnedVertexes.IsAllocated)
257 m_pinnedVertexes.Free();
258 if (m_pinnedIndex.IsAllocated)
259 m_pinnedIndex.Free();
260 if (m_verticesPtr != IntPtr.Zero)
261 {
262 System.Runtime.InteropServices.Marshal.FreeHGlobal(m_verticesPtr);
263 m_verticesPtr = IntPtr.Zero;
264 }
265 if (m_indicesPtr != IntPtr.Zero)
266 {
267 System.Runtime.InteropServices.Marshal.FreeHGlobal(m_indicesPtr);
268 m_indicesPtr = IntPtr.Zero;
269 }
270 }
271
272 /// <summary>
273 /// frees up the source mesh data to minimize memory - call this method after calling get*Locked() functions
274 /// </summary>
275 public void releaseSourceMeshData()
276 {
277 m_triangles = null;
278 m_vertices = null;
279 }
280
281 public void Append(IMesh newMesh)
282 {
283 if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
284 throw new NotSupportedException("Attempt to Append to a pinned Mesh");
285
286 if (!(newMesh is Mesh))
287 return;
288
289 foreach (Triangle t in ((Mesh)newMesh).m_triangles)
290 Add(t);
291 }
292
293 // Do a linear transformation of mesh.
294 public void TransformLinear(float[,] matrix, float[] offset)
295 {
296 if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
297 throw new NotSupportedException("Attempt to TransformLinear a pinned Mesh");
298
299 foreach (Vertex v in m_vertices.Keys)
300 {
301 if (v == null)
302 continue;
303 float x, y, z;
304 x = v.X*matrix[0, 0] + v.Y*matrix[1, 0] + v.Z*matrix[2, 0];
305 y = v.X*matrix[0, 1] + v.Y*matrix[1, 1] + v.Z*matrix[2, 1];
306 z = v.X*matrix[0, 2] + v.Y*matrix[1, 2] + v.Z*matrix[2, 2];
307 v.X = x + offset[0];
308 v.Y = y + offset[1];
309 v.Z = z + offset[2];
310 }
311 }
312
313 public void DumpRaw(String path, String name, String title)
314 {
315 if (path == null)
316 return;
317 String fileName = name + "_" + title + ".raw";
318 String completePath = System.IO.Path.Combine(path, fileName);
319 StreamWriter sw = new StreamWriter(completePath);
320 foreach (Triangle t in m_triangles)
321 {
322 String s = t.ToStringRaw();
323 sw.WriteLine(s);
324 }
325 sw.Close();
326 }
327
328 public void TrimExcess()
329 {
330 m_triangles.TrimExcess();
331 }
332 }
333}
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
deleted file mode 100644
index 8145d61..0000000
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ /dev/null
@@ -1,761 +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//#define SPAM
28
29using System;
30using System.Collections.Generic;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using System.Drawing;
36using System.Drawing.Imaging;
37using System.IO.Compression;
38using PrimMesher;
39using log4net;
40using Nini.Config;
41using System.Reflection;
42using System.IO;
43using ComponentAce.Compression.Libs.zlib;
44
45namespace OpenSim.Region.Physics.Meshing
46{
47 public class MeshmerizerPlugin : IMeshingPlugin
48 {
49 public MeshmerizerPlugin()
50 {
51 }
52
53 public string GetName()
54 {
55 return "Meshmerizer";
56 }
57
58 public IMesher GetMesher(IConfigSource config)
59 {
60 return new Meshmerizer(config);
61 }
62 }
63
64 public class Meshmerizer : IMesher
65 {
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67
68 // Setting baseDir to a path will enable the dumping of raw files
69 // raw files can be imported by blender so a visual inspection of the results can be done
70#if SPAM
71 const string baseDir = "rawFiles";
72#else
73 private const string baseDir = null; //"rawFiles";
74#endif
75
76 private bool cacheSculptMaps = true;
77 private string decodedSculptMapPath = null;
78 private bool useMeshiesPhysicsMesh = false;
79
80 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
81
82 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
83
84 public Meshmerizer(IConfigSource config)
85 {
86 IConfig start_config = config.Configs["Startup"];
87 IConfig mesh_config = config.Configs["Mesh"];
88
89 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
90 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
91 if(mesh_config != null)
92 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
93
94 try
95 {
96 if (!Directory.Exists(decodedSculptMapPath))
97 Directory.CreateDirectory(decodedSculptMapPath);
98 }
99 catch (Exception e)
100 {
101 m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message);
102 }
103 }
104
105 /// <summary>
106 /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may
107 /// be useful as a backup proxy when level of detail is not needed or when more complex meshes fail
108 /// for some reason
109 /// </summary>
110 /// <param name="minX"></param>
111 /// <param name="maxX"></param>
112 /// <param name="minY"></param>
113 /// <param name="maxY"></param>
114 /// <param name="minZ"></param>
115 /// <param name="maxZ"></param>
116 /// <returns></returns>
117 private static Mesh CreateSimpleBoxMesh(float minX, float maxX, float minY, float maxY, float minZ, float maxZ)
118 {
119 Mesh box = new Mesh();
120 List<Vertex> vertices = new List<Vertex>();
121 // bottom
122
123 vertices.Add(new Vertex(minX, maxY, minZ));
124 vertices.Add(new Vertex(maxX, maxY, minZ));
125 vertices.Add(new Vertex(maxX, minY, minZ));
126 vertices.Add(new Vertex(minX, minY, minZ));
127
128 box.Add(new Triangle(vertices[0], vertices[1], vertices[2]));
129 box.Add(new Triangle(vertices[0], vertices[2], vertices[3]));
130
131 // top
132
133 vertices.Add(new Vertex(maxX, maxY, maxZ));
134 vertices.Add(new Vertex(minX, maxY, maxZ));
135 vertices.Add(new Vertex(minX, minY, maxZ));
136 vertices.Add(new Vertex(maxX, minY, maxZ));
137
138 box.Add(new Triangle(vertices[4], vertices[5], vertices[6]));
139 box.Add(new Triangle(vertices[4], vertices[6], vertices[7]));
140
141 // sides
142
143 box.Add(new Triangle(vertices[5], vertices[0], vertices[3]));
144 box.Add(new Triangle(vertices[5], vertices[3], vertices[6]));
145
146 box.Add(new Triangle(vertices[1], vertices[0], vertices[5]));
147 box.Add(new Triangle(vertices[1], vertices[5], vertices[4]));
148
149 box.Add(new Triangle(vertices[7], vertices[1], vertices[4]));
150 box.Add(new Triangle(vertices[7], vertices[2], vertices[1]));
151
152 box.Add(new Triangle(vertices[3], vertices[2], vertices[7]));
153 box.Add(new Triangle(vertices[3], vertices[7], vertices[6]));
154
155 return box;
156 }
157
158 /// <summary>
159 /// Creates a simple bounding box mesh for a complex input mesh
160 /// </summary>
161 /// <param name="meshIn"></param>
162 /// <returns></returns>
163 private static Mesh CreateBoundingBoxMesh(Mesh meshIn)
164 {
165 float minX = float.MaxValue;
166 float maxX = float.MinValue;
167 float minY = float.MaxValue;
168 float maxY = float.MinValue;
169 float minZ = float.MaxValue;
170 float maxZ = float.MinValue;
171
172 foreach (Vector3 v in meshIn.getVertexList())
173 {
174 if (v.X < minX) minX = v.X;
175 if (v.Y < minY) minY = v.Y;
176 if (v.Z < minZ) minZ = v.Z;
177
178 if (v.X > maxX) maxX = v.X;
179 if (v.Y > maxY) maxY = v.Y;
180 if (v.Z > maxZ) maxZ = v.Z;
181 }
182
183 return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ);
184 }
185
186 private void ReportPrimError(string message, string primName, PrimMesh primMesh)
187 {
188 m_log.Error(message);
189 m_log.Error("\nPrim Name: " + primName);
190 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
191 }
192
193 /// <summary>
194 /// Add a submesh to an existing list of coords and faces.
195 /// </summary>
196 /// <param name="subMeshData"></param>
197 /// <param name="size">Size of entire object</param>
198 /// <param name="coords"></param>
199 /// <param name="faces"></param>
200 private void AddSubMesh(OSDMap subMeshData, Vector3 size, List<Coord> coords, List<Face> faces)
201 {
202 // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap));
203
204 // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level
205 // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no
206 // geometry for this submesh.
207 if (subMeshData.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshData["NoGeometry"]))
208 return;
209
210 OpenMetaverse.Vector3 posMax = ((OSDMap)subMeshData["PositionDomain"])["Max"].AsVector3();
211 OpenMetaverse.Vector3 posMin = ((OSDMap)subMeshData["PositionDomain"])["Min"].AsVector3();
212 ushort faceIndexOffset = (ushort)coords.Count;
213
214 byte[] posBytes = subMeshData["Position"].AsBinary();
215 for (int i = 0; i < posBytes.Length; i += 6)
216 {
217 ushort uX = Utils.BytesToUInt16(posBytes, i);
218 ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
219 ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
220
221 Coord c = new Coord(
222 Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X,
223 Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y,
224 Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z);
225
226 coords.Add(c);
227 }
228
229 byte[] triangleBytes = subMeshData["TriangleList"].AsBinary();
230 for (int i = 0; i < triangleBytes.Length; i += 6)
231 {
232 ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset);
233 ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset);
234 ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset);
235 Face f = new Face(v1, v2, v3);
236 faces.Add(f);
237 }
238 }
239
240 /// <summary>
241 /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type.
242 /// </summary>
243 /// <param name="primName"></param>
244 /// <param name="primShape"></param>
245 /// <param name="size"></param>
246 /// <param name="lod"></param>
247 /// <returns></returns>
248 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
249 {
250// m_log.DebugFormat(
251// "[MESH]: Creating physics proxy for {0}, shape {1}",
252// primName, (OpenMetaverse.SculptType)primShape.SculptType);
253
254 List<Coord> coords;
255 List<Face> faces;
256
257 if (primShape.SculptEntry)
258 {
259 if (((OpenMetaverse.SculptType)primShape.SculptType) == SculptType.Mesh)
260 {
261 if (!useMeshiesPhysicsMesh)
262 return null;
263
264 if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces))
265 return null;
266 }
267 else
268 {
269 if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces))
270 return null;
271 }
272 }
273 else
274 {
275 if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces))
276 return null;
277 }
278
279 // Remove the reference to any JPEG2000 sculpt data so it can be GCed
280 primShape.SculptData = Utils.EmptyBytes;
281
282 int numCoords = coords.Count;
283 int numFaces = faces.Count;
284
285 // Create the list of vertices
286 List<Vertex> vertices = new List<Vertex>();
287 for (int i = 0; i < numCoords; i++)
288 {
289 Coord c = coords[i];
290 vertices.Add(new Vertex(c.X, c.Y, c.Z));
291 }
292
293 Mesh mesh = new Mesh();
294 // Add the corresponding triangles to the mesh
295 for (int i = 0; i < numFaces; i++)
296 {
297 Face f = faces[i];
298 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
299 }
300
301 return mesh;
302 }
303
304 /// <summary>
305 /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim.
306 /// </summary>
307 /// <param name="primName"></param>
308 /// <param name="primShape"></param>
309 /// <param name="size"></param>
310 /// <param name="coords">Coords are added to this list by the method.</param>
311 /// <param name="faces">Faces are added to this list by the method.</param>
312 /// <returns>true if coords and faces were successfully generated, false if not</returns>
313 private bool GenerateCoordsAndFacesFromPrimMeshData(
314 string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces)
315 {
316// m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
317
318 coords = new List<Coord>();
319 faces = new List<Face>();
320 OSD meshOsd = null;
321
322 if (primShape.SculptData.Length <= 0)
323 {
324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
325 // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
326 // The first time will always call with unloaded SculptData if this needs to be uploaded.
327// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
328 return false;
329 }
330
331 long start = 0;
332 using (MemoryStream data = new MemoryStream(primShape.SculptData))
333 {
334 try
335 {
336 OSD osd = OSDParser.DeserializeLLSDBinary(data);
337 if (osd is OSDMap)
338 meshOsd = (OSDMap)osd;
339 else
340 {
341 m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
342 return false;
343 }
344 }
345 catch (Exception e)
346 {
347 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
348 }
349
350 start = data.Position;
351 }
352
353 if (meshOsd is OSDMap)
354 {
355 OSDMap physicsParms = null;
356 OSDMap map = (OSDMap)meshOsd;
357 if (map.ContainsKey("physics_shape"))
358 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
359 else if (map.ContainsKey("physics_mesh"))
360 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
361
362 if (physicsParms == null)
363 {
364 m_log.WarnFormat("[MESH]: No recognized physics mesh found in mesh asset for {0}", primName);
365 return false;
366 }
367
368 int physOffset = physicsParms["offset"].AsInteger() + (int)start;
369 int physSize = physicsParms["size"].AsInteger();
370
371 if (physOffset < 0 || physSize == 0)
372 return false; // no mesh data in asset
373
374 OSD decodedMeshOsd = new OSD();
375 byte[] meshBytes = new byte[physSize];
376 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
377// byte[] decompressed = new byte[physSize * 5];
378 try
379 {
380 using (MemoryStream inMs = new MemoryStream(meshBytes))
381 {
382 using (MemoryStream outMs = new MemoryStream())
383 {
384 using (ZOutputStream zOut = new ZOutputStream(outMs))
385 {
386 byte[] readBuffer = new byte[2048];
387 int readLen = 0;
388 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
389 {
390 zOut.Write(readBuffer, 0, readLen);
391 }
392 zOut.Flush();
393 outMs.Seek(0, SeekOrigin.Begin);
394
395 byte[] decompressedBuf = outMs.GetBuffer();
396
397 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
398 }
399 }
400 }
401 }
402 catch (Exception e)
403 {
404 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString());
405 return false;
406 }
407
408 OSDArray decodedMeshOsdArray = null;
409
410 // physics_shape is an array of OSDMaps, one for each submesh
411 if (decodedMeshOsd is OSDArray)
412 {
413// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
414
415 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
416 foreach (OSD subMeshOsd in decodedMeshOsdArray)
417 {
418 if (subMeshOsd is OSDMap)
419 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
420 }
421 }
422 }
423
424 return true;
425 }
426
427 /// <summary>
428 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
429 /// </summary>
430 /// <param name="primName"></param>
431 /// <param name="primShape"></param>
432 /// <param name="size"></param>
433 /// <param name="lod"></param>
434 /// <param name="coords">Coords are added to this list by the method.</param>
435 /// <param name="faces">Faces are added to this list by the method.</param>
436 /// <returns>true if coords and faces were successfully generated, false if not</returns>
437 private bool GenerateCoordsAndFacesFromPrimSculptData(
438 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
439 {
440 coords = new List<Coord>();
441 faces = new List<Face>();
442 PrimMesher.SculptMesh sculptMesh;
443 Image idata = null;
444 string decodedSculptFileName = "";
445
446 if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero)
447 {
448 decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString());
449 try
450 {
451 if (File.Exists(decodedSculptFileName))
452 {
453 idata = Image.FromFile(decodedSculptFileName);
454 }
455 }
456 catch (Exception e)
457 {
458 m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message);
459
460 }
461 //if (idata != null)
462 // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString());
463 }
464
465 if (idata == null)
466 {
467 if (primShape.SculptData == null || primShape.SculptData.Length == 0)
468 return false;
469
470 try
471 {
472 OpenMetaverse.Imaging.ManagedImage unusedData;
473 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata);
474
475 if (idata == null)
476 {
477 // In some cases it seems that the decode can return a null bitmap without throwing
478 // an exception
479 m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
480
481 return false;
482 }
483
484 unusedData = null;
485
486 //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData);
487
488 if (cacheSculptMaps)
489 {
490 try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
491 catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
492 }
493 }
494 catch (DllNotFoundException)
495 {
496 m_log.Error("[PHYSICS]: OpenJpeg is not installed correctly on this system. Physics Proxy generation failed. Often times this is because of an old version of GLIBC. You must have version 2.4 or above!");
497 return false;
498 }
499 catch (IndexOutOfRangeException)
500 {
501 m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
502 return false;
503 }
504 catch (Exception ex)
505 {
506 m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
507 return false;
508 }
509 }
510
511 PrimMesher.SculptMesh.SculptType sculptType;
512 switch ((OpenMetaverse.SculptType)primShape.SculptType)
513 {
514 case OpenMetaverse.SculptType.Cylinder:
515 sculptType = PrimMesher.SculptMesh.SculptType.cylinder;
516 break;
517 case OpenMetaverse.SculptType.Plane:
518 sculptType = PrimMesher.SculptMesh.SculptType.plane;
519 break;
520 case OpenMetaverse.SculptType.Torus:
521 sculptType = PrimMesher.SculptMesh.SculptType.torus;
522 break;
523 case OpenMetaverse.SculptType.Sphere:
524 sculptType = PrimMesher.SculptMesh.SculptType.sphere;
525 break;
526 default:
527 sculptType = PrimMesher.SculptMesh.SculptType.plane;
528 break;
529 }
530
531 bool mirror = ((primShape.SculptType & 128) != 0);
532 bool invert = ((primShape.SculptType & 64) != 0);
533
534 sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert);
535
536 idata.Dispose();
537
538 sculptMesh.DumpRaw(baseDir, primName, "primMesh");
539
540 sculptMesh.Scale(size.X, size.Y, size.Z);
541
542 coords = sculptMesh.coords;
543 faces = sculptMesh.faces;
544
545 return true;
546 }
547
548 /// <summary>
549 /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim.
550 /// </summary>
551 /// <param name="primName"></param>
552 /// <param name="primShape"></param>
553 /// <param name="size"></param>
554 /// <param name="coords">Coords are added to this list by the method.</param>
555 /// <param name="faces">Faces are added to this list by the method.</param>
556 /// <returns>true if coords and faces were successfully generated, false if not</returns>
557 private bool GenerateCoordsAndFacesFromPrimShapeData(
558 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
559 {
560 PrimMesh primMesh;
561 coords = new List<Coord>();
562 faces = new List<Face>();
563
564 float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
565 float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
566 float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
567 float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
568 float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
569 float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;
570
571 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
572 float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
573 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
574 if (profileHollow > 0.95f)
575 profileHollow = 0.95f;
576
577 int sides = 4;
578 LevelOfDetail iLOD = (LevelOfDetail)lod;
579 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
580 sides = 3;
581 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
582 {
583 switch (iLOD)
584 {
585 case LevelOfDetail.High: sides = 24; break;
586 case LevelOfDetail.Medium: sides = 12; break;
587 case LevelOfDetail.Low: sides = 6; break;
588 case LevelOfDetail.VeryLow: sides = 3; break;
589 default: sides = 24; break;
590 }
591 }
592 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
593 { // half circle, prim is a sphere
594 switch (iLOD)
595 {
596 case LevelOfDetail.High: sides = 24; break;
597 case LevelOfDetail.Medium: sides = 12; break;
598 case LevelOfDetail.Low: sides = 6; break;
599 case LevelOfDetail.VeryLow: sides = 3; break;
600 default: sides = 24; break;
601 }
602
603 profileBegin = 0.5f * profileBegin + 0.5f;
604 profileEnd = 0.5f * profileEnd + 0.5f;
605 }
606
607 int hollowSides = sides;
608 if (primShape.HollowShape == HollowShape.Circle)
609 {
610 switch (iLOD)
611 {
612 case LevelOfDetail.High: hollowSides = 24; break;
613 case LevelOfDetail.Medium: hollowSides = 12; break;
614 case LevelOfDetail.Low: hollowSides = 6; break;
615 case LevelOfDetail.VeryLow: hollowSides = 3; break;
616 default: hollowSides = 24; break;
617 }
618 }
619 else if (primShape.HollowShape == HollowShape.Square)
620 hollowSides = 4;
621 else if (primShape.HollowShape == HollowShape.Triangle)
622 hollowSides = 3;
623
624 primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
625
626 if (primMesh.errorMessage != null)
627 if (primMesh.errorMessage.Length > 0)
628 m_log.Error("[ERROR] " + primMesh.errorMessage);
629
630 primMesh.topShearX = pathShearX;
631 primMesh.topShearY = pathShearY;
632 primMesh.pathCutBegin = pathBegin;
633 primMesh.pathCutEnd = pathEnd;
634
635 if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible)
636 {
637 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
638 primMesh.twistEnd = primShape.PathTwist * 18 / 10;
639 primMesh.taperX = pathScaleX;
640 primMesh.taperY = pathScaleY;
641
642 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
643 {
644 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
645 if (profileBegin < 0.0f) profileBegin = 0.0f;
646 if (profileEnd > 1.0f) profileEnd = 1.0f;
647 }
648#if SPAM
649 m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
650#endif
651 try
652 {
653 primMesh.ExtrudeLinear();
654 }
655 catch (Exception ex)
656 {
657 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
658 return false;
659 }
660 }
661 else
662 {
663 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
664 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
665 primMesh.radius = 0.01f * primShape.PathRadiusOffset;
666 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
667 primMesh.skew = 0.01f * primShape.PathSkew;
668 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10;
669 primMesh.twistEnd = primShape.PathTwist * 36 / 10;
670 primMesh.taperX = primShape.PathTaperX * 0.01f;
671 primMesh.taperY = primShape.PathTaperY * 0.01f;
672
673 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
674 {
675 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
676 if (profileBegin < 0.0f) profileBegin = 0.0f;
677 if (profileEnd > 1.0f) profileEnd = 1.0f;
678 }
679#if SPAM
680 m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
681#endif
682 try
683 {
684 primMesh.ExtrudeCircular();
685 }
686 catch (Exception ex)
687 {
688 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
689 return false;
690 }
691 }
692
693 primMesh.DumpRaw(baseDir, primName, "primMesh");
694
695 primMesh.Scale(size.X, size.Y, size.Z);
696
697 coords = primMesh.coords;
698 faces = primMesh.faces;
699
700 return true;
701 }
702
703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
704 {
705 return CreateMesh(primName, primShape, size, lod, false, true);
706 }
707
708 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
709 {
710 return CreateMesh(primName, primShape, size, lod, isPhysical, true);
711 }
712
713 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
714 {
715#if SPAM
716 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
717#endif
718
719 Mesh mesh = null;
720 ulong key = 0;
721
722 // If this mesh has been created already, return it instead of creating another copy
723 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
724 if (shouldCache)
725 {
726 key = primShape.GetMeshKey(size, lod);
727 if (m_uniqueMeshes.TryGetValue(key, out mesh))
728 return mesh;
729 }
730
731 if (size.X < 0.01f) size.X = 0.01f;
732 if (size.Y < 0.01f) size.Y = 0.01f;
733 if (size.Z < 0.01f) size.Z = 0.01f;
734
735 mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
736
737 if (mesh != null)
738 {
739 if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh)
740 {
741#if SPAM
742 m_log.Debug("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " +
743 minSizeForComplexMesh.ToString() + " - creating simple bounding box");
744#endif
745 mesh = CreateBoundingBoxMesh(mesh);
746 mesh.DumpRaw(baseDir, primName, "Z extruded");
747 }
748
749 // trim the vertex and triangle lists to free up memory
750 mesh.TrimExcess();
751
752 if (shouldCache)
753 {
754 m_uniqueMeshes.Add(key, mesh);
755 }
756 }
757
758 return mesh;
759 }
760 }
761}
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs
deleted file mode 100644
index 4049ee1..0000000
--- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs
+++ /dev/null
@@ -1,2324 +0,0 @@
1/*
2 * Copyright (c) Contributors
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 System.IO;
32
33namespace PrimMesher
34{
35 public struct Quat
36 {
37 /// <summary>X value</summary>
38 public float X;
39 /// <summary>Y value</summary>
40 public float Y;
41 /// <summary>Z value</summary>
42 public float Z;
43 /// <summary>W value</summary>
44 public float W;
45
46 public Quat(float x, float y, float z, float w)
47 {
48 X = x;
49 Y = y;
50 Z = z;
51 W = w;
52 }
53
54 public Quat(Coord axis, float angle)
55 {
56 axis = axis.Normalize();
57
58 angle *= 0.5f;
59 float c = (float)Math.Cos(angle);
60 float s = (float)Math.Sin(angle);
61
62 X = axis.X * s;
63 Y = axis.Y * s;
64 Z = axis.Z * s;
65 W = c;
66
67 Normalize();
68 }
69
70 public float Length()
71 {
72 return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W);
73 }
74
75 public Quat Normalize()
76 {
77 const float MAG_THRESHOLD = 0.0000001f;
78 float mag = Length();
79
80 // Catch very small rounding errors when normalizing
81 if (mag > MAG_THRESHOLD)
82 {
83 float oomag = 1f / mag;
84 X *= oomag;
85 Y *= oomag;
86 Z *= oomag;
87 W *= oomag;
88 }
89 else
90 {
91 X = 0f;
92 Y = 0f;
93 Z = 0f;
94 W = 1f;
95 }
96
97 return this;
98 }
99
100 public static Quat operator *(Quat q1, Quat q2)
101 {
102 float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y;
103 float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X;
104 float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W;
105 float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z;
106 return new Quat(x, y, z, w);
107 }
108
109 public override string ToString()
110 {
111 return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">";
112 }
113 }
114
115 public struct Coord
116 {
117 public float X;
118 public float Y;
119 public float Z;
120
121 public Coord(float x, float y, float z)
122 {
123 this.X = x;
124 this.Y = y;
125 this.Z = z;
126 }
127
128 public float Length()
129 {
130 return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z);
131 }
132
133 public Coord Invert()
134 {
135 this.X = -this.X;
136 this.Y = -this.Y;
137 this.Z = -this.Z;
138
139 return this;
140 }
141
142 public Coord Normalize()
143 {
144 const float MAG_THRESHOLD = 0.0000001f;
145 float mag = Length();
146
147 // Catch very small rounding errors when normalizing
148 if (mag > MAG_THRESHOLD)
149 {
150 float oomag = 1.0f / mag;
151 this.X *= oomag;
152 this.Y *= oomag;
153 this.Z *= oomag;
154 }
155 else
156 {
157 this.X = 0.0f;
158 this.Y = 0.0f;
159 this.Z = 0.0f;
160 }
161
162 return this;
163 }
164
165 public override string ToString()
166 {
167 return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString();
168 }
169
170 public static Coord Cross(Coord c1, Coord c2)
171 {
172 return new Coord(
173 c1.Y * c2.Z - c2.Y * c1.Z,
174 c1.Z * c2.X - c2.Z * c1.X,
175 c1.X * c2.Y - c2.X * c1.Y
176 );
177 }
178
179 public static Coord operator +(Coord v, Coord a)
180 {
181 return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z);
182 }
183
184 public static Coord operator *(Coord v, Coord m)
185 {
186 return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z);
187 }
188
189 public static Coord operator *(Coord v, Quat q)
190 {
191 // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/
192
193 Coord c2 = new Coord(0.0f, 0.0f, 0.0f);
194
195 c2.X = q.W * q.W * v.X +
196 2f * q.Y * q.W * v.Z -
197 2f * q.Z * q.W * v.Y +
198 q.X * q.X * v.X +
199 2f * q.Y * q.X * v.Y +
200 2f * q.Z * q.X * v.Z -
201 q.Z * q.Z * v.X -
202 q.Y * q.Y * v.X;
203
204 c2.Y =
205 2f * q.X * q.Y * v.X +
206 q.Y * q.Y * v.Y +
207 2f * q.Z * q.Y * v.Z +
208 2f * q.W * q.Z * v.X -
209 q.Z * q.Z * v.Y +
210 q.W * q.W * v.Y -
211 2f * q.X * q.W * v.Z -
212 q.X * q.X * v.Y;
213
214 c2.Z =
215 2f * q.X * q.Z * v.X +
216 2f * q.Y * q.Z * v.Y +
217 q.Z * q.Z * v.Z -
218 2f * q.W * q.Y * v.X -
219 q.Y * q.Y * v.Z +
220 2f * q.W * q.X * v.Y -
221 q.X * q.X * v.Z +
222 q.W * q.W * v.Z;
223
224 return c2;
225 }
226 }
227
228 public struct UVCoord
229 {
230 public float U;
231 public float V;
232
233
234 public UVCoord(float u, float v)
235 {
236 this.U = u;
237 this.V = v;
238 }
239
240 public UVCoord Flip()
241 {
242 this.U = 1.0f - this.U;
243 this.V = 1.0f - this.V;
244 return this;
245 }
246 }
247
248 public struct Face
249 {
250 public int primFace;
251
252 // vertices
253 public int v1;
254 public int v2;
255 public int v3;
256
257 //normals
258 public int n1;
259 public int n2;
260 public int n3;
261
262 // uvs
263 public int uv1;
264 public int uv2;
265 public int uv3;
266
267 public Face(int v1, int v2, int v3)
268 {
269 primFace = 0;
270
271 this.v1 = v1;
272 this.v2 = v2;
273 this.v3 = v3;
274
275 this.n1 = 0;
276 this.n2 = 0;
277 this.n3 = 0;
278
279 this.uv1 = 0;
280 this.uv2 = 0;
281 this.uv3 = 0;
282
283 }
284
285 public Face(int v1, int v2, int v3, int n1, int n2, int n3)
286 {
287 primFace = 0;
288
289 this.v1 = v1;
290 this.v2 = v2;
291 this.v3 = v3;
292
293 this.n1 = n1;
294 this.n2 = n2;
295 this.n3 = n3;
296
297 this.uv1 = 0;
298 this.uv2 = 0;
299 this.uv3 = 0;
300 }
301
302 public Coord SurfaceNormal(List<Coord> coordList)
303 {
304 Coord c1 = coordList[this.v1];
305 Coord c2 = coordList[this.v2];
306 Coord c3 = coordList[this.v3];
307
308 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
309 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
310
311 return Coord.Cross(edge1, edge2).Normalize();
312 }
313 }
314
315 public struct ViewerFace
316 {
317 public int primFaceNumber;
318
319 public Coord v1;
320 public Coord v2;
321 public Coord v3;
322
323 public int coordIndex1;
324 public int coordIndex2;
325 public int coordIndex3;
326
327 public Coord n1;
328 public Coord n2;
329 public Coord n3;
330
331 public UVCoord uv1;
332 public UVCoord uv2;
333 public UVCoord uv3;
334
335 public ViewerFace(int primFaceNumber)
336 {
337 this.primFaceNumber = primFaceNumber;
338
339 this.v1 = new Coord();
340 this.v2 = new Coord();
341 this.v3 = new Coord();
342
343 this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet
344
345 this.n1 = new Coord();
346 this.n2 = new Coord();
347 this.n3 = new Coord();
348
349 this.uv1 = new UVCoord();
350 this.uv2 = new UVCoord();
351 this.uv3 = new UVCoord();
352 }
353
354 public void Scale(float x, float y, float z)
355 {
356 this.v1.X *= x;
357 this.v1.Y *= y;
358 this.v1.Z *= z;
359
360 this.v2.X *= x;
361 this.v2.Y *= y;
362 this.v2.Z *= z;
363
364 this.v3.X *= x;
365 this.v3.Y *= y;
366 this.v3.Z *= z;
367 }
368
369 public void AddPos(float x, float y, float z)
370 {
371 this.v1.X += x;
372 this.v2.X += x;
373 this.v3.X += x;
374
375 this.v1.Y += y;
376 this.v2.Y += y;
377 this.v3.Y += y;
378
379 this.v1.Z += z;
380 this.v2.Z += z;
381 this.v3.Z += z;
382 }
383
384 public void AddRot(Quat q)
385 {
386 this.v1 *= q;
387 this.v2 *= q;
388 this.v3 *= q;
389
390 this.n1 *= q;
391 this.n2 *= q;
392 this.n3 *= q;
393 }
394
395 public void CalcSurfaceNormal()
396 {
397
398 Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z);
399 Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z);
400
401 this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize();
402 }
403 }
404
405 internal struct Angle
406 {
407 internal float angle;
408 internal float X;
409 internal float Y;
410
411 internal Angle(float angle, float x, float y)
412 {
413 this.angle = angle;
414 this.X = x;
415 this.Y = y;
416 }
417 }
418
419 internal class AngleList
420 {
421 private float iX, iY; // intersection point
422
423 private static Angle[] angles3 =
424 {
425 new Angle(0.0f, 1.0f, 0.0f),
426 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
427 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
428 new Angle(1.0f, 1.0f, 0.0f)
429 };
430
431 private static Coord[] normals3 =
432 {
433 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(),
434 new Coord(-0.5f, 0.0f, 0.0f).Normalize(),
435 new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(),
436 new Coord(0.25f, 0.4330127019f, 0.0f).Normalize()
437 };
438
439 private static Angle[] angles4 =
440 {
441 new Angle(0.0f, 1.0f, 0.0f),
442 new Angle(0.25f, 0.0f, 1.0f),
443 new Angle(0.5f, -1.0f, 0.0f),
444 new Angle(0.75f, 0.0f, -1.0f),
445 new Angle(1.0f, 1.0f, 0.0f)
446 };
447
448 private static Coord[] normals4 =
449 {
450 new Coord(0.5f, 0.5f, 0.0f).Normalize(),
451 new Coord(-0.5f, 0.5f, 0.0f).Normalize(),
452 new Coord(-0.5f, -0.5f, 0.0f).Normalize(),
453 new Coord(0.5f, -0.5f, 0.0f).Normalize(),
454 new Coord(0.5f, 0.5f, 0.0f).Normalize()
455 };
456
457 private static Angle[] angles24 =
458 {
459 new Angle(0.0f, 1.0f, 0.0f),
460 new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f),
461 new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f),
462 new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f),
463 new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f),
464 new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f),
465 new Angle(0.25f, 0.0f, 1.0f),
466 new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f),
467 new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f),
468 new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f),
469 new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f),
470 new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f),
471 new Angle(0.5f, -1.0f, 0.0f),
472 new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f),
473 new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f),
474 new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f),
475 new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f),
476 new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f),
477 new Angle(0.75f, 0.0f, -1.0f),
478 new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f),
479 new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f),
480 new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f),
481 new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f),
482 new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f),
483 new Angle(1.0f, 1.0f, 0.0f)
484 };
485
486 private Angle interpolatePoints(float newPoint, Angle p1, Angle p2)
487 {
488 float m = (newPoint - p1.angle) / (p2.angle - p1.angle);
489 return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y));
490 }
491
492 private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
493 { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
494 double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
495 double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
496
497 if (denom != 0.0)
498 {
499 double ua = uaNumerator / denom;
500 iX = (float)(x1 + ua * (x2 - x1));
501 iY = (float)(y1 + ua * (y2 - y1));
502 }
503 }
504
505 internal List<Angle> angles;
506 internal List<Coord> normals;
507
508 internal void makeAngles(int sides, float startAngle, float stopAngle)
509 {
510 angles = new List<Angle>();
511 normals = new List<Coord>();
512
513 double twoPi = System.Math.PI * 2.0;
514 float twoPiInv = 1.0f / (float)twoPi;
515
516 if (sides < 1)
517 throw new Exception("number of sides not greater than zero");
518 if (stopAngle <= startAngle)
519 throw new Exception("stopAngle not greater than startAngle");
520
521 if ((sides == 3 || sides == 4 || sides == 24))
522 {
523 startAngle *= twoPiInv;
524 stopAngle *= twoPiInv;
525
526 Angle[] sourceAngles;
527 if (sides == 3)
528 sourceAngles = angles3;
529 else if (sides == 4)
530 sourceAngles = angles4;
531 else sourceAngles = angles24;
532
533 int startAngleIndex = (int)(startAngle * sides);
534 int endAngleIndex = sourceAngles.Length - 1;
535 if (stopAngle < 1.0f)
536 endAngleIndex = (int)(stopAngle * sides) + 1;
537 if (endAngleIndex == startAngleIndex)
538 endAngleIndex++;
539
540 for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++)
541 {
542 angles.Add(sourceAngles[angleIndex]);
543 if (sides == 3)
544 normals.Add(normals3[angleIndex]);
545 else if (sides == 4)
546 normals.Add(normals4[angleIndex]);
547 }
548
549 if (startAngle > 0.0f)
550 angles[0] = interpolatePoints(startAngle, angles[0], angles[1]);
551
552 if (stopAngle < 1.0f)
553 {
554 int lastAngleIndex = angles.Count - 1;
555 angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]);
556 }
557 }
558 else
559 {
560 double stepSize = twoPi / sides;
561
562 int startStep = (int)(startAngle / stepSize);
563 double angle = stepSize * startStep;
564 int step = startStep;
565 double stopAngleTest = stopAngle;
566 if (stopAngle < twoPi)
567 {
568 stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1);
569 if (stopAngleTest < stopAngle)
570 stopAngleTest += stepSize;
571 if (stopAngleTest > twoPi)
572 stopAngleTest = twoPi;
573 }
574
575 while (angle <= stopAngleTest)
576 {
577 Angle newAngle;
578 newAngle.angle = (float)angle;
579 newAngle.X = (float)System.Math.Cos(angle);
580 newAngle.Y = (float)System.Math.Sin(angle);
581 angles.Add(newAngle);
582 step += 1;
583 angle = stepSize * step;
584 }
585
586 if (startAngle > angles[0].angle)
587 {
588 Angle newAngle;
589 intersection(angles[0].X, angles[0].Y, angles[1].X, angles[1].Y, 0.0f, 0.0f, (float)Math.Cos(startAngle), (float)Math.Sin(startAngle));
590 newAngle.angle = startAngle;
591 newAngle.X = iX;
592 newAngle.Y = iY;
593 angles[0] = newAngle;
594 }
595
596 int index = angles.Count - 1;
597 if (stopAngle < angles[index].angle)
598 {
599 Angle newAngle;
600 intersection(angles[index - 1].X, angles[index - 1].Y, angles[index].X, angles[index].Y, 0.0f, 0.0f, (float)Math.Cos(stopAngle), (float)Math.Sin(stopAngle));
601 newAngle.angle = stopAngle;
602 newAngle.X = iX;
603 newAngle.Y = iY;
604 angles[index] = newAngle;
605 }
606 }
607 }
608 }
609
610 /// <summary>
611 /// generates a profile for extrusion
612 /// </summary>
613 public class Profile
614 {
615 private const float twoPi = 2.0f * (float)Math.PI;
616
617 public string errorMessage = null;
618
619 public List<Coord> coords;
620 public List<Face> faces;
621 public List<Coord> vertexNormals;
622 public List<float> us;
623 public List<UVCoord> faceUVs;
624 public List<int> faceNumbers;
625
626 // use these for making individual meshes for each prim face
627 public List<int> outerCoordIndices = null;
628 public List<int> hollowCoordIndices = null;
629 public List<int> cut1CoordIndices = null;
630 public List<int> cut2CoordIndices = null;
631
632 public Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f);
633 public Coord cutNormal1 = new Coord();
634 public Coord cutNormal2 = new Coord();
635
636 public int numOuterVerts = 0;
637 public int numHollowVerts = 0;
638
639 public int outerFaceNumber = -1;
640 public int hollowFaceNumber = -1;
641
642 public bool calcVertexNormals = false;
643 public int bottomFaceNumber = 0;
644 public int numPrimFaces = 0;
645
646 public Profile()
647 {
648 this.coords = new List<Coord>();
649 this.faces = new List<Face>();
650 this.vertexNormals = new List<Coord>();
651 this.us = new List<float>();
652 this.faceUVs = new List<UVCoord>();
653 this.faceNumbers = new List<int>();
654 }
655
656 public Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals)
657 {
658 this.calcVertexNormals = calcVertexNormals;
659 this.coords = new List<Coord>();
660 this.faces = new List<Face>();
661 this.vertexNormals = new List<Coord>();
662 this.us = new List<float>();
663 this.faceUVs = new List<UVCoord>();
664 this.faceNumbers = new List<int>();
665
666 Coord center = new Coord(0.0f, 0.0f, 0.0f);
667
668 List<Coord> hollowCoords = new List<Coord>();
669 List<Coord> hollowNormals = new List<Coord>();
670 List<float> hollowUs = new List<float>();
671
672 if (calcVertexNormals)
673 {
674 this.outerCoordIndices = new List<int>();
675 this.hollowCoordIndices = new List<int>();
676 this.cut1CoordIndices = new List<int>();
677 this.cut2CoordIndices = new List<int>();
678 }
679
680 bool hasHollow = (hollow > 0.0f);
681
682 bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f);
683
684 AngleList angles = new AngleList();
685 AngleList hollowAngles = new AngleList();
686
687 float xScale = 0.5f;
688 float yScale = 0.5f;
689 if (sides == 4) // corners of a square are sqrt(2) from center
690 {
691 xScale = 0.707107f;
692 yScale = 0.707107f;
693 }
694
695 float startAngle = profileStart * twoPi;
696 float stopAngle = profileEnd * twoPi;
697
698 try { angles.makeAngles(sides, startAngle, stopAngle); }
699 catch (Exception ex)
700 {
701
702 errorMessage = "makeAngles failed: Exception: " + ex.ToString()
703 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString();
704
705 return;
706 }
707
708 this.numOuterVerts = angles.angles.Count;
709
710 // flag to create as few triangles as possible for 3 or 4 side profile
711 bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut);
712
713 if (hasHollow)
714 {
715 if (sides == hollowSides)
716 hollowAngles = angles;
717 else
718 {
719 try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); }
720 catch (Exception ex)
721 {
722 errorMessage = "makeAngles failed: Exception: " + ex.ToString()
723 + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString();
724
725 return;
726 }
727 }
728 this.numHollowVerts = hollowAngles.angles.Count;
729 }
730 else if (!simpleFace)
731 {
732 this.coords.Add(center);
733 if (this.calcVertexNormals)
734 this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f));
735 this.us.Add(0.0f);
736 }
737
738 float z = 0.0f;
739
740 Angle angle;
741 Coord newVert = new Coord();
742 if (hasHollow && hollowSides != sides)
743 {
744 int numHollowAngles = hollowAngles.angles.Count;
745 for (int i = 0; i < numHollowAngles; i++)
746 {
747 angle = hollowAngles.angles[i];
748 newVert.X = hollow * xScale * angle.X;
749 newVert.Y = hollow * yScale * angle.Y;
750 newVert.Z = z;
751
752 hollowCoords.Add(newVert);
753 if (this.calcVertexNormals)
754 {
755 if (hollowSides < 5)
756 hollowNormals.Add(hollowAngles.normals[i].Invert());
757 else
758 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
759
760 if (hollowSides == 4)
761 hollowUs.Add(angle.angle * hollow * 0.707107f);
762 else
763 hollowUs.Add(angle.angle * hollow);
764 }
765 }
766 }
767
768 int index = 0;
769 int numAngles = angles.angles.Count;
770
771 for (int i = 0; i < numAngles; i++)
772 {
773 angle = angles.angles[i];
774 newVert.X = angle.X * xScale;
775 newVert.Y = angle.Y * yScale;
776 newVert.Z = z;
777 this.coords.Add(newVert);
778 if (this.calcVertexNormals)
779 {
780 this.outerCoordIndices.Add(this.coords.Count - 1);
781
782 if (sides < 5)
783 {
784 this.vertexNormals.Add(angles.normals[i]);
785 float u = angle.angle;
786 this.us.Add(u);
787 }
788 else
789 {
790 this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f));
791 this.us.Add(angle.angle);
792 }
793 }
794
795 if (hasHollow)
796 {
797 if (hollowSides == sides)
798 {
799 newVert.X *= hollow;
800 newVert.Y *= hollow;
801 newVert.Z = z;
802 hollowCoords.Add(newVert);
803 if (this.calcVertexNormals)
804 {
805 if (sides < 5)
806 {
807 hollowNormals.Add(angles.normals[i].Invert());
808 }
809
810 else
811 hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f));
812
813 hollowUs.Add(angle.angle * hollow);
814 }
815 }
816 }
817 else if (!simpleFace && createFaces && angle.angle > 0.0001f)
818 {
819 Face newFace = new Face();
820 newFace.v1 = 0;
821 newFace.v2 = index;
822 newFace.v3 = index + 1;
823
824 this.faces.Add(newFace);
825 }
826 index += 1;
827 }
828
829 if (hasHollow)
830 {
831 hollowCoords.Reverse();
832 if (this.calcVertexNormals)
833 {
834 hollowNormals.Reverse();
835 hollowUs.Reverse();
836 }
837
838 if (createFaces)
839 {
840 int numTotalVerts = this.numOuterVerts + this.numHollowVerts;
841
842 if (this.numOuterVerts == this.numHollowVerts)
843 {
844 Face newFace = new Face();
845
846 for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++)
847 {
848 newFace.v1 = coordIndex;
849 newFace.v2 = coordIndex + 1;
850 newFace.v3 = numTotalVerts - coordIndex - 1;
851 this.faces.Add(newFace);
852
853 newFace.v1 = coordIndex + 1;
854 newFace.v2 = numTotalVerts - coordIndex - 2;
855 newFace.v3 = numTotalVerts - coordIndex - 1;
856 this.faces.Add(newFace);
857 }
858 }
859 else
860 {
861 if (this.numOuterVerts < this.numHollowVerts)
862 {
863 Face newFace = new Face();
864 int j = 0; // j is the index for outer vertices
865 int maxJ = this.numOuterVerts - 1;
866 for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices
867 {
868 if (j < maxJ)
869 if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f)
870 {
871 newFace.v1 = numTotalVerts - i - 1;
872 newFace.v2 = j;
873 newFace.v3 = j + 1;
874
875 this.faces.Add(newFace);
876 j += 1;
877 }
878
879 newFace.v1 = j;
880 newFace.v2 = numTotalVerts - i - 2;
881 newFace.v3 = numTotalVerts - i - 1;
882
883 this.faces.Add(newFace);
884 }
885 }
886 else // numHollowVerts < numOuterVerts
887 {
888 Face newFace = new Face();
889 int j = 0; // j is the index for inner vertices
890 int maxJ = this.numHollowVerts - 1;
891 for (int i = 0; i < this.numOuterVerts; i++)
892 {
893 if (j < maxJ)
894 if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f)
895 {
896 newFace.v1 = i;
897 newFace.v2 = numTotalVerts - j - 2;
898 newFace.v3 = numTotalVerts - j - 1;
899
900 this.faces.Add(newFace);
901 j += 1;
902 }
903
904 newFace.v1 = numTotalVerts - j - 1;
905 newFace.v2 = i;
906 newFace.v3 = i + 1;
907
908 this.faces.Add(newFace);
909 }
910 }
911 }
912 }
913
914 if (calcVertexNormals)
915 {
916 foreach (Coord hc in hollowCoords)
917 {
918 this.coords.Add(hc);
919 hollowCoordIndices.Add(this.coords.Count - 1);
920 }
921 }
922 else
923 this.coords.AddRange(hollowCoords);
924
925 if (this.calcVertexNormals)
926 {
927 this.vertexNormals.AddRange(hollowNormals);
928 this.us.AddRange(hollowUs);
929
930 }
931 }
932
933 if (simpleFace && createFaces)
934 {
935 if (sides == 3)
936 this.faces.Add(new Face(0, 1, 2));
937 else if (sides == 4)
938 {
939 this.faces.Add(new Face(0, 1, 2));
940 this.faces.Add(new Face(0, 2, 3));
941 }
942 }
943
944 if (calcVertexNormals && hasProfileCut)
945 {
946 int lastOuterVertIndex = this.numOuterVerts - 1;
947
948 if (hasHollow)
949 {
950 this.cut1CoordIndices.Add(0);
951 this.cut1CoordIndices.Add(this.coords.Count - 1);
952
953 this.cut2CoordIndices.Add(lastOuterVertIndex + 1);
954 this.cut2CoordIndices.Add(lastOuterVertIndex);
955
956 this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y;
957 this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X);
958
959 this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y;
960 this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X);
961 }
962
963 else
964 {
965 this.cut1CoordIndices.Add(0);
966 this.cut1CoordIndices.Add(1);
967
968 this.cut2CoordIndices.Add(lastOuterVertIndex);
969 this.cut2CoordIndices.Add(0);
970
971 this.cutNormal1.X = this.vertexNormals[1].Y;
972 this.cutNormal1.Y = -this.vertexNormals[1].X;
973
974 this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y;
975 this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X;
976
977 }
978 this.cutNormal1.Normalize();
979 this.cutNormal2.Normalize();
980 }
981
982 this.MakeFaceUVs();
983
984 hollowCoords = null;
985 hollowNormals = null;
986 hollowUs = null;
987
988 if (calcVertexNormals)
989 { // calculate prim face numbers
990
991 // face number order is top, outer, hollow, bottom, start cut, end cut
992 // I know it's ugly but so is the whole concept of prim face numbers
993
994 int faceNum = 1; // start with outer faces
995 this.outerFaceNumber = faceNum;
996
997 int startVert = hasProfileCut && !hasHollow ? 1 : 0;
998 if (startVert > 0)
999 this.faceNumbers.Add(-1);
1000 for (int i = 0; i < this.numOuterVerts - 1; i++)
1001 this.faceNumbers.Add(sides < 5 && i <= sides ? faceNum++ : faceNum);
1002
1003 this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++);
1004
1005 if (sides > 4 && (hasHollow || hasProfileCut))
1006 faceNum++;
1007
1008 if (sides < 5 && (hasHollow || hasProfileCut) && this.numOuterVerts < sides)
1009 faceNum++;
1010
1011 if (hasHollow)
1012 {
1013 for (int i = 0; i < this.numHollowVerts; i++)
1014 this.faceNumbers.Add(faceNum);
1015
1016 this.hollowFaceNumber = faceNum++;
1017 }
1018
1019 this.bottomFaceNumber = faceNum++;
1020
1021 if (hasHollow && hasProfileCut)
1022 this.faceNumbers.Add(faceNum++);
1023
1024 for (int i = 0; i < this.faceNumbers.Count; i++)
1025 if (this.faceNumbers[i] == -1)
1026 this.faceNumbers[i] = faceNum++;
1027
1028 this.numPrimFaces = faceNum;
1029 }
1030
1031 }
1032
1033 public void MakeFaceUVs()
1034 {
1035 this.faceUVs = new List<UVCoord>();
1036 foreach (Coord c in this.coords)
1037 this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y)));
1038 }
1039
1040 public Profile Copy()
1041 {
1042 return this.Copy(true);
1043 }
1044
1045 public Profile Copy(bool needFaces)
1046 {
1047 Profile copy = new Profile();
1048
1049 copy.coords.AddRange(this.coords);
1050 copy.faceUVs.AddRange(this.faceUVs);
1051
1052 if (needFaces)
1053 copy.faces.AddRange(this.faces);
1054 if ((copy.calcVertexNormals = this.calcVertexNormals) == true)
1055 {
1056 copy.vertexNormals.AddRange(this.vertexNormals);
1057 copy.faceNormal = this.faceNormal;
1058 copy.cutNormal1 = this.cutNormal1;
1059 copy.cutNormal2 = this.cutNormal2;
1060 copy.us.AddRange(this.us);
1061 copy.faceNumbers.AddRange(this.faceNumbers);
1062
1063 copy.cut1CoordIndices = new List<int>(this.cut1CoordIndices);
1064 copy.cut2CoordIndices = new List<int>(this.cut2CoordIndices);
1065 copy.hollowCoordIndices = new List<int>(this.hollowCoordIndices);
1066 copy.outerCoordIndices = new List<int>(this.outerCoordIndices);
1067 }
1068 copy.numOuterVerts = this.numOuterVerts;
1069 copy.numHollowVerts = this.numHollowVerts;
1070
1071 return copy;
1072 }
1073
1074 public void AddPos(Coord v)
1075 {
1076 this.AddPos(v.X, v.Y, v.Z);
1077 }
1078
1079 public void AddPos(float x, float y, float z)
1080 {
1081 int i;
1082 int numVerts = this.coords.Count;
1083 Coord vert;
1084
1085 for (i = 0; i < numVerts; i++)
1086 {
1087 vert = this.coords[i];
1088 vert.X += x;
1089 vert.Y += y;
1090 vert.Z += z;
1091 this.coords[i] = vert;
1092 }
1093 }
1094
1095 public void AddRot(Quat q)
1096 {
1097 int i;
1098 int numVerts = this.coords.Count;
1099
1100 for (i = 0; i < numVerts; i++)
1101 this.coords[i] *= q;
1102
1103 if (this.calcVertexNormals)
1104 {
1105 int numNormals = this.vertexNormals.Count;
1106 for (i = 0; i < numNormals; i++)
1107 this.vertexNormals[i] *= q;
1108
1109 this.faceNormal *= q;
1110 this.cutNormal1 *= q;
1111 this.cutNormal2 *= q;
1112
1113 }
1114 }
1115
1116 public void Scale(float x, float y)
1117 {
1118 int i;
1119 int numVerts = this.coords.Count;
1120 Coord vert;
1121
1122 for (i = 0; i < numVerts; i++)
1123 {
1124 vert = this.coords[i];
1125 vert.X *= x;
1126 vert.Y *= y;
1127 this.coords[i] = vert;
1128 }
1129 }
1130
1131 /// <summary>
1132 /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices
1133 /// </summary>
1134 public void FlipNormals()
1135 {
1136 int i;
1137 int numFaces = this.faces.Count;
1138 Face tmpFace;
1139 int tmp;
1140
1141 for (i = 0; i < numFaces; i++)
1142 {
1143 tmpFace = this.faces[i];
1144 tmp = tmpFace.v3;
1145 tmpFace.v3 = tmpFace.v1;
1146 tmpFace.v1 = tmp;
1147 this.faces[i] = tmpFace;
1148 }
1149
1150 if (this.calcVertexNormals)
1151 {
1152 int normalCount = this.vertexNormals.Count;
1153 if (normalCount > 0)
1154 {
1155 Coord n = this.vertexNormals[normalCount - 1];
1156 n.Z = -n.Z;
1157 this.vertexNormals[normalCount - 1] = n;
1158 }
1159 }
1160
1161 this.faceNormal.X = -this.faceNormal.X;
1162 this.faceNormal.Y = -this.faceNormal.Y;
1163 this.faceNormal.Z = -this.faceNormal.Z;
1164
1165 int numfaceUVs = this.faceUVs.Count;
1166 for (i = 0; i < numfaceUVs; i++)
1167 {
1168 UVCoord uv = this.faceUVs[i];
1169 uv.V = 1.0f - uv.V;
1170 this.faceUVs[i] = uv;
1171 }
1172 }
1173
1174 public void AddValue2FaceVertexIndices(int num)
1175 {
1176 int numFaces = this.faces.Count;
1177 Face tmpFace;
1178 for (int i = 0; i < numFaces; i++)
1179 {
1180 tmpFace = this.faces[i];
1181 tmpFace.v1 += num;
1182 tmpFace.v2 += num;
1183 tmpFace.v3 += num;
1184
1185 this.faces[i] = tmpFace;
1186 }
1187 }
1188
1189 public void AddValue2FaceNormalIndices(int num)
1190 {
1191 if (this.calcVertexNormals)
1192 {
1193 int numFaces = this.faces.Count;
1194 Face tmpFace;
1195 for (int i = 0; i < numFaces; i++)
1196 {
1197 tmpFace = this.faces[i];
1198 tmpFace.n1 += num;
1199 tmpFace.n2 += num;
1200 tmpFace.n3 += num;
1201
1202 this.faces[i] = tmpFace;
1203 }
1204 }
1205 }
1206
1207 public void DumpRaw(String path, String name, String title)
1208 {
1209 if (path == null)
1210 return;
1211 String fileName = name + "_" + title + ".raw";
1212 String completePath = System.IO.Path.Combine(path, fileName);
1213 StreamWriter sw = new StreamWriter(completePath);
1214
1215 for (int i = 0; i < this.faces.Count; i++)
1216 {
1217 string s = this.coords[this.faces[i].v1].ToString();
1218 s += " " + this.coords[this.faces[i].v2].ToString();
1219 s += " " + this.coords[this.faces[i].v3].ToString();
1220
1221 sw.WriteLine(s);
1222 }
1223
1224 sw.Close();
1225 }
1226 }
1227
1228 public struct PathNode
1229 {
1230 public Coord position;
1231 public Quat rotation;
1232 public float xScale;
1233 public float yScale;
1234 public float percentOfPath;
1235 }
1236
1237 public enum PathType { Linear = 0, Circular = 1, Flexible = 2 }
1238
1239 public class Path
1240 {
1241 public List<PathNode> pathNodes = new List<PathNode>();
1242
1243 public float twistBegin = 0.0f;
1244 public float twistEnd = 0.0f;
1245 public float topShearX = 0.0f;
1246 public float topShearY = 0.0f;
1247 public float pathCutBegin = 0.0f;
1248 public float pathCutEnd = 1.0f;
1249 public float dimpleBegin = 0.0f;
1250 public float dimpleEnd = 1.0f;
1251 public float skew = 0.0f;
1252 public float holeSizeX = 1.0f; // called pathScaleX in pbs
1253 public float holeSizeY = 0.25f;
1254 public float taperX = 0.0f;
1255 public float taperY = 0.0f;
1256 public float radius = 0.0f;
1257 public float revolutions = 1.0f;
1258 public int stepsPerRevolution = 24;
1259
1260 private const float twoPi = 2.0f * (float)Math.PI;
1261
1262 public void Create(PathType pathType, int steps)
1263 {
1264 if (this.taperX > 0.999f)
1265 this.taperX = 0.999f;
1266 if (this.taperX < -0.999f)
1267 this.taperX = -0.999f;
1268 if (this.taperY > 0.999f)
1269 this.taperY = 0.999f;
1270 if (this.taperY < -0.999f)
1271 this.taperY = -0.999f;
1272
1273 if (pathType == PathType.Linear || pathType == PathType.Flexible)
1274 {
1275 int step = 0;
1276
1277 float length = this.pathCutEnd - this.pathCutBegin;
1278 float twistTotal = twistEnd - twistBegin;
1279 float twistTotalAbs = Math.Abs(twistTotal);
1280 if (twistTotalAbs > 0.01f)
1281 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number
1282
1283 float start = -0.5f;
1284 float stepSize = length / (float)steps;
1285 float percentOfPathMultiplier = stepSize * 0.999999f;
1286 float xOffset = this.topShearX * this.pathCutBegin;
1287 float yOffset = this.topShearY * this.pathCutBegin;
1288 float zOffset = start;
1289 float xOffsetStepIncrement = this.topShearX * length / steps;
1290 float yOffsetStepIncrement = this.topShearY * length / steps;
1291
1292 float percentOfPath = this.pathCutBegin;
1293 zOffset += percentOfPath;
1294
1295 // sanity checks
1296
1297 bool done = false;
1298
1299 while (!done)
1300 {
1301 PathNode newNode = new PathNode();
1302
1303 newNode.xScale = 1.0f;
1304 if (this.taperX == 0.0f)
1305 newNode.xScale = 1.0f;
1306 else if (this.taperX > 0.0f)
1307 newNode.xScale = 1.0f - percentOfPath * this.taperX;
1308 else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX;
1309
1310 newNode.yScale = 1.0f;
1311 if (this.taperY == 0.0f)
1312 newNode.yScale = 1.0f;
1313 else if (this.taperY > 0.0f)
1314 newNode.yScale = 1.0f - percentOfPath * this.taperY;
1315 else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY;
1316
1317 float twist = twistBegin + twistTotal * percentOfPath;
1318
1319 newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist);
1320 newNode.position = new Coord(xOffset, yOffset, zOffset);
1321 newNode.percentOfPath = percentOfPath;
1322
1323 pathNodes.Add(newNode);
1324
1325 if (step < steps)
1326 {
1327 step += 1;
1328 percentOfPath += percentOfPathMultiplier;
1329 xOffset += xOffsetStepIncrement;
1330 yOffset += yOffsetStepIncrement;
1331 zOffset += stepSize;
1332 if (percentOfPath > this.pathCutEnd)
1333 done = true;
1334 }
1335 else done = true;
1336 }
1337 } // end of linear path code
1338
1339 else // pathType == Circular
1340 {
1341 float twistTotal = twistEnd - twistBegin;
1342
1343 // if the profile has a lot of twist, add more layers otherwise the layers may overlap
1344 // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't
1345 // accurately match the viewer
1346 float twistTotalAbs = Math.Abs(twistTotal);
1347 if (twistTotalAbs > 0.01f)
1348 {
1349 if (twistTotalAbs > Math.PI * 1.5f)
1350 steps *= 2;
1351 if (twistTotalAbs > Math.PI * 3.0f)
1352 steps *= 2;
1353 }
1354
1355 float yPathScale = this.holeSizeY * 0.5f;
1356 float pathLength = this.pathCutEnd - this.pathCutBegin;
1357 float totalSkew = this.skew * 2.0f * pathLength;
1358 float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew;
1359 float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY));
1360 float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f;
1361
1362 // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end
1363 // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used
1364 // to calculate the sine for generating the path radius appears to approximate it's effects there
1365 // too, but there are some subtle differences in the radius which are noticeable as the prim size
1366 // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on
1367 // the meshes generated with this technique appear nearly identical in shape to the same prims when
1368 // displayed by the viewer.
1369
1370 float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f;
1371 float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f;
1372 float stepSize = twoPi / this.stepsPerRevolution;
1373
1374 int step = (int)(startAngle / stepSize);
1375 float angle = startAngle;
1376
1377 bool done = false;
1378 while (!done) // loop through the length of the path and add the layers
1379 {
1380 PathNode newNode = new PathNode();
1381
1382 float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX;
1383 float yProfileScale = this.holeSizeY;
1384
1385 float percentOfPath = angle / (twoPi * this.revolutions);
1386 float percentOfAngles = (angle - startAngle) / (endAngle - startAngle);
1387
1388 if (this.taperX > 0.01f)
1389 xProfileScale *= 1.0f - percentOfPath * this.taperX;
1390 else if (this.taperX < -0.01f)
1391 xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX;
1392
1393 if (this.taperY > 0.01f)
1394 yProfileScale *= 1.0f - percentOfPath * this.taperY;
1395 else if (this.taperY < -0.01f)
1396 yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY;
1397
1398 newNode.xScale = xProfileScale;
1399 newNode.yScale = yProfileScale;
1400
1401 float radiusScale = 1.0f;
1402 if (this.radius > 0.001f)
1403 radiusScale = 1.0f - this.radius * percentOfPath;
1404 else if (this.radius < 0.001f)
1405 radiusScale = 1.0f + this.radius * (1.0f - percentOfPath);
1406
1407 float twist = twistBegin + twistTotal * percentOfPath;
1408
1409 float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles);
1410 xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor;
1411
1412 float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale;
1413
1414 float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale;
1415
1416 newNode.position = new Coord(xOffset, yOffset, zOffset);
1417
1418 // now orient the rotation of the profile layer relative to it's position on the path
1419 // adding taperY to the angle used to generate the quat appears to approximate the viewer
1420
1421 newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY);
1422
1423 // next apply twist rotation to the profile layer
1424 if (twistTotal != 0.0f || twistBegin != 0.0f)
1425 newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist);
1426
1427 newNode.percentOfPath = percentOfPath;
1428
1429 pathNodes.Add(newNode);
1430
1431 // calculate terms for next iteration
1432 // calculate the angle for the next iteration of the loop
1433
1434 if (angle >= endAngle - 0.01)
1435 done = true;
1436 else
1437 {
1438 step += 1;
1439 angle = stepSize * step;
1440 if (angle > endAngle)
1441 angle = endAngle;
1442 }
1443 }
1444 }
1445 }
1446 }
1447
1448 public class PrimMesh
1449 {
1450 public string errorMessage = "";
1451 private const float twoPi = 2.0f * (float)Math.PI;
1452
1453 public List<Coord> coords;
1454 public List<Coord> normals;
1455 public List<Face> faces;
1456
1457 public List<ViewerFace> viewerFaces;
1458
1459 private int sides = 4;
1460 private int hollowSides = 4;
1461 private float profileStart = 0.0f;
1462 private float profileEnd = 1.0f;
1463 private float hollow = 0.0f;
1464 public int twistBegin = 0;
1465 public int twistEnd = 0;
1466 public float topShearX = 0.0f;
1467 public float topShearY = 0.0f;
1468 public float pathCutBegin = 0.0f;
1469 public float pathCutEnd = 1.0f;
1470 public float dimpleBegin = 0.0f;
1471 public float dimpleEnd = 1.0f;
1472 public float skew = 0.0f;
1473 public float holeSizeX = 1.0f; // called pathScaleX in pbs
1474 public float holeSizeY = 0.25f;
1475 public float taperX = 0.0f;
1476 public float taperY = 0.0f;
1477 public float radius = 0.0f;
1478 public float revolutions = 1.0f;
1479 public int stepsPerRevolution = 24;
1480
1481 private int profileOuterFaceNumber = -1;
1482 private int profileHollowFaceNumber = -1;
1483
1484 private bool hasProfileCut = false;
1485 private bool hasHollow = false;
1486 public bool calcVertexNormals = false;
1487 private bool normalsProcessed = false;
1488 public bool viewerMode = false;
1489 public bool sphereMode = false;
1490
1491 public int numPrimFaces = 0;
1492
1493 /// <summary>
1494 /// Human readable string representation of the parameters used to create a mesh.
1495 /// </summary>
1496 /// <returns></returns>
1497 public string ParamsToDisplayString()
1498 {
1499 string s = "";
1500 s += "sides..................: " + this.sides.ToString();
1501 s += "\nhollowSides..........: " + this.hollowSides.ToString();
1502 s += "\nprofileStart.........: " + this.profileStart.ToString();
1503 s += "\nprofileEnd...........: " + this.profileEnd.ToString();
1504 s += "\nhollow...............: " + this.hollow.ToString();
1505 s += "\ntwistBegin...........: " + this.twistBegin.ToString();
1506 s += "\ntwistEnd.............: " + this.twistEnd.ToString();
1507 s += "\ntopShearX............: " + this.topShearX.ToString();
1508 s += "\ntopShearY............: " + this.topShearY.ToString();
1509 s += "\npathCutBegin.........: " + this.pathCutBegin.ToString();
1510 s += "\npathCutEnd...........: " + this.pathCutEnd.ToString();
1511 s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString();
1512 s += "\ndimpleEnd............: " + this.dimpleEnd.ToString();
1513 s += "\nskew.................: " + this.skew.ToString();
1514 s += "\nholeSizeX............: " + this.holeSizeX.ToString();
1515 s += "\nholeSizeY............: " + this.holeSizeY.ToString();
1516 s += "\ntaperX...............: " + this.taperX.ToString();
1517 s += "\ntaperY...............: " + this.taperY.ToString();
1518 s += "\nradius...............: " + this.radius.ToString();
1519 s += "\nrevolutions..........: " + this.revolutions.ToString();
1520 s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString();
1521 s += "\nsphereMode...........: " + this.sphereMode.ToString();
1522 s += "\nhasProfileCut........: " + this.hasProfileCut.ToString();
1523 s += "\nhasHollow............: " + this.hasHollow.ToString();
1524 s += "\nviewerMode...........: " + this.viewerMode.ToString();
1525
1526 return s;
1527 }
1528
1529 public int ProfileOuterFaceNumber
1530 {
1531 get { return profileOuterFaceNumber; }
1532 }
1533
1534 public int ProfileHollowFaceNumber
1535 {
1536 get { return profileHollowFaceNumber; }
1537 }
1538
1539 public bool HasProfileCut
1540 {
1541 get { return hasProfileCut; }
1542 }
1543
1544 public bool HasHollow
1545 {
1546 get { return hasHollow; }
1547 }
1548
1549
1550 /// <summary>
1551 /// Constructs a PrimMesh object and creates the profile for extrusion.
1552 /// </summary>
1553 /// <param name="sides"></param>
1554 /// <param name="profileStart"></param>
1555 /// <param name="profileEnd"></param>
1556 /// <param name="hollow"></param>
1557 /// <param name="hollowSides"></param>
1558 public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides)
1559 {
1560 this.coords = new List<Coord>();
1561 this.faces = new List<Face>();
1562
1563 this.sides = sides;
1564 this.profileStart = profileStart;
1565 this.profileEnd = profileEnd;
1566 this.hollow = hollow;
1567 this.hollowSides = hollowSides;
1568
1569 if (sides < 3)
1570 this.sides = 3;
1571 if (hollowSides < 3)
1572 this.hollowSides = 3;
1573 if (profileStart < 0.0f)
1574 this.profileStart = 0.0f;
1575 if (profileEnd > 1.0f)
1576 this.profileEnd = 1.0f;
1577 if (profileEnd < 0.02f)
1578 this.profileEnd = 0.02f;
1579 if (profileStart >= profileEnd)
1580 this.profileStart = profileEnd - 0.02f;
1581 if (hollow > 0.99f)
1582 this.hollow = 0.99f;
1583 if (hollow < 0.0f)
1584 this.hollow = 0.0f;
1585 }
1586
1587 /// <summary>
1588 /// Extrudes a profile along a path.
1589 /// </summary>
1590 public void Extrude(PathType pathType)
1591 {
1592 bool needEndFaces = false;
1593
1594 this.coords = new List<Coord>();
1595 this.faces = new List<Face>();
1596
1597 if (this.viewerMode)
1598 {
1599 this.viewerFaces = new List<ViewerFace>();
1600 this.calcVertexNormals = true;
1601 }
1602
1603 if (this.calcVertexNormals)
1604 this.normals = new List<Coord>();
1605
1606 int steps = 1;
1607
1608 float length = this.pathCutEnd - this.pathCutBegin;
1609 normalsProcessed = false;
1610
1611 if (this.viewerMode && this.sides == 3)
1612 {
1613 // prisms don't taper well so add some vertical resolution
1614 // other prims may benefit from this but just do prisms for now
1615 if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01)
1616 steps = (int)(steps * 4.5 * length);
1617 }
1618
1619 if (this.sphereMode)
1620 this.hasProfileCut = this.profileEnd - this.profileStart < 0.4999f;
1621 else
1622 this.hasProfileCut = this.profileEnd - this.profileStart < 0.9999f;
1623 this.hasHollow = (this.hollow > 0.001f);
1624
1625 float twistBegin = this.twistBegin / 360.0f * twoPi;
1626 float twistEnd = this.twistEnd / 360.0f * twoPi;
1627 float twistTotal = twistEnd - twistBegin;
1628 float twistTotalAbs = Math.Abs(twistTotal);
1629 if (twistTotalAbs > 0.01f)
1630 steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number
1631
1632 float hollow = this.hollow;
1633
1634 if (pathType == PathType.Circular)
1635 {
1636 needEndFaces = false;
1637 if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f)
1638 needEndFaces = true;
1639 else if (this.taperX != 0.0f || this.taperY != 0.0f)
1640 needEndFaces = true;
1641 else if (this.skew != 0.0f)
1642 needEndFaces = true;
1643 else if (twistTotal != 0.0f)
1644 needEndFaces = true;
1645 else if (this.radius != 0.0f)
1646 needEndFaces = true;
1647 }
1648 else needEndFaces = true;
1649
1650 // sanity checks
1651 float initialProfileRot = 0.0f;
1652 if (pathType == PathType.Circular)
1653 {
1654 if (this.sides == 3)
1655 {
1656 initialProfileRot = (float)Math.PI;
1657 if (this.hollowSides == 4)
1658 {
1659 if (hollow > 0.7f)
1660 hollow = 0.7f;
1661 hollow *= 0.707f;
1662 }
1663 else hollow *= 0.5f;
1664 }
1665 else if (this.sides == 4)
1666 {
1667 initialProfileRot = 0.25f * (float)Math.PI;
1668 if (this.hollowSides != 4)
1669 hollow *= 0.707f;
1670 }
1671 else if (this.sides > 4)
1672 {
1673 initialProfileRot = (float)Math.PI;
1674 if (this.hollowSides == 4)
1675 {
1676 if (hollow > 0.7f)
1677 hollow = 0.7f;
1678 hollow /= 0.7f;
1679 }
1680 }
1681 }
1682 else
1683 {
1684 if (this.sides == 3)
1685 {
1686 if (this.hollowSides == 4)
1687 {
1688 if (hollow > 0.7f)
1689 hollow = 0.7f;
1690 hollow *= 0.707f;
1691 }
1692 else hollow *= 0.5f;
1693 }
1694 else if (this.sides == 4)
1695 {
1696 initialProfileRot = 1.25f * (float)Math.PI;
1697 if (this.hollowSides != 4)
1698 hollow *= 0.707f;
1699 }
1700 else if (this.sides == 24 && this.hollowSides == 4)
1701 hollow *= 1.414f;
1702 }
1703
1704 Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals);
1705 this.errorMessage = profile.errorMessage;
1706
1707 this.numPrimFaces = profile.numPrimFaces;
1708
1709 int cut1FaceNumber = profile.bottomFaceNumber + 1;
1710 int cut2FaceNumber = cut1FaceNumber + 1;
1711 if (!needEndFaces)
1712 {
1713 cut1FaceNumber -= 2;
1714 cut2FaceNumber -= 2;
1715 }
1716
1717 profileOuterFaceNumber = profile.outerFaceNumber;
1718 if (!needEndFaces)
1719 profileOuterFaceNumber--;
1720
1721 if (hasHollow)
1722 {
1723 profileHollowFaceNumber = profile.hollowFaceNumber;
1724 if (!needEndFaces)
1725 profileHollowFaceNumber--;
1726 }
1727
1728 int cut1Vert = -1;
1729 int cut2Vert = -1;
1730 if (hasProfileCut)
1731 {
1732 cut1Vert = hasHollow ? profile.coords.Count - 1 : 0;
1733 cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts;
1734 }
1735
1736 if (initialProfileRot != 0.0f)
1737 {
1738 profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot));
1739 if (viewerMode)
1740 profile.MakeFaceUVs();
1741 }
1742
1743 Coord lastCutNormal1 = new Coord();
1744 Coord lastCutNormal2 = new Coord();
1745 float thisV = 0.0f;
1746 float lastV = 0.0f;
1747
1748 Path path = new Path();
1749 path.twistBegin = twistBegin;
1750 path.twistEnd = twistEnd;
1751 path.topShearX = topShearX;
1752 path.topShearY = topShearY;
1753 path.pathCutBegin = pathCutBegin;
1754 path.pathCutEnd = pathCutEnd;
1755 path.dimpleBegin = dimpleBegin;
1756 path.dimpleEnd = dimpleEnd;
1757 path.skew = skew;
1758 path.holeSizeX = holeSizeX;
1759 path.holeSizeY = holeSizeY;
1760 path.taperX = taperX;
1761 path.taperY = taperY;
1762 path.radius = radius;
1763 path.revolutions = revolutions;
1764 path.stepsPerRevolution = stepsPerRevolution;
1765
1766 path.Create(pathType, steps);
1767
1768 for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++)
1769 {
1770 PathNode node = path.pathNodes[nodeIndex];
1771 Profile newLayer = profile.Copy();
1772 newLayer.Scale(node.xScale, node.yScale);
1773
1774 newLayer.AddRot(node.rotation);
1775 newLayer.AddPos(node.position);
1776
1777 if (needEndFaces && nodeIndex == 0)
1778 {
1779 newLayer.FlipNormals();
1780
1781 // add the bottom faces to the viewerFaces list
1782 if (this.viewerMode)
1783 {
1784 Coord faceNormal = newLayer.faceNormal;
1785 ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber);
1786 int numFaces = newLayer.faces.Count;
1787 List<Face> faces = newLayer.faces;
1788
1789 for (int i = 0; i < numFaces; i++)
1790 {
1791 Face face = faces[i];
1792 newViewerFace.v1 = newLayer.coords[face.v1];
1793 newViewerFace.v2 = newLayer.coords[face.v2];
1794 newViewerFace.v3 = newLayer.coords[face.v3];
1795
1796 newViewerFace.coordIndex1 = face.v1;
1797 newViewerFace.coordIndex2 = face.v2;
1798 newViewerFace.coordIndex3 = face.v3;
1799
1800 newViewerFace.n1 = faceNormal;
1801 newViewerFace.n2 = faceNormal;
1802 newViewerFace.n3 = faceNormal;
1803
1804 newViewerFace.uv1 = newLayer.faceUVs[face.v1];
1805 newViewerFace.uv2 = newLayer.faceUVs[face.v2];
1806 newViewerFace.uv3 = newLayer.faceUVs[face.v3];
1807
1808 if (pathType == PathType.Linear)
1809 {
1810 newViewerFace.uv1.Flip();
1811 newViewerFace.uv2.Flip();
1812 newViewerFace.uv3.Flip();
1813 }
1814
1815 this.viewerFaces.Add(newViewerFace);
1816 }
1817 }
1818 } // if (nodeIndex == 0)
1819
1820 // append this layer
1821
1822 int coordsLen = this.coords.Count;
1823 newLayer.AddValue2FaceVertexIndices(coordsLen);
1824
1825 this.coords.AddRange(newLayer.coords);
1826
1827 if (this.calcVertexNormals)
1828 {
1829 newLayer.AddValue2FaceNormalIndices(this.normals.Count);
1830 this.normals.AddRange(newLayer.vertexNormals);
1831 }
1832
1833 if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f)
1834 this.faces.AddRange(newLayer.faces);
1835
1836 // fill faces between layers
1837
1838 int numVerts = newLayer.coords.Count;
1839 Face newFace1 = new Face();
1840 Face newFace2 = new Face();
1841
1842 thisV = 1.0f - node.percentOfPath;
1843
1844 if (nodeIndex > 0)
1845 {
1846 int startVert = coordsLen + 1;
1847 int endVert = this.coords.Count;
1848
1849 if (sides < 5 || this.hasProfileCut || this.hasHollow)
1850 startVert--;
1851
1852 for (int i = startVert; i < endVert; i++)
1853 {
1854 int iNext = i + 1;
1855 if (i == endVert - 1)
1856 iNext = startVert;
1857
1858 int whichVert = i - startVert;
1859
1860 newFace1.v1 = i;
1861 newFace1.v2 = i - numVerts;
1862 newFace1.v3 = iNext;
1863
1864 newFace1.n1 = newFace1.v1;
1865 newFace1.n2 = newFace1.v2;
1866 newFace1.n3 = newFace1.v3;
1867 this.faces.Add(newFace1);
1868
1869 newFace2.v1 = iNext;
1870 newFace2.v2 = i - numVerts;
1871 newFace2.v3 = iNext - numVerts;
1872
1873 newFace2.n1 = newFace2.v1;
1874 newFace2.n2 = newFace2.v2;
1875 newFace2.n3 = newFace2.v3;
1876 this.faces.Add(newFace2);
1877
1878 if (this.viewerMode)
1879 {
1880 // add the side faces to the list of viewerFaces here
1881
1882 int primFaceNum = profile.faceNumbers[whichVert];
1883 if (!needEndFaces)
1884 primFaceNum -= 1;
1885
1886 ViewerFace newViewerFace1 = new ViewerFace(primFaceNum);
1887 ViewerFace newViewerFace2 = new ViewerFace(primFaceNum);
1888
1889 int uIndex = whichVert;
1890 if (!hasHollow && sides > 4 && uIndex < newLayer.us.Count - 1)
1891 {
1892 uIndex++;
1893 }
1894
1895 float u1 = newLayer.us[uIndex];
1896 float u2 = 1.0f;
1897 if (uIndex < (int)newLayer.us.Count - 1)
1898 u2 = newLayer.us[uIndex + 1];
1899
1900 if (whichVert == cut1Vert || whichVert == cut2Vert)
1901 {
1902 u1 = 0.0f;
1903 u2 = 1.0f;
1904 }
1905 else if (sides < 5)
1906 {
1907 if (whichVert < profile.numOuterVerts)
1908 { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled
1909 // to reflect the entire texture width
1910 u1 *= sides;
1911 u2 *= sides;
1912 u2 -= (int)u1;
1913 u1 -= (int)u1;
1914 if (u2 < 0.1f)
1915 u2 = 1.0f;
1916 }
1917 }
1918
1919 if (this.sphereMode)
1920 {
1921 if (whichVert != cut1Vert && whichVert != cut2Vert)
1922 {
1923 u1 = u1 * 2.0f - 1.0f;
1924 u2 = u2 * 2.0f - 1.0f;
1925
1926 if (whichVert >= newLayer.numOuterVerts)
1927 {
1928 u1 -= hollow;
1929 u2 -= hollow;
1930 }
1931
1932 }
1933 }
1934
1935 newViewerFace1.uv1.U = u1;
1936 newViewerFace1.uv2.U = u1;
1937 newViewerFace1.uv3.U = u2;
1938
1939 newViewerFace1.uv1.V = thisV;
1940 newViewerFace1.uv2.V = lastV;
1941 newViewerFace1.uv3.V = thisV;
1942
1943 newViewerFace2.uv1.U = u2;
1944 newViewerFace2.uv2.U = u1;
1945 newViewerFace2.uv3.U = u2;
1946
1947 newViewerFace2.uv1.V = thisV;
1948 newViewerFace2.uv2.V = lastV;
1949 newViewerFace2.uv3.V = lastV;
1950
1951 newViewerFace1.v1 = this.coords[newFace1.v1];
1952 newViewerFace1.v2 = this.coords[newFace1.v2];
1953 newViewerFace1.v3 = this.coords[newFace1.v3];
1954
1955 newViewerFace2.v1 = this.coords[newFace2.v1];
1956 newViewerFace2.v2 = this.coords[newFace2.v2];
1957 newViewerFace2.v3 = this.coords[newFace2.v3];
1958
1959 newViewerFace1.coordIndex1 = newFace1.v1;
1960 newViewerFace1.coordIndex2 = newFace1.v2;
1961 newViewerFace1.coordIndex3 = newFace1.v3;
1962
1963 newViewerFace2.coordIndex1 = newFace2.v1;
1964 newViewerFace2.coordIndex2 = newFace2.v2;
1965 newViewerFace2.coordIndex3 = newFace2.v3;
1966
1967 // profile cut faces
1968 if (whichVert == cut1Vert)
1969 {
1970 newViewerFace1.primFaceNumber = cut1FaceNumber;
1971 newViewerFace2.primFaceNumber = cut1FaceNumber;
1972 newViewerFace1.n1 = newLayer.cutNormal1;
1973 newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1;
1974
1975 newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1;
1976 newViewerFace2.n2 = lastCutNormal1;
1977 }
1978 else if (whichVert == cut2Vert)
1979 {
1980 newViewerFace1.primFaceNumber = cut2FaceNumber;
1981 newViewerFace2.primFaceNumber = cut2FaceNumber;
1982 newViewerFace1.n1 = newLayer.cutNormal2;
1983 newViewerFace1.n2 = lastCutNormal2;
1984 newViewerFace1.n3 = lastCutNormal2;
1985
1986 newViewerFace2.n1 = newLayer.cutNormal2;
1987 newViewerFace2.n3 = newLayer.cutNormal2;
1988 newViewerFace2.n2 = lastCutNormal2;
1989 }
1990
1991 else // outer and hollow faces
1992 {
1993 if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts))
1994 { // looks terrible when path is twisted... need vertex normals here
1995 newViewerFace1.CalcSurfaceNormal();
1996 newViewerFace2.CalcSurfaceNormal();
1997 }
1998 else
1999 {
2000 newViewerFace1.n1 = this.normals[newFace1.n1];
2001 newViewerFace1.n2 = this.normals[newFace1.n2];
2002 newViewerFace1.n3 = this.normals[newFace1.n3];
2003
2004 newViewerFace2.n1 = this.normals[newFace2.n1];
2005 newViewerFace2.n2 = this.normals[newFace2.n2];
2006 newViewerFace2.n3 = this.normals[newFace2.n3];
2007 }
2008 }
2009
2010 this.viewerFaces.Add(newViewerFace1);
2011 this.viewerFaces.Add(newViewerFace2);
2012
2013 }
2014 }
2015 }
2016
2017 lastCutNormal1 = newLayer.cutNormal1;
2018 lastCutNormal2 = newLayer.cutNormal2;
2019 lastV = thisV;
2020
2021 if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode)
2022 {
2023 // add the top faces to the viewerFaces list here
2024 Coord faceNormal = newLayer.faceNormal;
2025 ViewerFace newViewerFace = new ViewerFace(0);
2026 int numFaces = newLayer.faces.Count;
2027 List<Face> faces = newLayer.faces;
2028
2029 for (int i = 0; i < numFaces; i++)
2030 {
2031 Face face = faces[i];
2032 newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen];
2033 newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen];
2034 newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen];
2035
2036 newViewerFace.coordIndex1 = face.v1 - coordsLen;
2037 newViewerFace.coordIndex2 = face.v2 - coordsLen;
2038 newViewerFace.coordIndex3 = face.v3 - coordsLen;
2039
2040 newViewerFace.n1 = faceNormal;
2041 newViewerFace.n2 = faceNormal;
2042 newViewerFace.n3 = faceNormal;
2043
2044 newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen];
2045 newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen];
2046 newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen];
2047
2048 if (pathType == PathType.Linear)
2049 {
2050 newViewerFace.uv1.Flip();
2051 newViewerFace.uv2.Flip();
2052 newViewerFace.uv3.Flip();
2053 }
2054
2055 this.viewerFaces.Add(newViewerFace);
2056 }
2057 }
2058
2059
2060 } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++)
2061
2062 }
2063
2064
2065 /// <summary>
2066 /// DEPRICATED - use Extrude(PathType.Linear) instead
2067 /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism.
2068 /// </summary>
2069 ///
2070 public void ExtrudeLinear()
2071 {
2072 this.Extrude(PathType.Linear);
2073 }
2074
2075
2076 /// <summary>
2077 /// DEPRICATED - use Extrude(PathType.Circular) instead
2078 /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring.
2079 /// </summary>
2080 ///
2081 public void ExtrudeCircular()
2082 {
2083 this.Extrude(PathType.Circular);
2084 }
2085
2086
2087 private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3)
2088 {
2089 Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z);
2090 Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z);
2091
2092 Coord normal = Coord.Cross(edge1, edge2);
2093
2094 normal.Normalize();
2095
2096 return normal;
2097 }
2098
2099 private Coord SurfaceNormal(Face face)
2100 {
2101 return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]);
2102 }
2103
2104 /// <summary>
2105 /// Calculate the surface normal for a face in the list of faces
2106 /// </summary>
2107 /// <param name="faceIndex"></param>
2108 /// <returns></returns>
2109 public Coord SurfaceNormal(int faceIndex)
2110 {
2111 int numFaces = this.faces.Count;
2112 if (faceIndex < 0 || faceIndex >= numFaces)
2113 throw new Exception("faceIndex out of range");
2114
2115 return SurfaceNormal(this.faces[faceIndex]);
2116 }
2117
2118 /// <summary>
2119 /// Duplicates a PrimMesh object. All object properties are copied by value, including lists.
2120 /// </summary>
2121 /// <returns></returns>
2122 public PrimMesh Copy()
2123 {
2124 PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides);
2125 copy.twistBegin = this.twistBegin;
2126 copy.twistEnd = this.twistEnd;
2127 copy.topShearX = this.topShearX;
2128 copy.topShearY = this.topShearY;
2129 copy.pathCutBegin = this.pathCutBegin;
2130 copy.pathCutEnd = this.pathCutEnd;
2131 copy.dimpleBegin = this.dimpleBegin;
2132 copy.dimpleEnd = this.dimpleEnd;
2133 copy.skew = this.skew;
2134 copy.holeSizeX = this.holeSizeX;
2135 copy.holeSizeY = this.holeSizeY;
2136 copy.taperX = this.taperX;
2137 copy.taperY = this.taperY;
2138 copy.radius = this.radius;
2139 copy.revolutions = this.revolutions;
2140 copy.stepsPerRevolution = this.stepsPerRevolution;
2141 copy.calcVertexNormals = this.calcVertexNormals;
2142 copy.normalsProcessed = this.normalsProcessed;
2143 copy.viewerMode = this.viewerMode;
2144 copy.numPrimFaces = this.numPrimFaces;
2145 copy.errorMessage = this.errorMessage;
2146
2147 copy.coords = new List<Coord>(this.coords);
2148 copy.faces = new List<Face>(this.faces);
2149 copy.viewerFaces = new List<ViewerFace>(this.viewerFaces);
2150 copy.normals = new List<Coord>(this.normals);
2151
2152 return copy;
2153 }
2154
2155 /// <summary>
2156 /// Calculate surface normals for all of the faces in the list of faces in this mesh
2157 /// </summary>
2158 public void CalcNormals()
2159 {
2160 if (normalsProcessed)
2161 return;
2162
2163 normalsProcessed = true;
2164
2165 int numFaces = faces.Count;
2166
2167 if (!this.calcVertexNormals)
2168 this.normals = new List<Coord>();
2169
2170 for (int i = 0; i < numFaces; i++)
2171 {
2172 Face face = faces[i];
2173
2174 this.normals.Add(SurfaceNormal(i).Normalize());
2175
2176 int normIndex = normals.Count - 1;
2177 face.n1 = normIndex;
2178 face.n2 = normIndex;
2179 face.n3 = normIndex;
2180
2181 this.faces[i] = face;
2182 }
2183 }
2184
2185 /// <summary>
2186 /// Adds a value to each XYZ vertex coordinate in the mesh
2187 /// </summary>
2188 /// <param name="x"></param>
2189 /// <param name="y"></param>
2190 /// <param name="z"></param>
2191 public void AddPos(float x, float y, float z)
2192 {
2193 int i;
2194 int numVerts = this.coords.Count;
2195 Coord vert;
2196
2197 for (i = 0; i < numVerts; i++)
2198 {
2199 vert = this.coords[i];
2200 vert.X += x;
2201 vert.Y += y;
2202 vert.Z += z;
2203 this.coords[i] = vert;
2204 }
2205
2206 if (this.viewerFaces != null)
2207 {
2208 int numViewerFaces = this.viewerFaces.Count;
2209
2210 for (i = 0; i < numViewerFaces; i++)
2211 {
2212 ViewerFace v = this.viewerFaces[i];
2213 v.AddPos(x, y, z);
2214 this.viewerFaces[i] = v;
2215 }
2216 }
2217 }
2218
2219 /// <summary>
2220 /// Rotates the mesh
2221 /// </summary>
2222 /// <param name="q"></param>
2223 public void AddRot(Quat q)
2224 {
2225 int i;
2226 int numVerts = this.coords.Count;
2227
2228 for (i = 0; i < numVerts; i++)
2229 this.coords[i] *= q;
2230
2231 if (this.normals != null)
2232 {
2233 int numNormals = this.normals.Count;
2234 for (i = 0; i < numNormals; i++)
2235 this.normals[i] *= q;
2236 }
2237
2238 if (this.viewerFaces != null)
2239 {
2240 int numViewerFaces = this.viewerFaces.Count;
2241
2242 for (i = 0; i < numViewerFaces; i++)
2243 {
2244 ViewerFace v = this.viewerFaces[i];
2245 v.v1 *= q;
2246 v.v2 *= q;
2247 v.v3 *= q;
2248
2249 v.n1 *= q;
2250 v.n2 *= q;
2251 v.n3 *= q;
2252 this.viewerFaces[i] = v;
2253 }
2254 }
2255 }
2256
2257#if VERTEX_INDEXER
2258 public VertexIndexer GetVertexIndexer()
2259 {
2260 if (this.viewerMode && this.viewerFaces.Count > 0)
2261 return new VertexIndexer(this);
2262 return null;
2263 }
2264#endif
2265
2266 /// <summary>
2267 /// Scales the mesh
2268 /// </summary>
2269 /// <param name="x"></param>
2270 /// <param name="y"></param>
2271 /// <param name="z"></param>
2272 public void Scale(float x, float y, float z)
2273 {
2274 int i;
2275 int numVerts = this.coords.Count;
2276 //Coord vert;
2277
2278 Coord m = new Coord(x, y, z);
2279 for (i = 0; i < numVerts; i++)
2280 this.coords[i] *= m;
2281
2282 if (this.viewerFaces != null)
2283 {
2284 int numViewerFaces = this.viewerFaces.Count;
2285 for (i = 0; i < numViewerFaces; i++)
2286 {
2287 ViewerFace v = this.viewerFaces[i];
2288 v.v1 *= m;
2289 v.v2 *= m;
2290 v.v3 *= m;
2291 this.viewerFaces[i] = v;
2292 }
2293
2294 }
2295
2296 }
2297
2298 /// <summary>
2299 /// Dumps the mesh to a Blender compatible "Raw" format file
2300 /// </summary>
2301 /// <param name="path"></param>
2302 /// <param name="name"></param>
2303 /// <param name="title"></param>
2304 public void DumpRaw(String path, String name, String title)
2305 {
2306 if (path == null)
2307 return;
2308 String fileName = name + "_" + title + ".raw";
2309 String completePath = System.IO.Path.Combine(path, fileName);
2310 StreamWriter sw = new StreamWriter(completePath);
2311
2312 for (int i = 0; i < this.faces.Count; i++)
2313 {
2314 string s = this.coords[this.faces[i].v1].ToString();
2315 s += " " + this.coords[this.faces[i].v2].ToString();
2316 s += " " + this.coords[this.faces[i].v3].ToString();
2317
2318 sw.WriteLine(s);
2319 }
2320
2321 sw.Close();
2322 }
2323 }
2324}
diff --git a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs
deleted file mode 100644
index 4cc1731..0000000
--- a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,33 +0,0 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.Physics.Meshing")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("4b7e35c2-a9dd-4b10-b778-eb417f4f6884")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.5.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Region/Physics/Meshing/SculptMap.cs b/OpenSim/Region/Physics/Meshing/SculptMap.cs
deleted file mode 100644
index 740424e..0000000
--- a/OpenSim/Region/Physics/Meshing/SculptMap.cs
+++ /dev/null
@@ -1,183 +0,0 @@
1/*
2 * Copyright (c) Contributors
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
28// to build without references to System.Drawing, comment this out
29#define SYSTEM_DRAWING
30
31using System;
32using System.Collections.Generic;
33using System.Text;
34
35#if SYSTEM_DRAWING
36using System.Drawing;
37using System.Drawing.Imaging;
38
39namespace PrimMesher
40{
41 public class SculptMap
42 {
43 public int width;
44 public int height;
45 public byte[] redBytes;
46 public byte[] greenBytes;
47 public byte[] blueBytes;
48
49 public SculptMap()
50 {
51 }
52
53 public SculptMap(Bitmap bm, int lod)
54 {
55 int bmW = bm.Width;
56 int bmH = bm.Height;
57
58 if (bmW == 0 || bmH == 0)
59 throw new Exception("SculptMap: bitmap has no data");
60
61 int numLodPixels = lod * 2 * lod * 2; // (32 * 2)^2 = 64^2 pixels for default sculpt map image
62
63 bool needsScaling = false;
64
65 bool smallMap = bmW * bmH <= lod * lod;
66
67 width = bmW;
68 height = bmH;
69 while (width * height > numLodPixels)
70 {
71 width >>= 1;
72 height >>= 1;
73 needsScaling = true;
74 }
75
76
77
78 try
79 {
80 if (needsScaling)
81 bm = ScaleImage(bm, width, height,
82 System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor);
83 }
84
85 catch (Exception e)
86 {
87 throw new Exception("Exception in ScaleImage(): e: " + e.ToString());
88 }
89
90 if (width * height > lod * lod)
91 {
92 width >>= 1;
93 height >>= 1;
94 }
95
96 int numBytes = (width + 1) * (height + 1);
97 redBytes = new byte[numBytes];
98 greenBytes = new byte[numBytes];
99 blueBytes = new byte[numBytes];
100
101 int byteNdx = 0;
102
103 try
104 {
105 for (int y = 0; y <= height; y++)
106 {
107 for (int x = 0; x <= width; x++)
108 {
109 Color c;
110
111 if (smallMap)
112 c = bm.GetPixel(x < width ? x : x - 1,
113 y < height ? y : y - 1);
114 else
115 c = bm.GetPixel(x < width ? x * 2 : x * 2 - 1,
116 y < height ? y * 2 : y * 2 - 1);
117
118 redBytes[byteNdx] = c.R;
119 greenBytes[byteNdx] = c.G;
120 blueBytes[byteNdx] = c.B;
121
122 ++byteNdx;
123 }
124 }
125 }
126 catch (Exception e)
127 {
128 throw new Exception("Caught exception processing byte arrays in SculptMap(): e: " + e.ToString());
129 }
130
131 width++;
132 height++;
133 }
134
135 public List<List<Coord>> ToRows(bool mirror)
136 {
137 int numRows = height;
138 int numCols = width;
139
140 List<List<Coord>> rows = new List<List<Coord>>(numRows);
141
142 float pixScale = 1.0f / 255;
143
144 int rowNdx, colNdx;
145 int smNdx = 0;
146
147 for (rowNdx = 0; rowNdx < numRows; rowNdx++)
148 {
149 List<Coord> row = new List<Coord>(numCols);
150 for (colNdx = 0; colNdx < numCols; colNdx++)
151 {
152 if (mirror)
153 row.Add(new Coord(-(redBytes[smNdx] * pixScale - 0.5f), (greenBytes[smNdx] * pixScale - 0.5f), blueBytes[smNdx] * pixScale - 0.5f));
154 else
155 row.Add(new Coord(redBytes[smNdx] * pixScale - 0.5f, greenBytes[smNdx] * pixScale - 0.5f, blueBytes[smNdx] * pixScale - 0.5f));
156
157 ++smNdx;
158 }
159 rows.Add(row);
160 }
161 return rows;
162 }
163
164 private Bitmap ScaleImage(Bitmap srcImage, int destWidth, int destHeight,
165 System.Drawing.Drawing2D.InterpolationMode interpMode)
166 {
167 Bitmap scaledImage = new Bitmap(srcImage, destWidth, destHeight);
168 scaledImage.SetResolution(96.0f, 96.0f);
169
170 Graphics grPhoto = Graphics.FromImage(scaledImage);
171 grPhoto.InterpolationMode = interpMode;
172
173 grPhoto.DrawImage(srcImage,
174 new Rectangle(0, 0, destWidth, destHeight),
175 new Rectangle(0, 0, srcImage.Width, srcImage.Height),
176 GraphicsUnit.Pixel);
177
178 grPhoto.Dispose();
179 return scaledImage;
180 }
181 }
182}
183#endif
diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs
deleted file mode 100644
index 4a7f3ad..0000000
--- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs
+++ /dev/null
@@ -1,646 +0,0 @@
1/*
2 * Copyright (c) Contributors
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
28// to build without references to System.Drawing, comment this out
29#define SYSTEM_DRAWING
30
31using System;
32using System.Collections.Generic;
33using System.Text;
34using System.IO;
35
36#if SYSTEM_DRAWING
37using System.Drawing;
38using System.Drawing.Imaging;
39#endif
40
41namespace PrimMesher
42{
43
44 public class SculptMesh
45 {
46 public List<Coord> coords;
47 public List<Face> faces;
48
49 public List<ViewerFace> viewerFaces;
50 public List<Coord> normals;
51 public List<UVCoord> uvs;
52
53 public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 };
54
55#if SYSTEM_DRAWING
56
57 public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode)
58 {
59 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
60 SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode);
61 bitmap.Dispose();
62 return sculptMesh;
63 }
64
65
66 public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert)
67 {
68 Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName);
69 _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0);
70 bitmap.Dispose();
71 }
72#endif
73
74 /// <summary>
75 /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications
76 /// Construct a sculpt mesh from a 2D array of floats
77 /// </summary>
78 /// <param name="zMap"></param>
79 /// <param name="xBegin"></param>
80 /// <param name="xEnd"></param>
81 /// <param name="yBegin"></param>
82 /// <param name="yEnd"></param>
83 /// <param name="viewerMode"></param>
84 public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode)
85 {
86 float xStep, yStep;
87 float uStep, vStep;
88
89 int numYElements = zMap.GetLength(0);
90 int numXElements = zMap.GetLength(1);
91
92 try
93 {
94 xStep = (xEnd - xBegin) / (float)(numXElements - 1);
95 yStep = (yEnd - yBegin) / (float)(numYElements - 1);
96
97 uStep = 1.0f / (numXElements - 1);
98 vStep = 1.0f / (numYElements - 1);
99 }
100 catch (DivideByZeroException)
101 {
102 return;
103 }
104
105 coords = new List<Coord>();
106 faces = new List<Face>();
107 normals = new List<Coord>();
108 uvs = new List<UVCoord>();
109
110 viewerFaces = new List<ViewerFace>();
111
112 int p1, p2, p3, p4;
113
114 int x, y;
115 int xStart = 0, yStart = 0;
116
117 for (y = yStart; y < numYElements; y++)
118 {
119 int rowOffset = y * numXElements;
120
121 for (x = xStart; x < numXElements; x++)
122 {
123 /*
124 * p1-----p2
125 * | \ f2 |
126 * | \ |
127 * | f1 \|
128 * p3-----p4
129 */
130
131 p4 = rowOffset + x;
132 p3 = p4 - 1;
133
134 p2 = p4 - numXElements;
135 p1 = p3 - numXElements;
136
137 Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]);
138 this.coords.Add(c);
139 if (viewerMode)
140 {
141 this.normals.Add(new Coord());
142 this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y));
143 }
144
145 if (y > 0 && x > 0)
146 {
147 Face f1, f2;
148
149 if (viewerMode)
150 {
151 f1 = new Face(p1, p4, p3, p1, p4, p3);
152 f1.uv1 = p1;
153 f1.uv2 = p4;
154 f1.uv3 = p3;
155
156 f2 = new Face(p1, p2, p4, p1, p2, p4);
157 f2.uv1 = p1;
158 f2.uv2 = p2;
159 f2.uv3 = p4;
160 }
161 else
162 {
163 f1 = new Face(p1, p4, p3);
164 f2 = new Face(p1, p2, p4);
165 }
166
167 this.faces.Add(f1);
168 this.faces.Add(f2);
169 }
170 }
171 }
172
173 if (viewerMode)
174 calcVertexNormals(SculptType.plane, numXElements, numYElements);
175 }
176
177#if SYSTEM_DRAWING
178 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode)
179 {
180 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false);
181 }
182
183 public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
184 {
185 _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert);
186 }
187#endif
188
189 public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
190 {
191 _SculptMesh(rows, sculptType, viewerMode, mirror, invert);
192 }
193
194#if SYSTEM_DRAWING
195 /// <summary>
196 /// converts a bitmap to a list of lists of coords, while scaling the image.
197 /// the scaling is done in floating point so as to allow for reduced vertex position
198 /// quantization as the position will be averaged between pixel values. this routine will
199 /// likely fail if the bitmap width and height are not powers of 2.
200 /// </summary>
201 /// <param name="bitmap"></param>
202 /// <param name="scale"></param>
203 /// <param name="mirror"></param>
204 /// <returns></returns>
205 private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror)
206 {
207 int numRows = bitmap.Height / scale;
208 int numCols = bitmap.Width / scale;
209 List<List<Coord>> rows = new List<List<Coord>>(numRows);
210
211 float pixScale = 1.0f / (scale * scale);
212 pixScale /= 255;
213
214 int imageX, imageY = 0;
215
216 int rowNdx, colNdx;
217
218 for (rowNdx = 0; rowNdx < numRows; rowNdx++)
219 {
220 List<Coord> row = new List<Coord>(numCols);
221 for (colNdx = 0; colNdx < numCols; colNdx++)
222 {
223 imageX = colNdx * scale;
224 int imageYStart = rowNdx * scale;
225 int imageYEnd = imageYStart + scale;
226 int imageXEnd = imageX + scale;
227 float rSum = 0.0f;
228 float gSum = 0.0f;
229 float bSum = 0.0f;
230 for (; imageX < imageXEnd; imageX++)
231 {
232 for (imageY = imageYStart; imageY < imageYEnd; imageY++)
233 {
234 Color c = bitmap.GetPixel(imageX, imageY);
235 if (c.A != 255)
236 {
237 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B));
238 c = bitmap.GetPixel(imageX, imageY);
239 }
240 rSum += c.R;
241 gSum += c.G;
242 bSum += c.B;
243 }
244 }
245 if (mirror)
246 row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
247 else
248 row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f));
249
250 }
251 rows.Add(row);
252 }
253 return rows;
254 }
255
256 private List<List<Coord>> bitmap2CoordsSampled(Bitmap bitmap, int scale, bool mirror)
257 {
258 int numRows = bitmap.Height / scale;
259 int numCols = bitmap.Width / scale;
260 List<List<Coord>> rows = new List<List<Coord>>(numRows);
261
262 float pixScale = 1.0f / 256.0f;
263
264 int imageX, imageY = 0;
265
266 int rowNdx, colNdx;
267
268 for (rowNdx = 0; rowNdx <= numRows; rowNdx++)
269 {
270 List<Coord> row = new List<Coord>(numCols);
271 imageY = rowNdx * scale;
272 if (rowNdx == numRows) imageY--;
273 for (colNdx = 0; colNdx <= numCols; colNdx++)
274 {
275 imageX = colNdx * scale;
276 if (colNdx == numCols) imageX--;
277
278 Color c = bitmap.GetPixel(imageX, imageY);
279 if (c.A != 255)
280 {
281 bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B));
282 c = bitmap.GetPixel(imageX, imageY);
283 }
284
285 if (mirror)
286 row.Add(new Coord(-(c.R * pixScale - 0.5f), c.G * pixScale - 0.5f, c.B * pixScale - 0.5f));
287 else
288 row.Add(new Coord(c.R * pixScale - 0.5f, c.G * pixScale - 0.5f, c.B * pixScale - 0.5f));
289
290 }
291 rows.Add(row);
292 }
293 return rows;
294 }
295
296
297 void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert)
298 {
299 _SculptMesh(new SculptMap(sculptBitmap, lod).ToRows(mirror), sculptType, viewerMode, mirror, invert);
300 }
301#endif
302
303 void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert)
304 {
305 coords = new List<Coord>();
306 faces = new List<Face>();
307 normals = new List<Coord>();
308 uvs = new List<UVCoord>();
309
310 sculptType = (SculptType)(((int)sculptType) & 0x07);
311
312 if (mirror)
313 invert = !invert;
314
315 viewerFaces = new List<ViewerFace>();
316
317 int width = rows[0].Count;
318
319 int p1, p2, p3, p4;
320
321 int imageX, imageY;
322
323 if (sculptType != SculptType.plane)
324 {
325 if (rows.Count % 2 == 0)
326 {
327 for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++)
328 rows[rowNdx].Add(rows[rowNdx][0]);
329 }
330 else
331 {
332 int lastIndex = rows[0].Count - 1;
333
334 for (int i = 0; i < rows.Count; i++)
335 rows[i][0] = rows[i][lastIndex];
336 }
337 }
338
339 Coord topPole = rows[0][width / 2];
340 Coord bottomPole = rows[rows.Count - 1][width / 2];
341
342 if (sculptType == SculptType.sphere)
343 {
344 if (rows.Count % 2 == 0)
345 {
346 int count = rows[0].Count;
347 List<Coord> topPoleRow = new List<Coord>(count);
348 List<Coord> bottomPoleRow = new List<Coord>(count);
349
350 for (int i = 0; i < count; i++)
351 {
352 topPoleRow.Add(topPole);
353 bottomPoleRow.Add(bottomPole);
354 }
355 rows.Insert(0, topPoleRow);
356 rows.Add(bottomPoleRow);
357 }
358 else
359 {
360 int count = rows[0].Count;
361
362 List<Coord> topPoleRow = rows[0];
363 List<Coord> bottomPoleRow = rows[rows.Count - 1];
364
365 for (int i = 0; i < count; i++)
366 {
367 topPoleRow[i] = topPole;
368 bottomPoleRow[i] = bottomPole;
369 }
370 }
371 }
372
373 if (sculptType == SculptType.torus)
374 rows.Add(rows[0]);
375
376 int coordsDown = rows.Count;
377 int coordsAcross = rows[0].Count;
378// int lastColumn = coordsAcross - 1;
379
380 float widthUnit = 1.0f / (coordsAcross - 1);
381 float heightUnit = 1.0f / (coordsDown - 1);
382
383 for (imageY = 0; imageY < coordsDown; imageY++)
384 {
385 int rowOffset = imageY * coordsAcross;
386
387 for (imageX = 0; imageX < coordsAcross; imageX++)
388 {
389 /*
390 * p1-----p2
391 * | \ f2 |
392 * | \ |
393 * | f1 \|
394 * p3-----p4
395 */
396
397 p4 = rowOffset + imageX;
398 p3 = p4 - 1;
399
400 p2 = p4 - coordsAcross;
401 p1 = p3 - coordsAcross;
402
403 this.coords.Add(rows[imageY][imageX]);
404 if (viewerMode)
405 {
406 this.normals.Add(new Coord());
407 this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY));
408 }
409
410 if (imageY > 0 && imageX > 0)
411 {
412 Face f1, f2;
413
414 if (viewerMode)
415 {
416 if (invert)
417 {
418 f1 = new Face(p1, p4, p3, p1, p4, p3);
419 f1.uv1 = p1;
420 f1.uv2 = p4;
421 f1.uv3 = p3;
422
423 f2 = new Face(p1, p2, p4, p1, p2, p4);
424 f2.uv1 = p1;
425 f2.uv2 = p2;
426 f2.uv3 = p4;
427 }
428 else
429 {
430 f1 = new Face(p1, p3, p4, p1, p3, p4);
431 f1.uv1 = p1;
432 f1.uv2 = p3;
433 f1.uv3 = p4;
434
435 f2 = new Face(p1, p4, p2, p1, p4, p2);
436 f2.uv1 = p1;
437 f2.uv2 = p4;
438 f2.uv3 = p2;
439 }
440 }
441 else
442 {
443 if (invert)
444 {
445 f1 = new Face(p1, p4, p3);
446 f2 = new Face(p1, p2, p4);
447 }
448 else
449 {
450 f1 = new Face(p1, p3, p4);
451 f2 = new Face(p1, p4, p2);
452 }
453 }
454
455 this.faces.Add(f1);
456 this.faces.Add(f2);
457 }
458 }
459 }
460
461 if (viewerMode)
462 calcVertexNormals(sculptType, coordsAcross, coordsDown);
463 }
464
465 /// <summary>
466 /// Duplicates a SculptMesh object. All object properties are copied by value, including lists.
467 /// </summary>
468 /// <returns></returns>
469 public SculptMesh Copy()
470 {
471 return new SculptMesh(this);
472 }
473
474 public SculptMesh(SculptMesh sm)
475 {
476 coords = new List<Coord>(sm.coords);
477 faces = new List<Face>(sm.faces);
478 viewerFaces = new List<ViewerFace>(sm.viewerFaces);
479 normals = new List<Coord>(sm.normals);
480 uvs = new List<UVCoord>(sm.uvs);
481 }
482
483 private void calcVertexNormals(SculptType sculptType, int xSize, int ySize)
484 { // compute vertex normals by summing all the surface normals of all the triangles sharing
485 // each vertex and then normalizing
486 int numFaces = this.faces.Count;
487 for (int i = 0; i < numFaces; i++)
488 {
489 Face face = this.faces[i];
490 Coord surfaceNormal = face.SurfaceNormal(this.coords);
491 this.normals[face.n1] += surfaceNormal;
492 this.normals[face.n2] += surfaceNormal;
493 this.normals[face.n3] += surfaceNormal;
494 }
495
496 int numNormals = this.normals.Count;
497 for (int i = 0; i < numNormals; i++)
498 this.normals[i] = this.normals[i].Normalize();
499
500 if (sculptType != SculptType.plane)
501 { // blend the vertex normals at the cylinder seam
502 for (int y = 0; y < ySize; y++)
503 {
504 int rowOffset = y * xSize;
505
506 this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize();
507 }
508 }
509
510 foreach (Face face in this.faces)
511 {
512 ViewerFace vf = new ViewerFace(0);
513 vf.v1 = this.coords[face.v1];
514 vf.v2 = this.coords[face.v2];
515 vf.v3 = this.coords[face.v3];
516
517 vf.coordIndex1 = face.v1;
518 vf.coordIndex2 = face.v2;
519 vf.coordIndex3 = face.v3;
520
521 vf.n1 = this.normals[face.n1];
522 vf.n2 = this.normals[face.n2];
523 vf.n3 = this.normals[face.n3];
524
525 vf.uv1 = this.uvs[face.uv1];
526 vf.uv2 = this.uvs[face.uv2];
527 vf.uv3 = this.uvs[face.uv3];
528
529 this.viewerFaces.Add(vf);
530 }
531 }
532
533 /// <summary>
534 /// Adds a value to each XYZ vertex coordinate in the mesh
535 /// </summary>
536 /// <param name="x"></param>
537 /// <param name="y"></param>
538 /// <param name="z"></param>
539 public void AddPos(float x, float y, float z)
540 {
541 int i;
542 int numVerts = this.coords.Count;
543 Coord vert;
544
545 for (i = 0; i < numVerts; i++)
546 {
547 vert = this.coords[i];
548 vert.X += x;
549 vert.Y += y;
550 vert.Z += z;
551 this.coords[i] = vert;
552 }
553
554 if (this.viewerFaces != null)
555 {
556 int numViewerFaces = this.viewerFaces.Count;
557
558 for (i = 0; i < numViewerFaces; i++)
559 {
560 ViewerFace v = this.viewerFaces[i];
561 v.AddPos(x, y, z);
562 this.viewerFaces[i] = v;
563 }
564 }
565 }
566
567 /// <summary>
568 /// Rotates the mesh
569 /// </summary>
570 /// <param name="q"></param>
571 public void AddRot(Quat q)
572 {
573 int i;
574 int numVerts = this.coords.Count;
575
576 for (i = 0; i < numVerts; i++)
577 this.coords[i] *= q;
578
579 int numNormals = this.normals.Count;
580 for (i = 0; i < numNormals; i++)
581 this.normals[i] *= q;
582
583 if (this.viewerFaces != null)
584 {
585 int numViewerFaces = this.viewerFaces.Count;
586
587 for (i = 0; i < numViewerFaces; i++)
588 {
589 ViewerFace v = this.viewerFaces[i];
590 v.v1 *= q;
591 v.v2 *= q;
592 v.v3 *= q;
593
594 v.n1 *= q;
595 v.n2 *= q;
596 v.n3 *= q;
597
598 this.viewerFaces[i] = v;
599 }
600 }
601 }
602
603 public void Scale(float x, float y, float z)
604 {
605 int i;
606 int numVerts = this.coords.Count;
607
608 Coord m = new Coord(x, y, z);
609 for (i = 0; i < numVerts; i++)
610 this.coords[i] *= m;
611
612 if (this.viewerFaces != null)
613 {
614 int numViewerFaces = this.viewerFaces.Count;
615 for (i = 0; i < numViewerFaces; i++)
616 {
617 ViewerFace v = this.viewerFaces[i];
618 v.v1 *= m;
619 v.v2 *= m;
620 v.v3 *= m;
621 this.viewerFaces[i] = v;
622 }
623 }
624 }
625
626 public void DumpRaw(String path, String name, String title)
627 {
628 if (path == null)
629 return;
630 String fileName = name + "_" + title + ".raw";
631 String completePath = System.IO.Path.Combine(path, fileName);
632 StreamWriter sw = new StreamWriter(completePath);
633
634 for (int i = 0; i < this.faces.Count; i++)
635 {
636 string s = this.coords[this.faces[i].v1].ToString();
637 s += " " + this.coords[this.faces[i].v2].ToString();
638 s += " " + this.coords[this.faces[i].v3].ToString();
639
640 sw.WriteLine(s);
641 }
642
643 sw.Close();
644 }
645 }
646}
diff --git a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs
deleted file mode 100644
index 3c4f06a..0000000
--- a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs
+++ /dev/null
@@ -1,58 +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.Reflection;
29using System.Runtime.InteropServices;
30
31// Information about this assembly is defined by the following
32// attributes.
33//
34// change them to the information which is associated with the assembly
35// you compile.
36
37[assembly : AssemblyTitle("OdePlugin")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("OdePlugin")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.7.5.*")]
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
deleted file mode 100644
index 319f6ab..0000000
--- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs
+++ /dev/null
@@ -1,1411 +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.Reflection;
31using OpenMetaverse;
32using Ode.NET;
33using OpenSim.Framework;
34using OpenSim.Region.Physics.Manager;
35using log4net;
36
37namespace OpenSim.Region.Physics.OdePlugin
38{
39 /// <summary>
40 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
41 /// </summary>
42 public enum dParam : int
43 {
44 LowStop = 0,
45 HiStop = 1,
46 Vel = 2,
47 FMax = 3,
48 FudgeFactor = 4,
49 Bounce = 5,
50 CFM = 6,
51 StopERP = 7,
52 StopCFM = 8,
53 LoStop2 = 256,
54 HiStop2 = 257,
55 Vel2 = 258,
56 FMax2 = 259,
57 StopERP2 = 7 + 256,
58 StopCFM2 = 8 + 256,
59 LoStop3 = 512,
60 HiStop3 = 513,
61 Vel3 = 514,
62 FMax3 = 515,
63 StopERP3 = 7 + 512,
64 StopCFM3 = 8 + 512
65 }
66
67 public class OdeCharacter : PhysicsActor
68 {
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
71 private Vector3 _position;
72 private d.Vector3 _zeroPosition;
73 private bool _zeroFlag = false;
74 private bool m_lastUpdateSent = false;
75 private Vector3 _velocity;
76 private Vector3 m_taintTargetVelocity;
77 private Vector3 _target_velocity;
78 private Vector3 _acceleration;
79 private Vector3 m_rotationalVelocity;
80 private float m_mass = 80f;
81 private float m_density = 60f;
82 private bool m_pidControllerActive = true;
83 private float PID_D = 800.0f;
84 private float PID_P = 900.0f;
85 //private static float POSTURE_SERVO = 10000.0f;
86 private float CAPSULE_RADIUS = 0.37f;
87 private float CAPSULE_LENGTH = 2.140599f;
88 private float m_tensor = 3800000f;
89// private float heightFudgeFactor = 0.52f;
90 private float walkDivisor = 1.3f;
91 private float runDivisor = 0.8f;
92 private bool flying = false;
93 private bool m_iscolliding = false;
94 private bool m_iscollidingGround = false;
95 private bool m_wascolliding = false;
96 private bool m_wascollidingGround = false;
97 private bool m_iscollidingObj = false;
98 private bool m_alwaysRun = false;
99 private bool m_hackSentFall = false;
100 private bool m_hackSentFly = false;
101 private int m_requestedUpdateFrequency = 0;
102 private Vector3 m_taintPosition;
103 internal bool m_avatarplanted = false;
104 /// <summary>
105 /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force
106 /// while calculatios are going on
107 /// </summary>
108 private Vector3 m_taintForce;
109
110 // taints and their non-tainted counterparts
111 private bool m_isPhysical = false; // the current physical status
112 private bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing)
113 internal float MinimumGroundFlightOffset = 3f;
114
115 private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes.
116
117 /// <summary>
118 /// Base movement for calculating tilt.
119 /// </summary>
120 private float m_tiltBaseMovement = (float)Math.Sqrt(2);
121
122 /// <summary>
123 /// Used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider
124 /// </summary>
125 private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f;
126
127 private float m_buoyancy = 0f;
128
129 // private CollisionLocker ode;
130 private bool[] m_colliderarr = new bool[11];
131 private bool[] m_colliderGroundarr = new bool[11];
132
133 // Default we're a Character
134 private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
135
136 // Default, Collide with Other Geometries, spaces, bodies and characters.
137 private CollisionCategories m_collisionFlags = (CollisionCategories.Geom
138 | CollisionCategories.Space
139 | CollisionCategories.Body
140 | CollisionCategories.Character
141 | CollisionCategories.Land);
142 /// <summary>
143 /// Body for dynamics simulation
144 /// </summary>
145 internal IntPtr Body { get; private set; }
146
147 private OdeScene _parent_scene;
148
149 /// <summary>
150 /// Collision geometry
151 /// </summary>
152 internal IntPtr Shell { get; private set; }
153
154 private IntPtr Amotor = IntPtr.Zero;
155 private d.Mass ShellMass;
156
157 private int m_eventsubscription = 0;
158 private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
159
160 // unique UUID of this character object
161 internal UUID m_uuid { get; private set; }
162 internal bool bad = false;
163
164 /// <summary>
165 /// ODE Avatar.
166 /// </summary>
167 /// <param name="avName"></param>
168 /// <param name="parent_scene"></param>
169 /// <param name="pos"></param>
170 /// <param name="size"></param>
171 /// <param name="pid_d"></param>
172 /// <param name="pid_p"></param>
173 /// <param name="capsule_radius"></param>
174 /// <param name="tensor"></param>
175 /// <param name="density">
176 /// Only used right now to return information to LSL. Not actually used to set mass in ODE!
177 /// </param>
178 /// <param name="walk_divisor"></param>
179 /// <param name="rundivisor"></param>
180 public OdeCharacter(
181 String avName, OdeScene parent_scene, Vector3 pos, Vector3 size, float pid_d, float pid_p,
182 float capsule_radius, float tensor, float density,
183 float walk_divisor, float rundivisor)
184 {
185 m_uuid = UUID.Random();
186
187 if (pos.IsFinite())
188 {
189 if (pos.Z > 9999999f)
190 {
191 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
192 }
193 if (pos.Z < -90000f)
194 {
195 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
196 }
197
198 _position = pos;
199 m_taintPosition = pos;
200 }
201 else
202 {
203 _position
204 = new Vector3(
205 (float)_parent_scene.WorldExtents.X * 0.5f,
206 (float)_parent_scene.WorldExtents.Y * 0.5f,
207 parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f);
208 m_taintPosition = _position;
209
210 m_log.WarnFormat("[ODE CHARACTER]: Got NaN Position on Character Create for {0}", avName);
211 }
212
213 _parent_scene = parent_scene;
214
215 PID_D = pid_d;
216 PID_P = pid_p;
217 CAPSULE_RADIUS = capsule_radius;
218 m_tensor = tensor;
219 m_density = density;
220// heightFudgeFactor = height_fudge_factor;
221 walkDivisor = walk_divisor;
222 runDivisor = rundivisor;
223
224 // m_StandUpRotation =
225 // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f,
226 // 0.5f);
227
228 // We can set taint and actual to be the same here, since the entire character will be set up when the
229 // m_tainted_isPhysical is processed.
230 SetTaintedCapsuleLength(size);
231 CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
232
233 m_isPhysical = false; // current status: no ODE information exists
234 m_tainted_isPhysical = true; // new tainted status: need to create ODE information
235
236 _parent_scene.AddPhysicsActorTaint(this);
237
238 Name = avName;
239 }
240
241 public override int PhysicsActorType
242 {
243 get { return (int) ActorTypes.Agent; }
244 set { return; }
245 }
246
247 /// <summary>
248 /// If this is set, the avatar will move faster
249 /// </summary>
250 public override bool SetAlwaysRun
251 {
252 get { return m_alwaysRun; }
253 set { m_alwaysRun = value; }
254 }
255
256 public override bool Grabbed
257 {
258 set { return; }
259 }
260
261 public override bool Selected
262 {
263 set { return; }
264 }
265
266 public override float Buoyancy
267 {
268 get { return m_buoyancy; }
269 set { m_buoyancy = value; }
270 }
271
272 public override bool FloatOnWater
273 {
274 set { return; }
275 }
276
277 public override bool IsPhysical
278 {
279 get { return false; }
280 set { return; }
281 }
282
283 public override bool ThrottleUpdates
284 {
285 get { return false; }
286 set { return; }
287 }
288
289 public override bool Flying
290 {
291 get { return flying; }
292 set
293 {
294 flying = value;
295// m_log.DebugFormat("[ODE CHARACTER]: Set OdeCharacter Flying to {0}", flying);
296 }
297 }
298
299 /// <summary>
300 /// Returns if the avatar is colliding in general.
301 /// This includes the ground and objects and avatar.
302 /// </summary>
303 public override bool IsColliding
304 {
305 get { return m_iscolliding; }
306 set
307 {
308 int i;
309 int truecount = 0;
310 int falsecount = 0;
311
312 if (m_colliderarr.Length >= 10)
313 {
314 for (i = 0; i < 10; i++)
315 {
316 m_colliderarr[i] = m_colliderarr[i + 1];
317 }
318 }
319 m_colliderarr[10] = value;
320
321 for (i = 0; i < 11; i++)
322 {
323 if (m_colliderarr[i])
324 {
325 truecount++;
326 }
327 else
328 {
329 falsecount++;
330 }
331 }
332
333 // Equal truecounts and false counts means we're colliding with something.
334
335 if (falsecount > 1.2*truecount)
336 {
337 m_iscolliding = false;
338 }
339 else
340 {
341 m_iscolliding = true;
342 }
343
344 if (m_wascolliding != m_iscolliding)
345 {
346 //base.SendCollisionUpdate(new CollisionEventUpdate());
347 }
348
349 m_wascolliding = m_iscolliding;
350 }
351 }
352
353 /// <summary>
354 /// Returns if an avatar is colliding with the ground
355 /// </summary>
356 public override bool CollidingGround
357 {
358 get { return m_iscollidingGround; }
359 set
360 {
361 // Collisions against the ground are not really reliable
362 // So, to get a consistant value we have to average the current result over time
363 // Currently we use 1 second = 10 calls to this.
364 int i;
365 int truecount = 0;
366 int falsecount = 0;
367
368 if (m_colliderGroundarr.Length >= 10)
369 {
370 for (i = 0; i < 10; i++)
371 {
372 m_colliderGroundarr[i] = m_colliderGroundarr[i + 1];
373 }
374 }
375 m_colliderGroundarr[10] = value;
376
377 for (i = 0; i < 11; i++)
378 {
379 if (m_colliderGroundarr[i])
380 {
381 truecount++;
382 }
383 else
384 {
385 falsecount++;
386 }
387 }
388
389 // Equal truecounts and false counts means we're colliding with something.
390
391 if (falsecount > 1.2*truecount)
392 {
393 m_iscollidingGround = false;
394 }
395 else
396 {
397 m_iscollidingGround = true;
398 }
399 if (m_wascollidingGround != m_iscollidingGround)
400 {
401 //base.SendCollisionUpdate(new CollisionEventUpdate());
402 }
403 m_wascollidingGround = m_iscollidingGround;
404 }
405 }
406
407 /// <summary>
408 /// Returns if the avatar is colliding with an object
409 /// </summary>
410 public override bool CollidingObj
411 {
412 get { return m_iscollidingObj; }
413 set
414 {
415 m_iscollidingObj = value;
416 if (value && !m_avatarplanted)
417 m_pidControllerActive = false;
418 else
419 m_pidControllerActive = true;
420 }
421 }
422
423 /// <summary>
424 /// turn the PID controller on or off.
425 /// The PID Controller will turn on all by itself in many situations
426 /// </summary>
427 /// <param name="status"></param>
428 public void SetPidStatus(bool status)
429 {
430 m_pidControllerActive = status;
431 }
432
433 public override bool Stopped
434 {
435 get { return _zeroFlag; }
436 }
437
438 /// <summary>
439 /// This 'puts' an avatar somewhere in the physics space.
440 /// Not really a good choice unless you 'know' it's a good
441 /// spot otherwise you're likely to orbit the avatar.
442 /// </summary>
443 public override Vector3 Position
444 {
445 get { return _position; }
446 set
447 {
448 if (Body == IntPtr.Zero || Shell == IntPtr.Zero)
449 {
450 if (value.IsFinite())
451 {
452 if (value.Z > 9999999f)
453 {
454 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
455 }
456 if (value.Z < -90000f)
457 {
458 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
459 }
460
461 m_taintPosition = value;
462 _parent_scene.AddPhysicsActorTaint(this);
463 }
464 else
465 {
466 m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Position from Scene on character {0}", Name);
467 }
468 }
469 }
470 }
471
472 public override Vector3 RotationalVelocity
473 {
474 get { return m_rotationalVelocity; }
475 set { m_rotationalVelocity = value; }
476 }
477
478 /// <summary>
479 /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight
480 /// and use it to offset landings properly
481 /// </summary>
482 public override Vector3 Size
483 {
484 get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); }
485 set
486 {
487 SetTaintedCapsuleLength(value);
488
489 // If we reset velocity here, then an avatar stalls when it crosses a border for the first time
490 // (as the height of the new root agent is set).
491// Velocity = Vector3.Zero;
492
493 _parent_scene.AddPhysicsActorTaint(this);
494 }
495 }
496
497 private void SetTaintedCapsuleLength(Vector3 size)
498 {
499 if (size.IsFinite())
500 {
501 m_pidControllerActive = true;
502
503 m_tainted_CAPSULE_LENGTH = (size.Z * 1.15f) - CAPSULE_RADIUS * 2.0f;
504// m_log.Info("[ODE CHARACTER]: " + CAPSULE_LENGTH);
505 }
506 else
507 {
508 m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Size for {0} in {1}", Name, _parent_scene.Name);
509 }
510 }
511
512 private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector)
513 {
514 movementVector.Z = 0f;
515 float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y));
516 if (magnitude < 0.1f) return;
517
518 // normalize the velocity vector
519 float invMagnitude = 1.0f / magnitude;
520 movementVector.X *= invMagnitude;
521 movementVector.Y *= invMagnitude;
522
523 // if we change the capsule heading too often, the capsule can fall down
524 // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw),
525 // meaning only 4 possible capsule tilt orientations
526 if (movementVector.X > 0)
527 {
528 // east
529 if (movementVector.Y > 0)
530 {
531 // northeast
532 movementVector.X = m_tiltBaseMovement;
533 movementVector.Y = m_tiltBaseMovement;
534 }
535 else
536 {
537 // southeast
538 movementVector.X = m_tiltBaseMovement;
539 movementVector.Y = -m_tiltBaseMovement;
540 }
541 }
542 else
543 {
544 // west
545 if (movementVector.Y > 0)
546 {
547 // northwest
548 movementVector.X = -m_tiltBaseMovement;
549 movementVector.Y = m_tiltBaseMovement;
550 }
551 else
552 {
553 // southwest
554 movementVector.X = -m_tiltBaseMovement;
555 movementVector.Y = -m_tiltBaseMovement;
556 }
557 }
558
559 // movementVector.Z is zero
560
561 // calculate tilt components based on desired amount of tilt and current (snapped) heading.
562 // the "-" sign is to force the tilt to be OPPOSITE the direction of movement.
563 float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane;
564 float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane;
565
566 //m_log.Debug("[ODE CHARACTER]: changing avatar tilt");
567 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent);
568 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced
569 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent);
570 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop
571 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
572 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
573 }
574
575 /// <summary>
576 /// Uses the capped cyllinder volume formula to calculate the avatar's mass.
577 /// This may be used in calculations in the scene/scenepresence
578 /// </summary>
579 public override float Mass
580 {
581 get
582 {
583 float AVvolume = (float)(Math.PI * Math.Pow(CAPSULE_RADIUS, 2) * CAPSULE_LENGTH);
584 return m_density * AVvolume;
585 }
586 }
587
588 public override void link(PhysicsActor obj) {}
589
590 public override void delink() {}
591
592 public override void LockAngularMotion(Vector3 axis) {}
593
594// This code is very useful. Written by DanX0r. We're just not using it right now.
595// Commented out to prevent a warning.
596//
597// private void standupStraight()
598// {
599// // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air.
600// // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you
601// // change appearance and when you enter the simulator
602// // After this routine is done, the amotor stabilizes much quicker
603// d.Vector3 feet;
604// d.Vector3 head;
605// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet);
606// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head);
607// float posture = head.Z - feet.Z;
608
609// // restoring force proportional to lack of posture:
610// float servo = (2.5f - posture) * POSTURE_SERVO;
611// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f);
612// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f);
613// //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
614// //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyFArotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
615// }
616
617 public override Vector3 Force
618 {
619 get { return _target_velocity; }
620 set { return; }
621 }
622
623 public override int VehicleType
624 {
625 get { return 0; }
626 set { return; }
627 }
628
629 public override void VehicleFloatParam(int param, float value)
630 {
631 }
632
633 public override void VehicleVectorParam(int param, Vector3 value)
634 {
635 }
636
637 public override void VehicleRotationParam(int param, Quaternion rotation)
638 {
639 }
640
641 public override void VehicleFlags(int param, bool remove)
642 {
643 }
644
645 public override void SetVolumeDetect(int param)
646 {
647 }
648
649 public override Vector3 CenterOfMass
650 {
651 get { return Vector3.Zero; }
652 }
653
654 public override Vector3 GeometricCenter
655 {
656 get { return Vector3.Zero; }
657 }
658
659 public override PrimitiveBaseShape Shape
660 {
661 set { return; }
662 }
663
664 public override Vector3 TargetVelocity
665 {
666 get
667 {
668 return m_taintTargetVelocity;
669 }
670
671 set
672 {
673 Velocity = value;
674 }
675 }
676
677
678 public override Vector3 Velocity
679 {
680 get
681 {
682 // There's a problem with Vector3.Zero! Don't Use it Here!
683 if (_zeroFlag)
684 return Vector3.Zero;
685 m_lastUpdateSent = false;
686 return _velocity;
687 }
688
689 set
690 {
691 if (value.IsFinite())
692 {
693 m_pidControllerActive = true;
694 m_taintTargetVelocity = value;
695 _parent_scene.AddPhysicsActorTaint(this);
696 }
697 else
698 {
699 m_log.WarnFormat("[ODE CHARACTER]: Got a NaN velocity from Scene for {0}", Name);
700 }
701
702// m_log.DebugFormat("[PHYSICS]: Set target velocity of {0}", m_taintTargetVelocity);
703 }
704 }
705
706 public override Vector3 Torque
707 {
708 get { return Vector3.Zero; }
709 set { return; }
710 }
711
712 public override float CollisionScore
713 {
714 get { return 0f; }
715 set { }
716 }
717
718 public override bool Kinematic
719 {
720 get { return false; }
721 set { }
722 }
723
724 public override Quaternion Orientation
725 {
726 get { return Quaternion.Identity; }
727 set {
728 //Matrix3 or = Orientation.ToRotationMatrix();
729 //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22);
730 //d.BodySetRotation(Body, ref ord);
731 }
732 }
733
734 public override Vector3 Acceleration
735 {
736 get { return _acceleration; }
737 set { _acceleration = value; }
738 }
739
740 /// <summary>
741 /// Adds the force supplied to the Target Velocity
742 /// The PID controller takes this target velocity and tries to make it a reality
743 /// </summary>
744 /// <param name="force"></param>
745 public override void AddForce(Vector3 force, bool pushforce)
746 {
747 if (force.IsFinite())
748 {
749 if (pushforce)
750 {
751 m_pidControllerActive = false;
752 force *= 100f;
753 m_taintForce += force;
754 _parent_scene.AddPhysicsActorTaint(this);
755
756 // If uncommented, things get pushed off world
757 //
758 // m_log.Debug("Push!");
759 // m_taintTargetVelocity.X += force.X;
760 // m_taintTargetVelocity.Y += force.Y;
761 // m_taintTargetVelocity.Z += force.Z;
762 }
763 else
764 {
765 m_pidControllerActive = true;
766 m_taintTargetVelocity += force;
767 }
768 }
769 else
770 {
771 m_log.WarnFormat("[ODE CHARACTER]: Got a NaN force applied to {0}", Name);
772 }
773 //m_lastUpdateSent = false;
774 }
775
776 public override void AddAngularForce(Vector3 force, bool pushforce)
777 {
778 }
779
780 public override void SetMomentum(Vector3 momentum)
781 {
782 }
783
784 /// <summary>
785 /// Called from Simulate
786 /// This is the avatar's movement control + PID Controller
787 /// </summary>
788 /// <param name="defects">The character will be added to this list if there is something wrong (non-finite
789 /// position or velocity).
790 /// </param>
791 internal void Move(List<OdeCharacter> defects)
792 {
793 // no lock; for now it's only called from within Simulate()
794
795 // If the PID Controller isn't active then we set our force
796 // calculating base velocity to the current position
797
798 if (Body == IntPtr.Zero)
799 return;
800
801 if (m_pidControllerActive == false)
802 {
803 _zeroPosition = d.BodyGetPosition(Body);
804 }
805 //PidStatus = true;
806
807 d.Vector3 localpos = d.BodyGetPosition(Body);
808 Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z);
809
810 if (!localPos.IsFinite())
811 {
812 m_log.WarnFormat(
813 "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.",
814 localPos, Name);
815
816 defects.Add(this);
817
818 return;
819 }
820
821 Vector3 vec = Vector3.Zero;
822 d.Vector3 vel = d.BodyGetLinearVel(Body);
823
824// m_log.DebugFormat(
825// "[ODE CHARACTER]: Current velocity in Move() is <{0},{1},{2}>, target {3} for {4}",
826// vel.X, vel.Y, vel.Z, _target_velocity, Name);
827
828 float movementdivisor = 1f;
829
830 if (!m_alwaysRun)
831 {
832 movementdivisor = walkDivisor;
833 }
834 else
835 {
836 movementdivisor = runDivisor;
837 }
838
839 // if velocity is zero, use position control; otherwise, velocity control
840 if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding)
841 {
842 // keep track of where we stopped. No more slippin' & slidin'
843 if (!_zeroFlag)
844 {
845 _zeroFlag = true;
846 _zeroPosition = d.BodyGetPosition(Body);
847 }
848
849 if (m_pidControllerActive)
850 {
851 // We only want to deactivate the PID Controller if we think we want to have our surrogate
852 // react to the physics scene by moving it's position.
853 // Avatar to Avatar collisions
854 // Prim to avatar collisions
855
856 d.Vector3 pos = d.BodyGetPosition(Body);
857 vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
858 vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y)* (PID_P * 2);
859 if (flying)
860 {
861 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
862 }
863 }
864 //PidStatus = true;
865 }
866 else
867 {
868 m_pidControllerActive = true;
869 _zeroFlag = false;
870 if (m_iscolliding && !flying)
871 {
872 // We're standing on something
873 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D);
874 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D);
875 }
876 else if (m_iscolliding && flying)
877 {
878 // We're flying and colliding with something
879 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16);
880 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16);
881 }
882 else if (!m_iscolliding && flying)
883 {
884 // we're in mid air suspended
885 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6);
886 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6);
887
888// m_log.DebugFormat(
889// "[ODE CHARACTER]: !m_iscolliding && flying, vec {0}, _target_velocity {1}, movementdivisor {2}, vel {3}",
890// vec, _target_velocity, movementdivisor, vel);
891 }
892
893 if (m_iscolliding && !flying && _target_velocity.Z > 0.0f)
894 {
895 // We're colliding with something and we're not flying but we're moving
896 // This means we're walking or running.
897 d.Vector3 pos = d.BodyGetPosition(Body);
898 vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P;
899 if (_target_velocity.X > 0)
900 {
901 vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D;
902 }
903 if (_target_velocity.Y > 0)
904 {
905 vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D;
906 }
907 }
908 else if (!m_iscolliding && !flying)
909 {
910 // we're not colliding and we're not flying so that means we're falling!
911 // m_iscolliding includes collisions with the ground.
912
913 // d.Vector3 pos = d.BodyGetPosition(Body);
914 if (_target_velocity.X > 0)
915 {
916 vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D;
917 }
918 if (_target_velocity.Y > 0)
919 {
920 vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D;
921 }
922 }
923
924 if (flying)
925 {
926 // This also acts as anti-gravity so that we hover when flying rather than fall.
927 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D);
928 }
929 }
930
931 if (flying)
932 {
933 // Anti-gravity so that we hover when flying rather than fall.
934 vec.Z += ((-1 * _parent_scene.gravityz) * m_mass);
935
936 //Added for auto fly height. Kitto Flora
937 //d.Vector3 pos = d.BodyGetPosition(Body);
938 float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset;
939
940 if (_position.Z < target_altitude)
941 {
942 vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f;
943 }
944 // end add Kitto Flora
945 }
946
947 if (vec.IsFinite())
948 {
949 // Apply the total force acting on this avatar
950 d.BodyAddForce(Body, vec.X, vec.Y, vec.Z);
951
952 if (!_zeroFlag)
953 AlignAvatarTiltWithCurrentDirectionOfMovement(vec);
954 }
955 else
956 {
957 m_log.WarnFormat(
958 "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.",
959 vec, Name);
960
961 defects.Add(this);
962
963 return;
964 }
965
966 d.Vector3 newVel = d.BodyGetLinearVel(Body);
967 if (newVel.X >= 256 || newVel.X <= 256 || newVel.Y >= 256 || newVel.Y <= 256 || newVel.Z >= 256 || newVel.Z <= 256)
968 {
969// m_log.DebugFormat(
970// "[ODE CHARACTER]: Limiting falling velocity from {0} to {1} for {2}", newVel.Z, -9.8, Name);
971
972 newVel.X = Util.Clamp<float>(newVel.X, -255f, 255f);
973 newVel.Y = Util.Clamp<float>(newVel.Y, -255f, 255f);
974
975 if (!flying)
976 newVel.Z
977 = Util.Clamp<float>(
978 newVel.Z, -_parent_scene.AvatarTerminalVelocity, _parent_scene.AvatarTerminalVelocity);
979 else
980 newVel.Z = Util.Clamp<float>(newVel.Z, -255f, 255f);
981
982 d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z);
983 }
984 }
985
986 /// <summary>
987 /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence.
988 /// </summary>
989 /// <param name="defects">The character will be added to this list if there is something wrong (non-finite
990 /// position or velocity).
991 /// </param>
992 internal void UpdatePositionAndVelocity(List<OdeCharacter> defects)
993 {
994 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
995 d.Vector3 newPos;
996 try
997 {
998 newPos = d.BodyGetPosition(Body);
999 }
1000 catch (NullReferenceException)
1001 {
1002 bad = true;
1003 defects.Add(this);
1004 newPos = new d.Vector3(_position.X, _position.Y, _position.Z);
1005 base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem!
1006 m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid);
1007
1008 return;
1009 }
1010
1011 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
1012 if (newPos.X < 0.0f) newPos.X = 0.0f;
1013 if (newPos.Y < 0.0f) newPos.Y = 0.0f;
1014 if (newPos.X > (int)_parent_scene.WorldExtents.X - 0.05f) newPos.X = (int)_parent_scene.WorldExtents.X - 0.05f;
1015 if (newPos.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) newPos.Y = (int)_parent_scene.WorldExtents.Y - 0.05f;
1016
1017 _position.X = newPos.X;
1018 _position.Y = newPos.Y;
1019 _position.Z = newPos.Z;
1020
1021 // I think we need to update the taintPosition too -- Diva 12/24/10
1022 m_taintPosition = _position;
1023
1024 // Did we move last? = zeroflag
1025 // This helps keep us from sliding all over
1026
1027 if (_zeroFlag)
1028 {
1029 _velocity = Vector3.Zero;
1030
1031 // Did we send out the 'stopped' message?
1032 if (!m_lastUpdateSent)
1033 {
1034 m_lastUpdateSent = true;
1035 //base.RequestPhysicsterseUpdate();
1036 }
1037 }
1038 else
1039 {
1040 m_lastUpdateSent = false;
1041 d.Vector3 newVelocity;
1042
1043 try
1044 {
1045 newVelocity = d.BodyGetLinearVel(Body);
1046 }
1047 catch (NullReferenceException)
1048 {
1049 newVelocity.X = _velocity.X;
1050 newVelocity.Y = _velocity.Y;
1051 newVelocity.Z = _velocity.Z;
1052 }
1053
1054 _velocity.X = newVelocity.X;
1055 _velocity.Y = newVelocity.Y;
1056 _velocity.Z = newVelocity.Z;
1057
1058 if (_velocity.Z < -6 && !m_hackSentFall)
1059 {
1060 m_hackSentFall = true;
1061 m_pidControllerActive = false;
1062 }
1063 else if (flying && !m_hackSentFly)
1064 {
1065 //m_hackSentFly = true;
1066 //base.SendCollisionUpdate(new CollisionEventUpdate());
1067 }
1068 else
1069 {
1070 m_hackSentFly = false;
1071 m_hackSentFall = false;
1072 }
1073 }
1074 }
1075
1076 /// <summary>
1077 /// This creates the Avatar's physical Surrogate in ODE at the position supplied
1078 /// </summary>
1079 /// <remarks>
1080 /// WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access
1081 /// to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only
1082 /// place that is safe to call this routine AvatarGeomAndBodyCreation.
1083 /// </remarks>
1084 /// <param name="npositionX"></param>
1085 /// <param name="npositionY"></param>
1086 /// <param name="npositionZ"></param>
1087 /// <param name="tensor"></param>
1088 private void CreateOdeStructures(float npositionX, float npositionY, float npositionZ, float tensor)
1089 {
1090 if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero))
1091 {
1092 m_log.ErrorFormat(
1093 "[ODE CHARACTER]: Creating ODE structures for {0} even though some already exist. Shell = {1}, Body = {2}, Amotor = {3}",
1094 Name, Shell, Body, Amotor);
1095 }
1096
1097 int dAMotorEuler = 1;
1098// _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1099 if (CAPSULE_LENGTH <= 0)
1100 {
1101 m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
1102 CAPSULE_LENGTH = 0.01f;
1103 }
1104
1105 if (CAPSULE_RADIUS <= 0)
1106 {
1107 m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
1108 CAPSULE_RADIUS = 0.01f;
1109 }
1110
1111// lock (OdeScene.UniversalColliderSyncObject)
1112 Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
1113
1114 d.GeomSetCategoryBits(Shell, (int)m_collisionCategories);
1115 d.GeomSetCollideBits(Shell, (int)m_collisionFlags);
1116
1117 d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH);
1118 Body = d.BodyCreate(_parent_scene.world);
1119 d.BodySetPosition(Body, npositionX, npositionY, npositionZ);
1120
1121 _position.X = npositionX;
1122 _position.Y = npositionY;
1123 _position.Z = npositionZ;
1124
1125 m_taintPosition = _position;
1126
1127 d.BodySetMass(Body, ref ShellMass);
1128 d.Matrix3 m_caprot;
1129 // 90 Stand up on the cap of the capped cyllinder
1130 if (_parent_scene.IsAvCapsuleTilted)
1131 {
1132 d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2));
1133 }
1134 else
1135 {
1136 d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2));
1137 }
1138
1139 d.GeomSetRotation(Shell, ref m_caprot);
1140 d.BodySetRotation(Body, ref m_caprot);
1141
1142 d.GeomSetBody(Shell, Body);
1143
1144 // The purpose of the AMotor here is to keep the avatar's physical
1145 // surrogate from rotating while moving
1146 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
1147 d.JointAttach(Amotor, Body, IntPtr.Zero);
1148 d.JointSetAMotorMode(Amotor, dAMotorEuler);
1149 d.JointSetAMotorNumAxes(Amotor, 3);
1150 d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0);
1151 d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0);
1152 d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1);
1153 d.JointSetAMotorAngle(Amotor, 0, 0);
1154 d.JointSetAMotorAngle(Amotor, 1, 0);
1155 d.JointSetAMotorAngle(Amotor, 2, 0);
1156
1157 // These lowstops and high stops are effectively (no wiggle room)
1158 if (_parent_scene.IsAvCapsuleTilted)
1159 {
1160 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f);
1161 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f);
1162 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f);
1163 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f);
1164 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f);
1165 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f);
1166 }
1167 else
1168 {
1169 #region Documentation of capsule motor LowStop and HighStop parameters
1170 // Intentionally introduce some tilt into the capsule by setting
1171 // the motor stops to small epsilon values. This small tilt prevents
1172 // the capsule from falling into the terrain; a straight-up capsule
1173 // (with -0..0 motor stops) falls into the terrain for reasons yet
1174 // to be comprehended in their entirety.
1175 #endregion
1176 AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero);
1177 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f);
1178 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f);
1179 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f);
1180 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced
1181 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
1182 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop
1183 }
1184
1185 // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the
1186 // capped cyllinder will fall over
1187 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
1188 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor);
1189
1190 //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
1191 //d.QfromR(
1192 //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068,
1193 //
1194 //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
1195 //standupStraight();
1196
1197 _parent_scene.geom_name_map[Shell] = Name;
1198 _parent_scene.actor_name_map[Shell] = this;
1199 }
1200
1201 /// <summary>
1202 /// Cleanup the things we use in the scene.
1203 /// </summary>
1204 internal void Destroy()
1205 {
1206 m_tainted_isPhysical = false;
1207 _parent_scene.AddPhysicsActorTaint(this);
1208 }
1209
1210 /// <summary>
1211 /// Used internally to destroy the ODE structures associated with this character.
1212 /// </summary>
1213 internal void DestroyOdeStructures()
1214 {
1215 // Create avatar capsule and related ODE data
1216 if (Shell == IntPtr.Zero || Body == IntPtr.Zero || Amotor == IntPtr.Zero)
1217 {
1218 m_log.ErrorFormat(
1219 "[ODE CHARACTER]: Destroying ODE structures for {0} even though some are already null. Shell = {1}, Body = {2}, Amotor = {3}",
1220 Name, Shell, Body, Amotor);
1221 }
1222
1223 // destroy avatar capsule and related ODE data
1224 if (Amotor != IntPtr.Zero)
1225 {
1226 // Kill the Amotor
1227 d.JointDestroy(Amotor);
1228 Amotor = IntPtr.Zero;
1229 }
1230
1231 //kill the Geometry
1232// _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1233
1234 if (Body != IntPtr.Zero)
1235 {
1236 //kill the body
1237 d.BodyDestroy(Body);
1238 Body = IntPtr.Zero;
1239 }
1240
1241 if (Shell != IntPtr.Zero)
1242 {
1243// lock (OdeScene.UniversalColliderSyncObject)
1244 d.GeomDestroy(Shell);
1245
1246 _parent_scene.geom_name_map.Remove(Shell);
1247 _parent_scene.actor_name_map.Remove(Shell);
1248
1249 Shell = IntPtr.Zero;
1250 }
1251 }
1252
1253 public override void CrossingFailure()
1254 {
1255 }
1256
1257 public override Vector3 PIDTarget { set { return; } }
1258 public override bool PIDActive { set { return; } }
1259 public override float PIDTau { set { return; } }
1260
1261 public override float PIDHoverHeight { set { return; } }
1262 public override bool PIDHoverActive { set { return; } }
1263 public override PIDHoverType PIDHoverType { set { return; } }
1264 public override float PIDHoverTau { set { return; } }
1265
1266 public override Quaternion APIDTarget{ set { return; } }
1267
1268 public override bool APIDActive{ set { return; } }
1269
1270 public override float APIDStrength{ set { return; } }
1271
1272 public override float APIDDamping{ set { return; } }
1273
1274 public override void SubscribeEvents(int ms)
1275 {
1276 m_requestedUpdateFrequency = ms;
1277 m_eventsubscription = ms;
1278
1279 // Don't clear collision event reporting here. This is called directly from scene code and so can lead
1280 // to a race condition with the simulate loop
1281
1282 _parent_scene.AddCollisionEventReporting(this);
1283 }
1284
1285 public override void UnSubscribeEvents()
1286 {
1287 _parent_scene.RemoveCollisionEventReporting(this);
1288
1289 // Don't clear collision event reporting here. This is called directly from scene code and so can lead
1290 // to a race condition with the simulate loop
1291
1292 m_requestedUpdateFrequency = 0;
1293 m_eventsubscription = 0;
1294 }
1295
1296 internal void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
1297 {
1298 if (m_eventsubscription > 0)
1299 {
1300// m_log.DebugFormat(
1301// "[PHYSICS]: Adding collision event for {0}, collidedWith {1}, contact {2}", "", CollidedWith, contact);
1302
1303 CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
1304 }
1305 }
1306
1307 internal void SendCollisions()
1308 {
1309 if (m_eventsubscription > m_requestedUpdateFrequency)
1310 {
1311 base.SendCollisionUpdate(CollisionEventsThisFrame);
1312
1313 CollisionEventsThisFrame.Clear();
1314 m_eventsubscription = 0;
1315 }
1316 }
1317
1318 public override bool SubscribedEvents()
1319 {
1320 if (m_eventsubscription > 0)
1321 return true;
1322 return false;
1323 }
1324
1325 internal void ProcessTaints()
1326 {
1327 if (m_taintPosition != _position)
1328 {
1329 if (Body != IntPtr.Zero)
1330 {
1331 d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z);
1332 _position = m_taintPosition;
1333 }
1334 }
1335
1336 if (m_taintForce != Vector3.Zero)
1337 {
1338 if (Body != IntPtr.Zero)
1339 {
1340 // FIXME: This is not a good solution since it's subject to a race condition if a force is another
1341 // thread sets a new force while we're in this loop (since it could be obliterated by
1342 // m_taintForce = Vector3.Zero. Need to lock ProcessTaints() when we set a new tainted force.
1343 d.BodyAddForce(Body, m_taintForce.X, m_taintForce.Y, m_taintForce.Z);
1344 }
1345
1346 m_taintForce = Vector3.Zero;
1347 }
1348
1349 if (m_taintTargetVelocity != _target_velocity)
1350 _target_velocity = m_taintTargetVelocity;
1351
1352 if (m_tainted_isPhysical != m_isPhysical)
1353 {
1354 if (m_tainted_isPhysical)
1355 {
1356 CreateOdeStructures(_position.X, _position.Y, _position.Z, m_tensor);
1357 _parent_scene.AddCharacter(this);
1358 }
1359 else
1360 {
1361 _parent_scene.RemoveCharacter(this);
1362 DestroyOdeStructures();
1363 }
1364
1365 m_isPhysical = m_tainted_isPhysical;
1366 }
1367
1368 if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH)
1369 {
1370 if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero)
1371 {
1372// m_log.DebugFormat(
1373// "[ODE CHARACTER]: Changing capsule size from {0} to {1} for {2}",
1374// CAPSULE_LENGTH, m_tainted_CAPSULE_LENGTH, Name);
1375
1376 m_pidControllerActive = true;
1377
1378 // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate()
1379 DestroyOdeStructures();
1380
1381 float prevCapsule = CAPSULE_LENGTH;
1382 CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
1383
1384 CreateOdeStructures(
1385 _position.X,
1386 _position.Y,
1387 _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor);
1388
1389 // As with Size, we reset velocity. However, this isn't strictly necessary since it doesn't
1390 // appear to stall initial region crossings when done here. Being done for consistency.
1391// Velocity = Vector3.Zero;
1392 }
1393 else
1394 {
1395 m_log.Warn("[ODE CHARACTER]: trying to change capsule size for " + Name + ", but the following ODE data is missing - "
1396 + (Shell==IntPtr.Zero ? "Shell ":"")
1397 + (Body==IntPtr.Zero ? "Body ":"")
1398 + (Amotor==IntPtr.Zero ? "Amotor ":""));
1399 }
1400 }
1401 }
1402
1403 internal void AddCollisionFrameTime(int p)
1404 {
1405 // protect it from overflow crashing
1406 if (m_eventsubscription + p >= int.MaxValue)
1407 m_eventsubscription = 0;
1408 m_eventsubscription += p;
1409 }
1410 }
1411}
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEDynamics.c_comments b/OpenSim/Region/Physics/OdePlugin/ODEDynamics.c_comments
deleted file mode 100644
index 1060aa6..0000000
--- a/OpenSim/Region/Physics/OdePlugin/ODEDynamics.c_comments
+++ /dev/null
@@ -1,630 +0,0 @@
1/*
2 * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces
3 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
4 * ODEPrim.cs contains methods dealing with Prim editing, Prim
5 * characteristics and Kinetic motion.
6 * ODEDynamics.cs contains methods dealing with Prim Physical motion
7 * (dynamics) and the associated settings. Old Linear and angular
8 * motors for dynamic motion have been replace with MoveLinear()
9 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
10 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
11 * switch between 'VEHICLE' parameter use and general dynamics
12 * settings use.
13 *
14 * Copyright (c) Contributors, http://opensimulator.org/
15 * See CONTRIBUTORS.TXT for a full list of copyright holders.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are met:
19 * * Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * * Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * * Neither the name of the OpenSimulator Project nor the
25 * names of its contributors may be used to endorse or promote products
26 * derived from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
29 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39
40using System;
41using System.Collections.Generic;
42using System.Reflection;
43using System.Runtime.InteropServices;
44using log4net;
45using OpenMetaverse;
46using Ode.NET;
47using OpenSim.Framework;
48using OpenSim.Region.Physics.Manager;
49
50namespace OpenSim.Region.Physics.OdePlugin
51{
52 public class ODEDynamics
53 {
54 public Vehicle Type
55 {
56 get { return m_type; }
57 }
58
59 public IntPtr Body
60 {
61 get { return m_body; }
62 }
63
64 private int frcount = 0; // Used to limit dynamics debug output to
65 // every 100th frame
66
67 // private OdeScene m_parentScene = null;
68 private IntPtr m_body = IntPtr.Zero;
69 private IntPtr m_jointGroup = IntPtr.Zero;
70 private IntPtr m_aMotor = IntPtr.Zero;
71
72
73 // Vehicle properties
74 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
75 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
76 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
77 // HOVER_TERRAIN_ONLY
78 // HOVER_GLOBAL_HEIGHT
79 // NO_DEFLECTION_UP
80 // HOVER_WATER_ONLY
81 // HOVER_UP_ONLY
82 // LIMIT_MOTOR_UP
83 // LIMIT_ROLL_ONLY
84
85 // Linear properties
86 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
87 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
88 private Vector3 m_dir = Vector3.Zero; // velocity applied to body
89 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
90 private float m_linearMotorDecayTimescale = 0;
91 private float m_linearMotorTimescale = 0;
92 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
93 // private bool m_LinearMotorSetLastFrame = false;
94 // private Vector3 m_linearMotorOffset = Vector3.Zero;
95
96 //Angular properties
97 private Vector3 m_angularMotorDirection = Vector3.Zero;
98 private Vector3 m_angularMotorDirectionLASTSET = Vector3.Zero;
99 private Vector3 m_angularFrictionTimescale = Vector3.Zero;
100 private float m_angularMotorDecayTimescale = 0;
101 private float m_angularMotorTimescale = 0;
102 private Vector3 m_lastAngularVelocityVector = Vector3.Zero;
103
104 //Deflection properties
105 // private float m_angularDeflectionEfficiency = 0;
106 // private float m_angularDeflectionTimescale = 0;
107 // private float m_linearDeflectionEfficiency = 0;
108 // private float m_linearDeflectionTimescale = 0;
109
110 //Banking properties
111 // private float m_bankingEfficiency = 0;
112 // private float m_bankingMix = 0;
113 // private float m_bankingTimescale = 0;
114
115 //Hover and Buoyancy properties
116 private float m_VhoverHeight = 0f;
117 private float m_VhoverEfficiency = 0f;
118 private float m_VhoverTimescale = 0f;
119 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
120 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
121 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
122 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
123 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
124
125 //Attractor properties
126 private float m_verticalAttractionEfficiency = 0;
127 private float m_verticalAttractionTimescale = 0;
128
129
130
131
132
133 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
134 {
135 switch (pParam)
136 {
137 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
138 if (pValue < 0.01f) pValue = 0.01f;
139 // m_angularDeflectionEfficiency = pValue;
140 break;
141 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
142 if (pValue < 0.01f) pValue = 0.01f;
143 // m_angularDeflectionTimescale = pValue;
144 break;
145 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
146 if (pValue < 0.01f) pValue = 0.01f;
147 m_angularMotorDecayTimescale = pValue;
148 break;
149 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
150 if (pValue < 0.01f) pValue = 0.01f;
151 m_angularMotorTimescale = pValue;
152 break;
153 case Vehicle.BANKING_EFFICIENCY:
154 if (pValue < 0.01f) pValue = 0.01f;
155 // m_bankingEfficiency = pValue;
156 break;
157 case Vehicle.BANKING_MIX:
158 if (pValue < 0.01f) pValue = 0.01f;
159 // m_bankingMix = pValue;
160 break;
161 case Vehicle.BANKING_TIMESCALE:
162 if (pValue < 0.01f) pValue = 0.01f;
163 // m_bankingTimescale = pValue;
164 break;
165 case Vehicle.BUOYANCY:
166 if (pValue < -1f) pValue = -1f;
167 if (pValue > 1f) pValue = 1f;
168 m_VehicleBuoyancy = pValue;
169 break;
170 case Vehicle.HOVER_EFFICIENCY:
171 if (pValue < 0f) pValue = 0f;
172 if (pValue > 1f) pValue = 1f;
173 m_VhoverEfficiency = pValue;
174 break;
175 case Vehicle.HOVER_HEIGHT:
176 m_VhoverHeight = pValue;
177 break;
178 case Vehicle.HOVER_TIMESCALE:
179 if (pValue < 0.01f) pValue = 0.01f;
180 m_VhoverTimescale = pValue;
181 break;
182 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
183 if (pValue < 0.01f) pValue = 0.01f;
184 // m_linearDeflectionEfficiency = pValue;
185 break;
186 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
187 if (pValue < 0.01f) pValue = 0.01f;
188 // m_linearDeflectionTimescale = pValue;
189 break;
190 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
191 if (pValue < 0.01f) pValue = 0.01f;
192 m_linearMotorDecayTimescale = pValue;
193 break;
194 case Vehicle.LINEAR_MOTOR_TIMESCALE:
195 if (pValue < 0.01f) pValue = 0.01f;
196 m_linearMotorTimescale = pValue;
197 break;
198 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
199 if (pValue < 0.0f) pValue = 0.0f;
200 if (pValue > 1.0f) pValue = 1.0f;
201 m_verticalAttractionEfficiency = pValue;
202 break;
203 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
204 if (pValue < 0.01f) pValue = 0.01f;
205 m_verticalAttractionTimescale = pValue;
206 break;
207
208 // These are vector properties but the engine lets you use a single float value to
209 // set all of the components to the same value
210 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
211 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
212 break;
213 case Vehicle.ANGULAR_MOTOR_DIRECTION:
214 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
215 m_angularMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
216 break;
217 case Vehicle.LINEAR_FRICTION_TIMESCALE:
218 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
219 break;
220 case Vehicle.LINEAR_MOTOR_DIRECTION:
221 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
222 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
223 break;
224 case Vehicle.LINEAR_MOTOR_OFFSET:
225 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
226 break;
227
228 }
229
230 }//end ProcessFloatVehicleParam
231
232 internal void ProcessVectorVehicleParam(Vehicle pParam, PhysicsVector pValue)
233 {
234 switch (pParam)
235 {
236 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
237 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
238 break;
239 case Vehicle.ANGULAR_MOTOR_DIRECTION:
240 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
241 m_angularMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
242 break;
243 case Vehicle.LINEAR_FRICTION_TIMESCALE:
244 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
245 break;
246 case Vehicle.LINEAR_MOTOR_DIRECTION:
247 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
248 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
249 break;
250 case Vehicle.LINEAR_MOTOR_OFFSET:
251 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
252 break;
253 }
254
255 }//end ProcessVectorVehicleParam
256
257 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
258 {
259 switch (pParam)
260 {
261 case Vehicle.REFERENCE_FRAME:
262 // m_referenceFrame = pValue;
263 break;
264 }
265
266 }//end ProcessRotationVehicleParam
267
268 internal void ProcessTypeChange(Vehicle pType)
269 {
270Console.WriteLine("ProcessTypeChange to " + pType);
271
272 // Set Defaults For Type
273 m_type = pType;
274 switch (pType)
275 {
276 case Vehicle.TYPE_SLED:
277 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
278 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
279 m_linearMotorDirection = Vector3.Zero;
280 m_linearMotorTimescale = 1000;
281 m_linearMotorDecayTimescale = 120;
282 m_angularMotorDirection = Vector3.Zero;
283 m_angularMotorTimescale = 1000;
284 m_angularMotorDecayTimescale = 120;
285 m_VhoverHeight = 0;
286 m_VhoverEfficiency = 1;
287 m_VhoverTimescale = 10;
288 m_VehicleBuoyancy = 0;
289 // m_linearDeflectionEfficiency = 1;
290 // m_linearDeflectionTimescale = 1;
291 // m_angularDeflectionEfficiency = 1;
292 // m_angularDeflectionTimescale = 1000;
293 // m_bankingEfficiency = 0;
294 // m_bankingMix = 1;
295 // m_bankingTimescale = 10;
296 // m_referenceFrame = Quaternion.Identity;
297 m_flags &=
298 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
299 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
300 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
301 break;
302 case Vehicle.TYPE_CAR:
303 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
304 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
305 m_linearMotorDirection = Vector3.Zero;
306 m_linearMotorTimescale = 1;
307 m_linearMotorDecayTimescale = 60;
308 m_angularMotorDirection = Vector3.Zero;
309 m_angularMotorTimescale = 1;
310 m_angularMotorDecayTimescale = 0.8f;
311 m_VhoverHeight = 0;
312 m_VhoverEfficiency = 0;
313 m_VhoverTimescale = 1000;
314 m_VehicleBuoyancy = 0;
315 // // m_linearDeflectionEfficiency = 1;
316 // // m_linearDeflectionTimescale = 2;
317 // // m_angularDeflectionEfficiency = 0;
318 // m_angularDeflectionTimescale = 10;
319 m_verticalAttractionEfficiency = 1;
320 m_verticalAttractionTimescale = 10;
321 // m_bankingEfficiency = -0.2f;
322 // m_bankingMix = 1;
323 // m_bankingTimescale = 1;
324 // m_referenceFrame = Quaternion.Identity;
325 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
326 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_UP_ONLY |
327 VehicleFlag.LIMIT_MOTOR_UP);
328 break;
329 case Vehicle.TYPE_BOAT:
330 m_linearFrictionTimescale = new Vector3(10, 3, 2);
331 m_angularFrictionTimescale = new Vector3(10,10,10);
332 m_linearMotorDirection = Vector3.Zero;
333 m_linearMotorTimescale = 5;
334 m_linearMotorDecayTimescale = 60;
335 m_angularMotorDirection = Vector3.Zero;
336 m_angularMotorTimescale = 4;
337 m_angularMotorDecayTimescale = 4;
338 m_VhoverHeight = 0;
339 m_VhoverEfficiency = 0.5f;
340 m_VhoverTimescale = 2;
341 m_VehicleBuoyancy = 1;
342 // m_linearDeflectionEfficiency = 0.5f;
343 // m_linearDeflectionTimescale = 3;
344 // m_angularDeflectionEfficiency = 0.5f;
345 // m_angularDeflectionTimescale = 5;
346 m_verticalAttractionEfficiency = 0.5f;
347 m_verticalAttractionTimescale = 5;
348 // m_bankingEfficiency = -0.3f;
349 // m_bankingMix = 0.8f;
350 // m_bankingTimescale = 1;
351 // m_referenceFrame = Quaternion.Identity;
352 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.LIMIT_ROLL_ONLY |
353 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY |
355 VehicleFlag.LIMIT_MOTOR_UP);
356 break;
357 case Vehicle.TYPE_AIRPLANE:
358 m_linearFrictionTimescale = new Vector3(200, 10, 5);
359 m_angularFrictionTimescale = new Vector3(20, 20, 20);
360 m_linearMotorDirection = Vector3.Zero;
361 m_linearMotorTimescale = 2;
362 m_linearMotorDecayTimescale = 60;
363 m_angularMotorDirection = Vector3.Zero;
364 m_angularMotorTimescale = 4;
365 m_angularMotorDecayTimescale = 4;
366 m_VhoverHeight = 0;
367 m_VhoverEfficiency = 0.5f;
368 m_VhoverTimescale = 1000;
369 m_VehicleBuoyancy = 0;
370 // m_linearDeflectionEfficiency = 0.5f;
371 // m_linearDeflectionTimescale = 3;
372 // m_angularDeflectionEfficiency = 1;
373 // m_angularDeflectionTimescale = 2;
374 m_verticalAttractionEfficiency = 0.9f;
375 m_verticalAttractionTimescale = 2;
376 // m_bankingEfficiency = 1;
377 // m_bankingMix = 0.7f;
378 // m_bankingTimescale = 2;
379 // m_referenceFrame = Quaternion.Identity;
380 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
381 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
382 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
383 break;
384 case Vehicle.TYPE_BALLOON:
385 m_linearFrictionTimescale = new Vector3(5, 5, 5);
386 m_angularFrictionTimescale = new Vector3(10, 10, 10);
387 m_linearMotorDirection = Vector3.Zero;
388 m_linearMotorTimescale = 5;
389 m_linearMotorDecayTimescale = 60;
390 m_angularMotorDirection = Vector3.Zero;
391 m_angularMotorTimescale = 6;
392 m_angularMotorDecayTimescale = 10;
393 m_VhoverHeight = 5;
394 m_VhoverEfficiency = 0.8f;
395 m_VhoverTimescale = 10;
396 m_VehicleBuoyancy = 1;
397 // m_linearDeflectionEfficiency = 0;
398 // m_linearDeflectionTimescale = 5;
399 // m_angularDeflectionEfficiency = 0;
400 // m_angularDeflectionTimescale = 5;
401 m_verticalAttractionEfficiency = 1;
402 m_verticalAttractionTimescale = 1000;
403 // m_bankingEfficiency = 0;
404 // m_bankingMix = 0.7f;
405 // m_bankingTimescale = 5;
406 // m_referenceFrame = Quaternion.Identity;
407 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
408 VehicleFlag.HOVER_UP_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
409 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
410 break;
411
412 }
413 }//end SetDefaultsForType
414
415 internal void Enable(IntPtr pBody, OdeScene pParentScene)
416 {
417//Console.WriteLine("Enable m_type=" + m_type + " m_VehicleBuoyancy=" + m_VehicleBuoyancy);
418 if (m_type == Vehicle.TYPE_NONE)
419 return;
420
421 m_body = pBody;
422 //KF: This used to set up the linear and angular joints
423 }
424
425 internal void Step(float pTimestep, OdeScene pParentScene)
426 {
427 if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE)
428 return;
429 frcount++; // used to limit debug comment output
430 if (frcount > 100)
431 frcount = 0;
432
433 MoveLinear(pTimestep, pParentScene);
434 MoveAngular(pTimestep);
435 }// end Step
436
437 private void MoveLinear(float pTimestep, OdeScene _pParentScene)
438 {
439 if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant
440 {
441 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
442
443 // add drive to body
444 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
445 m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector?
446
447 // This will work temporarily, but we really need to compare speed on an axis
448 // KF: Limit body velocity to applied velocity?
449 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
450 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
451 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
452 m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y;
453 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
454 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
455
456 // decay applied velocity
457 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
458 //Console.WriteLine("decay: " + decayfraction);
459 m_linearMotorDirection -= m_linearMotorDirection * decayfraction;
460 //Console.WriteLine("actual: " + m_linearMotorDirection);
461 }
462 else
463 { // requested is not significant
464 // if what remains of applied is small, zero it.
465 if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
466 m_lastLinearVelocityVector = Vector3.Zero;
467 }
468
469
470 // convert requested object velocity to world-referenced vector
471 m_dir = m_lastLinearVelocityVector;
472 d.Quaternion rot = d.BodyGetQuaternion(Body);
473 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
474 m_dir *= rotq; // apply obj rotation to velocity vector
475
476 // add Gravity andBuoyancy
477 // KF: So far I have found no good method to combine a script-requested
478 // .Z velocity and gravity. Therefore only 0g will used script-requested
479 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
480 Vector3 grav = Vector3.Zero;
481 if(m_VehicleBuoyancy < 1.0f)
482 {
483 // There is some gravity, make a gravity force vector
484 // that is applied after object velocity.
485 d.Mass objMass;
486 d.BodyGetMass(Body, out objMass);
487 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
488 grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy);
489 // Preserve the current Z velocity
490 d.Vector3 vel_now = d.BodyGetLinearVel(Body);
491 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
492 } // else its 1.0, no gravity.
493
494 // Check if hovering
495 if( (m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
496 {
497 // We should hover, get the target height
498 d.Vector3 pos = d.BodyGetPosition(Body);
499 if((m_flags & VehicleFlag.HOVER_WATER_ONLY) == VehicleFlag.HOVER_WATER_ONLY)
500 {
501 m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight;
502 }
503 else if((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) == VehicleFlag.HOVER_TERRAIN_ONLY)
504 {
505 m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
506 }
507 else if((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == VehicleFlag.HOVER_GLOBAL_HEIGHT)
508 {
509 m_VhoverTargetHeight = m_VhoverHeight;
510 }
511
512 if((m_flags & VehicleFlag.HOVER_UP_ONLY) == VehicleFlag.HOVER_UP_ONLY)
513 {
514 // If body is aready heigher, use its height as target height
515 if(pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
516 }
517
518// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
519// m_VhoverTimescale = 0f; // time to acheive height
520// pTimestep is time since last frame,in secs
521 float herr0 = pos.Z - m_VhoverTargetHeight;
522//if(frcount == 0) Console.WriteLine("herr0=" + herr0);
523 // Replace Vertical speed with correction figure if significant
524 if(Math.Abs(herr0) > 0.01f )
525 {
526 d.Mass objMass;
527 d.BodyGetMass(Body, out objMass);
528 m_dir.Z = - ( (herr0 * pTimestep * 50.0f) / m_VhoverTimescale);
529 // m_VhoverEfficiency is not yet implemented
530 }
531 else
532 {
533 m_dir.Z = 0f;
534 }
535 }
536
537 // Apply velocity
538 d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z);
539//if(frcount == 0) Console.WriteLine("Move " + Body + ":"+ m_dir.X + " " + m_dir.Y + " " + m_dir.Z);
540 // apply gravity force
541 d.BodyAddForce(Body, grav.X, grav.Y, grav.Z);
542//if(frcount == 0) Console.WriteLine("Force " + Body + ":" + grav.X + " " + grav.Y + " " + grav.Z);
543
544
545 // apply friction
546 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
547 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount;
548 } // end MoveLinear()
549
550 private void MoveAngular(float pTimestep)
551 {
552
553 // m_angularMotorDirection is the latest value from the script, and is decayed here
554 // m_angularMotorDirectionLASTSET is the latest value from the script
555 // m_lastAngularVelocityVector is what is being applied to the Body, varied up and down here
556
557 if (!m_angularMotorDirection.ApproxEquals(Vector3.Zero, 0.01f))
558 {
559 if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
560 // ramp up to new value
561 Vector3 addAmount = m_angularMotorDirection / (m_angularMotorTimescale / pTimestep);
562 m_lastAngularVelocityVector += (addAmount * 10f);
563//if(frcount == 0) Console.WriteLine("add: " + addAmount);
564
565 // limit applied value to what was set by script
566 // This will work temporarily, but we really need to compare speed on an axis
567 if (Math.Abs(m_lastAngularVelocityVector.X) > Math.Abs(m_angularMotorDirectionLASTSET.X))
568 m_lastAngularVelocityVector.X = m_angularMotorDirectionLASTSET.X;
569 if (Math.Abs(m_lastAngularVelocityVector.Y) > Math.Abs(m_angularMotorDirectionLASTSET.Y))
570 m_lastAngularVelocityVector.Y = m_angularMotorDirectionLASTSET.Y;
571 if (Math.Abs(m_lastAngularVelocityVector.Z) > Math.Abs(m_angularMotorDirectionLASTSET.Z))
572 m_lastAngularVelocityVector.Z = m_angularMotorDirectionLASTSET.Z;
573
574 // decay the requested value
575 Vector3 decayfraction = ((Vector3.One / (m_angularMotorDecayTimescale / pTimestep)));
576 //Console.WriteLine("decay: " + decayfraction);
577 m_angularMotorDirection -= m_angularMotorDirection * decayfraction;
578 //Console.WriteLine("actual: " + m_linearMotorDirection);
579 }
580 // KF: m_lastAngularVelocityVector is rotational speed in rad/sec ?
581
582 // Vertical attractor section
583
584// d.Mass objMass;
585// d.BodyGetMass(Body, out objMass);
586// float servo = 100f * objMass.mass * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep);
587 float servo = 0.1f * m_verticalAttractionEfficiency / (m_verticalAttractionTimescale * pTimestep);
588 // get present body rotation
589 d.Quaternion rot = d.BodyGetQuaternion(Body);
590 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W);
591 // make a vector pointing up
592 Vector3 verterr = Vector3.Zero;
593 verterr.Z = 1.0f;
594 // rotate it to Body Angle
595 verterr = verterr * rotq;
596 // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
597 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go
598 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
599 if (verterr.Z < 0.0f)
600 {
601 verterr.X = 2.0f - verterr.X;
602 verterr.Y = 2.0f - verterr.Y;
603 }
604 // Error is 0 (no error) to +/- 2 (max error)
605 // scale it by servo
606 verterr = verterr * servo;
607
608 // rotate to object frame
609 // verterr = verterr * rotq;
610
611 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
612 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
613 m_lastAngularVelocityVector.X += verterr.Y;
614 m_lastAngularVelocityVector.Y -= verterr.X;
615/*
616if(frcount == 0)
617 {
618// Console.WriteLine("AngleMotor " + m_lastAngularVelocityVector);
619 Console.WriteLine(String.Format("VA Body:{0} servo:{1} err:<{2},{3},{4}> VAE:{5}",
620 Body, servo, verterr.X, verterr.Y, verterr.Z, m_verticalAttractionEfficiency));
621 }
622 */
623 d.BodySetAngularVel (Body, m_lastAngularVelocityVector.X, m_lastAngularVelocityVector.Y, m_lastAngularVelocityVector.Z);
624 // apply friction
625 Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
626 m_lastAngularVelocityVector -= m_lastAngularVelocityVector * decayamount;
627
628 } //end MoveAngular
629 }
630}
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEDynamics.cs b/OpenSim/Region/Physics/OdePlugin/ODEDynamics.cs
deleted file mode 100644
index 2342bfa..0000000
--- a/OpenSim/Region/Physics/OdePlugin/ODEDynamics.cs
+++ /dev/null
@@ -1,974 +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
28/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces
29 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
30 * ODEPrim.cs contains methods dealing with Prim editing, Prim
31 * characteristics and Kinetic motion.
32 * ODEDynamics.cs contains methods dealing with Prim Physical motion
33 * (dynamics) and the associated settings. Old Linear and angular
34 * motors for dynamic motion have been replace with MoveLinear()
35 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
36 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
37 * switch between 'VEHICLE' parameter use and general dynamics
38 * settings use.
39 */
40
41using System;
42using System.Collections.Generic;
43using System.Reflection;
44using System.Runtime.InteropServices;
45using log4net;
46using OpenMetaverse;
47using Ode.NET;
48using OpenSim.Framework;
49using OpenSim.Region.Physics.Manager;
50
51namespace OpenSim.Region.Physics.OdePlugin
52{
53 public class ODEDynamics
54 {
55 public Vehicle Type
56 {
57 get { return m_type; }
58 }
59
60 public IntPtr Body
61 {
62 get { return m_body; }
63 }
64
65 private int frcount = 0; // Used to limit dynamics debug output to
66 // every 100th frame
67
68 // private OdeScene m_parentScene = null;
69 private IntPtr m_body = IntPtr.Zero;
70// private IntPtr m_jointGroup = IntPtr.Zero;
71// private IntPtr m_aMotor = IntPtr.Zero;
72
73
74 // Vehicle properties
75 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
76 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
77 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
78 // HOVER_TERRAIN_ONLY
79 // HOVER_GLOBAL_HEIGHT
80 // NO_DEFLECTION_UP
81 // HOVER_WATER_ONLY
82 // HOVER_UP_ONLY
83 // LIMIT_MOTOR_UP
84 // LIMIT_ROLL_ONLY
85 private VehicleFlag m_Hoverflags = (VehicleFlag)0;
86 private Vector3 m_BlockingEndPoint = Vector3.Zero;
87 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
88 // Linear properties
89 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
90 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
91 private Vector3 m_dir = Vector3.Zero; // velocity applied to body
92 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
93 private float m_linearMotorDecayTimescale = 0;
94 private float m_linearMotorTimescale = 0;
95 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
96 private d.Vector3 m_lastPositionVector = new d.Vector3();
97 // private bool m_LinearMotorSetLastFrame = false;
98 // private Vector3 m_linearMotorOffset = Vector3.Zero;
99
100 //Angular properties
101 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
102 private int m_angularMotorApply = 0; // application frame counter
103 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
104 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
105 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
106 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
107 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
108 // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
109
110 //Deflection properties
111 // private float m_angularDeflectionEfficiency = 0;
112 // private float m_angularDeflectionTimescale = 0;
113 // private float m_linearDeflectionEfficiency = 0;
114 // private float m_linearDeflectionTimescale = 0;
115
116 //Banking properties
117 // private float m_bankingEfficiency = 0;
118 // private float m_bankingMix = 0;
119 // private float m_bankingTimescale = 0;
120
121 //Hover and Buoyancy properties
122 private float m_VhoverHeight = 0f;
123// private float m_VhoverEfficiency = 0f;
124 private float m_VhoverTimescale = 0f;
125 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
126 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
127 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
128 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
129 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
130
131 //Attractor properties
132 private float m_verticalAttractionEfficiency = 1.0f; // damped
133 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
134
135 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
136 {
137 switch (pParam)
138 {
139 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
140 if (pValue < 0.01f) pValue = 0.01f;
141 // m_angularDeflectionEfficiency = pValue;
142 break;
143 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
144 if (pValue < 0.01f) pValue = 0.01f;
145 // m_angularDeflectionTimescale = pValue;
146 break;
147 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
148 if (pValue < 0.01f) pValue = 0.01f;
149 m_angularMotorDecayTimescale = pValue;
150 break;
151 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
152 if (pValue < 0.01f) pValue = 0.01f;
153 m_angularMotorTimescale = pValue;
154 break;
155 case Vehicle.BANKING_EFFICIENCY:
156 if (pValue < 0.01f) pValue = 0.01f;
157 // m_bankingEfficiency = pValue;
158 break;
159 case Vehicle.BANKING_MIX:
160 if (pValue < 0.01f) pValue = 0.01f;
161 // m_bankingMix = pValue;
162 break;
163 case Vehicle.BANKING_TIMESCALE:
164 if (pValue < 0.01f) pValue = 0.01f;
165 // m_bankingTimescale = pValue;
166 break;
167 case Vehicle.BUOYANCY:
168 if (pValue < -1f) pValue = -1f;
169 if (pValue > 1f) pValue = 1f;
170 m_VehicleBuoyancy = pValue;
171 break;
172// case Vehicle.HOVER_EFFICIENCY:
173// if (pValue < 0f) pValue = 0f;
174// if (pValue > 1f) pValue = 1f;
175// m_VhoverEfficiency = pValue;
176// break;
177 case Vehicle.HOVER_HEIGHT:
178 m_VhoverHeight = pValue;
179 break;
180 case Vehicle.HOVER_TIMESCALE:
181 if (pValue < 0.01f) pValue = 0.01f;
182 m_VhoverTimescale = pValue;
183 break;
184 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
185 if (pValue < 0.01f) pValue = 0.01f;
186 // m_linearDeflectionEfficiency = pValue;
187 break;
188 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
189 if (pValue < 0.01f) pValue = 0.01f;
190 // m_linearDeflectionTimescale = pValue;
191 break;
192 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
193 if (pValue < 0.01f) pValue = 0.01f;
194 m_linearMotorDecayTimescale = pValue;
195 break;
196 case Vehicle.LINEAR_MOTOR_TIMESCALE:
197 if (pValue < 0.01f) pValue = 0.01f;
198 m_linearMotorTimescale = pValue;
199 break;
200 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
201 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
202 if (pValue > 1.0f) pValue = 1.0f;
203 m_verticalAttractionEfficiency = pValue;
204 break;
205 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
206 if (pValue < 0.01f) pValue = 0.01f;
207 m_verticalAttractionTimescale = pValue;
208 break;
209
210 // These are vector properties but the engine lets you use a single float value to
211 // set all of the components to the same value
212 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
213 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
214 break;
215 case Vehicle.ANGULAR_MOTOR_DIRECTION:
216 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
217 m_angularMotorApply = 10;
218 break;
219 case Vehicle.LINEAR_FRICTION_TIMESCALE:
220 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
221 break;
222 case Vehicle.LINEAR_MOTOR_DIRECTION:
223 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
224 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
225 break;
226 case Vehicle.LINEAR_MOTOR_OFFSET:
227 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
228 break;
229
230 }
231 }//end ProcessFloatVehicleParam
232
233 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
234 {
235 switch (pParam)
236 {
237 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
238 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
239 break;
240 case Vehicle.ANGULAR_MOTOR_DIRECTION:
241 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
242 // Limit requested angular speed to 2 rps= 4 pi rads/sec
243 if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
244 if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
245 if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
246 if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
247 if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
248 if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
249 m_angularMotorApply = 10;
250 break;
251 case Vehicle.LINEAR_FRICTION_TIMESCALE:
252 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
253 break;
254 case Vehicle.LINEAR_MOTOR_DIRECTION:
255 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
256 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
257 break;
258 case Vehicle.LINEAR_MOTOR_OFFSET:
259 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
260 break;
261 case Vehicle.BLOCK_EXIT:
262 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
263 break;
264 }
265 }//end ProcessVectorVehicleParam
266
267 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
268 {
269 switch (pParam)
270 {
271 case Vehicle.REFERENCE_FRAME:
272 // m_referenceFrame = pValue;
273 break;
274 case Vehicle.ROLL_FRAME:
275 m_RollreferenceFrame = pValue;
276 break;
277 }
278 }//end ProcessRotationVehicleParam
279
280 internal void ProcessVehicleFlags(int pParam, bool remove)
281 {
282 if (remove)
283 {
284 if (pParam == -1)
285 {
286 m_flags = (VehicleFlag)0;
287 m_Hoverflags = (VehicleFlag)0;
288 return;
289 }
290 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
291 {
292 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0)
293 m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT);
294 }
295 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
296 {
297 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0)
298 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY);
299 }
300 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
301 {
302 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0)
303 m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY);
304 }
305 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
306 {
307 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0)
308 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY);
309 }
310 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
311 {
312 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0)
313 m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP);
314 }
315 if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY)
316 {
317 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0)
318 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
319 }
320 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
321 {
322 if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0)
323 m_flags &= ~(VehicleFlag.MOUSELOOK_BANK);
324 }
325 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
326 {
327 if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0)
328 m_flags &= ~(VehicleFlag.MOUSELOOK_STEER);
329 }
330 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
331 {
332 if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0)
333 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP);
334 }
335 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
336 {
337 if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0)
338 m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED);
339 }
340 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
341 {
342 if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0)
343 m_flags &= ~(VehicleFlag.NO_X);
344 }
345 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
346 {
347 if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0)
348 m_flags &= ~(VehicleFlag.NO_Y);
349 }
350 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
351 {
352 if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0)
353 m_flags &= ~(VehicleFlag.NO_Z);
354 }
355 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
356 {
357 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0)
358 m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT);
359 }
360 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
361 {
362 if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0)
363 m_flags &= ~(VehicleFlag.NO_DEFLECTION);
364 }
365 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
366 {
367 if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0)
368 m_flags &= ~(VehicleFlag.LOCK_ROTATION);
369 }
370 }
371 else
372 {
373 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
374 {
375 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags);
376 }
377 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
378 {
379 m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags);
380 }
381 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
382 {
383 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags);
384 }
385 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
386 {
387 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags);
388 }
389 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
390 {
391 m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags);
392 }
393 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
394 {
395 m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags);
396 }
397 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
398 {
399 m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags);
400 }
401 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
402 {
403 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags);
404 }
405 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
406 {
407 m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags);
408 }
409 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
410 {
411 m_flags |= (VehicleFlag.NO_X);
412 }
413 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
414 {
415 m_flags |= (VehicleFlag.NO_Y);
416 }
417 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
418 {
419 m_flags |= (VehicleFlag.NO_Z);
420 }
421 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
422 {
423 m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT);
424 }
425 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
426 {
427 m_flags |= (VehicleFlag.NO_DEFLECTION);
428 }
429 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
430 {
431 m_flags |= (VehicleFlag.LOCK_ROTATION);
432 }
433 }
434 }//end ProcessVehicleFlags
435
436 internal void ProcessTypeChange(Vehicle pType)
437 {
438 // Set Defaults For Type
439 m_type = pType;
440 switch (pType)
441 {
442 case Vehicle.TYPE_NONE:
443 m_linearFrictionTimescale = new Vector3(0, 0, 0);
444 m_angularFrictionTimescale = new Vector3(0, 0, 0);
445 m_linearMotorDirection = Vector3.Zero;
446 m_linearMotorTimescale = 0;
447 m_linearMotorDecayTimescale = 0;
448 m_angularMotorDirection = Vector3.Zero;
449 m_angularMotorTimescale = 0;
450 m_angularMotorDecayTimescale = 0;
451 m_VhoverHeight = 0;
452 m_VhoverTimescale = 0;
453 m_VehicleBuoyancy = 0;
454 m_flags = (VehicleFlag)0;
455 break;
456
457 case Vehicle.TYPE_SLED:
458 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
459 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
460 m_linearMotorDirection = Vector3.Zero;
461 m_linearMotorTimescale = 1000;
462 m_linearMotorDecayTimescale = 120;
463 m_angularMotorDirection = Vector3.Zero;
464 m_angularMotorTimescale = 1000;
465 m_angularMotorDecayTimescale = 120;
466 m_VhoverHeight = 0;
467// m_VhoverEfficiency = 1;
468 m_VhoverTimescale = 10;
469 m_VehicleBuoyancy = 0;
470 // m_linearDeflectionEfficiency = 1;
471 // m_linearDeflectionTimescale = 1;
472 // m_angularDeflectionEfficiency = 1;
473 // m_angularDeflectionTimescale = 1000;
474 // m_bankingEfficiency = 0;
475 // m_bankingMix = 1;
476 // m_bankingTimescale = 10;
477 // m_referenceFrame = Quaternion.Identity;
478 m_Hoverflags &=
479 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
480 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
481 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
482 break;
483 case Vehicle.TYPE_CAR:
484 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
485 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
486 m_linearMotorDirection = Vector3.Zero;
487 m_linearMotorTimescale = 1;
488 m_linearMotorDecayTimescale = 60;
489 m_angularMotorDirection = Vector3.Zero;
490 m_angularMotorTimescale = 1;
491 m_angularMotorDecayTimescale = 0.8f;
492 m_VhoverHeight = 0;
493// m_VhoverEfficiency = 0;
494 m_VhoverTimescale = 1000;
495 m_VehicleBuoyancy = 0;
496 // // m_linearDeflectionEfficiency = 1;
497 // // m_linearDeflectionTimescale = 2;
498 // // m_angularDeflectionEfficiency = 0;
499 // m_angularDeflectionTimescale = 10;
500 m_verticalAttractionEfficiency = 1f;
501 m_verticalAttractionTimescale = 10f;
502 // m_bankingEfficiency = -0.2f;
503 // m_bankingMix = 1;
504 // m_bankingTimescale = 1;
505 // m_referenceFrame = Quaternion.Identity;
506 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
507 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY |
508 VehicleFlag.LIMIT_MOTOR_UP);
509 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY);
510 break;
511 case Vehicle.TYPE_BOAT:
512 m_linearFrictionTimescale = new Vector3(10, 3, 2);
513 m_angularFrictionTimescale = new Vector3(10,10,10);
514 m_linearMotorDirection = Vector3.Zero;
515 m_linearMotorTimescale = 5;
516 m_linearMotorDecayTimescale = 60;
517 m_angularMotorDirection = Vector3.Zero;
518 m_angularMotorTimescale = 4;
519 m_angularMotorDecayTimescale = 4;
520 m_VhoverHeight = 0;
521// m_VhoverEfficiency = 0.5f;
522 m_VhoverTimescale = 2;
523 m_VehicleBuoyancy = 1;
524 // m_linearDeflectionEfficiency = 0.5f;
525 // m_linearDeflectionTimescale = 3;
526 // m_angularDeflectionEfficiency = 0.5f;
527 // m_angularDeflectionTimescale = 5;
528 m_verticalAttractionEfficiency = 0.5f;
529 m_verticalAttractionTimescale = 5f;
530 // m_bankingEfficiency = -0.3f;
531 // m_bankingMix = 0.8f;
532 // m_bankingTimescale = 1;
533 // m_referenceFrame = Quaternion.Identity;
534 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
535 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
536 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
537 m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
538 VehicleFlag.LIMIT_MOTOR_UP);
539 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY);
540 break;
541 case Vehicle.TYPE_AIRPLANE:
542 m_linearFrictionTimescale = new Vector3(200, 10, 5);
543 m_angularFrictionTimescale = new Vector3(20, 20, 20);
544 m_linearMotorDirection = Vector3.Zero;
545 m_linearMotorTimescale = 2;
546 m_linearMotorDecayTimescale = 60;
547 m_angularMotorDirection = Vector3.Zero;
548 m_angularMotorTimescale = 4;
549 m_angularMotorDecayTimescale = 4;
550 m_VhoverHeight = 0;
551// m_VhoverEfficiency = 0.5f;
552 m_VhoverTimescale = 1000;
553 m_VehicleBuoyancy = 0;
554 // m_linearDeflectionEfficiency = 0.5f;
555 // m_linearDeflectionTimescale = 3;
556 // m_angularDeflectionEfficiency = 1;
557 // m_angularDeflectionTimescale = 2;
558 m_verticalAttractionEfficiency = 0.9f;
559 m_verticalAttractionTimescale = 2f;
560 // m_bankingEfficiency = 1;
561 // m_bankingMix = 0.7f;
562 // m_bankingTimescale = 2;
563 // m_referenceFrame = Quaternion.Identity;
564 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
565 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
566 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
567 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
568 break;
569 case Vehicle.TYPE_BALLOON:
570 m_linearFrictionTimescale = new Vector3(5, 5, 5);
571 m_angularFrictionTimescale = new Vector3(10, 10, 10);
572 m_linearMotorDirection = Vector3.Zero;
573 m_linearMotorTimescale = 5;
574 m_linearMotorDecayTimescale = 60;
575 m_angularMotorDirection = Vector3.Zero;
576 m_angularMotorTimescale = 6;
577 m_angularMotorDecayTimescale = 10;
578 m_VhoverHeight = 5;
579// m_VhoverEfficiency = 0.8f;
580 m_VhoverTimescale = 10;
581 m_VehicleBuoyancy = 1;
582 // m_linearDeflectionEfficiency = 0;
583 // m_linearDeflectionTimescale = 5;
584 // m_angularDeflectionEfficiency = 0;
585 // m_angularDeflectionTimescale = 5;
586 m_verticalAttractionEfficiency = 1f;
587 m_verticalAttractionTimescale = 100f;
588 // m_bankingEfficiency = 0;
589 // m_bankingMix = 0.7f;
590 // m_bankingTimescale = 5;
591 // m_referenceFrame = Quaternion.Identity;
592 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
593 VehicleFlag.HOVER_UP_ONLY);
594 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
595 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
596 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT);
597 break;
598
599 }
600 }//end SetDefaultsForType
601
602 internal void Enable(IntPtr pBody, OdeScene pParentScene)
603 {
604 if (m_type == Vehicle.TYPE_NONE)
605 return;
606
607 m_body = pBody;
608 }
609
610 internal void Step(float pTimestep, OdeScene pParentScene)
611 {
612 if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE)
613 return;
614 frcount++; // used to limit debug comment output
615 if (frcount > 100)
616 frcount = 0;
617
618 MoveLinear(pTimestep, pParentScene);
619 MoveAngular(pTimestep);
620 LimitRotation(pTimestep);
621 }// end Step
622
623 private void MoveLinear(float pTimestep, OdeScene _pParentScene)
624 {
625 if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant
626 {
627 if (!d.BodyIsEnabled(Body))
628 d.BodyEnable(Body);
629
630 // add drive to body
631 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
632 m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector?
633
634 // This will work temporarily, but we really need to compare speed on an axis
635 // KF: Limit body velocity to applied velocity?
636 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
637 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
638 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
639 m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y;
640 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
641 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
642
643 // decay applied velocity
644 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
645 //Console.WriteLine("decay: " + decayfraction);
646 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
647 //Console.WriteLine("actual: " + m_linearMotorDirection);
648 }
649 else
650 { // requested is not significant
651 // if what remains of applied is small, zero it.
652 if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
653 m_lastLinearVelocityVector = Vector3.Zero;
654 }
655
656 // convert requested object velocity to world-referenced vector
657 m_dir = m_lastLinearVelocityVector;
658 d.Quaternion rot = d.BodyGetQuaternion(Body);
659 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
660 m_dir *= rotq; // apply obj rotation to velocity vector
661
662 // add Gravity andBuoyancy
663 // KF: So far I have found no good method to combine a script-requested
664 // .Z velocity and gravity. Therefore only 0g will used script-requested
665 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
666 Vector3 grav = Vector3.Zero;
667 // There is some gravity, make a gravity force vector
668 // that is applied after object velocity.
669 d.Mass objMass;
670 d.BodyGetMass(Body, out objMass);
671 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
672 grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy);
673 // Preserve the current Z velocity
674 d.Vector3 vel_now = d.BodyGetLinearVel(Body);
675 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
676
677 d.Vector3 pos = d.BodyGetPosition(Body);
678// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
679 Vector3 posChange = new Vector3();
680 posChange.X = pos.X - m_lastPositionVector.X;
681 posChange.Y = pos.Y - m_lastPositionVector.Y;
682 posChange.Z = pos.Z - m_lastPositionVector.Z;
683 double Zchange = Math.Abs(posChange.Z);
684 if (m_BlockingEndPoint != Vector3.Zero)
685 {
686 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
687 {
688 pos.X -= posChange.X + 1;
689 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
690 }
691 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
692 {
693 pos.Y -= posChange.Y + 1;
694 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
695 }
696 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
697 {
698 pos.Z -= posChange.Z + 1;
699 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
700 }
701 if (pos.X <= 0)
702 {
703 pos.X += posChange.X + 1;
704 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
705 }
706 if (pos.Y <= 0)
707 {
708 pos.Y += posChange.Y + 1;
709 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
710 }
711 }
712 if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y))
713 {
714 pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2;
715 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
716 }
717
718 // Check if hovering
719 if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
720 {
721 // We should hover, get the target height
722 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0)
723 {
724 m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight;
725 }
726 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
727 {
728 m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
729 }
730 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
731 {
732 m_VhoverTargetHeight = m_VhoverHeight;
733 }
734
735 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0)
736 {
737 // If body is aready heigher, use its height as target height
738 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
739 }
740 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
741 {
742 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
743 {
744 d.BodySetPosition(Body, pos.X, pos.Y, m_VhoverTargetHeight);
745 }
746 }
747 else
748 {
749 float herr0 = pos.Z - m_VhoverTargetHeight;
750 // Replace Vertical speed with correction figure if significant
751 if (Math.Abs(herr0) > 0.01f)
752 {
753 m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale);
754 //KF: m_VhoverEfficiency is not yet implemented
755 }
756 else
757 {
758 m_dir.Z = 0f;
759 }
760 }
761
762// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
763// m_VhoverTimescale = 0f; // time to acheive height
764// pTimestep is time since last frame,in secs
765 }
766
767 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
768 {
769 //Start Experimental Values
770 if (Zchange > .3)
771 {
772 grav.Z = (float)(grav.Z * 3);
773 }
774 if (Zchange > .15)
775 {
776 grav.Z = (float)(grav.Z * 2);
777 }
778 if (Zchange > .75)
779 {
780 grav.Z = (float)(grav.Z * 1.5);
781 }
782 if (Zchange > .05)
783 {
784 grav.Z = (float)(grav.Z * 1.25);
785 }
786 if (Zchange > .025)
787 {
788 grav.Z = (float)(grav.Z * 1.125);
789 }
790 float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y);
791 float postemp = (pos.Z - terraintemp);
792 if (postemp > 2.5f)
793 {
794 grav.Z = (float)(grav.Z * 1.037125);
795 }
796 //End Experimental Values
797 }
798 if ((m_flags & (VehicleFlag.NO_X)) != 0)
799 {
800 m_dir.X = 0;
801 }
802 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
803 {
804 m_dir.Y = 0;
805 }
806 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
807 {
808 m_dir.Z = 0;
809 }
810
811 m_lastPositionVector = d.BodyGetPosition(Body);
812
813 // Apply velocity
814 d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z);
815 // apply gravity force
816 d.BodyAddForce(Body, grav.X, grav.Y, grav.Z);
817
818
819 // apply friction
820 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
821 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount;
822 } // end MoveLinear()
823
824 private void MoveAngular(float pTimestep)
825 {
826 /*
827 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
828 private int m_angularMotorApply = 0; // application frame counter
829 private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down)
830 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
831 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
832 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
833 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
834 */
835
836 // Get what the body is doing, this includes 'external' influences
837 d.Vector3 angularVelocity = d.BodyGetAngularVel(Body);
838 // Vector3 angularVelocity = Vector3.Zero;
839
840 if (m_angularMotorApply > 0)
841 {
842 // ramp up to new value
843 // current velocity += error / (time to get there / step interval)
844 // requested speed - last motor speed
845 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep);
846 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
847 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
848
849 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected
850 // velocity may still be acheived.
851 }
852 else
853 {
854 // no motor recently applied, keep the body velocity
855 /* m_angularMotorVelocity.X = angularVelocity.X;
856 m_angularMotorVelocity.Y = angularVelocity.Y;
857 m_angularMotorVelocity.Z = angularVelocity.Z; */
858
859 // and decay the velocity
860 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
861 } // end motor section
862
863 // Vertical attractor section
864 Vector3 vertattr = Vector3.Zero;
865
866 if (m_verticalAttractionTimescale < 300)
867 {
868 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep);
869 // get present body rotation
870 d.Quaternion rot = d.BodyGetQuaternion(Body);
871 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W);
872 // make a vector pointing up
873 Vector3 verterr = Vector3.Zero;
874 verterr.Z = 1.0f;
875 // rotate it to Body Angle
876 verterr = verterr * rotq;
877 // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
878 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go
879 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
880 if (verterr.Z < 0.0f)
881 {
882 verterr.X = 2.0f - verterr.X;
883 verterr.Y = 2.0f - verterr.Y;
884 }
885 // Error is 0 (no error) to +/- 2 (max error)
886 // scale it by VAservo
887 verterr = verterr * VAservo;
888//if (frcount == 0) Console.WriteLine("VAerr=" + verterr);
889
890 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
891 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
892 vertattr.X = verterr.Y;
893 vertattr.Y = - verterr.X;
894 vertattr.Z = 0f;
895
896 // scaling appears better usingsquare-law
897 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
898 vertattr.X += bounce * angularVelocity.X;
899 vertattr.Y += bounce * angularVelocity.Y;
900
901 } // else vertical attractor is off
902
903 // m_lastVertAttractor = vertattr;
904
905 // Bank section tba
906 // Deflection section tba
907
908 // Sum velocities
909 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
910
911 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
912 {
913 m_lastAngularVelocity.X = 0;
914 m_lastAngularVelocity.Y = 0;
915 }
916
917 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
918 {
919 if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
920 }
921 else
922 {
923 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
924 }
925
926 // apply friction
927 Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
928 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
929
930 // Apply to the body
931 d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z);
932
933 } //end MoveAngular
934 internal void LimitRotation(float timestep)
935 {
936 d.Quaternion rot = d.BodyGetQuaternion(Body);
937 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
938 d.Quaternion m_rot = new d.Quaternion();
939 bool changed = false;
940 m_rot.X = rotq.X;
941 m_rot.Y = rotq.Y;
942 m_rot.Z = rotq.Z;
943 m_rot.W = rotq.W;
944 if (m_RollreferenceFrame != Quaternion.Identity)
945 {
946 if (rotq.X >= m_RollreferenceFrame.X)
947 {
948 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
949 }
950 if (rotq.Y >= m_RollreferenceFrame.Y)
951 {
952 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
953 }
954 if (rotq.X <= -m_RollreferenceFrame.X)
955 {
956 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
957 }
958 if (rotq.Y <= -m_RollreferenceFrame.Y)
959 {
960 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
961 }
962 changed = true;
963 }
964 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
965 {
966 m_rot.X = 0;
967 m_rot.Y = 0;
968 changed = true;
969 }
970 if (changed)
971 d.BodySetQuaternion(Body, ref m_rot);
972 }
973 }
974}
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
deleted file mode 100644
index 0d66496..0000000
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ /dev/null
@@ -1,3380 +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
28/*
29 * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces
30 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
31 * ODEPrim.cs contains methods dealing with Prim editing, Prim
32 * characteristics and Kinetic motion.
33 * ODEDynamics.cs contains methods dealing with Prim Physical motion
34 * (dynamics) and the associated settings. Old Linear and angular
35 * motors for dynamic motion have been replace with MoveLinear()
36 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
37 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
38 * switch between 'VEHICLE' parameter use and general dynamics
39 * settings use.
40 */
41
42//#define SPAM
43
44using System;
45using System.Collections.Generic;
46using System.Reflection;
47using System.Runtime.InteropServices;
48using System.Threading;
49using log4net;
50using OpenMetaverse;
51using Ode.NET;
52using OpenSim.Framework;
53using OpenSim.Region.Physics.Manager;
54
55namespace OpenSim.Region.Physics.OdePlugin
56{
57 /// <summary>
58 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
59 /// </summary>
60 public class OdePrim : PhysicsActor
61 {
62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63
64 private bool m_isphysical;
65
66 public int ExpectedCollisionContacts { get { return m_expectedCollisionContacts; } }
67 private int m_expectedCollisionContacts = 0;
68
69 /// <summary>
70 /// Gets collide bits so that we can still perform land collisions if a mesh fails to load.
71 /// </summary>
72 private int BadMeshAssetCollideBits
73 {
74 get { return m_isphysical ? (int)CollisionCategories.Land : 0; }
75 }
76
77 /// <summary>
78 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
79 /// </summary>
80 public override bool IsPhysical
81 {
82 get { return m_isphysical; }
83 set
84 {
85 m_isphysical = value;
86 if (!m_isphysical) // Zero the remembered last velocity
87 m_lastVelocity = Vector3.Zero;
88 }
89 }
90
91 private Vector3 _position;
92 private Vector3 _velocity;
93 private Vector3 _torque;
94 private Vector3 m_lastVelocity;
95 private Vector3 m_lastposition;
96 private Quaternion m_lastorientation = new Quaternion();
97 private Vector3 m_rotationalVelocity;
98 private Vector3 _size;
99 private Vector3 _acceleration;
100 // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f);
101 private Quaternion _orientation;
102 private Vector3 m_taintposition;
103 private Vector3 m_taintsize;
104 private Vector3 m_taintVelocity;
105 private Vector3 m_taintTorque;
106 private Quaternion m_taintrot;
107 private Vector3 m_angularlock = Vector3.One;
108 private Vector3 m_taintAngularLock = Vector3.One;
109 private IntPtr Amotor = IntPtr.Zero;
110
111 private object m_assetsLock = new object();
112 private bool m_assetFailed = false;
113
114 private Vector3 m_PIDTarget;
115 private float m_PIDTau;
116 private float PID_D = 35f;
117 private float PID_G = 25f;
118 private bool m_usePID;
119
120 // KF: These next 7 params apply to llSetHoverHeight(float height, integer water, float tau),
121 // and are for non-VEHICLES only.
122
123 private float m_PIDHoverHeight;
124 private float m_PIDHoverTau;
125 private bool m_useHoverPID;
126 private PIDHoverType m_PIDHoverType = PIDHoverType.Ground;
127 private float m_targetHoverHeight;
128 private float m_groundHeight;
129 private float m_waterHeight;
130 private float m_buoyancy; //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle.
131
132 // private float m_tensor = 5f;
133 private int body_autodisable_frames = 20;
134
135
136 private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom
137 | CollisionCategories.Space
138 | CollisionCategories.Body
139 | CollisionCategories.Character
140 );
141 private bool m_taintshape;
142 private bool m_taintPhysics;
143 private bool m_collidesLand = true;
144 private bool m_collidesWater;
145
146 // Default we're a Geometry
147 private CollisionCategories m_collisionCategories = (CollisionCategories.Geom);
148
149 // Default, Collide with Other Geometries, spaces and Bodies
150 private CollisionCategories m_collisionFlags = m_default_collisionFlags;
151
152 public bool m_taintremove { get; private set; }
153 public bool m_taintdisable { get; private set; }
154 internal bool m_disabled;
155 public bool m_taintadd { get; private set; }
156 public bool m_taintselected { get; private set; }
157 public bool m_taintCollidesWater { get; private set; }
158
159 private bool m_taintforce = false;
160 private bool m_taintaddangularforce = false;
161 private Vector3 m_force;
162 private List<Vector3> m_forcelist = new List<Vector3>();
163 private List<Vector3> m_angularforcelist = new List<Vector3>();
164
165 private PrimitiveBaseShape _pbs;
166 private OdeScene _parent_scene;
167
168 /// <summary>
169 /// The physics space which contains prim geometries
170 /// </summary>
171 public IntPtr m_targetSpace = IntPtr.Zero;
172
173 /// <summary>
174 /// The prim geometry, used for collision detection.
175 /// </summary>
176 /// <remarks>
177 /// This is never null except for a brief period when the geometry needs to be replaced (due to resizing or
178 /// mesh change) or when the physical prim is being removed from the scene.
179 /// </remarks>
180 public IntPtr prim_geom { get; private set; }
181
182 public IntPtr _triMeshData { get; private set; }
183
184 private IntPtr _linkJointGroup = IntPtr.Zero;
185 private PhysicsActor _parent;
186 private PhysicsActor m_taintparent;
187
188 private List<OdePrim> childrenPrim = new List<OdePrim>();
189
190 private bool iscolliding;
191 private bool m_isSelected;
192
193 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively
194
195 private bool m_throttleUpdates;
196 private int throttleCounter;
197 public int m_interpenetrationcount { get; private set; }
198 internal float m_collisionscore;
199 public int m_roundsUnderMotionThreshold { get; private set; }
200 private int m_crossingfailures;
201
202 public bool outofBounds { get; private set; }
203 private float m_density = 10.000006836f; // Aluminum g/cm3;
204
205 public bool _zeroFlag { get; private set; }
206 private bool m_lastUpdateSent;
207
208 public IntPtr Body = IntPtr.Zero;
209 private Vector3 _target_velocity;
210 private d.Mass pMass;
211
212 private int m_eventsubscription;
213 private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
214
215 /// <summary>
216 /// Signal whether there were collisions on the previous frame, so we know if we need to send the
217 /// empty CollisionEventsThisFrame to the prim so that it can detect the end of a collision.
218 /// </summary>
219 /// <remarks>
220 /// This is probably a temporary measure, pending storing this information consistently in CollisionEventUpdate itself.
221 /// </remarks>
222 private bool m_collisionsOnPreviousFrame;
223
224 private IntPtr m_linkJoint = IntPtr.Zero;
225
226 internal volatile bool childPrim;
227
228 private ODEDynamics m_vehicle;
229
230 internal int m_material = (int)Material.Wood;
231
232 public OdePrim(
233 String primName, OdeScene parent_scene, Vector3 pos, Vector3 size,
234 Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
235 {
236 Name = primName;
237 m_vehicle = new ODEDynamics();
238 //gc = GCHandle.Alloc(prim_geom, GCHandleType.Pinned);
239
240 if (!pos.IsFinite())
241 {
242 pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f),
243 parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f);
244 m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Position for {0}", Name);
245 }
246 _position = pos;
247 m_taintposition = pos;
248 PID_D = parent_scene.bodyPIDD;
249 PID_G = parent_scene.bodyPIDG;
250 m_density = parent_scene.geomDefaultDensity;
251 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
252 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
253
254 prim_geom = IntPtr.Zero;
255
256 if (!pos.IsFinite())
257 {
258 size = new Vector3(0.5f, 0.5f, 0.5f);
259 m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Size for {0}", Name);
260 }
261
262 if (size.X <= 0) size.X = 0.01f;
263 if (size.Y <= 0) size.Y = 0.01f;
264 if (size.Z <= 0) size.Z = 0.01f;
265
266 _size = size;
267 m_taintsize = _size;
268
269 if (!QuaternionIsFinite(rotation))
270 {
271 rotation = Quaternion.Identity;
272 m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Rotation for {0}", Name);
273 }
274
275 _orientation = rotation;
276 m_taintrot = _orientation;
277 _pbs = pbs;
278
279 _parent_scene = parent_scene;
280 m_targetSpace = (IntPtr)0;
281
282 if (pos.Z < 0)
283 {
284 IsPhysical = false;
285 }
286 else
287 {
288 IsPhysical = pisPhysical;
289 // If we're physical, we need to be in the master space for now.
290 // linksets *should* be in a space together.. but are not currently
291 if (IsPhysical)
292 m_targetSpace = _parent_scene.space;
293 }
294
295 m_taintadd = true;
296 m_assetFailed = false;
297 _parent_scene.AddPhysicsActorTaint(this);
298 }
299
300 public override int PhysicsActorType
301 {
302 get { return (int) ActorTypes.Prim; }
303 set { return; }
304 }
305
306 public override bool SetAlwaysRun
307 {
308 get { return false; }
309 set { return; }
310 }
311
312 public override bool Grabbed
313 {
314 set { return; }
315 }
316
317 public override bool Selected
318 {
319 set
320 {
321 // This only makes the object not collidable if the object
322 // is physical or the object is modified somehow *IN THE FUTURE*
323 // without this, if an avatar selects prim, they can walk right
324 // through it while it's selected
325 m_collisionscore = 0;
326
327 if ((IsPhysical && !_zeroFlag) || !value)
328 {
329 m_taintselected = value;
330 _parent_scene.AddPhysicsActorTaint(this);
331 }
332 else
333 {
334 m_taintselected = value;
335 m_isSelected = value;
336 }
337
338 if (m_isSelected)
339 disableBodySoft();
340 }
341 }
342
343 /// <summary>
344 /// Set a new geometry for this prim.
345 /// </summary>
346 /// <param name="geom"></param>
347 private void SetGeom(IntPtr geom)
348 {
349 prim_geom = geom;
350//Console.WriteLine("SetGeom to " + prim_geom + " for " + Name);
351
352 if (m_assetFailed)
353 {
354 d.GeomSetCategoryBits(prim_geom, 0);
355 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
356 }
357 else
358 {
359 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
360 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
361 }
362
363 _parent_scene.geom_name_map[prim_geom] = Name;
364 _parent_scene.actor_name_map[prim_geom] = this;
365
366 if (childPrim)
367 {
368 if (_parent != null && _parent is OdePrim)
369 {
370 OdePrim parent = (OdePrim)_parent;
371//Console.WriteLine("SetGeom calls ChildSetGeom");
372 parent.ChildSetGeom(this);
373 }
374 }
375 //m_log.Warn("Setting Geom to: " + prim_geom);
376 }
377
378 private void enableBodySoft()
379 {
380 if (!childPrim)
381 {
382 if (IsPhysical && Body != IntPtr.Zero)
383 {
384 d.BodyEnable(Body);
385 if (m_vehicle.Type != Vehicle.TYPE_NONE)
386 m_vehicle.Enable(Body, _parent_scene);
387 }
388
389 m_disabled = false;
390 }
391 }
392
393 private void disableBodySoft()
394 {
395 m_disabled = true;
396
397 if (IsPhysical && Body != IntPtr.Zero)
398 {
399 d.BodyDisable(Body);
400 }
401 }
402
403 /// <summary>
404 /// Make a prim subject to physics.
405 /// </summary>
406 private void enableBody()
407 {
408 // Don't enable this body if we're a child prim
409 // this should be taken care of in the parent function not here
410 if (!childPrim)
411 {
412 // Sets the geom to a body
413 Body = d.BodyCreate(_parent_scene.world);
414
415 setMass();
416 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
417 d.Quaternion myrot = new d.Quaternion();
418 myrot.X = _orientation.X;
419 myrot.Y = _orientation.Y;
420 myrot.Z = _orientation.Z;
421 myrot.W = _orientation.W;
422 d.BodySetQuaternion(Body, ref myrot);
423 d.GeomSetBody(prim_geom, Body);
424
425 if (m_assetFailed)
426 {
427 d.GeomSetCategoryBits(prim_geom, 0);
428 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
429 }
430 else
431 {
432 m_collisionCategories |= CollisionCategories.Body;
433 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
434 }
435
436 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
437 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
438
439 d.BodySetAutoDisableFlag(Body, true);
440 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
441
442 // disconnect from world gravity so we can apply buoyancy
443 d.BodySetGravityMode (Body, false);
444
445 m_interpenetrationcount = 0;
446 m_collisionscore = 0;
447 m_disabled = false;
448
449 // The body doesn't already have a finite rotation mode set here
450 if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0.0f)) && _parent == null)
451 {
452 createAMotor(m_angularlock);
453 }
454 if (m_vehicle.Type != Vehicle.TYPE_NONE)
455 {
456 m_vehicle.Enable(Body, _parent_scene);
457 }
458
459 _parent_scene.ActivatePrim(this);
460 }
461 }
462
463 #region Mass Calculation
464
465 private float CalculateMass()
466 {
467 float volume = _size.X * _size.Y * _size.Z; // default
468 float tmp;
469
470 float returnMass = 0;
471 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
472 float hollowVolume = hollowAmount * hollowAmount;
473
474 switch (_pbs.ProfileShape)
475 {
476 case ProfileShape.Square:
477 // default box
478
479 if (_pbs.PathCurve == (byte)Extrusion.Straight)
480 {
481 if (hollowAmount > 0.0)
482 {
483 switch (_pbs.HollowShape)
484 {
485 case HollowShape.Square:
486 case HollowShape.Same:
487 break;
488
489 case HollowShape.Circle:
490
491 hollowVolume *= 0.78539816339f;
492 break;
493
494 case HollowShape.Triangle:
495
496 hollowVolume *= (0.5f * .5f);
497 break;
498
499 default:
500 hollowVolume = 0;
501 break;
502 }
503 volume *= (1.0f - hollowVolume);
504 }
505 }
506
507 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
508 {
509 //a tube
510
511 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
512 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
513 volume -= volume*tmp*tmp;
514
515 if (hollowAmount > 0.0)
516 {
517 hollowVolume *= hollowAmount;
518
519 switch (_pbs.HollowShape)
520 {
521 case HollowShape.Square:
522 case HollowShape.Same:
523 break;
524
525 case HollowShape.Circle:
526 hollowVolume *= 0.78539816339f;;
527 break;
528
529 case HollowShape.Triangle:
530 hollowVolume *= 0.5f * 0.5f;
531 break;
532 default:
533 hollowVolume = 0;
534 break;
535 }
536 volume *= (1.0f - hollowVolume);
537 }
538 }
539
540 break;
541
542 case ProfileShape.Circle:
543
544 if (_pbs.PathCurve == (byte)Extrusion.Straight)
545 {
546 volume *= 0.78539816339f; // elipse base
547
548 if (hollowAmount > 0.0)
549 {
550 switch (_pbs.HollowShape)
551 {
552 case HollowShape.Same:
553 case HollowShape.Circle:
554 break;
555
556 case HollowShape.Square:
557 hollowVolume *= 0.5f * 2.5984480504799f;
558 break;
559
560 case HollowShape.Triangle:
561 hollowVolume *= .5f * 1.27323954473516f;
562 break;
563
564 default:
565 hollowVolume = 0;
566 break;
567 }
568 volume *= (1.0f - hollowVolume);
569 }
570 }
571
572 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
573 {
574 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
575 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
576 volume *= (1.0f - tmp * tmp);
577
578 if (hollowAmount > 0.0)
579 {
580
581 // calculate the hollow volume by it's shape compared to the prim shape
582 hollowVolume *= hollowAmount;
583
584 switch (_pbs.HollowShape)
585 {
586 case HollowShape.Same:
587 case HollowShape.Circle:
588 break;
589
590 case HollowShape.Square:
591 hollowVolume *= 0.5f * 2.5984480504799f;
592 break;
593
594 case HollowShape.Triangle:
595 hollowVolume *= .5f * 1.27323954473516f;
596 break;
597
598 default:
599 hollowVolume = 0;
600 break;
601 }
602 volume *= (1.0f - hollowVolume);
603 }
604 }
605 break;
606
607 case ProfileShape.HalfCircle:
608 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
609 {
610 volume *= 0.52359877559829887307710723054658f;
611 }
612 break;
613
614 case ProfileShape.EquilateralTriangle:
615
616 if (_pbs.PathCurve == (byte)Extrusion.Straight)
617 {
618 volume *= 0.32475953f;
619
620 if (hollowAmount > 0.0)
621 {
622
623 // calculate the hollow volume by it's shape compared to the prim shape
624 switch (_pbs.HollowShape)
625 {
626 case HollowShape.Same:
627 case HollowShape.Triangle:
628 hollowVolume *= .25f;
629 break;
630
631 case HollowShape.Square:
632 hollowVolume *= 0.499849f * 3.07920140172638f;
633 break;
634
635 case HollowShape.Circle:
636 // Hollow shape is a perfect cyllinder in respect to the cube's scale
637 // Cyllinder hollow volume calculation
638
639 hollowVolume *= 0.1963495f * 3.07920140172638f;
640 break;
641
642 default:
643 hollowVolume = 0;
644 break;
645 }
646 volume *= (1.0f - hollowVolume);
647 }
648 }
649 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
650 {
651 volume *= 0.32475953f;
652 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
653 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
654 volume *= (1.0f - tmp * tmp);
655
656 if (hollowAmount > 0.0)
657 {
658
659 hollowVolume *= hollowAmount;
660
661 switch (_pbs.HollowShape)
662 {
663 case HollowShape.Same:
664 case HollowShape.Triangle:
665 hollowVolume *= .25f;
666 break;
667
668 case HollowShape.Square:
669 hollowVolume *= 0.499849f * 3.07920140172638f;
670 break;
671
672 case HollowShape.Circle:
673
674 hollowVolume *= 0.1963495f * 3.07920140172638f;
675 break;
676
677 default:
678 hollowVolume = 0;
679 break;
680 }
681 volume *= (1.0f - hollowVolume);
682 }
683 }
684 break;
685
686 default:
687 break;
688 }
689
690 float taperX1;
691 float taperY1;
692 float taperX;
693 float taperY;
694 float pathBegin;
695 float pathEnd;
696 float profileBegin;
697 float profileEnd;
698
699 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
700 {
701 taperX1 = _pbs.PathScaleX * 0.01f;
702 if (taperX1 > 1.0f)
703 taperX1 = 2.0f - taperX1;
704 taperX = 1.0f - taperX1;
705
706 taperY1 = _pbs.PathScaleY * 0.01f;
707 if (taperY1 > 1.0f)
708 taperY1 = 2.0f - taperY1;
709 taperY = 1.0f - taperY1;
710 }
711 else
712 {
713 taperX = _pbs.PathTaperX * 0.01f;
714 if (taperX < 0.0f)
715 taperX = -taperX;
716 taperX1 = 1.0f - taperX;
717
718 taperY = _pbs.PathTaperY * 0.01f;
719 if (taperY < 0.0f)
720 taperY = -taperY;
721 taperY1 = 1.0f - taperY;
722 }
723
724 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
725
726 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
727 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
728 volume *= (pathEnd - pathBegin);
729
730// this is crude aproximation
731 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
732 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
733 volume *= (profileEnd - profileBegin);
734
735 returnMass = m_density * volume;
736
737 if (returnMass <= 0)
738 returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
739// else if (returnMass > _parent_scene.maximumMassObject)
740// returnMass = _parent_scene.maximumMassObject;
741
742 // Recursively calculate mass
743 bool HasChildPrim = false;
744 lock (childrenPrim)
745 {
746 if (childrenPrim.Count > 0)
747 {
748 HasChildPrim = true;
749 }
750 }
751
752 if (HasChildPrim)
753 {
754 OdePrim[] childPrimArr = new OdePrim[0];
755
756 lock (childrenPrim)
757 childPrimArr = childrenPrim.ToArray();
758
759 for (int i = 0; i < childPrimArr.Length; i++)
760 {
761 if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove)
762 returnMass += childPrimArr[i].CalculateMass();
763 // failsafe, this shouldn't happen but with OpenSim, you never know :)
764 if (i > 256)
765 break;
766 }
767 }
768
769 if (returnMass > _parent_scene.maximumMassObject)
770 returnMass = _parent_scene.maximumMassObject;
771
772 return returnMass;
773 }
774
775 #endregion
776
777 private void setMass()
778 {
779 if (Body != (IntPtr) 0)
780 {
781 float newmass = CalculateMass();
782
783 //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString());
784
785 d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z);
786 d.BodySetMass(Body, ref pMass);
787 }
788 }
789
790 /// <summary>
791 /// Stop a prim from being subject to physics.
792 /// </summary>
793 internal void disableBody()
794 {
795 //this kills the body so things like 'mesh' can re-create it.
796 lock (this)
797 {
798 if (!childPrim)
799 {
800 if (Body != IntPtr.Zero)
801 {
802 _parent_scene.DeactivatePrim(this);
803 m_collisionCategories &= ~CollisionCategories.Body;
804 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
805
806 if (m_assetFailed)
807 {
808 d.GeomSetCategoryBits(prim_geom, 0);
809 d.GeomSetCollideBits(prim_geom, 0);
810 }
811 else
812 {
813 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
814 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
815 }
816
817 d.BodyDestroy(Body);
818 lock (childrenPrim)
819 {
820 if (childrenPrim.Count > 0)
821 {
822 foreach (OdePrim prm in childrenPrim)
823 {
824 _parent_scene.DeactivatePrim(prm);
825 prm.Body = IntPtr.Zero;
826 }
827 }
828 }
829 Body = IntPtr.Zero;
830 }
831 }
832 else
833 {
834 _parent_scene.DeactivatePrim(this);
835
836 m_collisionCategories &= ~CollisionCategories.Body;
837 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
838
839 if (m_assetFailed)
840 {
841 d.GeomSetCategoryBits(prim_geom, 0);
842 d.GeomSetCollideBits(prim_geom, 0);
843 }
844 else
845 {
846
847 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
848 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
849 }
850
851 Body = IntPtr.Zero;
852 }
853 }
854
855 m_disabled = true;
856 m_collisionscore = 0;
857 }
858
859 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>();
860
861 private void setMesh(OdeScene parent_scene, IMesh mesh)
862 {
863// m_log.DebugFormat("[ODE PRIM]: Setting mesh on {0} to {1}", Name, mesh);
864
865 // This sleeper is there to moderate how long it takes between
866 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object
867
868 //Thread.Sleep(10);
869
870 //Kill Body so that mesh can re-make the geom
871 if (IsPhysical && Body != IntPtr.Zero)
872 {
873 if (childPrim)
874 {
875 if (_parent != null)
876 {
877 OdePrim parent = (OdePrim)_parent;
878 parent.ChildDelink(this);
879 }
880 }
881 else
882 {
883 disableBody();
884 }
885 }
886
887 IntPtr vertices, indices;
888 int vertexCount, indexCount;
889 int vertexStride, triStride;
890 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
891 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
892 m_expectedCollisionContacts = indexCount;
893 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
894
895 // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at
896 // the same time.
897 lock (m_MeshToTriMeshMap)
898 {
899 if (m_MeshToTriMeshMap.ContainsKey(mesh))
900 {
901 _triMeshData = m_MeshToTriMeshMap[mesh];
902 }
903 else
904 {
905 _triMeshData = d.GeomTriMeshDataCreate();
906
907 d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
908 d.GeomTriMeshDataPreprocess(_triMeshData);
909 m_MeshToTriMeshMap[mesh] = _triMeshData;
910 }
911 }
912
913// _parent_scene.waitForSpaceUnlock(m_targetSpace);
914 try
915 {
916 SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null));
917 }
918 catch (AccessViolationException)
919 {
920 m_log.ErrorFormat("[PHYSICS]: MESH LOCKED FOR {0}", Name);
921 return;
922 }
923
924 // if (IsPhysical && Body == (IntPtr) 0)
925 // {
926 // Recreate the body
927 // m_interpenetrationcount = 0;
928 // m_collisionscore = 0;
929
930 // enableBody();
931 // }
932 }
933
934 internal void ProcessTaints()
935 {
936#if SPAM
937Console.WriteLine("ZProcessTaints for " + Name);
938#endif
939
940 // This must be processed as the very first taint so that later operations have a prim_geom to work with
941 // if this is a new prim.
942 if (m_taintadd)
943 changeadd();
944
945 if (!_position.ApproxEquals(m_taintposition, 0f))
946 changemove();
947
948 if (m_taintrot != _orientation)
949 {
950 if (childPrim && IsPhysical) // For physical child prim...
951 {
952 rotate();
953 // KF: ODE will also rotate the parent prim!
954 // so rotate the root back to where it was
955 OdePrim parent = (OdePrim)_parent;
956 parent.rotate();
957 }
958 else
959 {
960 //Just rotate the prim
961 rotate();
962 }
963 }
964
965 if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent))
966 changePhysicsStatus();
967
968 if (!_size.ApproxEquals(m_taintsize, 0f))
969 changesize();
970
971 if (m_taintshape)
972 changeshape();
973
974 if (m_taintforce)
975 changeAddForce();
976
977 if (m_taintaddangularforce)
978 changeAddAngularForce();
979
980 if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f))
981 changeSetTorque();
982
983 if (m_taintdisable)
984 changedisable();
985
986 if (m_taintselected != m_isSelected)
987 changeSelectedStatus();
988
989 if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f))
990 changevelocity();
991
992 if (m_taintparent != _parent)
993 changelink();
994
995 if (m_taintCollidesWater != m_collidesWater)
996 changefloatonwater();
997
998 if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f))
999 changeAngularLock();
1000 }
1001
1002 /// <summary>
1003 /// Change prim in response to an angular lock taint.
1004 /// </summary>
1005 private void changeAngularLock()
1006 {
1007 // do we have a Physical object?
1008 if (Body != IntPtr.Zero)
1009 {
1010 //Check that we have a Parent
1011 //If we have a parent then we're not authorative here
1012 if (_parent == null)
1013 {
1014 if (!m_taintAngularLock.ApproxEquals(Vector3.One, 0f))
1015 {
1016 //d.BodySetFiniteRotationMode(Body, 0);
1017 //d.BodySetFiniteRotationAxis(Body,m_taintAngularLock.X,m_taintAngularLock.Y,m_taintAngularLock.Z);
1018 createAMotor(m_taintAngularLock);
1019 }
1020 else
1021 {
1022 if (Amotor != IntPtr.Zero)
1023 {
1024 d.JointDestroy(Amotor);
1025 Amotor = IntPtr.Zero;
1026 }
1027 }
1028 }
1029 }
1030
1031 // Store this for later in case we get turned into a separate body
1032 m_angularlock = m_taintAngularLock;
1033 }
1034
1035 /// <summary>
1036 /// Change prim in response to a link taint.
1037 /// </summary>
1038 private void changelink()
1039 {
1040 // If the newly set parent is not null
1041 // create link
1042 if (_parent == null && m_taintparent != null)
1043 {
1044 if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim)
1045 {
1046 OdePrim obj = (OdePrim)m_taintparent;
1047 //obj.disableBody();
1048//Console.WriteLine("changelink calls ParentPrim");
1049 obj.AddChildPrim(this);
1050
1051 /*
1052 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body)
1053 {
1054 _linkJointGroup = d.JointGroupCreate(0);
1055 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1056 d.JointAttach(m_linkJoint, obj.Body, Body);
1057 d.JointSetFixed(m_linkJoint);
1058 }
1059 */
1060 }
1061 }
1062 // If the newly set parent is null
1063 // destroy link
1064 else if (_parent != null && m_taintparent == null)
1065 {
1066//Console.WriteLine(" changelink B");
1067
1068 if (_parent is OdePrim)
1069 {
1070 OdePrim obj = (OdePrim)_parent;
1071 obj.ChildDelink(this);
1072 childPrim = false;
1073 //_parent = null;
1074 }
1075
1076 /*
1077 if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0)
1078 d.JointGroupDestroy(_linkJointGroup);
1079
1080 _linkJointGroup = (IntPtr)0;
1081 m_linkJoint = (IntPtr)0;
1082 */
1083 }
1084
1085 _parent = m_taintparent;
1086 m_taintPhysics = IsPhysical;
1087 }
1088
1089 /// <summary>
1090 /// Add a child prim to this parent prim.
1091 /// </summary>
1092 /// <param name="prim">Child prim</param>
1093 private void AddChildPrim(OdePrim prim)
1094 {
1095 if (LocalID == prim.LocalID)
1096 return;
1097
1098 if (Body == IntPtr.Zero)
1099 {
1100 Body = d.BodyCreate(_parent_scene.world);
1101 setMass();
1102 }
1103
1104 lock (childrenPrim)
1105 {
1106 if (childrenPrim.Contains(prim))
1107 return;
1108
1109// m_log.DebugFormat(
1110// "[ODE PRIM]: Linking prim {0} {1} to {2} {3}", prim.Name, prim.LocalID, Name, LocalID);
1111
1112 childrenPrim.Add(prim);
1113
1114 foreach (OdePrim prm in childrenPrim)
1115 {
1116 d.Mass m2;
1117 d.MassSetZero(out m2);
1118 d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z);
1119
1120 d.Quaternion quat = new d.Quaternion();
1121 quat.W = prm._orientation.W;
1122 quat.X = prm._orientation.X;
1123 quat.Y = prm._orientation.Y;
1124 quat.Z = prm._orientation.Z;
1125
1126 d.Matrix3 mat = new d.Matrix3();
1127 d.RfromQ(out mat, ref quat);
1128 d.MassRotate(ref m2, ref mat);
1129 d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z);
1130 d.MassAdd(ref pMass, ref m2);
1131 }
1132
1133 foreach (OdePrim prm in childrenPrim)
1134 {
1135 prm.m_collisionCategories |= CollisionCategories.Body;
1136 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1137
1138//Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name);
1139 if (prm.m_assetFailed)
1140 {
1141 d.GeomSetCategoryBits(prm.prim_geom, 0);
1142 d.GeomSetCollideBits(prm.prim_geom, prm.BadMeshAssetCollideBits);
1143 }
1144 else
1145 {
1146 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories);
1147 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags);
1148 }
1149
1150 d.Quaternion quat = new d.Quaternion();
1151 quat.W = prm._orientation.W;
1152 quat.X = prm._orientation.X;
1153 quat.Y = prm._orientation.Y;
1154 quat.Z = prm._orientation.Z;
1155
1156 d.Matrix3 mat = new d.Matrix3();
1157 d.RfromQ(out mat, ref quat);
1158 if (Body != IntPtr.Zero)
1159 {
1160 d.GeomSetBody(prm.prim_geom, Body);
1161 prm.childPrim = true;
1162 d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z);
1163 //d.GeomSetOffsetPosition(prim.prim_geom,
1164 // (Position.X - prm.Position.X) - pMass.c.X,
1165 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1166 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1167 d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat);
1168 //d.GeomSetOffsetRotation(prm.prim_geom, ref mat);
1169 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1170 d.BodySetMass(Body, ref pMass);
1171 }
1172 else
1173 {
1174 m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name);
1175 }
1176
1177 prm.m_interpenetrationcount = 0;
1178 prm.m_collisionscore = 0;
1179 prm.m_disabled = false;
1180
1181 // The body doesn't already have a finite rotation mode set here
1182 if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null)
1183 {
1184 prm.createAMotor(m_angularlock);
1185 }
1186 prm.Body = Body;
1187 _parent_scene.ActivatePrim(prm);
1188 }
1189
1190 m_collisionCategories |= CollisionCategories.Body;
1191 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1192
1193 if (m_assetFailed)
1194 {
1195 d.GeomSetCategoryBits(prim_geom, 0);
1196 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1197 }
1198 else
1199 {
1200 //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name);
1201 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1202 //Console.WriteLine(" Post GeomSetCategoryBits 2");
1203 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1204 }
1205
1206 d.Quaternion quat2 = new d.Quaternion();
1207 quat2.W = _orientation.W;
1208 quat2.X = _orientation.X;
1209 quat2.Y = _orientation.Y;
1210 quat2.Z = _orientation.Z;
1211
1212 d.Matrix3 mat2 = new d.Matrix3();
1213 d.RfromQ(out mat2, ref quat2);
1214 d.GeomSetBody(prim_geom, Body);
1215 d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z);
1216 //d.GeomSetOffsetPosition(prim.prim_geom,
1217 // (Position.X - prm.Position.X) - pMass.c.X,
1218 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1219 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1220 //d.GeomSetOffsetRotation(prim_geom, ref mat2);
1221 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1222 d.BodySetMass(Body, ref pMass);
1223
1224 d.BodySetAutoDisableFlag(Body, true);
1225 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1226
1227 m_interpenetrationcount = 0;
1228 m_collisionscore = 0;
1229 m_disabled = false;
1230
1231 // The body doesn't already have a finite rotation mode set here
1232 if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null)
1233 {
1234 createAMotor(m_angularlock);
1235 }
1236
1237 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1238
1239 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1240 m_vehicle.Enable(Body, _parent_scene);
1241
1242 _parent_scene.ActivatePrim(this);
1243 }
1244 }
1245
1246 private void ChildSetGeom(OdePrim odePrim)
1247 {
1248// m_log.DebugFormat(
1249// "[ODE PRIM]: ChildSetGeom {0} {1} for {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID);
1250
1251 //if (IsPhysical && Body != IntPtr.Zero)
1252 lock (childrenPrim)
1253 {
1254 foreach (OdePrim prm in childrenPrim)
1255 {
1256 //prm.childPrim = true;
1257 prm.disableBody();
1258 //prm.m_taintparent = null;
1259 //prm._parent = null;
1260 //prm.m_taintPhysics = false;
1261 //prm.m_disabled = true;
1262 //prm.childPrim = false;
1263 }
1264 }
1265
1266 disableBody();
1267
1268 // Spurious - Body == IntPtr.Zero after disableBody()
1269// if (Body != IntPtr.Zero)
1270// {
1271// _parent_scene.DeactivatePrim(this);
1272// }
1273
1274 lock (childrenPrim)
1275 {
1276 foreach (OdePrim prm in childrenPrim)
1277 {
1278//Console.WriteLine("ChildSetGeom calls ParentPrim");
1279 AddChildPrim(prm);
1280 }
1281 }
1282 }
1283
1284 private void ChildDelink(OdePrim odePrim)
1285 {
1286// m_log.DebugFormat(
1287// "[ODE PRIM]: Delinking prim {0} {1} from {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID);
1288
1289 // Okay, we have a delinked child.. need to rebuild the body.
1290 lock (childrenPrim)
1291 {
1292 foreach (OdePrim prm in childrenPrim)
1293 {
1294 prm.childPrim = true;
1295 prm.disableBody();
1296 //prm.m_taintparent = null;
1297 //prm._parent = null;
1298 //prm.m_taintPhysics = false;
1299 //prm.m_disabled = true;
1300 //prm.childPrim = false;
1301 }
1302 }
1303
1304 disableBody();
1305
1306 lock (childrenPrim)
1307 {
1308 //Console.WriteLine("childrenPrim.Remove " + odePrim);
1309 childrenPrim.Remove(odePrim);
1310 }
1311
1312 // Spurious - Body == IntPtr.Zero after disableBody()
1313// if (Body != IntPtr.Zero)
1314// {
1315// _parent_scene.DeactivatePrim(this);
1316// }
1317
1318 lock (childrenPrim)
1319 {
1320 foreach (OdePrim prm in childrenPrim)
1321 {
1322//Console.WriteLine("ChildDelink calls ParentPrim");
1323 AddChildPrim(prm);
1324 }
1325 }
1326 }
1327
1328 /// <summary>
1329 /// Change prim in response to a selection taint.
1330 /// </summary>
1331 private void changeSelectedStatus()
1332 {
1333 if (m_taintselected)
1334 {
1335 m_collisionCategories = CollisionCategories.Selected;
1336 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
1337
1338 // We do the body disable soft twice because 'in theory' a collision could have happened
1339 // in between the disabling and the collision properties setting
1340 // which would wake the physical body up from a soft disabling and potentially cause it to fall
1341 // through the ground.
1342
1343 // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select
1344 // just one part of the assembly, the rest of the assembly is non-selected and still simulating,
1345 // so that causes the selected part to wake up and continue moving.
1346
1347 // even if you select all parts of a jointed assembly, it is not guaranteed that the entire
1348 // assembly will stop simulating during the selection, because of the lack of atomicity
1349 // of select operations (their processing could be interrupted by a thread switch, causing
1350 // simulation to continue before all of the selected object notifications trickle down to
1351 // the physics engine).
1352
1353 // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are
1354 // selected and disabled. then, due to a thread switch, the selection processing is
1355 // interrupted and the physics engine continues to simulate, so the last 50 items, whose
1356 // selection was not yet processed, continues to simulate. this wakes up ALL of the
1357 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1358 // up, start simulating again, which in turn wakes up the last 50.
1359
1360 if (IsPhysical)
1361 {
1362 disableBodySoft();
1363 }
1364
1365 if (m_assetFailed)
1366 {
1367 d.GeomSetCategoryBits(prim_geom, 0);
1368 d.GeomSetCollideBits(prim_geom, 0);
1369 }
1370 else
1371 {
1372 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1373 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1374 }
1375
1376 if (IsPhysical)
1377 {
1378 disableBodySoft();
1379 }
1380 }
1381 else
1382 {
1383 m_collisionCategories = CollisionCategories.Geom;
1384
1385 if (IsPhysical)
1386 m_collisionCategories |= CollisionCategories.Body;
1387
1388 m_collisionFlags = m_default_collisionFlags;
1389
1390 if (m_collidesLand)
1391 m_collisionFlags |= CollisionCategories.Land;
1392 if (m_collidesWater)
1393 m_collisionFlags |= CollisionCategories.Water;
1394
1395 if (m_assetFailed)
1396 {
1397 d.GeomSetCategoryBits(prim_geom, 0);
1398 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1399 }
1400 else
1401 {
1402 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1403 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1404 }
1405
1406 if (IsPhysical)
1407 {
1408 if (Body != IntPtr.Zero)
1409 {
1410 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1411 d.BodySetForce(Body, 0, 0, 0);
1412 enableBodySoft();
1413 }
1414 }
1415 }
1416
1417 resetCollisionAccounting();
1418 m_isSelected = m_taintselected;
1419 }//end changeSelectedStatus
1420
1421 internal void ResetTaints()
1422 {
1423 m_taintposition = _position;
1424 m_taintrot = _orientation;
1425 m_taintPhysics = IsPhysical;
1426 m_taintselected = m_isSelected;
1427 m_taintsize = _size;
1428 m_taintshape = false;
1429 m_taintforce = false;
1430 m_taintdisable = false;
1431 m_taintVelocity = Vector3.Zero;
1432 }
1433
1434 /// <summary>
1435 /// Create a geometry for the given mesh in the given target space.
1436 /// </summary>
1437 /// <param name="m_targetSpace"></param>
1438 /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param>
1439 private void CreateGeom(IntPtr m_targetSpace, IMesh mesh)
1440 {
1441#if SPAM
1442Console.WriteLine("CreateGeom:");
1443#endif
1444 if (mesh != null)
1445 {
1446 setMesh(_parent_scene, mesh);
1447 }
1448 else
1449 {
1450 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
1451 {
1452 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
1453 {
1454 if (((_size.X / 2f) > 0f))
1455 {
1456// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1457 try
1458 {
1459//Console.WriteLine(" CreateGeom 1");
1460 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1461 m_expectedCollisionContacts = 3;
1462 }
1463 catch (AccessViolationException)
1464 {
1465 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1466 return;
1467 }
1468 }
1469 else
1470 {
1471// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1472 try
1473 {
1474//Console.WriteLine(" CreateGeom 2");
1475 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1476 m_expectedCollisionContacts = 4;
1477 }
1478 catch (AccessViolationException)
1479 {
1480 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1481 return;
1482 }
1483 }
1484 }
1485 else
1486 {
1487// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1488 try
1489 {
1490//Console.WriteLine(" CreateGeom 3");
1491 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1492 m_expectedCollisionContacts = 4;
1493 }
1494 catch (AccessViolationException)
1495 {
1496 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1497 return;
1498 }
1499 }
1500 }
1501 else
1502 {
1503// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1504 try
1505 {
1506//Console.WriteLine(" CreateGeom 4");
1507 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1508 m_expectedCollisionContacts = 4;
1509 }
1510 catch (AccessViolationException)
1511 {
1512 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1513 return;
1514 }
1515 }
1516 }
1517 }
1518
1519 /// <summary>
1520 /// Remove the existing geom from this prim.
1521 /// </summary>
1522 /// <param name="m_targetSpace"></param>
1523 /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param>
1524 /// <returns>true if the geom was successfully removed, false if it was already gone or the remove failed.</returns>
1525 internal bool RemoveGeom()
1526 {
1527 if (prim_geom != IntPtr.Zero)
1528 {
1529 try
1530 {
1531 _parent_scene.geom_name_map.Remove(prim_geom);
1532 _parent_scene.actor_name_map.Remove(prim_geom);
1533 d.GeomDestroy(prim_geom);
1534 m_expectedCollisionContacts = 0;
1535 prim_geom = IntPtr.Zero;
1536 }
1537 catch (System.AccessViolationException)
1538 {
1539 prim_geom = IntPtr.Zero;
1540 m_expectedCollisionContacts = 0;
1541 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
1542
1543 return false;
1544 }
1545
1546 return true;
1547 }
1548 else
1549 {
1550 m_log.WarnFormat(
1551 "[ODE PRIM]: Called RemoveGeom() on {0} {1} where geometry was already null.", Name, LocalID);
1552
1553 return false;
1554 }
1555 }
1556 /// <summary>
1557 /// Add prim in response to an add taint.
1558 /// </summary>
1559 private void changeadd()
1560 {
1561// m_log.DebugFormat("[ODE PRIM]: Adding prim {0}", Name);
1562
1563 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1564 IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position);
1565
1566 if (targetspace == IntPtr.Zero)
1567 targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
1568
1569 m_targetSpace = targetspace;
1570
1571 IMesh mesh = null;
1572
1573 if (_parent_scene.needsMeshing(_pbs))
1574 {
1575 // Don't need to re-enable body.. it's done in SetMesh
1576 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1577 // createmesh returns null when it's a shape that isn't a cube.
1578 // m_log.Debug(m_localID);
1579 if (mesh == null)
1580 CheckMeshAsset();
1581 else
1582 m_assetFailed = false;
1583 }
1584
1585#if SPAM
1586Console.WriteLine("changeadd 1");
1587#endif
1588 CreateGeom(m_targetSpace, mesh);
1589
1590 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1591 d.Quaternion myrot = new d.Quaternion();
1592 myrot.X = _orientation.X;
1593 myrot.Y = _orientation.Y;
1594 myrot.Z = _orientation.Z;
1595 myrot.W = _orientation.W;
1596 d.GeomSetQuaternion(prim_geom, ref myrot);
1597
1598 if (IsPhysical && Body == IntPtr.Zero)
1599 enableBody();
1600
1601 changeSelectedStatus();
1602
1603 m_taintadd = false;
1604 }
1605
1606 /// <summary>
1607 /// Move prim in response to a move taint.
1608 /// </summary>
1609 private void changemove()
1610 {
1611 if (IsPhysical)
1612 {
1613 if (!m_disabled && !m_taintremove && !childPrim)
1614 {
1615 if (Body == IntPtr.Zero)
1616 enableBody();
1617
1618 //Prim auto disable after 20 frames,
1619 //if you move it, re-enable the prim manually.
1620 if (_parent != null)
1621 {
1622 if (m_linkJoint != IntPtr.Zero)
1623 {
1624 d.JointDestroy(m_linkJoint);
1625 m_linkJoint = IntPtr.Zero;
1626 }
1627 }
1628
1629 if (Body != IntPtr.Zero)
1630 {
1631 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1632
1633 if (_parent != null)
1634 {
1635 OdePrim odParent = (OdePrim)_parent;
1636 if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body)
1637 {
1638// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used??
1639Console.WriteLine(" JointCreateFixed");
1640 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1641 d.JointAttach(m_linkJoint, Body, odParent.Body);
1642 d.JointSetFixed(m_linkJoint);
1643 }
1644 }
1645 d.BodyEnable(Body);
1646 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1647 {
1648 m_vehicle.Enable(Body, _parent_scene);
1649 }
1650 }
1651 else
1652 {
1653 m_log.WarnFormat("[PHYSICS]: Body for {0} still null after enableBody(). This is a crash scenario.", Name);
1654 }
1655 }
1656 //else
1657 // {
1658 //m_log.Debug("[BUG]: race!");
1659 //}
1660 }
1661
1662 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
1663 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1664// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1665
1666 IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
1667 m_targetSpace = tempspace;
1668
1669// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1670
1671 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1672
1673// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1674 d.SpaceAdd(m_targetSpace, prim_geom);
1675
1676 changeSelectedStatus();
1677
1678 resetCollisionAccounting();
1679 m_taintposition = _position;
1680 }
1681
1682 internal void Move(float timestep)
1683 {
1684 float fx = 0;
1685 float fy = 0;
1686 float fz = 0;
1687
1688 if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // KF: Only move root prims.
1689 {
1690 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1691 {
1692 // 'VEHICLES' are dealt with in ODEDynamics.cs
1693 m_vehicle.Step(timestep, _parent_scene);
1694 }
1695 else
1696 {
1697//Console.WriteLine("Move " + Name);
1698 if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009
1699 // NON-'VEHICLES' are dealt with here
1700// if (d.BodyIsEnabled(Body) && !m_angularlock.ApproxEquals(Vector3.Zero, 0.003f))
1701// {
1702// d.Vector3 avel2 = d.BodyGetAngularVel(Body);
1703// /*
1704// if (m_angularlock.X == 1)
1705// avel2.X = 0;
1706// if (m_angularlock.Y == 1)
1707// avel2.Y = 0;
1708// if (m_angularlock.Z == 1)
1709// avel2.Z = 0;
1710// d.BodySetAngularVel(Body, avel2.X, avel2.Y, avel2.Z);
1711// */
1712// }
1713 //float PID_P = 900.0f;
1714
1715 float m_mass = CalculateMass();
1716
1717// fz = 0f;
1718 //m_log.Info(m_collisionFlags.ToString());
1719
1720
1721 //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle.
1722 // would come from SceneObjectPart.cs, public void SetBuoyancy(float fvalue) , PhysActor.Buoyancy = fvalue; ??
1723 // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up
1724 // gravityz multiplier = 1 - m_buoyancy
1725 fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass;
1726
1727 if (m_usePID)
1728 {
1729//Console.WriteLine("PID " + Name);
1730 // KF - this is for object move? eg. llSetPos() ?
1731 //if (!d.BodyIsEnabled(Body))
1732 //d.BodySetForce(Body, 0f, 0f, 0f);
1733 // If we're using the PID controller, then we have no gravity
1734 //fz = (-1 * _parent_scene.gravityz) * m_mass; //KF: ?? Prims have no global gravity,so simply...
1735 fz = 0f;
1736
1737 // no lock; for now it's only called from within Simulate()
1738
1739 // If the PID Controller isn't active then we set our force
1740 // calculating base velocity to the current position
1741
1742 if ((m_PIDTau < 1) && (m_PIDTau != 0))
1743 {
1744 //PID_G = PID_G / m_PIDTau;
1745 m_PIDTau = 1;
1746 }
1747
1748 if ((PID_G - m_PIDTau) <= 0)
1749 {
1750 PID_G = m_PIDTau + 1;
1751 }
1752 //PidStatus = true;
1753
1754 // PhysicsVector vec = new PhysicsVector();
1755 d.Vector3 vel = d.BodyGetLinearVel(Body);
1756
1757 d.Vector3 pos = d.BodyGetPosition(Body);
1758 _target_velocity =
1759 new Vector3(
1760 (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep),
1761 (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep),
1762 (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep)
1763 );
1764
1765 // if velocity is zero, use position control; otherwise, velocity control
1766
1767 if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f))
1768 {
1769 // keep track of where we stopped. No more slippin' & slidin'
1770
1771 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1772 // react to the physics scene by moving it's position.
1773 // Avatar to Avatar collisions
1774 // Prim to avatar collisions
1775
1776 //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
1777 //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2);
1778 //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
1779 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
1780 d.BodySetLinearVel(Body, 0, 0, 0);
1781 d.BodyAddForce(Body, 0, 0, fz);
1782 return;
1783 }
1784 else
1785 {
1786 _zeroFlag = false;
1787
1788 // We're flying and colliding with something
1789 fx = ((_target_velocity.X) - vel.X) * (PID_D);
1790 fy = ((_target_velocity.Y) - vel.Y) * (PID_D);
1791
1792 // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P;
1793
1794 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
1795 }
1796 } // end if (m_usePID)
1797
1798 // Hover PID Controller needs to be mutually exlusive to MoveTo PID controller
1799 if (m_useHoverPID && !m_usePID)
1800 {
1801//Console.WriteLine("Hover " + Name);
1802
1803 // If we're using the PID controller, then we have no gravity
1804 fz = (-1 * _parent_scene.gravityz) * m_mass;
1805
1806 // no lock; for now it's only called from within Simulate()
1807
1808 // If the PID Controller isn't active then we set our force
1809 // calculating base velocity to the current position
1810
1811 if ((m_PIDTau < 1))
1812 {
1813 PID_G = PID_G / m_PIDTau;
1814 }
1815
1816 if ((PID_G - m_PIDTau) <= 0)
1817 {
1818 PID_G = m_PIDTau + 1;
1819 }
1820
1821 // Where are we, and where are we headed?
1822 d.Vector3 pos = d.BodyGetPosition(Body);
1823 d.Vector3 vel = d.BodyGetLinearVel(Body);
1824
1825 // Non-Vehicles have a limited set of Hover options.
1826 // determine what our target height really is based on HoverType
1827 switch (m_PIDHoverType)
1828 {
1829 case PIDHoverType.Ground:
1830 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
1831 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
1832 break;
1833 case PIDHoverType.GroundAndWater:
1834 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
1835 m_waterHeight = _parent_scene.GetWaterLevel();
1836 if (m_groundHeight > m_waterHeight)
1837 {
1838 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
1839 }
1840 else
1841 {
1842 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
1843 }
1844 break;
1845
1846 } // end switch (m_PIDHoverType)
1847
1848
1849 _target_velocity =
1850 new Vector3(0.0f, 0.0f,
1851 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
1852 );
1853
1854 // if velocity is zero, use position control; otherwise, velocity control
1855
1856 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
1857 {
1858 // keep track of where we stopped. No more slippin' & slidin'
1859
1860 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1861 // react to the physics scene by moving it's position.
1862 // Avatar to Avatar collisions
1863 // Prim to avatar collisions
1864
1865 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
1866 d.BodySetLinearVel(Body, vel.X, vel.Y, 0);
1867 d.BodyAddForce(Body, 0, 0, fz);
1868 return;
1869 }
1870 else
1871 {
1872 _zeroFlag = false;
1873
1874 // We're flying and colliding with something
1875 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
1876 }
1877 }
1878
1879 fx *= m_mass;
1880 fy *= m_mass;
1881 //fz *= m_mass;
1882
1883 fx += m_force.X;
1884 fy += m_force.Y;
1885 fz += m_force.Z;
1886
1887 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
1888 if (fx != 0 || fy != 0 || fz != 0)
1889 {
1890 //m_taintdisable = true;
1891 //base.RaiseOutOfBounds(Position);
1892 //d.BodySetLinearVel(Body, fx, fy, 0f);
1893 if (!d.BodyIsEnabled(Body))
1894 {
1895 // A physical body at rest on a surface will auto-disable after a while,
1896 // this appears to re-enable it incase the surface it is upon vanishes,
1897 // and the body should fall again.
1898 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1899 d.BodySetForce(Body, 0, 0, 0);
1900 enableBodySoft();
1901 }
1902
1903 // 35x10 = 350n times the mass per second applied maximum.
1904 float nmax = 35f * m_mass;
1905 float nmin = -35f * m_mass;
1906
1907 if (fx > nmax)
1908 fx = nmax;
1909 if (fx < nmin)
1910 fx = nmin;
1911 if (fy > nmax)
1912 fy = nmax;
1913 if (fy < nmin)
1914 fy = nmin;
1915 d.BodyAddForce(Body, fx, fy, fz);
1916//Console.WriteLine("AddForce " + fx + "," + fy + "," + fz);
1917 }
1918 }
1919 }
1920 else
1921 { // is not physical, or is not a body or is selected
1922 // _zeroPosition = d.BodyGetPosition(Body);
1923 return;
1924//Console.WriteLine("Nothing " + Name);
1925
1926 }
1927 }
1928
1929 private void rotate()
1930 {
1931 d.Quaternion myrot = new d.Quaternion();
1932 myrot.X = _orientation.X;
1933 myrot.Y = _orientation.Y;
1934 myrot.Z = _orientation.Z;
1935 myrot.W = _orientation.W;
1936 if (Body != IntPtr.Zero)
1937 {
1938 // KF: If this is a root prim do BodySet
1939 d.BodySetQuaternion(Body, ref myrot);
1940 if (IsPhysical)
1941 {
1942 if (!m_angularlock.ApproxEquals(Vector3.One, 0f))
1943 createAMotor(m_angularlock);
1944 }
1945 }
1946 else
1947 {
1948 // daughter prim, do Geom set
1949 d.GeomSetQuaternion(prim_geom, ref myrot);
1950 }
1951
1952 resetCollisionAccounting();
1953 m_taintrot = _orientation;
1954 }
1955
1956 private void resetCollisionAccounting()
1957 {
1958 m_collisionscore = 0;
1959 m_interpenetrationcount = 0;
1960 m_disabled = false;
1961 }
1962
1963 /// <summary>
1964 /// Change prim in response to a disable taint.
1965 /// </summary>
1966 private void changedisable()
1967 {
1968 m_disabled = true;
1969 if (Body != IntPtr.Zero)
1970 {
1971 d.BodyDisable(Body);
1972 Body = IntPtr.Zero;
1973 }
1974
1975 m_taintdisable = false;
1976 }
1977
1978 /// <summary>
1979 /// Change prim in response to a physics status taint
1980 /// </summary>
1981 private void changePhysicsStatus()
1982 {
1983 if (IsPhysical)
1984 {
1985 if (Body == IntPtr.Zero)
1986 {
1987 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
1988 {
1989 changeshape();
1990 }
1991 else
1992 {
1993 enableBody();
1994 }
1995 }
1996 }
1997 else
1998 {
1999 if (Body != IntPtr.Zero)
2000 {
2001 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2002 {
2003 RemoveGeom();
2004
2005//Console.WriteLine("changePhysicsStatus for " + Name);
2006 changeadd();
2007 }
2008
2009 if (childPrim)
2010 {
2011 if (_parent != null)
2012 {
2013 OdePrim parent = (OdePrim)_parent;
2014 parent.ChildDelink(this);
2015 }
2016 }
2017 else
2018 {
2019 disableBody();
2020 }
2021 }
2022 }
2023
2024 changeSelectedStatus();
2025
2026 resetCollisionAccounting();
2027 m_taintPhysics = IsPhysical;
2028 }
2029
2030 /// <summary>
2031 /// Change prim in response to a size taint.
2032 /// </summary>
2033 private void changesize()
2034 {
2035#if SPAM
2036 m_log.DebugFormat("[ODE PRIM]: Called changesize");
2037#endif
2038
2039 if (_size.X <= 0) _size.X = 0.01f;
2040 if (_size.Y <= 0) _size.Y = 0.01f;
2041 if (_size.Z <= 0) _size.Z = 0.01f;
2042
2043 //kill body to rebuild
2044 if (IsPhysical && Body != IntPtr.Zero)
2045 {
2046 if (childPrim)
2047 {
2048 if (_parent != null)
2049 {
2050 OdePrim parent = (OdePrim)_parent;
2051 parent.ChildDelink(this);
2052 }
2053 }
2054 else
2055 {
2056 disableBody();
2057 }
2058 }
2059
2060 if (d.SpaceQuery(m_targetSpace, prim_geom))
2061 {
2062// _parent_scene.waitForSpaceUnlock(m_targetSpace);
2063 d.SpaceRemove(m_targetSpace, prim_geom);
2064 }
2065
2066 RemoveGeom();
2067
2068 // we don't need to do space calculation because the client sends a position update also.
2069
2070 IMesh mesh = null;
2071
2072 // Construction of new prim
2073 if (_parent_scene.needsMeshing(_pbs))
2074 {
2075 float meshlod = _parent_scene.meshSculptLOD;
2076
2077 if (IsPhysical)
2078 meshlod = _parent_scene.MeshSculptphysicalLOD;
2079 // Don't need to re-enable body.. it's done in SetMesh
2080
2081 if (_parent_scene.needsMeshing(_pbs))
2082 {
2083 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
2084 if (mesh == null)
2085 CheckMeshAsset();
2086 else
2087 m_assetFailed = false;
2088 }
2089
2090 }
2091
2092 CreateGeom(m_targetSpace, mesh);
2093 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2094 d.Quaternion myrot = new d.Quaternion();
2095 myrot.X = _orientation.X;
2096 myrot.Y = _orientation.Y;
2097 myrot.Z = _orientation.Z;
2098 myrot.W = _orientation.W;
2099 d.GeomSetQuaternion(prim_geom, ref myrot);
2100
2101 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2102 if (IsPhysical && Body == IntPtr.Zero && !childPrim)
2103 {
2104 // Re creates body on size.
2105 // EnableBody also does setMass()
2106 enableBody();
2107 d.BodyEnable(Body);
2108 }
2109
2110 changeSelectedStatus();
2111
2112 if (childPrim)
2113 {
2114 if (_parent is OdePrim)
2115 {
2116 OdePrim parent = (OdePrim)_parent;
2117 parent.ChildSetGeom(this);
2118 }
2119 }
2120 resetCollisionAccounting();
2121 m_taintsize = _size;
2122 }
2123
2124 /// <summary>
2125 /// Change prim in response to a float on water taint.
2126 /// </summary>
2127 /// <param name="timestep"></param>
2128 private void changefloatonwater()
2129 {
2130 m_collidesWater = m_taintCollidesWater;
2131
2132 if (m_collidesWater)
2133 {
2134 m_collisionFlags |= CollisionCategories.Water;
2135 }
2136 else
2137 {
2138 m_collisionFlags &= ~CollisionCategories.Water;
2139 }
2140
2141 if (m_assetFailed)
2142 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
2143 else
2144
2145 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2146 }
2147 /// <summary>
2148 /// Change prim in response to a shape taint.
2149 /// </summary>
2150 private void changeshape()
2151 {
2152 m_taintshape = false;
2153
2154 // Cleanup of old prim geometry and Bodies
2155 if (IsPhysical && Body != IntPtr.Zero)
2156 {
2157 if (childPrim)
2158 {
2159 if (_parent != null)
2160 {
2161 OdePrim parent = (OdePrim)_parent;
2162 parent.ChildDelink(this);
2163 }
2164 }
2165 else
2166 {
2167 disableBody();
2168 }
2169 }
2170
2171 RemoveGeom();
2172
2173 // we don't need to do space calculation because the client sends a position update also.
2174 if (_size.X <= 0) _size.X = 0.01f;
2175 if (_size.Y <= 0) _size.Y = 0.01f;
2176 if (_size.Z <= 0) _size.Z = 0.01f;
2177 // Construction of new prim
2178
2179 IMesh mesh = null;
2180
2181
2182 if (_parent_scene.needsMeshing(_pbs))
2183 {
2184 // Don't need to re-enable body.. it's done in CreateMesh
2185 float meshlod = _parent_scene.meshSculptLOD;
2186
2187 if (IsPhysical)
2188 meshlod = _parent_scene.MeshSculptphysicalLOD;
2189
2190 // createmesh returns null when it doesn't mesh.
2191 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
2192 if (mesh == null)
2193 CheckMeshAsset();
2194 else
2195 m_assetFailed = false;
2196 }
2197
2198 CreateGeom(m_targetSpace, mesh);
2199 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2200 d.Quaternion myrot = new d.Quaternion();
2201 //myrot.W = _orientation.w;
2202 myrot.W = _orientation.W;
2203 myrot.X = _orientation.X;
2204 myrot.Y = _orientation.Y;
2205 myrot.Z = _orientation.Z;
2206 d.GeomSetQuaternion(prim_geom, ref myrot);
2207
2208 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2209 if (IsPhysical && Body == IntPtr.Zero)
2210 {
2211 // Re creates body on size.
2212 // EnableBody also does setMass()
2213 enableBody();
2214 if (Body != IntPtr.Zero)
2215 {
2216 d.BodyEnable(Body);
2217 }
2218 }
2219
2220 changeSelectedStatus();
2221
2222 if (childPrim)
2223 {
2224 if (_parent is OdePrim)
2225 {
2226 OdePrim parent = (OdePrim)_parent;
2227 parent.ChildSetGeom(this);
2228 }
2229 }
2230
2231 resetCollisionAccounting();
2232// m_taintshape = false;
2233 }
2234
2235 /// <summary>
2236 /// Change prim in response to an add force taint.
2237 /// </summary>
2238 private void changeAddForce()
2239 {
2240 if (!m_isSelected)
2241 {
2242 lock (m_forcelist)
2243 {
2244 //m_log.Info("[PHYSICS]: dequeing forcelist");
2245 if (IsPhysical)
2246 {
2247 Vector3 iforce = Vector3.Zero;
2248 int i = 0;
2249 try
2250 {
2251 for (i = 0; i < m_forcelist.Count; i++)
2252 {
2253
2254 iforce = iforce + (m_forcelist[i] * 100);
2255 }
2256 }
2257 catch (IndexOutOfRangeException)
2258 {
2259 m_forcelist = new List<Vector3>();
2260 m_collisionscore = 0;
2261 m_interpenetrationcount = 0;
2262 m_taintforce = false;
2263 return;
2264 }
2265 catch (ArgumentOutOfRangeException)
2266 {
2267 m_forcelist = new List<Vector3>();
2268 m_collisionscore = 0;
2269 m_interpenetrationcount = 0;
2270 m_taintforce = false;
2271 return;
2272 }
2273 d.BodyEnable(Body);
2274 d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
2275 }
2276 m_forcelist.Clear();
2277 }
2278
2279 m_collisionscore = 0;
2280 m_interpenetrationcount = 0;
2281 }
2282
2283 m_taintforce = false;
2284 }
2285
2286 /// <summary>
2287 /// Change prim in response to a torque taint.
2288 /// </summary>
2289 private void changeSetTorque()
2290 {
2291 if (!m_isSelected)
2292 {
2293 if (IsPhysical && Body != IntPtr.Zero)
2294 {
2295 d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z);
2296 }
2297 }
2298
2299 m_taintTorque = Vector3.Zero;
2300 }
2301
2302 /// <summary>
2303 /// Change prim in response to an angular force taint.
2304 /// </summary>
2305 private void changeAddAngularForce()
2306 {
2307 if (!m_isSelected)
2308 {
2309 lock (m_angularforcelist)
2310 {
2311 //m_log.Info("[PHYSICS]: dequeing forcelist");
2312 if (IsPhysical)
2313 {
2314 Vector3 iforce = Vector3.Zero;
2315 for (int i = 0; i < m_angularforcelist.Count; i++)
2316 {
2317 iforce = iforce + (m_angularforcelist[i] * 100);
2318 }
2319 d.BodyEnable(Body);
2320 d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z);
2321
2322 }
2323 m_angularforcelist.Clear();
2324 }
2325
2326 m_collisionscore = 0;
2327 m_interpenetrationcount = 0;
2328 }
2329
2330 m_taintaddangularforce = false;
2331 }
2332
2333 /// <summary>
2334 /// Change prim in response to a velocity taint.
2335 /// </summary>
2336 private void changevelocity()
2337 {
2338 if (!m_isSelected)
2339 {
2340 // Not sure exactly why this sleep is here, but from experimentation it appears to stop an avatar
2341 // walking through a default rez size prim if it keeps kicking it around - justincc.
2342 Thread.Sleep(20);
2343
2344 if (IsPhysical)
2345 {
2346 if (Body != IntPtr.Zero)
2347 {
2348 d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
2349 }
2350 }
2351
2352 //resetCollisionAccounting();
2353 }
2354
2355 m_taintVelocity = Vector3.Zero;
2356 }
2357
2358 internal void setPrimForRemoval()
2359 {
2360 m_taintremove = true;
2361 }
2362
2363 public override bool Flying
2364 {
2365 // no flying prims for you
2366 get { return false; }
2367 set { }
2368 }
2369
2370 public override bool IsColliding
2371 {
2372 get { return iscolliding; }
2373 set { iscolliding = value; }
2374 }
2375
2376 public override bool CollidingGround
2377 {
2378 get { return false; }
2379 set { return; }
2380 }
2381
2382 public override bool CollidingObj
2383 {
2384 get { return false; }
2385 set { return; }
2386 }
2387
2388 public override bool ThrottleUpdates
2389 {
2390 get { return m_throttleUpdates; }
2391 set { m_throttleUpdates = value; }
2392 }
2393
2394 public override bool Stopped
2395 {
2396 get { return _zeroFlag; }
2397 }
2398
2399 public override Vector3 Position
2400 {
2401 get { return _position; }
2402
2403 set { _position = value;
2404 //m_log.Info("[PHYSICS]: " + _position.ToString());
2405 }
2406 }
2407
2408 public override Vector3 Size
2409 {
2410 get { return _size; }
2411 set
2412 {
2413 if (value.IsFinite())
2414 {
2415 _size = value;
2416// m_log.DebugFormat("[PHYSICS]: Set size on {0} to {1}", Name, value);
2417 }
2418 else
2419 {
2420 m_log.WarnFormat("[PHYSICS]: Got NaN Size on object {0}", Name);
2421 }
2422 }
2423 }
2424
2425 public override float Mass
2426 {
2427 get { return CalculateMass(); }
2428 }
2429
2430 public override Vector3 Force
2431 {
2432 //get { return Vector3.Zero; }
2433 get { return m_force; }
2434 set
2435 {
2436 if (value.IsFinite())
2437 {
2438 m_force = value;
2439 }
2440 else
2441 {
2442 m_log.WarnFormat("[PHYSICS]: NaN in Force Applied to an Object {0}", Name);
2443 }
2444 }
2445 }
2446
2447 public override int VehicleType
2448 {
2449 get { return (int)m_vehicle.Type; }
2450 set { m_vehicle.ProcessTypeChange((Vehicle)value); }
2451 }
2452
2453 public override void VehicleFloatParam(int param, float value)
2454 {
2455 m_vehicle.ProcessFloatVehicleParam((Vehicle) param, value);
2456 }
2457
2458 public override void VehicleVectorParam(int param, Vector3 value)
2459 {
2460 m_vehicle.ProcessVectorVehicleParam((Vehicle) param, value);
2461 }
2462
2463 public override void VehicleRotationParam(int param, Quaternion rotation)
2464 {
2465 m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation);
2466 }
2467
2468 public override void VehicleFlags(int param, bool remove)
2469 {
2470 m_vehicle.ProcessVehicleFlags(param, remove);
2471 }
2472
2473 public override void SetVolumeDetect(int param)
2474 {
2475 // We have to lock the scene here so that an entire simulate loop either uses volume detect for all
2476 // possible collisions with this prim or for none of them.
2477 lock (_parent_scene.OdeLock)
2478 {
2479 m_isVolumeDetect = (param != 0);
2480 }
2481 }
2482
2483 public override Vector3 CenterOfMass
2484 {
2485 get { return Vector3.Zero; }
2486 }
2487
2488 public override Vector3 GeometricCenter
2489 {
2490 get { return Vector3.Zero; }
2491 }
2492
2493 public override PrimitiveBaseShape Shape
2494 {
2495 set
2496 {
2497 _pbs = value;
2498 m_assetFailed = false;
2499 m_taintshape = true;
2500 }
2501 }
2502
2503 public override Vector3 Velocity
2504 {
2505 get
2506 {
2507 // Average previous velocity with the new one so
2508 // client object interpolation works a 'little' better
2509 if (_zeroFlag)
2510 return Vector3.Zero;
2511
2512 Vector3 returnVelocity = Vector3.Zero;
2513 returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2'
2514 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f;
2515 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f;
2516 return returnVelocity;
2517 }
2518 set
2519 {
2520 if (value.IsFinite())
2521 {
2522 _velocity = value;
2523
2524 m_taintVelocity = value;
2525 _parent_scene.AddPhysicsActorTaint(this);
2526 }
2527 else
2528 {
2529 m_log.WarnFormat("[PHYSICS]: Got NaN Velocity in Object {0}", Name);
2530 }
2531
2532 }
2533 }
2534
2535 public override Vector3 Torque
2536 {
2537 get
2538 {
2539 if (!IsPhysical || Body == IntPtr.Zero)
2540 return Vector3.Zero;
2541
2542 return _torque;
2543 }
2544
2545 set
2546 {
2547 if (value.IsFinite())
2548 {
2549 m_taintTorque = value;
2550 _parent_scene.AddPhysicsActorTaint(this);
2551 }
2552 else
2553 {
2554 m_log.WarnFormat("[PHYSICS]: Got NaN Torque in Object {0}", Name);
2555 }
2556 }
2557 }
2558
2559 public override float CollisionScore
2560 {
2561 get { return m_collisionscore; }
2562 set { m_collisionscore = value; }
2563 }
2564
2565 public override bool Kinematic
2566 {
2567 get { return false; }
2568 set { }
2569 }
2570
2571 public override Quaternion Orientation
2572 {
2573 get { return _orientation; }
2574 set
2575 {
2576 if (QuaternionIsFinite(value))
2577 _orientation = value;
2578 else
2579 m_log.WarnFormat("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object {0}", Name);
2580 }
2581 }
2582
2583 private static bool QuaternionIsFinite(Quaternion q)
2584 {
2585 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
2586 return false;
2587 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
2588 return false;
2589 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
2590 return false;
2591 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
2592 return false;
2593 return true;
2594 }
2595
2596 public override Vector3 Acceleration
2597 {
2598 get { return _acceleration; }
2599 set { _acceleration = value; }
2600 }
2601
2602 public override void AddForce(Vector3 force, bool pushforce)
2603 {
2604 if (force.IsFinite())
2605 {
2606 lock (m_forcelist)
2607 m_forcelist.Add(force);
2608
2609 m_taintforce = true;
2610 }
2611 else
2612 {
2613 m_log.WarnFormat("[PHYSICS]: Got Invalid linear force vector from Scene in Object {0}", Name);
2614 }
2615 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
2616 }
2617
2618 public override void AddAngularForce(Vector3 force, bool pushforce)
2619 {
2620 if (force.IsFinite())
2621 {
2622 m_angularforcelist.Add(force);
2623 m_taintaddangularforce = true;
2624 }
2625 else
2626 {
2627 m_log.WarnFormat("[PHYSICS]: Got Invalid Angular force vector from Scene in Object {0}", Name);
2628 }
2629 }
2630
2631 public override Vector3 RotationalVelocity
2632 {
2633 get
2634 {
2635 Vector3 pv = Vector3.Zero;
2636 if (_zeroFlag)
2637 return pv;
2638 m_lastUpdateSent = false;
2639
2640 if (m_rotationalVelocity.ApproxEquals(pv, 0.2f))
2641 return pv;
2642
2643 return m_rotationalVelocity;
2644 }
2645 set
2646 {
2647 if (value.IsFinite())
2648 {
2649 m_rotationalVelocity = value;
2650 }
2651 else
2652 {
2653 m_log.WarnFormat("[PHYSICS]: Got NaN RotationalVelocity in Object {0}", Name);
2654 }
2655 }
2656 }
2657
2658 public override void CrossingFailure()
2659 {
2660 m_crossingfailures++;
2661 if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds)
2662 {
2663 base.RaiseOutOfBounds(_position);
2664 return;
2665 }
2666 else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds)
2667 {
2668 m_log.Warn("[PHYSICS]: Too many crossing failures for: " + Name);
2669 }
2670 }
2671
2672 public override float Buoyancy
2673 {
2674 get { return m_buoyancy; }
2675 set { m_buoyancy = value; }
2676 }
2677
2678 public override void link(PhysicsActor obj)
2679 {
2680 m_taintparent = obj;
2681 }
2682
2683 public override void delink()
2684 {
2685 m_taintparent = null;
2686 }
2687
2688 public override void LockAngularMotion(Vector3 axis)
2689 {
2690 // reverse the zero/non zero values for ODE.
2691 if (axis.IsFinite())
2692 {
2693 axis.X = (axis.X > 0) ? 1f : 0f;
2694 axis.Y = (axis.Y > 0) ? 1f : 0f;
2695 axis.Z = (axis.Z > 0) ? 1f : 0f;
2696 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
2697 m_taintAngularLock = axis;
2698 }
2699 else
2700 {
2701 m_log.WarnFormat("[PHYSICS]: Got NaN locking axis from Scene on Object {0}", Name);
2702 }
2703 }
2704
2705 internal void UpdatePositionAndVelocity()
2706 {
2707 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
2708 if (_parent == null)
2709 {
2710 Vector3 pv = Vector3.Zero;
2711 bool lastZeroFlag = _zeroFlag;
2712 float m_minvelocity = 0;
2713 if (Body != (IntPtr)0) // FIXME -> or if it is a joint
2714 {
2715 d.Vector3 vec = d.BodyGetPosition(Body);
2716 d.Quaternion ori = d.BodyGetQuaternion(Body);
2717 d.Vector3 vel = d.BodyGetLinearVel(Body);
2718 d.Vector3 rotvel = d.BodyGetAngularVel(Body);
2719 d.Vector3 torque = d.BodyGetTorque(Body);
2720 _torque = new Vector3(torque.X, torque.Y, torque.Z);
2721 Vector3 l_position = Vector3.Zero;
2722 Quaternion l_orientation = Quaternion.Identity;
2723
2724 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
2725 //if (vec.X < 0.0f) { vec.X = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2726 //if (vec.Y < 0.0f) { vec.Y = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2727 //if (vec.X > 255.95f) { vec.X = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2728 //if (vec.Y > 255.95f) { vec.Y = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2729
2730 m_lastposition = _position;
2731 m_lastorientation = _orientation;
2732
2733 l_position.X = vec.X;
2734 l_position.Y = vec.Y;
2735 l_position.Z = vec.Z;
2736 l_orientation.X = ori.X;
2737 l_orientation.Y = ori.Y;
2738 l_orientation.Z = ori.Z;
2739 l_orientation.W = ori.W;
2740
2741 if (l_position.X > ((int)_parent_scene.WorldExtents.X - 0.05f) || l_position.X < 0f || l_position.Y > ((int)_parent_scene.WorldExtents.Y - 0.05f) || l_position.Y < 0f)
2742 {
2743 //base.RaiseOutOfBounds(l_position);
2744
2745 if (m_crossingfailures < _parent_scene.geomCrossingFailuresBeforeOutofbounds)
2746 {
2747 _position = l_position;
2748 //_parent_scene.remActivePrim(this);
2749 if (_parent == null)
2750 base.RequestPhysicsterseUpdate();
2751 return;
2752 }
2753 else
2754 {
2755 if (_parent == null)
2756 base.RaiseOutOfBounds(l_position);
2757 return;
2758 }
2759 }
2760
2761 if (l_position.Z < 0)
2762 {
2763 // This is so prim that get lost underground don't fall forever and suck up
2764 //
2765 // Sim resources and memory.
2766 // Disables the prim's movement physics....
2767 // It's a hack and will generate a console message if it fails.
2768
2769 //IsPhysical = false;
2770 if (_parent == null)
2771 base.RaiseOutOfBounds(_position);
2772
2773 _acceleration.X = 0;
2774 _acceleration.Y = 0;
2775 _acceleration.Z = 0;
2776
2777 _velocity.X = 0;
2778 _velocity.Y = 0;
2779 _velocity.Z = 0;
2780 m_rotationalVelocity.X = 0;
2781 m_rotationalVelocity.Y = 0;
2782 m_rotationalVelocity.Z = 0;
2783
2784 if (_parent == null)
2785 base.RequestPhysicsterseUpdate();
2786
2787 m_throttleUpdates = false;
2788 throttleCounter = 0;
2789 _zeroFlag = true;
2790 //outofBounds = true;
2791 }
2792
2793 //float Adiff = 1.0f - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation));
2794//Console.WriteLine("Adiff " + Name + " = " + Adiff);
2795 if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
2796 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
2797 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02)
2798// && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.01))
2799 && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.0001)) // KF 0.01 is far to large
2800 {
2801 _zeroFlag = true;
2802//Console.WriteLine("ZFT 2");
2803 m_throttleUpdates = false;
2804 }
2805 else
2806 {
2807 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
2808 _zeroFlag = false;
2809 m_lastUpdateSent = false;
2810 //m_throttleUpdates = false;
2811 }
2812
2813 if (_zeroFlag)
2814 {
2815 _velocity.X = 0.0f;
2816 _velocity.Y = 0.0f;
2817 _velocity.Z = 0.0f;
2818
2819 _acceleration.X = 0;
2820 _acceleration.Y = 0;
2821 _acceleration.Z = 0;
2822
2823 //_orientation.w = 0f;
2824 //_orientation.X = 0f;
2825 //_orientation.Y = 0f;
2826 //_orientation.Z = 0f;
2827 m_rotationalVelocity.X = 0;
2828 m_rotationalVelocity.Y = 0;
2829 m_rotationalVelocity.Z = 0;
2830 if (!m_lastUpdateSent)
2831 {
2832 m_throttleUpdates = false;
2833 throttleCounter = 0;
2834 m_rotationalVelocity = pv;
2835
2836 if (_parent == null)
2837 {
2838 base.RequestPhysicsterseUpdate();
2839 }
2840
2841 m_lastUpdateSent = true;
2842 }
2843 }
2844 else
2845 {
2846 if (lastZeroFlag != _zeroFlag)
2847 {
2848 if (_parent == null)
2849 {
2850 base.RequestPhysicsterseUpdate();
2851 }
2852 }
2853
2854 m_lastVelocity = _velocity;
2855
2856 _position = l_position;
2857
2858 _velocity.X = vel.X;
2859 _velocity.Y = vel.Y;
2860 _velocity.Z = vel.Z;
2861
2862 _acceleration = ((_velocity - m_lastVelocity) / 0.1f);
2863 _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f);
2864 //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString());
2865
2866 // Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing...
2867 // it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large.
2868 // reducing this to 0.02m/frame seems to help the angular rubberbanding quite a bit, however, to make sure it doesn't affect elevators and vehicles
2869 // adding these logical exclusion situations to maintain this where I think it was intended to be.
2870 if (m_throttleUpdates || m_usePID || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero))
2871 {
2872 m_minvelocity = 0.5f;
2873 }
2874 else
2875 {
2876 m_minvelocity = 0.02f;
2877 }
2878
2879 if (_velocity.ApproxEquals(pv, m_minvelocity))
2880 {
2881 m_rotationalVelocity = pv;
2882 }
2883 else
2884 {
2885 m_rotationalVelocity = new Vector3(rotvel.X, rotvel.Y, rotvel.Z);
2886 }
2887
2888 //m_log.Debug("ODE: " + m_rotationalVelocity.ToString());
2889 _orientation.X = ori.X;
2890 _orientation.Y = ori.Y;
2891 _orientation.Z = ori.Z;
2892 _orientation.W = ori.W;
2893 m_lastUpdateSent = false;
2894 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
2895 {
2896 if (_parent == null)
2897 {
2898 base.RequestPhysicsterseUpdate();
2899 }
2900 }
2901 else
2902 {
2903 throttleCounter++;
2904 }
2905 }
2906 m_lastposition = l_position;
2907 }
2908 else
2909 {
2910 // Not a body.. so Make sure the client isn't interpolating
2911 _velocity.X = 0;
2912 _velocity.Y = 0;
2913 _velocity.Z = 0;
2914
2915 _acceleration.X = 0;
2916 _acceleration.Y = 0;
2917 _acceleration.Z = 0;
2918
2919 m_rotationalVelocity.X = 0;
2920 m_rotationalVelocity.Y = 0;
2921 m_rotationalVelocity.Z = 0;
2922 _zeroFlag = true;
2923 }
2924 }
2925 }
2926
2927 public override bool FloatOnWater
2928 {
2929 set {
2930 m_taintCollidesWater = value;
2931 _parent_scene.AddPhysicsActorTaint(this);
2932 }
2933 }
2934
2935 public override void SetMomentum(Vector3 momentum)
2936 {
2937 }
2938
2939 public override Vector3 PIDTarget
2940 {
2941 set
2942 {
2943 if (value.IsFinite())
2944 {
2945 m_PIDTarget = value;
2946 }
2947 else
2948 m_log.WarnFormat("[PHYSICS]: Got NaN PIDTarget from Scene on Object {0}", Name);
2949 }
2950 }
2951 public override bool PIDActive { set { m_usePID = value; } }
2952 public override float PIDTau { set { m_PIDTau = value; } }
2953
2954 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
2955 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
2956 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
2957 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
2958
2959 public override Quaternion APIDTarget{ set { return; } }
2960
2961 public override bool APIDActive{ set { return; } }
2962
2963 public override float APIDStrength{ set { return; } }
2964
2965 public override float APIDDamping{ set { return; } }
2966
2967 private void createAMotor(Vector3 axis)
2968 {
2969 if (Body == IntPtr.Zero)
2970 return;
2971
2972 if (Amotor != IntPtr.Zero)
2973 {
2974 d.JointDestroy(Amotor);
2975 Amotor = IntPtr.Zero;
2976 }
2977
2978 float axisnum = 3;
2979
2980 axisnum = (axisnum - (axis.X + axis.Y + axis.Z));
2981
2982 // PhysicsVector totalSize = new PhysicsVector(_size.X, _size.Y, _size.Z);
2983
2984
2985 // Inverse Inertia Matrix, set the X, Y, and/r Z inertia to 0 then invert it again.
2986 d.Mass objMass;
2987 d.MassSetZero(out objMass);
2988 DMassCopy(ref pMass, ref objMass);
2989
2990 //m_log.DebugFormat("1-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22);
2991
2992 Matrix4 dMassMat = FromDMass(objMass);
2993
2994 Matrix4 mathmat = Inverse(dMassMat);
2995
2996 /*
2997 //m_log.DebugFormat("2-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", mathmat[0, 0], mathmat[0, 1], mathmat[0, 2], mathmat[1, 0], mathmat[1, 1], mathmat[1, 2], mathmat[2, 0], mathmat[2, 1], mathmat[2, 2]);
2998
2999 mathmat = Inverse(mathmat);
3000
3001
3002 objMass = FromMatrix4(mathmat, ref objMass);
3003 //m_log.DebugFormat("3-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22);
3004
3005 mathmat = Inverse(mathmat);
3006 */
3007 if (axis.X == 0)
3008 {
3009 mathmat.M33 = 50.0000001f;
3010 //objMass.I.M22 = 0;
3011 }
3012 if (axis.Y == 0)
3013 {
3014 mathmat.M22 = 50.0000001f;
3015 //objMass.I.M11 = 0;
3016 }
3017 if (axis.Z == 0)
3018 {
3019 mathmat.M11 = 50.0000001f;
3020 //objMass.I.M00 = 0;
3021 }
3022
3023
3024
3025 mathmat = Inverse(mathmat);
3026 objMass = FromMatrix4(mathmat, ref objMass);
3027 //m_log.DebugFormat("4-{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, ", objMass.I.M00, objMass.I.M01, objMass.I.M02, objMass.I.M10, objMass.I.M11, objMass.I.M12, objMass.I.M20, objMass.I.M21, objMass.I.M22);
3028
3029 //return;
3030 if (d.MassCheck(ref objMass))
3031 {
3032 d.BodySetMass(Body, ref objMass);
3033 }
3034 else
3035 {
3036 //m_log.Debug("[PHYSICS]: Mass invalid, ignoring");
3037 }
3038
3039 if (axisnum <= 0)
3040 return;
3041 // int dAMotorEuler = 1;
3042
3043 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
3044 d.JointAttach(Amotor, Body, IntPtr.Zero);
3045 d.JointSetAMotorMode(Amotor, 0);
3046
3047 d.JointSetAMotorNumAxes(Amotor,(int)axisnum);
3048 int i = 0;
3049
3050 if (axis.X == 0)
3051 {
3052 d.JointSetAMotorAxis(Amotor, i, 0, 1, 0, 0);
3053 i++;
3054 }
3055
3056 if (axis.Y == 0)
3057 {
3058 d.JointSetAMotorAxis(Amotor, i, 0, 0, 1, 0);
3059 i++;
3060 }
3061
3062 if (axis.Z == 0)
3063 {
3064 d.JointSetAMotorAxis(Amotor, i, 0, 0, 0, 1);
3065 i++;
3066 }
3067
3068 for (int j = 0; j < (int)axisnum; j++)
3069 {
3070 //d.JointSetAMotorAngle(Amotor, j, 0);
3071 }
3072
3073 //d.JointSetAMotorAngle(Amotor, 1, 0);
3074 //d.JointSetAMotorAngle(Amotor, 2, 0);
3075
3076 // These lowstops and high stops are effectively (no wiggle room)
3077 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0f);
3078 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f);
3079 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0f);
3080 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f);
3081 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f);
3082 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f);
3083 //d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 9000f);
3084 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
3085 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, Mass * 50f);//
3086 }
3087
3088 private Matrix4 FromDMass(d.Mass pMass)
3089 {
3090 Matrix4 obj;
3091 obj.M11 = pMass.I.M00;
3092 obj.M12 = pMass.I.M01;
3093 obj.M13 = pMass.I.M02;
3094 obj.M14 = 0;
3095 obj.M21 = pMass.I.M10;
3096 obj.M22 = pMass.I.M11;
3097 obj.M23 = pMass.I.M12;
3098 obj.M24 = 0;
3099 obj.M31 = pMass.I.M20;
3100 obj.M32 = pMass.I.M21;
3101 obj.M33 = pMass.I.M22;
3102 obj.M34 = 0;
3103 obj.M41 = 0;
3104 obj.M42 = 0;
3105 obj.M43 = 0;
3106 obj.M44 = 1;
3107 return obj;
3108 }
3109
3110 private d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj)
3111 {
3112 obj.I.M00 = pMat[0, 0];
3113 obj.I.M01 = pMat[0, 1];
3114 obj.I.M02 = pMat[0, 2];
3115 obj.I.M10 = pMat[1, 0];
3116 obj.I.M11 = pMat[1, 1];
3117 obj.I.M12 = pMat[1, 2];
3118 obj.I.M20 = pMat[2, 0];
3119 obj.I.M21 = pMat[2, 1];
3120 obj.I.M22 = pMat[2, 2];
3121 return obj;
3122 }
3123
3124 public override void SubscribeEvents(int ms)
3125 {
3126 m_eventsubscription = ms;
3127 _parent_scene.AddCollisionEventReporting(this);
3128 }
3129
3130 public override void UnSubscribeEvents()
3131 {
3132 _parent_scene.RemoveCollisionEventReporting(this);
3133 m_eventsubscription = 0;
3134 }
3135
3136 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
3137 {
3138 CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
3139 }
3140
3141 public void SendCollisions()
3142 {
3143 if (m_collisionsOnPreviousFrame || CollisionEventsThisFrame.Count > 0)
3144 {
3145 base.SendCollisionUpdate(CollisionEventsThisFrame);
3146
3147 if (CollisionEventsThisFrame.Count > 0)
3148 {
3149 m_collisionsOnPreviousFrame = true;
3150 CollisionEventsThisFrame.Clear();
3151 }
3152 else
3153 {
3154 m_collisionsOnPreviousFrame = false;
3155 }
3156 }
3157 }
3158
3159 public override bool SubscribedEvents()
3160 {
3161 if (m_eventsubscription > 0)
3162 return true;
3163 return false;
3164 }
3165
3166 public static Matrix4 Inverse(Matrix4 pMat)
3167 {
3168 if (determinant3x3(pMat) == 0)
3169 {
3170 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible
3171 }
3172
3173 return (Adjoint(pMat) / determinant3x3(pMat));
3174 }
3175
3176 public static Matrix4 Adjoint(Matrix4 pMat)
3177 {
3178 Matrix4 adjointMatrix = new Matrix4();
3179 for (int i=0; i<4; i++)
3180 {
3181 for (int j=0; j<4; j++)
3182 {
3183 Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j)))));
3184 }
3185 }
3186
3187 adjointMatrix = Transpose(adjointMatrix);
3188 return adjointMatrix;
3189 }
3190
3191 public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol)
3192 {
3193 Matrix4 minor = new Matrix4();
3194 int m = 0, n = 0;
3195 for (int i = 0; i < 4; i++)
3196 {
3197 if (i == iRow)
3198 continue;
3199 n = 0;
3200 for (int j = 0; j < 4; j++)
3201 {
3202 if (j == iCol)
3203 continue;
3204 Matrix4SetValue(ref minor, m,n, matrix[i, j]);
3205 n++;
3206 }
3207 m++;
3208 }
3209
3210 return minor;
3211 }
3212
3213 public static Matrix4 Transpose(Matrix4 pMat)
3214 {
3215 Matrix4 transposeMatrix = new Matrix4();
3216 for (int i = 0; i < 4; i++)
3217 for (int j = 0; j < 4; j++)
3218 Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]);
3219 return transposeMatrix;
3220 }
3221
3222 public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val)
3223 {
3224 switch (r)
3225 {
3226 case 0:
3227 switch (c)
3228 {
3229 case 0:
3230 pMat.M11 = val;
3231 break;
3232 case 1:
3233 pMat.M12 = val;
3234 break;
3235 case 2:
3236 pMat.M13 = val;
3237 break;
3238 case 3:
3239 pMat.M14 = val;
3240 break;
3241 }
3242
3243 break;
3244 case 1:
3245 switch (c)
3246 {
3247 case 0:
3248 pMat.M21 = val;
3249 break;
3250 case 1:
3251 pMat.M22 = val;
3252 break;
3253 case 2:
3254 pMat.M23 = val;
3255 break;
3256 case 3:
3257 pMat.M24 = val;
3258 break;
3259 }
3260
3261 break;
3262 case 2:
3263 switch (c)
3264 {
3265 case 0:
3266 pMat.M31 = val;
3267 break;
3268 case 1:
3269 pMat.M32 = val;
3270 break;
3271 case 2:
3272 pMat.M33 = val;
3273 break;
3274 case 3:
3275 pMat.M34 = val;
3276 break;
3277 }
3278
3279 break;
3280 case 3:
3281 switch (c)
3282 {
3283 case 0:
3284 pMat.M41 = val;
3285 break;
3286 case 1:
3287 pMat.M42 = val;
3288 break;
3289 case 2:
3290 pMat.M43 = val;
3291 break;
3292 case 3:
3293 pMat.M44 = val;
3294 break;
3295 }
3296
3297 break;
3298 }
3299 }
3300
3301 private static float determinant3x3(Matrix4 pMat)
3302 {
3303 float det = 0;
3304 float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2];
3305 float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0];
3306 float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1];
3307 float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2];
3308 float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0];
3309 float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1];
3310
3311 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6);
3312 return det;
3313 }
3314
3315 private static void DMassCopy(ref d.Mass src, ref d.Mass dst)
3316 {
3317 dst.c.W = src.c.W;
3318 dst.c.X = src.c.X;
3319 dst.c.Y = src.c.Y;
3320 dst.c.Z = src.c.Z;
3321 dst.mass = src.mass;
3322 dst.I.M00 = src.I.M00;
3323 dst.I.M01 = src.I.M01;
3324 dst.I.M02 = src.I.M02;
3325 dst.I.M10 = src.I.M10;
3326 dst.I.M11 = src.I.M11;
3327 dst.I.M12 = src.I.M12;
3328 dst.I.M20 = src.I.M20;
3329 dst.I.M21 = src.I.M21;
3330 dst.I.M22 = src.I.M22;
3331 }
3332
3333 public override void SetMaterial(int pMaterial)
3334 {
3335 m_material = pMaterial;
3336 }
3337
3338 private void CheckMeshAsset()
3339 {
3340 if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero)
3341 {
3342 m_assetFailed = true;
3343 Util.FireAndForget(delegate
3344 {
3345 RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod;
3346 if (assetProvider != null)
3347 assetProvider(_pbs.SculptTexture, MeshAssetReceived);
3348 });
3349 }
3350 }
3351
3352 private void MeshAssetReceived(AssetBase asset)
3353 {
3354 if (asset != null && asset.Data != null && asset.Data.Length > 0)
3355 {
3356 if (!_pbs.SculptEntry)
3357 return;
3358 if (_pbs.SculptTexture.ToString() != asset.ID)
3359 return;
3360
3361 _pbs.SculptData = new byte[asset.Data.Length];
3362 asset.Data.CopyTo(_pbs.SculptData, 0);
3363// m_assetFailed = false;
3364
3365// m_log.DebugFormat(
3366// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
3367// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
3368
3369 m_taintshape = true;
3370 _parent_scene.AddPhysicsActorTaint(this);
3371 }
3372 else
3373 {
3374 m_log.WarnFormat(
3375 "[ODE PRIM]: Could not get mesh/sculpt asset {0} for {1} at {2} in {3}",
3376 _pbs.SculptTexture, Name, _position, _parent_scene.Name);
3377 }
3378 }
3379 }
3380} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
deleted file mode 100644
index 8d7d3b3..0000000
--- a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs
+++ /dev/null
@@ -1,434 +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.Reflection;
31using System.Runtime.InteropServices;
32using System.Text;
33using OpenMetaverse;
34using OpenSim.Region.Physics.Manager;
35using Ode.NET;
36using log4net;
37
38namespace OpenSim.Region.Physics.OdePlugin
39{
40 /// <summary>
41 /// Processes raycast requests as ODE is in a state to be able to do them.
42 /// This ensures that it's thread safe and there will be no conflicts.
43 /// Requests get returned by a different thread then they were requested by.
44 /// </summary>
45 public class ODERayCastRequestManager
46 {
47 /// <summary>
48 /// Pending raycast requests
49 /// </summary>
50 protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>();
51
52 /// <summary>
53 /// Pending ray requests
54 /// </summary>
55 protected List<ODERayRequest> m_PendingRayRequests = new List<ODERayRequest>();
56
57 /// <summary>
58 /// Scene that created this object.
59 /// </summary>
60 private OdeScene m_scene;
61
62 /// <summary>
63 /// ODE contact array to be filled by the collision testing
64 /// </summary>
65 d.ContactGeom[] contacts = new d.ContactGeom[5];
66
67 /// <summary>
68 /// ODE near callback delegate
69 /// </summary>
70 private d.NearCallback nearCallback;
71 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
72 private List<ContactResult> m_contactResults = new List<ContactResult>();
73
74
75 public ODERayCastRequestManager(OdeScene pScene)
76 {
77 m_scene = pScene;
78 nearCallback = near;
79
80 }
81
82 /// <summary>
83 /// Queues a raycast
84 /// </summary>
85 /// <param name="position">Origin of Ray</param>
86 /// <param name="direction">Ray normal</param>
87 /// <param name="length">Ray length</param>
88 /// <param name="retMethod">Return method to send the results</param>
89 public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
90 {
91 lock (m_PendingRequests)
92 {
93 ODERayCastRequest req = new ODERayCastRequest();
94 req.callbackMethod = retMethod;
95 req.length = length;
96 req.Normal = direction;
97 req.Origin = position;
98
99 m_PendingRequests.Add(req);
100 }
101 }
102
103 /// <summary>
104 /// Queues a raycast
105 /// </summary>
106 /// <param name="position">Origin of Ray</param>
107 /// <param name="direction">Ray normal</param>
108 /// <param name="length">Ray length</param>
109 /// <param name="count"></param>
110 /// <param name="retMethod">Return method to send the results</param>
111 public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod)
112 {
113 lock (m_PendingRequests)
114 {
115 ODERayRequest req = new ODERayRequest();
116 req.callbackMethod = retMethod;
117 req.length = length;
118 req.Normal = direction;
119 req.Origin = position;
120 req.Count = count;
121
122 m_PendingRayRequests.Add(req);
123 }
124 }
125
126 /// <summary>
127 /// Process all queued raycast requests
128 /// </summary>
129 /// <returns>Time in MS the raycasts took to process.</returns>
130 public int ProcessQueuedRequests()
131 {
132 int time = System.Environment.TickCount;
133 lock (m_PendingRequests)
134 {
135 if (m_PendingRequests.Count > 0)
136 {
137 ODERayCastRequest[] reqs = m_PendingRequests.ToArray();
138 for (int i = 0; i < reqs.Length; i++)
139 {
140 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
141 RayCast(reqs[i]); // if there isn't anyone to send results
142 }
143
144 m_PendingRequests.Clear();
145 }
146 }
147
148 lock (m_PendingRayRequests)
149 {
150 if (m_PendingRayRequests.Count > 0)
151 {
152 ODERayRequest[] reqs = m_PendingRayRequests.ToArray();
153 for (int i = 0; i < reqs.Length; i++)
154 {
155 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
156 RayCast(reqs[i]); // if there isn't anyone to send results
157 }
158
159 m_PendingRayRequests.Clear();
160 }
161 }
162
163 lock (m_contactResults)
164 m_contactResults.Clear();
165
166 return System.Environment.TickCount - time;
167 }
168
169 /// <summary>
170 /// Method that actually initiates the raycast
171 /// </summary>
172 /// <param name="req"></param>
173 private void RayCast(ODERayCastRequest req)
174 {
175 // Create the ray
176 IntPtr ray = d.CreateRay(m_scene.space, req.length);
177 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
178
179 // Collide test
180 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
181
182 // Remove Ray
183 d.GeomDestroy(ray);
184
185 // Define default results
186 bool hitYN = false;
187 uint hitConsumerID = 0;
188 float distance = 999999999999f;
189 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
190 Vector3 snormal = Vector3.Zero;
191
192 // Find closest contact and object.
193 lock (m_contactResults)
194 {
195 foreach (ContactResult cResult in m_contactResults)
196 {
197 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
198 {
199 closestcontact = cResult.Pos;
200 hitConsumerID = cResult.ConsumerID;
201 distance = cResult.Depth;
202 hitYN = true;
203 snormal = cResult.Normal;
204 }
205 }
206
207 m_contactResults.Clear();
208 }
209
210 // Return results
211 if (req.callbackMethod != null)
212 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal);
213 }
214
215 /// <summary>
216 /// Method that actually initiates the raycast
217 /// </summary>
218 /// <param name="req"></param>
219 private void RayCast(ODERayRequest req)
220 {
221 // Create the ray
222 IntPtr ray = d.CreateRay(m_scene.space, req.length);
223 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
224
225 // Collide test
226 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
227
228 // Remove Ray
229 d.GeomDestroy(ray);
230
231 // Find closest contact and object.
232 lock (m_contactResults)
233 {
234 // Return results
235 if (req.callbackMethod != null)
236 req.callbackMethod(m_contactResults);
237 }
238 }
239
240 // This is the standard Near. Uses space AABBs to speed up detection.
241 private void near(IntPtr space, IntPtr g1, IntPtr g2)
242 {
243
244 //Don't test against heightfield Geom, or you'll be sorry!
245
246 /*
247 terminate called after throwing an instance of 'std::bad_alloc'
248 what(): std::bad_alloc
249 Stacktrace:
250
251 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004>
252 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff>
253 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280>
254 at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff
255 fffff>
256 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004>
257 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff>
258 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) <
259 0x00114>
260 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb>
261 at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6>
262 at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042>
263 at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e>
264 at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019>
265 at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff>
266
267 Native stacktrace:
268
269 mono [0x80d2a42]
270 [0xb7f5840c]
271 /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018]
272 /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988]
273 /usr/lib/libstdc++.so.6 [0xb45fa865]
274 /usr/lib/libstdc++.so.6 [0xb45fa8a2]
275 /usr/lib/libstdc++.so.6 [0xb45fa9da]
276 /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033]
277 /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d]
278 libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4]
279 libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b]
280 libode.so(dCollide+0x102) [0xb46571b2]
281 [0x95cfdec9]
282 [0x8ea07fe1]
283 [0xab260146]
284 libode.so [0xb465a5c4]
285 libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5]
286 libode.so(dSpaceCollide2+0x177) [0xb465ac67]
287 [0x95cf978e]
288 [0x8ea07945]
289 [0x95cf2bbc]
290 [0xab2787e7]
291 [0xab419fb3]
292 [0xab416657]
293 [0xab415bda]
294 [0xb609b08e]
295 mono(mono_runtime_delegate_invoke+0x34) [0x8192534]
296 mono [0x81a2f0f]
297 mono [0x81d28b6]
298 mono [0x81ea2c6]
299 /lib/i686/cmov/libpthread.so.0 [0xb7e744c0]
300 /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de]
301 */
302
303 // Exclude heightfield geom
304
305 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
306 return;
307 if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
308 return;
309
310 // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
311 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
312 {
313 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
314 return;
315
316 // Separating static prim geometry spaces.
317 // We'll be calling near recursivly if one
318 // of them is a space to find all of the
319 // contact points in the space
320 try
321 {
322 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
323 }
324 catch (AccessViolationException)
325 {
326 m_log.Warn("[PHYSICS]: Unable to collide test a space");
327 return;
328 }
329 //Colliding a space or a geom with a space or a geom. so drill down
330
331 //Collide all geoms in each space..
332 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
333 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
334 return;
335 }
336
337 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
338 return;
339
340 int count = 0;
341 try
342 {
343
344 if (g1 == g2)
345 return; // Can't collide with yourself
346
347 lock (contacts)
348 {
349 count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
350 }
351 }
352 catch (SEHException)
353 {
354 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
355 }
356 catch (Exception e)
357 {
358 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
359 return;
360 }
361
362 PhysicsActor p1 = null;
363 PhysicsActor p2 = null;
364
365 if (g1 != IntPtr.Zero)
366 m_scene.actor_name_map.TryGetValue(g1, out p1);
367
368 if (g2 != IntPtr.Zero)
369 m_scene.actor_name_map.TryGetValue(g1, out p2);
370
371 // Loop over contacts, build results.
372 for (int i = 0; i < count; i++)
373 {
374 if (p1 != null)
375 {
376 if (p1 is OdePrim)
377 {
378 ContactResult collisionresult = new ContactResult();
379
380 collisionresult.ConsumerID = p1.LocalID;
381 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
382 collisionresult.Depth = contacts[i].depth;
383 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
384 contacts[i].normal.Z);
385 lock (m_contactResults)
386 m_contactResults.Add(collisionresult);
387 }
388 }
389
390 if (p2 != null)
391 {
392 if (p2 is OdePrim)
393 {
394 ContactResult collisionresult = new ContactResult();
395
396 collisionresult.ConsumerID = p2.LocalID;
397 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
398 collisionresult.Depth = contacts[i].depth;
399 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
400 contacts[i].normal.Z);
401
402 lock (m_contactResults)
403 m_contactResults.Add(collisionresult);
404 }
405 }
406 }
407 }
408
409 /// <summary>
410 /// Dereference the creator scene so that it can be garbage collected if needed.
411 /// </summary>
412 internal void Dispose()
413 {
414 m_scene = null;
415 }
416 }
417
418 public struct ODERayCastRequest
419 {
420 public Vector3 Origin;
421 public Vector3 Normal;
422 public float length;
423 public RaycastCallback callbackMethod;
424 }
425
426 public struct ODERayRequest
427 {
428 public Vector3 Origin;
429 public Vector3 Normal;
430 public int Count;
431 public float length;
432 public RayCallback callbackMethod;
433 }
434} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePhysicsJoint.cs b/OpenSim/Region/Physics/OdePlugin/OdePhysicsJoint.cs
deleted file mode 100644
index b4a3c48..0000000
--- a/OpenSim/Region/Physics/OdePlugin/OdePhysicsJoint.cs
+++ /dev/null
@@ -1,48 +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 OpenMetaverse;
30using Ode.NET;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.OdePlugin;
34
35namespace OpenSim.Region.Physics.OdePlugin
36{
37 class OdePhysicsJoint : PhysicsJoint
38 {
39 public override bool IsInPhysicsEngine
40 {
41 get
42 {
43 return (jointID != IntPtr.Zero);
44 }
45 }
46 public IntPtr jointID;
47 }
48}
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
deleted file mode 100644
index 478dd95..0000000
--- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
+++ /dev/null
@@ -1,90 +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.Reflection;
31using System.Runtime.InteropServices;
32using System.Threading;
33using System.IO;
34using System.Diagnostics;
35using log4net;
36using Nini.Config;
37using Ode.NET;
38using OpenSim.Framework;
39using OpenSim.Region.Physics.Manager;
40using OpenMetaverse;
41
42namespace OpenSim.Region.Physics.OdePlugin
43{
44 /// <summary>
45 /// ODE plugin
46 /// </summary>
47 public class OdePlugin : IPhysicsPlugin
48 {
49 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
50
51 private OdeScene m_scene;
52
53 public bool Init()
54 {
55 return true;
56 }
57
58 public PhysicsScene GetScene(String sceneIdentifier)
59 {
60 if (m_scene == null)
61 {
62 // We do this so that OpenSimulator on Windows loads the correct native ODE library depending on whether
63 // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports
64 // will find it already loaded later on.
65 //
66 // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be
67 // controlled in Ode.NET.dll.config
68 if (Util.IsWindows())
69 Util.LoadArchSpecificWindowsDll("ode.dll");
70
71 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to
72 // http://opensimulator.org/mantis/view.php?id=2750).
73 d.InitODE();
74
75 m_scene = new OdeScene(sceneIdentifier);
76 }
77
78 return m_scene;
79 }
80
81 public string GetName()
82 {
83 return ("OpenDynamicsEngine");
84 }
85
86 public void Dispose()
87 {
88 }
89 }
90} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
deleted file mode 100644
index d53bd90..0000000
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ /dev/null
@@ -1,4323 +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
28//#define USE_DRAWSTUFF
29//#define SPAM
30
31using System;
32using System.Collections.Generic;
33using System.Diagnostics;
34using System.IO;
35using System.Linq;
36using System.Reflection;
37using System.Runtime.InteropServices;
38using System.Threading;
39using log4net;
40using Nini.Config;
41using Ode.NET;
42using OpenMetaverse;
43#if USE_DRAWSTUFF
44using Drawstuff.NET;
45#endif
46using OpenSim.Framework;
47using OpenSim.Region.Physics.Manager;
48
49namespace OpenSim.Region.Physics.OdePlugin
50{
51 public enum StatusIndicators : int
52 {
53 Generic = 0,
54 Start = 1,
55 End = 2
56 }
57
58// public struct sCollisionData
59// {
60// public uint ColliderLocalId;
61// public uint CollidedWithLocalId;
62// public int NumberOfCollisions;
63// public int CollisionType;
64// public int StatusIndicator;
65// public int lastframe;
66// }
67
68 [Flags]
69 public enum CollisionCategories : int
70 {
71 Disabled = 0,
72 Geom = 0x00000001,
73 Body = 0x00000002,
74 Space = 0x00000004,
75 Character = 0x00000008,
76 Land = 0x00000010,
77 Water = 0x00000020,
78 Wind = 0x00000040,
79 Sensor = 0x00000080,
80 Selected = 0x00000100
81 }
82
83 /// <summary>
84 /// Material type for a primitive
85 /// </summary>
86 public enum Material : int
87 {
88 /// <summary></summary>
89 Stone = 0,
90 /// <summary></summary>
91 Metal = 1,
92 /// <summary></summary>
93 Glass = 2,
94 /// <summary></summary>
95 Wood = 3,
96 /// <summary></summary>
97 Flesh = 4,
98 /// <summary></summary>
99 Plastic = 5,
100 /// <summary></summary>
101 Rubber = 6
102 }
103
104 public class OdeScene : PhysicsScene
105 {
106 private readonly ILog m_log;
107 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
108
109 /// <summary>
110 /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances.
111 /// </summary>
112 /// <remarks>
113 /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a
114 /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts
115 /// uses a static cache at the ODE level.
116 ///
117 /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar
118 /// to
119 ///
120 /// mono() [0x489171]
121 /// mono() [0x4d154f]
122 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60]
123 /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a]
124 ///
125 /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option
126 /// causes OpenSimulator to immediately crash with a native stack trace similar to
127 ///
128 /// mono() [0x489171]
129 /// mono() [0x4d154f]
130 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60]
131 /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82]
132 /// </remarks>
133 internal static Object UniversalColliderSyncObject = new Object();
134
135 /// <summary>
136 /// Is stats collecting enabled for this ODE scene?
137 /// </summary>
138 public bool CollectStats { get; set; }
139
140 /// <summary>
141 /// Statistics for this scene.
142 /// </summary>
143 private Dictionary<string, float> m_stats = new Dictionary<string, float>();
144
145 /// <summary>
146 /// Stat name for total number of avatars in this ODE scene.
147 /// </summary>
148 public const string ODETotalAvatarsStatName = "ODETotalAvatars";
149
150 /// <summary>
151 /// Stat name for total number of prims in this ODE scene.
152 /// </summary>
153 public const string ODETotalPrimsStatName = "ODETotalPrims";
154
155 /// <summary>
156 /// Stat name for total number of prims with active physics in this ODE scene.
157 /// </summary>
158 public const string ODEActivePrimsStatName = "ODEActivePrims";
159
160 /// <summary>
161 /// Stat name for the total time spent in ODE frame processing.
162 /// </summary>
163 /// <remarks>
164 /// A sanity check for the main scene loop physics time.
165 /// </remarks>
166 public const string ODETotalFrameMsStatName = "ODETotalFrameMS";
167
168 /// <summary>
169 /// Stat name for time spent processing avatar taints per frame
170 /// </summary>
171 public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS";
172
173 /// <summary>
174 /// Stat name for time spent processing prim taints per frame
175 /// </summary>
176 public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS";
177
178 /// <summary>
179 /// Stat name for time spent calculating avatar forces per frame.
180 /// </summary>
181 public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS";
182
183 /// <summary>
184 /// Stat name for time spent calculating prim forces per frame
185 /// </summary>
186 public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS";
187
188 /// <summary>
189 /// Stat name for time spent fulfilling raycasting requests per frame
190 /// </summary>
191 public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS";
192
193 /// <summary>
194 /// Stat name for time spent in native code that actually steps through the simulation.
195 /// </summary>
196 public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS";
197
198 /// <summary>
199 /// Stat name for the number of milliseconds that ODE spends in native space collision code.
200 /// </summary>
201 public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS";
202
203 /// <summary>
204 /// Stat name for milliseconds that ODE spends in native geom collision code.
205 /// </summary>
206 public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS";
207
208 /// <summary>
209 /// Time spent in collision processing that is not spent in native space or geom collision code.
210 /// </summary>
211 public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS";
212
213 /// <summary>
214 /// Stat name for time spent notifying listeners of collisions
215 /// </summary>
216 public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS";
217
218 /// <summary>
219 /// Stat name for milliseconds spent updating avatar position and velocity
220 /// </summary>
221 public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS";
222
223 /// <summary>
224 /// Stat name for the milliseconds spent updating prim position and velocity
225 /// </summary>
226 public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS";
227
228 /// <summary>
229 /// Stat name for avatar collisions with another entity.
230 /// </summary>
231 public const string ODEAvatarContactsStatsName = "ODEAvatarContacts";
232
233 /// <summary>
234 /// Stat name for prim collisions with another entity.
235 /// </summary>
236 public const string ODEPrimContactsStatName = "ODEPrimContacts";
237
238 /// <summary>
239 /// Used to hold tick numbers for stat collection purposes.
240 /// </summary>
241 private int m_nativeCollisionStartTick;
242
243 /// <summary>
244 /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback.
245 /// </summary>
246 private bool m_inCollisionTiming;
247
248 /// <summary>
249 /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object
250 /// collisions occured using the _perloopcontact if stats collection is enabled.
251 /// </summary>
252 private int m_tempAvatarCollisionsThisFrame;
253
254 /// <summary>
255 /// Used in calculating physics frame time dilation
256 /// </summary>
257 private int tickCountFrameRun;
258
259 /// <summary>
260 /// Used in calculating physics frame time dilation
261 /// </summary>
262 private int latertickcount;
263
264 private Random fluidRandomizer = new Random(Environment.TickCount);
265
266 private const uint m_regionWidth = Constants.RegionSize;
267 private const uint m_regionHeight = Constants.RegionSize;
268
269 private float ODE_STEPSIZE = 0.0178f;
270 private float metersInSpace = 29.9f;
271 private float m_timeDilation = 1.0f;
272
273 public float gravityx = 0f;
274 public float gravityy = 0f;
275 public float gravityz = -9.8f;
276
277 public float AvatarTerminalVelocity { get; set; }
278
279 private float contactsurfacelayer = 0.001f;
280
281 private int worldHashspaceLow = -4;
282 private int worldHashspaceHigh = 128;
283
284 private int smallHashspaceLow = -4;
285 private int smallHashspaceHigh = 66;
286
287 private float waterlevel = 0f;
288 private int framecount = 0;
289 //private int m_returncollisions = 10;
290
291 private readonly IntPtr contactgroup;
292
293 internal IntPtr WaterGeom;
294
295 private float nmTerrainContactFriction = 255.0f;
296 private float nmTerrainContactBounce = 0.1f;
297 private float nmTerrainContactERP = 0.1025f;
298
299 private float mTerrainContactFriction = 75f;
300 private float mTerrainContactBounce = 0.1f;
301 private float mTerrainContactERP = 0.05025f;
302
303 private float nmAvatarObjectContactFriction = 250f;
304 private float nmAvatarObjectContactBounce = 0.1f;
305
306 private float mAvatarObjectContactFriction = 75f;
307 private float mAvatarObjectContactBounce = 0.1f;
308
309 private float avPIDD = 3200f;
310 private float avPIDP = 1400f;
311 private float avCapRadius = 0.37f;
312 private float avStandupTensor = 2000000f;
313
314 /// <summary>
315 /// true = old compatibility mode with leaning capsule; false = new corrected mode
316 /// </summary>
317 /// <remarks>
318 /// Even when set to false, the capsule still tilts but this is done in a different way.
319 /// </remarks>
320 public bool IsAvCapsuleTilted { get; private set; }
321
322 private float avDensity = 80f;
323// private float avHeightFudgeFactor = 0.52f;
324 private float avMovementDivisorWalk = 1.3f;
325 private float avMovementDivisorRun = 0.8f;
326 private float minimumGroundFlightOffset = 3f;
327 public float maximumMassObject = 10000.01f;
328
329 public bool meshSculptedPrim = true;
330 public bool forceSimplePrimMeshing = false;
331
332 public float meshSculptLOD = 32;
333 public float MeshSculptphysicalLOD = 16;
334
335 public float geomDefaultDensity = 10.000006836f;
336
337 public int geomContactPointsStartthrottle = 3;
338 public int geomUpdatesPerThrottledUpdate = 15;
339 private const int avatarExpectedContacts = 3;
340
341 public float bodyPIDD = 35f;
342 public float bodyPIDG = 25;
343
344 public int geomCrossingFailuresBeforeOutofbounds = 5;
345
346 public float bodyMotorJointMaxforceTensor = 2;
347
348 public int bodyFramesAutoDisable = 20;
349
350 private float[] _watermap;
351 private bool m_filterCollisions = true;
352
353 private d.NearCallback nearCallback;
354 public d.TriCallback triCallback;
355 public d.TriArrayCallback triArrayCallback;
356
357 /// <summary>
358 /// Avatars in the physics scene.
359 /// </summary>
360 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
361
362 /// <summary>
363 /// Prims in the physics scene.
364 /// </summary>
365 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
366
367 /// <summary>
368 /// Prims in the physics scene that are subject to physics, not just collisions.
369 /// </summary>
370 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
371
372 /// <summary>
373 /// Prims that the simulator has created/deleted/updated and so need updating in ODE.
374 /// </summary>
375 private readonly HashSet<OdePrim> _taintedPrims = new HashSet<OdePrim>();
376
377 /// <summary>
378 /// Record a character that has taints to be processed.
379 /// </summary>
380 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
381
382 /// <summary>
383 /// Keep record of contacts in the physics loop so that we can remove duplicates.
384 /// </summary>
385 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
386
387 /// <summary>
388 /// A dictionary of actors that should receive collision events.
389 /// </summary>
390 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActors = new Dictionary<uint, PhysicsActor>();
391
392 /// <summary>
393 /// A dictionary of collision event changes that are waiting to be processed.
394 /// </summary>
395 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActorsChanges = new Dictionary<uint, PhysicsActor>();
396
397 /// <summary>
398 /// Maps a unique geometry id (a memory location) to a physics actor name.
399 /// </summary>
400 /// <remarks>
401 /// Only actors participating in collisions have geometries. This has to be maintained separately from
402 /// actor_name_map because terrain and water currently don't conceptually have a physics actor of their own
403 /// apart from the singleton PANull
404 /// </remarks>
405 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
406
407 /// <summary>
408 /// Maps a unique geometry id (a memory location) to a physics actor.
409 /// </summary>
410 /// <remarks>
411 /// Only actors participating in collisions have geometries.
412 /// </remarks>
413 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
414
415 /// <summary>
416 /// Defects list to remove characters that no longer have finite positions due to some other bug.
417 /// </summary>
418 /// <remarks>
419 /// Used repeatedly in Simulate() but initialized once here.
420 /// </remarks>
421 private readonly List<OdeCharacter> defects = new List<OdeCharacter>();
422
423 private bool m_NINJA_physics_joints_enabled = false;
424 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
425 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
426 private d.ContactGeom[] contacts;
427
428 /// <summary>
429 /// Lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
430 /// </summary>
431 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>();
432
433 /// <summary>
434 /// can lock for longer. accessed only by OdeScene.
435 /// </summary>
436 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>();
437
438 /// <summary>
439 /// can lock for longer. accessed only by OdeScene.
440 /// </summary>
441 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>();
442
443 /// <summary>
444 /// lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
445 /// </summary>
446 private readonly List<string> requestedJointsToBeDeleted = new List<string>();
447
448 private Object externalJointRequestsLock = new Object();
449 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
450 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
451 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
452 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
453
454 private d.Contact contact;
455 private d.Contact TerrainContact;
456 private d.Contact AvatarMovementprimContact;
457 private d.Contact AvatarMovementTerrainContact;
458 private d.Contact WaterContact;
459 private d.Contact[,] m_materialContacts;
460
461//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
462//Ckrinke private int m_randomizeWater = 200;
463 private int m_physicsiterations = 10;
464 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
465 private readonly PhysicsActor PANull = new NullPhysicsActor();
466// private float step_time = 0.0f;
467//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
468//Ckrinke private int ms = 0;
469 public IntPtr world;
470 //private bool returncollisions = false;
471 // private uint obj1LocalID = 0;
472 private uint obj2LocalID = 0;
473 //private int ctype = 0;
474 private OdeCharacter cc1;
475 private OdePrim cp1;
476 private OdeCharacter cc2;
477 private OdePrim cp2;
478 private int p1ExpectedPoints = 0;
479 private int p2ExpectedPoints = 0;
480 //private int cStartStop = 0;
481 //private string cDictKey = "";
482
483 public IntPtr space;
484
485 //private IntPtr tmpSpace;
486 // split static geometry collision handling into spaces of 30 meters
487 public IntPtr[,] staticPrimspace;
488
489 /// <summary>
490 /// Used to lock the entire physics scene. Locked during the main part of Simulate()
491 /// </summary>
492 internal Object OdeLock = new Object();
493
494 private bool _worldInitialized = false;
495
496 public IMesher mesher;
497
498 private IConfigSource m_config;
499
500 public bool physics_logging = false;
501 public int physics_logging_interval = 0;
502 public bool physics_logging_append_existing_logfile = false;
503
504 private bool avplanted = false;
505 private bool av_av_collisions_off = false;
506
507 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
508 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
509
510 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
511 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
512 // TODO: unused: private uint heightmapWidthSamples;
513 // TODO: unused: private uint heightmapHeightSamples;
514
515 private volatile int m_global_contactcount = 0;
516
517 private Vector3 m_worldOffset = Vector3.Zero;
518 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
519 private PhysicsScene m_parentScene = null;
520
521 private ODERayCastRequestManager m_rayCastManager;
522
523 /// <summary>
524 /// Initiailizes the scene
525 /// Sets many properties that ODE requires to be stable
526 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
527 /// </summary>
528 /// <param value="name">Name of the scene. Useful in debug messages.</param>
529 public OdeScene(string name)
530 {
531 m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name);
532
533 Name = name;
534
535 nearCallback = near;
536 triCallback = TriCallback;
537 triArrayCallback = TriArrayCallback;
538 m_rayCastManager = new ODERayCastRequestManager(this);
539
540 // Create the world and the first space
541 world = d.WorldCreate();
542 space = d.HashSpaceCreate(IntPtr.Zero);
543
544 contactgroup = d.JointGroupCreate(0);
545
546 d.WorldSetAutoDisableFlag(world, false);
547
548 #if USE_DRAWSTUFF
549 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
550 viewthread.Start();
551 #endif
552
553 _watermap = new float[258 * 258];
554
555 // Zero out the prim spaces array (we split our space into smaller spaces so
556 // we can hit test less.
557 }
558
559#if USE_DRAWSTUFF
560 public void startvisualization(object o)
561 {
562 ds.Functions fn;
563 fn.version = ds.VERSION;
564 fn.start = new ds.CallbackFunction(start);
565 fn.step = new ds.CallbackFunction(step);
566 fn.command = new ds.CallbackFunction(command);
567 fn.stop = null;
568 fn.path_to_textures = "./textures";
569 string[] args = new string[0];
570 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
571 }
572#endif
573
574 // Initialize the mesh plugin
575 public override void Initialise(IMesher meshmerizer, IConfigSource config)
576 {
577 InitializeExtraStats();
578
579 mesher = meshmerizer;
580 m_config = config;
581 // Defaults
582
583 if (Environment.OSVersion.Platform == PlatformID.Unix)
584 {
585 avPIDD = 3200.0f;
586 avPIDP = 1400.0f;
587 avStandupTensor = 2000000f;
588 }
589 else
590 {
591 avPIDD = 2200.0f;
592 avPIDP = 900.0f;
593 avStandupTensor = 550000f;
594 }
595
596 int contactsPerCollision = 80;
597
598 if (m_config != null)
599 {
600 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
601 if (physicsconfig != null)
602 {
603 CollectStats = physicsconfig.GetBoolean("collect_stats", false);
604
605 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
606 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
607 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
608
609 float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f);
610 AvatarTerminalVelocity = Util.Clamp<float>(avatarTerminalVelocity, 0, 255f);
611 if (AvatarTerminalVelocity != avatarTerminalVelocity)
612 {
613 m_log.WarnFormat(
614 "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}",
615 avatarTerminalVelocity, AvatarTerminalVelocity);
616 }
617
618 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
619 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
620
621 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
622 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
623 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
624
625 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
626
627 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
628 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
629 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
630
631 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
632 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
633 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
634
635 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
636 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
637
638 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
639 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
640
641 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE);
642 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
643
644 avDensity = physicsconfig.GetFloat("av_density", 80f);
645// avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
646 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
647 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
648 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
649 avplanted = physicsconfig.GetBoolean("av_planted", false);
650 av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
651
652 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
653
654 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
655
656 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5);
657 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
658 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
659
660 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
661 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
662
663 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
664 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
665
666 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
667 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
668 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
669 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
670 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
671
672
673
674 if (Environment.OSVersion.Platform == PlatformID.Unix)
675 {
676 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
677 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
678 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
679 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
680 }
681 else
682 {
683 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
684 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
685 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
686 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
687 }
688
689 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
690 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
691 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
692
693 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
694 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
695 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
696 }
697 }
698
699 contacts = new d.ContactGeom[contactsPerCollision];
700
701 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
702
703 // Centeral contact friction and bounce
704 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
705 // an avatar falls through in Z but not in X or Y when walking on a prim.
706 contact.surface.mode |= d.ContactFlags.SoftERP;
707 contact.surface.mu = nmAvatarObjectContactFriction;
708 contact.surface.bounce = nmAvatarObjectContactBounce;
709 contact.surface.soft_cfm = 0.010f;
710 contact.surface.soft_erp = 0.010f;
711
712 // Terrain contact friction and Bounce
713 // This is the *non* moving version. Use this when an avatar
714 // isn't moving to keep it in place better
715 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
716 TerrainContact.surface.mu = nmTerrainContactFriction;
717 TerrainContact.surface.bounce = nmTerrainContactBounce;
718 TerrainContact.surface.soft_erp = nmTerrainContactERP;
719
720 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
721 WaterContact.surface.mu = 0f; // No friction
722 WaterContact.surface.bounce = 0.0f; // No bounce
723 WaterContact.surface.soft_cfm = 0.010f;
724 WaterContact.surface.soft_erp = 0.010f;
725
726 // Prim contact friction and bounce
727 // THis is the *non* moving version of friction and bounce
728 // Use this when an avatar comes in contact with a prim
729 // and is moving
730 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
731 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
732
733 // Terrain contact friction bounce and various error correcting calculations
734 // Use this when an avatar is in contact with the terrain and moving.
735 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
736 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
737 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
738 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
739
740 /*
741 <summary></summary>
742 Stone = 0,
743 /// <summary></summary>
744 Metal = 1,
745 /// <summary></summary>
746 Glass = 2,
747 /// <summary></summary>
748 Wood = 3,
749 /// <summary></summary>
750 Flesh = 4,
751 /// <summary></summary>
752 Plastic = 5,
753 /// <summary></summary>
754 Rubber = 6
755 */
756
757 m_materialContacts = new d.Contact[7,2];
758
759 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
760 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
761 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
762 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
763 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
764 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
765
766 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
767 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
768 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
769 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
770 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
771 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
772
773 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
774 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
775 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
776 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
777 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
778 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
779
780 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
781 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
782 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
783 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
784 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
785 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
786
787 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
788 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
789 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
790 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
791 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
792 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
793
794 /*
795 private float nmAvatarObjectContactFriction = 250f;
796 private float nmAvatarObjectContactBounce = 0.1f;
797
798 private float mAvatarObjectContactFriction = 75f;
799 private float mAvatarObjectContactBounce = 0.1f;
800 */
801 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
802 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
803 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
804 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
805 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
806 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
807
808 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
809 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
810 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
811 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
812 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
813 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
814
815 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
816 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
817 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
818 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
819 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
820 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
821
822 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
823 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
824 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
825 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
826 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
827 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
828
829 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
830 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
831 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
832 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
833 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
834 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
835
836 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
837 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
838 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
839 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
840 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
841 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
842
843 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
844 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
845 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
846 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
847 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
848 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
849
850 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
851 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
852 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
853 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
854 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
855 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
856
857 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
858 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
859 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
860 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
861 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
862 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
863
864 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
865
866 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
867
868 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
869 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
870
871 d.WorldSetLinearDamping(world, 256f);
872 d.WorldSetAngularDamping(world, 256f);
873 d.WorldSetAngularDampingThreshold(world, 256f);
874 d.WorldSetLinearDampingThreshold(world, 256f);
875 d.WorldSetMaxAngularSpeed(world, 256f);
876
877 // Set how many steps we go without running collision testing
878 // This is in addition to the step size.
879 // Essentially Steps * m_physicsiterations
880 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
881 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
882
883 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
884 {
885 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
886 {
887 staticPrimspace[i, j] = IntPtr.Zero;
888 }
889 }
890
891 _worldInitialized = true;
892 }
893
894// internal void waitForSpaceUnlock(IntPtr space)
895// {
896// //if (space != IntPtr.Zero)
897// //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
898// }
899
900// /// <summary>
901// /// Debug space message for printing the space that a prim/avatar is in.
902// /// </summary>
903// /// <param name="pos"></param>
904// /// <returns>Returns which split up space the given position is in.</returns>
905// public string whichspaceamIin(Vector3 pos)
906// {
907// return calculateSpaceForGeom(pos).ToString();
908// }
909
910 #region Collision Detection
911
912 /// <summary>
913 /// Collides two geometries.
914 /// </summary>
915 /// <returns></returns>
916 /// <param name='geom1'></param>
917 /// <param name='geom2'>/param>
918 /// <param name='maxContacts'></param>
919 /// <param name='contactsArray'></param>
920 /// <param name='contactGeomSize'></param>
921 private int CollideGeoms(
922 IntPtr geom1, IntPtr geom2, int maxContacts, Ode.NET.d.ContactGeom[] contactsArray, int contactGeomSize)
923 {
924 int count;
925
926 lock (OdeScene.UniversalColliderSyncObject)
927 {
928 // We do this inside the lock so that we don't count any delay in acquiring it
929 if (CollectStats)
930 m_nativeCollisionStartTick = Util.EnvironmentTickCount();
931
932 count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize);
933 }
934
935 // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably
936 // negligable
937 if (CollectStats)
938 m_stats[ODENativeGeomCollisionFrameMsStatName]
939 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
940
941 return count;
942 }
943
944 /// <summary>
945 /// Collide two spaces or a space and a geometry.
946 /// </summary>
947 /// <param name='space1'></param>
948 /// <param name='space2'>/param>
949 /// <param name='data'></param>
950 private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data)
951 {
952 if (CollectStats)
953 {
954 m_inCollisionTiming = true;
955 m_nativeCollisionStartTick = Util.EnvironmentTickCount();
956 }
957
958 d.SpaceCollide2(space1, space2, data, nearCallback);
959
960 if (CollectStats && m_inCollisionTiming)
961 {
962 m_stats[ODENativeSpaceCollisionFrameMsStatName]
963 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
964 m_inCollisionTiming = false;
965 }
966 }
967
968 /// <summary>
969 /// This is our near callback. A geometry is near a body
970 /// </summary>
971 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
972 /// <param name="g1">a geometry or space</param>
973 /// <param name="g2">another geometry or space</param>
974 private void near(IntPtr space, IntPtr g1, IntPtr g2)
975 {
976 if (CollectStats && m_inCollisionTiming)
977 {
978 m_stats[ODENativeSpaceCollisionFrameMsStatName]
979 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
980 m_inCollisionTiming = false;
981 }
982
983// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space);
984 // no lock here! It's invoked from within Simulate(), which is thread-locked
985
986 // Test if we're colliding a geom with a space.
987 // If so we have to drill down into the space recursively
988
989 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
990 {
991 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
992 return;
993
994 // Separating static prim geometry spaces.
995 // We'll be calling near recursivly if one
996 // of them is a space to find all of the
997 // contact points in the space
998 try
999 {
1000 CollideSpaces(g1, g2, IntPtr.Zero);
1001 }
1002 catch (AccessViolationException)
1003 {
1004 m_log.Error("[ODE SCENE]: Unable to collide test a space");
1005 return;
1006 }
1007 //Colliding a space or a geom with a space or a geom. so drill down
1008
1009 //Collide all geoms in each space..
1010 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
1011 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
1012 return;
1013 }
1014
1015 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
1016 return;
1017
1018 IntPtr b1 = d.GeomGetBody(g1);
1019 IntPtr b2 = d.GeomGetBody(g2);
1020
1021 // d.GeomClassID id = d.GeomGetClass(g1);
1022
1023 String name1 = null;
1024 String name2 = null;
1025
1026 if (!geom_name_map.TryGetValue(g1, out name1))
1027 {
1028 name1 = "null";
1029 }
1030 if (!geom_name_map.TryGetValue(g2, out name2))
1031 {
1032 name2 = "null";
1033 }
1034
1035 //if (id == d.GeomClassId.TriMeshClass)
1036 //{
1037 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
1038 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1039 //}
1040
1041 // Figure out how many contact points we have
1042 int count = 0;
1043
1044 try
1045 {
1046 // Colliding Geom To Geom
1047 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
1048
1049 if (g1 == g2)
1050 return; // Can't collide with yourself
1051
1052 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
1053 return;
1054
1055 count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
1056
1057 // All code after this is only relevant if we have any collisions
1058 if (count <= 0)
1059 return;
1060
1061 if (count > contacts.Length)
1062 m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
1063 }
1064 catch (SEHException)
1065 {
1066 m_log.Error(
1067 "[ODE SCENE]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
1068 base.TriggerPhysicsBasedRestart();
1069 }
1070 catch (Exception e)
1071 {
1072 m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message);
1073 return;
1074 }
1075
1076 PhysicsActor p1;
1077 PhysicsActor p2;
1078
1079 p1ExpectedPoints = 0;
1080 p2ExpectedPoints = 0;
1081
1082 if (!actor_name_map.TryGetValue(g1, out p1))
1083 {
1084 p1 = PANull;
1085 }
1086
1087 if (!actor_name_map.TryGetValue(g2, out p2))
1088 {
1089 p2 = PANull;
1090 }
1091
1092 ContactPoint maxDepthContact = new ContactPoint();
1093 if (p1.CollisionScore + count >= float.MaxValue)
1094 p1.CollisionScore = 0;
1095 p1.CollisionScore += count;
1096
1097 if (p2.CollisionScore + count >= float.MaxValue)
1098 p2.CollisionScore = 0;
1099 p2.CollisionScore += count;
1100
1101 for (int i = 0; i < count; i++)
1102 {
1103 d.ContactGeom curContact = contacts[i];
1104
1105 if (curContact.depth > maxDepthContact.PenetrationDepth)
1106 {
1107 maxDepthContact = new ContactPoint(
1108 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
1109 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
1110 curContact.depth
1111 );
1112 }
1113
1114 //m_log.Warn("[CCOUNT]: " + count);
1115 IntPtr joint;
1116 // If we're colliding with terrain, use 'TerrainContact' instead of contact.
1117 // allows us to have different settings
1118
1119 // We only need to test p2 for 'jump crouch purposes'
1120 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
1121 {
1122 // Testing if the collision is at the feet of the avatar
1123
1124 //m_log.DebugFormat("[PHYSICS]: {0} - {1} - {2} - {3}", curContact.pos.Z, p2.Position.Z, (p2.Position.Z - curContact.pos.Z), (p2.Size.Z * 0.6f));
1125 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
1126 p2.IsColliding = true;
1127 }
1128 else
1129 {
1130 p2.IsColliding = true;
1131 }
1132
1133 //if ((framecount % m_returncollisions) == 0)
1134
1135 switch (p1.PhysicsActorType)
1136 {
1137 case (int)ActorTypes.Agent:
1138 p1ExpectedPoints = avatarExpectedContacts;
1139 p2.CollidingObj = true;
1140 break;
1141 case (int)ActorTypes.Prim:
1142 if (p1 != null && p1 is OdePrim)
1143 p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts;
1144
1145 if (p2.Velocity.LengthSquared() > 0.0f)
1146 p2.CollidingObj = true;
1147 break;
1148 case (int)ActorTypes.Unknown:
1149 p2.CollidingGround = true;
1150 break;
1151 default:
1152 p2.CollidingGround = true;
1153 break;
1154 }
1155
1156 // we don't want prim or avatar to explode
1157
1158 #region InterPenetration Handling - Unintended physics explosions
1159# region disabled code1
1160
1161 if (curContact.depth >= 0.08f)
1162 {
1163 //This is disabled at the moment only because it needs more tweaking
1164 //It will eventually be uncommented
1165 /*
1166 if (contact.depth >= 1.00f)
1167 {
1168 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
1169 }
1170
1171 //If you interpenetrate a prim with an agent
1172 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
1173 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
1174 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
1175 p2.PhysicsActorType == (int) ActorTypes.Prim))
1176 {
1177
1178 //contact.depth = contact.depth * 4.15f;
1179 /*
1180 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
1181 {
1182 p2.CollidingObj = true;
1183 contact.depth = 0.003f;
1184 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
1185 OdeCharacter character = (OdeCharacter) p2;
1186 character.SetPidStatus(true);
1187 contact.pos = new d.Vector3(contact.pos.X + (p1.Size.X / 2), contact.pos.Y + (p1.Size.Y / 2), contact.pos.Z + (p1.Size.Z / 2));
1188
1189 }
1190 else
1191 {
1192
1193 //contact.depth = 0.0000000f;
1194 }
1195 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1196 {
1197
1198 p1.CollidingObj = true;
1199 contact.depth = 0.003f;
1200 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
1201 contact.pos = new d.Vector3(contact.pos.X + (p2.Size.X / 2), contact.pos.Y + (p2.Size.Y / 2), contact.pos.Z + (p2.Size.Z / 2));
1202 OdeCharacter character = (OdeCharacter)p1;
1203 character.SetPidStatus(true);
1204 }
1205 else
1206 {
1207
1208 //contact.depth = 0.0000000f;
1209 }
1210
1211
1212
1213 }
1214*/
1215 // If you interpenetrate a prim with another prim
1216 /*
1217 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
1218 {
1219 #region disabledcode2
1220 //OdePrim op1 = (OdePrim)p1;
1221 //OdePrim op2 = (OdePrim)p2;
1222 //op1.m_collisionscore++;
1223 //op2.m_collisionscore++;
1224
1225 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
1226 //{
1227 //op1.m_taintdisable = true;
1228 //AddPhysicsActorTaint(p1);
1229 //op2.m_taintdisable = true;
1230 //AddPhysicsActorTaint(p2);
1231 //}
1232
1233 //if (contact.depth >= 0.25f)
1234 //{
1235 // Don't collide, one or both prim will expld.
1236
1237 //op1.m_interpenetrationcount++;
1238 //op2.m_interpenetrationcount++;
1239 //interpenetrations_before_disable = 200;
1240 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
1241 //{
1242 //op1.m_taintdisable = true;
1243 //AddPhysicsActorTaint(p1);
1244 //}
1245 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
1246 //{
1247 // op2.m_taintdisable = true;
1248 //AddPhysicsActorTaint(p2);
1249 //}
1250
1251 //contact.depth = contact.depth / 8f;
1252 //contact.normal = new d.Vector3(0, 0, 1);
1253 //}
1254 //if (op1.m_disabled || op2.m_disabled)
1255 //{
1256 //Manually disabled objects stay disabled
1257 //contact.depth = 0f;
1258 //}
1259 #endregion
1260 }
1261 */
1262#endregion
1263 if (curContact.depth >= 1.00f)
1264 {
1265 //m_log.Info("[P]: " + contact.depth.ToString());
1266 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
1267 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
1268 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
1269 p2.PhysicsActorType == (int) ActorTypes.Unknown))
1270 {
1271 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
1272 {
1273 if (p2 is OdeCharacter)
1274 {
1275 OdeCharacter character = (OdeCharacter) p2;
1276
1277 //p2.CollidingObj = true;
1278 curContact.depth = 0.00000003f;
1279 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
1280 curContact.pos =
1281 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1282 curContact.pos.Y + (p1.Size.Y/2),
1283 curContact.pos.Z + (p1.Size.Z/2));
1284 character.SetPidStatus(true);
1285 }
1286 }
1287
1288 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1289 {
1290 if (p1 is OdeCharacter)
1291 {
1292 OdeCharacter character = (OdeCharacter) p1;
1293
1294 //p2.CollidingObj = true;
1295 curContact.depth = 0.00000003f;
1296 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1297 curContact.pos =
1298 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1299 curContact.pos.Y + (p1.Size.Y/2),
1300 curContact.pos.Z + (p1.Size.Z/2));
1301 character.SetPidStatus(true);
1302 }
1303 }
1304 }
1305 }
1306 }
1307
1308 #endregion
1309
1310 // Logic for collision handling
1311 // Note, that if *all* contacts are skipped (VolumeDetect)
1312 // The prim still detects (and forwards) collision events but
1313 // appears to be phantom for the world
1314 Boolean skipThisContact = false;
1315
1316 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1317 skipThisContact = true; // No collision on volume detect prims
1318
1319 if (av_av_collisions_off)
1320 if ((p1 is OdeCharacter) && (p2 is OdeCharacter))
1321 skipThisContact = true;
1322
1323 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1324 skipThisContact = true; // No collision on volume detect prims
1325
1326 if (!skipThisContact && curContact.depth < 0f)
1327 skipThisContact = true;
1328
1329 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1330 skipThisContact = true;
1331
1332 const int maxContactsbeforedeath = 4000;
1333 joint = IntPtr.Zero;
1334
1335 if (!skipThisContact)
1336 {
1337 _perloopContact.Add(curContact);
1338
1339 if (name1 == "Terrain" || name2 == "Terrain")
1340 {
1341 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1342 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1343 {
1344 p2ExpectedPoints = avatarExpectedContacts;
1345 // Avatar is moving on terrain, use the movement terrain contact
1346 AvatarMovementTerrainContact.geom = curContact;
1347
1348 if (m_global_contactcount < maxContactsbeforedeath)
1349 {
1350 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1351 m_global_contactcount++;
1352 }
1353 }
1354 else
1355 {
1356 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1357 {
1358 p2ExpectedPoints = avatarExpectedContacts;
1359 // Avatar is standing on terrain, use the non moving terrain contact
1360 TerrainContact.geom = curContact;
1361
1362 if (m_global_contactcount < maxContactsbeforedeath)
1363 {
1364 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1365 m_global_contactcount++;
1366 }
1367 }
1368 else
1369 {
1370 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1371 {
1372 // prim prim contact
1373 // int pj294950 = 0;
1374 int movintYN = 0;
1375 int material = (int) Material.Wood;
1376 // prim terrain contact
1377 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1378 {
1379 movintYN = 1;
1380 }
1381
1382 if (p2 is OdePrim)
1383 {
1384 material = ((OdePrim) p2).m_material;
1385 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1386 }
1387
1388 // Unnessesary because p1 is defined above
1389 //if (p1 is OdePrim)
1390 // {
1391 // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts;
1392 // }
1393 //m_log.DebugFormat("Material: {0}", material);
1394
1395 m_materialContacts[material, movintYN].geom = curContact;
1396
1397 if (m_global_contactcount < maxContactsbeforedeath)
1398 {
1399 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1400 m_global_contactcount++;
1401 }
1402 }
1403 else
1404 {
1405 int movintYN = 0;
1406 // prim terrain contact
1407 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1408 {
1409 movintYN = 1;
1410 }
1411
1412 int material = (int)Material.Wood;
1413
1414 if (p2 is OdePrim)
1415 {
1416 material = ((OdePrim)p2).m_material;
1417 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1418 }
1419
1420 //m_log.DebugFormat("Material: {0}", material);
1421 m_materialContacts[material, movintYN].geom = curContact;
1422
1423 if (m_global_contactcount < maxContactsbeforedeath)
1424 {
1425 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1426 m_global_contactcount++;
1427 }
1428 }
1429 }
1430 }
1431 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1432 //{
1433 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1434 //}
1435 }
1436 else if (name1 == "Water" || name2 == "Water")
1437 {
1438 /*
1439 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1440 {
1441 }
1442 else
1443 {
1444 }
1445 */
1446 //WaterContact.surface.soft_cfm = 0.0000f;
1447 //WaterContact.surface.soft_erp = 0.00000f;
1448 if (curContact.depth > 0.1f)
1449 {
1450 curContact.depth *= 52;
1451 //contact.normal = new d.Vector3(0, 0, 1);
1452 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1453 }
1454
1455 WaterContact.geom = curContact;
1456
1457 if (m_global_contactcount < maxContactsbeforedeath)
1458 {
1459 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1460 m_global_contactcount++;
1461 }
1462 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1463 }
1464 else
1465 {
1466 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1467 {
1468 p2ExpectedPoints = avatarExpectedContacts;
1469 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1470 {
1471 // Avatar is moving on a prim, use the Movement prim contact
1472 AvatarMovementprimContact.geom = curContact;
1473
1474 if (m_global_contactcount < maxContactsbeforedeath)
1475 {
1476 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1477 m_global_contactcount++;
1478 }
1479 }
1480 else
1481 {
1482 // Avatar is standing still on a prim, use the non movement contact
1483 contact.geom = curContact;
1484
1485 if (m_global_contactcount < maxContactsbeforedeath)
1486 {
1487 joint = d.JointCreateContact(world, contactgroup, ref contact);
1488 m_global_contactcount++;
1489 }
1490 }
1491 }
1492 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1493 {
1494 //p1.PhysicsActorType
1495 int material = (int)Material.Wood;
1496
1497 if (p2 is OdePrim)
1498 {
1499 material = ((OdePrim)p2).m_material;
1500 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1501 }
1502
1503 //m_log.DebugFormat("Material: {0}", material);
1504 m_materialContacts[material, 0].geom = curContact;
1505
1506 if (m_global_contactcount < maxContactsbeforedeath)
1507 {
1508 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1509 m_global_contactcount++;
1510 }
1511 }
1512 }
1513
1514 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1515 {
1516 d.JointAttach(joint, b1, b2);
1517 m_global_contactcount++;
1518 }
1519 }
1520
1521 collision_accounting_events(p1, p2, maxDepthContact);
1522
1523 if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle))
1524 {
1525 // If there are more then 3 contact points, it's likely
1526 // that we've got a pile of objects, so ...
1527 // We don't want to send out hundreds of terse updates over and over again
1528 // so lets throttle them and send them again after it's somewhat sorted out.
1529 p2.ThrottleUpdates = true;
1530 }
1531 //m_log.Debug(count.ToString());
1532 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1533 }
1534 }
1535
1536 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1537 {
1538 if (!m_filterCollisions)
1539 return false;
1540
1541 bool result = false;
1542
1543 ActorTypes at = (ActorTypes)atype;
1544
1545 foreach (d.ContactGeom contact in _perloopContact)
1546 {
1547 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1548 //{
1549 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1550 if (at == ActorTypes.Agent)
1551 {
1552 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f)
1553 && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f)
1554 && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
1555 {
1556 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1557 {
1558 //contactGeom.depth *= .00005f;
1559 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1560 // m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1561 result = true;
1562 break;
1563 }
1564// else
1565// {
1566// //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1567// }
1568 }
1569// else
1570// {
1571// //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1572// //int i = 0;
1573// }
1574 }
1575 else if (at == ActorTypes.Prim)
1576 {
1577 //d.AABB aabb1 = new d.AABB();
1578 //d.AABB aabb2 = new d.AABB();
1579
1580 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1581 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1582 //aabb1.
1583 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f) && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f) && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
1584 {
1585 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1586 {
1587 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1588 {
1589 result = true;
1590 break;
1591 }
1592 }
1593 //m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1594 //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z));
1595 }
1596 }
1597 }
1598
1599 return result;
1600 }
1601
1602 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1603 {
1604 // obj1LocalID = 0;
1605 //returncollisions = false;
1606 obj2LocalID = 0;
1607 //ctype = 0;
1608 //cStartStop = 0;
1609 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1610 return;
1611
1612 switch ((ActorTypes)p2.PhysicsActorType)
1613 {
1614 case ActorTypes.Agent:
1615 cc2 = (OdeCharacter)p2;
1616
1617 // obj1LocalID = cc2.m_localID;
1618 switch ((ActorTypes)p1.PhysicsActorType)
1619 {
1620 case ActorTypes.Agent:
1621 cc1 = (OdeCharacter)p1;
1622 obj2LocalID = cc1.LocalID;
1623 cc1.AddCollisionEvent(cc2.LocalID, contact);
1624 //ctype = (int)CollisionCategories.Character;
1625
1626 //if (cc1.CollidingObj)
1627 //cStartStop = (int)StatusIndicators.Generic;
1628 //else
1629 //cStartStop = (int)StatusIndicators.Start;
1630
1631 //returncollisions = true;
1632 break;
1633
1634 case ActorTypes.Prim:
1635 if (p1 is OdePrim)
1636 {
1637 cp1 = (OdePrim) p1;
1638 obj2LocalID = cp1.LocalID;
1639 cp1.AddCollisionEvent(cc2.LocalID, contact);
1640 }
1641 //ctype = (int)CollisionCategories.Geom;
1642
1643 //if (cp1.CollidingObj)
1644 //cStartStop = (int)StatusIndicators.Generic;
1645 //else
1646 //cStartStop = (int)StatusIndicators.Start;
1647
1648 //returncollisions = true;
1649 break;
1650
1651 case ActorTypes.Ground:
1652 case ActorTypes.Unknown:
1653 obj2LocalID = 0;
1654 //ctype = (int)CollisionCategories.Land;
1655 //returncollisions = true;
1656 break;
1657 }
1658
1659 cc2.AddCollisionEvent(obj2LocalID, contact);
1660 break;
1661
1662 case ActorTypes.Prim:
1663
1664 if (p2 is OdePrim)
1665 {
1666 cp2 = (OdePrim) p2;
1667
1668 // obj1LocalID = cp2.m_localID;
1669 switch ((ActorTypes) p1.PhysicsActorType)
1670 {
1671 case ActorTypes.Agent:
1672 if (p1 is OdeCharacter)
1673 {
1674 cc1 = (OdeCharacter) p1;
1675 obj2LocalID = cc1.LocalID;
1676 cc1.AddCollisionEvent(cp2.LocalID, contact);
1677 //ctype = (int)CollisionCategories.Character;
1678
1679 //if (cc1.CollidingObj)
1680 //cStartStop = (int)StatusIndicators.Generic;
1681 //else
1682 //cStartStop = (int)StatusIndicators.Start;
1683 //returncollisions = true;
1684 }
1685 break;
1686 case ActorTypes.Prim:
1687
1688 if (p1 is OdePrim)
1689 {
1690 cp1 = (OdePrim) p1;
1691 obj2LocalID = cp1.LocalID;
1692 cp1.AddCollisionEvent(cp2.LocalID, contact);
1693 //ctype = (int)CollisionCategories.Geom;
1694
1695 //if (cp1.CollidingObj)
1696 //cStartStop = (int)StatusIndicators.Generic;
1697 //else
1698 //cStartStop = (int)StatusIndicators.Start;
1699
1700 //returncollisions = true;
1701 }
1702 break;
1703
1704 case ActorTypes.Ground:
1705 case ActorTypes.Unknown:
1706 obj2LocalID = 0;
1707 //ctype = (int)CollisionCategories.Land;
1708
1709 //returncollisions = true;
1710 break;
1711 }
1712
1713 cp2.AddCollisionEvent(obj2LocalID, contact);
1714 }
1715 break;
1716 }
1717 //if (returncollisions)
1718 //{
1719
1720 //lock (m_storedCollisions)
1721 //{
1722 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1723 //if (m_storedCollisions.ContainsKey(cDictKey))
1724 //{
1725 //sCollisionData objd = m_storedCollisions[cDictKey];
1726 //objd.NumberOfCollisions += 1;
1727 //objd.lastframe = framecount;
1728 //m_storedCollisions[cDictKey] = objd;
1729 //}
1730 //else
1731 //{
1732 //sCollisionData objd = new sCollisionData();
1733 //objd.ColliderLocalId = obj1LocalID;
1734 //objd.CollidedWithLocalId = obj2LocalID;
1735 //objd.CollisionType = ctype;
1736 //objd.NumberOfCollisions = 1;
1737 //objd.lastframe = framecount;
1738 //objd.StatusIndicator = cStartStop;
1739 //m_storedCollisions.Add(cDictKey, objd);
1740 //}
1741 //}
1742 // }
1743 }
1744
1745 private int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1746 {
1747 /* String name1 = null;
1748 String name2 = null;
1749
1750 if (!geom_name_map.TryGetValue(trimesh, out name1))
1751 {
1752 name1 = "null";
1753 }
1754 if (!geom_name_map.TryGetValue(refObject, out name2))
1755 {
1756 name2 = "null";
1757 }
1758
1759 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1760 */
1761 return 1;
1762 }
1763
1764 private int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1765 {
1766// String name1 = null;
1767// String name2 = null;
1768//
1769// if (!geom_name_map.TryGetValue(trimesh, out name1))
1770// {
1771// name1 = "null";
1772// }
1773//
1774// if (!geom_name_map.TryGetValue(refObject, out name2))
1775// {
1776// name2 = "null";
1777// }
1778
1779 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1780
1781 d.Vector3 v0 = new d.Vector3();
1782 d.Vector3 v1 = new d.Vector3();
1783 d.Vector3 v2 = new d.Vector3();
1784
1785 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1786 // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
1787
1788 return 1;
1789 }
1790
1791 /// <summary>
1792 /// This is our collision testing routine in ODE
1793 /// </summary>
1794 private void collision_optimized()
1795 {
1796 _perloopContact.Clear();
1797
1798 foreach (OdeCharacter chr in _characters)
1799 {
1800 // Reset the collision values to false
1801 // since we don't know if we're colliding yet
1802 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1803 continue;
1804
1805 chr.IsColliding = false;
1806 chr.CollidingGround = false;
1807 chr.CollidingObj = false;
1808
1809 // Test the avatar's geometry for collision with the space
1810 // This will return near and the space that they are the closest to
1811 // And we'll run this again against the avatar and the space segment
1812 // This will return with a bunch of possible objects in the space segment
1813 // and we'll run it again on all of them.
1814 try
1815 {
1816 CollideSpaces(space, chr.Shell, IntPtr.Zero);
1817 }
1818 catch (AccessViolationException)
1819 {
1820 m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", Name);
1821 }
1822
1823 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1824 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1825 //{
1826 //chr.Position.Z = terrainheight + 10.0f;
1827 //forcedZ = true;
1828 //}
1829 }
1830
1831 if (CollectStats)
1832 {
1833 m_tempAvatarCollisionsThisFrame = _perloopContact.Count;
1834 m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame;
1835 }
1836
1837 List<OdePrim> removeprims = null;
1838 foreach (OdePrim chr in _activeprims)
1839 {
1840 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1841 {
1842 try
1843 {
1844 lock (chr)
1845 {
1846 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1847 {
1848 CollideSpaces(space, chr.prim_geom, IntPtr.Zero);
1849 }
1850 else
1851 {
1852 if (removeprims == null)
1853 {
1854 removeprims = new List<OdePrim>();
1855 }
1856 removeprims.Add(chr);
1857 m_log.Error(
1858 "[ODE SCENE]: unable to collide test active prim against space. The space was zero, the geom was zero or it was in the process of being removed. Removed it from the active prim list. This needs to be fixed!");
1859 }
1860 }
1861 }
1862 catch (AccessViolationException)
1863 {
1864 m_log.Error("[ODE SCENE]: Unable to space collide");
1865 }
1866 }
1867 }
1868
1869 if (CollectStats)
1870 m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame;
1871
1872 if (removeprims != null)
1873 {
1874 foreach (OdePrim chr in removeprims)
1875 {
1876 _activeprims.Remove(chr);
1877 }
1878 }
1879 }
1880
1881 #endregion
1882
1883 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1884 {
1885 m_worldOffset = offset;
1886 WorldExtents = new Vector2(extents.X, extents.Y);
1887 m_parentScene = pScene;
1888 }
1889
1890 // Recovered for use by fly height. Kitto Flora
1891 internal float GetTerrainHeightAtXY(float x, float y)
1892 {
1893 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1894 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1895
1896 IntPtr heightFieldGeom = IntPtr.Zero;
1897
1898 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1899 {
1900 if (heightFieldGeom != IntPtr.Zero)
1901 {
1902 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1903 {
1904
1905 int index;
1906
1907
1908 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1909 (int)x < 0.001f || (int)y < 0.001f)
1910 return 0;
1911
1912 x = x - offsetX;
1913 y = y - offsetY;
1914
1915 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1916
1917 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1918 {
1919 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1920 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1921 }
1922
1923 else
1924 return 0f;
1925 }
1926 else
1927 {
1928 return 0f;
1929 }
1930
1931 }
1932 else
1933 {
1934 return 0f;
1935 }
1936
1937 }
1938 else
1939 {
1940 return 0f;
1941 }
1942 }
1943// End recovered. Kitto Flora
1944
1945 /// <summary>
1946 /// Add actor to the list that should receive collision events in the simulate loop.
1947 /// </summary>
1948 /// <param name="obj"></param>
1949 internal void AddCollisionEventReporting(PhysicsActor obj)
1950 {
1951// m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID);
1952
1953 lock (m_collisionEventActorsChanges)
1954 m_collisionEventActorsChanges[obj.LocalID] = obj;
1955 }
1956
1957 /// <summary>
1958 /// Remove actor from the list that should receive collision events in the simulate loop.
1959 /// </summary>
1960 /// <param name="obj"></param>
1961 internal void RemoveCollisionEventReporting(PhysicsActor obj)
1962 {
1963// m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID);
1964
1965 lock (m_collisionEventActorsChanges)
1966 m_collisionEventActorsChanges[obj.LocalID] = null;
1967 }
1968
1969 #region Add/Remove Entities
1970
1971 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
1972 {
1973 Vector3 pos;
1974 pos.X = position.X;
1975 pos.Y = position.Y;
1976 pos.Z = position.Z;
1977
1978 OdeCharacter newAv
1979 = new OdeCharacter(
1980 avName, this, pos, size, avPIDD, avPIDP,
1981 avCapRadius, avStandupTensor, avDensity,
1982 avMovementDivisorWalk, avMovementDivisorRun);
1983
1984 newAv.Flying = isFlying;
1985 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1986 newAv.m_avatarplanted = avplanted;
1987
1988 return newAv;
1989 }
1990
1991 public override void RemoveAvatar(PhysicsActor actor)
1992 {
1993// m_log.DebugFormat(
1994// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}",
1995// actor.Name, actor.LocalID, Name);
1996
1997 ((OdeCharacter) actor).Destroy();
1998 }
1999
2000 internal void AddCharacter(OdeCharacter chr)
2001 {
2002 chr.m_avatarplanted = avplanted;
2003 if (!_characters.Contains(chr))
2004 {
2005 _characters.Add(chr);
2006
2007// m_log.DebugFormat(
2008// "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}",
2009// chr.Name, chr.LocalID, Name, _characters.Count);
2010
2011 if (chr.bad)
2012 m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to characters list", chr.m_uuid);
2013 }
2014 else
2015 {
2016 m_log.ErrorFormat(
2017 "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!",
2018 chr.Name, chr.LocalID);
2019 }
2020 }
2021
2022 internal void RemoveCharacter(OdeCharacter chr)
2023 {
2024 if (_characters.Contains(chr))
2025 {
2026 _characters.Remove(chr);
2027
2028// m_log.DebugFormat(
2029// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}",
2030// chr.Name, chr.LocalID, Name, _characters.Count);
2031 }
2032 else
2033 {
2034 m_log.ErrorFormat(
2035 "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!",
2036 chr.Name, chr.LocalID);
2037 }
2038 }
2039
2040 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
2041 PrimitiveBaseShape pbs, bool isphysical, uint localID)
2042 {
2043 Vector3 pos = position;
2044 Vector3 siz = size;
2045 Quaternion rot = rotation;
2046
2047 OdePrim newPrim;
2048 lock (OdeLock)
2049 {
2050 newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical);
2051
2052 lock (_prims)
2053 _prims.Add(newPrim);
2054 }
2055 newPrim.LocalID = localID;
2056 return newPrim;
2057 }
2058
2059 /// <summary>
2060 /// Make this prim subject to physics.
2061 /// </summary>
2062 /// <param name="prim"></param>
2063 internal void ActivatePrim(OdePrim prim)
2064 {
2065 // adds active prim.. (ones that should be iterated over in collisions_optimized
2066 if (!_activeprims.Contains(prim))
2067 _activeprims.Add(prim);
2068 //else
2069 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
2070 }
2071
2072 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
2073 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
2074 {
2075// m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name);
2076
2077 return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid);
2078 }
2079
2080 public override float TimeDilation
2081 {
2082 get { return m_timeDilation; }
2083 }
2084
2085 public override bool SupportsNINJAJoints
2086 {
2087 get { return m_NINJA_physics_joints_enabled; }
2088 }
2089
2090 // internal utility function: must be called within a lock (OdeLock)
2091 private void InternalAddActiveJoint(PhysicsJoint joint)
2092 {
2093 activeJoints.Add(joint);
2094 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
2095 }
2096
2097 // internal utility function: must be called within a lock (OdeLock)
2098 private void InternalAddPendingJoint(OdePhysicsJoint joint)
2099 {
2100 pendingJoints.Add(joint);
2101 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
2102 }
2103
2104 // internal utility function: must be called within a lock (OdeLock)
2105 private void InternalRemovePendingJoint(PhysicsJoint joint)
2106 {
2107 pendingJoints.Remove(joint);
2108 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
2109 }
2110
2111 // internal utility function: must be called within a lock (OdeLock)
2112 private void InternalRemoveActiveJoint(PhysicsJoint joint)
2113 {
2114 activeJoints.Remove(joint);
2115 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
2116 }
2117
2118 public override void DumpJointInfo()
2119 {
2120 string hdr = "[NINJA] JOINTINFO: ";
2121 foreach (PhysicsJoint j in pendingJoints)
2122 {
2123 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
2124 }
2125 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
2126 foreach (string jointName in SOPName_to_pendingJoint.Keys)
2127 {
2128 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
2129 }
2130 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
2131 foreach (PhysicsJoint j in activeJoints)
2132 {
2133 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
2134 }
2135 m_log.Debug(hdr + activeJoints.Count + " total active joints");
2136 foreach (string jointName in SOPName_to_activeJoint.Keys)
2137 {
2138 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
2139 }
2140 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
2141
2142 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
2143 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
2144 foreach (string actorName in joints_connecting_actor.Keys)
2145 {
2146 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
2147 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
2148 {
2149 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
2150 }
2151 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
2152 }
2153 }
2154
2155 public override void RequestJointDeletion(string ObjectNameInScene)
2156 {
2157 lock (externalJointRequestsLock)
2158 {
2159 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
2160 {
2161 requestedJointsToBeDeleted.Add(ObjectNameInScene);
2162 }
2163 }
2164 }
2165
2166 private void DeleteRequestedJoints()
2167 {
2168 List<string> myRequestedJointsToBeDeleted;
2169 lock (externalJointRequestsLock)
2170 {
2171 // make a local copy of the shared list for processing (threading issues)
2172 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
2173 }
2174
2175 foreach (string jointName in myRequestedJointsToBeDeleted)
2176 {
2177 lock (OdeLock)
2178 {
2179 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
2180 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
2181 {
2182 OdePhysicsJoint joint = null;
2183 if (SOPName_to_activeJoint.ContainsKey(jointName))
2184 {
2185 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
2186 InternalRemoveActiveJoint(joint);
2187 }
2188 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
2189 {
2190 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
2191 InternalRemovePendingJoint(joint);
2192 }
2193
2194 if (joint != null)
2195 {
2196 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
2197 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
2198 {
2199 string bodyName = joint.BodyNames[iBodyName];
2200 if (bodyName != "NULL")
2201 {
2202 joints_connecting_actor[bodyName].Remove(joint);
2203 if (joints_connecting_actor[bodyName].Count == 0)
2204 {
2205 joints_connecting_actor.Remove(bodyName);
2206 }
2207 }
2208 }
2209
2210 DoJointDeactivated(joint);
2211 if (joint.jointID != IntPtr.Zero)
2212 {
2213 d.JointDestroy(joint.jointID);
2214 joint.jointID = IntPtr.Zero;
2215 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
2216 }
2217 else
2218 {
2219 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
2220 }
2221 }
2222 else
2223 {
2224 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
2225 }
2226 }
2227 else
2228 {
2229 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
2230 }
2231 }
2232 }
2233
2234 // remove processed joints from the shared list
2235 lock (externalJointRequestsLock)
2236 {
2237 foreach (string jointName in myRequestedJointsToBeDeleted)
2238 {
2239 requestedJointsToBeDeleted.Remove(jointName);
2240 }
2241 }
2242 }
2243
2244 // for pending joints we don't know if their associated bodies exist yet or not.
2245 // the joint is actually created during processing of the taints
2246 private void CreateRequestedJoints()
2247 {
2248 List<PhysicsJoint> myRequestedJointsToBeCreated;
2249 lock (externalJointRequestsLock)
2250 {
2251 // make a local copy of the shared list for processing (threading issues)
2252 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
2253 }
2254
2255 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2256 {
2257 lock (OdeLock)
2258 {
2259 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
2260 {
2261 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already pending joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
2262 continue;
2263 }
2264 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
2265 {
2266 DoJointErrorMessage(joint, "WARNING: ignoring request to re-add already active joint Name:" + joint.ObjectNameInScene + " type:" + joint.Type + " parms: " + joint.RawParams + " pos: " + joint.Position + " rot:" + joint.Rotation);
2267 continue;
2268 }
2269
2270 InternalAddPendingJoint(joint as OdePhysicsJoint);
2271
2272 if (joint.BodyNames.Count >= 2)
2273 {
2274 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
2275 {
2276 string bodyName = joint.BodyNames[iBodyName];
2277 if (bodyName != "NULL")
2278 {
2279 if (!joints_connecting_actor.ContainsKey(bodyName))
2280 {
2281 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
2282 }
2283 joints_connecting_actor[bodyName].Add(joint);
2284 }
2285 }
2286 }
2287 }
2288 }
2289
2290 // remove processed joints from shared list
2291 lock (externalJointRequestsLock)
2292 {
2293 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2294 {
2295 requestedJointsToBeCreated.Remove(joint);
2296 }
2297 }
2298 }
2299
2300 /// <summary>
2301 /// Add a request for joint creation.
2302 /// </summary>
2303 /// <remarks>
2304 /// this joint will just be added to a waiting list that is NOT processed during the main
2305 /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
2306 /// </remarks>
2307 /// <param name="objectNameInScene"></param>
2308 /// <param name="jointType"></param>
2309 /// <param name="position"></param>
2310 /// <param name="rotation"></param>
2311 /// <param name="parms"></param>
2312 /// <param name="bodyNames"></param>
2313 /// <param name="trackedBodyName"></param>
2314 /// <param name="localRotation"></param>
2315 /// <returns></returns>
2316 public override PhysicsJoint RequestJointCreation(
2317 string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2318 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2319 {
2320 OdePhysicsJoint joint = new OdePhysicsJoint();
2321 joint.ObjectNameInScene = objectNameInScene;
2322 joint.Type = jointType;
2323 joint.Position = position;
2324 joint.Rotation = rotation;
2325 joint.RawParams = parms;
2326 joint.BodyNames = new List<string>(bodyNames);
2327 joint.TrackedBodyName = trackedBodyName;
2328 joint.LocalRotation = localRotation;
2329 joint.jointID = IntPtr.Zero;
2330 joint.ErrorMessageCount = 0;
2331
2332 lock (externalJointRequestsLock)
2333 {
2334 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2335 {
2336 requestedJointsToBeCreated.Add(joint);
2337 }
2338 }
2339
2340 return joint;
2341 }
2342
2343 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2344 {
2345 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2346 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2347 {
2348 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2349 //TODO: merge these 2 loops (originally it was needed to avoid altering a list being iterated over, but it is no longer needed due to the joint request queue mechanism)
2350 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2351 {
2352 jointsToRemove.Add(j);
2353 }
2354 foreach (PhysicsJoint j in jointsToRemove)
2355 {
2356 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2357 RequestJointDeletion(j.ObjectNameInScene);
2358 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2359 j.TrackedBodyName = null; // *IMMEDIATELY* prevent any further movement of this joint (else a deleted actor might cause spurious tracking motion of the joint for a few frames, leading to the joint proxy object disappearing)
2360 }
2361 }
2362 }
2363
2364 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2365 {
2366 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2367 lock (OdeLock)
2368 {
2369 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2370 RemoveAllJointsConnectedToActor(actor);
2371 }
2372 }
2373
2374 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2375 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2376 {
2377 Debug.Assert(joint.IsInPhysicsEngine);
2378 d.Vector3 pos = new d.Vector3();
2379
2380 if (!(joint is OdePhysicsJoint))
2381 {
2382 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2383 }
2384 else
2385 {
2386 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2387 switch (odeJoint.Type)
2388 {
2389 case PhysicsJointType.Ball:
2390 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2391 break;
2392 case PhysicsJointType.Hinge:
2393 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2394 break;
2395 }
2396 }
2397 return new Vector3(pos.X, pos.Y, pos.Z);
2398 }
2399
2400 /// <summary>
2401 /// Get joint axis.
2402 /// </summary>
2403 /// <remarks>
2404 /// normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2405 /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2406 /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2407 /// keeping track of the joint's original orientation relative to one of the involved bodies.
2408 /// </remarks>
2409 /// <param name="joint"></param>
2410 /// <returns></returns>
2411 public override Vector3 GetJointAxis(PhysicsJoint joint)
2412 {
2413 Debug.Assert(joint.IsInPhysicsEngine);
2414 d.Vector3 axis = new d.Vector3();
2415
2416 if (!(joint is OdePhysicsJoint))
2417 {
2418 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2419 }
2420 else
2421 {
2422 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2423 switch (odeJoint.Type)
2424 {
2425 case PhysicsJointType.Ball:
2426 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2427 break;
2428 case PhysicsJointType.Hinge:
2429 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2430 break;
2431 }
2432 }
2433 return new Vector3(axis.X, axis.Y, axis.Z);
2434 }
2435
2436 /// <summary>
2437 /// Stop this prim being subject to physics
2438 /// </summary>
2439 /// <param name="prim"></param>
2440 internal void DeactivatePrim(OdePrim prim)
2441 {
2442 _activeprims.Remove(prim);
2443 }
2444
2445 public override void RemovePrim(PhysicsActor prim)
2446 {
2447 // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be
2448 // removed in the next physics simulate pass.
2449 if (prim is OdePrim)
2450 {
2451 lock (OdeLock)
2452 {
2453 OdePrim p = (OdePrim) prim;
2454
2455 p.setPrimForRemoval();
2456 AddPhysicsActorTaint(prim);
2457 }
2458 }
2459 }
2460
2461 /// <summary>
2462 /// This is called from within simulate but outside the locked portion
2463 /// We need to do our own locking here
2464 /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in
2465 /// Simulate() -- justincc).
2466 ///
2467 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2468 ///
2469 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2470 /// that the space was using.
2471 /// </summary>
2472 /// <param name="prim"></param>
2473 internal void RemovePrimThreadLocked(OdePrim prim)
2474 {
2475// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID);
2476
2477 lock (prim)
2478 {
2479 RemoveCollisionEventReporting(prim);
2480
2481 if (prim.prim_geom != IntPtr.Zero)
2482 {
2483 prim.ResetTaints();
2484
2485 if (prim.IsPhysical)
2486 {
2487 prim.disableBody();
2488 if (prim.childPrim)
2489 {
2490 prim.childPrim = false;
2491 prim.Body = IntPtr.Zero;
2492 prim.m_disabled = true;
2493 prim.IsPhysical = false;
2494 }
2495
2496
2497 }
2498 // we don't want to remove the main space
2499
2500 // If the geometry is in the targetspace, remove it from the target space
2501 //m_log.Warn(prim.m_targetSpace);
2502
2503 //if (prim.m_targetSpace != IntPtr.Zero)
2504 //{
2505 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2506 //{
2507
2508 //if (d.GeomIsSpace(prim.m_targetSpace))
2509 //{
2510 //waitForSpaceUnlock(prim.m_targetSpace);
2511 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2512 prim.m_targetSpace = IntPtr.Zero;
2513 //}
2514 //else
2515 //{
2516 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2517 //((OdePrim)prim).m_targetSpace.ToString());
2518 //}
2519
2520 //}
2521 //}
2522 //m_log.Warn(prim.prim_geom);
2523
2524 if (!prim.RemoveGeom())
2525 m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene");
2526
2527 lock (_prims)
2528 _prims.Remove(prim);
2529
2530 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2531 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2532 //{
2533 //if (prim.m_targetSpace != null)
2534 //{
2535 //if (d.GeomIsSpace(prim.m_targetSpace))
2536 //{
2537 //waitForSpaceUnlock(prim.m_targetSpace);
2538 //d.SpaceRemove(space, prim.m_targetSpace);
2539 // free up memory used by the space.
2540 //d.SpaceDestroy(prim.m_targetSpace);
2541 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2542 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2543 //}
2544 //else
2545 //{
2546 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2547 //((OdePrim) prim).m_targetSpace.ToString());
2548 //}
2549 //}
2550 //}
2551
2552 if (SupportsNINJAJoints)
2553 RemoveAllJointsConnectedToActorThreadLocked(prim);
2554 }
2555 }
2556 }
2557
2558 #endregion
2559
2560 #region Space Separation Calculation
2561
2562 /// <summary>
2563 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2564 /// </summary>
2565 /// <param name="pSpace"></param>
2566 private void resetSpaceArrayItemToZero(IntPtr pSpace)
2567 {
2568 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2569 {
2570 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2571 {
2572 if (staticPrimspace[x, y] == pSpace)
2573 staticPrimspace[x, y] = IntPtr.Zero;
2574 }
2575 }
2576 }
2577
2578// private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2579// {
2580// staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2581// }
2582
2583 /// <summary>
2584 /// Called when a static prim moves. Allocates a space for the prim based on its position
2585 /// </summary>
2586 /// <param name="geom">the pointer to the geom that moved</param>
2587 /// <param name="pos">the position that the geom moved to</param>
2588 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2589 /// <returns>a pointer to the new space it's in</returns>
2590 internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2591 {
2592 // Called from setting the Position and Size of an ODEPrim so
2593 // it's already in locked space.
2594
2595 // we don't want to remove the main space
2596 // we don't need to test physical here because this function should
2597 // never be called if the prim is physical(active)
2598
2599 // All physical prim end up in the root space
2600 //Thread.Sleep(20);
2601 if (currentspace != space)
2602 {
2603 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2604 //if (currentspace == IntPtr.Zero)
2605 //{
2606 //int adfadf = 0;
2607 //}
2608 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2609 {
2610 if (d.GeomIsSpace(currentspace))
2611 {
2612// waitForSpaceUnlock(currentspace);
2613 d.SpaceRemove(currentspace, geom);
2614 }
2615 else
2616 {
2617 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2618 " Geom:" + geom);
2619 }
2620 }
2621 else
2622 {
2623 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2624 if (sGeomIsIn != IntPtr.Zero)
2625 {
2626 if (d.GeomIsSpace(currentspace))
2627 {
2628// waitForSpaceUnlock(sGeomIsIn);
2629 d.SpaceRemove(sGeomIsIn, geom);
2630 }
2631 else
2632 {
2633 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2634 sGeomIsIn + " Geom:" + geom);
2635 }
2636 }
2637 }
2638
2639 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2640 if (d.SpaceGetNumGeoms(currentspace) == 0)
2641 {
2642 if (currentspace != IntPtr.Zero)
2643 {
2644 if (d.GeomIsSpace(currentspace))
2645 {
2646// waitForSpaceUnlock(currentspace);
2647// waitForSpaceUnlock(space);
2648 d.SpaceRemove(space, currentspace);
2649 // free up memory used by the space.
2650
2651 //d.SpaceDestroy(currentspace);
2652 resetSpaceArrayItemToZero(currentspace);
2653 }
2654 else
2655 {
2656 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2657 currentspace + " Geom:" + geom);
2658 }
2659 }
2660 }
2661 }
2662 else
2663 {
2664 // this is a physical object that got disabled. ;.;
2665 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2666 {
2667 if (d.SpaceQuery(currentspace, geom))
2668 {
2669 if (d.GeomIsSpace(currentspace))
2670 {
2671// waitForSpaceUnlock(currentspace);
2672 d.SpaceRemove(currentspace, geom);
2673 }
2674 else
2675 {
2676 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2677 currentspace + " Geom:" + geom);
2678 }
2679 }
2680 else
2681 {
2682 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2683 if (sGeomIsIn != IntPtr.Zero)
2684 {
2685 if (d.GeomIsSpace(sGeomIsIn))
2686 {
2687// waitForSpaceUnlock(sGeomIsIn);
2688 d.SpaceRemove(sGeomIsIn, geom);
2689 }
2690 else
2691 {
2692 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2693 sGeomIsIn + " Geom:" + geom);
2694 }
2695 }
2696 }
2697 }
2698 }
2699
2700 // The routines in the Position and Size sections do the 'inserting' into the space,
2701 // so all we have to do is make sure that the space that we're putting the prim into
2702 // is in the 'main' space.
2703 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2704 IntPtr newspace = calculateSpaceForGeom(pos);
2705
2706 if (newspace == IntPtr.Zero)
2707 {
2708 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2709 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2710 }
2711
2712 return newspace;
2713 }
2714
2715 /// <summary>
2716 /// Creates a new space at X Y
2717 /// </summary>
2718 /// <param name="iprimspaceArrItemX"></param>
2719 /// <param name="iprimspaceArrItemY"></param>
2720 /// <returns>A pointer to the created space</returns>
2721 internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2722 {
2723 // creating a new space for prim and inserting it into main space.
2724 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2725 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2726// waitForSpaceUnlock(space);
2727 d.SpaceSetSublevel(space, 1);
2728 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2729
2730 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2731 }
2732
2733 /// <summary>
2734 /// Calculates the space the prim should be in by its position
2735 /// </summary>
2736 /// <param name="pos"></param>
2737 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2738 internal IntPtr calculateSpaceForGeom(Vector3 pos)
2739 {
2740 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2741 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2742 return staticPrimspace[xyspace[0], xyspace[1]];
2743 }
2744
2745 /// <summary>
2746 /// Holds the space allocation logic
2747 /// </summary>
2748 /// <param name="pos"></param>
2749 /// <returns>an array item based on the position</returns>
2750 internal int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2751 {
2752 int[] returnint = new int[2];
2753
2754 returnint[0] = (int) (pos.X/metersInSpace);
2755
2756 if (returnint[0] > ((int) (259f/metersInSpace)))
2757 returnint[0] = ((int) (259f/metersInSpace));
2758 if (returnint[0] < 0)
2759 returnint[0] = 0;
2760
2761 returnint[1] = (int) (pos.Y/metersInSpace);
2762 if (returnint[1] > ((int) (259f/metersInSpace)))
2763 returnint[1] = ((int) (259f/metersInSpace));
2764 if (returnint[1] < 0)
2765 returnint[1] = 0;
2766
2767 return returnint;
2768 }
2769
2770 #endregion
2771
2772 /// <summary>
2773 /// Routine to figure out if we need to mesh this prim with our mesher
2774 /// </summary>
2775 /// <param name="pbs"></param>
2776 /// <returns></returns>
2777 internal bool needsMeshing(PrimitiveBaseShape pbs)
2778 {
2779 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2780 // but we still need to check for sculptie meshing being enabled so this is the most
2781 // convenient place to do it for now...
2782
2783 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2784 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2785 int iPropertiesNotSupportedDefault = 0;
2786
2787 if (pbs.SculptEntry && !meshSculptedPrim)
2788 {
2789#if SPAM
2790 m_log.Warn("NonMesh");
2791#endif
2792 return false;
2793 }
2794
2795 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since ODE can use an internal representation for the prim
2796 if (!forceSimplePrimMeshing && !pbs.SculptEntry)
2797 {
2798 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2799 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2800 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2801 {
2802
2803 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2804 && pbs.ProfileHollow == 0
2805 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2806 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2807 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2808 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2809 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2810 {
2811#if SPAM
2812 m_log.Warn("NonMesh");
2813#endif
2814 return false;
2815 }
2816 }
2817 }
2818
2819 if (pbs.ProfileHollow != 0)
2820 iPropertiesNotSupportedDefault++;
2821
2822 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2823 iPropertiesNotSupportedDefault++;
2824
2825 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2826 iPropertiesNotSupportedDefault++;
2827
2828 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2829 iPropertiesNotSupportedDefault++;
2830
2831 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2832 iPropertiesNotSupportedDefault++;
2833
2834 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2835 iPropertiesNotSupportedDefault++;
2836
2837 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2838 iPropertiesNotSupportedDefault++;
2839
2840 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
2841 iPropertiesNotSupportedDefault++;
2842
2843 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2844 iPropertiesNotSupportedDefault++;
2845
2846 // test for torus
2847 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2848 {
2849 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2850 {
2851 iPropertiesNotSupportedDefault++;
2852 }
2853 }
2854 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2855 {
2856 if (pbs.PathCurve == (byte)Extrusion.Straight)
2857 {
2858 iPropertiesNotSupportedDefault++;
2859 }
2860
2861 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2862 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2863 {
2864 iPropertiesNotSupportedDefault++;
2865 }
2866 }
2867 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2868 {
2869 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2870 {
2871 iPropertiesNotSupportedDefault++;
2872 }
2873 }
2874 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2875 {
2876 if (pbs.PathCurve == (byte)Extrusion.Straight)
2877 {
2878 iPropertiesNotSupportedDefault++;
2879 }
2880 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2881 {
2882 iPropertiesNotSupportedDefault++;
2883 }
2884 }
2885
2886 if (pbs.SculptEntry && meshSculptedPrim)
2887 iPropertiesNotSupportedDefault++;
2888
2889 if (iPropertiesNotSupportedDefault == 0)
2890 {
2891#if SPAM
2892 m_log.Warn("NonMesh");
2893#endif
2894 return false;
2895 }
2896#if SPAM
2897 m_log.Debug("Mesh");
2898#endif
2899 return true;
2900 }
2901
2902 /// <summary>
2903 /// Called after our prim properties are set Scale, position etc.
2904 /// </summary>
2905 /// <remarks>
2906 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2907 /// This assures us that we have no race conditions
2908 /// </remarks>
2909 /// <param name="actor"></param>
2910 public override void AddPhysicsActorTaint(PhysicsActor actor)
2911 {
2912 if (actor is OdePrim)
2913 {
2914 OdePrim taintedprim = ((OdePrim)actor);
2915 lock (_taintedPrims)
2916 _taintedPrims.Add(taintedprim);
2917 }
2918 else if (actor is OdeCharacter)
2919 {
2920 OdeCharacter taintedchar = ((OdeCharacter)actor);
2921 lock (_taintedActors)
2922 {
2923 _taintedActors.Add(taintedchar);
2924 if (taintedchar.bad)
2925 m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2926 }
2927 }
2928 }
2929
2930 /// <summary>
2931 /// This is our main simulate loop
2932 /// </summary>
2933 /// <remarks>
2934 /// It's thread locked by a Mutex in the scene.
2935 /// It holds Collisions, it instructs ODE to step through the physical reactions
2936 /// It moves the objects around in memory
2937 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2938 /// </remarks>
2939 /// <param name="timeStep"></param>
2940 /// <returns>The number of frames simulated over that period.</returns>
2941 public override float Simulate(float timeStep)
2942 {
2943 if (!_worldInitialized) return 11f;
2944
2945 int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0;
2946 int tempTick = 0, tempTick2 = 0;
2947
2948 if (framecount >= int.MaxValue)
2949 framecount = 0;
2950
2951 framecount++;
2952
2953 float fps = 0;
2954
2955 float timeLeft = timeStep;
2956
2957 //m_log.Info(timeStep.ToString());
2958// step_time += timeSte
2959//
2960// // If We're loaded down by something else,
2961// // or debugging with the Visual Studio project on pause
2962// // skip a few frames to catch up gracefully.
2963// // without shooting the physicsactors all over the place
2964//
2965// if (step_time >= m_SkipFramesAtms)
2966// {
2967// // Instead of trying to catch up, it'll do 5 physics frames only
2968// step_time = ODE_STEPSIZE;
2969// m_physicsiterations = 5;
2970// }
2971// else
2972// {
2973// m_physicsiterations = 10;
2974// }
2975
2976 // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential
2977 // deadlock if the collision event tries to lock something else later on which is already locked by a
2978 // caller that is adding or removing the collision event.
2979 lock (m_collisionEventActorsChanges)
2980 {
2981 foreach (KeyValuePair<uint, PhysicsActor> kvp in m_collisionEventActorsChanges)
2982 {
2983 if (kvp.Value == null)
2984 m_collisionEventActors.Remove(kvp.Key);
2985 else
2986 m_collisionEventActors[kvp.Key] = kvp.Value;
2987 }
2988
2989 m_collisionEventActorsChanges.Clear();
2990 }
2991
2992 if (SupportsNINJAJoints)
2993 {
2994 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2995 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2996 }
2997
2998 lock (OdeLock)
2999 {
3000 // Process 10 frames if the sim is running normal..
3001 // process 5 frames if the sim is running slow
3002 //try
3003 //{
3004 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
3005 //}
3006 //catch (StackOverflowException)
3007 //{
3008 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
3009 // ode.drelease(world);
3010 //base.TriggerPhysicsBasedRestart();
3011 //}
3012
3013 // Figure out the Frames Per Second we're going at.
3014 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
3015
3016 fps = (timeStep / ODE_STEPSIZE) * 1000;
3017 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
3018 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
3019
3020 while (timeLeft > 0.0f)
3021 {
3022 try
3023 {
3024 if (CollectStats)
3025 tempTick = Util.EnvironmentTickCount();
3026
3027 lock (_taintedActors)
3028 {
3029 foreach (OdeCharacter character in _taintedActors)
3030 character.ProcessTaints();
3031
3032 _taintedActors.Clear();
3033 }
3034
3035 if (CollectStats)
3036 {
3037 tempTick2 = Util.EnvironmentTickCount();
3038 m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3039 tempTick = tempTick2;
3040 }
3041
3042 lock (_taintedPrims)
3043 {
3044 foreach (OdePrim prim in _taintedPrims)
3045 {
3046 if (prim.m_taintremove)
3047 {
3048// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name);
3049 RemovePrimThreadLocked(prim);
3050 }
3051 else
3052 {
3053// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name);
3054 prim.ProcessTaints();
3055 }
3056
3057 prim.m_collisionscore = 0;
3058
3059 // This loop can block up the Heartbeat for a very long time on large regions.
3060 // We need to let the Watchdog know that the Heartbeat is not dead
3061 // NOTE: This is currently commented out, but if things like OAR loading are
3062 // timing the heartbeat out we will need to uncomment it
3063 //Watchdog.UpdateThread();
3064 }
3065
3066 if (SupportsNINJAJoints)
3067 SimulatePendingNINJAJoints();
3068
3069 _taintedPrims.Clear();
3070 }
3071
3072 if (CollectStats)
3073 {
3074 tempTick2 = Util.EnvironmentTickCount();
3075 m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3076 tempTick = tempTick2;
3077 }
3078
3079 // Move characters
3080 foreach (OdeCharacter actor in _characters)
3081 actor.Move(defects);
3082
3083 if (defects.Count != 0)
3084 {
3085 foreach (OdeCharacter actor in defects)
3086 {
3087 m_log.ErrorFormat(
3088 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving",
3089 actor.Name, actor.LocalID, Name);
3090
3091 RemoveCharacter(actor);
3092 actor.DestroyOdeStructures();
3093 }
3094
3095 defects.Clear();
3096 }
3097
3098 if (CollectStats)
3099 {
3100 tempTick2 = Util.EnvironmentTickCount();
3101 m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3102 tempTick = tempTick2;
3103 }
3104
3105 // Move other active objects
3106 foreach (OdePrim prim in _activeprims)
3107 {
3108 prim.m_collisionscore = 0;
3109 prim.Move(timeStep);
3110 }
3111
3112 if (CollectStats)
3113 {
3114 tempTick2 = Util.EnvironmentTickCount();
3115 m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3116 tempTick = tempTick2;
3117 }
3118
3119 //if ((framecount % m_randomizeWater) == 0)
3120 // randomizeWater(waterlevel);
3121
3122 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
3123 m_rayCastManager.ProcessQueuedRequests();
3124
3125 if (CollectStats)
3126 {
3127 tempTick2 = Util.EnvironmentTickCount();
3128 m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3129 tempTick = tempTick2;
3130 }
3131
3132 collision_optimized();
3133
3134 if (CollectStats)
3135 {
3136 tempTick2 = Util.EnvironmentTickCount();
3137 m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3138 tempTick = tempTick2;
3139 }
3140
3141 foreach (PhysicsActor obj in m_collisionEventActors.Values)
3142 {
3143// m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID);
3144
3145 switch ((ActorTypes)obj.PhysicsActorType)
3146 {
3147 case ActorTypes.Agent:
3148 OdeCharacter cobj = (OdeCharacter)obj;
3149 cobj.AddCollisionFrameTime(100);
3150 cobj.SendCollisions();
3151 break;
3152
3153 case ActorTypes.Prim:
3154 OdePrim pobj = (OdePrim)obj;
3155 pobj.SendCollisions();
3156 break;
3157 }
3158 }
3159
3160// if (m_global_contactcount > 0)
3161// m_log.DebugFormat(
3162// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount);
3163
3164 m_global_contactcount = 0;
3165
3166 if (CollectStats)
3167 {
3168 tempTick2 = Util.EnvironmentTickCount();
3169 m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3170 tempTick = tempTick2;
3171 }
3172
3173 d.WorldQuickStep(world, ODE_STEPSIZE);
3174
3175 if (CollectStats)
3176 m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
3177
3178 d.JointGroupEmpty(contactgroup);
3179 }
3180 catch (Exception e)
3181 {
3182 m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3183 }
3184
3185 timeLeft -= ODE_STEPSIZE;
3186 }
3187
3188 if (CollectStats)
3189 tempTick = Util.EnvironmentTickCount();
3190
3191 foreach (OdeCharacter actor in _characters)
3192 {
3193 if (actor.bad)
3194 m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3195
3196 actor.UpdatePositionAndVelocity(defects);
3197 }
3198
3199 if (defects.Count != 0)
3200 {
3201 foreach (OdeCharacter actor in defects)
3202 {
3203 m_log.ErrorFormat(
3204 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity",
3205 actor.Name, actor.LocalID, Name);
3206
3207 RemoveCharacter(actor);
3208 actor.DestroyOdeStructures();
3209 }
3210
3211 defects.Clear();
3212 }
3213
3214 if (CollectStats)
3215 {
3216 tempTick2 = Util.EnvironmentTickCount();
3217 m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3218 tempTick = tempTick2;
3219 }
3220
3221 //if (timeStep < 0.2f)
3222
3223 foreach (OdePrim prim in _activeprims)
3224 {
3225 if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag))
3226 {
3227 prim.UpdatePositionAndVelocity();
3228
3229 if (SupportsNINJAJoints)
3230 SimulateActorPendingJoints(prim);
3231 }
3232 }
3233
3234 if (CollectStats)
3235 m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
3236
3237 //DumpJointInfo();
3238
3239 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3240 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3241 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3242 if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0))
3243 {
3244 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3245 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3246
3247 if (physics_logging_append_existing_logfile)
3248 {
3249 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3250 TextWriter fwriter = File.AppendText(fname);
3251 fwriter.WriteLine(header);
3252 fwriter.Close();
3253 }
3254
3255 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3256 }
3257
3258 latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun);
3259
3260 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
3261 // has a max of 100 ms to run theoretically.
3262 // If the main loop stalls, it calls Simulate later which makes the tick count ms larger.
3263 // If Physics stalls, it takes longer which makes the tick count ms larger.
3264
3265 if (latertickcount < 100)
3266 {
3267 m_timeDilation = 1.0f;
3268 }
3269 else
3270 {
3271 m_timeDilation = 100f / latertickcount;
3272 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f);
3273 }
3274
3275 tickCountFrameRun = Util.EnvironmentTickCount();
3276
3277 if (CollectStats)
3278 m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick);
3279 }
3280
3281 return fps;
3282 }
3283
3284 /// <summary>
3285 /// Simulate pending NINJA joints.
3286 /// </summary>
3287 /// <remarks>
3288 /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else.
3289 /// </remarks>
3290 private void SimulatePendingNINJAJoints()
3291 {
3292 // Create pending joints, if possible
3293
3294 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
3295 // a joint requires specifying the body id of both involved bodies
3296 if (pendingJoints.Count > 0)
3297 {
3298 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
3299 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
3300 foreach (PhysicsJoint joint in pendingJoints)
3301 {
3302 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
3303 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
3304 List<IntPtr> jointBodies = new List<IntPtr>();
3305 bool allJointBodiesAreReady = true;
3306 foreach (string jointParam in jointParams)
3307 {
3308 if (jointParam == "NULL")
3309 {
3310 //DoJointErrorMessage(joint, "attaching NULL joint to world");
3311 jointBodies.Add(IntPtr.Zero);
3312 }
3313 else
3314 {
3315 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
3316 bool foundPrim = false;
3317 lock (_prims)
3318 {
3319 foreach (OdePrim prim in _prims) // FIXME: inefficient
3320 {
3321 if (prim.SOPName == jointParam)
3322 {
3323 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
3324 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
3325 {
3326 jointBodies.Add(prim.Body);
3327 foundPrim = true;
3328 break;
3329 }
3330 else
3331 {
3332 DoJointErrorMessage(joint, "prim name " + jointParam +
3333 " exists but is not (yet) physical; deferring joint creation. " +
3334 "IsPhysical property is " + prim.IsPhysical +
3335 " and body is " + prim.Body);
3336 foundPrim = false;
3337 break;
3338 }
3339 }
3340 }
3341 }
3342 if (foundPrim)
3343 {
3344 // all is fine
3345 }
3346 else
3347 {
3348 allJointBodiesAreReady = false;
3349 break;
3350 }
3351 }
3352 }
3353
3354 if (allJointBodiesAreReady)
3355 {
3356 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
3357 if (jointBodies[0] == jointBodies[1])
3358 {
3359 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
3360 }
3361 else
3362 {
3363 switch (joint.Type)
3364 {
3365 case PhysicsJointType.Ball:
3366 {
3367 IntPtr odeJoint;
3368 //DoJointErrorMessage(joint, "ODE creating ball joint ");
3369 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
3370 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3371 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3372 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
3373 d.JointSetBallAnchor(odeJoint,
3374 joint.Position.X,
3375 joint.Position.Y,
3376 joint.Position.Z);
3377 //DoJointErrorMessage(joint, "ODE joint setting OK");
3378 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
3379 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
3380 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
3381 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
3382
3383 if (joint is OdePhysicsJoint)
3384 {
3385 ((OdePhysicsJoint)joint).jointID = odeJoint;
3386 }
3387 else
3388 {
3389 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3390 }
3391 }
3392 break;
3393 case PhysicsJointType.Hinge:
3394 {
3395 IntPtr odeJoint;
3396 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
3397 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
3398 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3399 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3400 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
3401 d.JointSetHingeAnchor(odeJoint,
3402 joint.Position.X,
3403 joint.Position.Y,
3404 joint.Position.Z);
3405 // We use the orientation of the x-axis of the joint's coordinate frame
3406 // as the axis for the hinge.
3407
3408 // Therefore, we must get the joint's coordinate frame based on the
3409 // joint.Rotation field, which originates from the orientation of the
3410 // joint's proxy object in the scene.
3411
3412 // The joint's coordinate frame is defined as the transformation matrix
3413 // that converts a vector from joint-local coordinates into world coordinates.
3414 // World coordinates are defined as the XYZ coordinate system of the sim,
3415 // as shown in the top status-bar of the viewer.
3416
3417 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
3418 // and use that as the hinge axis.
3419
3420 //joint.Rotation.Normalize();
3421 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
3422
3423 // Now extract the X axis of the joint's coordinate frame.
3424
3425 // Do not try to use proxyFrame.AtAxis or you will become mired in the
3426 // tar pit of transposed, inverted, and generally messed-up orientations.
3427 // (In other words, Matrix4.AtAxis() is borked.)
3428 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
3429
3430 // Instead, compute the X axis of the coordinate frame by transforming
3431 // the (1,0,0) vector. At least that works.
3432
3433 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
3434 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
3435 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
3436 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
3437 d.JointSetHingeAxis(odeJoint,
3438 jointAxis.X,
3439 jointAxis.Y,
3440 jointAxis.Z);
3441 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
3442 if (joint is OdePhysicsJoint)
3443 {
3444 ((OdePhysicsJoint)joint).jointID = odeJoint;
3445 }
3446 else
3447 {
3448 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3449 }
3450 }
3451 break;
3452 }
3453 successfullyProcessedPendingJoints.Add(joint);
3454 }
3455 }
3456 else
3457 {
3458 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
3459 }
3460 }
3461
3462 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
3463 {
3464 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
3465 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
3466 InternalRemovePendingJoint(successfullyProcessedJoint);
3467 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
3468 InternalAddActiveJoint(successfullyProcessedJoint);
3469 //DoJointErrorMessage(successfullyProcessedJoint, "done");
3470 }
3471 }
3472 }
3473
3474 /// <summary>
3475 /// Simulate the joint proxies of a NINJA actor.
3476 /// </summary>
3477 /// <remarks>
3478 /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there.
3479 /// </remarks>
3480 /// <param name="actor"></param>
3481 private void SimulateActorPendingJoints(OdePrim actor)
3482 {
3483 // If an actor moved, move its joint proxy objects as well.
3484 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3485 // for this purpose but it is never called! So we just do the joint
3486 // movement code here.
3487
3488 if (actor.SOPName != null &&
3489 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3490 joints_connecting_actor[actor.SOPName] != null &&
3491 joints_connecting_actor[actor.SOPName].Count > 0)
3492 {
3493 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3494 {
3495 if (affectedJoint.IsInPhysicsEngine)
3496 {
3497 DoJointMoved(affectedJoint);
3498 }
3499 else
3500 {
3501 DoJointErrorMessage(affectedJoint, "a body connected to a joint was moved, but the joint doesn't exist yet! this will lead to joint error. joint was: " + affectedJoint.ObjectNameInScene + " parms:" + affectedJoint.RawParams);
3502 }
3503 }
3504 }
3505 }
3506
3507 public override void GetResults()
3508 {
3509 }
3510
3511 public override bool IsThreaded
3512 {
3513 // for now we won't be multithreaded
3514 get { return false; }
3515 }
3516
3517 #region ODE Specific Terrain Fixes
3518 private float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3519 {
3520 float[] returnarr = new float[262144];
3521 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3522
3523 // Filling out the array into its multi-dimensional components
3524 for (int y = 0; y < WorldExtents.Y; y++)
3525 {
3526 for (int x = 0; x < WorldExtents.X; x++)
3527 {
3528 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3529 }
3530 }
3531
3532 // Resize using Nearest Neighbour
3533
3534 // This particular way is quick but it only works on a multiple of the original
3535
3536 // The idea behind this method can be described with the following diagrams
3537 // second pass and third pass happen in the same loop really.. just separated
3538 // them to show what this does.
3539
3540 // First Pass
3541 // ResultArr:
3542 // 1,1,1,1,1,1
3543 // 1,1,1,1,1,1
3544 // 1,1,1,1,1,1
3545 // 1,1,1,1,1,1
3546 // 1,1,1,1,1,1
3547 // 1,1,1,1,1,1
3548
3549 // Second Pass
3550 // ResultArr2:
3551 // 1,,1,,1,,1,,1,,1,
3552 // ,,,,,,,,,,
3553 // 1,,1,,1,,1,,1,,1,
3554 // ,,,,,,,,,,
3555 // 1,,1,,1,,1,,1,,1,
3556 // ,,,,,,,,,,
3557 // 1,,1,,1,,1,,1,,1,
3558 // ,,,,,,,,,,
3559 // 1,,1,,1,,1,,1,,1,
3560 // ,,,,,,,,,,
3561 // 1,,1,,1,,1,,1,,1,
3562
3563 // Third pass fills in the blanks
3564 // ResultArr2:
3565 // 1,1,1,1,1,1,1,1,1,1,1,1
3566 // 1,1,1,1,1,1,1,1,1,1,1,1
3567 // 1,1,1,1,1,1,1,1,1,1,1,1
3568 // 1,1,1,1,1,1,1,1,1,1,1,1
3569 // 1,1,1,1,1,1,1,1,1,1,1,1
3570 // 1,1,1,1,1,1,1,1,1,1,1,1
3571 // 1,1,1,1,1,1,1,1,1,1,1,1
3572 // 1,1,1,1,1,1,1,1,1,1,1,1
3573 // 1,1,1,1,1,1,1,1,1,1,1,1
3574 // 1,1,1,1,1,1,1,1,1,1,1,1
3575 // 1,1,1,1,1,1,1,1,1,1,1,1
3576
3577 // X,Y = .
3578 // X+1,y = ^
3579 // X,Y+1 = *
3580 // X+1,Y+1 = #
3581
3582 // Filling in like this;
3583 // .*
3584 // ^#
3585 // 1st .
3586 // 2nd *
3587 // 3rd ^
3588 // 4th #
3589 // on single loop.
3590
3591 float[,] resultarr2 = new float[512, 512];
3592 for (int y = 0; y < WorldExtents.Y; y++)
3593 {
3594 for (int x = 0; x < WorldExtents.X; x++)
3595 {
3596 resultarr2[y * 2, x * 2] = resultarr[y, x];
3597
3598 if (y < WorldExtents.Y)
3599 {
3600 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3601 }
3602 if (x < WorldExtents.X)
3603 {
3604 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3605 }
3606 if (x < WorldExtents.X && y < WorldExtents.Y)
3607 {
3608 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3609 }
3610 }
3611 }
3612
3613 //Flatten out the array
3614 int i = 0;
3615 for (int y = 0; y < 512; y++)
3616 {
3617 for (int x = 0; x < 512; x++)
3618 {
3619 if (resultarr2[y, x] <= 0)
3620 returnarr[i] = 0.0000001f;
3621 else
3622 returnarr[i] = resultarr2[y, x];
3623
3624 i++;
3625 }
3626 }
3627
3628 return returnarr;
3629 }
3630
3631 private float[] ResizeTerrain512Interpolation(float[] heightMap)
3632 {
3633 float[] returnarr = new float[262144];
3634 float[,] resultarr = new float[512,512];
3635
3636 // Filling out the array into its multi-dimensional components
3637 for (int y = 0; y < 256; y++)
3638 {
3639 for (int x = 0; x < 256; x++)
3640 {
3641 resultarr[y, x] = heightMap[y * 256 + x];
3642 }
3643 }
3644
3645 // Resize using interpolation
3646
3647 // This particular way is quick but it only works on a multiple of the original
3648
3649 // The idea behind this method can be described with the following diagrams
3650 // second pass and third pass happen in the same loop really.. just separated
3651 // them to show what this does.
3652
3653 // First Pass
3654 // ResultArr:
3655 // 1,1,1,1,1,1
3656 // 1,1,1,1,1,1
3657 // 1,1,1,1,1,1
3658 // 1,1,1,1,1,1
3659 // 1,1,1,1,1,1
3660 // 1,1,1,1,1,1
3661
3662 // Second Pass
3663 // ResultArr2:
3664 // 1,,1,,1,,1,,1,,1,
3665 // ,,,,,,,,,,
3666 // 1,,1,,1,,1,,1,,1,
3667 // ,,,,,,,,,,
3668 // 1,,1,,1,,1,,1,,1,
3669 // ,,,,,,,,,,
3670 // 1,,1,,1,,1,,1,,1,
3671 // ,,,,,,,,,,
3672 // 1,,1,,1,,1,,1,,1,
3673 // ,,,,,,,,,,
3674 // 1,,1,,1,,1,,1,,1,
3675
3676 // Third pass fills in the blanks
3677 // ResultArr2:
3678 // 1,1,1,1,1,1,1,1,1,1,1,1
3679 // 1,1,1,1,1,1,1,1,1,1,1,1
3680 // 1,1,1,1,1,1,1,1,1,1,1,1
3681 // 1,1,1,1,1,1,1,1,1,1,1,1
3682 // 1,1,1,1,1,1,1,1,1,1,1,1
3683 // 1,1,1,1,1,1,1,1,1,1,1,1
3684 // 1,1,1,1,1,1,1,1,1,1,1,1
3685 // 1,1,1,1,1,1,1,1,1,1,1,1
3686 // 1,1,1,1,1,1,1,1,1,1,1,1
3687 // 1,1,1,1,1,1,1,1,1,1,1,1
3688 // 1,1,1,1,1,1,1,1,1,1,1,1
3689
3690 // X,Y = .
3691 // X+1,y = ^
3692 // X,Y+1 = *
3693 // X+1,Y+1 = #
3694
3695 // Filling in like this;
3696 // .*
3697 // ^#
3698 // 1st .
3699 // 2nd *
3700 // 3rd ^
3701 // 4th #
3702 // on single loop.
3703
3704 float[,] resultarr2 = new float[512,512];
3705 for (int y = 0; y < (int)Constants.RegionSize; y++)
3706 {
3707 for (int x = 0; x < (int)Constants.RegionSize; x++)
3708 {
3709 resultarr2[y*2, x*2] = resultarr[y, x];
3710
3711 if (y < (int)Constants.RegionSize)
3712 {
3713 if (y + 1 < (int)Constants.RegionSize)
3714 {
3715 if (x + 1 < (int)Constants.RegionSize)
3716 {
3717 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3718 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3719 }
3720 else
3721 {
3722 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3723 }
3724 }
3725 else
3726 {
3727 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3728 }
3729 }
3730 if (x < (int)Constants.RegionSize)
3731 {
3732 if (x + 1 < (int)Constants.RegionSize)
3733 {
3734 if (y + 1 < (int)Constants.RegionSize)
3735 {
3736 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3737 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3738 }
3739 else
3740 {
3741 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3742 }
3743 }
3744 else
3745 {
3746 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3747 }
3748 }
3749 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3750 {
3751 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3752 {
3753 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3754 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3755 }
3756 else
3757 {
3758 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3759 }
3760 }
3761 }
3762 }
3763 //Flatten out the array
3764 int i = 0;
3765 for (int y = 0; y < 512; y++)
3766 {
3767 for (int x = 0; x < 512; x++)
3768 {
3769 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3770 {
3771 m_log.Warn("[ODE SCENE]: Non finite heightfield element detected. Setting it to 0");
3772 resultarr2[y, x] = 0;
3773 }
3774 returnarr[i] = resultarr2[y, x];
3775 i++;
3776 }
3777 }
3778
3779 return returnarr;
3780 }
3781
3782 #endregion
3783
3784 public override void SetTerrain(float[] heightMap)
3785 {
3786 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3787 {
3788 if (m_parentScene is OdeScene)
3789 {
3790 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3791 }
3792 }
3793 else
3794 {
3795 SetTerrain(heightMap, m_worldOffset);
3796 }
3797 }
3798
3799 private void SetTerrain(float[] heightMap, Vector3 pOffset)
3800 {
3801 int startTime = Util.EnvironmentTickCount();
3802 m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", Name, pOffset);
3803
3804 // this._heightmap[i] = (double)heightMap[i];
3805 // dbm (danx0r) -- creating a buffer zone of one extra sample all around
3806 //_origheightmap = heightMap;
3807
3808 float[] _heightmap;
3809
3810 // zero out a heightmap array float array (single dimension [flattened]))
3811 //if ((int)Constants.RegionSize == 256)
3812 // _heightmap = new float[514 * 514];
3813 //else
3814
3815 _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))];
3816
3817 uint heightmapWidth = Constants.RegionSize + 1;
3818 uint heightmapHeight = Constants.RegionSize + 1;
3819
3820 uint heightmapWidthSamples;
3821
3822 uint heightmapHeightSamples;
3823
3824 //if (((int)Constants.RegionSize) == 256)
3825 //{
3826 // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2;
3827 // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2;
3828 // heightmapWidth++;
3829 // heightmapHeight++;
3830 //}
3831 //else
3832 //{
3833
3834 heightmapWidthSamples = (uint)Constants.RegionSize + 1;
3835 heightmapHeightSamples = (uint)Constants.RegionSize + 1;
3836 //}
3837
3838 const float scale = 1.0f;
3839 const float offset = 0.0f;
3840 const float thickness = 0.2f;
3841 const int wrap = 0;
3842
3843 int regionsize = (int) Constants.RegionSize + 2;
3844 //Double resolution
3845 //if (((int)Constants.RegionSize) == 256)
3846 // heightMap = ResizeTerrain512Interpolation(heightMap);
3847
3848
3849 // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256)
3850 // regionsize = 512;
3851
3852 float hfmin = 2000;
3853 float hfmax = -2000;
3854
3855 for (int x = 0; x < heightmapWidthSamples; x++)
3856 {
3857 for (int y = 0; y < heightmapHeightSamples; y++)
3858 {
3859 int xx = Util.Clip(x - 1, 0, regionsize - 1);
3860 int yy = Util.Clip(y - 1, 0, regionsize - 1);
3861
3862
3863 float val= heightMap[yy * (int)Constants.RegionSize + xx];
3864 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val;
3865
3866 hfmin = (val < hfmin) ? val : hfmin;
3867 hfmax = (val > hfmax) ? val : hfmax;
3868 }
3869 }
3870
3871 lock (OdeLock)
3872 {
3873 IntPtr GroundGeom = IntPtr.Zero;
3874 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3875 {
3876 RegionTerrain.Remove(pOffset);
3877 if (GroundGeom != IntPtr.Zero)
3878 {
3879 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3880 {
3881 TerrainHeightFieldHeights.Remove(GroundGeom);
3882 }
3883 d.SpaceRemove(space, GroundGeom);
3884 d.GeomDestroy(GroundGeom);
3885 }
3886
3887 }
3888 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3889 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1,
3890 (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale,
3891 offset, thickness, wrap);
3892 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3893 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3894 if (GroundGeom != IntPtr.Zero)
3895 {
3896 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3897 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3898
3899 }
3900 geom_name_map[GroundGeom] = "Terrain";
3901
3902 d.Matrix3 R = new d.Matrix3();
3903
3904 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3905 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3906 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3907
3908 q1 = q1 * q2;
3909 //q1 = q1 * q3;
3910 Vector3 v3;
3911 float angle;
3912 q1.GetAxisAngle(out v3, out angle);
3913
3914 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3915 d.GeomSetRotation(GroundGeom, ref R);
3916 d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)), (pOffset.Y + ((int)Constants.RegionSize * 0.5f)), 0);
3917 IntPtr testGround = IntPtr.Zero;
3918 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3919 {
3920 RegionTerrain.Remove(pOffset);
3921 }
3922 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3923 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3924 }
3925
3926 m_log.DebugFormat(
3927 "[ODE SCENE]: Setting terrain for {0} took {1}ms", Name, Util.EnvironmentTickCountSubtract(startTime));
3928 }
3929
3930 public override void DeleteTerrain()
3931 {
3932 }
3933
3934 internal float GetWaterLevel()
3935 {
3936 return waterlevel;
3937 }
3938
3939 public override bool SupportsCombining()
3940 {
3941 return true;
3942 }
3943
3944// public override void UnCombine(PhysicsScene pScene)
3945// {
3946// IntPtr localGround = IntPtr.Zero;
3947//// float[] localHeightfield;
3948// bool proceed = false;
3949// List<IntPtr> geomDestroyList = new List<IntPtr>();
3950//
3951// lock (OdeLock)
3952// {
3953// if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3954// {
3955// foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3956// {
3957// if (geom == localGround)
3958// {
3959//// localHeightfield = TerrainHeightFieldHeights[geom];
3960// proceed = true;
3961// }
3962// else
3963// {
3964// geomDestroyList.Add(geom);
3965// }
3966// }
3967//
3968// if (proceed)
3969// {
3970// m_worldOffset = Vector3.Zero;
3971// WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3972// m_parentScene = null;
3973//
3974// foreach (IntPtr g in geomDestroyList)
3975// {
3976// // removingHeightField needs to be done or the garbage collector will
3977// // collect the terrain data before we tell ODE to destroy it causing
3978// // memory corruption
3979// if (TerrainHeightFieldHeights.ContainsKey(g))
3980// {
3981//// float[] removingHeightField = TerrainHeightFieldHeights[g];
3982// TerrainHeightFieldHeights.Remove(g);
3983//
3984// if (RegionTerrain.ContainsKey(g))
3985// {
3986// RegionTerrain.Remove(g);
3987// }
3988//
3989// d.GeomDestroy(g);
3990// //removingHeightField = new float[0];
3991// }
3992// }
3993//
3994// }
3995// else
3996// {
3997// m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3998// }
3999// }
4000// }
4001// }
4002
4003 public override void SetWaterLevel(float baseheight)
4004 {
4005 waterlevel = baseheight;
4006 randomizeWater(waterlevel);
4007 }
4008
4009 private void randomizeWater(float baseheight)
4010 {
4011 const uint heightmapWidth = m_regionWidth + 2;
4012 const uint heightmapHeight = m_regionHeight + 2;
4013 const uint heightmapWidthSamples = m_regionWidth + 2;
4014 const uint heightmapHeightSamples = m_regionHeight + 2;
4015 const float scale = 1.0f;
4016 const float offset = 0.0f;
4017 const float thickness = 2.9f;
4018 const int wrap = 0;
4019
4020 for (int i = 0; i < (258 * 258); i++)
4021 {
4022 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
4023 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
4024 }
4025
4026 lock (OdeLock)
4027 {
4028 if (WaterGeom != IntPtr.Zero)
4029 {
4030 d.SpaceRemove(space, WaterGeom);
4031 }
4032 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
4033 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
4034 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
4035 offset, thickness, wrap);
4036 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
4037 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
4038 if (WaterGeom != IntPtr.Zero)
4039 {
4040 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
4041 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
4042 }
4043
4044 geom_name_map[WaterGeom] = "Water";
4045
4046 d.Matrix3 R = new d.Matrix3();
4047
4048 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
4049 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
4050 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
4051
4052 q1 = q1 * q2;
4053 //q1 = q1 * q3;
4054 Vector3 v3;
4055 float angle;
4056 q1.GetAxisAngle(out v3, out angle);
4057
4058 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
4059 d.GeomSetRotation(WaterGeom, ref R);
4060 d.GeomSetPosition(WaterGeom, 128, 128, 0);
4061 }
4062 }
4063
4064 public override void Dispose()
4065 {
4066 _worldInitialized = false;
4067
4068 m_rayCastManager.Dispose();
4069 m_rayCastManager = null;
4070
4071 lock (OdeLock)
4072 {
4073 lock (_prims)
4074 {
4075 foreach (OdePrim prm in _prims)
4076 {
4077 RemovePrim(prm);
4078 }
4079 }
4080
4081 //foreach (OdeCharacter act in _characters)
4082 //{
4083 //RemoveAvatar(act);
4084 //}
4085 d.WorldDestroy(world);
4086 //d.CloseODE();
4087 }
4088
4089 }
4090
4091 public override Dictionary<uint, float> GetTopColliders()
4092 {
4093 Dictionary<uint, float> topColliders;
4094
4095 lock (_prims)
4096 {
4097 List<OdePrim> orderedPrims = new List<OdePrim>(_prims);
4098 orderedPrims.OrderByDescending(p => p.CollisionScore).Take(25);
4099 topColliders = orderedPrims.ToDictionary(p => p.LocalID, p => p.CollisionScore);
4100
4101 foreach (OdePrim p in _prims)
4102 p.CollisionScore = 0;
4103 }
4104
4105 return topColliders;
4106 }
4107
4108 public override bool SupportsRayCast()
4109 {
4110 return true;
4111 }
4112
4113 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
4114 {
4115 if (retMethod != null)
4116 {
4117 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
4118 }
4119 }
4120
4121 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
4122 {
4123 if (retMethod != null)
4124 {
4125 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
4126 }
4127 }
4128
4129 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
4130 {
4131 ContactResult[] ourResults = null;
4132 RayCallback retMethod = delegate(List<ContactResult> results)
4133 {
4134 ourResults = new ContactResult[results.Count];
4135 results.CopyTo(ourResults, 0);
4136 };
4137 int waitTime = 0;
4138 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
4139 while (ourResults == null && waitTime < 1000)
4140 {
4141 Thread.Sleep(1);
4142 waitTime++;
4143 }
4144 if (ourResults == null)
4145 return new List<ContactResult> ();
4146 return new List<ContactResult>(ourResults);
4147 }
4148
4149#if USE_DRAWSTUFF
4150 // Keyboard callback
4151 public void command(int cmd)
4152 {
4153 IntPtr geom;
4154 d.Mass mass;
4155 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
4156
4157
4158
4159 Char ch = Char.ToLower((Char)cmd);
4160 switch ((Char)ch)
4161 {
4162 case 'w':
4163 try
4164 {
4165 Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
4166
4167 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
4168 ds.SetViewpoint(ref xyz, ref hpr);
4169 }
4170 catch (ArgumentException)
4171 { hpr.X = 0; }
4172 break;
4173
4174 case 'a':
4175 hpr.X++;
4176 ds.SetViewpoint(ref xyz, ref hpr);
4177 break;
4178
4179 case 's':
4180 try
4181 {
4182 Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD));
4183
4184 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
4185 ds.SetViewpoint(ref xyz, ref hpr);
4186 }
4187 catch (ArgumentException)
4188 { hpr.X = 0; }
4189 break;
4190 case 'd':
4191 hpr.X--;
4192 ds.SetViewpoint(ref xyz, ref hpr);
4193 break;
4194 case 'r':
4195 xyz.Z++;
4196 ds.SetViewpoint(ref xyz, ref hpr);
4197 break;
4198 case 'f':
4199 xyz.Z--;
4200 ds.SetViewpoint(ref xyz, ref hpr);
4201 break;
4202 case 'e':
4203 xyz.Y++;
4204 ds.SetViewpoint(ref xyz, ref hpr);
4205 break;
4206 case 'q':
4207 xyz.Y--;
4208 ds.SetViewpoint(ref xyz, ref hpr);
4209 break;
4210 }
4211 }
4212
4213 public void step(int pause)
4214 {
4215
4216 ds.SetColor(1.0f, 1.0f, 0.0f);
4217 ds.SetTexture(ds.Texture.Wood);
4218 lock (_prims)
4219 {
4220 foreach (OdePrim prm in _prims)
4221 {
4222 //IntPtr body = d.GeomGetBody(prm.prim_geom);
4223 if (prm.prim_geom != IntPtr.Zero)
4224 {
4225 d.Vector3 pos;
4226 d.GeomCopyPosition(prm.prim_geom, out pos);
4227 //d.BodyCopyPosition(body, out pos);
4228
4229 d.Matrix3 R;
4230 d.GeomCopyRotation(prm.prim_geom, out R);
4231 //d.BodyCopyRotation(body, out R);
4232
4233
4234 d.Vector3 sides = new d.Vector3();
4235 sides.X = prm.Size.X;
4236 sides.Y = prm.Size.Y;
4237 sides.Z = prm.Size.Z;
4238
4239 ds.DrawBox(ref pos, ref R, ref sides);
4240 }
4241 }
4242 }
4243 ds.SetColor(1.0f, 0.0f, 0.0f);
4244
4245 foreach (OdeCharacter chr in _characters)
4246 {
4247 if (chr.Shell != IntPtr.Zero)
4248 {
4249 IntPtr body = d.GeomGetBody(chr.Shell);
4250
4251 d.Vector3 pos;
4252 d.GeomCopyPosition(chr.Shell, out pos);
4253 //d.BodyCopyPosition(body, out pos);
4254
4255 d.Matrix3 R;
4256 d.GeomCopyRotation(chr.Shell, out R);
4257 //d.BodyCopyRotation(body, out R);
4258
4259 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
4260 d.Vector3 sides = new d.Vector3();
4261 sides.X = 0.5f;
4262 sides.Y = 0.5f;
4263 sides.Z = 0.5f;
4264
4265 ds.DrawBox(ref pos, ref R, ref sides);
4266 }
4267 }
4268 }
4269
4270 public void start(int unused)
4271 {
4272 ds.SetViewpoint(ref xyz, ref hpr);
4273 }
4274#endif
4275
4276 public override Dictionary<string, float> GetStats()
4277 {
4278 if (!CollectStats)
4279 return null;
4280
4281 Dictionary<string, float> returnStats;
4282
4283 lock (OdeLock)
4284 {
4285 returnStats = new Dictionary<string, float>(m_stats);
4286
4287 // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by
4288 // 3 from the SimStatsReporter.
4289 returnStats[ODETotalAvatarsStatName] = _characters.Count * 3;
4290 returnStats[ODETotalPrimsStatName] = _prims.Count * 3;
4291 returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3;
4292
4293 InitializeExtraStats();
4294 }
4295
4296 returnStats[ODEOtherCollisionFrameMsStatName]
4297 = returnStats[ODEOtherCollisionFrameMsStatName]
4298 - returnStats[ODENativeSpaceCollisionFrameMsStatName]
4299 - returnStats[ODENativeGeomCollisionFrameMsStatName];
4300
4301 return returnStats;
4302 }
4303
4304 private void InitializeExtraStats()
4305 {
4306 m_stats[ODETotalFrameMsStatName] = 0;
4307 m_stats[ODEAvatarTaintMsStatName] = 0;
4308 m_stats[ODEPrimTaintMsStatName] = 0;
4309 m_stats[ODEAvatarForcesFrameMsStatName] = 0;
4310 m_stats[ODEPrimForcesFrameMsStatName] = 0;
4311 m_stats[ODERaycastingFrameMsStatName] = 0;
4312 m_stats[ODENativeStepFrameMsStatName] = 0;
4313 m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0;
4314 m_stats[ODENativeGeomCollisionFrameMsStatName] = 0;
4315 m_stats[ODEOtherCollisionFrameMsStatName] = 0;
4316 m_stats[ODECollisionNotificationFrameMsStatName] = 0;
4317 m_stats[ODEAvatarContactsStatsName] = 0;
4318 m_stats[ODEPrimContactsStatName] = 0;
4319 m_stats[ODEAvatarUpdateFrameMsStatName] = 0;
4320 m_stats[ODEPrimUpdateFrameMsStatName] = 0;
4321 }
4322 }
4323}
diff --git a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs b/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
deleted file mode 100644
index 16404c6..0000000
--- a/OpenSim/Region/Physics/OdePlugin/Tests/ODETestClass.cs
+++ /dev/null
@@ -1,128 +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 Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.OdePlugin;
35using OpenSim.Tests.Common;
36using log4net;
37using System.Reflection;
38
39namespace OpenSim.Region.Physics.OdePlugin.Tests
40{
41 [TestFixture]
42 public class ODETestClass : OpenSimTestCase
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 private OpenSim.Region.Physics.OdePlugin.OdePlugin cbt;
47 private PhysicsScene ps;
48 private IMeshingPlugin imp;
49
50 [SetUp]
51 public void Initialize()
52 {
53 IConfigSource TopConfig = new IniConfigSource();
54 IConfig config = TopConfig.AddConfig("Startup");
55 config.Set("DecodedSculptMapPath","j2kDecodeCache");
56
57 // Loading ODEPlugin
58 cbt = new OdePlugin();
59 // Loading Zero Mesher
60 imp = new ZeroMesherPlugin();
61 // Getting Physics Scene
62 ps = cbt.GetScene("test");
63 // Initializing Physics Scene.
64 ps.Initialise(imp.GetMesher(TopConfig),null);
65 float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize];
66 for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++)
67 {
68 _heightmap[i] = 21f;
69 }
70 ps.SetTerrain(_heightmap);
71 }
72
73 [TearDown]
74 public void Terminate()
75 {
76 ps.DeleteTerrain();
77 ps.Dispose();
78
79 }
80
81 [Test]
82 public void CreateAndDropPhysicalCube()
83 {
84 PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox();
85 Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f);
86 Vector3 size = new Vector3(0.5f, 0.5f, 0.5f);
87 Quaternion rot = Quaternion.Identity;
88 PhysicsActor prim = ps.AddPrimShape("CoolShape", newcube, position, size, rot, true, 0);
89 OdePrim oprim = (OdePrim)prim;
90 OdeScene pscene = (OdeScene) ps;
91
92 Assert.That(oprim.m_taintadd);
93
94 prim.LocalID = 5;
95
96 for (int i = 0; i < 58; i++)
97 {
98 ps.Simulate(0.133f);
99
100 Assert.That(oprim.prim_geom != (IntPtr)0);
101
102 Assert.That(oprim.m_targetSpace != (IntPtr)0);
103
104 //Assert.That(oprim.m_targetSpace == pscene.space);
105 m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space);
106
107 Assert.That(!oprim.m_taintadd);
108 m_log.Info("Prim Position (" + oprim.LocalID + "): " + prim.Position);
109
110 // Make sure we're above the ground
111 //Assert.That(prim.Position.Z > 20f);
112 //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore);
113
114 // Make sure we've got a Body
115 Assert.That(oprim.Body != (IntPtr)0);
116 //m_log.Info(
117 }
118
119 // Make sure we're not somewhere above the ground
120 Assert.That(prim.Position.Z < 21.5f);
121
122 ps.RemovePrim(prim);
123 Assert.That(oprim.m_taintremove);
124 ps.Simulate(0.133f);
125 Assert.That(oprim.Body == (IntPtr)0);
126 }
127 }
128}
diff --git a/OpenSim/Region/Physics/OdePlugin/drawstuff.cs b/OpenSim/Region/Physics/OdePlugin/drawstuff.cs
deleted file mode 100644
index 87ca446..0000000
--- a/OpenSim/Region/Physics/OdePlugin/drawstuff.cs
+++ /dev/null
@@ -1,98 +0,0 @@
1/*
2 * Copyright ODE
3 * Ode.NET - .NET bindings for ODE
4 * Jason Perkins (starkos@industriousone.com)
5 * Licensed under the New BSD
6 * Part of the OpenDynamicsEngine
7Open Dynamics Engine
8Copyright (c) 2001-2007, Russell L. Smith.
9All rights reserved.
10
11Redistribution and use in source and binary forms, with or without
12modification, are permitted provided that the following conditions
13are met:
14
15Redistributions of source code must retain the above copyright notice,
16this list of conditions and the following disclaimer.
17
18Redistributions in binary form must reproduce the above copyright notice,
19this list of conditions and the following disclaimer in the documentation
20and/or other materials provided with the distribution.
21
22Neither the names of ODE's copyright owner nor the names of its
23contributors may be used to endorse or promote products derived from
24this software without specific prior written permission.
25
26THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
32TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 *
38 *
39 */
40
41using System;
42using System.Runtime.InteropServices;
43using Ode.NET;
44
45namespace Drawstuff.NET
46{
47#if dDOUBLE
48 using dReal = System.Double;
49#else
50 using dReal = System.Single;
51#endif
52
53 public static class ds
54 {
55 public const int VERSION = 2;
56
57 public enum Texture
58 {
59 None,
60 Wood
61 }
62
63 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
64 public delegate void CallbackFunction(int arg);
65
66 [StructLayout(LayoutKind.Sequential)]
67 public struct Functions
68 {
69 public int version;
70 public CallbackFunction start;
71 public CallbackFunction step;
72 public CallbackFunction command;
73 public CallbackFunction stop;
74 public string path_to_textures;
75 }
76
77 [DllImport("drawstuff", EntryPoint = "dsDrawBox")]
78 public static extern void DrawBox(ref d.Vector3 pos, ref d.Matrix3 R, ref d.Vector3 sides);
79
80 [DllImport("drawstuff", EntryPoint = "dsDrawCapsule")]
81 public static extern void DrawCapsule(ref d.Vector3 pos, ref d.Matrix3 R, dReal length, dReal radius);
82
83 [DllImport("drawstuff", EntryPoint = "dsDrawConvex")]
84 public static extern void DrawConvex(ref d.Vector3 pos, ref d.Matrix3 R, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons);
85
86 [DllImport("drawstuff", EntryPoint = "dsSetColor")]
87 public static extern void SetColor(float red, float green, float blue);
88
89 [DllImport("drawstuff", EntryPoint = "dsSetTexture")]
90 public static extern void SetTexture(Texture texture);
91
92 [DllImport("drawstuff", EntryPoint = "dsSetViewpoint")]
93 public static extern void SetViewpoint(ref d.Vector3 xyz, ref d.Vector3 hpr);
94
95 [DllImport("drawstuff", EntryPoint = "dsSimulationLoop")]
96 public static extern void SimulationLoop(int argc, string[] argv, int window_width, int window_height, ref Functions fn);
97 }
98}
diff --git a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs
deleted file mode 100644
index d07df02..0000000
--- a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs
+++ /dev/null
@@ -1,58 +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.Reflection;
29using System.Runtime.InteropServices;
30
31// Information about this assembly is defined by the following
32// attributes.
33//
34// change them to the information which is associated with the assembly
35// you compile.
36
37[assembly : AssemblyTitle("POSPlugin")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("POSPlugin")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.7.5.*")]
diff --git a/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs b/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs
deleted file mode 100644
index ae534ea..0000000
--- a/OpenSim/Region/Physics/POSPlugin/POSCharacter.cs
+++ /dev/null
@@ -1,340 +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 Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.POSPlugin
36{
37 public class POSCharacter : PhysicsActor
38 {
39 private Vector3 _position;
40 public Vector3 _velocity;
41 public Vector3 _target_velocity = Vector3.Zero;
42 public Vector3 _size = Vector3.Zero;
43 private Vector3 _acceleration;
44 private Vector3 m_rotationalVelocity = Vector3.Zero;
45 private bool flying;
46 private bool isColliding;
47
48 public POSCharacter()
49 {
50 }
51
52 public override int PhysicsActorType
53 {
54 get { return (int) ActorTypes.Agent; }
55 set { return; }
56 }
57
58 public override Vector3 RotationalVelocity
59 {
60 get { return m_rotationalVelocity; }
61 set { m_rotationalVelocity = value; }
62 }
63
64 public override bool SetAlwaysRun
65 {
66 get { return false; }
67 set { return; }
68 }
69
70 public override uint LocalID
71 {
72 set { return; }
73 }
74
75 public override bool Grabbed
76 {
77 set { return; }
78 }
79
80 public override bool Selected
81 {
82 set { return; }
83 }
84
85 public override float Buoyancy
86 {
87 get { return 0f; }
88 set { return; }
89 }
90
91 public override bool FloatOnWater
92 {
93 set { return; }
94 }
95
96 public override bool IsPhysical
97 {
98 get { return false; }
99 set { return; }
100 }
101
102 public override bool ThrottleUpdates
103 {
104 get { return false; }
105 set { return; }
106 }
107
108 public override bool Flying
109 {
110 get { return flying; }
111 set { flying = value; }
112 }
113
114 public override bool IsColliding
115 {
116 get { return isColliding; }
117 set { isColliding = value; }
118 }
119
120 public override bool CollidingGround
121 {
122 get { return false; }
123 set { return; }
124 }
125
126 public override bool CollidingObj
127 {
128 get { return false; }
129 set { return; }
130 }
131
132 public override bool Stopped
133 {
134 get { return false; }
135 }
136
137 public override Vector3 Position
138 {
139 get { return _position; }
140 set { _position = value; }
141 }
142
143 public override Vector3 Size
144 {
145 get { return _size; }
146 set
147 {
148 _size = value;
149 _size.Z = _size.Z / 2.0f;
150 }
151 }
152
153 public override float Mass
154 {
155 get { return 0f; }
156 }
157
158 public override Vector3 Force
159 {
160 get { return Vector3.Zero; }
161 set { return; }
162 }
163
164 public override int VehicleType
165 {
166 get { return 0; }
167 set { return; }
168 }
169
170 public override void VehicleFloatParam(int param, float value)
171 {
172
173 }
174
175 public override void VehicleVectorParam(int param, Vector3 value)
176 {
177
178 }
179
180 public override void VehicleRotationParam(int param, Quaternion rotation)
181 {
182
183 }
184
185 public override void VehicleFlags(int param, bool remove) { }
186
187 public override void SetVolumeDetect(int param)
188 {
189
190 }
191
192 public override Vector3 CenterOfMass
193 {
194 get { return Vector3.Zero; }
195 }
196
197 public override Vector3 GeometricCenter
198 {
199 get { return Vector3.Zero; }
200 }
201
202 public override PrimitiveBaseShape Shape
203 {
204 set { return; }
205 }
206
207 public override Vector3 Velocity
208 {
209 get { return _velocity; }
210 set { _target_velocity = value; }
211 }
212
213 public override Vector3 Torque
214 {
215 get { return Vector3.Zero; }
216 set { return; }
217 }
218
219 public override float CollisionScore
220 {
221 get { return 0f; }
222 set { }
223 }
224
225 public override Quaternion Orientation
226 {
227 get { return Quaternion.Identity; }
228 set { }
229 }
230
231 public override Vector3 Acceleration
232 {
233 get { return _acceleration; }
234 set { _acceleration = value; }
235 }
236
237 public override bool Kinematic
238 {
239 get { return true; }
240 set { }
241 }
242
243 public override void link(PhysicsActor obj)
244 {
245 }
246
247 public override void delink()
248 {
249 }
250
251 public override void LockAngularMotion(Vector3 axis)
252 {
253 }
254
255 public override void AddForce(Vector3 force, bool pushforce)
256 {
257 }
258
259 public override void AddAngularForce(Vector3 force, bool pushforce)
260 {
261 }
262
263 public override void SetMomentum(Vector3 momentum)
264 {
265 }
266
267 public override void CrossingFailure()
268 {
269 }
270
271 public override Vector3 PIDTarget
272 {
273 set { return; }
274 }
275
276 public override bool PIDActive
277 {
278 set { return; }
279 }
280
281 public override float PIDTau
282 {
283 set { return; }
284 }
285
286 public override float PIDHoverHeight
287 {
288 set { return; }
289 }
290
291 public override bool PIDHoverActive
292 {
293 set { return; }
294 }
295
296 public override PIDHoverType PIDHoverType
297 {
298 set { return; }
299 }
300
301 public override float PIDHoverTau
302 {
303 set { return; }
304 }
305
306 public override Quaternion APIDTarget
307 {
308 set { return; }
309 }
310
311 public override bool APIDActive
312 {
313 set { return; }
314 }
315
316 public override float APIDStrength
317 {
318 set { return; }
319 }
320
321 public override float APIDDamping
322 {
323 set { return; }
324 }
325
326
327 public override void SubscribeEvents(int ms)
328 {
329 }
330
331 public override void UnSubscribeEvents()
332 {
333 }
334
335 public override bool SubscribedEvents()
336 {
337 return false;
338 }
339 }
340}
diff --git a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs b/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs
deleted file mode 100644
index e6b42e6..0000000
--- a/OpenSim/Region/Physics/POSPlugin/POSPlugin.cs
+++ /dev/null
@@ -1,64 +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 Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33
34namespace OpenSim.Region.Physics.POSPlugin
35{
36 /// <summary>
37 /// for now will be a very POS physics engine
38 /// </summary>
39 public class POSPlugin : IPhysicsPlugin
40 {
41 public POSPlugin()
42 {
43 }
44
45 public bool Init()
46 {
47 return true;
48 }
49
50 public PhysicsScene GetScene(string sceneIdentifier)
51 {
52 return new POSScene(sceneIdentifier);
53 }
54
55 public string GetName()
56 {
57 return ("POS");
58 }
59
60 public void Dispose()
61 {
62 }
63 }
64}
diff --git a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs b/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
deleted file mode 100644
index e4fd7eb..0000000
--- a/OpenSim/Region/Physics/POSPlugin/POSPrim.cs
+++ /dev/null
@@ -1,335 +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 Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.POSPlugin
36{
37 public class POSPrim : PhysicsActor
38 {
39 private Vector3 _position;
40 private Vector3 _velocity;
41 private Vector3 _acceleration;
42 private Vector3 _size;
43 private Vector3 m_rotationalVelocity = Vector3.Zero;
44 private Quaternion _orientation;
45 private bool iscolliding;
46
47 public POSPrim()
48 {
49 }
50
51 public override int PhysicsActorType
52 {
53 get { return (int) ActorTypes.Prim; }
54 set { return; }
55 }
56
57 public override Vector3 RotationalVelocity
58 {
59 get { return m_rotationalVelocity; }
60 set { m_rotationalVelocity = value; }
61 }
62
63 public override bool IsPhysical
64 {
65 get { return false; }
66 set { return; }
67 }
68
69 public override bool ThrottleUpdates
70 {
71 get { return false; }
72 set { return; }
73 }
74
75 public override bool IsColliding
76 {
77 get { return iscolliding; }
78 set { iscolliding = value; }
79 }
80
81 public override bool CollidingGround
82 {
83 get { return false; }
84 set { return; }
85 }
86
87 public override bool CollidingObj
88 {
89 get { return false; }
90 set { return; }
91 }
92
93 public override bool Stopped
94 {
95 get { return false; }
96 }
97
98 public override Vector3 Position
99 {
100 get { return _position; }
101 set { _position = value; }
102 }
103
104 public override Vector3 Size
105 {
106 get { return _size; }
107 set { _size = value; }
108 }
109
110 public override float Mass
111 {
112 get { return 0f; }
113 }
114
115 public override Vector3 Force
116 {
117 get { return Vector3.Zero; }
118 set { return; }
119 }
120
121 public override int VehicleType
122 {
123 get { return 0; }
124 set { return; }
125 }
126
127 public override void VehicleFloatParam(int param, float value)
128 {
129
130 }
131
132 public override void VehicleVectorParam(int param, Vector3 value)
133 {
134
135 }
136
137 public override void VehicleRotationParam(int param, Quaternion rotation)
138 {
139
140 }
141
142 public override void VehicleFlags(int param, bool remove) { }
143
144 public override void SetVolumeDetect(int param)
145 {
146
147 }
148
149 public override Vector3 CenterOfMass
150 {
151 get { return Vector3.Zero; }
152 }
153
154 public override Vector3 GeometricCenter
155 {
156 get { return Vector3.Zero; }
157 }
158
159 public override PrimitiveBaseShape Shape
160 {
161 set { return; }
162 }
163
164 public override float Buoyancy
165 {
166 get { return 0f; }
167 set { return; }
168 }
169
170 public override bool FloatOnWater
171 {
172 set { return; }
173 }
174
175 public override Vector3 Velocity
176 {
177 get { return _velocity; }
178 set { _velocity = value; }
179 }
180
181 public override float CollisionScore
182 {
183 get { return 0f; }
184 set { }
185 }
186
187 public override Quaternion Orientation
188 {
189 get { return _orientation; }
190 set { _orientation = value; }
191 }
192
193 public override Vector3 Acceleration
194 {
195 get { return _acceleration; }
196 set { _acceleration = value; }
197 }
198
199 public override bool Kinematic
200 {
201 get { return true; }
202 set { }
203 }
204
205 public override void AddForce(Vector3 force, bool pushforce)
206 {
207 }
208
209 public override void AddAngularForce(Vector3 force, bool pushforce)
210 {
211 }
212
213 public override Vector3 Torque
214 {
215 get { return Vector3.Zero; }
216 set { return; }
217 }
218
219 public override void SetMomentum(Vector3 momentum)
220 {
221 }
222
223 public override bool Flying
224 {
225 get { return false; }
226 set { }
227 }
228
229 public override bool SetAlwaysRun
230 {
231 get { return false; }
232 set { return; }
233 }
234
235 public override uint LocalID
236 {
237 set { return; }
238 }
239
240 public override bool Grabbed
241 {
242 set { return; }
243 }
244
245 public override void link(PhysicsActor obj)
246 {
247 }
248
249 public override void delink()
250 {
251 }
252
253 public override void LockAngularMotion(Vector3 axis)
254 {
255 }
256
257 public override bool Selected
258 {
259 set { return; }
260 }
261
262 public override void CrossingFailure()
263 {
264 }
265
266 public override Vector3 PIDTarget
267 {
268 set { return; }
269 }
270
271 public override bool PIDActive
272 {
273 set { return; }
274 }
275
276 public override float PIDTau
277 {
278 set { return; }
279 }
280
281 public override float PIDHoverHeight
282 {
283 set { return; }
284 }
285
286 public override bool PIDHoverActive
287 {
288 set { return; }
289 }
290
291 public override PIDHoverType PIDHoverType
292 {
293 set { return; }
294 }
295
296 public override float PIDHoverTau
297 {
298 set { return; }
299 }
300
301 public override Quaternion APIDTarget
302 {
303 set { return; }
304 }
305
306 public override bool APIDActive
307 {
308 set { return; }
309 }
310
311 public override float APIDStrength
312 {
313 set { return; }
314 }
315
316 public override float APIDDamping
317 {
318 set { return; }
319 }
320
321
322 public override void SubscribeEvents(int ms)
323 {
324 }
325
326 public override void UnSubscribeEvents()
327 {
328 }
329
330 public override bool SubscribedEvents()
331 {
332 return false;
333 }
334 }
335}
diff --git a/OpenSim/Region/Physics/POSPlugin/POSScene.cs b/OpenSim/Region/Physics/POSPlugin/POSScene.cs
deleted file mode 100644
index 2f24a50..0000000
--- a/OpenSim/Region/Physics/POSPlugin/POSScene.cs
+++ /dev/null
@@ -1,270 +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 Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.POSPlugin
36{
37 public class POSScene : PhysicsScene
38 {
39 private List<POSCharacter> _characters = new List<POSCharacter>();
40 private List<POSPrim> _prims = new List<POSPrim>();
41 private float[] _heightMap;
42 private const float gravity = -9.8f;
43
44 //protected internal string sceneIdentifier;
45
46 public POSScene(String _sceneIdentifier)
47 {
48 //sceneIdentifier = _sceneIdentifier;
49 }
50
51 public override void Initialise(IMesher meshmerizer, IConfigSource config)
52 {
53 }
54
55 public override void Dispose()
56 {
57 }
58
59 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
60 {
61 POSCharacter act = new POSCharacter();
62 act.Position = position;
63 act.Flying = isFlying;
64 _characters.Add(act);
65 return act;
66 }
67
68 public override void RemovePrim(PhysicsActor prim)
69 {
70 POSPrim p = (POSPrim) prim;
71 if (_prims.Contains(p))
72 {
73 _prims.Remove(p);
74 }
75 }
76
77 public override void RemoveAvatar(PhysicsActor character)
78 {
79 POSCharacter act = (POSCharacter) character;
80 if (_characters.Contains(act))
81 {
82 _characters.Remove(act);
83 }
84 }
85
86/*
87 public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation)
88 {
89 return null;
90 }
91*/
92
93 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
94 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
95 {
96 POSPrim prim = new POSPrim();
97 prim.Position = position;
98 prim.Orientation = rotation;
99 prim.Size = size;
100 _prims.Add(prim);
101 return prim;
102 }
103
104 private bool isColliding(POSCharacter c, POSPrim p)
105 {
106 Vector3 rotatedPos = new Vector3(c.Position.X - p.Position.X, c.Position.Y - p.Position.Y,
107 c.Position.Z - p.Position.Z) * Quaternion.Inverse(p.Orientation);
108 Vector3 avatarSize = new Vector3(c.Size.X, c.Size.Y, c.Size.Z) * Quaternion.Inverse(p.Orientation);
109
110 return (Math.Abs(rotatedPos.X) < (p.Size.X*0.5 + Math.Abs(avatarSize.X)) &&
111 Math.Abs(rotatedPos.Y) < (p.Size.Y*0.5 + Math.Abs(avatarSize.Y)) &&
112 Math.Abs(rotatedPos.Z) < (p.Size.Z*0.5 + Math.Abs(avatarSize.Z)));
113 }
114
115 private bool isCollidingWithPrim(POSCharacter c)
116 {
117 foreach (POSPrim p in _prims)
118 {
119 if (isColliding(c, p))
120 {
121 return true;
122 }
123 }
124
125 return false;
126 }
127
128 public override void AddPhysicsActorTaint(PhysicsActor prim)
129 {
130 }
131
132 public override float Simulate(float timeStep)
133 {
134 float fps = 0;
135 for (int i = 0; i < _characters.Count; ++i)
136 {
137 fps++;
138 POSCharacter character = _characters[i];
139
140 float oldposX = character.Position.X;
141 float oldposY = character.Position.Y;
142 float oldposZ = character.Position.Z;
143
144 if (!character.Flying)
145 {
146 character._target_velocity.Z += gravity * timeStep;
147 }
148
149 Vector3 characterPosition = character.Position;
150
151 characterPosition.X += character._target_velocity.X * timeStep;
152 characterPosition.Y += character._target_velocity.Y * timeStep;
153
154 characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f);
155 characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f);
156
157 bool forcedZ = false;
158
159 float terrainheight = _heightMap[(int)character.Position.Y * Constants.RegionSize + (int)character.Position.X];
160 if (character.Position.Z + (character._target_velocity.Z * timeStep) < terrainheight + 2)
161 {
162 characterPosition.Z = terrainheight + character.Size.Z;
163 forcedZ = true;
164 }
165 else
166 {
167 characterPosition.Z += character._target_velocity.Z*timeStep;
168 }
169
170 /// this is it -- the magic you've all been waiting for! Ladies and gentlemen --
171 /// Completely Bogus Collision Detection!!!
172 /// better known as the CBCD algorithm
173
174 if (isCollidingWithPrim(character))
175 {
176 characterPosition.Z = oldposZ; // first try Z axis
177 if (isCollidingWithPrim(character))
178 {
179 characterPosition.Z = oldposZ + character.Size.Z / 4.4f; // try harder
180 if (isCollidingWithPrim(character))
181 {
182 characterPosition.Z = oldposZ + character.Size.Z / 2.2f; // try very hard
183 if (isCollidingWithPrim(character))
184 {
185 characterPosition.X = oldposX;
186 characterPosition.Y = oldposY;
187 characterPosition.Z = oldposZ;
188
189 characterPosition.X += character._target_velocity.X * timeStep;
190 if (isCollidingWithPrim(character))
191 {
192 characterPosition.X = oldposX;
193 }
194
195 characterPosition.Y += character._target_velocity.Y * timeStep;
196 if (isCollidingWithPrim(character))
197 {
198 characterPosition.Y = oldposY;
199 }
200 }
201 else
202 {
203 forcedZ = true;
204 }
205 }
206 else
207 {
208 forcedZ = true;
209 }
210 }
211 else
212 {
213 forcedZ = true;
214 }
215 }
216
217 characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f);
218 characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f);
219
220 character.Position = characterPosition;
221
222 character._velocity.X = (character.Position.X - oldposX)/timeStep;
223 character._velocity.Y = (character.Position.Y - oldposY)/timeStep;
224
225 if (forcedZ)
226 {
227 character._velocity.Z = 0;
228 character._target_velocity.Z = 0;
229 ((PhysicsActor)character).IsColliding = true;
230 character.RequestPhysicsterseUpdate();
231 }
232 else
233 {
234 ((PhysicsActor)character).IsColliding = false;
235 character._velocity.Z = (character.Position.Z - oldposZ)/timeStep;
236 }
237 }
238 return fps;
239 }
240
241 public override void GetResults()
242 {
243 }
244
245 public override bool IsThreaded
246 {
247 // for now we won't be multithreaded
248 get { return (false); }
249 }
250
251 public override void SetTerrain(float[] heightMap)
252 {
253 _heightMap = heightMap;
254 }
255
256 public override void DeleteTerrain()
257 {
258 }
259
260 public override void SetWaterLevel(float baseheight)
261 {
262 }
263
264 public override Dictionary<uint, float> GetTopColliders()
265 {
266 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
267 return returncolliders;
268 }
269 }
270}