aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules
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/PhysicsModules
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/PhysicsModules')
-rw-r--r--OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs62
-rw-r--r--OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs303
-rw-r--r--OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs316
-rw-r--r--OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs256
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs2120
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs2589
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs457
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs174
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs219
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs220
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs138
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs139
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActors.cs154
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs763
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs813
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs144
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs180
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs181
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs54
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs55
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs55
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs103
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs1800
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs503
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs477
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs852
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs203
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSMotors.cs451
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSParam.cs927
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs620
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs1895
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs182
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs349
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSScene.cs1333
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs425
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSShapes.cs1463
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs169
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs584
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs440
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs277
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt379
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs622
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs36
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs156
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs56
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs109
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs205
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/CTri.cs341
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs233
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs411
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs200
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs74
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs171
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs99
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs1868
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/LICENSE.txt28
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Plane.cs99
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs211
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs209
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/README.txt7
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/SplitPlane.cs265
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs70
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs70
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs444
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs195
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs170
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs284
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs128
-rw-r--r--OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs66
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/HelperTypes.cs436
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs333
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs1010
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/PrimMesher.cs2324
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMap.cs183
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMesh.cs646
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs36
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/ZeroMesher.cs132
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs62
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs1409
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments630
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs974
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs3382
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs441
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs48
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/OdeScene.cs4117
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs151
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/drawstuff.cs98
-rw-r--r--OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs62
-rw-r--r--OpenSim/Region/PhysicsModules/POS/POSCharacter.cs341
-rw-r--r--OpenSim/Region/PhysicsModules/POS/POSPrim.cs336
-rw-r--r--OpenSim/Region/PhysicsModules/POS/POSScene.cs323
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/CollisionLocker.cs73
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs71
-rwxr-xr-xOpenSim/Region/PhysicsModules/SharedBase/IPhysicsParameters.cs73
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs117
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs584
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/PhysicsJoint.cs55
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs358
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs78
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs186
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs121
103 files changed, 48935 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs
new file mode 100644
index 0000000..1765ae0
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs
@@ -0,0 +1,62 @@
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;
30using Mono.Addins;
31
32// Information about this assembly is defined by the following
33// attributes.
34//
35// change them to the information which is associated with the assembly
36// you compile.
37
38[assembly : AssemblyTitle("BasicPhysicsModule")]
39[assembly : AssemblyDescription("")]
40[assembly : AssemblyConfiguration("")]
41[assembly : AssemblyCompany("http://opensimulator.org")]
42[assembly : AssemblyProduct("BasicPhysicsModule")]
43[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
44[assembly : AssemblyTrademark("")]
45[assembly : AssemblyCulture("")]
46
47// This sets the default COM visibility of types in the assembly to invisible.
48// If you need to expose a type to COM, use [ComVisible(true)] on that type.
49
50[assembly : ComVisible(false)]
51
52// The assembly version has following format :
53//
54// Major.Minor.Build.Revision
55//
56// You can specify all values by your own or you can build default build and revision
57// numbers with the '*' character (the default):
58
59[assembly : AssemblyVersion("0.8.2.*")]
60
61[assembly: Addin("OpenSim.Region.PhysicsModule.BasicPhysics", OpenSim.VersionInfo.VersionNumber)]
62[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs
new file mode 100644
index 0000000..e7b30ba
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs
@@ -0,0 +1,303 @@
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.PhysicsModules.SharedBase;
34
35namespace OpenSim.Region.PhysicsModule.BasicPhysics
36{
37 public class BasicActor : PhysicsActor
38 {
39 public BasicActor(Vector3 size)
40 {
41 Size = size;
42 }
43
44 public override int PhysicsActorType
45 {
46 get { return (int) ActorTypes.Agent; }
47 set { return; }
48 }
49
50 public override Vector3 RotationalVelocity { get; set; }
51
52 public override bool SetAlwaysRun
53 {
54 get { return false; }
55 set { return; }
56 }
57
58 public override uint LocalID
59 {
60 set { return; }
61 }
62
63 public override bool Grabbed
64 {
65 set { return; }
66 }
67
68 public override bool Selected
69 {
70 set { return; }
71 }
72
73 public override float Buoyancy
74 {
75 get { return 0f; }
76 set { return; }
77 }
78
79 public override bool FloatOnWater
80 {
81 set { return; }
82 }
83
84 public override bool IsPhysical
85 {
86 get { return false; }
87 set { return; }
88 }
89
90 public override bool ThrottleUpdates
91 {
92 get { return false; }
93 set { return; }
94 }
95
96 public override bool Flying { get; set; }
97
98 public override bool IsColliding { get; set; }
99
100 public override bool CollidingGround
101 {
102 get { return false; }
103 set { return; }
104 }
105
106 public override bool CollidingObj
107 {
108 get { return false; }
109 set { return; }
110 }
111
112 public override bool Stopped
113 {
114 get { return false; }
115 }
116
117 public override Vector3 Position { get; set; }
118
119 public override Vector3 Size { get; set; }
120
121 public override PrimitiveBaseShape Shape
122 {
123 set { return; }
124 }
125
126 public override float Mass
127 {
128 get { return 0f; }
129 }
130
131 public override Vector3 Force
132 {
133 get { return Vector3.Zero; }
134 set { return; }
135 }
136
137 public override int VehicleType
138 {
139 get { return 0; }
140 set { return; }
141 }
142
143 public override void VehicleFloatParam(int param, float value)
144 {
145
146 }
147
148 public override void VehicleVectorParam(int param, Vector3 value)
149 {
150
151 }
152
153 public override void VehicleRotationParam(int param, Quaternion rotation)
154 {
155
156 }
157
158 public override void VehicleFlags(int param, bool remove)
159 {
160
161 }
162
163 public override void SetVolumeDetect(int param)
164 {
165
166 }
167
168 public override Vector3 CenterOfMass
169 {
170 get { return Vector3.Zero; }
171 }
172
173 public override Vector3 GeometricCenter
174 {
175 get { return Vector3.Zero; }
176 }
177
178 public override Vector3 Velocity { get; set; }
179
180 public override Vector3 Torque
181 {
182 get { return Vector3.Zero; }
183 set { return; }
184 }
185
186 public override float CollisionScore
187 {
188 get { return 0f; }
189 set { }
190 }
191
192 public override Quaternion Orientation
193 {
194 get { return Quaternion.Identity; }
195 set { }
196 }
197
198 public override Vector3 Acceleration { get; set; }
199
200 public override bool Kinematic
201 {
202 get { return true; }
203 set { }
204 }
205
206 public override void link(PhysicsActor obj)
207 {
208 }
209
210 public override void delink()
211 {
212 }
213
214 public override void LockAngularMotion(Vector3 axis)
215 {
216 }
217
218 public override void AddForce(Vector3 force, bool pushforce)
219 {
220 }
221
222 public override void AddAngularForce(Vector3 force, bool pushforce)
223 {
224 }
225
226 public override void SetMomentum(Vector3 momentum)
227 {
228 }
229
230 public override void CrossingFailure()
231 {
232 }
233
234 public override Vector3 PIDTarget
235 {
236 set { return; }
237 }
238
239 public override bool PIDActive
240 {
241 get { return false; }
242 set { return; }
243 }
244
245 public override float PIDTau
246 {
247 set { return; }
248 }
249
250 public override float PIDHoverHeight
251 {
252 set { return; }
253 }
254
255 public override bool PIDHoverActive
256 {
257 set { return; }
258 }
259
260 public override PIDHoverType PIDHoverType
261 {
262 set { return; }
263 }
264
265 public override float PIDHoverTau
266 {
267 set { return; }
268 }
269
270 public override Quaternion APIDTarget
271 {
272 set { return; }
273 }
274
275 public override bool APIDActive
276 {
277 set { return; }
278 }
279
280 public override float APIDStrength
281 {
282 set { return; }
283 }
284
285 public override float APIDDamping
286 {
287 set { return; }
288 }
289
290 public override void SubscribeEvents(int ms)
291 {
292 }
293
294 public override void UnSubscribeEvents()
295 {
296 }
297
298 public override bool SubscribedEvents()
299 {
300 return false;
301 }
302 }
303}
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs
new file mode 100644
index 0000000..5383f1b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs
@@ -0,0 +1,316 @@
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.PhysicsModules.SharedBase;
34
35namespace OpenSim.Region.PhysicsModule.BasicPhysics
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 get { return false; }
255 set { return; }
256 }
257
258 public override float PIDTau
259 {
260 set { return; }
261 }
262
263 public override float PIDHoverHeight
264 {
265 set { return; }
266 }
267
268 public override bool PIDHoverActive
269 {
270 set { return; }
271 }
272
273 public override PIDHoverType PIDHoverType
274 {
275 set { return; }
276 }
277
278 public override float PIDHoverTau
279 {
280 set { return; }
281 }
282
283 public override Quaternion APIDTarget
284 {
285 set { return; }
286 }
287
288 public override bool APIDActive
289 {
290 set { return; }
291 }
292
293 public override float APIDStrength
294 {
295 set { return; }
296 }
297
298 public override float APIDDamping
299 {
300 set { return; }
301 }
302
303 public override void SubscribeEvents(int ms)
304 {
305 }
306
307 public override void UnSubscribeEvents()
308 {
309 }
310
311 public override bool SubscribedEvents()
312 {
313 return false;
314 }
315 }
316}
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs
new file mode 100644
index 0000000..20b337a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs
@@ -0,0 +1,256 @@
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 Mono.Addins;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.PhysicsModules.SharedBase;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Interfaces;
37
38namespace OpenSim.Region.PhysicsModule.BasicPhysics
39{
40 /// <summary>
41 /// This is an incomplete extremely basic physics implementation
42 /// </summary>
43 /// <remarks>
44 /// Not useful for anything at the moment apart from some regression testing in other components where some form
45 /// of physics plugin is needed.
46 /// </remarks>
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BasicPhysicsScene")]
48 public class BasicScene : PhysicsScene, INonSharedRegionModule
49 {
50 private List<BasicActor> _actors = new List<BasicActor>();
51 private List<BasicPhysicsPrim> _prims = new List<BasicPhysicsPrim>();
52 private float[] _heightMap;
53 private Vector3 m_regionExtent;
54
55 private bool m_Enabled = false;
56
57 //protected internal string sceneIdentifier;
58 #region INonSharedRegionModule
59 public string Name
60 {
61 get { return "basicphysics"; }
62 }
63
64 public Type ReplaceableInterface
65 {
66 get { return null; }
67 }
68
69 public void Initialise(IConfigSource source)
70 {
71 // TODO: Move this out of Startup
72 IConfig config = source.Configs["Startup"];
73 if (config != null)
74 {
75 string physics = config.GetString("physics", string.Empty);
76 if (physics == Name)
77 m_Enabled = true;
78 }
79
80 }
81
82 public void Close()
83 {
84 }
85
86 public void AddRegion(Scene scene)
87 {
88 if (!m_Enabled)
89 return;
90
91 EngineType = Name;
92 PhysicsSceneName = EngineType + "/" + scene.RegionInfo.RegionName;
93
94 scene.RegisterModuleInterface<PhysicsScene>(this);
95 m_regionExtent = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, scene.RegionInfo.RegionSizeZ);
96 base.Initialise(scene.PhysicsRequestAsset,
97 (scene.Heightmap != null ? scene.Heightmap.GetFloatsSerialised() : new float[scene.RegionInfo.RegionSizeX * scene.RegionInfo.RegionSizeY]),
98 (float)scene.RegionInfo.RegionSettings.WaterHeight);
99
100 }
101
102 public void RemoveRegion(Scene scene)
103 {
104 if (!m_Enabled)
105 return;
106 }
107
108 public void RegionLoaded(Scene scene)
109 {
110 if (!m_Enabled)
111 return;
112 }
113 #endregion
114
115 public override void Dispose() {}
116
117 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
118 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
119 {
120 BasicPhysicsPrim prim = new BasicPhysicsPrim(primName, localid, position, size, rotation, pbs);
121 prim.IsPhysical = isPhysical;
122
123 _prims.Add(prim);
124
125 return prim;
126 }
127
128 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
129 {
130 BasicActor act = new BasicActor(size);
131 act.Position = position;
132 act.Velocity = velocity;
133 act.Flying = isFlying;
134 _actors.Add(act);
135 return act;
136 }
137
138 public override void RemovePrim(PhysicsActor actor)
139 {
140 BasicPhysicsPrim prim = (BasicPhysicsPrim)actor;
141 if (_prims.Contains(prim))
142 _prims.Remove(prim);
143 }
144
145 public override void RemoveAvatar(PhysicsActor actor)
146 {
147 BasicActor act = (BasicActor)actor;
148 if (_actors.Contains(act))
149 _actors.Remove(act);
150 }
151
152 public override void AddPhysicsActorTaint(PhysicsActor prim)
153 {
154 }
155
156 public override float Simulate(float timeStep)
157 {
158// Console.WriteLine("Simulating");
159
160 float fps = 0;
161 for (int i = 0; i < _actors.Count; ++i)
162 {
163 BasicActor actor = _actors[i];
164 Vector3 actorPosition = actor.Position;
165 Vector3 actorVelocity = actor.Velocity;
166
167 //Console.WriteLine(
168 // "Processing actor {0}, starting pos {1}, starting vel {2}", i, actorPosition, actorVelocity);
169
170 actorPosition.X += actor.Velocity.X * timeStep;
171 actorPosition.Y += actor.Velocity.Y * timeStep;
172
173 if (actor.Position.Y < 0)
174 {
175 actorPosition.Y = 0.1F;
176 }
177 else if (actor.Position.Y >= m_regionExtent.Y)
178 {
179 actorPosition.Y = (m_regionExtent.Y - 0.1f);
180 }
181
182 if (actor.Position.X < 0)
183 {
184 actorPosition.X = 0.1F;
185 }
186 else if (actor.Position.X >= m_regionExtent.X)
187 {
188 actorPosition.X = (m_regionExtent.X - 0.1f);
189 }
190
191 float terrainHeight = 0;
192 if (_heightMap != null)
193 terrainHeight = _heightMap[(int)actor.Position.Y * (int)m_regionExtent.Y + (int)actor.Position.X];
194
195 float height = terrainHeight + actor.Size.Z;
196// Console.WriteLine("height {0}, actorPosition {1}", height, actorPosition);
197
198 if (actor.Flying)
199 {
200 if (actor.Position.Z + (actor.Velocity.Z * timeStep) < terrainHeight + 2)
201 {
202 actorPosition.Z = height;
203 actorVelocity.Z = 0;
204 actor.IsColliding = true;
205 }
206 else
207 {
208 actorPosition.Z += actor.Velocity.Z * timeStep;
209 actor.IsColliding = false;
210 }
211 }
212 else
213 {
214 actorPosition.Z = height;
215 actorVelocity.Z = 0;
216 actor.IsColliding = true;
217 }
218
219 actor.Position = actorPosition;
220 actor.Velocity = actorVelocity;
221 }
222
223 return fps;
224 }
225
226 public override void GetResults()
227 {
228 }
229
230 public override bool IsThreaded
231 {
232 get { return (false); // for now we won't be multithreaded
233 }
234 }
235
236 public override void SetTerrain(float[] heightMap)
237 {
238 _heightMap = heightMap;
239 }
240
241 public override void DeleteTerrain()
242 {
243 }
244
245 public override void SetWaterLevel(float baseheight)
246 {
247 }
248
249 public override Dictionary<uint, float> GetTopColliders()
250 {
251 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
252 return returncolliders;
253 }
254
255 }
256}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
new file mode 100755
index 0000000..c4a923c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
@@ -0,0 +1,2120 @@
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.PhysicsModule.BulletS
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 shapeType = 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, shapeType);
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 if (m_paramsHandle.IsAllocated)
217 {
218 m_paramsHandle.Free();
219 }
220 if (m_collisionArrayPinnedHandle.IsAllocated)
221 {
222 m_collisionArrayPinnedHandle.Free();
223 }
224 if (m_updateArrayPinnedHandle.IsAllocated)
225 {
226 m_updateArrayPinnedHandle.Free();
227 }
228}
229
230public override bool PushUpdate(BulletBody obj)
231{
232 BulletBodyUnman bodyu = obj as BulletBodyUnman;
233 return BSAPICPP.PushUpdate2(bodyu.ptr);
234}
235
236public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value)
237{
238 BulletWorldUnman worldu = world as BulletWorldUnman;
239 return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value);
240}
241
242// =====================================================================================
243// Mesh, hull, shape and body creation helper routines
244public override BulletShape CreateMeshShape(BulletWorld world,
245 int indicesCount, int[] indices,
246 int verticesCount, float[] vertices)
247{
248 BulletWorldUnman worldu = world as BulletWorldUnman;
249 return new BulletShapeUnman(
250 BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
251 BSPhysicsShapeType.SHAPE_MESH);
252}
253
254public override BulletShape CreateGImpactShape(BulletWorld world,
255 int indicesCount, int[] indices,
256 int verticesCount, float[] vertices)
257{
258 BulletWorldUnman worldu = world as BulletWorldUnman;
259 return new BulletShapeUnman(
260 BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
261 BSPhysicsShapeType.SHAPE_GIMPACT);
262}
263
264public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
265{
266 BulletWorldUnman worldu = world as BulletWorldUnman;
267 return new BulletShapeUnman(
268 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
269 BSPhysicsShapeType.SHAPE_HULL);
270}
271
272public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
273{
274 BulletWorldUnman worldu = world as BulletWorldUnman;
275 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
276 return new BulletShapeUnman(
277 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms),
278 BSPhysicsShapeType.SHAPE_HULL);
279}
280
281public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
282{
283 BulletWorldUnman worldu = world as BulletWorldUnman;
284 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
285 return new BulletShapeUnman(
286 BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
287 BSPhysicsShapeType.SHAPE_CONVEXHULL);
288}
289
290public override BulletShape CreateConvexHullShape(BulletWorld world,
291 int indicesCount, int[] indices,
292 int verticesCount, float[] vertices)
293{
294 BulletWorldUnman worldu = world as BulletWorldUnman;
295 return new BulletShapeUnman(
296 BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
297 BSPhysicsShapeType.SHAPE_CONVEXHULL);
298}
299
300public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
301{
302 BulletWorldUnman worldu = world as BulletWorldUnman;
303 return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type);
304}
305
306public override bool IsNativeShape(BulletShape shape)
307{
308 BulletShapeUnman shapeu = shape as BulletShapeUnman;
309 if (shapeu != null && shapeu.HasPhysicalShape)
310 return BSAPICPP.IsNativeShape2(shapeu.ptr);
311 return false;
312}
313
314public override void SetShapeCollisionMargin(BulletShape shape, float margin)
315{
316 BulletShapeUnman shapeu = shape as BulletShapeUnman;
317 if (shapeu != null && shapeu.HasPhysicalShape)
318 BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin);
319}
320
321public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
322{
323 BulletWorldUnman worldu = world as BulletWorldUnman;
324 return new BulletShapeUnman(
325 BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale),
326 BSPhysicsShapeType.SHAPE_CAPSULE);
327}
328
329public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree)
330{
331 BulletWorldUnman worldu = world as BulletWorldUnman;
332 return new BulletShapeUnman(
333 BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree),
334 BSPhysicsShapeType.SHAPE_COMPOUND);
335
336}
337
338public override int GetNumberOfCompoundChildren(BulletShape shape)
339{
340 BulletShapeUnman shapeu = shape as BulletShapeUnman;
341 if (shapeu != null && shapeu.HasPhysicalShape)
342 return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr);
343 return 0;
344}
345
346public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot)
347{
348 BulletShapeUnman shapeu = shape as BulletShapeUnman;
349 BulletShapeUnman addShapeu = addShape as BulletShapeUnman;
350 BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot);
351}
352
353public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
354{
355 BulletShapeUnman shapeu = shape as BulletShapeUnman;
356 return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
357}
358
359public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
360{
361 BulletShapeUnman shapeu = shape as BulletShapeUnman;
362 return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
363}
364
365public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape)
366{
367 BulletShapeUnman shapeu = shape as BulletShapeUnman;
368 BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman;
369 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
370}
371
372public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb)
373{
374 BulletShapeUnman shapeu = pShape as BulletShapeUnman;
375 BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb);
376}
377
378public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
379{
380 BulletShapeUnman shapeu = shape as BulletShapeUnman;
381 BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr);
382}
383
384public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id)
385{
386 BulletWorldUnman worldu = world as BulletWorldUnman;
387 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
388 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
389}
390
391public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
392{
393 BulletWorldUnman worldu = world as BulletWorldUnman;
394 BulletShapeUnman shapeu = shape as BulletShapeUnman;
395 return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr);
396}
397
398public override CollisionObjectTypes GetBodyType(BulletBody obj)
399{
400 BulletBodyUnman bodyu = obj as BulletBodyUnman;
401 return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr);
402}
403
404public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
405{
406 BulletWorldUnman worldu = world as BulletWorldUnman;
407 BulletShapeUnman shapeu = shape as BulletShapeUnman;
408 return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
409}
410
411public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot)
412{
413 BulletShapeUnman shapeu = shape as BulletShapeUnman;
414 return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot));
415}
416
417public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
418{
419 BulletWorldUnman worldu = world as BulletWorldUnman;
420 BulletShapeUnman shapeu = shape as BulletShapeUnman;
421 return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
422}
423
424public override void DestroyObject(BulletWorld world, BulletBody obj)
425{
426 BulletWorldUnman worldu = world as BulletWorldUnman;
427 BulletBodyUnman bodyu = obj as BulletBodyUnman;
428 BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr);
429}
430
431// =====================================================================================
432// Terrain creation and helper routines
433public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin)
434{
435 return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE);
436}
437
438public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
439 float scaleFactor, float collisionMargin)
440{
441 return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin),
442 BSPhysicsShapeType.SHAPE_TERRAIN);
443}
444
445// =====================================================================================
446// Constraint creation and helper routines
447public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
448 Vector3 frame1loc, Quaternion frame1rot,
449 Vector3 frame2loc, Quaternion frame2rot,
450 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
451{
452 BulletWorldUnman worldu = world as BulletWorldUnman;
453 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
454 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
455 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
456 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
457}
458
459public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
460 Vector3 joinPoint,
461 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
462{
463 BulletWorldUnman worldu = world as BulletWorldUnman;
464 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
465 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
466 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
467 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
468}
469
470public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
471 Vector3 frameInBloc, Quaternion frameInBrot,
472 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
473{
474 BulletWorldUnman worldu = world as BulletWorldUnman;
475 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
476 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr,
477 frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies));
478}
479
480public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
481 Vector3 frame1loc, Quaternion frame1rot,
482 Vector3 frame2loc, Quaternion frame2rot,
483 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
484{
485 BulletWorldUnman worldu = world as BulletWorldUnman;
486 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
487 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
488 return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
489 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
490}
491
492public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
493 Vector3 pivotinA, Vector3 pivotinB,
494 Vector3 axisInA, Vector3 axisInB,
495 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
496{
497 BulletWorldUnman worldu = world as BulletWorldUnman;
498 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
499 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
500 return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
501 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
502}
503
504public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
505 Vector3 frame1loc, Quaternion frame1rot,
506 Vector3 frame2loc, Quaternion frame2rot,
507 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
508{
509 BulletWorldUnman worldu = world as BulletWorldUnman;
510 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
511 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
512 return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
513 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
514}
515
516public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
517 Vector3 frame1loc, Quaternion frame1rot,
518 Vector3 frame2loc, Quaternion frame2rot,
519 bool disableCollisionsBetweenLinkedBodies)
520{
521 BulletWorldUnman worldu = world as BulletWorldUnman;
522 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
523 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
524 return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
525 frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies));
526}
527
528public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
529 Vector3 axisInA, Vector3 axisInB,
530 float ratio, bool disableCollisionsBetweenLinkedBodies)
531{
532 BulletWorldUnman worldu = world as BulletWorldUnman;
533 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
534 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
535 return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB,
536 ratio, disableCollisionsBetweenLinkedBodies));
537}
538
539public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
540 Vector3 pivotInA, Vector3 pivotInB,
541 bool disableCollisionsBetweenLinkedBodies)
542{
543 BulletWorldUnman worldu = world as BulletWorldUnman;
544 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
545 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
546 return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB,
547 disableCollisionsBetweenLinkedBodies));
548}
549
550public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
551{
552 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
553 BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse);
554}
555
556public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations)
557{
558 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
559 BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations);
560}
561
562public override bool SetFrames(BulletConstraint constrain,
563 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
564{
565 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
566 return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot);
567}
568
569public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
570{
571 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
572 return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi);
573}
574
575public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
576{
577 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
578 return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi);
579}
580
581public override bool UseFrameOffset(BulletConstraint constrain, float enable)
582{
583 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
584 return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable);
585}
586
587public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce)
588{
589 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
590 return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce);
591}
592
593public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold)
594{
595 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
596 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
597}
598
599public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation)
600{
601 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
602 return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation);
603}
604
605public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse)
606{
607 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
608 return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse);
609}
610
611public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint)
612{
613 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
614 return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint);
615}
616
617public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss)
618{
619 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
620 return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss);
621}
622
623public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping)
624{
625 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
626 return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping);
627}
628
629public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val)
630{
631 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
632 return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val);
633}
634
635public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val)
636{
637 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
638 return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val);
639}
640
641public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse)
642{
643 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
644 return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse);
645}
646
647public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val)
648{
649 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
650 return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val);
651}
652
653public override bool CalculateTransforms(BulletConstraint constrain)
654{
655 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
656 return BSAPICPP.CalculateTransforms2(constrainu.ptr);
657}
658
659public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis)
660{
661 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
662 return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis);
663}
664
665public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain)
666{
667 BulletWorldUnman worldu = world as BulletWorldUnman;
668 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
669 return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr);
670}
671
672// =====================================================================================
673// btCollisionWorld entries
674public override void UpdateSingleAabb(BulletWorld world, BulletBody obj)
675{
676 BulletWorldUnman worldu = world as BulletWorldUnman;
677 BulletBodyUnman bodyu = obj as BulletBodyUnman;
678 BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr);
679}
680
681public override void UpdateAabbs(BulletWorld world)
682{
683 BulletWorldUnman worldu = world as BulletWorldUnman;
684 BSAPICPP.UpdateAabbs2(worldu.ptr);
685}
686
687public override bool GetForceUpdateAllAabbs(BulletWorld world)
688{
689 BulletWorldUnman worldu = world as BulletWorldUnman;
690 return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr);
691}
692
693public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
694{
695 BulletWorldUnman worldu = world as BulletWorldUnman;
696 BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force);
697}
698
699// =====================================================================================
700// btDynamicsWorld entries
701public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
702{
703 BulletWorldUnman worldu = world as BulletWorldUnman;
704 BulletBodyUnman bodyu = obj as BulletBodyUnman;
705
706 // Bullet resets several variables when an object is added to the world.
707 // Gravity is reset to world default depending on the static/dynamic
708 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
709 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
710
711 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
712
713 if (ret)
714 {
715 BSAPICPP.SetGravity2(bodyu.ptr, origGrav);
716 obj.ApplyCollisionMask(world.physicsScene);
717 }
718 return ret;
719}
720
721public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
722{
723 BulletWorldUnman worldu = world as BulletWorldUnman;
724 BulletBodyUnman bodyu = obj as BulletBodyUnman;
725 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
726}
727
728public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj)
729{
730 BulletWorldUnman worldu = world as BulletWorldUnman;
731 BulletBodyUnman bodyu = obj as BulletBodyUnman;
732 return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr);
733}
734
735public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
736{
737 BulletWorldUnman worldu = world as BulletWorldUnman;
738 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
739 return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects);
740}
741
742public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
743{
744 BulletWorldUnman worldu = world as BulletWorldUnman;
745 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
746 return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr);
747}
748// =====================================================================================
749// btCollisionObject entries
750public override Vector3 GetAnisotripicFriction(BulletConstraint constrain)
751{
752 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
753 return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr);
754}
755
756public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict)
757{
758 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
759 return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict);
760}
761
762public override bool HasAnisotripicFriction(BulletConstraint constrain)
763{
764 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
765 return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr);
766}
767
768public override void SetContactProcessingThreshold(BulletBody obj, float val)
769{
770 BulletBodyUnman bodyu = obj as BulletBodyUnman;
771 BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val);
772}
773
774public override float GetContactProcessingThreshold(BulletBody obj)
775{
776 BulletBodyUnman bodyu = obj as BulletBodyUnman;
777 return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr);
778}
779
780public override bool IsStaticObject(BulletBody obj)
781{
782 BulletBodyUnman bodyu = obj as BulletBodyUnman;
783 return BSAPICPP.IsStaticObject2(bodyu.ptr);
784}
785
786public override bool IsKinematicObject(BulletBody obj)
787{
788 BulletBodyUnman bodyu = obj as BulletBodyUnman;
789 return BSAPICPP.IsKinematicObject2(bodyu.ptr);
790}
791
792public override bool IsStaticOrKinematicObject(BulletBody obj)
793{
794 BulletBodyUnman bodyu = obj as BulletBodyUnman;
795 return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr);
796}
797
798public override bool HasContactResponse(BulletBody obj)
799{
800 BulletBodyUnman bodyu = obj as BulletBodyUnman;
801 return BSAPICPP.HasContactResponse2(bodyu.ptr);
802}
803
804public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape)
805{
806 BulletWorldUnman worldu = world as BulletWorldUnman;
807 BulletBodyUnman bodyu = obj as BulletBodyUnman;
808 BulletShapeUnman shapeu = shape as BulletShapeUnman;
809 if (worldu != null && bodyu != null)
810 {
811 // Special case to allow the caller to zero out the reference to any physical shape
812 if (shapeu != null)
813 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr);
814 else
815 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero);
816 }
817}
818
819public override BulletShape GetCollisionShape(BulletBody obj)
820{
821 BulletBodyUnman bodyu = obj as BulletBodyUnman;
822 return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN);
823}
824
825public override int GetActivationState(BulletBody obj)
826{
827 BulletBodyUnman bodyu = obj as BulletBodyUnman;
828 return BSAPICPP.GetActivationState2(bodyu.ptr);
829}
830
831public override void SetActivationState(BulletBody obj, int state)
832{
833 BulletBodyUnman bodyu = obj as BulletBodyUnman;
834 BSAPICPP.SetActivationState2(bodyu.ptr, state);
835}
836
837public override void SetDeactivationTime(BulletBody obj, float dtime)
838{
839 BulletBodyUnman bodyu = obj as BulletBodyUnman;
840 BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime);
841}
842
843public override float GetDeactivationTime(BulletBody obj)
844{
845 BulletBodyUnman bodyu = obj as BulletBodyUnman;
846 return BSAPICPP.GetDeactivationTime2(bodyu.ptr);
847}
848
849public override void ForceActivationState(BulletBody obj, ActivationState state)
850{
851 BulletBodyUnman bodyu = obj as BulletBodyUnman;
852 BSAPICPP.ForceActivationState2(bodyu.ptr, state);
853}
854
855public override void Activate(BulletBody obj, bool forceActivation)
856{
857 BulletBodyUnman bodyu = obj as BulletBodyUnman;
858 BSAPICPP.Activate2(bodyu.ptr, forceActivation);
859}
860
861public override bool IsActive(BulletBody obj)
862{
863 BulletBodyUnman bodyu = obj as BulletBodyUnman;
864 return BSAPICPP.IsActive2(bodyu.ptr);
865}
866
867public override void SetRestitution(BulletBody obj, float val)
868{
869 BulletBodyUnman bodyu = obj as BulletBodyUnman;
870 BSAPICPP.SetRestitution2(bodyu.ptr, val);
871}
872
873public override float GetRestitution(BulletBody obj)
874{
875 BulletBodyUnman bodyu = obj as BulletBodyUnman;
876 return BSAPICPP.GetRestitution2(bodyu.ptr);
877}
878
879public override void SetFriction(BulletBody obj, float val)
880{
881 BulletBodyUnman bodyu = obj as BulletBodyUnman;
882 BSAPICPP.SetFriction2(bodyu.ptr, val);
883}
884
885public override float GetFriction(BulletBody obj)
886{
887 BulletBodyUnman bodyu = obj as BulletBodyUnman;
888 return BSAPICPP.GetFriction2(bodyu.ptr);
889}
890
891public override Vector3 GetPosition(BulletBody obj)
892{
893 BulletBodyUnman bodyu = obj as BulletBodyUnman;
894 return BSAPICPP.GetPosition2(bodyu.ptr);
895}
896
897public override Quaternion GetOrientation(BulletBody obj)
898{
899 BulletBodyUnman bodyu = obj as BulletBodyUnman;
900 return BSAPICPP.GetOrientation2(bodyu.ptr);
901}
902
903public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation)
904{
905 BulletBodyUnman bodyu = obj as BulletBodyUnman;
906 BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation);
907}
908
909 /*
910public override IntPtr GetBroadphaseHandle(BulletBody obj)
911{
912 BulletBodyUnman bodyu = obj as BulletBodyUnman;
913 return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr);
914}
915
916public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle)
917{
918 BulletBodyUnman bodyu = obj as BulletBodyUnman;
919 BSAPICPP.SetUserPointer2(bodyu.ptr, handle);
920}
921 */
922
923public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel)
924{
925 BulletBodyUnman bodyu = obj as BulletBodyUnman;
926 BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel);
927}
928
929public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel)
930{
931 BulletBodyUnman bodyu = obj as BulletBodyUnman;
932 BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel);
933}
934
935public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel)
936{
937 BulletBodyUnman bodyu = obj as BulletBodyUnman;
938 BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel);
939}
940
941public override float GetHitFraction(BulletBody obj)
942{
943 BulletBodyUnman bodyu = obj as BulletBodyUnman;
944 return BSAPICPP.GetHitFraction2(bodyu.ptr);
945}
946
947public override void SetHitFraction(BulletBody obj, float val)
948{
949 BulletBodyUnman bodyu = obj as BulletBodyUnman;
950 BSAPICPP.SetHitFraction2(bodyu.ptr, val);
951}
952
953public override CollisionFlags GetCollisionFlags(BulletBody obj)
954{
955 BulletBodyUnman bodyu = obj as BulletBodyUnman;
956 return BSAPICPP.GetCollisionFlags2(bodyu.ptr);
957}
958
959public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags)
960{
961 BulletBodyUnman bodyu = obj as BulletBodyUnman;
962 return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags);
963}
964
965public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags)
966{
967 BulletBodyUnman bodyu = obj as BulletBodyUnman;
968 return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags);
969}
970
971public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags)
972{
973 BulletBodyUnman bodyu = obj as BulletBodyUnman;
974 return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags);
975}
976
977public override float GetCcdMotionThreshold(BulletBody obj)
978{
979 BulletBodyUnman bodyu = obj as BulletBodyUnman;
980 return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr);
981}
982
983
984public override void SetCcdMotionThreshold(BulletBody obj, float val)
985{
986 BulletBodyUnman bodyu = obj as BulletBodyUnman;
987 BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val);
988}
989
990public override float GetCcdSweptSphereRadius(BulletBody obj)
991{
992 BulletBodyUnman bodyu = obj as BulletBodyUnman;
993 return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr);
994}
995
996public override void SetCcdSweptSphereRadius(BulletBody obj, float val)
997{
998 BulletBodyUnman bodyu = obj as BulletBodyUnman;
999 BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val);
1000}
1001
1002public override IntPtr GetUserPointer(BulletBody obj)
1003{
1004 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1005 return BSAPICPP.GetUserPointer2(bodyu.ptr);
1006}
1007
1008public override void SetUserPointer(BulletBody obj, IntPtr val)
1009{
1010 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1011 BSAPICPP.SetUserPointer2(bodyu.ptr, val);
1012}
1013
1014// =====================================================================================
1015// btRigidBody entries
1016public override void ApplyGravity(BulletBody obj)
1017{
1018 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1019 BSAPICPP.ApplyGravity2(bodyu.ptr);
1020}
1021
1022public override void SetGravity(BulletBody obj, Vector3 val)
1023{
1024 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1025 BSAPICPP.SetGravity2(bodyu.ptr, val);
1026}
1027
1028public override Vector3 GetGravity(BulletBody obj)
1029{
1030 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1031 return BSAPICPP.GetGravity2(bodyu.ptr);
1032}
1033
1034public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping)
1035{
1036 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1037 BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping);
1038}
1039
1040public override void SetLinearDamping(BulletBody obj, float lin_damping)
1041{
1042 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1043 BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping);
1044}
1045
1046public override void SetAngularDamping(BulletBody obj, float ang_damping)
1047{
1048 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1049 BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping);
1050}
1051
1052public override float GetLinearDamping(BulletBody obj)
1053{
1054 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1055 return BSAPICPP.GetLinearDamping2(bodyu.ptr);
1056}
1057
1058public override float GetAngularDamping(BulletBody obj)
1059{
1060 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1061 return BSAPICPP.GetAngularDamping2(bodyu.ptr);
1062}
1063
1064public override float GetLinearSleepingThreshold(BulletBody obj)
1065{
1066 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1067 return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr);
1068}
1069
1070public override void ApplyDamping(BulletBody obj, float timeStep)
1071{
1072 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1073 BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep);
1074}
1075
1076public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia)
1077{
1078 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1079 BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia);
1080}
1081
1082public override Vector3 GetLinearFactor(BulletBody obj)
1083{
1084 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1085 return BSAPICPP.GetLinearFactor2(bodyu.ptr);
1086}
1087
1088public override void SetLinearFactor(BulletBody obj, Vector3 factor)
1089{
1090 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1091 BSAPICPP.SetLinearFactor2(bodyu.ptr, factor);
1092}
1093
1094public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot)
1095{
1096 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1097 BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot);
1098}
1099
1100// Add a force to the object as if its mass is one.
1101// Deep down in Bullet: m_totalForce += force*m_linearFactor;
1102public override void ApplyCentralForce(BulletBody obj, Vector3 force)
1103{
1104 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1105 BSAPICPP.ApplyCentralForce2(bodyu.ptr, force);
1106}
1107
1108// Set the force being applied to the object as if its mass is one.
1109public override void SetObjectForce(BulletBody obj, Vector3 force)
1110{
1111 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1112 BSAPICPP.SetObjectForce2(bodyu.ptr, force);
1113}
1114
1115public override Vector3 GetTotalForce(BulletBody obj)
1116{
1117 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1118 return BSAPICPP.GetTotalForce2(bodyu.ptr);
1119}
1120
1121public override Vector3 GetTotalTorque(BulletBody obj)
1122{
1123 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1124 return BSAPICPP.GetTotalTorque2(bodyu.ptr);
1125}
1126
1127public override Vector3 GetInvInertiaDiagLocal(BulletBody obj)
1128{
1129 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1130 return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr);
1131}
1132
1133public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert)
1134{
1135 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1136 BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert);
1137}
1138
1139public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold)
1140{
1141 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1142 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
1143}
1144
1145// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
1146public override void ApplyTorque(BulletBody obj, Vector3 torque)
1147{
1148 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1149 BSAPICPP.ApplyTorque2(bodyu.ptr, torque);
1150}
1151
1152// Apply force at the given point. Will add torque to the object.
1153// Deep down in Bullet: applyCentralForce(force);
1154// applyTorque(rel_pos.cross(force*m_linearFactor));
1155public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
1156{
1157 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1158 BSAPICPP.ApplyForce2(bodyu.ptr, force, pos);
1159}
1160
1161// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1162// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
1163public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
1164{
1165 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1166 BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp);
1167}
1168
1169// Apply impulse to the object's torque. Force is scaled by object's mass.
1170// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
1171public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
1172{
1173 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1174 BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp);
1175}
1176
1177// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1178// Deep down in Bullet: applyCentralImpulse(impulse);
1179// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
1180public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
1181{
1182 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1183 BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos);
1184}
1185
1186public override void ClearForces(BulletBody obj)
1187{
1188 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1189 BSAPICPP.ClearForces2(bodyu.ptr);
1190}
1191
1192public override void ClearAllForces(BulletBody obj)
1193{
1194 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1195 BSAPICPP.ClearAllForces2(bodyu.ptr);
1196}
1197
1198public override void UpdateInertiaTensor(BulletBody obj)
1199{
1200 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1201 BSAPICPP.UpdateInertiaTensor2(bodyu.ptr);
1202}
1203
1204public override Vector3 GetLinearVelocity(BulletBody obj)
1205{
1206 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1207 return BSAPICPP.GetLinearVelocity2(bodyu.ptr);
1208}
1209
1210public override Vector3 GetAngularVelocity(BulletBody obj)
1211{
1212 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1213 return BSAPICPP.GetAngularVelocity2(bodyu.ptr);
1214}
1215
1216public override void SetLinearVelocity(BulletBody obj, Vector3 vel)
1217{
1218 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1219 BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel);
1220}
1221
1222public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity)
1223{
1224 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1225 BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity);
1226}
1227
1228public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos)
1229{
1230 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1231 return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos);
1232}
1233
1234public override void Translate(BulletBody obj, Vector3 trans)
1235{
1236 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1237 BSAPICPP.Translate2(bodyu.ptr, trans);
1238}
1239
1240public override void UpdateDeactivation(BulletBody obj, float timeStep)
1241{
1242 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1243 BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep);
1244}
1245
1246public override bool WantsSleeping(BulletBody obj)
1247{
1248 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1249 return BSAPICPP.WantsSleeping2(bodyu.ptr);
1250}
1251
1252public override void SetAngularFactor(BulletBody obj, float factor)
1253{
1254 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1255 BSAPICPP.SetAngularFactor2(bodyu.ptr, factor);
1256}
1257
1258public override void SetAngularFactorV(BulletBody obj, Vector3 factor)
1259{
1260 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1261 BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor);
1262}
1263
1264public override Vector3 GetAngularFactor(BulletBody obj)
1265{
1266 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1267 return BSAPICPP.GetAngularFactor2(bodyu.ptr);
1268}
1269
1270public override bool IsInWorld(BulletWorld world, BulletBody obj)
1271{
1272 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1273 return BSAPICPP.IsInWorld2(bodyu.ptr);
1274}
1275
1276public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain)
1277{
1278 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1279 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1280 BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr);
1281}
1282
1283public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain)
1284{
1285 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1286 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1287 BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr);
1288}
1289
1290public override BulletConstraint GetConstraintRef(BulletBody obj, int index)
1291{
1292 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1293 return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index));
1294}
1295
1296public override int GetNumConstraintRefs(BulletBody obj)
1297{
1298 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1299 return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr);
1300}
1301
1302public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask)
1303{
1304 BulletBodyUnman bodyu = body as BulletBodyUnman;
1305 return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask);
1306}
1307
1308// =====================================================================================
1309// btCollisionShape entries
1310
1311public override float GetAngularMotionDisc(BulletShape shape)
1312{
1313 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1314 return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr);
1315}
1316
1317public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor)
1318{
1319 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1320 return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor);
1321}
1322
1323public override bool IsPolyhedral(BulletShape shape)
1324{
1325 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1326 return BSAPICPP.IsPolyhedral2(shapeu.ptr);
1327}
1328
1329public override bool IsConvex2d(BulletShape shape)
1330{
1331 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1332 return BSAPICPP.IsConvex2d2(shapeu.ptr);
1333}
1334
1335public override bool IsConvex(BulletShape shape)
1336{
1337 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1338 return BSAPICPP.IsConvex2(shapeu.ptr);
1339}
1340
1341public override bool IsNonMoving(BulletShape shape)
1342{
1343 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1344 return BSAPICPP.IsNonMoving2(shapeu.ptr);
1345}
1346
1347public override bool IsConcave(BulletShape shape)
1348{
1349 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1350 return BSAPICPP.IsConcave2(shapeu.ptr);
1351}
1352
1353public override bool IsCompound(BulletShape shape)
1354{
1355 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1356 return BSAPICPP.IsCompound2(shapeu.ptr);
1357}
1358
1359public override bool IsSoftBody(BulletShape shape)
1360{
1361 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1362 return BSAPICPP.IsSoftBody2(shapeu.ptr);
1363}
1364
1365public override bool IsInfinite(BulletShape shape)
1366{
1367 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1368 return BSAPICPP.IsInfinite2(shapeu.ptr);
1369}
1370
1371public override void SetLocalScaling(BulletShape shape, Vector3 scale)
1372{
1373 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1374 BSAPICPP.SetLocalScaling2(shapeu.ptr, scale);
1375}
1376
1377public override Vector3 GetLocalScaling(BulletShape shape)
1378{
1379 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1380 return BSAPICPP.GetLocalScaling2(shapeu.ptr);
1381}
1382
1383public override Vector3 CalculateLocalInertia(BulletShape shape, float mass)
1384{
1385 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1386 return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass);
1387}
1388
1389public override int GetShapeType(BulletShape shape)
1390{
1391 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1392 return BSAPICPP.GetShapeType2(shapeu.ptr);
1393}
1394
1395public override void SetMargin(BulletShape shape, float val)
1396{
1397 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1398 BSAPICPP.SetMargin2(shapeu.ptr, val);
1399}
1400
1401public override float GetMargin(BulletShape shape)
1402{
1403 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1404 return BSAPICPP.GetMargin2(shapeu.ptr);
1405}
1406
1407// =====================================================================================
1408// Debugging
1409public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
1410{
1411 BulletWorldUnman worldu = world as BulletWorldUnman;
1412 BulletBodyUnman bodyu = collisionObject as BulletBodyUnman;
1413 BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr);
1414}
1415
1416public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape)
1417{
1418 BulletWorldUnman worldu = world as BulletWorldUnman;
1419 BulletShapeUnman shapeu = collisionShape as BulletShapeUnman;
1420 BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr);
1421}
1422
1423public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
1424{
1425 BulletWorldUnman worldu = world as BulletWorldUnman;
1426 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1427 BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr);
1428}
1429
1430public override void DumpActivationInfo(BulletWorld world)
1431{
1432 BulletWorldUnman worldu = world as BulletWorldUnman;
1433 BSAPICPP.DumpActivationInfo2(worldu.ptr);
1434}
1435
1436public override void DumpAllInfo(BulletWorld world)
1437{
1438 BulletWorldUnman worldu = world as BulletWorldUnman;
1439 BSAPICPP.DumpAllInfo2(worldu.ptr);
1440}
1441
1442public override void DumpPhysicsStatistics(BulletWorld world)
1443{
1444 BulletWorldUnman worldu = world as BulletWorldUnman;
1445 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1446}
1447public override void ResetBroadphasePool(BulletWorld world)
1448{
1449 BulletWorldUnman worldu = world as BulletWorldUnman;
1450 BSAPICPP.ResetBroadphasePool(worldu.ptr);
1451}
1452public override void ResetConstraintSolver(BulletWorld world)
1453{
1454 BulletWorldUnman worldu = world as BulletWorldUnman;
1455 BSAPICPP.ResetConstraintSolver(worldu.ptr);
1456}
1457
1458// =====================================================================================
1459// =====================================================================================
1460// =====================================================================================
1461// =====================================================================================
1462// =====================================================================================
1463// The actual interface to the unmanaged code
1464static class BSAPICPP
1465{
1466// ===============================================================================
1467// Link back to the managed code for outputting log messages
1468[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1469public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
1470
1471// ===============================================================================
1472// Initialization and simulation
1473[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1474public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
1475 int maxCollisions, IntPtr collisionArray,
1476 int maxUpdates, IntPtr updateArray,
1477 DebugLogCallback logRoutine);
1478
1479[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1480public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
1481 out int updatedEntityCount, out int collidersCount);
1482
1483[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1484public static extern void Shutdown2(IntPtr sim);
1485
1486[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1487public static extern bool PushUpdate2(IntPtr obj);
1488
1489[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1490public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
1491
1492// =====================================================================================
1493// Mesh, hull, shape and body creation helper routines
1494[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1495public static extern IntPtr CreateMeshShape2(IntPtr world,
1496 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1497 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1498
1499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1500public static extern IntPtr CreateGImpactShape2(IntPtr world,
1501 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1502 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1503
1504[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1505public static extern IntPtr CreateHullShape2(IntPtr world,
1506 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1507
1508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1509public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms);
1510
1511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1512public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1513
1514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1515public static extern IntPtr CreateConvexHullShape2(IntPtr world,
1516 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1517 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1518
1519[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1520public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
1521
1522[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1523public static extern bool IsNativeShape2(IntPtr shape);
1524
1525[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1526public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
1527
1528[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1529public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
1530
1531[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1532public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
1533
1534[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1535public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
1536
1537[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1538public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
1539
1540[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1541public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1542
1543[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1544public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1545
1546[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1547public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1548
1549[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1550public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
1551
1552[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1553public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1554
1555[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1556public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
1557
1558[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1559public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
1560
1561[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1562public static extern int GetBodyType2(IntPtr obj);
1563
1564[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1565public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1566
1567[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1568public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1569
1570[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1571public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1572
1573[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1574public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1575
1576// =====================================================================================
1577// Terrain creation and helper routines
1578[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1579public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1580
1581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1582public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1583 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1584 float scaleFactor, float collisionMargin);
1585
1586// =====================================================================================
1587// Constraint creation and helper routines
1588[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1589public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1590 Vector3 frame1loc, Quaternion frame1rot,
1591 Vector3 frame2loc, Quaternion frame2rot,
1592 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1593
1594[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1595public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1596 Vector3 joinPoint,
1597 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1598
1599[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1600public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1,
1601 Vector3 frameInBloc, Quaternion frameInBrot,
1602 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
1603
1604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1605public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1606 Vector3 frame1loc, Quaternion frame1rot,
1607 Vector3 frame2loc, Quaternion frame2rot,
1608 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1609
1610[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1611public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1612 Vector3 pivotinA, Vector3 pivotinB,
1613 Vector3 axisInA, Vector3 axisInB,
1614 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1615
1616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1617public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1618 Vector3 frameInAloc, Quaternion frameInArot,
1619 Vector3 frameInBloc, Quaternion frameInBrot,
1620 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1621
1622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1623public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1624 Vector3 frameInAloc, Quaternion frameInArot,
1625 Vector3 frameInBloc, Quaternion frameInBrot,
1626 bool disableCollisionsBetweenLinkedBodies);
1627
1628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1629public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1630 Vector3 axisInA, Vector3 axisInB,
1631 float ratio, bool disableCollisionsBetweenLinkedBodies);
1632
1633[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1634public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1635 Vector3 pivotInA, Vector3 pivotInB,
1636 bool disableCollisionsBetweenLinkedBodies);
1637
1638
1639[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1640public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1641
1642[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1643public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
1644
1645[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1646public static extern bool SetFrames2(IntPtr constrain,
1647 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
1648
1649[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1650public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1651
1652[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1653public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1654
1655[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1656public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
1657
1658[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1659public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
1660
1661[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1662public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1663
1664[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1665public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation);
1666
1667[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1668public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse);
1669
1670[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1671public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint);
1672
1673[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1674public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness);
1675
1676[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1677public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping);
1678
1679[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1680public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val);
1681
1682[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1683public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
1684
1685[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1686public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse);
1687
1688[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1689public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val);
1690
1691[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1692public static extern bool CalculateTransforms2(IntPtr constrain);
1693
1694[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1695public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
1696
1697[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1698public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
1699
1700// =====================================================================================
1701// btCollisionWorld entries
1702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1703public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
1704
1705[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1706public static extern void UpdateAabbs2(IntPtr world);
1707
1708[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1709public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
1710
1711[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1712public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
1713
1714// =====================================================================================
1715// btDynamicsWorld entries
1716[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1717public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1718
1719[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1720public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1721
1722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1723public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj);
1724
1725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1726public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1727
1728[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1729public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
1730// =====================================================================================
1731// btCollisionObject entries
1732[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1733public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
1734
1735[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1736public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
1737
1738[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1739public static extern bool HasAnisotripicFriction2(IntPtr constrain);
1740
1741[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1742public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
1743
1744[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1745public static extern float GetContactProcessingThreshold2(IntPtr obj);
1746
1747[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1748public static extern bool IsStaticObject2(IntPtr obj);
1749
1750[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1751public static extern bool IsKinematicObject2(IntPtr obj);
1752
1753[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1754public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
1755
1756[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1757public static extern bool HasContactResponse2(IntPtr obj);
1758
1759[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1760public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
1761
1762[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1763public static extern IntPtr GetCollisionShape2(IntPtr obj);
1764
1765[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1766public static extern int GetActivationState2(IntPtr obj);
1767
1768[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1769public static extern void SetActivationState2(IntPtr obj, int state);
1770
1771[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1772public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
1773
1774[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1775public static extern float GetDeactivationTime2(IntPtr obj);
1776
1777[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1778public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
1779
1780[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1781public static extern void Activate2(IntPtr obj, bool forceActivation);
1782
1783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1784public static extern bool IsActive2(IntPtr obj);
1785
1786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1787public static extern void SetRestitution2(IntPtr obj, float val);
1788
1789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1790public static extern float GetRestitution2(IntPtr obj);
1791
1792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1793public static extern void SetFriction2(IntPtr obj, float val);
1794
1795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1796public static extern float GetFriction2(IntPtr obj);
1797
1798 /* Haven't defined the type 'Transform'
1799[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1800public static extern Transform GetWorldTransform2(IntPtr obj);
1801
1802[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1803public static extern void setWorldTransform2(IntPtr obj, Transform trans);
1804 */
1805
1806[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1807public static extern Vector3 GetPosition2(IntPtr obj);
1808
1809[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1810public static extern Quaternion GetOrientation2(IntPtr obj);
1811
1812[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1813public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
1814
1815[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1816public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
1817
1818[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1819public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
1820
1821 /*
1822[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1823public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
1824
1825[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1826public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
1827 */
1828
1829[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1830public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
1831
1832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1833public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
1834
1835[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1836public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
1837
1838[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1839public static extern float GetHitFraction2(IntPtr obj);
1840
1841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1842public static extern void SetHitFraction2(IntPtr obj, float val);
1843
1844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1845public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
1846
1847[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1848public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
1849
1850[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1851public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
1852
1853[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1854public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
1855
1856[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1857public static extern float GetCcdMotionThreshold2(IntPtr obj);
1858
1859[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1860public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
1861
1862[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1863public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
1864
1865[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1866public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
1867
1868[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1869public static extern IntPtr GetUserPointer2(IntPtr obj);
1870
1871[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1872public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
1873
1874// =====================================================================================
1875// btRigidBody entries
1876[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1877public static extern void ApplyGravity2(IntPtr obj);
1878
1879[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1880public static extern void SetGravity2(IntPtr obj, Vector3 val);
1881
1882[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1883public static extern Vector3 GetGravity2(IntPtr obj);
1884
1885[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1886public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
1887
1888[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1889public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
1890
1891[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1892public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
1893
1894[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1895public static extern float GetLinearDamping2(IntPtr obj);
1896
1897[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1898public static extern float GetAngularDamping2(IntPtr obj);
1899
1900[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1901public static extern float GetLinearSleepingThreshold2(IntPtr obj);
1902
1903[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1904public static extern float GetAngularSleepingThreshold2(IntPtr obj);
1905
1906[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1907public static extern void ApplyDamping2(IntPtr obj, float timeStep);
1908
1909[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1910public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
1911
1912[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1913public static extern Vector3 GetLinearFactor2(IntPtr obj);
1914
1915[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1916public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
1917
1918 /*
1919[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1920public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
1921 */
1922
1923[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1924public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
1925
1926// Add a force to the object as if its mass is one.
1927[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1928public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
1929
1930// Set the force being applied to the object as if its mass is one.
1931[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1932public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
1933
1934[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1935public static extern Vector3 GetTotalForce2(IntPtr obj);
1936
1937[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1938public static extern Vector3 GetTotalTorque2(IntPtr obj);
1939
1940[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1941public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
1942
1943[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1944public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
1945
1946[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1947public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
1948
1949[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1950public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
1951
1952// Apply force at the given point. Will add torque to the object.
1953[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1954public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
1955
1956// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1957[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1958public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
1959
1960// Apply impulse to the object's torque. Force is scaled by object's mass.
1961[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1962public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
1963
1964// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1965[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1966public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
1967
1968[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1969public static extern void ClearForces2(IntPtr obj);
1970
1971[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1972public static extern void ClearAllForces2(IntPtr obj);
1973
1974[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1975public static extern void UpdateInertiaTensor2(IntPtr obj);
1976
1977[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1978public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
1979
1980 /*
1981[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1982public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
1983 */
1984
1985[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1986public static extern Vector3 GetLinearVelocity2(IntPtr obj);
1987
1988[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1989public static extern Vector3 GetAngularVelocity2(IntPtr obj);
1990
1991[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1992public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1993
1994[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1995public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1996
1997[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1998public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1999
2000[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2001public static extern void Translate2(IntPtr obj, Vector3 trans);
2002
2003[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2004public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
2005
2006[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2007public static extern bool WantsSleeping2(IntPtr obj);
2008
2009[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2010public static extern void SetAngularFactor2(IntPtr obj, float factor);
2011
2012[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2013public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
2014
2015[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2016public static extern Vector3 GetAngularFactor2(IntPtr obj);
2017
2018[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2019public static extern bool IsInWorld2(IntPtr obj);
2020
2021[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2022public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
2023
2024[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2025public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
2026
2027[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2028public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
2029
2030[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2031public static extern int GetNumConstraintRefs2(IntPtr obj);
2032
2033[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2034public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
2035
2036// =====================================================================================
2037// btCollisionShape entries
2038
2039[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2040public static extern float GetAngularMotionDisc2(IntPtr shape);
2041
2042[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2043public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
2044
2045[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2046public static extern bool IsPolyhedral2(IntPtr shape);
2047
2048[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2049public static extern bool IsConvex2d2(IntPtr shape);
2050
2051[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2052public static extern bool IsConvex2(IntPtr shape);
2053
2054[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2055public static extern bool IsNonMoving2(IntPtr shape);
2056
2057[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2058public static extern bool IsConcave2(IntPtr shape);
2059
2060[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2061public static extern bool IsCompound2(IntPtr shape);
2062
2063[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2064public static extern bool IsSoftBody2(IntPtr shape);
2065
2066[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2067public static extern bool IsInfinite2(IntPtr shape);
2068
2069[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2070public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
2071
2072[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2073public static extern Vector3 GetLocalScaling2(IntPtr shape);
2074
2075[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2076public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
2077
2078[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2079public static extern int GetShapeType2(IntPtr shape);
2080
2081[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2082public static extern void SetMargin2(IntPtr shape, float val);
2083
2084[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2085public static extern float GetMargin2(IntPtr shape);
2086
2087// =====================================================================================
2088// Debugging
2089[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2090public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
2091
2092[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2093public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
2094
2095[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2096public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
2097
2098[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2099public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
2100
2101[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2102public static extern void DumpActivationInfo2(IntPtr sim);
2103
2104[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2105public static extern void DumpAllInfo2(IntPtr sim);
2106
2107[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2108public static extern void DumpPhysicsStatistics2(IntPtr sim);
2109
2110[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2111public static extern void ResetBroadphasePool(IntPtr sim);
2112
2113[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2114public static extern void ResetConstraintSolver(IntPtr sim);
2115
2116}
2117
2118}
2119
2120}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
new file mode 100755
index 0000000..887311d
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
@@ -0,0 +1,2589 @@
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.Text;
32
33using OpenSim.Framework;
34
35using OpenMetaverse;
36
37using BulletXNA;
38using BulletXNA.LinearMath;
39using BulletXNA.BulletCollision;
40using BulletXNA.BulletDynamics;
41using BulletXNA.BulletCollision.CollisionDispatch;
42
43namespace OpenSim.Region.PhysicsModule.BulletS
44{
45public sealed class BSAPIXNA : BSAPITemplate
46{
47private sealed class BulletWorldXNA : BulletWorld
48{
49 public DiscreteDynamicsWorld world;
50 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
51 : base(id, physScene)
52 {
53 world = xx;
54 }
55}
56
57private sealed class BulletBodyXNA : BulletBody
58{
59 public CollisionObject body;
60 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
61
62 public BulletBodyXNA(uint id, CollisionObject xx)
63 : base(id)
64 {
65 body = xx;
66 }
67 public override bool HasPhysicalBody
68 {
69 get { return body != null; }
70 }
71 public override void Clear()
72 {
73 body = null;
74 }
75 public override string AddrString
76 {
77 get { return "XNARigidBody"; }
78 }
79}
80
81private sealed class BulletShapeXNA : BulletShape
82{
83 public CollisionShape shape;
84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
85 : base()
86 {
87 shape = xx;
88 shapeType = typ;
89 }
90 public override bool HasPhysicalShape
91 {
92 get { return shape != null; }
93 }
94 public override void Clear()
95 {
96 shape = null;
97 }
98 public override BulletShape Clone()
99 {
100 return new BulletShapeXNA(shape, shapeType);
101 }
102 public override bool ReferenceSame(BulletShape other)
103 {
104 BulletShapeXNA otheru = other as BulletShapeXNA;
105 return (otheru != null) && (this.shape == otheru.shape);
106
107 }
108 public override string AddrString
109 {
110 get { return "XNACollisionShape"; }
111 }
112}
113private sealed class BulletConstraintXNA : BulletConstraint
114{
115 public TypedConstraint constrain;
116 public BulletConstraintXNA(TypedConstraint xx) : base()
117 {
118 constrain = xx;
119 }
120
121 public override void Clear()
122 {
123 constrain = null;
124 }
125 public override bool HasPhysicalConstraint { get { return constrain != null; } }
126
127 // Used for log messages for a unique display of the memory/object allocated to this instance
128 public override string AddrString
129 {
130 get { return "XNAConstraint"; }
131 }
132}
133 internal int m_maxCollisions;
134 internal CollisionDesc[] UpdatedCollisions;
135 internal int LastCollisionDesc = 0;
136 internal int m_maxUpdatesPerFrame;
137 internal int LastEntityProperty = 0;
138
139 internal EntityProperties[] UpdatedObjects;
140 internal Dictionary<uint, GhostObject> specialCollisionObjects;
141
142 private static int m_collisionsThisFrame;
143 private BSScene PhysicsScene { get; set; }
144
145 public override string BulletEngineName { get { return "BulletXNA"; } }
146 public override string BulletEngineVersion { get; protected set; }
147
148 public BSAPIXNA(string paramName, BSScene physScene)
149 {
150 PhysicsScene = physScene;
151 }
152
153 /// <summary>
154 ///
155 /// </summary>
156 /// <param name="p"></param>
157 /// <param name="p_2"></param>
158 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
159 {
160 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
161 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
162 CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
163 if (body != null)
164 world.RemoveRigidBody(body);
165 else if (collisionObject != null)
166 world.RemoveCollisionObject(collisionObject);
167 else
168 return false;
169 return true;
170 }
171
172 public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody)
173 {
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
176 CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
177 if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null)
178 {
179 world.RemoveCollisionObject(collisionObject);
180 world.AddCollisionObject(collisionObject);
181 }
182 return true;
183 }
184
185 public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
186 {
187 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
188 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
189 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
190
191 return true;
192
193 }
194
195 public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint)
196 {
197 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
198 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
199 world.RemoveConstraint(constraint);
200 return true;
201 }
202
203 public override void SetRestitution(BulletBody pCollisionObject, float pRestitution)
204 {
205 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
206 collisionObject.SetRestitution(pRestitution);
207 }
208
209 public override int GetShapeType(BulletShape pShape)
210 {
211 CollisionShape shape = (pShape as BulletShapeXNA).shape;
212 return (int)shape.GetShapeType();
213 }
214 public override void SetMargin(BulletShape pShape, float pMargin)
215 {
216 CollisionShape shape = (pShape as BulletShapeXNA).shape;
217 shape.SetMargin(pMargin);
218 }
219
220 public override float GetMargin(BulletShape pShape)
221 {
222 CollisionShape shape = (pShape as BulletShapeXNA).shape;
223 return shape.GetMargin();
224 }
225
226 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
227 {
228 CollisionShape shape = (pShape as BulletShapeXNA).shape;
229 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
230 shape.SetLocalScaling(ref vec);
231
232 }
233
234 public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold)
235 {
236 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
237 collisionObject.SetContactProcessingThreshold(contactprocessingthreshold);
238 }
239
240 public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold)
241 {
242 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
243 collisionObject.SetCcdMotionThreshold(pccdMotionThreashold);
244 }
245
246 public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius)
247 {
248 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
249 collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
250 }
251
252 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
253 {
254 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
255 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
256 }
257
258 public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
259 {
260 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
261 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
262 existingcollisionFlags |= pcollisionFlags;
263 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
264 return (CollisionFlags) (uint) existingcollisionFlags;
265 }
266
267 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
268 {
269 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
270 CollisionObject cbody = (pBody as BulletBodyXNA).body;
271 RigidBody rbody = cbody as RigidBody;
272
273 // Bullet resets several variables when an object is added to the world. In particular,
274 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
275 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
276 IndexedMatrix origPos = cbody.GetWorldTransform();
277 if (rbody != null)
278 {
279 IndexedVector3 origGrav = rbody.GetGravity();
280 world.AddRigidBody(rbody);
281 rbody.SetGravity(origGrav);
282 }
283 else
284 {
285 world.AddCollisionObject(cbody);
286 }
287 cbody.SetWorldTransform(origPos);
288
289 pBody.ApplyCollisionMask(pWorld.physicsScene);
290
291 //if (body.GetBroadphaseHandle() != null)
292 // world.UpdateSingleAabb(body);
293 return true;
294 }
295
296 public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState)
297 {
298 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
299 collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
300 }
301
302 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject)
303 {
304 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
305 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
306 world.UpdateSingleAabb(collisionObject);
307 }
308
309 public override void UpdateAabbs(BulletWorld pWorld) {
310 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
311 world.UpdateAabbs();
312 }
313 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
314 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
315 return world.GetForceUpdateAllAabbs();
316
317 }
318 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
319 {
320 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
321 world.SetForceUpdateAllAabbs(pForce);
322 }
323
324 public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask)
325 {
326 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
327 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
328 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
329 if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0)
330 return false;
331 return true;
332 }
333
334 public override void ClearAllForces(BulletBody pCollisionObject)
335 {
336 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
337 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
338 collisionObject.SetInterpolationLinearVelocity(ref zeroVector);
339 collisionObject.SetInterpolationAngularVelocity(ref zeroVector);
340 IndexedMatrix bodytransform = collisionObject.GetWorldTransform();
341
342 collisionObject.SetInterpolationWorldTransform(ref bodytransform);
343
344 if (collisionObject is RigidBody)
345 {
346 RigidBody rigidbody = collisionObject as RigidBody;
347 rigidbody.SetLinearVelocity(zeroVector);
348 rigidbody.SetAngularVelocity(zeroVector);
349 rigidbody.ClearForces();
350 }
351 }
352
353 public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3)
354 {
355 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
356 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
357 collisionObject.SetInterpolationAngularVelocity(ref vec);
358 }
359
360 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
361 {
362 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
363 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
364 body.SetAngularVelocity(ref vec);
365 }
366 public override Vector3 GetTotalForce(BulletBody pBody)
367 {
368 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
369 IndexedVector3 iv3 = body.GetTotalForce();
370 return new Vector3(iv3.X, iv3.Y, iv3.Z);
371 }
372 public override Vector3 GetTotalTorque(BulletBody pBody)
373 {
374 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
375 IndexedVector3 iv3 = body.GetTotalTorque();
376 return new Vector3(iv3.X, iv3.Y, iv3.Z);
377 }
378 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
379 {
380 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
381 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
382 return new Vector3(iv3.X, iv3.Y, iv3.Z);
383 }
384 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
385 {
386 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
387 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
388 body.SetInvInertiaDiagLocal(ref iv3);
389 }
390 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
391 {
392 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
393 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
394 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
395 body.ApplyForce(ref forceiv3, ref posiv3);
396 }
397 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
398 {
399 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
400 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
401 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
402 body.ApplyImpulse(ref impiv3, ref posiv3);
403 }
404
405 public override void ClearForces(BulletBody pBody)
406 {
407 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
408 body.ClearForces();
409 }
410
411 public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation)
412 {
413 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
414 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
415 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
416 _orientation.W);
417 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
418 mat._origin = vposition;
419 collisionObject.SetWorldTransform(mat);
420
421 }
422
423 public override Vector3 GetPosition(BulletBody pCollisionObject)
424 {
425 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
426 IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin;
427 return new Vector3(pos.X, pos.Y, pos.Z);
428 }
429
430 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
431 {
432 CollisionShape shape = (pShape as BulletShapeXNA).shape;
433 IndexedVector3 inertia = IndexedVector3.Zero;
434 shape.CalculateLocalInertia(pphysMass, out inertia);
435 return new Vector3(inertia.X, inertia.Y, inertia.Z);
436 }
437
438 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
439 {
440 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
441 if (body != null) // Can't set mass props on collision object.
442 {
443 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
444 body.SetMassProps(pphysMass, inertia);
445 }
446 }
447
448
449 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
450 {
451 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
452 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
453 body.SetTotalForce(ref force);
454 }
455
456 public override void SetFriction(BulletBody pCollisionObject, float _currentFriction)
457 {
458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
459 collisionObject.SetFriction(_currentFriction);
460 }
461
462 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
463 {
464 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
465 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
466 body.SetLinearVelocity(velocity);
467 }
468
469 public override void Activate(BulletBody pCollisionObject, bool pforceactivation)
470 {
471 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
472 collisionObject.Activate(pforceactivation);
473
474 }
475
476 public override Quaternion GetOrientation(BulletBody pCollisionObject)
477 {
478 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
479 IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation();
480 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
481 }
482
483 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
484 {
485 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
486 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
487 existingcollisionFlags &= ~pcollisionFlags;
488 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
489 return (CollisionFlags)(uint)existingcollisionFlags;
490 }
491
492 public override float GetCcdMotionThreshold(BulletBody pCollisionObject)
493 {
494 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
495 return collisionObject.GetCcdSquareMotionThreshold();
496 }
497
498 public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject)
499 {
500 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
501 return collisionObject.GetCcdSweptSphereRadius();
502
503 }
504
505 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
506 {
507 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
508 return (IntPtr)shape.GetUserPointer();
509 }
510
511 public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val)
512 {
513 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
514 shape.SetUserPointer(val);
515 }
516
517 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
518 {
519 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
520 if (body != null) // Can't set collisionobject.set gravity
521 {
522 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
523 body.SetGravity(gravity);
524 }
525 }
526
527 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
528 {
529 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
530 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
531 world.RemoveConstraint(constraint);
532 return true;
533 }
534
535 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
536 {
537 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
538 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
539 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
540 constraint.SetLinearLowerLimit(lowlimit);
541 constraint.SetLinearUpperLimit(highlimit);
542 return true;
543 }
544
545 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
546 {
547 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
548 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
549 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
550 constraint.SetAngularLowerLimit(lowlimit);
551 constraint.SetAngularUpperLimit(highlimit);
552 return true;
553 }
554
555 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
556 {
557 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
558 constraint.SetOverrideNumSolverIterations((int)cnt);
559 }
560
561 public override bool CalculateTransforms(BulletConstraint pConstraint)
562 {
563 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
564 constraint.CalculateTransforms();
565 return true;
566 }
567
568 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
569 {
570 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
571 constraint.SetEnabled((p_2 == 0) ? false : true);
572 }
573
574
575 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
576 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
577 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
578
579 {
580 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
581 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
582 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
583 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
584 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
585 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
586 frame1._origin = frame1v;
587
588 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
589 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
590 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
591 frame2._origin = frame1v;
592
593 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
594 puseLinearReferenceFrameA);
595 consttr.CalculateTransforms();
596 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
597
598 return new BulletConstraintXNA(consttr);
599 }
600
601 public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1,
602 Vector3 pframe1, Quaternion pframe1rot,
603 bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies)
604 {
605 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
606 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
607 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
608 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
609 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
610 frame1._origin = frame1v;
611
612 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB);
613 consttr.CalculateTransforms();
614 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
615
616 return new BulletConstraintXNA(consttr);
617 }
618
619 /// <summary>
620 ///
621 /// </summary>
622 /// <param name="pWorld"></param>
623 /// <param name="pBody1"></param>
624 /// <param name="pBody2"></param>
625 /// <param name="pjoinPoint"></param>
626 /// <param name="puseLinearReferenceFrameA"></param>
627 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
628 /// <returns></returns>
629 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
630 {
631 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
632 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
633 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
634 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
635 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
636
637 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
638 IndexedMatrix mat = IndexedMatrix.Identity;
639 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
640 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
641 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
642
643 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
644 consttr.CalculateTransforms();
645 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
646
647 return new BulletConstraintXNA(consttr);
648 }
649 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
650 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
651 {
652 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
653 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
654 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
655 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
656 frame1._origin = frame1v;
657
658 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
659 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
660 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
661 frame2._origin = frame2v;
662 constraint.SetFrames(ref frame1, ref frame2);
663 return true;
664 }
665
666 public override Vector3 GetLinearVelocity(BulletBody pBody)
667 {
668 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
669 IndexedVector3 iv3 = body.GetLinearVelocity();
670 return new Vector3(iv3.X, iv3.Y, iv3.Z);
671 }
672 public override Vector3 GetAngularVelocity(BulletBody pBody)
673 {
674 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
675 IndexedVector3 iv3 = body.GetAngularVelocity();
676 return new Vector3(iv3.X, iv3.Y, iv3.Z);
677 }
678 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
679 {
680 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
681 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
682 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
683 return new Vector3(iv3.X, iv3.Y, iv3.Z);
684 }
685 public override void Translate(BulletBody pCollisionObject, Vector3 trans)
686 {
687 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
688 collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z));
689 }
690 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
691 {
692 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
693 body.UpdateDeactivation(timeStep);
694 }
695
696 public override bool WantsSleeping(BulletBody pBody)
697 {
698 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
699 return body.WantsSleeping();
700 }
701
702 public override void SetAngularFactor(BulletBody pBody, float factor)
703 {
704 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
705 body.SetAngularFactor(factor);
706 }
707
708 public override Vector3 GetAngularFactor(BulletBody pBody)
709 {
710 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
711 IndexedVector3 iv3 = body.GetAngularFactor();
712 return new Vector3(iv3.X, iv3.Y, iv3.Z);
713 }
714
715 public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject)
716 {
717 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
718 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
719 return world.IsInWorld(collisionObject);
720 }
721
722 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
723 {
724 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
725 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
726 body.AddConstraintRef(constrain);
727 }
728
729 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
730 {
731 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
732 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
733 body.RemoveConstraintRef(constrain);
734 }
735
736 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
737 {
738 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
739 return new BulletConstraintXNA(body.GetConstraintRef(index));
740 }
741
742 public override int GetNumConstraintRefs(BulletBody pBody)
743 {
744 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
745 return body.GetNumConstraintRefs();
746 }
747
748 public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity)
749 {
750 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
751 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
752 collisionObject.SetInterpolationLinearVelocity(ref velocity);
753 }
754
755 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
756 {
757 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
758 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
759 return true;
760 }
761 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
762 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
763 {
764 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
765 constraint.SetBreakingImpulseThreshold(threshold);
766 return true;
767 }
768 public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation)
769 {
770 HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint;
771 if (softness == HINGE_NOT_SPECIFIED)
772 constraint.SetLimit(low, high);
773 else
774 constraint.SetLimit(low, high, softness, bias, relaxation);
775 return true;
776 }
777 public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse)
778 {
779 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
780 constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true));
781 return true;
782 }
783
784 public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint)
785 {
786 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
787 if (index == SPRING_NOT_SPECIFIED)
788 {
789 constraint.SetEquilibriumPoint();
790 }
791 else
792 {
793 if (equilibriumPoint == SPRING_NOT_SPECIFIED)
794 constraint.SetEquilibriumPoint(index);
795 else
796 constraint.SetEquilibriumPoint(index, equilibriumPoint);
797 }
798 return true;
799 }
800
801 public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness)
802 {
803 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
804 constraint.SetStiffness(index, stiffness);
805 return true;
806 }
807
808 public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping)
809 {
810 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
811 constraint.SetDamping(index, damping);
812 return true;
813 }
814
815 public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val)
816 {
817 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
818 switch (lowerUpper)
819 {
820 case SLIDER_LOWER_LIMIT:
821 switch (linAng)
822 {
823 case SLIDER_LINEAR:
824 constraint.SetLowerLinLimit(val);
825 break;
826 case SLIDER_ANGULAR:
827 constraint.SetLowerAngLimit(val);
828 break;
829 }
830 break;
831 case SLIDER_UPPER_LIMIT:
832 switch (linAng)
833 {
834 case SLIDER_LINEAR:
835 constraint.SetUpperLinLimit(val);
836 break;
837 case SLIDER_ANGULAR:
838 constraint.SetUpperAngLimit(val);
839 break;
840 }
841 break;
842 }
843 return true;
844 }
845 public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val)
846 {
847 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
848 switch (softRestDamp)
849 {
850 case SLIDER_SET_SOFTNESS:
851 switch (dirLimOrtho)
852 {
853 case SLIDER_SET_DIRECTION:
854 switch (linAng)
855 {
856 case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break;
857 case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break;
858 }
859 break;
860 case SLIDER_SET_LIMIT:
861 switch (linAng)
862 {
863 case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break;
864 case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break;
865 }
866 break;
867 case SLIDER_SET_ORTHO:
868 switch (linAng)
869 {
870 case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break;
871 case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break;
872 }
873 break;
874 }
875 break;
876 case SLIDER_SET_RESTITUTION:
877 switch (dirLimOrtho)
878 {
879 case SLIDER_SET_DIRECTION:
880 switch (linAng)
881 {
882 case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break;
883 case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break;
884 }
885 break;
886 case SLIDER_SET_LIMIT:
887 switch (linAng)
888 {
889 case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break;
890 case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break;
891 }
892 break;
893 case SLIDER_SET_ORTHO:
894 switch (linAng)
895 {
896 case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break;
897 case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break;
898 }
899 break;
900 }
901 break;
902 case SLIDER_SET_DAMPING:
903 switch (dirLimOrtho)
904 {
905 case SLIDER_SET_DIRECTION:
906 switch (linAng)
907 {
908 case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break;
909 case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break;
910 }
911 break;
912 case SLIDER_SET_LIMIT:
913 switch (linAng)
914 {
915 case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break;
916 case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break;
917 }
918 break;
919 case SLIDER_SET_ORTHO:
920 switch (linAng)
921 {
922 case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break;
923 case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break;
924 }
925 break;
926 }
927 break;
928 }
929 return true;
930 }
931 public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse)
932 {
933 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
934 switch (linAng)
935 {
936 case SLIDER_LINEAR:
937 constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true);
938 break;
939 case SLIDER_ANGULAR:
940 constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true);
941 break;
942 }
943 return true;
944 }
945 public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val)
946 {
947 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
948 switch (forceVel)
949 {
950 case SLIDER_MOTOR_VELOCITY:
951 switch (linAng)
952 {
953 case SLIDER_LINEAR:
954 constraint.SetTargetLinMotorVelocity(val);
955 break;
956 case SLIDER_ANGULAR:
957 constraint.SetTargetAngMotorVelocity(val);
958 break;
959 }
960 break;
961 case SLIDER_MAX_MOTOR_FORCE:
962 switch (linAng)
963 {
964 case SLIDER_LINEAR:
965 constraint.SetMaxLinMotorForce(val);
966 break;
967 case SLIDER_ANGULAR:
968 constraint.SetMaxAngMotorForce(val);
969 break;
970 }
971 break;
972 }
973 return true;
974 }
975
976 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
977 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
978 {
979 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
980 float lineardamping = body.GetLinearDamping();
981 body.SetDamping(lineardamping, angularDamping);
982
983 }
984
985 public override void UpdateInertiaTensor(BulletBody pBody)
986 {
987 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
988 if (body != null) // can't update inertia tensor on CollisionObject
989 body.UpdateInertiaTensor();
990 }
991
992 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
993 {
994 CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
995 shape.RecalculateLocalAabb();
996 }
997
998 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
999 public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject)
1000 {
1001 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1002 uint flags = (uint)collisionObject.GetCollisionFlags();
1003 return (CollisionFlags) flags;
1004 }
1005
1006 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
1007 {
1008 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1009 body.SetDamping(pLinear, pAngular);
1010 }
1011 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
1012 public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime)
1013 {
1014 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1015 collisionObject.SetDeactivationTime(pDeactivationTime);
1016 }
1017 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
1018 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
1019 {
1020 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1021 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
1022 }
1023
1024 public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject)
1025 {
1026 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1027 return (CollisionObjectTypes)(int) collisionObject.GetInternalType();
1028 }
1029
1030 public override void ApplyGravity(BulletBody pBody)
1031 {
1032
1033 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1034 body.ApplyGravity();
1035 }
1036
1037 public override Vector3 GetGravity(BulletBody pBody)
1038 {
1039 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1040 IndexedVector3 gravity = body.GetGravity();
1041 return new Vector3(gravity.X, gravity.Y, gravity.Z);
1042 }
1043
1044 public override void SetLinearDamping(BulletBody pBody, float lin_damping)
1045 {
1046 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1047 float angularDamping = body.GetAngularDamping();
1048 body.SetDamping(lin_damping, angularDamping);
1049 }
1050
1051 public override float GetLinearDamping(BulletBody pBody)
1052 {
1053 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1054 return body.GetLinearDamping();
1055 }
1056
1057 public override float GetAngularDamping(BulletBody pBody)
1058 {
1059 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1060 return body.GetAngularDamping();
1061 }
1062
1063 public override float GetLinearSleepingThreshold(BulletBody pBody)
1064 {
1065 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1066 return body.GetLinearSleepingThreshold();
1067 }
1068
1069 public override void ApplyDamping(BulletBody pBody, float timeStep)
1070 {
1071 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1072 body.ApplyDamping(timeStep);
1073 }
1074
1075 public override Vector3 GetLinearFactor(BulletBody pBody)
1076 {
1077 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1078 IndexedVector3 linearFactor = body.GetLinearFactor();
1079 return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z);
1080 }
1081
1082 public override void SetLinearFactor(BulletBody pBody, Vector3 factor)
1083 {
1084 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1085 body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z));
1086 }
1087
1088 public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot)
1089 {
1090 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1091 IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W);
1092 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat);
1093 mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z);
1094 body.SetCenterOfMassTransform( ref mat);
1095 /* TODO: double check this */
1096 }
1097
1098 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
1099 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
1100 {
1101 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1102 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1103 body.ApplyCentralForce(ref fSum);
1104 }
1105 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
1106 {
1107 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1108 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1109 body.ApplyCentralImpulse(ref fSum);
1110 }
1111 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
1112 {
1113 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1114 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1115 body.ApplyTorque(ref fSum);
1116 }
1117 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
1118 {
1119 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1120 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1121 body.ApplyTorqueImpulse(ref fSum);
1122 }
1123
1124 public override void DestroyObject(BulletWorld pWorld, BulletBody pBody)
1125 {
1126 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1127 CollisionObject co = (pBody as BulletBodyXNA).rigidBody;
1128 RigidBody bo = co as RigidBody;
1129 if (bo == null)
1130 {
1131
1132 if (world.IsInWorld(co))
1133 {
1134 world.RemoveCollisionObject(co);
1135 }
1136 }
1137 else
1138 {
1139
1140 if (world.IsInWorld(bo))
1141 {
1142 world.RemoveRigidBody(bo);
1143 }
1144 }
1145 if (co != null)
1146 {
1147 if (co.GetUserPointer() != null)
1148 {
1149 uint localId = (uint) co.GetUserPointer();
1150 if (specialCollisionObjects.ContainsKey(localId))
1151 {
1152 specialCollisionObjects.Remove(localId);
1153 }
1154 }
1155 }
1156
1157 }
1158
1159 public override void Shutdown(BulletWorld pWorld)
1160 {
1161 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1162 world.Cleanup();
1163 }
1164
1165 public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id)
1166 {
1167 CollisionShape shape1 = (pShape as BulletShapeXNA).shape;
1168
1169 // TODO: Turn this from a reference copy to a Value Copy.
1170 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType()));
1171
1172 return shape2;
1173 }
1174
1175 public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape)
1176 {
1177 //TODO:
1178 return false;
1179 }
1180 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1181
1182 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1183 {
1184 CollisionWorld world = (pWorld as BulletWorldXNA).world;
1185 IndexedMatrix mat =
1186 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
1187 pRawOrientation.Z, pRawOrientation.W));
1188 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1189 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1190 //UpdateSingleAabb(world, shape);
1191 // TODO: Feed Update array into null
1192 SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null);
1193 RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero);
1194 RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero)
1195 {
1196 m_mass = 0
1197 };
1198 /*
1199 m_mass = mass;
1200 m_motionState =motionState;
1201 m_collisionShape = collisionShape;
1202 m_localInertia = localInertia;
1203 m_linearDamping = 0f;
1204 m_angularDamping = 0f;
1205 m_friction = 0.5f;
1206 m_restitution = 0f;
1207 m_linearSleepingThreshold = 0.8f;
1208 m_angularSleepingThreshold = 1f;
1209 m_additionalDamping = false;
1210 m_additionalDampingFactor = 0.005f;
1211 m_additionalLinearDampingThresholdSqr = 0.01f;
1212 m_additionalAngularDampingThresholdSqr = 0.01f;
1213 m_additionalAngularDampingFactor = 0.01f;
1214 m_startWorldTransform = IndexedMatrix.Identity;
1215 */
1216 body.SetUserPointer(pLocalID);
1217
1218 return new BulletBodyXNA(pLocalID, body);
1219 }
1220
1221
1222 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1223 {
1224
1225 IndexedMatrix mat =
1226 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
1227 pRawOrientation.Z, pRawOrientation.W));
1228 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1229
1230 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1231
1232 // TODO: Feed Update array into null
1233 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
1234 body.SetWorldTransform(mat);
1235 body.SetUserPointer(pLocalID);
1236 return new BulletBodyXNA(pLocalID, body);
1237 }
1238 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
1239 public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags)
1240 {
1241 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1242 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
1243 return (CollisionFlags)collisionObject.GetCollisionFlags();
1244 }
1245
1246 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
1247 {
1248
1249 /* TODO */
1250 return Vector3.Zero;
1251 }
1252 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
1253 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
1254 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
1255 public override bool IsStaticObject(BulletBody pCollisionObject)
1256 {
1257 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1258 return collisionObject.IsStaticObject();
1259
1260 }
1261 public override bool IsKinematicObject(BulletBody pCollisionObject)
1262 {
1263 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1264 return collisionObject.IsKinematicObject();
1265 }
1266 public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject)
1267 {
1268 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1269 return collisionObject.IsStaticOrKinematicObject();
1270 }
1271 public override bool HasContactResponse(BulletBody pCollisionObject)
1272 {
1273 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1274 return collisionObject.HasContactResponse();
1275 }
1276 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
1277 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
1278 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
1279 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
1280 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
1281 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
1282 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
1283 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
1284
1285 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
1286 public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction)
1287 {
1288 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1289 collisionObject.SetHitFraction(pHitFraction);
1290 }
1291 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
1292 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
1293 {
1294 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1295 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
1296 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
1297 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
1298 capsuleShapeZ.SetLocalScaling(ref scale);
1299
1300 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
1301 }
1302
1303 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
1304 int maxCollisions, ref CollisionDesc[] collisionArray,
1305 int maxUpdates, ref EntityProperties[] updateArray
1306 )
1307 {
1308
1309 UpdatedObjects = updateArray;
1310 UpdatedCollisions = collisionArray;
1311 /* TODO */
1312 ConfigurationParameters[] configparms = new ConfigurationParameters[1];
1313 configparms[0] = parms;
1314 Vector3 worldExtent = maxPosition;
1315 m_maxCollisions = maxCollisions;
1316 m_maxUpdatesPerFrame = maxUpdates;
1317 specialCollisionObjects = new Dictionary<uint, GhostObject>();
1318
1319 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
1320 }
1321
1322 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
1323 ConfigurationParameters[] o,
1324 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
1325 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
1326 object mDebugLogCallbackHandle)
1327 {
1328 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
1329
1330 p.angularDamping = BSParam.AngularDamping;
1331 p.defaultFriction = o[0].defaultFriction;
1332 p.defaultFriction = o[0].defaultFriction;
1333 p.defaultDensity = o[0].defaultDensity;
1334 p.defaultRestitution = o[0].defaultRestitution;
1335 p.collisionMargin = o[0].collisionMargin;
1336 p.gravity = o[0].gravity;
1337
1338 p.linearDamping = BSParam.LinearDamping;
1339 p.angularDamping = BSParam.AngularDamping;
1340 p.deactivationTime = BSParam.DeactivationTime;
1341 p.linearSleepingThreshold = BSParam.LinearSleepingThreshold;
1342 p.angularSleepingThreshold = BSParam.AngularSleepingThreshold;
1343 p.ccdMotionThreshold = BSParam.CcdMotionThreshold;
1344 p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius;
1345 p.contactProcessingThreshold = BSParam.ContactProcessingThreshold;
1346
1347 p.terrainImplementation = BSParam.TerrainImplementation;
1348 p.terrainFriction = BSParam.TerrainFriction;
1349
1350 p.terrainHitFraction = BSParam.TerrainHitFraction;
1351 p.terrainRestitution = BSParam.TerrainRestitution;
1352 p.terrainCollisionMargin = BSParam.TerrainCollisionMargin;
1353
1354 p.avatarFriction = BSParam.AvatarFriction;
1355 p.avatarStandingFriction = BSParam.AvatarStandingFriction;
1356 p.avatarDensity = BSParam.AvatarDensity;
1357 p.avatarRestitution = BSParam.AvatarRestitution;
1358 p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth;
1359 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth;
1360 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight;
1361 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold;
1362
1363 p.vehicleAngularDamping = BSParam.VehicleAngularDamping;
1364
1365 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
1366 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
1367 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
1368 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
1369 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
1370 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
1371 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
1372 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
1373
1374 p.linksetImplementation = BSParam.LinksetImplementation;
1375 p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset);
1376 p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor);
1377 p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
1378 p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
1379 p.linkConstraintERP = BSParam.LinkConstraintERP;
1380 p.linkConstraintCFM = BSParam.LinkConstraintCFM;
1381 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations;
1382 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
1383 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
1384
1385 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
1386 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
1387
1388
1389 if (p.maxPersistantManifoldPoolSize > 0)
1390 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
1391 if (p.shouldDisableContactPoolDynamicAllocation !=0)
1392 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
1393 //if (p.maxCollisionAlgorithmPoolSize >0 )
1394
1395 DbvtBroadphase m_broadphase = new DbvtBroadphase();
1396 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
1397 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
1398
1399 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
1400 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
1401
1402 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
1403
1404 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
1405
1406 world.LastCollisionDesc = 0;
1407 world.LastEntityProperty = 0;
1408
1409 world.WorldSettings.Params = p;
1410 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
1411 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
1412 if (p.shouldRandomizeSolverOrder != 0)
1413 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
1414
1415 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
1416 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
1417
1418 if (p.shouldEnableFrictionCaching != 0)
1419 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1420
1421 if (p.numberOfSolverIterations > 0)
1422 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
1423
1424
1425 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
1426 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
1427 world.GetSolverInfo().m_globalCfm = 0.0f;
1428 world.GetSolverInfo().m_tau = 0.6f;
1429 world.GetSolverInfo().m_friction = 0.3f;
1430 world.GetSolverInfo().m_maxErrorReduction = 20f;
1431 world.GetSolverInfo().m_numIterations = 10;
1432 world.GetSolverInfo().m_erp = 0.2f;
1433 world.GetSolverInfo().m_erp2 = 0.1f;
1434 world.GetSolverInfo().m_sor = 1.0f;
1435 world.GetSolverInfo().m_splitImpulse = false;
1436 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1437 world.GetSolverInfo().m_linearSlop = 0.0f;
1438 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1439 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1440 world.SetForceUpdateAllAabbs(true);
1441
1442 //BSParam.TerrainImplementation = 0;
1443 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1444
1445 // Turn off Pooling since globals and pooling are bad for threading.
1446 BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false);
1447 BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false);
1448 BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false);
1449 BulletGlobals.CastResultPool.SetPoolingEnabled(false);
1450 BulletGlobals.SphereShapePool.SetPoolingEnabled(false);
1451 BulletGlobals.DbvtNodePool.SetPoolingEnabled(false);
1452 BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false);
1453 BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false);
1454 BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false);
1455 BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false);
1456 BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false);
1457 BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false);
1458 BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false);
1459 BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false);
1460 BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false);
1461 BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false);
1462
1463 BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
1464 BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false);
1465 BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false);
1466 BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false);
1467 BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false);
1468 BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
1469 BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false);
1470 BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false);
1471 BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false);
1472 BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false);
1473 BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false);
1474 BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false);
1475 BulletGlobals.GJKPool.SetPoolingEnabled(false);
1476 BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false);
1477 BulletGlobals.TriangleShapePool.SetPoolingEnabled(false);
1478 BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false);
1479 BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false);
1480 BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false);
1481 BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false);
1482 BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false);
1483 BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false);
1484 BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false);
1485 BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false);
1486 BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false);
1487 BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false);
1488
1489 return world;
1490 }
1491 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1492 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1493 {
1494 Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
1495 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1496 {
1497 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1498 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1499 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1500 }
1501 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1502 {
1503 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1504 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1505 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1506 }
1507 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1508 {
1509 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1510 }
1511 return true;
1512 }
1513
1514 public override bool PushUpdate(BulletBody pCollisionObject)
1515 {
1516 bool ret = false;
1517 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1518 RigidBody rb = collisionObject as RigidBody;
1519 if (rb != null)
1520 {
1521 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1522 if (sms != null)
1523 {
1524 IndexedMatrix wt = IndexedMatrix.Identity;
1525 sms.GetWorldTransform(out wt);
1526 sms.SetWorldTransform(ref wt, true);
1527 ret = true;
1528 }
1529 }
1530 return ret;
1531
1532 }
1533
1534 public override float GetAngularMotionDisc(BulletShape pShape)
1535 {
1536 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1537 return shape.GetAngularMotionDisc();
1538 }
1539 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1540 {
1541 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1542 return shape.GetContactBreakingThreshold(defaultFactor);
1543 }
1544 public override bool IsCompound(BulletShape pShape)
1545 {
1546 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1547 return shape.IsCompound();
1548 }
1549 public override bool IsSoftBody(BulletShape pShape)
1550 {
1551 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1552 return shape.IsSoftBody();
1553 }
1554 public override bool IsPolyhedral(BulletShape pShape)
1555 {
1556 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1557 return shape.IsPolyhedral();
1558 }
1559 public override bool IsConvex2d(BulletShape pShape)
1560 {
1561 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1562 return shape.IsConvex2d();
1563 }
1564 public override bool IsConvex(BulletShape pShape)
1565 {
1566 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1567 return shape.IsConvex();
1568 }
1569 public override bool IsNonMoving(BulletShape pShape)
1570 {
1571 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1572 return shape.IsNonMoving();
1573 }
1574 public override bool IsConcave(BulletShape pShape)
1575 {
1576 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1577 return shape.IsConcave();
1578 }
1579 public override bool IsInfinite(BulletShape pShape)
1580 {
1581 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1582 return shape.IsInfinite();
1583 }
1584 public override bool IsNativeShape(BulletShape pShape)
1585 {
1586 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1587 bool ret;
1588 switch (shape.GetShapeType())
1589 {
1590 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1591 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1592 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1593 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1594 ret = true;
1595 break;
1596 default:
1597 ret = false;
1598 break;
1599 }
1600 return ret;
1601 }
1602
1603 public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin)
1604 {
1605 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1606 shape.SetMargin(pMargin);
1607 }
1608
1609 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1610 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1611 {
1612 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1613 IndexedMatrix bodyTransform = new IndexedMatrix();
1614 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1615 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1616 GhostObject gObj = new PairCachingGhostObject();
1617 gObj.SetWorldTransform(bodyTransform);
1618 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1619 gObj.SetCollisionShape(shape);
1620 gObj.SetUserPointer(pLocalID);
1621
1622 if (specialCollisionObjects.ContainsKey(pLocalID))
1623 specialCollisionObjects[pLocalID] = gObj;
1624 else
1625 specialCollisionObjects.Add(pLocalID, gObj);
1626
1627 // TODO: Add to Special CollisionObjects!
1628 return new BulletBodyXNA(pLocalID, gObj);
1629 }
1630
1631 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape)
1632 {
1633 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1634 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1635 if (pShape == null)
1636 {
1637 collisionObject.SetCollisionShape(new EmptyShape());
1638 }
1639 else
1640 {
1641 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1642 collisionObject.SetCollisionShape(shape);
1643 }
1644 }
1645 public override BulletShape GetCollisionShape(BulletBody pCollisionObject)
1646 {
1647 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1648 CollisionShape shape = collisionObject.GetCollisionShape();
1649 return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1650 }
1651
1652 //(PhysicsScene.World.ptr, nativeShapeData)
1653 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1654 {
1655 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1656 CollisionShape shape = null;
1657 switch (pShapeData.Type)
1658 {
1659 case BSPhysicsShapeType.SHAPE_BOX:
1660 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1661 break;
1662 case BSPhysicsShapeType.SHAPE_CONE:
1663 shape = new ConeShapeZ(0.5f, 1.0f);
1664 break;
1665 case BSPhysicsShapeType.SHAPE_CYLINDER:
1666 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1667 break;
1668 case BSPhysicsShapeType.SHAPE_SPHERE:
1669 shape = new SphereShape(0.5f);
1670 break;
1671
1672 }
1673 if (shape != null)
1674 {
1675 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1676 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1677 shape.SetLocalScaling(ref scaling);
1678
1679 }
1680 return new BulletShapeXNA(shape, pShapeData.Type);
1681 }
1682 //PhysicsScene.World.ptr, false
1683 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1684 {
1685 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1686 }
1687
1688 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1689 {
1690 CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
1691 return compoundshape.GetNumChildShapes();
1692 }
1693 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1694 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1695 {
1696 IndexedMatrix relativeTransform = new IndexedMatrix();
1697 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1698 CollisionShape addshape = (paddShape as BulletShapeXNA).shape;
1699
1700 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1701 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1702 compoundshape.AddChildShape(ref relativeTransform, addshape);
1703
1704 }
1705
1706 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1707 {
1708 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1709 CollisionShape ret = null;
1710 ret = compoundshape.GetChildShape(pii);
1711 compoundshape.RemoveChildShapeByIndex(pii);
1712 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType()));
1713 }
1714
1715 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) {
1716
1717 if (cShape == null)
1718 return null;
1719 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape;
1720 CollisionShape shape = compoundShape.GetChildShape(indx);
1721 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1722
1723
1724 return retShape;
1725 }
1726
1727 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin)
1728 {
1729 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1730 switch (pin)
1731 {
1732 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1733 ret = BSPhysicsShapeType.SHAPE_BOX;
1734 break;
1735 case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE:
1736 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1737 break;
1738
1739 case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE:
1740 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1741 break;
1742 case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE:
1743 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1744 break;
1745 case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE:
1746 ret = BSPhysicsShapeType.SHAPE_HULL;
1747 break;
1748 case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE:
1749 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1750 break;
1751 case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE:
1752 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1753 break;
1754 //implicit convex shapes
1755 case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE:
1756 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1757 break;
1758 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1759 ret = BSPhysicsShapeType.SHAPE_SPHERE;
1760 break;
1761 case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE:
1762 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1763 break;
1764 case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE:
1765 ret = BSPhysicsShapeType.SHAPE_CAPSULE;
1766 break;
1767 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1768 ret = BSPhysicsShapeType.SHAPE_CONE;
1769 break;
1770 case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE:
1771 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1772 break;
1773 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1774 ret = BSPhysicsShapeType.SHAPE_CYLINDER;
1775 break;
1776 case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE:
1777 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1778 break;
1779 case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE:
1780 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1781 break;
1782 case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE:
1783 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1784 break;
1785 case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE:
1786 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1787 break;
1788 case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE:
1789 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1790 break;
1791 case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE:
1792 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1793 break;
1794 //concave shape
1795 case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE:
1796 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1797 break;
1798 //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy!
1799 case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE:
1800 ret = BSPhysicsShapeType.SHAPE_MESH;
1801 break;
1802 case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE:
1803 ret = BSPhysicsShapeType.SHAPE_MESH;
1804 break;
1805 ///used for demo integration FAST/Swift collision library and Bullet
1806 case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE:
1807 ret = BSPhysicsShapeType.SHAPE_MESH;
1808 break;
1809 //terrain
1810 case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE:
1811 ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP;
1812 break;
1813 ///Used for GIMPACT Trimesh integration
1814 case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE:
1815 ret = BSPhysicsShapeType.SHAPE_GIMPACT;
1816 break;
1817 ///Multimaterial mesh
1818 case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE:
1819 ret = BSPhysicsShapeType.SHAPE_MESH;
1820 break;
1821
1822 case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE:
1823 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1824 break;
1825 case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE:
1826 ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE;
1827 break;
1828 case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE:
1829 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1830 break;
1831 case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE:
1832 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1833 break;
1834
1835 case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE:
1836 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
1837 break;
1838
1839 case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE:
1840 ret = BSPhysicsShapeType.SHAPE_MESH;
1841 break;
1842 case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE:
1843 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1844 break;
1845 case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE:
1846 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1847 break;
1848 case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE:
1849 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1850 break;
1851 }
1852 return ret;
1853 }
1854
1855 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1856 public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ }
1857
1858 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1859 {
1860 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1861 m_planeshape.SetMargin(pcollisionMargin);
1862 m_planeshape.SetUserPointer(pLocalId);
1863 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1864 }
1865
1866 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1867 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
1868 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1869
1870 {
1871 Generic6DofSpringConstraint constrain = null;
1872 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1873 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
1874 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
1875 if (body1 != null && body2 != null)
1876 {
1877 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1878 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1879 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1880 frame1._origin = frame1v;
1881
1882 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1883 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1884 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1885 frame2._origin = frame1v;
1886
1887 constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1888 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1889
1890 constrain.CalculateTransforms();
1891 }
1892
1893 return new BulletConstraintXNA(constrain);
1894 }
1895
1896 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1897 Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB,
1898 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1899 {
1900 HingeConstraint constrain = null;
1901 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1902 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1903 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1904 if (rb1 != null && rb2 != null)
1905 {
1906 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1907 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1908 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1909 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1910 constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA);
1911 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1912 }
1913 return new BulletConstraintXNA(constrain);
1914 }
1915
1916 public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1917 Vector3 pframe1, Quaternion pframe1rot,
1918 Vector3 pframe2, Quaternion pframe2rot,
1919 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1920 {
1921 SliderConstraint constrain = null;
1922 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1923 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1924 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1925 if (rb1 != null && rb2 != null)
1926 {
1927 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1928 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1929 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1930 frame1._origin = frame1v;
1931
1932 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1933 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1934 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1935 frame2._origin = frame1v;
1936
1937 constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1938 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1939 }
1940 return new BulletConstraintXNA(constrain);
1941 }
1942
1943 public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1944 Vector3 pframe1, Quaternion pframe1rot,
1945 Vector3 pframe2, Quaternion pframe2rot,
1946 bool pdisableCollisionsBetweenLinkedBodies)
1947 {
1948 ConeTwistConstraint constrain = null;
1949 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1950 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1951 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1952 if (rb1 != null && rb2 != null)
1953 {
1954 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1955 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1956 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1957 frame1._origin = frame1v;
1958
1959 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1960 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1961 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1962 frame2._origin = frame1v;
1963
1964 constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2);
1965 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1966 }
1967 return new BulletConstraintXNA(constrain);
1968 }
1969
1970 public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1971 Vector3 paxisInA, Vector3 paxisInB,
1972 float pratio, bool pdisableCollisionsBetweenLinkedBodies)
1973 {
1974 Generic6DofConstraint constrain = null;
1975 /* BulletXNA does not have a gear constraint
1976 GearConstraint constrain = null;
1977 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1978 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1979 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1980 if (rb1 != null && rb2 != null)
1981 {
1982 IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1983 IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1984 constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio);
1985 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1986 }
1987 */
1988 return new BulletConstraintXNA(constrain);
1989 }
1990
1991 public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1992 Vector3 ppivotInA, Vector3 ppivotInB,
1993 bool pdisableCollisionsBetweenLinkedBodies)
1994 {
1995 Point2PointConstraint constrain = null;
1996 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1997 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1998 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1999 if (rb1 != null && rb2 != null)
2000 {
2001 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
2002 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
2003 constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB);
2004 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
2005 }
2006 return new BulletConstraintXNA(constrain);
2007 }
2008
2009 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
2010 {
2011 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2012 CompoundShape compoundshape = new CompoundShape(false);
2013
2014 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
2015 int ii = 1;
2016
2017 for (int i = 0; i < pHullCount; i++)
2018 {
2019 int vertexCount = (int) pConvHulls[ii];
2020
2021 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
2022 IndexedMatrix childTrans = IndexedMatrix.Identity;
2023 childTrans._origin = centroid;
2024
2025 List<IndexedVector3> virts = new List<IndexedVector3>();
2026 int ender = ((ii + 4) + (vertexCount*3));
2027 for (int iii = ii + 4; iii < ender; iii+=3)
2028 {
2029
2030 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
2031 }
2032 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
2033 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
2034 compoundshape.AddChildShape(ref childTrans, convexShape);
2035 ii += (vertexCount*3 + 4);
2036 }
2037
2038 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
2039 }
2040
2041 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
2042 {
2043 /* TODO */ return null;
2044 }
2045
2046 public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
2047 {
2048 /* TODO */ return null;
2049 }
2050
2051 public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2052 {
2053 /* TODO */ return null;
2054 }
2055
2056 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2057 {
2058 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
2059
2060 for (int iter = 0; iter < pVerticesCount; iter++)
2061 {
2062 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
2063 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
2064 }
2065
2066 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
2067 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
2068 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
2069 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2070 IndexedMesh mesh = new IndexedMesh();
2071 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
2072 mesh.m_numTriangles = pIndicesCount/3;
2073 mesh.m_numVertices = pVerticesCount;
2074 mesh.m_triangleIndexBase = indicesarr;
2075 mesh.m_vertexBase = vertices;
2076 mesh.m_vertexStride = 3;
2077 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
2078 mesh.m_triangleIndexStride = 3;
2079
2080 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
2081 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
2082 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
2083 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
2084 // world.UpdateSingleAabb(meshShape);
2085 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
2086
2087 }
2088 public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2089 {
2090 // TODO:
2091 return null;
2092 }
2093 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
2094 {
2095
2096 String fileName = "objTest3.raw";
2097 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
2098 StreamWriter sw = new StreamWriter(completePath);
2099 IndexedMesh mesh = new IndexedMesh();
2100
2101 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
2102 mesh.m_numTriangles = pIndicesCount / 3;
2103 mesh.m_numVertices = pVerticesCount;
2104 mesh.m_triangleIndexBase = indices;
2105 mesh.m_vertexBase = vertices;
2106 mesh.m_vertexStride = 3;
2107 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
2108 mesh.m_triangleIndexStride = 3;
2109
2110 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
2111 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
2112
2113
2114
2115 for (int i = 0; i < pVerticesCount; i++)
2116 {
2117
2118 string s = vertices[indices[i * 3]].ToString("0.0000");
2119 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
2120 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
2121
2122 sw.Write(s + "\n");
2123 }
2124
2125 sw.Close();
2126 }
2127 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
2128 {
2129
2130 String fileName = "objTest6.raw";
2131 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
2132 StreamWriter sw = new StreamWriter(completePath);
2133 IndexedMesh mesh = new IndexedMesh();
2134
2135 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
2136 mesh.m_numTriangles = pIndicesCount / 3;
2137 mesh.m_numVertices = pVerticesCount;
2138 mesh.m_triangleIndexBase = indices;
2139 mesh.m_vertexBase = vertices;
2140 mesh.m_vertexStride = 3;
2141 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
2142 mesh.m_triangleIndexStride = 3;
2143
2144 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
2145 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
2146
2147
2148 sw.WriteLine("Indices");
2149 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
2150 for (int iter = 0; iter < indices.Length; iter++)
2151 {
2152 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
2153 }
2154 sw.WriteLine("VerticesFloats");
2155 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
2156 for (int iter = 0; iter < vertices.Length; iter++)
2157 {
2158 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
2159 }
2160
2161 // for (int i = 0; i < pVerticesCount; i++)
2162 // {
2163 //
2164 // string s = vertices[indices[i * 3]].ToString("0.0000");
2165 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
2166 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
2167 //
2168 // sw.Write(s + "\n");
2169 //}
2170
2171 sw.Close();
2172 }
2173
2174 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
2175 float scaleFactor, float collisionMargin)
2176 {
2177 const int upAxis = 2;
2178 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
2179 heightMap, scaleFactor,
2180 minHeight, maxHeight, upAxis,
2181 false);
2182 terrainShape.SetMargin(collisionMargin);
2183 terrainShape.SetUseDiamondSubdivision(true);
2184 terrainShape.SetUserPointer(id);
2185 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
2186 }
2187
2188 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
2189 {
2190 TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain;
2191 bool onOff = ponOff != 0;
2192 bool ret = false;
2193
2194 switch (tconstrain.GetConstraintType())
2195 {
2196 case TypedConstraintType.D6_CONSTRAINT_TYPE:
2197 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
2198 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
2199 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
2200 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
2201 ret = true;
2202 break;
2203 }
2204
2205
2206 return ret;
2207
2208 }
2209
2210 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
2211 out int updatedEntityCount, out int collidersCount)
2212 {
2213 /* TODO */
2214 updatedEntityCount = 0;
2215 collidersCount = 0;
2216
2217
2218 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
2219
2220 return ret;
2221 }
2222
2223 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
2224 out int updatedEntityCount, out EntityProperties[] updatedEntities,
2225 out int collidersCount, out CollisionDesc[] colliders)
2226 {
2227 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
2228 out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame);
2229 return epic;
2230 }
2231
2232 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
2233 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
2234 {
2235 int numSimSteps = 0;
2236 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length);
2237 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length);
2238 LastEntityProperty=0;
2239
2240
2241
2242
2243
2244
2245 LastCollisionDesc=0;
2246
2247 updatedEntityCount = 0;
2248 collidersCount = 0;
2249
2250
2251 if (pWorld is BulletWorldXNA)
2252 {
2253 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2254
2255 world.LastCollisionDesc = 0;
2256 world.LastEntityProperty = 0;
2257 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
2258
2259 PersistentManifold contactManifold;
2260 CollisionObject objA;
2261 CollisionObject objB;
2262 ManifoldPoint manifoldPoint;
2263 PairCachingGhostObject pairCachingGhostObject;
2264
2265 m_collisionsThisFrame = 0;
2266 int numManifolds = world.GetDispatcher().GetNumManifolds();
2267 for (int j = 0; j < numManifolds; j++)
2268 {
2269 contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
2270 int numContacts = contactManifold.GetNumContacts();
2271 if (numContacts == 0)
2272 continue;
2273
2274 objA = contactManifold.GetBody0() as CollisionObject;
2275 objB = contactManifold.GetBody1() as CollisionObject;
2276
2277 manifoldPoint = contactManifold.GetContactPoint(0);
2278 //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
2279 // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
2280
2281 RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance());
2282 m_collisionsThisFrame ++;
2283 if (m_collisionsThisFrame >= 9999999)
2284 break;
2285
2286
2287 }
2288
2289 foreach (GhostObject ghostObject in specialCollisionObjects.Values)
2290 {
2291 pairCachingGhostObject = ghostObject as PairCachingGhostObject;
2292 if (pairCachingGhostObject != null)
2293 {
2294 RecordGhostCollisions(pairCachingGhostObject);
2295 }
2296
2297 }
2298
2299
2300 updatedEntityCount = LastEntityProperty;
2301 updatedEntities = UpdatedObjects;
2302
2303 collidersCount = LastCollisionDesc;
2304 colliders = UpdatedCollisions;
2305
2306
2307 }
2308 else
2309 {
2310 //if (updatedEntities is null)
2311 //updatedEntities = new List<BulletXNA.EntityProperties>();
2312 //updatedEntityCount = 0;
2313
2314
2315 //collidersCount = 0;
2316
2317 updatedEntities = new EntityProperties[0];
2318
2319
2320 colliders = new CollisionDesc[0];
2321
2322 }
2323 return numSimSteps;
2324 }
2325 public void RecordGhostCollisions(PairCachingGhostObject obj)
2326 {
2327 IOverlappingPairCache cache = obj.GetOverlappingPairCache();
2328 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray();
2329
2330 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world;
2331 PersistentManifoldArray manifoldArray = new PersistentManifoldArray();
2332 BroadphasePair collisionPair;
2333 PersistentManifold contactManifold;
2334
2335 CollisionObject objA;
2336 CollisionObject objB;
2337
2338 ManifoldPoint pt;
2339
2340 int numPairs = pairs.Count;
2341
2342 for (int i = 0; i < numPairs; i++)
2343 {
2344 manifoldArray.Clear();
2345 if (LastCollisionDesc < UpdatedCollisions.Length)
2346 break;
2347 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1);
2348 if (collisionPair == null)
2349 continue;
2350
2351 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray);
2352 for (int j = 0; j < manifoldArray.Count; j++)
2353 {
2354 contactManifold = manifoldArray[j];
2355 int numContacts = contactManifold.GetNumContacts();
2356 objA = contactManifold.GetBody0() as CollisionObject;
2357 objB = contactManifold.GetBody1() as CollisionObject;
2358 for (int p = 0; p < numContacts; p++)
2359 {
2360 pt = contactManifold.GetContactPoint(p);
2361 if (pt.GetDistance() < 0.0f)
2362 {
2363 RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance());
2364 break;
2365 }
2366 }
2367 }
2368 }
2369
2370 }
2371 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration)
2372 {
2373
2374 IndexedVector3 contactNormal = norm;
2375 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
2376 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
2377 {
2378 return;
2379 }
2380 uint idA = (uint)objA.GetUserPointer();
2381 uint idB = (uint)objB.GetUserPointer();
2382 if (idA > idB)
2383 {
2384 uint temp = idA;
2385 idA = idB;
2386 idB = temp;
2387 contactNormal = -contactNormal;
2388 }
2389
2390 //ulong collisionID = ((ulong) idA << 32) | idB;
2391
2392 CollisionDesc cDesc = new CollisionDesc()
2393 {
2394 aID = idA,
2395 bID = idB,
2396 point = new Vector3(contact.X,contact.Y,contact.Z),
2397 normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z),
2398 penetration = penetration
2399
2400 };
2401 if (world.LastCollisionDesc < world.UpdatedCollisions.Length)
2402 world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc);
2403 m_collisionsThisFrame++;
2404
2405
2406 }
2407 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject)
2408 {
2409 EntityProperties ent = new EntityProperties();
2410 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2411 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
2412 IndexedMatrix transform = collisionObject.GetWorldTransform();
2413 IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity();
2414 IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity();
2415 IndexedQuaternion rotation = transform.GetRotation();
2416 ent.Acceleration = Vector3.Zero;
2417 ent.ID = (uint)collisionObject.GetUserPointer();
2418 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
2419 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
2420 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
2421 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
2422 return ent;
2423 }
2424
2425 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */
2426 return false; }
2427
2428 public override Vector3 GetLocalScaling(BulletShape pShape)
2429 {
2430 CollisionShape shape = (pShape as BulletShapeXNA).shape;
2431 IndexedVector3 scale = shape.GetLocalScaling();
2432 return new Vector3(scale.X,scale.Y,scale.Z);
2433 }
2434
2435 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
2436 {
2437 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2438 if (world != null)
2439 {
2440 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
2441 {
2442 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
2443
2444 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
2445 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
2446 using (
2447 ClosestNotMeRayResultCallback rayCallback =
2448 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
2449 )
2450 {
2451 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
2452 if (rayCallback.HasHit())
2453 {
2454 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
2455 }
2456 return rayCallback.HasHit();
2457 }
2458 }
2459 }
2460 return false;
2461 }
2462}
2463
2464
2465
2466
2467 public class SimMotionState : DefaultMotionState
2468 {
2469 public RigidBody Rigidbody;
2470 public Vector3 ZeroVect;
2471
2472 private IndexedMatrix m_xform;
2473
2474 private EntityProperties m_properties;
2475 private EntityProperties m_lastProperties;
2476 private BSAPIXNA m_world;
2477
2478 const float POSITION_TOLERANCE = 0.05f;
2479 const float VELOCITY_TOLERANCE = 0.001f;
2480 const float ROTATION_TOLERANCE = 0.01f;
2481 const float ANGULARVELOCITY_TOLERANCE = 0.01f;
2482
2483 public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates)
2484 {
2485 IndexedQuaternion OrientationQuaterion = starTransform.GetRotation();
2486 m_properties = new EntityProperties()
2487 {
2488 ID = id,
2489 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z),
2490 Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W)
2491 };
2492 m_lastProperties = new EntityProperties()
2493 {
2494 ID = id,
2495 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z),
2496 Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W)
2497 };
2498 m_world = pWorld;
2499 m_xform = starTransform;
2500 }
2501
2502 public override void GetWorldTransform(out IndexedMatrix worldTrans)
2503 {
2504 worldTrans = m_xform;
2505 }
2506
2507 public override void SetWorldTransform(IndexedMatrix worldTrans)
2508 {
2509 SetWorldTransform(ref worldTrans);
2510 }
2511
2512 public override void SetWorldTransform(ref IndexedMatrix worldTrans)
2513 {
2514 SetWorldTransform(ref worldTrans, false);
2515 }
2516 public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force)
2517 {
2518 m_xform = worldTrans;
2519 // Put the new transform into m_properties
2520 IndexedQuaternion OrientationQuaternion = m_xform.GetRotation();
2521 IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity();
2522 IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity();
2523 m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z);
2524 m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y,
2525 OrientationQuaternion.Z, OrientationQuaternion.W);
2526 // A problem with stock Bullet is that we don't get an event when an object is deactivated.
2527 // This means that the last non-zero values for linear and angular velocity
2528 // are left in the viewer who does dead reconning and the objects look like
2529 // they float off.
2530 // BulletSim ships with a patch to Bullet which creates such an event.
2531 m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z);
2532 m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z);
2533
2534 if (force
2535
2536 || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE)
2537 || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE)
2538 // If the Velocity and AngularVelocity are zero, most likely the object has
2539 // been deactivated. If they both are zero and they have become zero recently,
2540 // make sure a property update is sent so the zeros make it to the viewer.
2541 || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect)
2542 &&
2543 (m_properties.Velocity != m_lastProperties.Velocity ||
2544 m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity))
2545 // If Velocity and AngularVelocity are non-zero but have changed, send an update.
2546 || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE)
2547 ||
2548 !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity,
2549 ANGULARVELOCITY_TOLERANCE)
2550 )
2551
2552
2553 {
2554 // Add this update to the list of updates for this frame.
2555 m_lastProperties = m_properties;
2556 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length)
2557 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties);
2558
2559 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties;
2560 }
2561
2562
2563
2564
2565 }
2566 public override void SetRigidBody(RigidBody body)
2567 {
2568 Rigidbody = body;
2569 }
2570 internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon)
2571 {
2572 return
2573 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2574 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2575 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon)));
2576 }
2577
2578 internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon)
2579 {
2580 return
2581 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2582 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2583 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) &&
2584 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon)));
2585 }
2586
2587 }
2588}
2589
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs
new file mode 100755
index 0000000..0191893
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs
@@ -0,0 +1,457 @@
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
33using OpenSim.Framework;
34using OpenSim.Region.PhysicsModules.SharedBase;
35
36using OMV = OpenMetaverse;
37
38namespace OpenSim.Region.PhysicsModule.BulletS
39{
40public class BSActorAvatarMove : BSActor
41{
42 BSVMotor m_velocityMotor;
43
44 // Set to true if we think we're going up stairs.
45 // This state is remembered because collisions will turn on and off as we go up stairs.
46 int m_walkingUpStairs;
47 // The amount the step up is applying. Used to smooth stair walking.
48 float m_lastStepUp;
49
50 // Jumping happens over several frames. If use applies up force while colliding, start the
51 // jump and allow the jump to continue for this number of frames.
52 int m_jumpFrames = 0;
53 float m_jumpVelocity = 0f;
54
55 public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
56 : base(physicsScene, pObj, actorName)
57 {
58 m_velocityMotor = null;
59 m_walkingUpStairs = 0;
60 m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
61 }
62
63 // BSActor.isActive
64 public override bool isActive
65 {
66 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
67 }
68
69 // Release any connections and resources used by the actor.
70 // BSActor.Dispose()
71 public override void Dispose()
72 {
73 base.SetEnabled(false);
74 DeactivateAvatarMove();
75 }
76
77 // Called when physical parameters (properties set in Bullet) need to be re-applied.
78 // Called at taint-time.
79 // BSActor.Refresh()
80 public override void Refresh()
81 {
82 m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
83
84 // If the object is physically active, add the hoverer prestep action
85 if (isActive)
86 {
87 ActivateAvatarMove();
88 }
89 else
90 {
91 DeactivateAvatarMove();
92 }
93 }
94
95 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
96 // Register a prestep action to restore physical requirements before the next simulation step.
97 // Called at taint-time.
98 // BSActor.RemoveDependencies()
99 public override void RemoveDependencies()
100 {
101 // Nothing to do for the hoverer since it is all software at pre-step action time.
102 }
103
104 // Usually called when target velocity changes to set the current velocity and the target
105 // into the movement motor.
106 public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
107 {
108 m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate()
109 {
110 if (m_velocityMotor != null)
111 {
112// if (targ == OMV.Vector3.Zero)
113// Util.PrintCallStack();
114//
115// Console.WriteLine("SetVelocityAndTarget, {0} {1}", vel, targ);
116 m_velocityMotor.Reset();
117 m_velocityMotor.SetTarget(targ);
118 m_velocityMotor.SetCurrent(vel);
119 m_velocityMotor.Enabled = true;
120 }
121 });
122 }
123
124 // If a hover motor has not been created, create one and start the hovering.
125 private void ActivateAvatarMove()
126 {
127 if (m_velocityMotor == null)
128 {
129 // Infinite decay and timescale values so motor only changes current to target values.
130 m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
131 0.2f, // time scale
132 BSMotor.Infinite, // decay time scale
133 1f // efficiency
134 );
135 m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold;
136 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
137 SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
138
139 m_physicsScene.BeforeStep += Mover;
140 m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty;
141
142 m_walkingUpStairs = 0;
143 }
144 }
145
146 private void DeactivateAvatarMove()
147 {
148 if (m_velocityMotor != null)
149 {
150 m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty;
151 m_physicsScene.BeforeStep -= Mover;
152 m_velocityMotor = null;
153 }
154 }
155
156 // Called just before the simulation step. Update the vertical position for hoverness.
157 private void Mover(float timeStep)
158 {
159 // Don't do movement while the object is selected.
160 if (!isActive)
161 return;
162
163 // TODO: Decide if the step parameters should be changed depending on the avatar's
164 // state (flying, colliding, ...). There is code in ODE to do this.
165
166 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
167 // specified for the avatar is the one that should be used. For falling, if the avatar
168 // is not flying and is not colliding then it is presumed to be falling and the Z
169 // component is not fooled with (thus allowing gravity to do its thing).
170 // When the avatar is standing, though, the user has specified a velocity of zero and
171 // the avatar should be standing. But if the avatar is pushed by something in the world
172 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
173 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
174 // errors can creap in and the avatar will slowly float off in some direction.
175 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
176 // from real pushing.
177 // The code below uses whether the collider is static or moving to decide whether to zero motion.
178
179 m_velocityMotor.Step(timeStep);
180 m_controllingPrim.IsStationary = false;
181
182 // If we're not supposed to be moving, make sure things are zero.
183 if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
184 {
185 // The avatar shouldn't be moving
186 m_velocityMotor.Zero();
187
188 if (m_controllingPrim.IsColliding)
189 {
190 // If we are colliding with a stationary object, presume we're standing and don't move around
191 if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect)
192 {
193 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
194 m_controllingPrim.IsStationary = true;
195 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
196 }
197
198 // Standing has more friction on the ground
199 if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
200 {
201 m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
202 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
203 }
204 }
205 else
206 {
207 if (m_controllingPrim.Flying)
208 {
209 // Flying and not colliding and velocity nearly zero.
210 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
211 }
212 else
213 {
214 //We are falling but are not touching any keys make sure not falling too fast
215 if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity)
216 {
217
218 OMV.Vector3 slowingForce = new OMV.Vector3(0f, 0f, BSParam.AvatarTerminalVelocity - m_controllingPrim.RawVelocity.Z) * m_controllingPrim.Mass;
219 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, slowingForce);
220 }
221
222 }
223 }
224
225 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
226 m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
227 }
228 else
229 {
230 // Supposed to be moving.
231 OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
232
233 if (m_controllingPrim.Friction != BSParam.AvatarFriction)
234 {
235 // Probably starting to walk. Set friction to moving friction.
236 m_controllingPrim.Friction = BSParam.AvatarFriction;
237 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
238 }
239
240 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
241 {
242 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
243 }
244
245 // Colliding and not flying with an upward force. The avatar must be trying to jump.
246 if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0)
247 {
248 // We allow the upward force to happen for this many frames.
249 m_jumpFrames = BSParam.AvatarJumpFrames;
250 m_jumpVelocity = stepVelocity.Z;
251 }
252
253 // The case where the avatar is not colliding and is not flying is special.
254 // The avatar is either falling or jumping and the user can be applying force to the avatar
255 // (force in some direction or force up or down).
256 // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity.
257 // If the user is trying to apply upward force but we're not colliding, assume the avatar
258 // is trying to jump and don't apply the upward force if not touching the ground any more.
259 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
260 {
261 // If upward velocity is being applied, this must be a jump and only allow that to go on so long
262 if (m_jumpFrames > 0)
263 {
264 // Since not touching the ground, only apply upward force for so long.
265 m_jumpFrames--;
266 stepVelocity.Z = m_jumpVelocity;
267 }
268 else
269 {
270
271 // Since we're not affected by anything, the avatar must be falling and we do not want that to be too fast.
272 if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity)
273 {
274
275 stepVelocity.Z = BSParam.AvatarTerminalVelocity;
276 }
277 else
278 {
279 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
280 }
281 }
282 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
283 }
284
285 //Alicia: Maintain minimum height when flying.
286 // SL has a flying effect that keeps the avatar flying above the ground by some margin
287 if (m_controllingPrim.Flying)
288 {
289 float hover_height = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition)
290 + BSParam.AvatarFlyingGroundMargin;
291
292 if( m_controllingPrim.Position.Z < hover_height)
293 {
294 stepVelocity.Z += BSParam.AvatarFlyingGroundUpForce;
295 }
296 }
297
298 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
299 OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
300
301 // Add special movement force to allow avatars to walk up stepped surfaces.
302 moveForce += WalkUpStairs();
303
304 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
305 m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
306 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
307 }
308 }
309
310 // Called just as the property update is received from the physics engine.
311 // Do any mode necessary for avatar movement.
312 private void Process_OnPreUpdateProperty(ref EntityProperties entprop)
313 {
314 // Don't change position if standing on a stationary object.
315 if (m_controllingPrim.IsStationary)
316 {
317 entprop.Position = m_controllingPrim.RawPosition;
318 entprop.Velocity = OMV.Vector3.Zero;
319 m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation);
320 }
321
322 }
323
324 // Decide if the character is colliding with a low object and compute a force to pop the
325 // avatar up so it can walk up and over the low objects.
326 private OMV.Vector3 WalkUpStairs()
327 {
328 OMV.Vector3 ret = OMV.Vector3.Zero;
329
330 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}",
331 m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying,
332 m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z);
333
334 // Check for stairs climbing if colliding, not flying and moving forward
335 if ( m_controllingPrim.IsColliding
336 && !m_controllingPrim.Flying
337 && m_controllingPrim.TargetVelocitySpeed > 0.1f )
338 {
339 // The range near the character's feet where we will consider stairs
340 // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
341 // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off
342 // from the height. Revisit size and this computation when height is scaled properly.
343 float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - BSParam.AvatarStepGroundFudge;
344 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
345
346 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is.
347 // Find the highest 'good' collision.
348 OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero;
349 foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
350 {
351 // Don't care about collisions with the terrain
352 if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
353 {
354 BSPhysObject collisionObject;
355 if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject))
356 {
357 if (!collisionObject.IsVolumeDetect)
358 {
359 OMV.Vector3 touchPosition = kvp.Value.Position;
360 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
361 m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
362 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
363 {
364 // This contact is within the 'near the feet' range.
365 // The step is presumed to be more or less vertical. Thus the Z component should
366 // be nearly horizontal.
367 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
368 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
369 const float PIOver2 = 1.571f; // Used to make unit vector axis into approx radian angles
370 // m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,avNormal={1},colNormal={2},diff={3}",
371 // m_controllingPrim.LocalID, directionFacing, touchNormal,
372 // Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)) );
373 if ((Math.Abs(directionFacing.Z) * PIOver2) < BSParam.AvatarStepAngle
374 && (Math.Abs(touchNormal.Z) * PIOver2) < BSParam.AvatarStepAngle)
375 {
376 // The normal should be our contact point to the object so it is pointing away
377 // thus the difference between our facing orientation and the normal should be small.
378 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
379 if (diff < BSParam.AvatarStepApproachFactor)
380 {
381 if (highestTouchPosition.Z < touchPosition.Z)
382 highestTouchPosition = touchPosition;
383 }
384 }
385 }
386 }
387 }
388 }
389 }
390 m_walkingUpStairs = 0;
391 // If there is a good step sensing, move the avatar over the step.
392 if (highestTouchPosition != OMV.Vector3.Zero)
393 {
394 // Remember that we are going up stairs. This is needed because collisions
395 // will stop when we move up so this smoothes out that effect.
396 m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps;
397
398 m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin;
399 ret = ComputeStairCorrection(m_lastStepUp);
400 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}",
401 m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret);
402 }
403 }
404 else
405 {
406 // If we used to be going up stairs but are not now, smooth the case where collision goes away while
407 // we are bouncing up the stairs.
408 if (m_walkingUpStairs > 0)
409 {
410 m_walkingUpStairs--;
411 ret = ComputeStairCorrection(m_lastStepUp);
412 }
413 }
414
415 return ret;
416 }
417
418 private OMV.Vector3 ComputeStairCorrection(float stepUp)
419 {
420 OMV.Vector3 ret = OMV.Vector3.Zero;
421 OMV.Vector3 displacement = OMV.Vector3.Zero;
422
423 if (stepUp > 0f)
424 {
425 // Found the stairs contact point. Push up a little to raise the character.
426 if (BSParam.AvatarStepForceFactor > 0f)
427 {
428 float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
429 ret = new OMV.Vector3(0f, 0f, upForce);
430 }
431
432 // Also move the avatar up for the new height
433 if (BSParam.AvatarStepUpCorrectionFactor > 0f)
434 {
435 // Move the avatar up related to the height of the collision
436 displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor);
437 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
438 }
439 else
440 {
441 if (BSParam.AvatarStepUpCorrectionFactor < 0f)
442 {
443 // Move the avatar up about the specified step height
444 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight);
445 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
446 }
447 }
448 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,stepUp={1},isp={2},force={3}",
449 m_controllingPrim.LocalID, stepUp, displacement, ret);
450
451 }
452 return ret;
453 }
454}
455}
456
457
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs
new file mode 100755
index 0000000..7ff171e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs
@@ -0,0 +1,174 @@
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
33using OpenSim.Region.PhysicsModules.SharedBase;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
38{
39public class BSActorHover : BSActor
40{
41 private BSFMotor m_hoverMotor;
42
43 public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_hoverMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 DeactivateHover();
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
70
71 // If not active any more, turn me off
72 if (!m_controllingPrim.HoverActive)
73 {
74 SetEnabled(false);
75 }
76
77 // If the object is physically active, add the hoverer prestep action
78 if (isActive)
79 {
80 ActivateHover();
81 }
82 else
83 {
84 DeactivateHover();
85 }
86 }
87
88 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
89 // Register a prestep action to restore physical requirements before the next simulation step.
90 // Called at taint-time.
91 // BSActor.RemoveDependencies()
92 public override void RemoveDependencies()
93 {
94 // Nothing to do for the hoverer since it is all software at pre-step action time.
95 }
96
97 // If a hover motor has not been created, create one and start the hovering.
98 private void ActivateHover()
99 {
100 if (m_hoverMotor == null)
101 {
102 // Turning the target on
103 m_hoverMotor = new BSFMotor("BSActorHover",
104 m_controllingPrim.HoverTau, // timeScale
105 BSMotor.Infinite, // decay time scale
106 1f // efficiency
107 );
108 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
109 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
110 m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
111
112 m_physicsScene.BeforeStep += Hoverer;
113 }
114 }
115
116 private void DeactivateHover()
117 {
118 if (m_hoverMotor != null)
119 {
120 m_physicsScene.BeforeStep -= Hoverer;
121 m_hoverMotor = null;
122 }
123 }
124
125 // Called just before the simulation step. Update the vertical position for hoverness.
126 private void Hoverer(float timeStep)
127 {
128 // Don't do hovering while the object is selected.
129 if (!isActive)
130 return;
131
132 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
133 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
134 float targetHeight = m_hoverMotor.Step(timeStep);
135
136 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
137 // Compute the amount of force to push us there.
138 float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
139 // Undo anything the object thinks it's doing at the moment
140 moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
141
142 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
143 m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
144 m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
145 }
146
147 // Based on current position, determine what we should be hovering at now.
148 // Must recompute often. What if we walked offa cliff>
149 private float ComputeCurrentHoverHeight()
150 {
151 float ret = m_controllingPrim.HoverHeight;
152 float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
153
154 switch (m_controllingPrim.HoverType)
155 {
156 case PIDHoverType.Ground:
157 ret = groundHeight + m_controllingPrim.HoverHeight;
158 break;
159 case PIDHoverType.GroundAndWater:
160 float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
161 if (groundHeight > waterHeight)
162 {
163 ret = groundHeight + m_controllingPrim.HoverHeight;
164 }
165 else
166 {
167 ret = waterHeight + m_controllingPrim.HoverHeight;
168 }
169 break;
170 }
171 return ret;
172 }
173}
174}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs
new file mode 100755
index 0000000..78c1b6a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs
@@ -0,0 +1,219 @@
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
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.PhysicsModule.BulletS
36{
37public class BSActorLockAxis : BSActor
38{
39 private BSConstraint LockAxisConstraint = null;
40 private bool HaveRegisteredForBeforeStepCallback = false;
41
42 // The lock access flags (which axises were locked) when the contraint was built.
43 // Used to see if locking has changed since when the constraint was built.
44 OMV.Vector3 LockAxisLinearFlags;
45 OMV.Vector3 LockAxisAngularFlags;
46
47 public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
48 : base(physicsScene, pObj, actorName)
49 {
50 m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
51 LockAxisConstraint = null;
52 HaveRegisteredForBeforeStepCallback = false;
53 }
54
55 // BSActor.isActive
56 public override bool isActive
57 {
58 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
59 }
60
61 // Release any connections and resources used by the actor.
62 // BSActor.Dispose()
63 public override void Dispose()
64 {
65 Enabled = false;
66 UnRegisterForBeforeStepCallback();
67 RemoveAxisLockConstraint();
68 }
69
70 // Called when physical parameters (properties set in Bullet) need to be re-applied.
71 // Called at taint-time.
72 // BSActor.Refresh()
73 public override void Refresh()
74 {
75 // Since the axis logging is done with a constraint, Refresh() time is good for
76 // changing parameters but this needs to wait until the prim/linkset is physically
77 // constructed. Therefore, the constraint itself is placed at pre-step time.
78
79 // If all the axis are free, we don't need to exist
80 // Refresh() only turns off. Enabling is done by InitializeAxisActor()
81 // whenever parameters are changed.
82 // This leaves 'enable' free to turn off an actor when it is not wanted to run.
83 if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree
84 && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree)
85 {
86 Enabled = false;
87 }
88
89 if (isActive)
90 {
91 RegisterForBeforeStepCallback();
92 }
93 else
94 {
95 RemoveDependencies();
96 UnRegisterForBeforeStepCallback();
97 }
98 }
99
100 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
101 // Register a prestep action to restore physical requirements before the next simulation step.
102 // Called at taint-time.
103 // BSActor.RemoveDependencies()
104 public override void RemoveDependencies()
105 {
106 RemoveAxisLockConstraint();
107 }
108
109 private void RegisterForBeforeStepCallback()
110 {
111 if (!HaveRegisteredForBeforeStepCallback)
112 {
113 m_physicsScene.BeforeStep += PhysicsScene_BeforeStep;
114 HaveRegisteredForBeforeStepCallback = true;
115 }
116 }
117
118 private void UnRegisterForBeforeStepCallback()
119 {
120 if (HaveRegisteredForBeforeStepCallback)
121 {
122 m_physicsScene.BeforeStep -= PhysicsScene_BeforeStep;
123 HaveRegisteredForBeforeStepCallback = false;
124 }
125 }
126
127 private void PhysicsScene_BeforeStep(float timestep)
128 {
129 // If all the axis are free, we don't need to exist
130 if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree
131 && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree)
132 {
133 Enabled = false;
134 }
135
136 // If the object is physically active, add the axis locking constraint
137 if (isActive)
138 {
139 // Check to see if the locking parameters have changed
140 if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags
141 || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags)
142 {
143 // The locking has changed. Remove the old constraint and build a new one
144 RemoveAxisLockConstraint();
145 }
146
147 AddAxisLockConstraint();
148 }
149 else
150 {
151 RemoveAxisLockConstraint();
152 }
153 }
154
155 // Note that this relies on being called at TaintTime
156 private void AddAxisLockConstraint()
157 {
158 if (LockAxisConstraint == null)
159 {
160 // Lock that axis by creating a 6DOF constraint that has one end in the world and
161 // the other in the object.
162 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
163 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
164
165 // Remove any existing axis constraint (just to be sure)
166 RemoveAxisLockConstraint();
167
168 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
169 OMV.Vector3.Zero, OMV.Quaternion.Identity,
170 false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
171 LockAxisConstraint = axisConstrainer;
172 m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
173
174 // Remember the clocking being inforced so we can notice if they have changed
175 LockAxisLinearFlags = m_controllingPrim.LockedLinearAxis;
176 LockAxisAngularFlags = m_controllingPrim.LockedAngularAxis;
177
178 // The constraint is tied to the world and oriented to the prim.
179
180 if (!axisConstrainer.SetLinearLimits(m_controllingPrim.LockedLinearAxisLow, m_controllingPrim.LockedLinearAxisHigh))
181 {
182 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetLinearLimits",
183 m_controllingPrim.LocalID);
184 }
185
186 if (!axisConstrainer.SetAngularLimits(m_controllingPrim.LockedAngularAxisLow, m_controllingPrim.LockedAngularAxisHigh))
187 {
188 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits",
189 m_controllingPrim.LocalID);
190 }
191
192 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
193 m_controllingPrim.LocalID,
194 m_controllingPrim.LockedLinearAxisLow,
195 m_controllingPrim.LockedLinearAxisHigh,
196 m_controllingPrim.LockedAngularAxisLow,
197 m_controllingPrim.LockedAngularAxisHigh);
198
199 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
200 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
201
202 axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
203
204 RegisterForBeforeStepCallback();
205 }
206 }
207
208 private void RemoveAxisLockConstraint()
209 {
210 UnRegisterForBeforeStepCallback();
211 if (LockAxisConstraint != null)
212 {
213 m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
214 LockAxisConstraint = null;
215 m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID);
216 }
217 }
218}
219}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs
new file mode 100755
index 0000000..3db8f2c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs
@@ -0,0 +1,220 @@
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
33using OpenSim.Region.PhysicsModules.SharedBase;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
38{
39public class BSActorMoveToTarget : BSActor
40{
41 private BSVMotor m_targetMotor;
42
43 public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_targetMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 // MoveToTarget only works on physical prims
54 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
55 }
56
57 // Release any connections and resources used by the actor.
58 // BSActor.Dispose()
59 public override void Dispose()
60 {
61 Enabled = false;
62 DeactivateMoveToTarget();
63 }
64
65 // Called when physical parameters (properties set in Bullet) need to be re-applied.
66 // Called at taint-time.
67 // BSActor.Refresh()
68 public override void Refresh()
69 {
70 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}",
71 m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive,
72 m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau );
73
74 // If not active any more...
75 if (!m_controllingPrim.MoveToTargetActive)
76 {
77 Enabled = false;
78 }
79
80 if (isActive)
81 {
82 ActivateMoveToTarget();
83 }
84 else
85 {
86 DeactivateMoveToTarget();
87 }
88 }
89
90 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
91 // Register a prestep action to restore physical requirements before the next simulation step.
92 // Called at taint-time.
93 // BSActor.RemoveDependencies()
94 public override void RemoveDependencies()
95 {
96 // Nothing to do for the moveToTarget since it is all software at pre-step action time.
97 }
98
99 // If a hover motor has not been created, create one and start the hovering.
100 private void ActivateMoveToTarget()
101 {
102 if (m_targetMotor == null)
103 {
104 // We're taking over after this.
105 m_controllingPrim.ZeroMotion(true);
106
107 /* Someday use the PID controller
108 m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString());
109 m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau;
110 m_targetMotor.Efficiency = 1f;
111 */
112 m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(),
113 m_controllingPrim.MoveToTargetTau, // timeScale
114 BSMotor.Infinite, // decay time scale
115 1f // efficiency
116 );
117 m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
118 m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
119 m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
120
121 // m_physicsScene.BeforeStep += Mover;
122 m_physicsScene.BeforeStep += Mover2;
123 }
124 else
125 {
126 // If already allocated, make sure the target and other paramters are current
127 m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
128 m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
129 }
130 }
131
132 private void DeactivateMoveToTarget()
133 {
134 if (m_targetMotor != null)
135 {
136 // m_physicsScene.BeforeStep -= Mover;
137 m_physicsScene.BeforeStep -= Mover2;
138 m_targetMotor = null;
139 }
140 }
141
142 // Origional mover that set the objects position to move to the target.
143 // The problem was that gravity would keep trying to push the object down so
144 // the overall downward velocity would increase to infinity.
145 // Called just before the simulation step.
146 private void Mover(float timeStep)
147 {
148 // Don't do hovering while the object is selected.
149 if (!isActive)
150 return;
151
152 OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
153
154 // 'movePosition' is where we'd like the prim to be at this moment.
155 OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep);
156
157 // If we are very close to our target, turn off the movement motor.
158 if (m_targetMotor.ErrorIsZero())
159 {
160 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}",
161 m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
162 m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
163 m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
164 // Setting the position does not cause the physics engine to generate a property update. Force it.
165 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
166 }
167 else
168 {
169 m_controllingPrim.ForcePosition = movePosition;
170 // Setting the position does not cause the physics engine to generate a property update. Force it.
171 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
172 }
173 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}",
174 m_controllingPrim.LocalID, origPosition, movePosition);
175 }
176
177 // Version of mover that applies forces to move the physical object to the target.
178 // Also overcomes gravity so the object doesn't just drop to the ground.
179 // Called just before the simulation step.
180 private void Mover2(float timeStep)
181 {
182 // Don't do hovering while the object is selected.
183 if (!isActive)
184 return;
185
186 OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
187 OMV.Vector3 addedForce = OMV.Vector3.Zero;
188
189 // CorrectionVector is the movement vector required this step
190 OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition);
191
192 // If we are very close to our target, turn off the movement motor.
193 if (m_targetMotor.ErrorIsZero())
194 {
195 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}",
196 m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
197 m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
198 m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
199 // Setting the position does not cause the physics engine to generate a property update. Force it.
200 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
201 }
202 else
203 {
204 // First force to move us there -- the motor return a timestep scaled value.
205 addedForce = correctionVector / timeStep;
206 // Remove the existing velocity (only the moveToTarget force counts)
207 addedForce -= m_controllingPrim.RawVelocity;
208 // Overcome gravity.
209 addedForce -= m_controllingPrim.Gravity;
210
211 // Add enough force to overcome the mass of the object
212 addedForce *= m_controllingPrim.Mass;
213
214 m_controllingPrim.AddForce(addedForce, false /* pushForce */, true /* inTaintTime */);
215 }
216 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}",
217 m_controllingPrim.LocalID, origPosition, addedForce);
218 }
219}
220}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs
new file mode 100755
index 0000000..ecb4b7f
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs
@@ -0,0 +1,138 @@
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
33using OpenSim.Region.PhysicsModules.SharedBase;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
38{
39public class BSActorSetForce : BSActor
40{
41 BSFMotor m_forceMotor;
42
43 public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_forceMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 DeactivateSetForce();
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
70
71 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
72 if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
73 {
74 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
75 Enabled = false;
76 return;
77 }
78
79 // If the object is physically active, add the hoverer prestep action
80 if (isActive)
81 {
82 ActivateSetForce();
83 }
84 else
85 {
86 DeactivateSetForce();
87 }
88 }
89
90 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
91 // Register a prestep action to restore physical requirements before the next simulation step.
92 // Called at taint-time.
93 // BSActor.RemoveDependencies()
94 public override void RemoveDependencies()
95 {
96 // Nothing to do for the hoverer since it is all software at pre-step action time.
97 }
98
99 // If a hover motor has not been created, create one and start the hovering.
100 private void ActivateSetForce()
101 {
102 if (m_forceMotor == null)
103 {
104 // A fake motor that might be used someday
105 m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f);
106
107 m_physicsScene.BeforeStep += Mover;
108 }
109 }
110
111 private void DeactivateSetForce()
112 {
113 if (m_forceMotor != null)
114 {
115 m_physicsScene.BeforeStep -= Mover;
116 m_forceMotor = null;
117 }
118 }
119
120 // Called just before the simulation step. Update the vertical position for hoverness.
121 private void Mover(float timeStep)
122 {
123 // Don't do force while the object is selected.
124 if (!isActive)
125 return;
126
127 m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
128 if (m_controllingPrim.PhysBody.HasPhysicalBody)
129 {
130 m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
131 m_controllingPrim.ActivateIfPhysical(false);
132 }
133
134 // TODO:
135 }
136}
137}
138
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs
new file mode 100755
index 0000000..a1cf4db
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs
@@ -0,0 +1,139 @@
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
33using OpenSim.Region.PhysicsModules.SharedBase;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
38{
39public class BSActorSetTorque : BSActor
40{
41 BSFMotor m_torqueMotor;
42
43 public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_torqueMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 DeactivateSetTorque();
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
70
71 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
72 if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
73 {
74 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName);
75 Enabled = false;
76 return;
77 }
78
79 // If the object is physically active, add the hoverer prestep action
80 if (isActive)
81 {
82 ActivateSetTorque();
83 }
84 else
85 {
86 DeactivateSetTorque();
87 }
88 }
89
90 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
91 // Register a prestep action to restore physical requirements before the next simulation step.
92 // Called at taint-time.
93 // BSActor.RemoveDependencies()
94 public override void RemoveDependencies()
95 {
96 // Nothing to do for the hoverer since it is all software at pre-step action time.
97 }
98
99 // If a hover motor has not been created, create one and start the hovering.
100 private void ActivateSetTorque()
101 {
102 if (m_torqueMotor == null)
103 {
104 // A fake motor that might be used someday
105 m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f);
106
107 m_physicsScene.BeforeStep += Mover;
108 }
109 }
110
111 private void DeactivateSetTorque()
112 {
113 if (m_torqueMotor != null)
114 {
115 m_physicsScene.BeforeStep -= Mover;
116 m_torqueMotor = null;
117 }
118 }
119
120 // Called just before the simulation step. Update the vertical position for hoverness.
121 private void Mover(float timeStep)
122 {
123 // Don't do force while the object is selected.
124 if (!isActive)
125 return;
126
127 m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
128 if (m_controllingPrim.PhysBody.HasPhysicalBody)
129 {
130 m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
131 m_controllingPrim.ActivateIfPhysical(false);
132 }
133
134 // TODO:
135 }
136}
137}
138
139
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs
new file mode 100755
index 0000000..851347b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs
@@ -0,0 +1,154 @@
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
31namespace OpenSim.Region.PhysicsModule.BulletS
32{
33public class BSActorCollection
34{
35 private Dictionary<string, BSActor> m_actors;
36
37 public BSActorCollection()
38 {
39 m_actors = new Dictionary<string, BSActor>();
40 }
41 public void Add(string name, BSActor actor)
42 {
43 lock (m_actors)
44 {
45 if (!m_actors.ContainsKey(name))
46 {
47 m_actors[name] = actor;
48 }
49 }
50 }
51 public bool RemoveAndRelease(string name)
52 {
53 bool ret = false;
54 lock (m_actors)
55 {
56 if (m_actors.ContainsKey(name))
57 {
58 BSActor beingRemoved = m_actors[name];
59 m_actors.Remove(name);
60 beingRemoved.Dispose();
61 ret = true;
62 }
63 }
64 return ret;
65 }
66 public void Clear()
67 {
68 lock (m_actors)
69 {
70 ForEachActor(a => a.Dispose());
71 m_actors.Clear();
72 }
73 }
74 public void Dispose()
75 {
76 Clear();
77 }
78 public bool HasActor(string name)
79 {
80 return m_actors.ContainsKey(name);
81 }
82 public bool TryGetActor(string actorName, out BSActor theActor)
83 {
84 return m_actors.TryGetValue(actorName, out theActor);
85 }
86 public void ForEachActor(Action<BSActor> act)
87 {
88 lock (m_actors)
89 {
90 foreach (KeyValuePair<string, BSActor> kvp in m_actors)
91 act(kvp.Value);
92 }
93 }
94
95 public void Enable(bool enabl)
96 {
97 ForEachActor(a => a.SetEnabled(enabl));
98 }
99 public void Refresh()
100 {
101 ForEachActor(a => a.Refresh());
102 }
103 public void RemoveDependencies()
104 {
105 ForEachActor(a => a.RemoveDependencies());
106 }
107}
108
109// =============================================================================
110/// <summary>
111/// Each physical object can have 'actors' who are pushing the object around.
112/// This can be used for hover, locking axis, making vehicles, etc.
113/// Each physical object can have multiple actors acting on it.
114///
115/// An actor usually registers itself with physics scene events (pre-step action)
116/// and modifies the parameters on the host physical object.
117/// </summary>
118public abstract class BSActor
119{
120 protected BSScene m_physicsScene { get; private set; }
121 protected BSPhysObject m_controllingPrim { get; private set; }
122 public virtual bool Enabled { get; set; }
123 public string ActorName { get; private set; }
124
125 public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
126 {
127 m_physicsScene = physicsScene;
128 m_controllingPrim = pObj;
129 ActorName = actorName;
130 Enabled = true;
131 }
132
133 // Return 'true' if activily updating the prim
134 public virtual bool isActive
135 {
136 get { return Enabled; }
137 }
138
139 // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled.
140 // Anyone else should assign true/false to 'Enabled'.
141 public void SetEnabled(bool setEnabled)
142 {
143 Enabled = setEnabled;
144 }
145 // Release any connections and resources used by the actor.
146 public abstract void Dispose();
147 // Called when physical parameters (properties set in Bullet) need to be re-applied.
148 public abstract void Refresh();
149 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
150 // Register a prestep action to restore physical requirements before the next simulation step.
151 public abstract void RemoveDependencies();
152
153}
154}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
new file mode 100644
index 0000000..7756b10
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
@@ -0,0 +1,763 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Runtime.InteropServices;
30using System.Security;
31using System.Text;
32using OpenMetaverse;
33
34namespace OpenSim.Region.PhysicsModule.BulletS {
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 GEAR_CONSTRAINT_TYPE, // added in Bullet 2.82
47 FIXED_CONSTRAINT_TYPE, // added in Bullet 2.82
48 MAX_CONSTRAINT_TYPE, // last type defined by Bullet
49 //
50 BS_FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving
51}
52
53// ===============================================================================
54[StructLayout(LayoutKind.Sequential)]
55public struct ConvexHull
56{
57 Vector3 Offset;
58 int VertexCount;
59 Vector3[] Vertices;
60}
61public enum BSPhysicsShapeType
62{
63 SHAPE_UNKNOWN = 0,
64 SHAPE_CAPSULE = 1,
65 SHAPE_BOX = 2,
66 SHAPE_CONE = 3,
67 SHAPE_CYLINDER = 4,
68 SHAPE_SPHERE = 5,
69 SHAPE_MESH = 6,
70 SHAPE_HULL = 7,
71 // following defined by BulletSim
72 SHAPE_GROUNDPLANE = 20,
73 SHAPE_TERRAIN = 21,
74 SHAPE_COMPOUND = 22,
75 SHAPE_HEIGHTMAP = 23,
76 SHAPE_AVATAR = 24,
77 SHAPE_CONVEXHULL= 25,
78 SHAPE_GIMPACT = 26,
79};
80
81// The native shapes have predefined shape hash keys
82public enum FixedShapeKey : ulong
83{
84 KEY_NONE = 0,
85 KEY_BOX = 1,
86 KEY_SPHERE = 2,
87 KEY_CONE = 3,
88 KEY_CYLINDER = 4,
89 KEY_CAPSULE = 5,
90 KEY_AVATAR = 6,
91}
92
93[StructLayout(LayoutKind.Sequential)]
94public struct ShapeData
95{
96 public UInt32 ID;
97 public BSPhysicsShapeType Type;
98 public Vector3 Position;
99 public Quaternion Rotation;
100 public Vector3 Velocity;
101 public Vector3 Scale;
102 public float Mass;
103 public float Buoyancy;
104 public System.UInt64 HullKey;
105 public System.UInt64 MeshKey;
106 public float Friction;
107 public float Restitution;
108 public float Collidable; // true of things bump into this
109 public float Static; // true if a static object. Otherwise gravity, etc.
110 public float Solid; // true if object cannot be passed through
111 public Vector3 Size;
112
113 // note that bools are passed as floats since bool size changes by language and architecture
114 public const float numericTrue = 1f;
115 public const float numericFalse = 0f;
116}
117[StructLayout(LayoutKind.Sequential)]
118public struct SweepHit
119{
120 public UInt32 ID;
121 public float Fraction;
122 public Vector3 Normal;
123 public Vector3 Point;
124}
125[StructLayout(LayoutKind.Sequential)]
126public struct RaycastHit
127{
128 public UInt32 ID;
129 public float Fraction;
130 public Vector3 Normal;
131}
132[StructLayout(LayoutKind.Sequential)]
133public struct CollisionDesc
134{
135 public UInt32 aID;
136 public UInt32 bID;
137 public Vector3 point;
138 public Vector3 normal;
139 public float penetration;
140}
141[StructLayout(LayoutKind.Sequential)]
142public struct EntityProperties
143{
144 public UInt32 ID;
145 public Vector3 Position;
146 public Quaternion Rotation;
147 public Vector3 Velocity;
148 public Vector3 Acceleration;
149 public Vector3 RotationalVelocity;
150
151 public override string ToString()
152 {
153 StringBuilder buff = new StringBuilder();
154 buff.Append("<i=");
155 buff.Append(ID.ToString());
156 buff.Append(",p=");
157 buff.Append(Position.ToString());
158 buff.Append(",r=");
159 buff.Append(Rotation.ToString());
160 buff.Append(",v=");
161 buff.Append(Velocity.ToString());
162 buff.Append(",a=");
163 buff.Append(Acceleration.ToString());
164 buff.Append(",rv=");
165 buff.Append(RotationalVelocity.ToString());
166 buff.Append(">");
167 return buff.ToString();
168 }
169}
170
171// Format of this structure must match the definition in the C++ code
172// NOTE: adding the X causes compile breaks if used. These are unused symbols
173// that can be removed from both here and the unmanaged definition of this structure.
174[StructLayout(LayoutKind.Sequential)]
175public struct ConfigurationParameters
176{
177 public float defaultFriction;
178 public float defaultDensity;
179 public float defaultRestitution;
180 public float collisionMargin;
181 public float gravity;
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 public float useSingleSidedMeshes;
192 public float globalContactBreakingThreshold;
193
194 public float physicsLoggingFrames;
195
196 public const float numericTrue = 1f;
197 public const float numericFalse = 0f;
198}
199
200// Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library.
201[StructLayout(LayoutKind.Sequential)]
202public struct HACDParams
203{
204 // usual default values
205 public float maxVerticesPerHull; // 100
206 public float minClusters; // 2
207 public float compacityWeight; // 0.1
208 public float volumeWeight; // 0.0
209 public float concavity; // 100
210 public float addExtraDistPoints; // false
211 public float addNeighboursDistPoints; // false
212 public float addFacesPoints; // false
213 public float shouldAdjustCollisionMargin; // false
214 // VHACD
215 public float whichHACD; // zero if Bullet HACD, non-zero says VHACD
216 // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html
217 public float vHACDresolution; // 100,000 max number of voxels generated during voxelization stage
218 public float vHACDdepth; // 20 max number of clipping stages
219 public float vHACDconcavity; // 0.0025 maximum concavity
220 public float vHACDplaneDownsampling; // 4 granularity of search for best clipping plane
221 public float vHACDconvexHullDownsampling; // 4 precision of hull gen process
222 public float vHACDalpha; // 0.05 bias toward clipping along symmetry planes
223 public float vHACDbeta; // 0.05 bias toward clipping along revolution axis
224 public float vHACDgamma; // 0.00125 max concavity when merging
225 public float vHACDpca; // 0 on/off normalizing mesh before decomp
226 public float vHACDmode; // 0 0:voxel based, 1: tetrahedron based
227 public float vHACDmaxNumVerticesPerCH; // 64 max triangles per convex hull
228 public float vHACDminVolumePerCH; // 0.0001 sampling of generated convex hulls
229}
230
231// The states a bullet collision object can have
232public enum ActivationState : uint
233{
234 ACTIVE_TAG = 1,
235 ISLAND_SLEEPING,
236 WANTS_DEACTIVATION,
237 DISABLE_DEACTIVATION,
238 DISABLE_SIMULATION,
239}
240
241public enum CollisionObjectTypes : int
242{
243 CO_COLLISION_OBJECT = 1 << 0,
244 CO_RIGID_BODY = 1 << 1,
245 CO_GHOST_OBJECT = 1 << 2,
246 CO_SOFT_BODY = 1 << 3,
247 CO_HF_FLUID = 1 << 4,
248 CO_USER_TYPE = 1 << 5,
249}
250
251// Values used by Bullet and BulletSim to control object properties.
252// Bullet's "CollisionFlags" has more to do with operations on the
253// object (if collisions happen, if gravity effects it, ...).
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, // return collision events from unmanaged to managed
265 BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
266 BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
267 BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
268 BS_NONE = 0,
269 BS_ALL = 0x7FFF // collision flags are a signed short
270};
271
272// Values f collisions groups and masks
273public enum CollisionFilterGroups : uint
274{
275 // Don't use the bit definitions!! Define the use in a
276 // filter/mask definition below. This way collision interactions
277 // are more easily found and debugged.
278 BNoneGroup = 0,
279 BDefaultGroup = 1 << 0, // 0001
280 BStaticGroup = 1 << 1, // 0002
281 BKinematicGroup = 1 << 2, // 0004
282 BDebrisGroup = 1 << 3, // 0008
283 BSensorTrigger = 1 << 4, // 0010
284 BCharacterGroup = 1 << 5, // 0020
285 BAllGroup = 0x0007FFF, // collision flags are a signed short
286 // Filter groups defined by BulletSim
287 BGroundPlaneGroup = 1 << 8, // 0400
288 BTerrainGroup = 1 << 9, // 0800
289 BRaycastGroup = 1 << 10, // 1000
290 BSolidGroup = 1 << 11, // 2000
291 // BLinksetGroup = xx // a linkset proper is either static or dynamic
292 BLinksetChildGroup = 1 << 12, // 4000
293};
294
295// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
296// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
297public enum ConstraintParams : int
298{
299 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
300 BT_CONSTRAINT_STOP_ERP,
301 BT_CONSTRAINT_CFM,
302 BT_CONSTRAINT_STOP_CFM,
303};
304public enum ConstraintParamAxis : int
305{
306 AXIS_LINEAR_X = 0,
307 AXIS_LINEAR_Y,
308 AXIS_LINEAR_Z,
309 AXIS_ANGULAR_X,
310 AXIS_ANGULAR_Y,
311 AXIS_ANGULAR_Z,
312 AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls
313 AXIS_ANGULAR_ALL,
314 AXIS_ALL
315};
316
317public abstract class BSAPITemplate
318{
319// Returns the name of the underlying Bullet engine
320public abstract string BulletEngineName { get; }
321public abstract string BulletEngineVersion { get; protected set;}
322
323// Initialization and simulation
324public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
325 int maxCollisions, ref CollisionDesc[] collisionArray,
326 int maxUpdates, ref EntityProperties[] updateArray
327 );
328
329public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
330 out int updatedEntityCount, out int collidersCount);
331
332public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value);
333
334public abstract void Shutdown(BulletWorld sim);
335
336public abstract bool PushUpdate(BulletBody obj);
337
338// =====================================================================================
339// Mesh, hull, shape and body creation helper routines
340public abstract BulletShape CreateMeshShape(BulletWorld world,
341 int indicesCount, int[] indices,
342 int verticesCount, float[] vertices );
343
344public abstract BulletShape CreateGImpactShape(BulletWorld world,
345 int indicesCount, int[] indices,
346 int verticesCount, float[] vertices );
347
348public abstract BulletShape CreateHullShape(BulletWorld world,
349 int hullCount, float[] hulls);
350
351public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms);
352
353public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
354
355public abstract BulletShape CreateConvexHullShape(BulletWorld world,
356 int indicesCount, int[] indices,
357 int verticesCount, float[] vertices );
358
359public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
360
361public abstract bool IsNativeShape(BulletShape shape);
362
363public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
364
365public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale);
366
367public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree);
368
369public abstract int GetNumberOfCompoundChildren(BulletShape cShape);
370
371public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot);
372
373public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
374
375public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
376
377public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
378
379public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
380
381public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
382
383public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id);
384
385public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
386
387public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
388
389public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
390
391public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
392
393public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
394
395public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
396
397// =====================================================================================
398public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
399
400public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
401 float scaleFactor, float collisionMargin);
402
403// =====================================================================================
404// Constraint creation and helper routines
405public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
406 Vector3 frame1loc, Quaternion frame1rot,
407 Vector3 frame2loc, Quaternion frame2rot,
408 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
409
410public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
411 Vector3 joinPoint,
412 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
413
414public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
415 Vector3 frameInBloc, Quaternion frameInBrot,
416 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
417
418public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
419 Vector3 frame1loc, Quaternion frame1rot,
420 Vector3 frame2loc, Quaternion frame2rot,
421 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
422
423public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
424 Vector3 pivotinA, Vector3 pivotinB,
425 Vector3 axisInA, Vector3 axisInB,
426 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
427
428public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
429 Vector3 frameInAloc, Quaternion frameInArot,
430 Vector3 frameInBloc, Quaternion frameInBrot,
431 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
432
433public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
434 Vector3 frameInAloc, Quaternion frameInArot,
435 Vector3 frameInBloc, Quaternion frameInBrot,
436 bool disableCollisionsBetweenLinkedBodies);
437
438public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
439 Vector3 axisInA, Vector3 axisInB,
440 float ratio, bool disableCollisionsBetweenLinkedBodies);
441
442public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
443 Vector3 pivotInA, Vector3 pivotInB,
444 bool disableCollisionsBetweenLinkedBodies);
445
446public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
447
448public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
449
450public abstract bool SetFrames(BulletConstraint constrain,
451 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
452
453public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
454
455public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
456
457public abstract bool UseFrameOffset(BulletConstraint constrain, float enable);
458
459public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce);
460
461public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
462
463public const int HINGE_NOT_SPECIFIED = -1;
464public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation);
465
466public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse);
467
468public const int SPRING_NOT_SPECIFIED = -1;
469public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint);
470
471public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss);
472
473public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping);
474
475public const int SLIDER_LOWER_LIMIT = 0;
476public const int SLIDER_UPPER_LIMIT = 1;
477public const int SLIDER_LINEAR = 2;
478public const int SLIDER_ANGULAR = 3;
479public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val);
480
481public const int SLIDER_SET_SOFTNESS = 4;
482public const int SLIDER_SET_RESTITUTION = 5;
483public const int SLIDER_SET_DAMPING = 6;
484public const int SLIDER_SET_DIRECTION = 7;
485public const int SLIDER_SET_LIMIT = 8;
486public const int SLIDER_SET_ORTHO = 9;
487public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
488
489public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse);
490
491public const int SLIDER_MOTOR_VELOCITY = 10;
492public const int SLIDER_MAX_MOTOR_FORCE = 11;
493public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val);
494
495public abstract bool CalculateTransforms(BulletConstraint constrain);
496
497public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
498
499public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain);
500
501// =====================================================================================
502// btCollisionWorld entries
503public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj);
504
505public abstract void UpdateAabbs(BulletWorld world);
506
507public abstract bool GetForceUpdateAllAabbs(BulletWorld world);
508
509public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force);
510
511// =====================================================================================
512// btDynamicsWorld entries
513// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot);
514public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
515
516public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
517
518public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj);
519
520public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
521
522public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
523// =====================================================================================
524// btCollisionObject entries
525public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain);
526
527public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict);
528
529public abstract bool HasAnisotripicFriction(BulletConstraint constrain);
530
531public abstract void SetContactProcessingThreshold(BulletBody obj, float val);
532
533public abstract float GetContactProcessingThreshold(BulletBody obj);
534
535public abstract bool IsStaticObject(BulletBody obj);
536
537public abstract bool IsKinematicObject(BulletBody obj);
538
539public abstract bool IsStaticOrKinematicObject(BulletBody obj);
540
541public abstract bool HasContactResponse(BulletBody obj);
542
543public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
544
545public abstract BulletShape GetCollisionShape(BulletBody obj);
546
547public abstract int GetActivationState(BulletBody obj);
548
549public abstract void SetActivationState(BulletBody obj, int state);
550
551public abstract void SetDeactivationTime(BulletBody obj, float dtime);
552
553public abstract float GetDeactivationTime(BulletBody obj);
554
555public abstract void ForceActivationState(BulletBody obj, ActivationState state);
556
557public abstract void Activate(BulletBody obj, bool forceActivation);
558
559public abstract bool IsActive(BulletBody obj);
560
561public abstract void SetRestitution(BulletBody obj, float val);
562
563public abstract float GetRestitution(BulletBody obj);
564
565public abstract void SetFriction(BulletBody obj, float val);
566
567public abstract float GetFriction(BulletBody obj);
568
569public abstract Vector3 GetPosition(BulletBody obj);
570
571public abstract Quaternion GetOrientation(BulletBody obj);
572
573public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation);
574
575// public abstract IntPtr GetBroadphaseHandle(BulletBody obj);
576
577// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle);
578
579public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel);
580
581public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel);
582
583public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel);
584
585public abstract float GetHitFraction(BulletBody obj);
586
587public abstract void SetHitFraction(BulletBody obj, float val);
588
589public abstract CollisionFlags GetCollisionFlags(BulletBody obj);
590
591public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags);
592
593public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags);
594
595public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags);
596
597public abstract float GetCcdMotionThreshold(BulletBody obj);
598
599public abstract void SetCcdMotionThreshold(BulletBody obj, float val);
600
601public abstract float GetCcdSweptSphereRadius(BulletBody obj);
602
603public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val);
604
605public abstract IntPtr GetUserPointer(BulletBody obj);
606
607public abstract void SetUserPointer(BulletBody obj, IntPtr val);
608
609// =====================================================================================
610// btRigidBody entries
611public abstract void ApplyGravity(BulletBody obj);
612
613public abstract void SetGravity(BulletBody obj, Vector3 val);
614
615public abstract Vector3 GetGravity(BulletBody obj);
616
617public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping);
618
619public abstract void SetLinearDamping(BulletBody obj, float lin_damping);
620
621public abstract void SetAngularDamping(BulletBody obj, float ang_damping);
622
623public abstract float GetLinearDamping(BulletBody obj);
624
625public abstract float GetAngularDamping(BulletBody obj);
626
627public abstract float GetLinearSleepingThreshold(BulletBody obj);
628
629public abstract void ApplyDamping(BulletBody obj, float timeStep);
630
631public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia);
632
633public abstract Vector3 GetLinearFactor(BulletBody obj);
634
635public abstract void SetLinearFactor(BulletBody obj, Vector3 factor);
636
637public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot);
638
639// Add a force to the object as if its mass is one.
640public abstract void ApplyCentralForce(BulletBody obj, Vector3 force);
641
642// Set the force being applied to the object as if its mass is one.
643public abstract void SetObjectForce(BulletBody obj, Vector3 force);
644
645public abstract Vector3 GetTotalForce(BulletBody obj);
646
647public abstract Vector3 GetTotalTorque(BulletBody obj);
648
649public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj);
650
651public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert);
652
653public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold);
654
655public abstract void ApplyTorque(BulletBody obj, Vector3 torque);
656
657// Apply force at the given point. Will add torque to the object.
658public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos);
659
660// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
661public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp);
662
663// Apply impulse to the object's torque. Force is scaled by object's mass.
664public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp);
665
666// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
667public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos);
668
669public abstract void ClearForces(BulletBody obj);
670
671public abstract void ClearAllForces(BulletBody obj);
672
673public abstract void UpdateInertiaTensor(BulletBody obj);
674
675public abstract Vector3 GetLinearVelocity(BulletBody obj);
676
677public abstract Vector3 GetAngularVelocity(BulletBody obj);
678
679public abstract void SetLinearVelocity(BulletBody obj, Vector3 val);
680
681public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity);
682
683public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos);
684
685public abstract void Translate(BulletBody obj, Vector3 trans);
686
687public abstract void UpdateDeactivation(BulletBody obj, float timeStep);
688
689public abstract bool WantsSleeping(BulletBody obj);
690
691public abstract void SetAngularFactor(BulletBody obj, float factor);
692
693public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor);
694
695public abstract Vector3 GetAngularFactor(BulletBody obj);
696
697public abstract bool IsInWorld(BulletWorld world, BulletBody obj);
698
699public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain);
700
701public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain);
702
703public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
704
705public abstract int GetNumConstraintRefs(BulletBody obj);
706
707public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask);
708
709// =====================================================================================
710// btCollisionShape entries
711
712public abstract float GetAngularMotionDisc(BulletShape shape);
713
714public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor);
715
716public abstract bool IsPolyhedral(BulletShape shape);
717
718public abstract bool IsConvex2d(BulletShape shape);
719
720public abstract bool IsConvex(BulletShape shape);
721
722public abstract bool IsNonMoving(BulletShape shape);
723
724public abstract bool IsConcave(BulletShape shape);
725
726public abstract bool IsCompound(BulletShape shape);
727
728public abstract bool IsSoftBody(BulletShape shape);
729
730public abstract bool IsInfinite(BulletShape shape);
731
732public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
733
734public abstract Vector3 GetLocalScaling(BulletShape shape);
735
736public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass);
737
738public abstract int GetShapeType(BulletShape shape);
739
740public abstract void SetMargin(BulletShape shape, float val);
741
742public abstract float GetMargin(BulletShape shape);
743
744// =====================================================================================
745// Debugging
746public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
747
748public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
749
750public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
751
752public virtual void DumpActivationInfo(BulletWorld sim) { }
753
754public virtual void DumpAllInfo(BulletWorld sim) { }
755
756public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
757
758public virtual void ResetBroadphasePool(BulletWorld sim) { }
759
760public virtual void ResetConstraintSolver(BulletWorld sim) { }
761
762};
763}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
new file mode 100644
index 0000000..83fc3a6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
@@ -0,0 +1,813 @@
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.PhysicsModules.SharedBase;
34
35namespace OpenSim.Region.PhysicsModule.BulletS
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 float _mass;
47 private float _avatarVolume;
48 private float _collisionScore;
49 private OMV.Vector3 _acceleration;
50 private int _physicsActorType;
51 private bool _isPhysical;
52 private bool _flying;
53 private bool _setAlwaysRun;
54 private bool _throttleUpdates;
55 private bool _floatOnWater;
56 private OMV.Vector3 _rotationalVelocity;
57 private bool _kinematic;
58 private float _buoyancy;
59
60 private BSActorAvatarMove m_moveActor;
61 private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
62
63 private OMV.Vector3 _PIDTarget;
64 private float _PIDTau;
65
66// public override OMV.Vector3 RawVelocity
67// { get { return base.RawVelocity; }
68// set {
69// if (value != base.RawVelocity)
70// Util.PrintCallStack();
71// Console.WriteLine("Set rawvel to {0}", value);
72// base.RawVelocity = value; }
73// }
74
75 // Avatars are always complete (in the physics engine sense)
76 public override bool IsIncomplete { get { return false; } }
77
78 public BSCharacter(
79 uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying)
80
81 : base(parent_scene, localID, avName, "BSCharacter")
82 {
83 _physicsActorType = (int)ActorTypes.Agent;
84 RawPosition = pos;
85
86 _flying = isFlying;
87 RawOrientation = OMV.Quaternion.Identity;
88 RawVelocity = vel;
89 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
90 Friction = BSParam.AvatarStandingFriction;
91 Density = BSParam.AvatarDensity;
92
93 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
94 // replace with the default values.
95 _size = size;
96 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
97 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
98
99 // The dimensions of the physical capsule are kept in the scale.
100 // Physics creates a unit capsule which is scaled by the physics engine.
101 Scale = ComputeAvatarScale(_size);
102 // set _avatarVolume and _mass based on capsule size, _density and Scale
103 ComputeAvatarVolumeAndMass();
104
105 DetailLog(
106 "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}",
107 LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel);
108
109 // do actual creation in taint time
110 PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
111 {
112 DetailLog("{0},BSCharacter.create,taint", LocalID);
113
114 // New body and shape into PhysBody and PhysShape
115 PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
116
117 // The avatar's movement is controlled by this motor that speeds up and slows down
118 // the avatar seeking to reach the motor's target speed.
119 // This motor runs as a prestep action for the avatar so it will keep the avatar
120 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
121 m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
122 PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
123
124 SetPhysicalProperties();
125
126 IsInitialized = true;
127 });
128 return;
129 }
130
131 // called when this character is being destroyed and the resources should be released
132 public override void Destroy()
133 {
134 IsInitialized = false;
135
136 base.Destroy();
137
138 DetailLog("{0},BSCharacter.Destroy", LocalID);
139 PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
140 {
141 PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
142 PhysBody.Clear();
143 PhysShape.Dereference(PhysScene);
144 PhysShape = new BSShapeNull();
145 });
146 }
147
148 private void SetPhysicalProperties()
149 {
150 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
151
152 ForcePosition = RawPosition;
153
154 // Set the velocity
155 if (m_moveActor != null)
156 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
157
158 ForceVelocity = RawVelocity;
159 TargetVelocity = RawVelocity;
160
161 // This will enable or disable the flying buoyancy of the avatar.
162 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
163 Flying = _flying;
164
165 PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
166 PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
167 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
168 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
169 if (BSParam.CcdMotionThreshold > 0f)
170 {
171 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
172 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
173 }
174
175 UpdatePhysicalMassProperties(RawMass, false);
176
177 // Make so capsule does not fall over
178 PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
179
180 // The avatar mover sets some parameters.
181 PhysicalActors.Refresh();
182
183 PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
184
185 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
186
187 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
188 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
189 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
190
191 // Do this after the object has been added to the world
192 if (BSParam.AvatarToAvatarCollisionsByDefault)
193 PhysBody.collisionType = CollisionType.Avatar;
194 else
195 PhysBody.collisionType = CollisionType.PhantomToOthersAvatar;
196
197 PhysBody.ApplyCollisionMask(PhysScene);
198 }
199
200 public override void RequestPhysicsterseUpdate()
201 {
202 base.RequestPhysicsterseUpdate();
203 }
204
205 // No one calls this method so I don't know what it could possibly mean
206 public override bool Stopped { get { return false; } }
207
208 public override OMV.Vector3 Size {
209 get
210 {
211 // Avatar capsule size is kept in the scale parameter.
212 return _size;
213 }
214
215 set {
216 // This is how much the avatar size is changing. Positive means getting bigger.
217 // The avatar altitude must be adjusted for this change.
218 float heightChange = value.Z - _size.Z;
219
220 _size = value;
221 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
222 // replace with the default values.
223 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
224 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
225
226 Scale = ComputeAvatarScale(_size);
227 ComputeAvatarVolumeAndMass();
228 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
229 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
230
231 PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
232 {
233 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
234 {
235 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
236 UpdatePhysicalMassProperties(RawMass, true);
237
238 // Adjust the avatar's position to account for the increase/decrease in size
239 ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f);
240
241 // Make sure this change appears as a property update event
242 PhysScene.PE.PushUpdate(PhysBody);
243 }
244 });
245
246 }
247 }
248
249 public override PrimitiveBaseShape Shape
250 {
251 set { BaseShape = value; }
252 }
253
254 public override bool Grabbed {
255 set { _grabbed = value; }
256 }
257 public override bool Selected {
258 set { _selected = value; }
259 }
260 public override bool IsSelected
261 {
262 get { return _selected; }
263 }
264 public override void CrossingFailure() { return; }
265 public override void link(PhysicsActor obj) { return; }
266 public override void delink() { return; }
267
268 // Set motion values to zero.
269 // Do it to the properties so the values get set in the physics engine.
270 // Push the setting of the values to the viewer.
271 // Called at taint time!
272 public override void ZeroMotion(bool inTaintTime)
273 {
274 RawVelocity = OMV.Vector3.Zero;
275 _acceleration = OMV.Vector3.Zero;
276 _rotationalVelocity = OMV.Vector3.Zero;
277
278 // Zero some other properties directly into the physics engine
279 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
280 {
281 if (PhysBody.HasPhysicalBody)
282 PhysScene.PE.ClearAllForces(PhysBody);
283 });
284 }
285
286 public override void ZeroAngularMotion(bool inTaintTime)
287 {
288 _rotationalVelocity = OMV.Vector3.Zero;
289
290 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
291 {
292 if (PhysBody.HasPhysicalBody)
293 {
294 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
295 PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
296 // The next also get rid of applied linear force but the linear velocity is untouched.
297 PhysScene.PE.ClearForces(PhysBody);
298 }
299 });
300 }
301
302
303 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
304
305 public override OMV.Vector3 Position {
306 get {
307 // Don't refetch the position because this function is called a zillion times
308 // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
309 return RawPosition;
310 }
311 set {
312 RawPosition = value;
313
314 PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
315 {
316 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
317 PositionSanityCheck();
318 ForcePosition = RawPosition;
319 });
320 }
321 }
322 public override OMV.Vector3 ForcePosition {
323 get {
324 RawPosition = PhysScene.PE.GetPosition(PhysBody);
325 return RawPosition;
326 }
327 set {
328 RawPosition = value;
329 if (PhysBody.HasPhysicalBody)
330 {
331 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
332 }
333 }
334 }
335
336
337 // Check that the current position is sane and, if not, modify the position to make it so.
338 // Check for being below terrain or on water.
339 // Returns 'true' of the position was made sane by some action.
340 private bool PositionSanityCheck()
341 {
342 bool ret = false;
343
344 // TODO: check for out of bounds
345 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
346 {
347 // The character is out of the known/simulated area.
348 // Force the avatar position to be within known. ScenePresence will use the position
349 // plus the velocity to decide if the avatar is moving out of the region.
350 RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
351 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
352 return true;
353 }
354
355 // If below the ground, move the avatar up
356 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
357 if (Position.Z < terrainHeight)
358 {
359 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
360 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters);
361 ret = true;
362 }
363 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
364 {
365 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
366 if (Position.Z < waterHeight)
367 {
368 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight);
369 ret = true;
370 }
371 }
372
373 return ret;
374 }
375
376 // A version of the sanity check that also makes sure a new position value is
377 // pushed back to the physics engine. This routine would be used by anyone
378 // who is not already pushing the value.
379 private bool PositionSanityCheck(bool inTaintTime)
380 {
381 bool ret = false;
382 if (PositionSanityCheck())
383 {
384 // The new position value must be pushed into the physics engine but we can't
385 // just assign to "Position" because of potential call loops.
386 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
387 {
388 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
389 ForcePosition = RawPosition;
390 });
391 ret = true;
392 }
393 return ret;
394 }
395
396 public override float Mass { get { return _mass; } }
397
398 // used when we only want this prim's mass and not the linkset thing
399 public override float RawMass {
400 get {return _mass; }
401 }
402 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
403 {
404 OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
405 PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
406 }
407
408 public override OMV.Vector3 Force {
409 get { return RawForce; }
410 set {
411 RawForce = value;
412 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
413 PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
414 {
415 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
416 if (PhysBody.HasPhysicalBody)
417 PhysScene.PE.SetObjectForce(PhysBody, RawForce);
418 });
419 }
420 }
421
422 // Avatars don't do vehicles
423 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
424 public override void VehicleFloatParam(int param, float value) { }
425 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
426 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
427 public override void VehicleFlags(int param, bool remove) { }
428
429 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
430 public override void SetVolumeDetect(int param) { return; }
431 public override bool IsVolumeDetect { get { return false; } }
432
433 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
434 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
435
436 // Sets the target in the motor. This starts the changing of the avatar's velocity.
437 public override OMV.Vector3 TargetVelocity
438 {
439 get
440 {
441 return base.m_targetVelocity;
442 }
443 set
444 {
445 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
446 m_targetVelocity = value;
447 OMV.Vector3 targetVel = value;
448 if (_setAlwaysRun && !_flying)
449 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f);
450
451 if (m_moveActor != null)
452 m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
453 }
454 }
455 // Directly setting velocity means this is what the user really wants now.
456 public override OMV.Vector3 Velocity {
457 get { return RawVelocity; }
458 set {
459 RawVelocity = value;
460 OMV.Vector3 vel = RawVelocity;
461
462 DetailLog("{0}: set Velocity = {1}", LocalID, value);
463
464 PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
465 {
466 if (m_moveActor != null)
467 m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */);
468
469 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel);
470 ForceVelocity = vel;
471 });
472 }
473 }
474
475 public override OMV.Vector3 ForceVelocity {
476 get { return RawVelocity; }
477 set {
478 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
479// Util.PrintCallStack();
480 DetailLog("{0}: set ForceVelocity = {1}", LocalID, value);
481
482 RawVelocity = value;
483 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
484 PhysScene.PE.Activate(PhysBody, true);
485 }
486 }
487
488 public override OMV.Vector3 Torque {
489 get { return RawTorque; }
490 set { RawTorque = value;
491 }
492 }
493
494 public override float CollisionScore {
495 get { return _collisionScore; }
496 set { _collisionScore = value;
497 }
498 }
499 public override OMV.Vector3 Acceleration {
500 get { return _acceleration; }
501 set { _acceleration = value; }
502 }
503 public override OMV.Quaternion Orientation {
504 get { return RawOrientation; }
505 set {
506 // Orientation is set zillions of times when an avatar is walking. It's like
507 // the viewer doesn't trust us.
508 if (RawOrientation != value)
509 {
510 RawOrientation = value;
511 PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
512 {
513 // Bullet assumes we know what we are doing when forcing orientation
514 // so it lets us go against all the rules and just compensates for them later.
515 // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
516 // This keeps us from flipping the capsule over which the veiwer does not understand.
517 float oRoll, oPitch, oYaw;
518 RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
519 OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
520 // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
521 // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation,
522 // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
523 ForceOrientation = trimmedOrientation;
524 });
525 }
526 }
527 }
528 // Go directly to Bullet to get/set the value.
529 public override OMV.Quaternion ForceOrientation
530 {
531 get
532 {
533 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
534 return RawOrientation;
535 }
536 set
537 {
538 RawOrientation = value;
539 if (PhysBody.HasPhysicalBody)
540 {
541 // RawPosition = PhysicsScene.PE.GetPosition(BSBody);
542 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
543 }
544 }
545 }
546 public override int PhysicsActorType {
547 get { return _physicsActorType; }
548 set { _physicsActorType = value;
549 }
550 }
551 public override bool IsPhysical {
552 get { return _isPhysical; }
553 set { _isPhysical = value;
554 }
555 }
556 public override bool IsSolid {
557 get { return true; }
558 }
559 public override bool IsStatic {
560 get { return false; }
561 }
562 public override bool IsPhysicallyActive {
563 get { return true; }
564 }
565 public override bool Flying {
566 get { return _flying; }
567 set {
568 _flying = value;
569
570 // simulate flying by changing the effect of gravity
571 Buoyancy = ComputeBuoyancyFromFlying(_flying);
572 }
573 }
574 // Flying is implimented by changing the avatar's buoyancy.
575 // Would this be done better with a vehicle type?
576 private float ComputeBuoyancyFromFlying(bool ifFlying) {
577 return ifFlying ? 1f : 0f;
578 }
579 public override bool
580 SetAlwaysRun {
581 get { return _setAlwaysRun; }
582 set { _setAlwaysRun = value; }
583 }
584 public override bool ThrottleUpdates {
585 get { return _throttleUpdates; }
586 set { _throttleUpdates = value; }
587 }
588 public override bool FloatOnWater {
589 set {
590 _floatOnWater = value;
591 PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
592 {
593 if (PhysBody.HasPhysicalBody)
594 {
595 if (_floatOnWater)
596 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
597 else
598 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
599 }
600 });
601 }
602 }
603 public override OMV.Vector3 RotationalVelocity {
604 get { return _rotationalVelocity; }
605 set { _rotationalVelocity = value; }
606 }
607 public override OMV.Vector3 ForceRotationalVelocity {
608 get { return _rotationalVelocity; }
609 set { _rotationalVelocity = value; }
610 }
611 public override bool Kinematic {
612 get { return _kinematic; }
613 set { _kinematic = value; }
614 }
615 // neg=fall quickly, 0=1g, 1=0g, pos=float up
616 public override float Buoyancy {
617 get { return _buoyancy; }
618 set { _buoyancy = value;
619 PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
620 {
621 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
622 ForceBuoyancy = _buoyancy;
623 });
624 }
625 }
626 public override float ForceBuoyancy {
627 get { return _buoyancy; }
628 set {
629 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
630
631 _buoyancy = value;
632 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
633 // Buoyancy is faked by changing the gravity applied to the object
634 float grav = BSParam.Gravity * (1f - _buoyancy);
635 Gravity = new OMV.Vector3(0f, 0f, grav);
636 if (PhysBody.HasPhysicalBody)
637 PhysScene.PE.SetGravity(PhysBody, Gravity);
638 }
639 }
640
641 // Used for MoveTo
642 public override OMV.Vector3 PIDTarget {
643 set { _PIDTarget = value; }
644 }
645
646 public override bool PIDActive { get; set; }
647
648 public override float PIDTau {
649 set { _PIDTau = value; }
650 }
651
652 public override void AddForce(OMV.Vector3 force, bool pushforce)
653 {
654 // Since this force is being applied in only one step, make this a force per second.
655 OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
656 AddForce(addForce, pushforce, false);
657 }
658 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
659 if (force.IsFinite())
660 {
661 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
662 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
663
664 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
665 {
666 // Bullet adds this central force to the total force for this tick
667 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
668 if (PhysBody.HasPhysicalBody)
669 {
670 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
671 }
672 });
673 }
674 else
675 {
676 m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
677 return;
678 }
679 }
680
681 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
682 }
683 public override void SetMomentum(OMV.Vector3 momentum) {
684 }
685
686 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
687 {
688 OMV.Vector3 newScale = size;
689
690 // Bullet's capsule total height is the "passed height + radius * 2";
691 // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
692 // The number we pass in for 'scaling' is the multiplier to get that base
693 // shape to be the size desired.
694 // So, when creating the scale for the avatar height, we take the passed height
695 // (size.Z) and remove the caps.
696 // An oddity of the Bullet capsule implementation is that it presumes the Y
697 // dimension is the radius of the capsule. Even though some of the code allows
698 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
699
700 // Scale is multiplier of radius with one of "0.5"
701
702 float heightAdjust = BSParam.AvatarHeightMidFudge;
703 if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
704 {
705 const float AVATAR_LOW = 1.1f;
706 const float AVATAR_MID = 1.775f; // 1.87f
707 const float AVATAR_HI = 2.45f;
708 // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m.
709 float midHeightOffset = size.Z - AVATAR_MID;
710 if (midHeightOffset < 0f)
711 {
712 // Small avatar. Add the adjustment based on the distance from midheight
713 heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge;
714 }
715 else
716 {
717 // Large avatar. Add the adjustment based on the distance from midheight
718 heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge;
719 }
720 }
721 if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule)
722 {
723 newScale.X = size.X / 2f;
724 newScale.Y = size.Y / 2f;
725 // The total scale height is the central cylindar plus the caps on the two ends.
726 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
727 }
728 else
729 {
730 newScale.Z = size.Z + heightAdjust;
731 }
732 // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
733
734 // If smaller than the endcaps, just fake like we're almost that small
735 if (newScale.Z < 0)
736 newScale.Z = 0.1f;
737
738 DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}",
739 LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale);
740
741 return newScale;
742 }
743
744 // set _avatarVolume and _mass based on capsule size, _density and Scale
745 private void ComputeAvatarVolumeAndMass()
746 {
747 _avatarVolume = (float)(
748 Math.PI
749 * Size.X / 2f
750 * Size.Y / 2f // the area of capsule cylinder
751 * Size.Z // times height of capsule cylinder
752 + 1.33333333f
753 * Math.PI
754 * Size.X / 2f
755 * Math.Min(Size.X, Size.Y) / 2
756 * Size.Y / 2f // plus the volume of the capsule end caps
757 );
758 _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
759 }
760
761 // The physics engine says that properties have updated. Update same and inform
762 // the world that things have changed.
763 public override void UpdateProperties(EntityProperties entprop)
764 {
765 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
766 TriggerPreUpdatePropertyAction(ref entprop);
767
768 RawPosition = entprop.Position;
769 RawOrientation = entprop.Rotation;
770
771 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
772 // and will send agent updates to the clients if velocity changes by more than
773 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
774 // extra updates.
775 //
776 // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to
777 // avatar movement rather than removes it. The larger the threshold, the bigger the jitter.
778 // This is most noticeable in level flight and can be seen with
779 // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower
780 // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update
781 // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?)
782 // has not yet been identified.
783 //
784 // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra
785 // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients().
786// if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
787 RawVelocity = entprop.Velocity;
788
789 _acceleration = entprop.Acceleration;
790 _rotationalVelocity = entprop.RotationalVelocity;
791
792 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
793 if (PositionSanityCheck(true))
794 {
795 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition);
796 entprop.Position = RawPosition;
797 }
798
799 // remember the current and last set values
800 LastEntityProperties = CurrentEntityProperties;
801 CurrentEntityProperties = entprop;
802
803 // Tell the linkset about value changes
804 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
805
806 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
807 // PhysScene.PostUpdate(this);
808
809 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
810 LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
811 }
812}
813}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
new file mode 100755
index 0000000..e42e868
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
@@ -0,0 +1,144 @@
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.PhysicsModule.BulletS
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 m_body1.ID,
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 {
81 m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high);
82 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
83 }
84 return ret;
85 }
86
87 public virtual bool SetAngularLimits(Vector3 low, Vector3 high)
88 {
89 bool ret = false;
90 if (m_enabled)
91 {
92 m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high);
93 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
94 }
95 return ret;
96 }
97
98 public virtual bool SetSolverIterations(float cnt)
99 {
100 bool ret = false;
101 if (m_enabled)
102 {
103 PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt);
104 ret = true;
105 }
106 return ret;
107 }
108
109 public virtual bool CalculateTransforms()
110 {
111 bool ret = false;
112 if (m_enabled)
113 {
114 // Recompute the internal transforms
115 PhysicsScene.PE.CalculateTransforms(m_constraint);
116 ret = true;
117 }
118 return ret;
119 }
120
121 // Reset this constraint making sure it has all its internal structures
122 // recomputed and is enabled and ready to go.
123 public virtual bool RecomputeConstraintVariables(float mass)
124 {
125 bool ret = false;
126 if (m_enabled)
127 {
128 ret = CalculateTransforms();
129 if (ret)
130 {
131 // Setting an object's mass to zero (making it static like when it's selected)
132 // automatically disables the constraints.
133 // If the link is enabled, be sure to set the constraint itself to enabled.
134 PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true));
135 }
136 else
137 {
138 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
139 }
140 }
141 return ret;
142 }
143}
144}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
new file mode 100755
index 0000000..4bcde2b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
@@ -0,0 +1,180 @@
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.PhysicsModule.BulletS
33{
34
35public 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 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world)
42 {
43 m_body1 = obj1;
44 m_body2 = obj2;
45 m_enabled = false;
46 }
47
48 // Create a btGeneric6DofConstraint
49 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
50 Vector3 frame1, Quaternion frame1rot,
51 Vector3 frame2, Quaternion frame2rot,
52 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
53 : base(world)
54 {
55 m_body1 = obj1;
56 m_body2 = obj2;
57 m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2,
58 frame1, frame1rot,
59 frame2, frame2rot,
60 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
61 m_enabled = true;
62 PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
63 m_body1.ID, world.worldID,
64 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
65 PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
66 m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
67 }
68
69 // 6 Dof constraint based on a midpoint between the two constrained bodies
70 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
71 Vector3 joinPoint,
72 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
73 : base(world)
74 {
75 m_body1 = obj1;
76 m_body2 = obj2;
77 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
78 {
79 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
80 BSScene.DetailLogZero, world.worldID,
81 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
82 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
83 LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
84 m_enabled = false;
85 }
86 else
87 {
88 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
89 joinPoint,
90 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
91
92 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
93 m_body1.ID, world.worldID, m_constraint.AddrString,
94 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
95
96 if (!m_constraint.HasPhysicalConstraint)
97 {
98 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
99 LogHeader, obj1.ID, obj2.ID);
100 m_enabled = false;
101 }
102 else
103 {
104 m_enabled = true;
105 }
106 }
107 }
108
109 // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object
110 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot,
111 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
112 : base(world)
113 {
114 m_body1 = obj1;
115 m_body2 = obj1; // Look out for confusion down the road
116 m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1,
117 frameInBloc, frameInBrot,
118 useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
119 m_enabled = true;
120 PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
121 m_body1.ID, world.worldID, obj1.ID, obj1.AddrString);
122 PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}",
123 m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
124 }
125
126 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
127 {
128 bool ret = false;
129 if (m_enabled)
130 {
131 PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot);
132 ret = true;
133 }
134 return ret;
135 }
136
137 public bool SetCFMAndERP(float cfm, float erp)
138 {
139 bool ret = false;
140 if (m_enabled)
141 {
142 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
143 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
144 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
145 ret = true;
146 }
147 return ret;
148 }
149
150 public bool UseFrameOffset(bool useOffset)
151 {
152 bool ret = false;
153 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
154 if (m_enabled)
155 ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff);
156 return ret;
157 }
158
159 public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
160 {
161 bool ret = false;
162 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
163 if (m_enabled)
164 {
165 ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce);
166 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
167 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
168 }
169 return ret;
170 }
171
172 public bool SetBreakingImpulseThreshold(float threshold)
173 {
174 bool ret = false;
175 if (m_enabled)
176 ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold);
177 return ret;
178 }
179}
180}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs
new file mode 100755
index 0000000..5746ac1
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs
@@ -0,0 +1,181 @@
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.PhysicsModule.BulletS
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 ret = RemoveAndDestroyConstraint(constrain);
121 }
122 }
123
124 return ret;
125 }
126
127 // The constraint MUST exist in the collection
128 // Could be called if the constraint was previously removed.
129 // Return 'true' if the constraint was actually removed and disposed.
130 public bool RemoveAndDestroyConstraint(BSConstraint constrain)
131 {
132 bool removed = false;
133 lock (m_constraints)
134 {
135 // remove the constraint from our collection
136 removed = m_constraints.Remove(constrain);
137 }
138 // Dispose() is safe to call multiple times
139 constrain.Dispose();
140 return removed;
141 }
142
143 // Remove all constraints that reference the passed body.
144 // Return 'true' if any constraints were destroyed.
145 public bool RemoveAndDestroyConstraint(BulletBody body1)
146 {
147 List<BSConstraint> toRemove = new List<BSConstraint>();
148 uint lookingID = body1.ID;
149 lock (m_constraints)
150 {
151 foreach (BSConstraint constrain in m_constraints)
152 {
153 if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
154 {
155 toRemove.Add(constrain);
156 }
157 }
158 foreach (BSConstraint constrain in toRemove)
159 {
160 m_constraints.Remove(constrain);
161 constrain.Dispose();
162 }
163 }
164 return (toRemove.Count > 0);
165 }
166
167 public bool RecalculateAllConstraints()
168 {
169 bool ret = false;
170 lock (m_constraints)
171 {
172 foreach (BSConstraint constrain in m_constraints)
173 {
174 constrain.CalculateTransforms();
175 ret = true;
176 }
177 }
178 return ret;
179 }
180}
181}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs
new file mode 100755
index 0000000..e7566a8
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs
@@ -0,0 +1,54 @@
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.PhysicsModule.BulletS
33{
34
35public sealed class BSConstraintConeTwist : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } }
38
39 public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frameInAloc, Quaternion frameInArot,
41 Vector3 frameInBloc, Quaternion frameInBrot,
42 bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2,
48 frameInAloc, frameInArot, frameInBloc, frameInBrot,
49 disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52}
53
54}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
new file mode 100755
index 0000000..d20538d
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
@@ -0,0 +1,55 @@
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.PhysicsModule.BulletS
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/PhysicsModules/BulletS/BSConstraintSlider.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
new file mode 100755
index 0000000..83d42af
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
@@ -0,0 +1,55 @@
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.PhysicsModule.BulletS
33{
34
35public sealed class BSConstraintSlider : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } }
38
39 public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frameInAloc, Quaternion frameInArot,
41 Vector3 frameInBloc, Quaternion frameInBrot,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2,
48 frameInAloc, frameInArot, frameInBloc, frameInBrot,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52
53}
54
55}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs
new file mode 100755
index 0000000..563a1b1
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs
@@ -0,0 +1,103 @@
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.PhysicsModule.BulletS
33{
34
35public sealed class BSConstraintSpring : BSConstraint6Dof
36{
37 public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } }
38
39 public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frame1Loc, Quaternion frame1Rot,
41 Vector3 frame2Loc, Quaternion frame2Rot,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 :base(world, obj1, obj2)
44 {
45 m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2,
46 frame1Loc, frame1Rot, frame2Loc, frame2Rot,
47 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
48 m_enabled = true;
49
50 PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
51 obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
52 PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
53 m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
54 }
55
56 public bool SetAxisEnable(int pIndex, bool pAxisEnable)
57 {
58 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}",
59 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable);
60 PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable));
61 return true;
62 }
63
64 public bool SetStiffness(int pIndex, float pStiffness)
65 {
66 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}",
67 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness);
68 PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness);
69 return true;
70 }
71
72 public bool SetDamping(int pIndex, float pDamping)
73 {
74 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}",
75 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping);
76 PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping);
77 return true;
78 }
79
80 public bool SetEquilibriumPoint(int pIndex, float pEqPoint)
81 {
82 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}",
83 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint);
84 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint);
85 return true;
86 }
87
88 public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq)
89 {
90 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}",
91 m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq);
92 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X);
93 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y);
94 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z);
95 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X);
96 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y);
97 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z);
98 return true;
99 }
100
101}
102
103} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
new file mode 100644
index 0000000..0fc5577
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
@@ -0,0 +1,1800 @@
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.Framework;
39using OpenSim.Region.PhysicsModules.SharedBase;
40
41namespace OpenSim.Region.PhysicsModule.BulletS
42{
43 public sealed class BSDynamics : BSActor
44 {
45#pragma warning disable 414
46 private static string LogHeader = "[BULLETSIM VEHICLE]";
47#pragma warning restore 414
48
49 // the prim this dynamic controller belongs to
50 private BSPrimLinkable ControllingPrim { get; set; }
51
52 private bool m_haveRegisteredForSceneEvents;
53
54 // mass of the vehicle fetched each time we're calles
55 private float m_vehicleMass;
56
57 // Vehicle properties
58 public Vehicle Type { get; set; }
59
60 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
61 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
62 // HOVER_TERRAIN_ONLY
63 // HOVER_GLOBAL_HEIGHT
64 // NO_DEFLECTION_UP
65 // HOVER_WATER_ONLY
66 // HOVER_UP_ONLY
67 // LIMIT_MOTOR_UP
68 // LIMIT_ROLL_ONLY
69 private Vector3 m_BlockingEndPoint = Vector3.Zero;
70 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
71 private Quaternion m_referenceFrame = Quaternion.Identity;
72
73 // Linear properties
74 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
75 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
76 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
77 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
78 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
79 private float m_linearMotorDecayTimescale = 1;
80 private float m_linearMotorTimescale = 1;
81 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
82 private Vector3 m_lastPositionVector = Vector3.Zero;
83 // private bool m_LinearMotorSetLastFrame = false;
84 // private Vector3 m_linearMotorOffset = Vector3.Zero;
85
86 //Angular properties
87 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
88 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
89 // private int m_angularMotorApply = 0; // application frame counter
90 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
91 private float m_angularMotorTimescale = 1; // motor angular velocity ramp up rate
92 private float m_angularMotorDecayTimescale = 1; // motor angular velocity decay rate
93 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
94 private Vector3 m_lastAngularVelocity = Vector3.Zero;
95 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
96
97 //Deflection properties
98 private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
99 private float m_angularDeflectionEfficiency = 0;
100 private float m_angularDeflectionTimescale = 0;
101 private float m_linearDeflectionEfficiency = 0;
102 private float m_linearDeflectionTimescale = 0;
103
104 //Banking properties
105 private float m_bankingEfficiency = 0;
106 private float m_bankingMix = 1;
107 private float m_bankingTimescale = 0;
108
109 //Hover and Buoyancy properties
110 private BSVMotor m_hoverMotor = new BSVMotor("Hover");
111 private float m_VhoverHeight = 0f;
112 private float m_VhoverEfficiency = 0f;
113 private float m_VhoverTimescale = 0f;
114 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
115 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
116 private float m_VehicleBuoyancy = 0f;
117 private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set
118
119 //Attractor properties
120 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
121 private float m_verticalAttractionEfficiency = 1.0f; // damped
122 private float m_verticalAttractionCutoff = 500f; // per the documentation
123 // Timescale > cutoff means no vert attractor.
124 private float m_verticalAttractionTimescale = 510f;
125
126 // Just some recomputed constants:
127#pragma warning disable 414
128 static readonly float TwoPI = ((float)Math.PI) * 2f;
129 static readonly float FourPI = ((float)Math.PI) * 4f;
130 static readonly float PIOverFour = ((float)Math.PI) / 4f;
131 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
132#pragma warning restore 414
133
134 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
135 : base(myScene, myPrim, actorName)
136 {
137 Type = Vehicle.TYPE_NONE;
138 m_haveRegisteredForSceneEvents = false;
139
140 ControllingPrim = myPrim as BSPrimLinkable;
141 if (ControllingPrim == null)
142 {
143 // THIS CANNOT HAPPEN!!
144 }
145 VDetailLog("{0},Creation", ControllingPrim.LocalID);
146 }
147
148 // Return 'true' if this vehicle is doing vehicle things
149 public bool IsActive
150 {
151 get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); }
152 }
153
154 // Return 'true' if this a vehicle that should be sitting on the ground
155 public bool IsGroundVehicle
156 {
157 get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); }
158 }
159
160 #region Vehicle parameter setting
161 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
162 {
163 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
164 float clampTemp;
165
166 switch (pParam)
167 {
168 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
169 m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
170 break;
171 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
172 m_angularDeflectionTimescale = ClampInRange(0.25f, pValue, 120);
173 break;
174 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
175 m_angularMotorDecayTimescale = ClampInRange(0.25f, pValue, 120);
176 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
177 break;
178 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
179 m_angularMotorTimescale = ClampInRange(0.25f, pValue, 120);
180 m_angularMotor.TimeScale = m_angularMotorTimescale;
181 break;
182 case Vehicle.BANKING_EFFICIENCY:
183 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
184 break;
185 case Vehicle.BANKING_MIX:
186 m_bankingMix = ClampInRange(0.01f, pValue, 1);
187 break;
188 case Vehicle.BANKING_TIMESCALE:
189 m_bankingTimescale = ClampInRange(0.25f, pValue, 120);
190 break;
191 case Vehicle.BUOYANCY:
192 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
193 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
194 break;
195 case Vehicle.HOVER_EFFICIENCY:
196 m_VhoverEfficiency = ClampInRange(0.01f, pValue, 1f);
197 break;
198 case Vehicle.HOVER_HEIGHT:
199 m_VhoverHeight = ClampInRange(0f, pValue, 1000000f);
200 break;
201 case Vehicle.HOVER_TIMESCALE:
202 m_VhoverTimescale = ClampInRange(0.01f, pValue, 120);
203 break;
204 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
205 m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
206 break;
207 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
208 m_linearDeflectionTimescale = ClampInRange(0.01f, pValue, 120);
209 break;
210 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
211 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
212 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
213 break;
214 case Vehicle.LINEAR_MOTOR_TIMESCALE:
215 m_linearMotorTimescale = ClampInRange(0.01f, pValue, 120);
216 m_linearMotor.TimeScale = m_linearMotorTimescale;
217 break;
218 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
219 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
220 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
221 break;
222 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
223 m_verticalAttractionTimescale = ClampInRange(0.01f, pValue, 120);
224 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
225 break;
226
227 // These are vector properties but the engine lets you use a single float value to
228 // set all of the components to the same value
229 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
230 clampTemp = ClampInRange(0.01f, pValue, 120);
231 m_angularFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
232 break;
233 case Vehicle.ANGULAR_MOTOR_DIRECTION:
234 clampTemp = ClampInRange(-TwoPI, pValue, TwoPI);
235 m_angularMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
236 m_angularMotor.Zero();
237 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 clampTemp = ClampInRange(0.01f, pValue, 120);
241 m_linearFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
242 break;
243 case Vehicle.LINEAR_MOTOR_DIRECTION:
244 clampTemp = ClampInRange(-BSParam.MaxLinearVelocity, pValue, BSParam.MaxLinearVelocity);
245 m_linearMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
246 m_linearMotorDirectionLASTSET = new Vector3(clampTemp, clampTemp, clampTemp);
247 m_linearMotor.SetTarget(m_linearMotorDirection);
248 break;
249 case Vehicle.LINEAR_MOTOR_OFFSET:
250 clampTemp = ClampInRange(-1000, pValue, 1000);
251 m_linearMotorOffset = new Vector3(clampTemp, clampTemp, clampTemp);
252 break;
253
254 }
255 }//end ProcessFloatVehicleParam
256
257 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
258 {
259 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
260 switch (pParam)
261 {
262 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
263 pValue.X = ClampInRange(0.25f, pValue.X, 120);
264 pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
265 pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
266 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
267 break;
268 case Vehicle.ANGULAR_MOTOR_DIRECTION:
269 // Limit requested angular speed to 2 rps= 4 pi rads/sec
270 pValue.X = ClampInRange(-FourPI, pValue.X, FourPI);
271 pValue.Y = ClampInRange(-FourPI, pValue.Y, FourPI);
272 pValue.Z = ClampInRange(-FourPI, pValue.Z, FourPI);
273 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
274 m_angularMotor.Zero();
275 m_angularMotor.SetTarget(m_angularMotorDirection);
276 break;
277 case Vehicle.LINEAR_FRICTION_TIMESCALE:
278 pValue.X = ClampInRange(0.25f, pValue.X, 120);
279 pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
280 pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
281 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
282 break;
283 case Vehicle.LINEAR_MOTOR_DIRECTION:
284 pValue.X = ClampInRange(-BSParam.MaxLinearVelocity, pValue.X, BSParam.MaxLinearVelocity);
285 pValue.Y = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Y, BSParam.MaxLinearVelocity);
286 pValue.Z = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Z, BSParam.MaxLinearVelocity);
287 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
288 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
289 m_linearMotor.SetTarget(m_linearMotorDirection);
290 break;
291 case Vehicle.LINEAR_MOTOR_OFFSET:
292 // Not sure the correct range to limit this variable
293 pValue.X = ClampInRange(-1000, pValue.X, 1000);
294 pValue.Y = ClampInRange(-1000, pValue.Y, 1000);
295 pValue.Z = ClampInRange(-1000, pValue.Z, 1000);
296 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
297 break;
298 case Vehicle.BLOCK_EXIT:
299 // Not sure the correct range to limit this variable
300 pValue.X = ClampInRange(-10000, pValue.X, 10000);
301 pValue.Y = ClampInRange(-10000, pValue.Y, 10000);
302 pValue.Z = ClampInRange(-10000, pValue.Z, 10000);
303 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
304 break;
305 }
306 }//end ProcessVectorVehicleParam
307
308 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
309 {
310 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
311 switch (pParam)
312 {
313 case Vehicle.REFERENCE_FRAME:
314 m_referenceFrame = pValue;
315 break;
316 case Vehicle.ROLL_FRAME:
317 m_RollreferenceFrame = pValue;
318 break;
319 }
320 }//end ProcessRotationVehicleParam
321
322 internal void ProcessVehicleFlags(int pParam, bool remove)
323 {
324 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove);
325 VehicleFlag parm = (VehicleFlag)pParam;
326 if (pParam == -1)
327 m_flags = (VehicleFlag)0;
328 else
329 {
330 if (remove)
331 m_flags &= ~parm;
332 else
333 m_flags |= parm;
334 }
335 }
336
337 public void ProcessTypeChange(Vehicle pType)
338 {
339 VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType);
340 // Set Defaults For Type
341 Type = pType;
342 switch (pType)
343 {
344 case Vehicle.TYPE_NONE:
345 m_linearMotorDirection = Vector3.Zero;
346 m_linearMotorTimescale = 0;
347 m_linearMotorDecayTimescale = 0;
348 m_linearFrictionTimescale = new Vector3(0, 0, 0);
349
350 m_angularMotorDirection = Vector3.Zero;
351 m_angularMotorDecayTimescale = 0;
352 m_angularMotorTimescale = 0;
353 m_angularFrictionTimescale = new Vector3(0, 0, 0);
354
355 m_VhoverHeight = 0;
356 m_VhoverEfficiency = 0;
357 m_VhoverTimescale = 0;
358 m_VehicleBuoyancy = 0;
359
360 m_linearDeflectionEfficiency = 1;
361 m_linearDeflectionTimescale = 1;
362
363 m_angularDeflectionEfficiency = 0;
364 m_angularDeflectionTimescale = 1000;
365
366 m_verticalAttractionEfficiency = 0;
367 m_verticalAttractionTimescale = 0;
368
369 m_bankingEfficiency = 0;
370 m_bankingTimescale = 1000;
371 m_bankingMix = 1;
372
373 m_referenceFrame = Quaternion.Identity;
374 m_flags = (VehicleFlag)0;
375
376 break;
377
378 case Vehicle.TYPE_SLED:
379 m_linearMotorDirection = Vector3.Zero;
380 m_linearMotorTimescale = 1000;
381 m_linearMotorDecayTimescale = 120;
382 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
383
384 m_angularMotorDirection = Vector3.Zero;
385 m_angularMotorTimescale = 1000;
386 m_angularMotorDecayTimescale = 120;
387 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
388
389 m_VhoverHeight = 0;
390 m_VhoverEfficiency = 10; // TODO: this looks wrong!!
391 m_VhoverTimescale = 10;
392 m_VehicleBuoyancy = 0;
393
394 m_linearDeflectionEfficiency = 1;
395 m_linearDeflectionTimescale = 1;
396
397 m_angularDeflectionEfficiency = 1;
398 m_angularDeflectionTimescale = 1000;
399
400 m_verticalAttractionEfficiency = 0;
401 m_verticalAttractionTimescale = 0;
402
403 m_bankingEfficiency = 0;
404 m_bankingTimescale = 10;
405 m_bankingMix = 1;
406
407 m_referenceFrame = Quaternion.Identity;
408 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
409 | VehicleFlag.HOVER_TERRAIN_ONLY
410 | VehicleFlag.HOVER_GLOBAL_HEIGHT
411 | VehicleFlag.HOVER_UP_ONLY);
412 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
413 | VehicleFlag.LIMIT_ROLL_ONLY
414 | VehicleFlag.LIMIT_MOTOR_UP);
415
416 break;
417 case Vehicle.TYPE_CAR:
418 m_linearMotorDirection = Vector3.Zero;
419 m_linearMotorTimescale = 1;
420 m_linearMotorDecayTimescale = 60;
421 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
422
423 m_angularMotorDirection = Vector3.Zero;
424 m_angularMotorTimescale = 1;
425 m_angularMotorDecayTimescale = 0.8f;
426 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
427
428 m_VhoverHeight = 0;
429 m_VhoverEfficiency = 0;
430 m_VhoverTimescale = 1000;
431 m_VehicleBuoyancy = 0;
432
433 m_linearDeflectionEfficiency = 1;
434 m_linearDeflectionTimescale = 2;
435
436 m_angularDeflectionEfficiency = 0;
437 m_angularDeflectionTimescale = 10;
438
439 m_verticalAttractionEfficiency = 1f;
440 m_verticalAttractionTimescale = 10f;
441
442 m_bankingEfficiency = -0.2f;
443 m_bankingMix = 1;
444 m_bankingTimescale = 1;
445
446 m_referenceFrame = Quaternion.Identity;
447 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
448 | VehicleFlag.HOVER_TERRAIN_ONLY
449 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
450 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
451 | VehicleFlag.LIMIT_ROLL_ONLY
452 | VehicleFlag.LIMIT_MOTOR_UP
453 | VehicleFlag.HOVER_UP_ONLY);
454 break;
455 case Vehicle.TYPE_BOAT:
456 m_linearMotorDirection = Vector3.Zero;
457 m_linearMotorTimescale = 5;
458 m_linearMotorDecayTimescale = 60;
459 m_linearFrictionTimescale = new Vector3(10, 3, 2);
460
461 m_angularMotorDirection = Vector3.Zero;
462 m_angularMotorTimescale = 4;
463 m_angularMotorDecayTimescale = 4;
464 m_angularFrictionTimescale = new Vector3(10,10,10);
465
466 m_VhoverHeight = 0;
467 m_VhoverEfficiency = 0.5f;
468 m_VhoverTimescale = 2;
469 m_VehicleBuoyancy = 1;
470
471 m_linearDeflectionEfficiency = 0.5f;
472 m_linearDeflectionTimescale = 3;
473
474 m_angularDeflectionEfficiency = 0.5f;
475 m_angularDeflectionTimescale = 5;
476
477 m_verticalAttractionEfficiency = 0.5f;
478 m_verticalAttractionTimescale = 5f;
479
480 m_bankingEfficiency = -0.3f;
481 m_bankingMix = 0.8f;
482 m_bankingTimescale = 1;
483
484 m_referenceFrame = Quaternion.Identity;
485 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
486 | VehicleFlag.HOVER_GLOBAL_HEIGHT
487 | VehicleFlag.LIMIT_ROLL_ONLY
488 | VehicleFlag.HOVER_UP_ONLY);
489 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
490 | VehicleFlag.LIMIT_MOTOR_UP
491 | VehicleFlag.HOVER_WATER_ONLY);
492 break;
493 case Vehicle.TYPE_AIRPLANE:
494 m_linearMotorDirection = Vector3.Zero;
495 m_linearMotorTimescale = 2;
496 m_linearMotorDecayTimescale = 60;
497 m_linearFrictionTimescale = new Vector3(200, 10, 5);
498
499 m_angularMotorDirection = Vector3.Zero;
500 m_angularMotorTimescale = 4;
501 m_angularMotorDecayTimescale = 4;
502 m_angularFrictionTimescale = new Vector3(20, 20, 20);
503
504 m_VhoverHeight = 0;
505 m_VhoverEfficiency = 0.5f;
506 m_VhoverTimescale = 1000;
507 m_VehicleBuoyancy = 0;
508
509 m_linearDeflectionEfficiency = 0.5f;
510 m_linearDeflectionTimescale = 3;
511
512 m_angularDeflectionEfficiency = 1;
513 m_angularDeflectionTimescale = 2;
514
515 m_verticalAttractionEfficiency = 0.9f;
516 m_verticalAttractionTimescale = 2f;
517
518 m_bankingEfficiency = 1;
519 m_bankingMix = 0.7f;
520 m_bankingTimescale = 2;
521
522 m_referenceFrame = Quaternion.Identity;
523 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
524 | VehicleFlag.HOVER_TERRAIN_ONLY
525 | VehicleFlag.HOVER_GLOBAL_HEIGHT
526 | VehicleFlag.HOVER_UP_ONLY
527 | VehicleFlag.NO_DEFLECTION_UP
528 | VehicleFlag.LIMIT_MOTOR_UP);
529 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
530 break;
531 case Vehicle.TYPE_BALLOON:
532 m_linearMotorDirection = Vector3.Zero;
533 m_linearMotorTimescale = 5;
534 m_linearFrictionTimescale = new Vector3(5, 5, 5);
535 m_linearMotorDecayTimescale = 60;
536
537 m_angularMotorDirection = Vector3.Zero;
538 m_angularMotorTimescale = 6;
539 m_angularFrictionTimescale = new Vector3(10, 10, 10);
540 m_angularMotorDecayTimescale = 10;
541
542 m_VhoverHeight = 5;
543 m_VhoverEfficiency = 0.8f;
544 m_VhoverTimescale = 10;
545 m_VehicleBuoyancy = 1;
546
547 m_linearDeflectionEfficiency = 0;
548 m_linearDeflectionTimescale = 5;
549
550 m_angularDeflectionEfficiency = 0;
551 m_angularDeflectionTimescale = 5;
552
553 m_verticalAttractionEfficiency = 1f;
554 m_verticalAttractionTimescale = 100f;
555
556 m_bankingEfficiency = 0;
557 m_bankingMix = 0.7f;
558 m_bankingTimescale = 5;
559
560 m_referenceFrame = Quaternion.Identity;
561
562 m_referenceFrame = Quaternion.Identity;
563 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
564 | VehicleFlag.HOVER_TERRAIN_ONLY
565 | VehicleFlag.HOVER_UP_ONLY
566 | VehicleFlag.NO_DEFLECTION_UP
567 | VehicleFlag.LIMIT_MOTOR_UP);
568 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY
569 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
570 break;
571 }
572
573 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f);
574 // m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
575
576 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f);
577 // m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
578
579 /* Not implemented
580 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
581 BSMotor.Infinite, BSMotor.InfiniteVector,
582 m_verticalAttractionEfficiency);
583 // Z goes away and we keep X and Y
584 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
585 */
586
587 if (this.Type == Vehicle.TYPE_NONE)
588 {
589 UnregisterForSceneEvents();
590 }
591 else
592 {
593 RegisterForSceneEvents();
594 }
595
596 // Update any physical parameters based on this type.
597 Refresh();
598 }
599 #endregion // Vehicle parameter setting
600
601 // BSActor.Refresh()
602 public override void Refresh()
603 {
604 // If asking for a refresh, reset the physical parameters before the next simulation step.
605 // Called whether active or not since the active state may be updated before the next step.
606 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate()
607 {
608 SetPhysicalParameters();
609 });
610 }
611
612 // Some of the properties of this prim may have changed.
613 // Do any updating needed for a vehicle
614 private void SetPhysicalParameters()
615 {
616 if (IsActive)
617 {
618 // Remember the mass so we don't have to fetch it every step
619 m_vehicleMass = ControllingPrim.TotalMass;
620
621 // Friction affects are handled by this vehicle code
622 // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
623 // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
624 ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
625 ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
626
627 // Moderate angular movement introduced by Bullet.
628 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
629 // Maybe compute linear and angular factor and damping from params.
630 m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping);
631 m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor);
632 m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor);
633
634 // Vehicles report collision events so we know when it's on the ground
635 // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
636 ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
637
638 // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
639 // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
640 // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
641 // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
642 ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass);
643
644 // Set the gravity for the vehicle depending on the buoyancy
645 // TODO: what should be done if prim and vehicle buoyancy differ?
646 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
647 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
648 // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
649 ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero);
650
651 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
652 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
653 BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution,
654 BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor
655 );
656 }
657 else
658 {
659 if (ControllingPrim.PhysBody.HasPhysicalBody)
660 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
661 // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
662 }
663 }
664
665 // BSActor.RemoveBodyDependencies
666 public override void RemoveDependencies()
667 {
668 Refresh();
669 }
670
671 // BSActor.Release()
672 public override void Dispose()
673 {
674 VDetailLog("{0},Dispose", ControllingPrim.LocalID);
675 UnregisterForSceneEvents();
676 Type = Vehicle.TYPE_NONE;
677 Enabled = false;
678 return;
679 }
680
681 private void RegisterForSceneEvents()
682 {
683 if (!m_haveRegisteredForSceneEvents)
684 {
685 m_physicsScene.BeforeStep += this.Step;
686 m_physicsScene.AfterStep += this.PostStep;
687 ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty;
688 m_haveRegisteredForSceneEvents = true;
689 }
690 }
691
692 private void UnregisterForSceneEvents()
693 {
694 if (m_haveRegisteredForSceneEvents)
695 {
696 m_physicsScene.BeforeStep -= this.Step;
697 m_physicsScene.AfterStep -= this.PostStep;
698 ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty;
699 m_haveRegisteredForSceneEvents = false;
700 }
701 }
702
703 private void PreUpdateProperty(ref EntityProperties entprop)
704 {
705 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
706 // TODO: handle physics introduced by Bullet with computed vehicle physics.
707 if (IsActive)
708 {
709 entprop.RotationalVelocity = Vector3.Zero;
710 }
711 }
712
713 #region Known vehicle value functions
714 // Vehicle physical parameters that we buffer from constant getting and setting.
715 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
716 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
717 // This does two things: 1) saves continuious calls into unmanaged code, and
718 // 2) signals when a physics property update must happen back to the simulator
719 // to update values modified for the vehicle.
720 private int m_knownChanged;
721 private int m_knownHas;
722 private float m_knownTerrainHeight;
723 private float m_knownWaterLevel;
724 private Vector3 m_knownPosition;
725 private Vector3 m_knownVelocity;
726 private Vector3 m_knownForce;
727 private Vector3 m_knownForceImpulse;
728 private Quaternion m_knownOrientation;
729 private Vector3 m_knownRotationalVelocity;
730 private Vector3 m_knownRotationalForce;
731 private Vector3 m_knownRotationalImpulse;
732
733 private const int m_knownChangedPosition = 1 << 0;
734 private const int m_knownChangedVelocity = 1 << 1;
735 private const int m_knownChangedForce = 1 << 2;
736 private const int m_knownChangedForceImpulse = 1 << 3;
737 private const int m_knownChangedOrientation = 1 << 4;
738 private const int m_knownChangedRotationalVelocity = 1 << 5;
739 private const int m_knownChangedRotationalForce = 1 << 6;
740 private const int m_knownChangedRotationalImpulse = 1 << 7;
741 private const int m_knownChangedTerrainHeight = 1 << 8;
742 private const int m_knownChangedWaterLevel = 1 << 9;
743
744 public void ForgetKnownVehicleProperties()
745 {
746 m_knownHas = 0;
747 m_knownChanged = 0;
748 }
749 // Push all the changed values back into the physics engine
750 public void PushKnownChanged()
751 {
752 if (m_knownChanged != 0)
753 {
754 if ((m_knownChanged & m_knownChangedPosition) != 0)
755 ControllingPrim.ForcePosition = m_knownPosition;
756
757 if ((m_knownChanged & m_knownChangedOrientation) != 0)
758 ControllingPrim.ForceOrientation = m_knownOrientation;
759
760 if ((m_knownChanged & m_knownChangedVelocity) != 0)
761 {
762 ControllingPrim.ForceVelocity = m_knownVelocity;
763 // Fake out Bullet by making it think the velocity is the same as last time.
764 // Bullet does a bunch of smoothing for changing parameters.
765 // Since the vehicle is demanding this setting, we override Bullet's smoothing
766 // by telling Bullet the value was the same last time.
767 // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
768 }
769
770 if ((m_knownChanged & m_knownChangedForce) != 0)
771 ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
772
773 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
774 ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
775
776 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
777 {
778 ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity;
779 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
780 }
781
782 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
783 ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
784
785 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
786 {
787 ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
788 }
789
790 // If we set one of the values (ie, the physics engine didn't do it) we must force
791 // an UpdateProperties event to send the changes up to the simulator.
792 m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody);
793 }
794 m_knownChanged = 0;
795 }
796
797 // Since the computation of terrain height can be a little involved, this routine
798 // is used to fetch the height only once for each vehicle simulation step.
799 Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1);
800 private float GetTerrainHeight(Vector3 pos)
801 {
802 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
803 {
804 lastRememberedHeightPos = pos;
805 m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
806 m_knownHas |= m_knownChangedTerrainHeight;
807 }
808 return m_knownTerrainHeight;
809 }
810
811 // Since the computation of water level can be a little involved, this routine
812 // is used ot fetch the level only once for each vehicle simulation step.
813 Vector3 lastRememberedWaterHeightPos = new Vector3(-1, -1, -1);
814 private float GetWaterLevel(Vector3 pos)
815 {
816 if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos)
817 {
818 lastRememberedWaterHeightPos = pos;
819 m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos);
820 m_knownHas |= m_knownChangedWaterLevel;
821 }
822 return m_knownWaterLevel;
823 }
824
825 private Vector3 VehiclePosition
826 {
827 get
828 {
829 if ((m_knownHas & m_knownChangedPosition) == 0)
830 {
831 m_knownPosition = ControllingPrim.ForcePosition;
832 m_knownHas |= m_knownChangedPosition;
833 }
834 return m_knownPosition;
835 }
836 set
837 {
838 m_knownPosition = value;
839 m_knownChanged |= m_knownChangedPosition;
840 m_knownHas |= m_knownChangedPosition;
841 }
842 }
843
844 private Quaternion VehicleOrientation
845 {
846 get
847 {
848 if ((m_knownHas & m_knownChangedOrientation) == 0)
849 {
850 m_knownOrientation = ControllingPrim.ForceOrientation;
851 m_knownHas |= m_knownChangedOrientation;
852 }
853 return m_knownOrientation;
854 }
855 set
856 {
857 m_knownOrientation = value;
858 m_knownChanged |= m_knownChangedOrientation;
859 m_knownHas |= m_knownChangedOrientation;
860 }
861 }
862
863 private Vector3 VehicleVelocity
864 {
865 get
866 {
867 if ((m_knownHas & m_knownChangedVelocity) == 0)
868 {
869 m_knownVelocity = ControllingPrim.ForceVelocity;
870 m_knownHas |= m_knownChangedVelocity;
871 }
872 return m_knownVelocity;
873 }
874 set
875 {
876 m_knownVelocity = value;
877 m_knownChanged |= m_knownChangedVelocity;
878 m_knownHas |= m_knownChangedVelocity;
879 }
880 }
881
882 private void VehicleAddForce(Vector3 pForce)
883 {
884 if ((m_knownHas & m_knownChangedForce) == 0)
885 {
886 m_knownForce = Vector3.Zero;
887 m_knownHas |= m_knownChangedForce;
888 }
889 m_knownForce += pForce;
890 m_knownChanged |= m_knownChangedForce;
891 }
892
893 private void VehicleAddForceImpulse(Vector3 pImpulse)
894 {
895 if ((m_knownHas & m_knownChangedForceImpulse) == 0)
896 {
897 m_knownForceImpulse = Vector3.Zero;
898 m_knownHas |= m_knownChangedForceImpulse;
899 }
900 m_knownForceImpulse += pImpulse;
901 m_knownChanged |= m_knownChangedForceImpulse;
902 }
903
904 private Vector3 VehicleRotationalVelocity
905 {
906 get
907 {
908 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
909 {
910 m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity;
911 m_knownHas |= m_knownChangedRotationalVelocity;
912 }
913 return (Vector3)m_knownRotationalVelocity;
914 }
915 set
916 {
917 m_knownRotationalVelocity = value;
918 m_knownChanged |= m_knownChangedRotationalVelocity;
919 m_knownHas |= m_knownChangedRotationalVelocity;
920 }
921 }
922 private void VehicleAddAngularForce(Vector3 aForce)
923 {
924 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
925 {
926 m_knownRotationalForce = Vector3.Zero;
927 }
928 m_knownRotationalForce += aForce;
929 m_knownChanged |= m_knownChangedRotationalForce;
930 m_knownHas |= m_knownChangedRotationalForce;
931 }
932 private void VehicleAddRotationalImpulse(Vector3 pImpulse)
933 {
934 if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
935 {
936 m_knownRotationalImpulse = Vector3.Zero;
937 m_knownHas |= m_knownChangedRotationalImpulse;
938 }
939 m_knownRotationalImpulse += pImpulse;
940 m_knownChanged |= m_knownChangedRotationalImpulse;
941 }
942
943 // Vehicle relative forward velocity
944 private Vector3 VehicleForwardVelocity
945 {
946 get
947 {
948 return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleFrameOrientation));
949 }
950 }
951
952 private float VehicleForwardSpeed
953 {
954 get
955 {
956 return VehicleForwardVelocity.X;
957 }
958 }
959 private Quaternion VehicleFrameOrientation
960 {
961 get
962 {
963 return VehicleOrientation * m_referenceFrame;
964 }
965 }
966
967 #endregion // Known vehicle value functions
968
969 // One step of the vehicle properties for the next 'pTimestep' seconds.
970 internal void Step(float pTimestep)
971 {
972 if (!IsActive) return;
973
974 ForgetKnownVehicleProperties();
975
976 MoveLinear(pTimestep);
977 MoveAngular(pTimestep);
978
979 LimitRotation(pTimestep);
980
981 // remember the position so next step we can limit absolute movement effects
982 m_lastPositionVector = VehiclePosition;
983
984 // If we forced the changing of some vehicle parameters, update the values and
985 // for the physics engine to note the changes so an UpdateProperties event will happen.
986 PushKnownChanged();
987
988 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
989 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
990
991 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
992 ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
993 }
994
995 // Called after the simulation step
996 internal void PostStep(float pTimestep)
997 {
998 if (!IsActive) return;
999
1000 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
1001 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
1002 }
1003
1004 // Apply the effect of the linear motor and other linear motions (like hover and float).
1005 private void MoveLinear(float pTimestep)
1006 {
1007 ComputeLinearVelocity(pTimestep);
1008
1009 ComputeLinearDeflection(pTimestep);
1010
1011 ComputeLinearTerrainHeightCorrection(pTimestep);
1012
1013 ComputeLinearHover(pTimestep);
1014
1015 ComputeLinearBlockingEndPoint(pTimestep);
1016
1017 ComputeLinearMotorUp(pTimestep);
1018
1019 ApplyGravity(pTimestep);
1020
1021 // If not changing some axis, reduce out velocity
1022 if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
1023 {
1024 Vector3 vel = VehicleVelocity;
1025 if ((m_flags & (VehicleFlag.NO_X)) != 0)
1026 {
1027 vel.X = 0;
1028 }
1029 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
1030 {
1031 vel.Y = 0;
1032 }
1033 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
1034 {
1035 vel.Z = 0;
1036 }
1037 VehicleVelocity = vel;
1038 }
1039
1040 // ==================================================================
1041 // Clamp high or low velocities
1042 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
1043 if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared)
1044 {
1045 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
1046 VehicleVelocity /= VehicleVelocity.Length();
1047 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
1048 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
1049 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
1050 }
1051 else if (newVelocityLengthSq < BSParam.VehicleMinLinearVelocitySquared)
1052 {
1053 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
1054 VDetailLog("{0}, MoveLinear,clampMin,origVelW={1},lenSq={2}",
1055 ControllingPrim.LocalID, origVelW, newVelocityLengthSq);
1056 VehicleVelocity = Vector3.Zero;
1057 }
1058
1059 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity );
1060
1061 } // end MoveLinear()
1062
1063 public void ComputeLinearVelocity(float pTimestep)
1064 {
1065 // Step the motor from the current value. Get the correction needed this step.
1066 Vector3 origVelW = VehicleVelocity; // DEBUG
1067 Vector3 currentVelV = VehicleForwardVelocity;
1068 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
1069
1070 // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction.
1071 Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep);
1072 linearMotorCorrectionV -= (currentVelV * frictionFactorV);
1073
1074 // Motor is vehicle coordinates. Rotate it to world coordinates
1075 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleFrameOrientation;
1076
1077 // If we're a ground vehicle, don't add any upward Z movement
1078 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
1079 {
1080 if (linearMotorVelocityW.Z > 0f)
1081 linearMotorVelocityW.Z = 0f;
1082 }
1083
1084 // Add this correction to the velocity to make it faster/slower.
1085 VehicleVelocity += linearMotorVelocityW;
1086
1087 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}",
1088 ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV,
1089 linearMotorVelocityW, VehicleVelocity, frictionFactorV);
1090 }
1091
1092 //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis
1093 //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity
1094 private void ComputeLinearDeflection(float pTimestep)
1095 {
1096 Vector3 linearDeflectionV = Vector3.Zero;
1097 Vector3 velocityV = VehicleForwardVelocity;
1098
1099 if (BSParam.VehicleEnableLinearDeflection)
1100 {
1101 // Velocity in Y and Z dimensions is movement to the side or turning.
1102 // Compute deflection factor from the to the side and rotational velocity
1103 linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y);
1104 linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z);
1105
1106 // Velocity to the side and around is corrected and moved into the forward direction
1107 linearDeflectionV.X += Math.Abs(linearDeflectionV.Y);
1108 linearDeflectionV.X += Math.Abs(linearDeflectionV.Z);
1109
1110 // Scale the deflection to the fractional simulation time
1111 linearDeflectionV *= pTimestep;
1112
1113 // Subtract the sideways and rotational velocity deflection factors while adding the correction forward
1114 linearDeflectionV *= new Vector3(1, -1, -1);
1115
1116 // Correction is vehicle relative. Convert to world coordinates.
1117 Vector3 linearDeflectionW = linearDeflectionV * VehicleFrameOrientation;
1118
1119 // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall.
1120 if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision)
1121 {
1122 linearDeflectionW.Z = 0f;
1123 }
1124
1125 VehicleVelocity += linearDeflectionW;
1126
1127 VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}",
1128 ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV);
1129 }
1130 }
1131
1132 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
1133 {
1134 // If below the terrain, move us above the ground a little.
1135 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
1136 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
1137 {
1138 // Force position because applying force won't get the vehicle through the terrain
1139 Vector3 newPosition = VehiclePosition;
1140 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
1141 VehiclePosition = newPosition;
1142 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
1143 ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
1144 }
1145 }
1146
1147 public void ComputeLinearHover(float pTimestep)
1148 {
1149 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
1150 // m_VhoverTimescale: time to achieve height
1151 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0 && (m_VhoverHeight > 0) && (m_VhoverTimescale < 300))
1152 {
1153 // We should hover, get the target height
1154 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
1155 {
1156 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
1157 }
1158 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
1159 {
1160 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
1161 }
1162 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
1163 {
1164 m_VhoverTargetHeight = m_VhoverHeight;
1165 }
1166 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
1167 {
1168 // If body is already heigher, use its height as target height
1169 if (VehiclePosition.Z > m_VhoverTargetHeight)
1170 {
1171 m_VhoverTargetHeight = VehiclePosition.Z;
1172
1173 // A 'misfeature' of this flag is that if the vehicle is above it's hover height,
1174 // the vehicle's buoyancy goes away. This is an SL bug that got used by so many
1175 // scripts that it could not be changed.
1176 // So, if above the height, reapply gravity if buoyancy had it turned off.
1177 if (m_VehicleBuoyancy != 0)
1178 {
1179 Vector3 appliedGravity = ControllingPrim.ComputeGravity(ControllingPrim.Buoyancy) * m_vehicleMass;
1180 VehicleAddForce(appliedGravity);
1181 }
1182 }
1183 }
1184
1185 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
1186 {
1187 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
1188 {
1189 Vector3 pos = VehiclePosition;
1190 pos.Z = m_VhoverTargetHeight;
1191 VehiclePosition = pos;
1192
1193 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos);
1194 }
1195 }
1196 else
1197 {
1198 // Error is positive if below the target and negative if above.
1199 Vector3 hpos = VehiclePosition;
1200 float verticalError = m_VhoverTargetHeight - hpos.Z;
1201 float verticalCorrection = verticalError / m_VhoverTimescale;
1202 verticalCorrection *= m_VhoverEfficiency;
1203
1204 hpos.Z += verticalCorrection;
1205 VehiclePosition = hpos;
1206
1207 // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
1208 Vector3 vel = VehicleVelocity;
1209 vel.Z = 0f;
1210 VehicleVelocity = vel;
1211
1212 /*
1213 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
1214 Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
1215 verticalCorrection *= m_vehicleMass;
1216
1217 // TODO: implement m_VhoverEfficiency correctly
1218 VehicleAddForceImpulse(verticalCorrection);
1219 */
1220
1221 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
1222 ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency,
1223 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1224 verticalError, verticalCorrection);
1225 }
1226 }
1227 }
1228
1229 public bool ComputeLinearBlockingEndPoint(float pTimestep)
1230 {
1231 bool changed = false;
1232
1233 Vector3 pos = VehiclePosition;
1234 Vector3 posChange = pos - m_lastPositionVector;
1235 if (m_BlockingEndPoint != Vector3.Zero)
1236 {
1237 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
1238 {
1239 pos.X -= posChange.X + 1;
1240 changed = true;
1241 }
1242 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
1243 {
1244 pos.Y -= posChange.Y + 1;
1245 changed = true;
1246 }
1247 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
1248 {
1249 pos.Z -= posChange.Z + 1;
1250 changed = true;
1251 }
1252 if (pos.X <= 0)
1253 {
1254 pos.X += posChange.X + 1;
1255 changed = true;
1256 }
1257 if (pos.Y <= 0)
1258 {
1259 pos.Y += posChange.Y + 1;
1260 changed = true;
1261 }
1262 if (changed)
1263 {
1264 VehiclePosition = pos;
1265 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1266 ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos);
1267 }
1268 }
1269 return changed;
1270 }
1271
1272 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1273 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
1274 // used with conjunction with banking: the strength of the banking will decay when the
1275 // vehicle no longer experiences collisions. The decay timescale is the same as
1276 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1277 // when they are in mid jump.
1278 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1279 // This is just using the ground and a general collision check. Should really be using
1280 // a downward raycast to find what is below.
1281 public void ComputeLinearMotorUp(float pTimestep)
1282 {
1283 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1284 {
1285 // This code tries to decide if the object is not on the ground and then pushing down
1286 /*
1287 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1288 distanceAboveGround = VehiclePosition.Z - targetHeight;
1289 // Not colliding if the vehicle is off the ground
1290 if (!Prim.HasSomeCollision)
1291 {
1292 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1293 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
1294 }
1295 // TODO: this calculation is wrong. From the description at
1296 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
1297 // has a decay factor. This says this force should
1298 // be computed with a motor.
1299 // TODO: add interaction with banking.
1300 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1301 Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret);
1302 */
1303
1304 // Another approach is to measure if we're going up. If going up and not colliding,
1305 // the vehicle is in the air. Fix that by pushing down.
1306 if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1)
1307 {
1308 // Get rid of any of the velocity vector that is pushing us up.
1309 float upVelocity = VehicleVelocity.Z;
1310 VehicleVelocity += new Vector3(0, 0, -upVelocity);
1311
1312 /*
1313 // If we're pointed up into the air, we should nose down
1314 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1315 // The rotation around the Y axis is pitch up or down
1316 if (pointingDirection.Y > 0.01f)
1317 {
1318 float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
1319 Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
1320 // Rotate into world coordinates and apply to vehicle
1321 angularCorrectionVector *= VehicleOrientation;
1322 VehicleAddAngularForce(angularCorrectionVector);
1323 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
1324 Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
1325 }
1326 */
1327 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1328 ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity);
1329 }
1330 }
1331 }
1332
1333 private void ApplyGravity(float pTimeStep)
1334 {
1335 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1336
1337 // Hack to reduce downward force if the vehicle is probably sitting on the ground
1338 if (ControllingPrim.HasSomeCollision && IsGroundVehicle)
1339 appliedGravity *= BSParam.VehicleGroundGravityFudge;
1340
1341 VehicleAddForce(appliedGravity);
1342
1343 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
1344 ControllingPrim.LocalID, m_VehicleGravity,
1345 ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1346 }
1347
1348 // =======================================================================
1349 // =======================================================================
1350 // Apply the effect of the angular motor.
1351 // The 'contribution' is how much angular correction velocity each function wants.
1352 // All the contributions are added together and the resulting velocity is
1353 // set directly on the vehicle.
1354 private void MoveAngular(float pTimestep)
1355 {
1356 ComputeAngularTurning(pTimestep);
1357
1358 ComputeAngularVerticalAttraction();
1359
1360 ComputeAngularDeflection();
1361
1362 ComputeAngularBanking();
1363
1364 // ==================================================================
1365 if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f))
1366 {
1367 // The vehicle is not adding anything angular wise.
1368 VehicleRotationalVelocity = Vector3.Zero;
1369 VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID);
1370 }
1371 else
1372 {
1373 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity);
1374 }
1375
1376 // ==================================================================
1377 //Offset section
1378 if (m_linearMotorOffset != Vector3.Zero)
1379 {
1380 //Offset of linear velocity doesn't change the linear velocity,
1381 // but causes a torque to be applied, for example...
1382 //
1383 // IIIII >>> IIIII
1384 // IIIII >>> IIIII
1385 // IIIII >>> IIIII
1386 // ^
1387 // | Applying a force at the arrow will cause the object to move forward, but also rotate
1388 //
1389 //
1390 // The torque created is the linear velocity crossed with the offset
1391
1392 // TODO: this computation should be in the linear section
1393 // because that is where we know the impulse being applied.
1394 Vector3 torqueFromOffset = Vector3.Zero;
1395 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
1396 if (float.IsNaN(torqueFromOffset.X))
1397 torqueFromOffset.X = 0;
1398 if (float.IsNaN(torqueFromOffset.Y))
1399 torqueFromOffset.Y = 0;
1400 if (float.IsNaN(torqueFromOffset.Z))
1401 torqueFromOffset.Z = 0;
1402
1403 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1404 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset);
1405 }
1406
1407 }
1408
1409 private void ComputeAngularTurning(float pTimestep)
1410 {
1411 // The user wants this many radians per second angular change?
1412 Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG
1413 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleFrameOrientation);
1414 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1415
1416 // ==================================================================
1417 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1418 // This flag prevents linear deflection parallel to world z-axis. This is useful
1419 // for preventing ground vehicles with large linear deflection, like bumper cars,
1420 // from climbing their linear deflection into the sky.
1421 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1422 // TODO: This is here because this is where ODE put it but documentation says it
1423 // is a linear effect. Where should this check go?
1424 //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1425 // {
1426 // angularMotorContributionV.X = 0f;
1427 // angularMotorContributionV.Y = 0f;
1428 // }
1429
1430 // Reduce any velocity by friction.
1431 Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep);
1432 angularMotorContributionV -= (currentAngularV * frictionFactorW);
1433
1434 Vector3 angularMotorContributionW = angularMotorContributionV * VehicleFrameOrientation;
1435 VehicleRotationalVelocity += angularMotorContributionW;
1436
1437 VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}",
1438 ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW);
1439 }
1440
1441 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1442 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1443 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1444 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1445 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1446 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1447 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1448 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1449 public void ComputeAngularVerticalAttraction()
1450 {
1451
1452 // If vertical attaction timescale is reasonable
1453 if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1454 {
1455 Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleFrameOrientation;
1456 switch (BSParam.VehicleAngularVerticalAttractionAlgorithm)
1457 {
1458 case 0:
1459 {
1460 //Another formula to try got from :
1461 //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html
1462
1463 // Flipping what was originally a timescale into a speed variable and then multiplying it by 2
1464 // since only computing half the distance between the angles.
1465 float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
1466
1467 // Make a prediction of where the up axis will be when this is applied rather then where it is now as
1468 // this makes for a smoother adjustment and less fighting between the various forces.
1469 Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1470
1471 // This is only half the distance to the target so it will take 2 seconds to complete the turn.
1472 Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
1473
1474 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != 0)
1475 {
1476 Vector3 vehicleForwardAxis = Vector3.UnitX * VehicleFrameOrientation;
1477 torqueVector = ProjectVector(torqueVector, vehicleForwardAxis);
1478 }
1479
1480 // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
1481 Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed;
1482
1483 VehicleRotationalVelocity += vertContributionV;
1484
1485 VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}",
1486 ControllingPrim.LocalID,
1487 verticalAttractionSpeed,
1488 vehicleUpAxis,
1489 predictedUp,
1490 torqueVector,
1491 vertContributionV);
1492 break;
1493 }
1494 case 1:
1495 {
1496 // Possible solution derived from a discussion at:
1497 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1498
1499 // Create a rotation that is only the vehicle's rotation around Z
1500 Vector3 currentEulerW = Vector3.Zero;
1501 VehicleFrameOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z);
1502 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z);
1503
1504 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1505 Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleFrameOrientation);
1506 // Compute the angle between those to vectors.
1507 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation)));
1508 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1509
1510 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1511 // TODO: add 'efficiency'.
1512 // differenceAngle /= m_verticalAttractionTimescale;
1513
1514 // Create the quaterian representing the correction angle
1515 Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle);
1516
1517 // Turn that quaternion into Euler values to make it into velocities to apply.
1518 Vector3 vertContributionW = Vector3.Zero;
1519 correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z);
1520 vertContributionW *= -1f;
1521 vertContributionW /= m_verticalAttractionTimescale;
1522
1523 VehicleRotationalVelocity += vertContributionW;
1524
1525 VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}",
1526 ControllingPrim.LocalID,
1527 vehicleUpAxis,
1528 differenceAxisW,
1529 differenceAngle,
1530 correctionRotationW,
1531 vertContributionW);
1532 break;
1533 }
1534 case 2:
1535 {
1536 Vector3 vertContributionV = Vector3.Zero;
1537 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1538
1539 // Take a vector pointing up and convert it from world to vehicle relative coords.
1540 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation);
1541
1542 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1543 // is now:
1544 // leaning to one side: rotated around the X axis with the Y value going
1545 // from zero (nearly straight up) to one (completely to the side)) or
1546 // leaning front-to-back: rotated around the Y axis with the value of X being between
1547 // zero and one.
1548 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1549
1550 // Y error means needed rotation around X axis and visa versa.
1551 // Since the error goes from zero to one, the asin is the corresponding angle.
1552 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1553 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1554 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1555
1556 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1557 if (verticalError.Z < 0f)
1558 {
1559 vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour;
1560 // vertContribution.Y -= PIOverFour;
1561 }
1562
1563 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1564 // Correction happens over a number of seconds.
1565 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1566
1567 // The correction happens over the user's time period
1568 vertContributionV /= m_verticalAttractionTimescale;
1569
1570 // Rotate the vehicle rotation to the world coordinates.
1571 VehicleRotationalVelocity += (vertContributionV * VehicleFrameOrientation);
1572
1573 VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}",
1574 ControllingPrim.LocalID,
1575 vehicleUpAxis,
1576 origRotVelW,
1577 verticalError,
1578 unscaledContribVerticalErrorV,
1579 m_verticalAttractionEfficiency,
1580 m_verticalAttractionTimescale,
1581 vertContributionV);
1582 break;
1583 }
1584 default:
1585 {
1586 break;
1587 }
1588 }
1589 }
1590 }
1591
1592 // Angular correction to correct the direction the vehicle is pointing to be
1593 // the direction is should want to be pointing.
1594 // The vehicle is moving in some direction and correct its orientation to it is pointing
1595 // in that direction.
1596 // TODO: implement reference frame.
1597 public void ComputeAngularDeflection()
1598 {
1599
1600 if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1601 {
1602 Vector3 deflectContributionV = Vector3.Zero;
1603
1604 // The direction the vehicle is moving
1605 Vector3 movingDirection = VehicleVelocity;
1606 movingDirection.Normalize();
1607
1608 // If the vehicle is going backward, it is still pointing forward
1609 movingDirection *= Math.Sign(VehicleForwardSpeed);
1610
1611 // The direction the vehicle is pointing
1612 Vector3 pointingDirection = Vector3.UnitX * VehicleFrameOrientation;
1613 //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep
1614 // from overshooting and allow this correction to merge with the Vertical Attraction peacefully.
1615 Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1616 predictedPointingDirection.Normalize();
1617
1618 // The difference between what is and what should be.
1619 // Vector3 deflectionError = movingDirection - predictedPointingDirection;
1620 Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection);
1621
1622 // Don't try to correct very large errors (not our job)
1623 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
1624 // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
1625 // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
1626 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1627 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1628 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1629
1630 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1631
1632 // Scale the correction by recovery timescale and efficiency
1633 // Not modeling a spring so clamp the scale to no more then the arc
1634 deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f);
1635 //deflectContributionV /= m_angularDeflectionTimescale;
1636
1637 VehicleRotationalVelocity += deflectContributionV;
1638 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1639 ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1640 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}",
1641 ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection);
1642 }
1643 }
1644
1645 // Angular change to rotate the vehicle around the Z axis when the vehicle
1646 // is tipped around the X axis.
1647 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1648 // The vertical attractor feature must be enabled in order for the banking behavior to
1649 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1650 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1651 // of the yaw effect will be proportional to the
1652 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1653 // velocity along its preferred axis of motion.
1654 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1655 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1656 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1657 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1658 // Negating the banking coefficient will make it so that the vehicle leans to the
1659 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1660 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1661 // banking vehicles do what you want rather than what the laws of physics allow.
1662 // For example, consider a real motorcycle...it must be moving forward in order for
1663 // it to turn while banking, however video-game motorcycles are often configured
1664 // to turn in place when at a dead stop--because they are often easier to control
1665 // that way using the limited interface of the keyboard or game controller. The
1666 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1667 // banking by functioning as a slider between a banking that is correspondingly
1668 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1669 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1670 // to "dynamic" where the banking is also proportional to its velocity along its
1671 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1672 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1673 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1674 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1675 // make a sluggish vehicle by giving it a timescale of several seconds.
1676 public void ComputeAngularBanking()
1677 {
1678 if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1679 {
1680 Vector3 bankingContributionV = Vector3.Zero;
1681
1682 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1683 // As the vehicle rolls to the right or left, the Y value will increase from
1684 // zero (straight up) to 1 or -1 (full tilt right or left)
1685 Vector3 rollComponents = Vector3.UnitZ * VehicleFrameOrientation;
1686
1687 // Figure out the yaw value for this much roll.
1688 float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
1689 // actual error = static turn error + dynamic turn error
1690 float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
1691
1692 // TODO: the banking effect should not go to infinity but what to limit it to?
1693 // And what should happen when this is being added to a user defined yaw that is already PI*4?
1694 mixedYawAngle = ClampInRange(-FourPI, mixedYawAngle, FourPI);
1695
1696 // Build the force vector to change rotation from what it is to what it should be
1697 bankingContributionV.Z = -mixedYawAngle;
1698
1699 // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
1700 bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
1701
1702 VehicleRotationalVelocity += bankingContributionV;
1703
1704
1705 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1706 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1707 }
1708 }
1709
1710 // This is from previous instantiations of XXXDynamics.cs.
1711 // Applies roll reference frame.
1712 // TODO: is this the right way to separate the code to do this operation?
1713 // Should this be in MoveAngular()?
1714 internal void LimitRotation(float timestep)
1715 {
1716 Quaternion rotq = VehicleOrientation;
1717 Quaternion m_rot = rotq;
1718 if (m_RollreferenceFrame != Quaternion.Identity)
1719 {
1720 if (rotq.X >= m_RollreferenceFrame.X)
1721 {
1722 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
1723 }
1724 if (rotq.Y >= m_RollreferenceFrame.Y)
1725 {
1726 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
1727 }
1728 if (rotq.X <= -m_RollreferenceFrame.X)
1729 {
1730 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
1731 }
1732 if (rotq.Y <= -m_RollreferenceFrame.Y)
1733 {
1734 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
1735 }
1736 }
1737 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
1738 {
1739 m_rot.X = 0;
1740 m_rot.Y = 0;
1741 }
1742 if (rotq != m_rot)
1743 {
1744 VehicleOrientation = m_rot;
1745 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot);
1746 }
1747
1748 }
1749
1750 // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce
1751 // some value by to apply this friction.
1752 private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep)
1753 {
1754 Vector3 frictionFactor = Vector3.Zero;
1755 if (friction != BSMotor.InfiniteVector)
1756 {
1757 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
1758 // Individual friction components can be 'infinite' so compute each separately.
1759 frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X);
1760 frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y);
1761 frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z);
1762 frictionFactor *= pTimestep;
1763 }
1764 return frictionFactor;
1765 }
1766
1767 private float SortedClampInRange(float clampa, float val, float clampb)
1768 {
1769 if (clampa > clampb)
1770 {
1771 float temp = clampa;
1772 clampa = clampb;
1773 clampb = temp;
1774 }
1775 return ClampInRange(clampa, val, clampb);
1776
1777 }
1778
1779 //Given a Vector and a unit vector will return the amount of the vector is on the same axis as the unit.
1780 private Vector3 ProjectVector(Vector3 vector, Vector3 onNormal)
1781 {
1782 float vectorDot = Vector3.Dot(vector, onNormal);
1783 return onNormal * vectorDot;
1784
1785 }
1786
1787 private float ClampInRange(float low, float val, float high)
1788 {
1789 return Math.Max(low, Math.Min(val, high));
1790 // return Utils.Clamp(val, low, high);
1791 }
1792
1793 // Invoke the detailed logger and output something if it's enabled.
1794 private void VDetailLog(string msg, params Object[] args)
1795 {
1796 if (ControllingPrim.PhysScene.VehicleLoggingEnabled)
1797 ControllingPrim.PhysScene.DetailLog(msg, args);
1798 }
1799 }
1800}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs
new file mode 100755
index 0000000..8312239
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs
@@ -0,0 +1,503 @@
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.PhysicsModule.BulletS
34{
35
36public abstract class BSLinkset
37{
38 // private static string LogHeader = "[BULLETSIM LINKSET]";
39
40 public enum LinksetImplementation
41 {
42 Constraint = 0, // linkset tied together with constraints
43 Compound = 1, // linkset tied together as a compound object
44 Manual = 2 // linkset tied together manually (code moves all the pieces)
45 }
46 // Create the correct type of linkset for this child
47 public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
48 {
49 BSLinkset ret = null;
50
51 switch (parent.LinksetType)
52 {
53 case LinksetImplementation.Constraint:
54 ret = new BSLinksetConstraints(physScene, parent);
55 break;
56 case LinksetImplementation.Compound:
57 ret = new BSLinksetCompound(physScene, parent);
58 break;
59 case LinksetImplementation.Manual:
60 // ret = new BSLinksetManual(physScene, parent);
61 break;
62 default:
63 ret = new BSLinksetCompound(physScene, parent);
64 break;
65 }
66 if (ret == null)
67 {
68 physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
69 }
70 return ret;
71 }
72
73 public class BSLinkInfo
74 {
75 public BSPrimLinkable member;
76 public BSLinkInfo(BSPrimLinkable pMember)
77 {
78 member = pMember;
79 }
80 public virtual void ResetLink() { }
81 public virtual void SetLinkParameters(BSConstraint constrain) { }
82 // Returns 'true' if physical property updates from the child should be reported to the simulator
83 public virtual bool ShouldUpdateChildProperties() { return false; }
84 }
85
86 public LinksetImplementation LinksetImpl { get; protected set; }
87
88 public BSPrimLinkable LinksetRoot { get; protected set; }
89
90 protected BSScene m_physicsScene { get; private set; }
91
92 static int m_nextLinksetID = 1;
93 public int LinksetID { get; private set; }
94
95 // The children under the root in this linkset.
96 // protected HashSet<BSPrimLinkable> m_children;
97 protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children;
98
99 // We lock the diddling of linkset classes to prevent any badness.
100 // This locks the modification of the instances of this class. Changes
101 // to the physical representation is done via the tainting mechenism.
102 protected object m_linksetActivityLock = new Object();
103
104 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
105 public float LinksetMass { get; protected set; }
106
107 public virtual bool LinksetIsColliding { get { return false; } }
108
109 public OMV.Vector3 CenterOfMass
110 {
111 get { return ComputeLinksetCenterOfMass(); }
112 }
113
114 public OMV.Vector3 GeometricCenter
115 {
116 get { return ComputeLinksetGeometricCenter(); }
117 }
118
119 protected BSLinkset(BSScene scene, BSPrimLinkable parent)
120 {
121 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++;
123 // We create LOTS of linksets.
124 if (m_nextLinksetID <= 0)
125 m_nextLinksetID = 1;
126 m_physicsScene = scene;
127 LinksetRoot = parent;
128 m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>();
129 LinksetMass = parent.RawMass;
130 Rebuilding = false;
131 RebuildScheduled = false;
132
133 parent.ClearDisplacement();
134 }
135
136 // Link to a linkset where the child knows the parent.
137 // Parent changing should not happen so do some sanity checking.
138 // We return the parent's linkset so the child can track its membership.
139 // Called at runtime.
140 public BSLinkset AddMeToLinkset(BSPrimLinkable child)
141 {
142 lock (m_linksetActivityLock)
143 {
144 // Don't add the root to its own linkset
145 if (!IsRoot(child))
146 AddChildToLinkset(child);
147 LinksetMass = ComputeLinksetMass();
148 }
149 return this;
150 }
151
152 // Remove a child from a linkset.
153 // Returns a new linkset for the child which is a linkset of one (just the
154 // orphened child).
155 // Called at runtime.
156 public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
157 {
158 lock (m_linksetActivityLock)
159 {
160 if (IsRoot(child))
161 {
162 // Cannot remove the root from a linkset.
163 return this;
164 }
165 RemoveChildFromLinkset(child, inTaintTime);
166 LinksetMass = ComputeLinksetMass();
167 }
168
169 // The child is down to a linkset of just itself
170 return BSLinkset.Factory(m_physicsScene, child);
171 }
172
173 // Return 'true' if the passed object is the root object of this linkset
174 public bool IsRoot(BSPrimLinkable requestor)
175 {
176 return (requestor.LocalID == LinksetRoot.LocalID);
177 }
178
179 public int NumberOfChildren { get { return m_children.Count; } }
180
181 // Return 'true' if this linkset has any children (more than the root member)
182 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
183
184 // Return 'true' if this child is in this linkset
185 public bool HasChild(BSPrimLinkable child)
186 {
187 bool ret = false;
188 lock (m_linksetActivityLock)
189 {
190 ret = m_children.ContainsKey(child);
191 }
192 return ret;
193 }
194
195 // Perform an action on each member of the linkset including root prim.
196 // Depends on the action on whether this should be done at taint time.
197 public delegate bool ForEachMemberAction(BSPrimLinkable obj);
198 public virtual bool ForEachMember(ForEachMemberAction action)
199 {
200 bool ret = false;
201 lock (m_linksetActivityLock)
202 {
203 action(LinksetRoot);
204 foreach (BSPrimLinkable po in m_children.Keys)
205 {
206 if (action(po))
207 break;
208 }
209 }
210 return ret;
211 }
212
213 public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo)
214 {
215 bool ret = false;
216 BSLinkInfo found = null;
217 lock (m_linksetActivityLock)
218 {
219 ret = m_children.TryGetValue(child, out found);
220 }
221 foundInfo = found;
222 return ret;
223 }
224 // Perform an action on each member of the linkset including root prim.
225 // Depends on the action on whether this should be done at taint time.
226 public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
227 public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
228 {
229 bool ret = false;
230 lock (m_linksetActivityLock)
231 {
232 foreach (BSLinkInfo po in m_children.Values)
233 {
234 if (action(po))
235 break;
236 }
237 }
238 return ret;
239 }
240
241 // Check the type of the link and return 'true' if the link is flexible and the
242 // updates from the child should be sent to the simulator so things change.
243 public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child)
244 {
245 bool ret = false;
246
247 BSLinkInfo linkInfo;
248 if (m_children.TryGetValue(child, out linkInfo))
249 {
250 ret = linkInfo.ShouldUpdateChildProperties();
251 }
252
253 return ret;
254 }
255
256 // Called after a simulation step to post a collision with this object.
257 // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
258 // anything to add for the collision and it should be passed through normal processing.
259 // Default processing for a linkset.
260 public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee,
261 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
262 {
263 bool ret = false;
264
265 // prims in the same linkset cannot collide with each other
266 BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
267 if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
268 {
269 // By returning 'true', we tell the caller the collision has been 'handled' so it won't
270 // do anything about this collision and thus, effectivily, ignoring the collision.
271 ret = true;
272 }
273 else
274 {
275 // Not a collision between members of the linkset. Must be a real collision.
276 // So the linkset root can know if there is a collision anywhere in the linkset.
277 LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
278 }
279
280 return ret;
281 }
282
283 // I am the root of a linkset and a new child is being added
284 // Called while LinkActivity is locked.
285 protected abstract void AddChildToLinkset(BSPrimLinkable child);
286
287 // I am the root of a linkset and one of my children is being removed.
288 // Safe to call even if the child is not really in my linkset.
289 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime);
290
291 // When physical properties are changed the linkset needs to recalculate
292 // its internal properties.
293 // May be called at runtime or taint-time.
294 public virtual void Refresh(BSPrimLinkable requestor)
295 {
296 LinksetMass = ComputeLinksetMass();
297 }
298
299 // Flag denoting the linkset is in the process of being rebuilt.
300 // Used to know not the schedule a rebuild in the middle of a rebuild.
301 // Because of potential update calls that could want to schedule another rebuild.
302 protected bool Rebuilding { get; set; }
303
304 // Flag saying a linkset rebuild has been scheduled.
305 // This is turned on when the rebuild is requested and turned off when
306 // the rebuild is complete. Used to limit modifications to the
307 // linkset parameters while the linkset is in an intermediate state.
308 // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object
309 public bool RebuildScheduled { get; protected set; }
310
311 // The object is going dynamic (physical). Do any setup necessary
312 // for a dynamic linkset.
313 // Only the state of the passed object can be modified. The rest of the linkset
314 // has not yet been fully constructed.
315 // Return 'true' if any properties updated on the passed object.
316 // Called at taint-time!
317 public abstract bool MakeDynamic(BSPrimLinkable child);
318
319 public virtual bool AllPartsComplete
320 {
321 get {
322 bool ret = true;
323 this.ForEachMember((member) =>
324 {
325 if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting)
326 {
327 ret = false;
328 return true; // exit loop
329 }
330 return false; // continue loop
331 });
332 return ret;
333 }
334 }
335
336 // The object is going static (non-physical). Do any setup necessary
337 // for a static linkset.
338 // Return 'true' if any properties updated on the passed object.
339 // Called at taint-time!
340 public abstract bool MakeStatic(BSPrimLinkable child);
341
342 // Called when a parameter update comes from the physics engine for any object
343 // of the linkset is received.
344 // Passed flag is update came from physics engine (true) or the user (false).
345 // Called at taint-time!!
346 public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
347
348 // Routine used when rebuilding the body of the root of the linkset
349 // Destroy all the constraints have have been made to root.
350 // This is called when the root body is changing.
351 // Returns 'true' of something was actually removed and would need restoring
352 // Called at taint-time!!
353 public abstract bool RemoveDependencies(BSPrimLinkable child);
354
355 // ================================================================
356 // Some physical setting happen to all members of the linkset
357 public virtual void SetPhysicalFriction(float friction)
358 {
359 ForEachMember((member) =>
360 {
361 if (member.PhysBody.HasPhysicalBody)
362 m_physicsScene.PE.SetFriction(member.PhysBody, friction);
363 return false; // 'false' says to continue looping
364 }
365 );
366 }
367 public virtual void SetPhysicalRestitution(float restitution)
368 {
369 ForEachMember((member) =>
370 {
371 if (member.PhysBody.HasPhysicalBody)
372 m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
373 return false; // 'false' says to continue looping
374 }
375 );
376 }
377 public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
378 {
379 ForEachMember((member) =>
380 {
381 if (member.PhysBody.HasPhysicalBody)
382 m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
383 return false; // 'false' says to continue looping
384 }
385 );
386 }
387 public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
388 {
389 ForEachMember((member) =>
390 {
391 if (member.PhysBody.HasPhysicalBody)
392 {
393 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass);
394 member.Inertia = inertia * inertiaFactor;
395 m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia);
396 m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
397 DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia);
398
399 }
400 return false; // 'false' says to continue looping
401 }
402 );
403 }
404 public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
405 {
406 ForEachMember((member) =>
407 {
408 if (member.PhysBody.HasPhysicalBody)
409 m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
410 return false; // 'false' says to continue looping
411 }
412 );
413 }
414 public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
415 {
416 ForEachMember((member) =>
417 {
418 if (member.PhysBody.HasPhysicalBody)
419 m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags);
420 return false; // 'false' says to continue looping
421 }
422 );
423 }
424 public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
425 {
426 ForEachMember((member) =>
427 {
428 if (member.PhysBody.HasPhysicalBody)
429 m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
430 return false; // 'false' says to continue looping
431 }
432 );
433 }
434 // ================================================================
435 protected virtual float ComputeLinksetMass()
436 {
437 float mass = LinksetRoot.RawMass;
438 if (HasAnyChildren)
439 {
440 lock (m_linksetActivityLock)
441 {
442 foreach (BSPrimLinkable bp in m_children.Keys)
443 {
444 mass += bp.RawMass;
445 }
446 }
447 }
448 return mass;
449 }
450
451 // Computes linkset's center of mass in world coordinates.
452 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
453 {
454 OMV.Vector3 com;
455 lock (m_linksetActivityLock)
456 {
457 com = LinksetRoot.Position * LinksetRoot.RawMass;
458 float totalMass = LinksetRoot.RawMass;
459
460 foreach (BSPrimLinkable bp in m_children.Keys)
461 {
462 com += bp.Position * bp.RawMass;
463 totalMass += bp.RawMass;
464 }
465 if (totalMass != 0f)
466 com /= totalMass;
467 }
468
469 return com;
470 }
471
472 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
473 {
474 OMV.Vector3 com;
475 lock (m_linksetActivityLock)
476 {
477 com = LinksetRoot.Position;
478
479 foreach (BSPrimLinkable bp in m_children.Keys)
480 {
481 com += bp.Position;
482 }
483 com /= (m_children.Count + 1);
484 }
485
486 return com;
487 }
488
489 #region Extension
490 public virtual object Extension(string pFunct, params object[] pParams)
491 {
492 return null;
493 }
494 #endregion // Extension
495
496 // Invoke the detailed logger and output something if it's enabled.
497 protected void DetailLog(string msg, params Object[] args)
498 {
499 if (m_physicsScene.PhysicsLogging.Enabled)
500 m_physicsScene.DetailLog(msg, args);
501 }
502}
503}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
new file mode 100755
index 0000000..953ddee
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
@@ -0,0 +1,477 @@
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.PhysicsModule.BulletS
36{
37
38public sealed class BSLinksetCompound : BSLinkset
39{
40#pragma warning disable 414
41 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
42#pragma warning restore 414
43
44 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
45 : base(scene, parent)
46 {
47 LinksetImpl = LinksetImplementation.Compound;
48 }
49
50 // ================================================================
51 // Changing the physical property of the linkset only needs to change the root
52 public override void SetPhysicalFriction(float friction)
53 {
54 if (LinksetRoot.PhysBody.HasPhysicalBody)
55 m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
56 }
57 public override void SetPhysicalRestitution(float restitution)
58 {
59 if (LinksetRoot.PhysBody.HasPhysicalBody)
60 m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
61 }
62 public override void SetPhysicalGravity(OMV.Vector3 gravity)
63 {
64 if (LinksetRoot.PhysBody.HasPhysicalBody)
65 m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
66 }
67 public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
68 {
69 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass);
70 LinksetRoot.Inertia = inertia * inertiaFactor;
71 m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia);
72 m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
73 }
74 public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
75 {
76 if (LinksetRoot.PhysBody.HasPhysicalBody)
77 m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
78 }
79 public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
80 {
81 if (LinksetRoot.PhysBody.HasPhysicalBody)
82 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags);
83 }
84 public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
85 {
86 if (LinksetRoot.PhysBody.HasPhysicalBody)
87 m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
88 }
89 // ================================================================
90
91 // When physical properties are changed the linkset needs to recalculate
92 // its internal properties.
93 public override void Refresh(BSPrimLinkable requestor)
94 {
95 // Something changed so do the rebuilding thing
96 ScheduleRebuild(requestor);
97 base.Refresh(requestor);
98 }
99
100 // Schedule a refresh to happen after all the other taint processing.
101 private void ScheduleRebuild(BSPrimLinkable requestor)
102 {
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 lock (m_linksetActivityLock)
107 {
108 if (!RebuildScheduled && !Rebuilding && HasAnyChildren)
109 {
110 InternalScheduleRebuild(requestor);
111 }
112 }
113 }
114
115 // Must be called with m_linksetActivityLock or race conditions will haunt you.
116 private void InternalScheduleRebuild(BSPrimLinkable requestor)
117 {
118 DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}",
119 requestor.LocalID, Rebuilding, HasAnyChildren);
120 RebuildScheduled = true;
121 m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
122 {
123 if (HasAnyChildren)
124 {
125 if (this.AllPartsComplete)
126 {
127 RecomputeLinksetCompound();
128 }
129 else
130 {
131 DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete",
132 requestor.LocalID);
133 InternalScheduleRebuild(requestor);
134 }
135 }
136 RebuildScheduled = false;
137 });
138 }
139
140 // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
141 // Only the state of the passed object can be modified. The rest of the linkset
142 // has not yet been fully constructed.
143 // Return 'true' if any properties updated on the passed object.
144 // Called at taint-time!
145 public override bool MakeDynamic(BSPrimLinkable child)
146 {
147 bool ret = false;
148 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
149 if (IsRoot(child))
150 {
151 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
152 Refresh(LinksetRoot);
153 }
154 return ret;
155 }
156
157 // The object is going static (non-physical). We do not do anything for static linksets.
158 // Return 'true' if any properties updated on the passed object.
159 // Called at taint-time!
160 public override bool MakeStatic(BSPrimLinkable child)
161 {
162 bool ret = false;
163
164 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
165 child.ClearDisplacement();
166 if (IsRoot(child))
167 {
168 // Schedule a rebuild to verify that the root shape is set to the real shape.
169 Refresh(LinksetRoot);
170 }
171 return ret;
172 }
173
174 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
175 // Called at taint-time.
176 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
177 {
178 if (!LinksetRoot.IsPhysicallyActive)
179 {
180 // No reason to do this physical stuff for static linksets.
181 DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
182 return;
183 }
184
185 // The user moving a child around requires the rebuilding of the linkset compound shape
186 // One problem is this happens when a border is crossed -- the simulator implementation
187 // stores the position into the group which causes the move of the object
188 // but it also means all the child positions get updated.
189 // What would cause an unnecessary rebuild so we make sure the linkset is in a
190 // region before bothering to do a rebuild.
191 if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
192 {
193 // If a child of the linkset is updating only the position or rotation, that can be done
194 // without rebuilding the linkset.
195 // If a handle for the child can be fetch, we update the child here. If a rebuild was
196 // scheduled by someone else, the rebuild will just replace this setting.
197
198 bool updatedChild = false;
199 // Anything other than updating position or orientation usually means a physical update
200 // and that is caused by us updating the object.
201 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
202 {
203 // Find the physical instance of the child
204 if (!RebuildScheduled // if rebuilding, let the rebuild do it
205 && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change
206 && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned
207 && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
208 {
209 // It is possible that the linkset is still under construction and the child is not yet
210 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
211 // build the whole thing with the new position or rotation.
212 // The index must be checked because Bullet references the child array but does no validity
213 // checking of the child index passed.
214 int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
215 if (updated.LinksetChildIndex < numLinksetChildren)
216 {
217 BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
218 if (linksetChildShape.HasPhysicalShape)
219 {
220 // Found the child shape within the compound shape
221 m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
222 updated.RawPosition - LinksetRoot.RawPosition,
223 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
224 true /* shouldRecalculateLocalAabb */);
225 updatedChild = true;
226 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
227 updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
228 }
229 else // DEBUG DEBUG
230 { // DEBUG DEBUG
231 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
232 updated.LocalID, linksetChildShape);
233 } // DEBUG DEBUG
234 }
235 else // DEBUG DEBUG
236 { // DEBUG DEBUG
237 // the child is not yet in the compound shape. This is non-fatal.
238 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
239 updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
240 } // DEBUG DEBUG
241 }
242 else // DEBUG DEBUG
243 { // DEBUG DEBUG
244 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
245 } // DEBUG DEBUG
246
247 if (!updatedChild)
248 {
249 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
250 // Note: there are several ways through this code that will not update the child if
251 // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
252 // there will already be a rebuild scheduled.
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
254 updated.LocalID, whichUpdated);
255 Refresh(updated);
256 }
257 }
258 }
259 }
260
261 // Routine called when rebuilding the body of some member of the linkset.
262 // If one of the bodies is being changed, the linkset needs rebuilding.
263 // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
264 // Returns 'true' of something was actually removed and would need restoring
265 // Called at taint-time!!
266 public override bool RemoveDependencies(BSPrimLinkable child)
267 {
268 bool ret = false;
269
270 DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
271 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
272
273 Refresh(child);
274
275 return ret;
276 }
277
278 // ================================================================
279
280 // Add a new child to the linkset.
281 // Called while LinkActivity is locked.
282 protected override void AddChildToLinkset(BSPrimLinkable child)
283 {
284 if (!HasChild(child))
285 {
286 m_children.Add(child, new BSLinkInfo(child));
287
288 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
289
290 // Rebuild the compound shape with the new child shape included
291 Refresh(child);
292 }
293 return;
294 }
295
296 // Remove the specified child from the linkset.
297 // Safe to call even if the child is not really in the linkset.
298 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
299 {
300 child.ClearDisplacement();
301
302 if (m_children.Remove(child))
303 {
304 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
305 child.LocalID,
306 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
307 child.LocalID, child.PhysBody.AddrString);
308
309 // Cause the child's body to be rebuilt and thus restored to normal operation
310 child.ForceBodyShapeRebuild(inTaintTime);
311
312 if (!HasAnyChildren)
313 {
314 // The linkset is now empty. The root needs rebuilding.
315 LinksetRoot.ForceBodyShapeRebuild(inTaintTime);
316 }
317 else
318 {
319 // Rebuild the compound shape with the child removed
320 Refresh(LinksetRoot);
321 }
322 }
323 return;
324 }
325
326 // Called before the simulation step to make sure the compound based linkset
327 // is all initialized.
328 // Constraint linksets are rebuilt every time.
329 // Note that this works for rebuilding just the root after a linkset is taken apart.
330 // Called at taint time!!
331 private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
332 private void RecomputeLinksetCompound()
333 {
334 try
335 {
336 Rebuilding = true;
337
338 // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
339 // to what they should be as if the root was not in a linkset.
340 // Not that bad since we only get into this routine if there are children in the linkset and
341 // something has been updated/changed.
342 // Have to do the rebuild before checking for physical because this might be a linkset
343 // being destructed and going non-physical.
344 LinksetRoot.ForceBodyShapeRebuild(true);
345
346 // There is no reason to build all this physical stuff for a non-physical or empty linkset.
347 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
348 {
349 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
350 return; // Note the 'finally' clause at the botton which will get executed.
351 }
352
353 // Get a new compound shape to build the linkset shape in.
354 BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
355
356 // Compute a displacement for each component so it is relative to the center-of-mass.
357 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
358 OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
359
360 OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
361 OMV.Vector3 origRootPosition = LinksetRoot.RawPosition;
362
363 // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass
364 OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
365 if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass)
366 {
367 // Zero everything if center-of-mass displacement is not being done.
368 centerDisplacementV = OMV.Vector3.Zero;
369 LinksetRoot.ClearDisplacement();
370 }
371 else
372 {
373 // The actual center-of-mass could have been set by the user.
374 centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
375 }
376
377 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
378 LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV);
379
380 // Add the shapes of all the components of the linkset
381 int memberIndex = 1;
382 ForEachMember((cPrim) =>
383 {
384 if (IsRoot(cPrim))
385 {
386 // Root shape is always index zero.
387 cPrim.LinksetChildIndex = 0;
388 }
389 else
390 {
391 cPrim.LinksetChildIndex = memberIndex;
392 memberIndex++;
393 }
394
395 // Get a reference to the shape of the child for adding of that shape to the linkset compound shape
396 BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
397
398 // Offset the child shape from the center-of-mass and rotate it to root relative.
399 OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV;
400 OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
401
402 // Add the child shape to the compound shape being built
403 if (childShape.physShapeInfo.HasPhysicalShape)
404 {
405 m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
406 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
407 LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
408
409 // Since we are borrowing the shape of the child, disable the origional child body
410 if (!IsRoot(cPrim))
411 {
412 m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
413 m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
414 // We don't want collisions from the old linkset children.
415 m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
416 cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
417 }
418 }
419 else
420 {
421 // The linkset must be in an intermediate state where all the children have not yet
422 // been constructed. This sometimes happens on startup when everything is getting
423 // built and some shapes have to wait for assets to be read in.
424 // Just skip this linkset for the moment and cause the shape to be rebuilt next tick.
425 // One problem might be that the shape is broken somehow and it never becomes completely
426 // available. This might cause the rebuild to happen over and over.
427 InternalScheduleRebuild(LinksetRoot);
428 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}",
429 LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
430 // Output an annoying warning. It should only happen once but if it keeps coming out,
431 // the user knows there is something wrong and will report it.
432 m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader);
433 m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}",
434 LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape);
435
436 // This causes the loop to bail on building the rest of this linkset.
437 // The rebuild operation will fix it up next tick or declare the object unbuildable.
438 return true;
439 }
440
441 return false; // 'false' says to move onto the next child in the list
442 });
443
444 // Replace the root shape with the built compound shape.
445 // Object removed and added to world to get collision cache rebuilt for new shape.
446 LinksetRoot.PhysShape.Dereference(m_physicsScene);
447 LinksetRoot.PhysShape = linksetShape;
448 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
449 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
450 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
451 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
452 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
453
454 // With all of the linkset packed into the root prim, it has the mass of everyone.
455 LinksetMass = ComputeLinksetMass();
456 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
457
458 if (UseBulletSimRootOffsetHack)
459 {
460 // Enable the physical position updator to return the position and rotation of the root shape.
461 // This enables a feature in the C++ code to return the world coordinates of the first shape in the
462 // compound shape. This aleviates the need to offset the returned physical position by the
463 // center-of-mass offset.
464 // TODO: either debug this feature or remove it.
465 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
466 }
467 }
468 finally
469 {
470 Rebuilding = false;
471 }
472
473 // See that the Aabb surrounds the new shape
474 m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
475 }
476}
477} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs
new file mode 100755
index 0000000..c4b4c86
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs
@@ -0,0 +1,852 @@
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.PhysicsModule.BulletS
34{
35public sealed class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public class BSLinkInfoConstraint : BSLinkInfo
40 {
41 public ConstraintType constraintType;
42 public BSConstraint constraint;
43 public OMV.Vector3 linearLimitLow;
44 public OMV.Vector3 linearLimitHigh;
45 public OMV.Vector3 angularLimitLow;
46 public OMV.Vector3 angularLimitHigh;
47 public bool useFrameOffset;
48 public bool enableTransMotor;
49 public float transMotorMaxVel;
50 public float transMotorMaxForce;
51 public float cfm;
52 public float erp;
53 public float solverIterations;
54 //
55 public OMV.Vector3 frameInAloc;
56 public OMV.Quaternion frameInArot;
57 public OMV.Vector3 frameInBloc;
58 public OMV.Quaternion frameInBrot;
59 public bool useLinearReferenceFrameA;
60 // Spring
61 public bool[] springAxisEnable;
62 public float[] springDamping;
63 public float[] springStiffness;
64 public OMV.Vector3 springLinearEquilibriumPoint;
65 public OMV.Vector3 springAngularEquilibriumPoint;
66
67 public BSLinkInfoConstraint(BSPrimLinkable pMember)
68 : base(pMember)
69 {
70 constraint = null;
71 ResetLink();
72 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID);
73 }
74
75 // Set all the parameters for this constraint to a fixed, non-movable constraint.
76 public override void ResetLink()
77 {
78 // constraintType = ConstraintType.D6_CONSTRAINT_TYPE;
79 constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE;
80 linearLimitLow = OMV.Vector3.Zero;
81 linearLimitHigh = OMV.Vector3.Zero;
82 angularLimitLow = OMV.Vector3.Zero;
83 angularLimitHigh = OMV.Vector3.Zero;
84 useFrameOffset = BSParam.LinkConstraintUseFrameOffset;
85 enableTransMotor = BSParam.LinkConstraintEnableTransMotor;
86 transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
87 transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
88 cfm = BSParam.LinkConstraintCFM;
89 erp = BSParam.LinkConstraintERP;
90 solverIterations = BSParam.LinkConstraintSolverIterations;
91 frameInAloc = OMV.Vector3.Zero;
92 frameInArot = OMV.Quaternion.Identity;
93 frameInBloc = OMV.Vector3.Zero;
94 frameInBrot = OMV.Quaternion.Identity;
95 useLinearReferenceFrameA = true;
96 springAxisEnable = new bool[6];
97 springDamping = new float[6];
98 springStiffness = new float[6];
99 for (int ii = 0; ii < springAxisEnable.Length; ii++)
100 {
101 springAxisEnable[ii] = false;
102 springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
103 springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
104 }
105 springLinearEquilibriumPoint = OMV.Vector3.Zero;
106 springAngularEquilibriumPoint = OMV.Vector3.Zero;
107 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID);
108 }
109
110 // Given a constraint, apply the current constraint parameters to same.
111 public override void SetLinkParameters(BSConstraint constrain)
112 {
113 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType);
114 switch (constraintType)
115 {
116 case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
117 case ConstraintType.D6_CONSTRAINT_TYPE:
118 BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof;
119 if (constrain6dof != null)
120 {
121 // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code.
122 // zero linear and angular limits makes the objects unable to move in relation to each other
123 constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh);
124 constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh);
125
126 // tweek the constraint to increase stability
127 constrain6dof.UseFrameOffset(useFrameOffset);
128 constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
129 constrain6dof.SetCFMAndERP(cfm, erp);
130 if (solverIterations != 0f)
131 {
132 constrain6dof.SetSolverIterations(solverIterations);
133 }
134 }
135 break;
136 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
137 BSConstraintSpring constrainSpring = constrain as BSConstraintSpring;
138 if (constrainSpring != null)
139 {
140 // zero linear and angular limits makes the objects unable to move in relation to each other
141 constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh);
142 constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh);
143
144 // tweek the constraint to increase stability
145 constrainSpring.UseFrameOffset(useFrameOffset);
146 constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
147 constrainSpring.SetCFMAndERP(cfm, erp);
148 if (solverIterations != 0f)
149 {
150 constrainSpring.SetSolverIterations(solverIterations);
151 }
152 for (int ii = 0; ii < springAxisEnable.Length; ii++)
153 {
154 constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]);
155 if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
156 constrainSpring.SetDamping(ii, springDamping[ii]);
157 if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
158 constrainSpring.SetStiffness(ii, springStiffness[ii]);
159 }
160 constrainSpring.CalculateTransforms();
161
162 if (springLinearEquilibriumPoint != OMV.Vector3.Zero)
163 constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint);
164 else
165 constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED);
166 }
167 break;
168 default:
169 break;
170 }
171 }
172
173 // Return 'true' if the property updates from the physics engine should be reported
174 // to the simulator.
175 // If the constraint is fixed, we don't need to report as the simulator and viewer will
176 // report the right things.
177 public override bool ShouldUpdateChildProperties()
178 {
179 bool ret = true;
180 if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE)
181 ret = false;
182
183 return ret;
184 }
185 }
186
187 public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
188 {
189 LinksetImpl = LinksetImplementation.Constraint;
190 }
191
192 private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]";
193
194 // When physical properties are changed the linkset needs to recalculate
195 // its internal properties.
196 // This is queued in the 'post taint' queue so the
197 // refresh will happen once after all the other taints are applied.
198 public override void Refresh(BSPrimLinkable requestor)
199 {
200 ScheduleRebuild(requestor);
201 base.Refresh(requestor);
202
203 }
204
205 private void ScheduleRebuild(BSPrimLinkable requestor)
206 {
207 DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
208 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
209
210 // When rebuilding, it is possible to set properties that would normally require a rebuild.
211 // If already rebuilding, don't request another rebuild.
212 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
213 lock (this)
214 {
215 if (!RebuildScheduled)
216 {
217 if (!Rebuilding && HasAnyChildren)
218 {
219 RebuildScheduled = true;
220 // Queue to happen after all the other taint processing
221 m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
222 {
223 if (HasAnyChildren)
224 {
225 // Constraints that have not been changed are not rebuild but make sure
226 // the constraint of the requestor is rebuilt.
227 PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor);
228 // Rebuild the linkset and all its constraints.
229 RecomputeLinksetConstraints();
230 }
231 RebuildScheduled = false;
232 });
233 }
234 }
235 }
236 }
237
238 // The object is going dynamic (physical). Do any setup necessary
239 // for a dynamic linkset.
240 // Only the state of the passed object can be modified. The rest of the linkset
241 // has not yet been fully constructed.
242 // Return 'true' if any properties updated on the passed object.
243 // Called at taint-time!
244 public override bool MakeDynamic(BSPrimLinkable child)
245 {
246 bool ret = false;
247 DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
248 if (IsRoot(child))
249 {
250 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
251 Refresh(LinksetRoot);
252 }
253 return ret;
254 }
255
256 // The object is going static (non-physical). Do any setup necessary for a static linkset.
257 // Return 'true' if any properties updated on the passed object.
258 // This doesn't normally happen -- OpenSim removes the objects from the physical
259 // world if it is a static linkset.
260 // Called at taint-time!
261 public override bool MakeStatic(BSPrimLinkable child)
262 {
263 bool ret = false;
264
265 DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
266 child.ClearDisplacement();
267 if (IsRoot(child))
268 {
269 // Schedule a rebuild to verify that the root shape is set to the real shape.
270 Refresh(LinksetRoot);
271 }
272 return ret;
273 }
274
275 // Called at taint-time!!
276 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj)
277 {
278 // Nothing to do for constraints on property updates
279 }
280
281 // Routine called when rebuilding the body of some member of the linkset.
282 // Destroy all the constraints have have been made to root and set
283 // up to rebuild the constraints before the next simulation step.
284 // Returns 'true' of something was actually removed and would need restoring
285 // Called at taint-time!!
286 public override bool RemoveDependencies(BSPrimLinkable child)
287 {
288 bool ret = false;
289
290 DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
291 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
292
293 lock (m_linksetActivityLock)
294 {
295 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
296 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
297 // Cause the constraints, et al to be rebuilt before the next simulation step.
298 Refresh(LinksetRoot);
299 }
300 return ret;
301 }
302
303 // ================================================================
304
305 // Add a new child to the linkset.
306 // Called while LinkActivity is locked.
307 protected override void AddChildToLinkset(BSPrimLinkable child)
308 {
309 if (!HasChild(child))
310 {
311 m_children.Add(child, new BSLinkInfoConstraint(child));
312
313 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
314
315 // Cause constraints and assorted properties to be recomputed before the next simulation step.
316 Refresh(LinksetRoot);
317 }
318 return;
319 }
320
321 // Remove the specified child from the linkset.
322 // Safe to call even if the child is not really in my linkset.
323 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
324 {
325 if (m_children.Remove(child))
326 {
327 BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now
328 BSPrimLinkable childx = child;
329
330 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
331 childx.LocalID,
332 rootx.LocalID, rootx.PhysBody.AddrString,
333 childx.LocalID, childx.PhysBody.AddrString);
334
335 m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate()
336 {
337 PhysicallyUnlinkAChildFromRoot(rootx, childx);
338 });
339 // See that the linkset parameters are recomputed at the end of the taint time.
340 Refresh(LinksetRoot);
341 }
342 else
343 {
344 // Non-fatal occurance.
345 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
346 }
347 return;
348 }
349
350 // Create a constraint between me (root of linkset) and the passed prim (the child).
351 // Called at taint time!
352 private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
353 {
354 // Don't build the constraint when asked. Put it off until just before the simulation step.
355 Refresh(rootPrim);
356 }
357
358 // Create a static constraint between the two passed objects
359 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li)
360 {
361 BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint;
362 if (linkInfo == null)
363 return null;
364
365 // Zero motion for children so they don't interpolate
366 li.member.ZeroMotion(true);
367
368 BSConstraint constrain = null;
369
370 switch (linkInfo.constraintType)
371 {
372 case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
373 case ConstraintType.D6_CONSTRAINT_TYPE:
374 // Relative position normalized to the root prim
375 // Essentually a vector pointing from center of rootPrim to center of li.member
376 OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position;
377
378 // real world coordinate of midpoint between the two objects
379 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
380
381 DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}",
382 rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody,
383 rootPrim.Position, linkInfo.member.Position, midPoint);
384
385 // create a constraint that allows no freedom of movement between the two objects
386 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
387
388 constrain = new BSConstraint6Dof(
389 m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true );
390
391 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
392 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
393 * of the objects.
394 * Code left for future programmers.
395 // ==================================================================================
396 // relative position normalized to the root prim
397 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
398 OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation;
399
400 // relative rotation of the child to the parent
401 OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation;
402 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
403
404 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID);
405 constrain = new BS6DofConstraint(
406 PhysicsScene.World, rootPrim.Body, liConstraint.member.Body,
407 OMV.Vector3.Zero,
408 OMV.Quaternion.Inverse(rootPrim.Orientation),
409 OMV.Vector3.Zero,
410 OMV.Quaternion.Inverse(liConstraint.member.Orientation),
411 true,
412 true
413 );
414 // ==================================================================================
415 */
416
417 break;
418 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
419 constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody,
420 linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot,
421 linkInfo.useLinearReferenceFrameA,
422 true /*disableCollisionsBetweenLinkedBodies*/);
423 DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}",
424 rootPrim.LocalID,
425 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
426 linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString,
427 rootPrim.Position, linkInfo.member.Position);
428
429 break;
430 default:
431 break;
432 }
433
434 linkInfo.SetLinkParameters(constrain);
435
436 m_physicsScene.Constraints.AddConstraint(constrain);
437
438 return constrain;
439 }
440
441 // Remove linkage between the linkset root and a particular child
442 // The root and child bodies are passed in because we need to remove the constraint between
443 // the bodies that were present at unlink time.
444 // Called at taint time!
445 private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
446 {
447 bool ret = false;
448 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
449 rootPrim.LocalID,
450 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
451 childPrim.LocalID, childPrim.PhysBody.AddrString);
452
453 // If asked to unlink root from root, just remove all the constraints
454 if (rootPrim == childPrim || childPrim == LinksetRoot)
455 {
456 PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
457 ret = true;
458 }
459 else
460 {
461 // Find the constraint for this link and get rid of it from the overall collection and from my list
462 if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
463 {
464 // Make the child refresh its location
465 m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
466 ret = true;
467 }
468 }
469
470 return ret;
471 }
472
473 // Remove linkage between myself and any possible children I might have.
474 // Returns 'true' of any constraints were destroyed.
475 // Called at taint time!
476 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim)
477 {
478 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
479
480 return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
481 }
482
483 // Call each of the constraints that make up this linkset and recompute the
484 // various transforms and variables. Create constraints of not created yet.
485 // Called before the simulation step to make sure the constraint based linkset
486 // is all initialized.
487 // Called at taint time!!
488 private void RecomputeLinksetConstraints()
489 {
490 float linksetMass = LinksetMass;
491 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
492
493 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
494 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
495
496 try
497 {
498 Rebuilding = true;
499
500 // There is no reason to build all this physical stuff for a non-physical linkset.
501 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
502 {
503 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
504 return; // Note the 'finally' clause at the botton which will get executed.
505 }
506
507 ForEachLinkInfo((li) =>
508 {
509 // A child in the linkset physically shows the mass of the whole linkset.
510 // This allows Bullet to apply enough force on the child to move the whole linkset.
511 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
512 li.member.UpdatePhysicalMassProperties(linksetMass, true);
513
514 BSConstraint constrain;
515 if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain))
516 {
517 // If constraint doesn't exist yet, create it.
518 constrain = BuildConstraint(LinksetRoot, li);
519 }
520 li.SetLinkParameters(constrain);
521 constrain.RecomputeConstraintVariables(linksetMass);
522
523 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
524 return false; // 'false' says to keep processing other members
525 });
526 }
527 finally
528 {
529 Rebuilding = false;
530 }
531 }
532
533 #region Extension
534 public override object Extension(string pFunct, params object[] pParams)
535 {
536 object ret = null;
537 switch (pFunct)
538 {
539 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
540 case ExtendedPhysics.PhysFunctChangeLinkType:
541 if (pParams.Length > 2)
542 {
543 int requestedType = (int)pParams[2];
544 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType);
545 if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE
546 || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE
547 || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE
548 || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE
549 || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE
550 || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE)
551 {
552 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
553 if (child != null)
554 {
555 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}",
556 LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType);
557 m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate()
558 {
559 // Pick up all the constraints currently created.
560 RemoveDependencies(child);
561
562 BSLinkInfo linkInfo = null;
563 if (TryGetLinkInfo(child, out linkInfo))
564 {
565 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
566 if (linkInfoC != null)
567 {
568 linkInfoC.constraintType = (ConstraintType)requestedType;
569 ret = (object)true;
570 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}",
571 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
572 }
573 else
574 {
575 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID);
576 }
577 }
578 else
579 {
580 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID);
581 }
582 // Cause the whole linkset to be rebuilt in post-taint time.
583 Refresh(child);
584 });
585 }
586 else
587 {
588 DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID);
589 }
590 }
591 else
592 {
593 DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}",
594 LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE));
595 }
596 }
597 break;
598 // pParams = [ BSPhysObject root, BSPhysObject child ]
599 case ExtendedPhysics.PhysFunctGetLinkType:
600 if (pParams.Length > 0)
601 {
602 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
603 if (child != null)
604 {
605 BSLinkInfo linkInfo = null;
606 if (TryGetLinkInfo(child, out linkInfo))
607 {
608 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
609 if (linkInfoC != null)
610 {
611 ret = (object)(int)linkInfoC.constraintType;
612 DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}",
613 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
614
615 }
616 }
617 }
618 }
619 break;
620 // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ]
621 case ExtendedPhysics.PhysFunctChangeLinkParams:
622 // There should be two parameters: the childActor and a list of parameters to set
623 if (pParams.Length > 2)
624 {
625 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
626 BSLinkInfo baseLinkInfo = null;
627 if (TryGetLinkInfo(child, out baseLinkInfo))
628 {
629 BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint;
630 if (linkInfo != null)
631 {
632 int valueInt;
633 float valueFloat;
634 bool valueBool;
635 OMV.Vector3 valueVector;
636 OMV.Vector3 valueVector2;
637 OMV.Quaternion valueQuaternion;
638 int axisLow, axisHigh;
639
640 int opIndex = 2;
641 while (opIndex < pParams.Length)
642 {
643 int thisOp = 0;
644 string errMsg = "";
645 try
646 {
647 thisOp = (int)pParams[opIndex];
648 DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}",
649 linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]);
650 switch (thisOp)
651 {
652 case ExtendedPhysics.PHYS_PARAM_LINK_TYPE:
653 valueInt = (int)pParams[opIndex + 1];
654 ConstraintType valueType = (ConstraintType)valueInt;
655 if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE
656 || valueType == ConstraintType.D6_CONSTRAINT_TYPE
657 || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE
658 || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE
659 || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE
660 || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE)
661 {
662 linkInfo.constraintType = valueType;
663 }
664 opIndex += 2;
665 break;
666 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC:
667 errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector";
668 valueVector = (OMV.Vector3)pParams[opIndex + 1];
669 linkInfo.frameInAloc = valueVector;
670 opIndex += 2;
671 break;
672 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT:
673 errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation";
674 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
675 linkInfo.frameInArot = valueQuaternion;
676 opIndex += 2;
677 break;
678 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC:
679 errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector";
680 valueVector = (OMV.Vector3)pParams[opIndex + 1];
681 linkInfo.frameInBloc = valueVector;
682 opIndex += 2;
683 break;
684 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT:
685 errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation";
686 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
687 linkInfo.frameInBrot = valueQuaternion;
688 opIndex += 2;
689 break;
690 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW:
691 errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector";
692 valueVector = (OMV.Vector3)pParams[opIndex + 1];
693 linkInfo.linearLimitLow = valueVector;
694 opIndex += 2;
695 break;
696 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH:
697 errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector";
698 valueVector = (OMV.Vector3)pParams[opIndex + 1];
699 linkInfo.linearLimitHigh = valueVector;
700 opIndex += 2;
701 break;
702 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW:
703 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector";
704 valueVector = (OMV.Vector3)pParams[opIndex + 1];
705 linkInfo.angularLimitLow = valueVector;
706 opIndex += 2;
707 break;
708 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH:
709 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector";
710 valueVector = (OMV.Vector3)pParams[opIndex + 1];
711 linkInfo.angularLimitHigh = valueVector;
712 opIndex += 2;
713 break;
714 case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET:
715 errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)";
716 valueBool = ((int)pParams[opIndex + 1]) != 0;
717 linkInfo.useFrameOffset = valueBool;
718 opIndex += 2;
719 break;
720 case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR:
721 errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)";
722 valueBool = ((int)pParams[opIndex + 1]) != 0;
723 linkInfo.enableTransMotor = valueBool;
724 opIndex += 2;
725 break;
726 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL:
727 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float";
728 valueFloat = (float)pParams[opIndex + 1];
729 linkInfo.transMotorMaxVel = valueFloat;
730 opIndex += 2;
731 break;
732 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE:
733 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float";
734 valueFloat = (float)pParams[opIndex + 1];
735 linkInfo.transMotorMaxForce = valueFloat;
736 opIndex += 2;
737 break;
738 case ExtendedPhysics.PHYS_PARAM_CFM:
739 errMsg = "PHYS_PARAM_CFM takes one parameter of type float";
740 valueFloat = (float)pParams[opIndex + 1];
741 linkInfo.cfm = valueFloat;
742 opIndex += 2;
743 break;
744 case ExtendedPhysics.PHYS_PARAM_ERP:
745 errMsg = "PHYS_PARAM_ERP takes one parameter of type float";
746 valueFloat = (float)pParams[opIndex + 1];
747 linkInfo.erp = valueFloat;
748 opIndex += 2;
749 break;
750 case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS:
751 errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float";
752 valueFloat = (float)pParams[opIndex + 1];
753 linkInfo.solverIterations = valueFloat;
754 opIndex += 2;
755 break;
756 case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE:
757 errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)";
758 valueInt = (int)pParams[opIndex + 1];
759 valueBool = ((int)pParams[opIndex + 2]) != 0;
760 GetAxisRange(valueInt, out axisLow, out axisHigh);
761 for (int ii = axisLow; ii <= axisHigh; ii++)
762 linkInfo.springAxisEnable[ii] = valueBool;
763 opIndex += 3;
764 break;
765 case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING:
766 errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float";
767 valueInt = (int)pParams[opIndex + 1];
768 valueFloat = (float)pParams[opIndex + 2];
769 GetAxisRange(valueInt, out axisLow, out axisHigh);
770 for (int ii = axisLow; ii <= axisHigh; ii++)
771 linkInfo.springDamping[ii] = valueFloat;
772 opIndex += 3;
773 break;
774 case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS:
775 errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float";
776 valueInt = (int)pParams[opIndex + 1];
777 valueFloat = (float)pParams[opIndex + 2];
778 GetAxisRange(valueInt, out axisLow, out axisHigh);
779 for (int ii = axisLow; ii <= axisHigh; ii++)
780 linkInfo.springStiffness[ii] = valueFloat;
781 opIndex += 3;
782 break;
783 case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT:
784 errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector";
785 valueVector = (OMV.Vector3)pParams[opIndex + 1];
786 valueVector2 = (OMV.Vector3)pParams[opIndex + 2];
787 linkInfo.springLinearEquilibriumPoint = valueVector;
788 linkInfo.springAngularEquilibriumPoint = valueVector2;
789 opIndex += 3;
790 break;
791 case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA:
792 errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)";
793 valueBool = ((int)pParams[opIndex + 1]) != 0;
794 linkInfo.useLinearReferenceFrameA = valueBool;
795 opIndex += 2;
796 break;
797 default:
798 break;
799 }
800 }
801 catch (InvalidCastException e)
802 {
803 m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}",
804 LogHeader, errMsg, e);
805 }
806 catch (Exception e)
807 {
808 m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e);
809 }
810 }
811 }
812 // Something changed so a rebuild is in order
813 Refresh(child);
814 }
815 }
816 break;
817 default:
818 ret = base.Extension(pFunct, pParams);
819 break;
820 }
821 return ret;
822 }
823
824 // Bullet constraints keep some limit parameters for each linear and angular axis.
825 // Setting same is easier if there is an easy way to see all or types.
826 // This routine returns the array limits for the set of axis.
827 private void GetAxisRange(int rangeSpec, out int low, out int high)
828 {
829 switch (rangeSpec)
830 {
831 case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL:
832 low = 0;
833 high = 2;
834 break;
835 case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL:
836 low = 3;
837 high = 5;
838 break;
839 case ExtendedPhysics.PHYS_AXIS_ALL:
840 low = 0;
841 high = 5;
842 break;
843 default:
844 low = high = rangeSpec;
845 break;
846 }
847 return;
848 }
849 #endregion // Extension
850
851}
852}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
new file mode 100755
index 0000000..0e44d03
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
@@ -0,0 +1,203 @@
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.PhysicsModule.BulletS
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 // Get the current attribute values for this material
184 MaterialAttributes thisAttrib = Attributes[matType];
185 // Find the field for the passed attribute name (eg, find field named 'friction')
186 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
187 if (fieldInfo != null)
188 {
189 fieldInfo.SetValue(thisAttrib, val);
190 // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
191 Attributes[matType] = thisAttrib;
192 }
193 }
194
195 // Given a material type, return a structure of attributes.
196 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
197 {
198 int ind = (int)type;
199 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
200 return Attributes[ind];
201 }
202}
203}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
new file mode 100755
index 0000000..2faf2d4
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
@@ -0,0 +1,451 @@
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.PhysicsModule.BulletS
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 PhysicsScene.DetailLog(msg, parms);
63 }
64 }
65}
66
67// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
68// The TargetValue decays in TargetValueDecayTimeScale.
69// This motor will "zero itself" over time in that the targetValue will
70// decay to zero and the currentValue will follow it to that zero.
71// The overall effect is for the returned correction value to go from large
72// values to small and eventually zero values.
73// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
74
75// For instance, if something is moving at speed X and the desired speed is Y,
76// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
77// values of CurrentValue are returned that approach the TargetValue.
78// The feature of decaying TargetValue is so vehicles will eventually
79// come to a stop rather than run forever. This can be disabled by
80// setting TargetValueDecayTimescale to 'infinite'.
81// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
82public class BSVMotor : BSMotor
83{
84 // public Vector3 FrameOfReference { get; set; }
85 // public Vector3 Offset { get; set; }
86
87 public virtual float TimeScale { get; set; }
88 public virtual float TargetValueDecayTimeScale { get; set; }
89 public virtual float Efficiency { get; set; }
90
91 public virtual float ErrorZeroThreshold { get; set; }
92
93 public virtual Vector3 TargetValue { get; protected set; }
94 public virtual Vector3 CurrentValue { get; protected set; }
95 public virtual Vector3 LastError { get; protected set; }
96
97 public virtual bool ErrorIsZero()
98 {
99 return ErrorIsZero(LastError);
100 }
101 public virtual bool ErrorIsZero(Vector3 err)
102 {
103 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
104 }
105
106 public BSVMotor(string useName)
107 : base(useName)
108 {
109 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
110 Efficiency = 1f;
111 CurrentValue = TargetValue = Vector3.Zero;
112 ErrorZeroThreshold = 0.001f;
113 }
114 public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency)
115 : this(useName)
116 {
117 TimeScale = timeScale;
118 TargetValueDecayTimeScale = decayTimeScale;
119 Efficiency = efficiency;
120 CurrentValue = TargetValue = Vector3.Zero;
121 }
122 public void SetCurrent(Vector3 current)
123 {
124 CurrentValue = current;
125 }
126 public void SetTarget(Vector3 target)
127 {
128 TargetValue = target;
129 }
130 public override void Zero()
131 {
132 base.Zero();
133 CurrentValue = TargetValue = Vector3.Zero;
134 }
135
136 // Compute the next step and return the new current value.
137 // Returns the correction needed to move 'current' to 'target'.
138 public virtual Vector3 Step(float timeStep)
139 {
140 if (!Enabled) return TargetValue;
141
142 Vector3 origTarget = TargetValue; // DEBUG
143 Vector3 origCurrVal = CurrentValue; // DEBUG
144
145 Vector3 correction = Vector3.Zero;
146 Vector3 error = TargetValue - CurrentValue;
147 if (!ErrorIsZero(error))
148 {
149 correction = StepError(timeStep, error);
150
151 CurrentValue += correction;
152
153 // The desired value reduces to zero which also reduces the difference with current.
154 // If the decay time is infinite, don't decay at all.
155 float decayFactor = 0f;
156 if (TargetValueDecayTimeScale != BSMotor.Infinite)
157 {
158 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
159 TargetValue *= (1f - decayFactor);
160 }
161
162 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
163 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
164 timeStep, error, correction);
165 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
166 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
167 }
168 else
169 {
170 // Difference between what we have and target is small. Motor is done.
171 if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
172 {
173 // The target can step down to nearly zero but not get there. If close to zero
174 // it is really zero.
175 TargetValue = Vector3.Zero;
176 }
177 CurrentValue = TargetValue;
178 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
179 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
180 }
181 LastError = error;
182
183 return correction;
184 }
185 // version of step that sets the current value before doing the step
186 public virtual Vector3 Step(float timeStep, Vector3 current)
187 {
188 CurrentValue = current;
189 return Step(timeStep);
190 }
191 // Given and error, computer a correction for this step.
192 // Simple scaling of the error by the timestep.
193 public virtual Vector3 StepError(float timeStep, Vector3 error)
194 {
195 if (!Enabled) return Vector3.Zero;
196
197 Vector3 returnCorrection = Vector3.Zero;
198 if (!ErrorIsZero(error))
199 {
200 // correction = error / secondsItShouldTakeToCorrect
201 Vector3 correctionAmount;
202 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
203 correctionAmount = error * timeStep;
204 else
205 correctionAmount = error / TimeScale * timeStep;
206
207 returnCorrection = correctionAmount;
208 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
209 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
210 }
211 return returnCorrection;
212 }
213
214 // The user sets all the parameters and calls this which outputs values until error is zero.
215 public override void GenerateTestOutput(float timeStep)
216 {
217 // maximum number of outputs to generate.
218 int maxOutput = 50;
219 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
220 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}",
221 BSScene.DetailLogZero, UseName,
222 TimeScale, TargetValueDecayTimeScale, Efficiency,
223 CurrentValue, TargetValue);
224
225 LastError = BSMotor.InfiniteVector;
226 while (maxOutput-- > 0 && !ErrorIsZero())
227 {
228 Vector3 lastStep = Step(timeStep);
229 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
230 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
231 }
232 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
233
234
235 }
236
237 public override string ToString()
238 {
239 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
240 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
241 }
242}
243
244// ============================================================================
245// ============================================================================
246public class BSFMotor : BSMotor
247{
248 public virtual float TimeScale { get; set; }
249 public virtual float TargetValueDecayTimeScale { get; set; }
250 public virtual float Efficiency { get; set; }
251
252 public virtual float ErrorZeroThreshold { get; set; }
253
254 public virtual float TargetValue { get; protected set; }
255 public virtual float CurrentValue { get; protected set; }
256 public virtual float LastError { get; protected set; }
257
258 public virtual bool ErrorIsZero()
259 {
260 return ErrorIsZero(LastError);
261 }
262 public virtual bool ErrorIsZero(float err)
263 {
264 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
265 }
266
267 public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency)
268 : base(useName)
269 {
270 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
271 Efficiency = 1f;
272 CurrentValue = TargetValue = 0f;
273 ErrorZeroThreshold = 0.01f;
274 }
275 public void SetCurrent(float current)
276 {
277 CurrentValue = current;
278 }
279 public void SetTarget(float target)
280 {
281 TargetValue = target;
282 }
283 public override void Zero()
284 {
285 base.Zero();
286 CurrentValue = TargetValue = 0f;
287 }
288
289 public virtual float Step(float timeStep)
290 {
291 if (!Enabled) return TargetValue;
292
293 float origTarget = TargetValue; // DEBUG
294 float origCurrVal = CurrentValue; // DEBUG
295
296 float correction = 0f;
297 float error = TargetValue - CurrentValue;
298 if (!ErrorIsZero(error))
299 {
300 correction = StepError(timeStep, error);
301
302 CurrentValue += correction;
303
304 // The desired value reduces to zero which also reduces the difference with current.
305 // If the decay time is infinite, don't decay at all.
306 float decayFactor = 0f;
307 if (TargetValueDecayTimeScale != BSMotor.Infinite)
308 {
309 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
310 TargetValue *= (1f - decayFactor);
311 }
312
313 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
314 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
315 timeStep, error, correction);
316 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
317 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
318 }
319 else
320 {
321 // Difference between what we have and target is small. Motor is done.
322 if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold))
323 {
324 // The target can step down to nearly zero but not get there. If close to zero
325 // it is really zero.
326 TargetValue = 0f;
327 }
328 CurrentValue = TargetValue;
329 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
330 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
331 }
332 LastError = error;
333
334 return CurrentValue;
335 }
336
337 public virtual float StepError(float timeStep, float error)
338 {
339 if (!Enabled) return 0f;
340
341 float returnCorrection = 0f;
342 if (!ErrorIsZero(error))
343 {
344 // correction = error / secondsItShouldTakeToCorrect
345 float correctionAmount;
346 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
347 correctionAmount = error * timeStep;
348 else
349 correctionAmount = error / TimeScale * timeStep;
350
351 returnCorrection = correctionAmount;
352 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
353 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
354 }
355 return returnCorrection;
356 }
357
358 public override string ToString()
359 {
360 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
361 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
362 }
363
364}
365
366// ============================================================================
367// ============================================================================
368// Proportional, Integral, Derivitive ("PID") Motor
369// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
370public class BSPIDVMotor : BSVMotor
371{
372 // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
373 public Vector3 proportionFactor { get; set; }
374 public Vector3 integralFactor { get; set; }
375 public Vector3 derivFactor { get; set; }
376
377 // The factors are vectors for the three dimensions. This is the proportional of each
378 // that is applied. This could be multiplied through the actual factors but it
379 // is sometimes easier to manipulate the factors and their mix separately.
380 public Vector3 FactorMix;
381
382 // Arbritrary factor range.
383 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
384 public float EfficiencyHigh = 0.4f;
385 public float EfficiencyLow = 4.0f;
386
387 // Running integration of the error
388 Vector3 RunningIntegration { get; set; }
389
390 public BSPIDVMotor(string useName)
391 : base(useName)
392 {
393 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
394 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
395 derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
396 FactorMix = new Vector3(0.5f, 0.25f, 0.25f);
397 RunningIntegration = Vector3.Zero;
398 LastError = Vector3.Zero;
399 }
400
401 public override void Zero()
402 {
403 base.Zero();
404 }
405
406 public override float Efficiency
407 {
408 get { return base.Efficiency; }
409 set
410 {
411 base.Efficiency = Util.Clamp(value, 0f, 1f);
412
413 // Compute factors based on efficiency.
414 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
415 // If efficiency is low (0f), use a factor value that overcorrects.
416 // TODO: might want to vary contribution of different factor depending on efficiency.
417 // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
418 float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
419
420 proportionFactor = new Vector3(factor, factor, factor);
421 integralFactor = new Vector3(factor, factor, factor);
422 derivFactor = new Vector3(factor, factor, factor);
423
424 MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
425 }
426 }
427
428 // Advance the PID computation on this error.
429 public override Vector3 StepError(float timeStep, Vector3 error)
430 {
431 if (!Enabled) return Vector3.Zero;
432
433 // Add up the error so we can integrate over the accumulated errors
434 RunningIntegration += error * timeStep;
435
436 // A simple derivitive is the rate of change from the last error.
437 Vector3 derivitive = (error - LastError) * timeStep;
438
439 // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
440 Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X
441 + RunningIntegration / TimeScale * integralFactor * FactorMix.Y
442 + derivitive / TimeScale * derivFactor * FactorMix.Z
443 ;
444
445 MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}",
446 BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret);
447
448 return ret;
449 }
450}
451}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
new file mode 100755
index 0000000..c296008
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
@@ -0,0 +1,927 @@
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.Text;
31
32using OpenSim.Region.PhysicsModules.SharedBase;
33
34using OpenMetaverse;
35using Nini.Config;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
38{
39public static class BSParam
40{
41 private static string LogHeader = "[BULLETSIM PARAMETERS]";
42
43 // Tuning notes:
44 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
45 // Contact points can be added even if the distance is positive. The constraint solver can deal with
46 // contacts with positive distances as well as negative (penetration). Contact points are discarded
47 // if the distance exceeds a certain threshold.
48 // Bullet has a contact processing threshold and a contact breaking threshold.
49 // If the distance is larger than the contact breaking threshold, it will be removed after one frame.
50 // If the distance is larger than the contact processing threshold, the constraint solver will ignore it.
51
52 // This is separate/independent from the collision margin. The collision margin increases the object a bit
53 // to improve collision detection performance and accuracy.
54 // ===================
55 // From:
56
57 /// <summary>
58 /// Set whether physics is active or not.
59 /// </summary>
60 /// <remarks>
61 /// Can be enabled and disabled to start and stop physics.
62 /// </remarks>
63 public static bool Active { get; private set; }
64
65 public static bool UseSeparatePhysicsThread { get; private set; }
66 public static float PhysicsTimeStep { get; private set; }
67
68 // Level of Detail values kept as float because that's what the Meshmerizer wants
69 public static float MeshLOD { get; private set; }
70 public static float MeshCircularLOD { get; private set; }
71 public static float MeshMegaPrimLOD { get; private set; }
72 public static float MeshMegaPrimThreshold { get; private set; }
73 public static float SculptLOD { get; private set; }
74
75 public static int CrossingFailuresBeforeOutOfBounds { get; private set; }
76 public static float UpdateVelocityChangeThreshold { get; private set; }
77
78 public static float MinimumObjectMass { get; private set; }
79 public static float MaximumObjectMass { get; private set; }
80 public static float MaxLinearVelocity { get; private set; }
81 public static float MaxLinearVelocitySquared { get; private set; }
82 public static float MaxAngularVelocity { get; private set; }
83 public static float MaxAngularVelocitySquared { get; private set; }
84 public static float MaxAddForceMagnitude { get; private set; }
85 public static float MaxAddForceMagnitudeSquared { get; private set; }
86 public static float DensityScaleFactor { get; private set; }
87
88 public static float LinearDamping { get; private set; }
89 public static float AngularDamping { get; private set; }
90 public static float DeactivationTime { get; private set; }
91 public static float LinearSleepingThreshold { get; private set; }
92 public static float AngularSleepingThreshold { get; private set; }
93 public static float CcdMotionThreshold { get; private set; }
94 public static float CcdSweptSphereRadius { get; private set; }
95 public static float ContactProcessingThreshold { get; private set; }
96
97 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
98 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
99 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
100 public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
101 public static bool ShouldUseBulletHACD { get; set; }
102 public static bool ShouldUseSingleConvexHullForPrims { get; set; }
103 public static bool ShouldUseGImpactShapeForPrims { get; set; }
104 public static bool ShouldUseAssetHulls { get; set; }
105
106 public static float TerrainImplementation { get; set; }
107 public static int TerrainMeshMagnification { get; private set; }
108 public static float TerrainGroundPlane { get; private set; }
109 public static float TerrainFriction { get; private set; }
110 public static float TerrainHitFraction { get; private set; }
111 public static float TerrainRestitution { get; private set; }
112 public static float TerrainContactProcessingThreshold { get; private set; }
113 public static float TerrainCollisionMargin { get; private set; }
114
115 public static float DefaultFriction { get; private set; }
116 public static float DefaultDensity { get; private set; }
117 public static float DefaultRestitution { get; private set; }
118 public static float CollisionMargin { get; private set; }
119 public static float Gravity { get; private set; }
120
121 // Physics Engine operation
122 public static float MaxPersistantManifoldPoolSize { get; private set; }
123 public static float MaxCollisionAlgorithmPoolSize { get; private set; }
124 public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; }
125 public static bool ShouldForceUpdateAllAabbs { get; private set; }
126 public static bool ShouldRandomizeSolverOrder { get; private set; }
127 public static bool ShouldSplitSimulationIslands { get; private set; }
128 public static bool ShouldEnableFrictionCaching { get; private set; }
129 public static float NumberOfSolverIterations { get; private set; }
130 public static bool UseSingleSidedMeshes { get; private set; }
131 public static float GlobalContactBreakingThreshold { get; private set; }
132 public static float PhysicsUnmanLoggingFrames { get; private set; }
133
134 // Avatar parameters
135 public static bool AvatarToAvatarCollisionsByDefault { get; private set; }
136 public static float AvatarFriction { get; private set; }
137 public static float AvatarStandingFriction { get; private set; }
138 public static float AvatarAlwaysRunFactor { get; private set; }
139 public static float AvatarDensity { get; private set; }
140 public static float AvatarRestitution { get; private set; }
141 public static int AvatarShape { get; private set; }
142 public static float AvatarCapsuleWidth { get; private set; }
143 public static float AvatarCapsuleDepth { get; private set; }
144 public static float AvatarCapsuleHeight { get; private set; }
145 public static float AvatarHeightLowFudge { get; private set; }
146 public static float AvatarHeightMidFudge { get; private set; }
147 public static float AvatarHeightHighFudge { get; private set; }
148 public static float AvatarFlyingGroundMargin { get; private set; }
149 public static float AvatarFlyingGroundUpForce { get; private set; }
150 public static float AvatarTerminalVelocity { get; private set; }
151 public static float AvatarContactProcessingThreshold { get; private set; }
152 public static float AvatarStopZeroThreshold { get; private set; }
153 public static int AvatarJumpFrames { get; private set; }
154 public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
155 public static float AvatarStepHeight { get; private set; }
156 public static float AvatarStepAngle { get; private set; }
157 public static float AvatarStepGroundFudge { get; private set; }
158 public static float AvatarStepApproachFactor { get; private set; }
159 public static float AvatarStepForceFactor { get; private set; }
160 public static float AvatarStepUpCorrectionFactor { get; private set; }
161 public static int AvatarStepSmoothingSteps { get; private set; }
162
163 // Vehicle parameters
164 public static float VehicleMaxLinearVelocity { get; private set; }
165 public static float VehicleMaxLinearVelocitySquared { get; private set; }
166 public static float VehicleMinLinearVelocity { get; private set; }
167 public static float VehicleMinLinearVelocitySquared { get; private set; }
168 public static float VehicleMaxAngularVelocity { get; private set; }
169 public static float VehicleMaxAngularVelocitySq { get; private set; }
170 public static float VehicleAngularDamping { get; private set; }
171 public static float VehicleFriction { get; private set; }
172 public static float VehicleRestitution { get; private set; }
173 public static Vector3 VehicleLinearFactor { get; private set; }
174 public static Vector3 VehicleAngularFactor { get; private set; }
175 public static Vector3 VehicleInertiaFactor { get; private set; }
176 public static float VehicleGroundGravityFudge { get; private set; }
177 public static float VehicleAngularBankingTimescaleFudge { get; private set; }
178 public static bool VehicleEnableLinearDeflection { get; private set; }
179 public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; }
180 public static bool VehicleEnableAngularVerticalAttraction { get; private set; }
181 public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; }
182 public static bool VehicleEnableAngularDeflection { get; private set; }
183 public static bool VehicleEnableAngularBanking { get; private set; }
184
185 // Convex Hulls
186 // Parameters for convex hull routine that ships with Bullet
187 public static int CSHullMaxDepthSplit { get; private set; }
188 public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
189 public static float CSHullConcavityThresholdPercent { get; private set; }
190 public static float CSHullVolumeConservationThresholdPercent { get; private set; }
191 public static int CSHullMaxVertices { get; private set; }
192 public static float CSHullMaxSkinWidth { get; private set; }
193 public static float BHullMaxVerticesPerHull { get; private set; } // 100
194 public static float BHullMinClusters { get; private set; } // 2
195 public static float BHullCompacityWeight { get; private set; } // 0.1
196 public static float BHullVolumeWeight { get; private set; } // 0.0
197 public static float BHullConcavity { get; private set; } // 100
198 public static bool BHullAddExtraDistPoints { get; private set; } // false
199 public static bool BHullAddNeighboursDistPoints { get; private set; } // false
200 public static bool BHullAddFacesPoints { get; private set; } // false
201 public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false
202 public static float WhichHACD { get; private set; } // zero if Bullet HACD, non-zero says VHACD
203 // Parameters for VHACD 2.0: http://code.google.com/p/v-hacd
204 // To enable, set both ShouldUseBulletHACD=true and WhichHACD=1
205 // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html
206 public static float VHACDresolution { get; private set; } // 100,000 max number of voxels generated during voxelization stage
207 public static float VHACDdepth { get; private set; } // 20 max number of clipping stages
208 public static float VHACDconcavity { get; private set; } // 0.0025 maximum concavity
209 public static float VHACDplaneDownsampling { get; private set; } // 4 granularity of search for best clipping plane
210 public static float VHACDconvexHullDownsampling { get; private set; } // 4 precision of hull gen process
211 public static float VHACDalpha { get; private set; } // 0.05 bias toward clipping along symmetry planes
212 public static float VHACDbeta { get; private set; } // 0.05 bias toward clipping along revolution axis
213 public static float VHACDgamma { get; private set; } // 0.00125 max concavity when merging
214 public static float VHACDpca { get; private set; } // 0 on/off normalizing mesh before decomp
215 public static float VHACDmode { get; private set; } // 0 0:voxel based, 1: tetrahedron based
216 public static float VHACDmaxNumVerticesPerCH { get; private set; } // 64 max triangles per convex hull
217 public static float VHACDminVolumePerCH { get; private set; } // 0.0001 sampling of generated convex hulls
218
219 // Linkset implementation parameters
220 public static float LinksetImplementation { get; private set; }
221 public static bool LinksetOffsetCenterOfMass { get; private set; }
222 public static bool LinkConstraintUseFrameOffset { get; private set; }
223 public static bool LinkConstraintEnableTransMotor { get; private set; }
224 public static float LinkConstraintTransMotorMaxVel { get; private set; }
225 public static float LinkConstraintTransMotorMaxForce { get; private set; }
226 public static float LinkConstraintERP { get; private set; }
227 public static float LinkConstraintCFM { get; private set; }
228 public static float LinkConstraintSolverIterations { get; private set; }
229
230 public static float PID_D { get; private set; } // derivative
231 public static float PID_P { get; private set; } // proportional
232
233 // Various constants that come from that other virtual world that shall not be named.
234 public const float MinGravityZ = -1f;
235 public const float MaxGravityZ = 28f;
236 public const float MinFriction = 0f;
237 public const float MaxFriction = 255f;
238 public const float MinDensity = 0.01f;
239 public const float MaxDensity = 22587f;
240 public const float MinRestitution = 0f;
241 public const float MaxRestitution = 1f;
242
243 // =====================================================================================
244 // =====================================================================================
245
246 // Base parameter definition that gets and sets parameter values via a string
247 public abstract class ParameterDefnBase
248 {
249 public string name; // string name of the parameter
250 public string desc; // a short description of what the parameter means
251 public ParameterDefnBase(string pName, string pDesc)
252 {
253 name = pName;
254 desc = pDesc;
255 }
256 // Set the parameter value to the default
257 public abstract void AssignDefault(BSScene s);
258 // Get the value as a string
259 public abstract string GetValue(BSScene s);
260 // Set the value to this string value
261 public abstract void SetValue(BSScene s, string valAsString);
262 // set the value on a particular object (usually sets in physics engine)
263 public abstract void SetOnObject(BSScene s, BSPhysObject obj);
264 public abstract bool HasSetOnObject { get; }
265 }
266
267 // Specific parameter definition for a parameter of a specific type.
268 public delegate T PGetValue<T>(BSScene s);
269 public delegate void PSetValue<T>(BSScene s, T val);
270 public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj);
271 public sealed class ParameterDefn<T> : ParameterDefnBase
272 {
273 private T defaultValue;
274 private PSetValue<T> setter;
275 private PGetValue<T> getter;
276 private PSetOnObject<T> objectSet;
277 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter)
278 : base(pName, pDesc)
279 {
280 defaultValue = pDefault;
281 setter = pSetter;
282 getter = pGetter;
283 objectSet = null;
284 }
285 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter, PSetOnObject<T> pObjSetter)
286 : base(pName, pDesc)
287 {
288 defaultValue = pDefault;
289 setter = pSetter;
290 getter = pGetter;
291 objectSet = pObjSetter;
292 }
293 // Simple parameter variable where property name is the same as the INI file name
294 // and the value is only a simple get and set.
295 public ParameterDefn(string pName, string pDesc, T pDefault)
296 : base(pName, pDesc)
297 {
298 defaultValue = pDefault;
299 setter = (s, v) => { SetValueByName(s, name, v); };
300 getter = (s) => { return GetValueByName(s, name); };
301 objectSet = null;
302 }
303 // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same.
304 private void SetValueByName(BSScene s, string pName, T val)
305 {
306 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
307 if (prop == null)
308 {
309 // This should only be output when someone adds a new INI parameter and misspells the name.
310 s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName);
311 }
312 else
313 {
314 prop.SetValue(null, val, null);
315 }
316 }
317 // Use reflection to find the property named 'pName' in BSParam and return the value in same.
318 private T GetValueByName(BSScene s, string pName)
319 {
320 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
321 if (prop == null)
322 {
323 // This should only be output when someone adds a new INI parameter and misspells the name.
324 s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName);
325 }
326 return (T)prop.GetValue(null, null);
327 }
328 public override void AssignDefault(BSScene s)
329 {
330 setter(s, defaultValue);
331 }
332 public override string GetValue(BSScene s)
333 {
334 return getter(s).ToString();
335 }
336 public override void SetValue(BSScene s, string valAsString)
337 {
338 // Get the generic type of the setter
339 Type genericType = setter.GetType().GetGenericArguments()[0];
340 // Find the 'Parse' method on that type
341 System.Reflection.MethodInfo parser = null;
342 try
343 {
344 parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } );
345 }
346 catch (Exception e)
347 {
348 s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e);
349 parser = null;
350 }
351 if (parser != null)
352 {
353 // Parse the input string
354 try
355 {
356 T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
357 // Store the parsed value
358 setter(s, setValue);
359 // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
360 }
361 catch
362 {
363 s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType);
364 }
365 }
366 else
367 {
368 s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType);
369 }
370 }
371 public override bool HasSetOnObject
372 {
373 get { return objectSet != null; }
374 }
375 public override void SetOnObject(BSScene s, BSPhysObject obj)
376 {
377 if (objectSet != null)
378 objectSet(s, obj);
379 }
380 }
381
382 // List of all of the externally visible parameters.
383 // For each parameter, this table maps a text name to getter and setters.
384 // To add a new externally referencable/settable parameter, add the paramter storage
385 // location somewhere in the program and make an entry in this table with the
386 // getters and setters.
387 // It is easiest to find an existing definition and copy it.
388 //
389 // A ParameterDefn<T>() takes the following parameters:
390 // -- the text name of the parameter. This is used for console input and ini file.
391 // -- a short text description of the parameter. This shows up in the console listing.
392 // -- a default value
393 // -- a delegate for getting the value
394 // -- a delegate for setting the value
395 // -- an optional delegate to update the value in the world. Most often used to
396 // push the new value to an in-world object.
397 //
398 // The single letter parameters for the delegates are:
399 // s = BSScene
400 // o = BSPhysObject
401 // v = value (appropriate type)
402 private static ParameterDefnBase[] ParameterDefinitions =
403 {
404 new ParameterDefn<bool>("Active", "If 'true', false then physics is not active",
405 false ),
406 new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat",
407 false ),
408 new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval",
409 0.089f ),
410
411 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties",
412 true,
413 (s) => { return ShouldMeshSculptedPrim; },
414 (s,v) => { ShouldMeshSculptedPrim = v; } ),
415 new ParameterDefn<bool>("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
416 false,
417 (s) => { return ShouldForceSimplePrimMeshing; },
418 (s,v) => { ShouldForceSimplePrimMeshing = v; } ),
419 new ParameterDefn<bool>("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
420 true,
421 (s) => { return ShouldUseHullsForPhysicalObjects; },
422 (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ),
423 new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes",
424 true ),
425 new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD",
426 false ),
427 new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims",
428 true ),
429 new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists",
430 false ),
431 new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info",
432 true ),
433
434 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
435 5 ),
436 new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator",
437 0.1f ),
438
439 new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
440 32f,
441 (s) => { return MeshLOD; },
442 (s,v) => { MeshLOD = v; } ),
443 new ParameterDefn<float>("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes",
444 32f,
445 (s) => { return MeshCircularLOD; },
446 (s,v) => { MeshCircularLOD = v; } ),
447 new ParameterDefn<float>("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
448 10f,
449 (s) => { return MeshMegaPrimThreshold; },
450 (s,v) => { MeshMegaPrimThreshold = v; } ),
451 new ParameterDefn<float>("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
452 32f,
453 (s) => { return MeshMegaPrimLOD; },
454 (s,v) => { MeshMegaPrimLOD = v; } ),
455 new ParameterDefn<float>("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
456 32f,
457 (s) => { return SculptLOD; },
458 (s,v) => { SculptLOD = v; } ),
459
460 new ParameterDefn<int>("MaxSubStep", "In simulation step, maximum number of substeps",
461 10,
462 (s) => { return s.m_maxSubSteps; },
463 (s,v) => { s.m_maxSubSteps = (int)v; } ),
464 new ParameterDefn<float>("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
465 1f / 60f,
466 (s) => { return s.m_fixedTimeStep; },
467 (s,v) => { s.m_fixedTimeStep = v; } ),
468 new ParameterDefn<float>("NominalFrameRate", "The base frame rate we claim",
469 55f,
470 (s) => { return s.NominalFrameRate; },
471 (s,v) => { s.NominalFrameRate = (int)v; } ),
472 new ParameterDefn<int>("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
473 2048,
474 (s) => { return s.m_maxCollisionsPerFrame; },
475 (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
476 new ParameterDefn<int>("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
477 8000,
478 (s) => { return s.m_maxUpdatesPerFrame; },
479 (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
480
481 new ParameterDefn<float>("MinObjectMass", "Minimum object mass (0.0001)",
482 0.0001f,
483 (s) => { return MinimumObjectMass; },
484 (s,v) => { MinimumObjectMass = v; } ),
485 new ParameterDefn<float>("MaxObjectMass", "Maximum object mass (10000.01)",
486 10000.01f,
487 (s) => { return MaximumObjectMass; },
488 (s,v) => { MaximumObjectMass = v; } ),
489 new ParameterDefn<float>("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
490 1000.0f,
491 (s) => { return MaxLinearVelocity; },
492 (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ),
493 new ParameterDefn<float>("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
494 1000.0f,
495 (s) => { return MaxAngularVelocity; },
496 (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ),
497 // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
498 new ParameterDefn<float>("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
499 20000.0f,
500 (s) => { return MaxAddForceMagnitude; },
501 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
502 // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
503 // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well
504 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
505 0.01f ),
506
507 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
508 2200f ),
509 new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing",
510 900f ),
511
512 new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects",
513 0.2f,
514 (s) => { return DefaultFriction; },
515 (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ),
516 // For historical reasons, the viewer and simulator multiply the density by 100
517 new ParameterDefn<float>("DefaultDensity", "Density for new objects" ,
518 1000.0006836f, // Aluminum g/cm3 * 100
519 (s) => { return DefaultDensity; },
520 (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ),
521 new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" ,
522 0f,
523 (s) => { return DefaultRestitution; },
524 (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ),
525 new ParameterDefn<float>("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
526 0.04f,
527 (s) => { return CollisionMargin; },
528 (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ),
529 new ParameterDefn<float>("Gravity", "Vertical force of gravity (negative means down)",
530 -9.80665f,
531 (s) => { return Gravity; },
532 (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; },
533 (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ),
534
535
536 new ParameterDefn<float>("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
537 0f,
538 (s) => { return LinearDamping; },
539 (s,v) => { LinearDamping = v; },
540 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
541 new ParameterDefn<float>("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
542 0f,
543 (s) => { return AngularDamping; },
544 (s,v) => { AngularDamping = v; },
545 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
546 new ParameterDefn<float>("DeactivationTime", "Seconds before considering an object potentially static",
547 0.2f,
548 (s) => { return DeactivationTime; },
549 (s,v) => { DeactivationTime = v; },
550 (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ),
551 new ParameterDefn<float>("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
552 0.8f,
553 (s) => { return LinearSleepingThreshold; },
554 (s,v) => { LinearSleepingThreshold = v;},
555 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
556 new ParameterDefn<float>("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
557 1.0f,
558 (s) => { return AngularSleepingThreshold; },
559 (s,v) => { AngularSleepingThreshold = v;},
560 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
561 new ParameterDefn<float>("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
562 0.0f, // set to zero to disable
563 (s) => { return CcdMotionThreshold; },
564 (s,v) => { CcdMotionThreshold = v;},
565 (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ),
566 new ParameterDefn<float>("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
567 0.2f,
568 (s) => { return CcdSweptSphereRadius; },
569 (s,v) => { CcdSweptSphereRadius = v;},
570 (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ),
571 new ParameterDefn<float>("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" ,
572 0.0f,
573 (s) => { return ContactProcessingThreshold; },
574 (s,v) => { ContactProcessingThreshold = v;},
575 (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ),
576
577 new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
578 (float)BSTerrainPhys.TerrainImplementation.Heightmap ),
579 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
580 2 ),
581 new ParameterDefn<float>("TerrainGroundPlane", "Altitude of ground plane used to keep things from falling to infinity" ,
582 -500.0f ),
583 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
584 0.3f ),
585 new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" ,
586 0.8f ),
587 new ParameterDefn<float>("TerrainRestitution", "Bouncyness" ,
588 0f ),
589 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
590 0.0f ),
591 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" ,
592 0.04f ),
593
594 new ParameterDefn<bool>("AvatarToAvatarCollisionsByDefault", "Should avatars collide with other avatars by default?",
595 true),
596 new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
597 0.2f ),
598 new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
599 0.95f ),
600 new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
601 1.3f ),
602 // For historical reasons, density is reported * 100
603 new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.",
604 3500f) , // 3.5 * 100
605 new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
606 0f ),
607 new ParameterDefn<int>("AvatarShape", "Code for avatar physical shape: 0:capsule, 1:cube, 2:ovoid, 2:mesh",
608 BSShapeCollection.AvatarShapeCube ) ,
609 new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
610 0.6f ) ,
611 new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
612 0.45f ),
613 new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar",
614 1.5f ),
615 new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground",
616 0f ),
617 new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground",
618 0f ),
619 new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground",
620 0f ),
621 new ParameterDefn<float>("AvatarFlyingGroundMargin", "Meters avatar is kept above the ground when flying",
622 5f ),
623 new ParameterDefn<float>("AvatarFlyingGroundUpForce", "Upward force applied to the avatar to keep it at flying ground margin",
624 2.0f ),
625 new ParameterDefn<float>("AvatarTerminalVelocity", "Terminal Velocity of falling avatar",
626 -54.0f ),
627 new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
628 0.1f ),
629 new ParameterDefn<float>("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped",
630 0.1f ),
631 new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
632 1.0f ),
633 new ParameterDefn<int>("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.",
634 4 ),
635 new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
636 0.999f ) ,
637 new ParameterDefn<float>("AvatarStepAngle", "The angle (in radians) for a vertical surface to be considered a step",
638 0.3f ) ,
639 new ParameterDefn<float>("AvatarStepGroundFudge", "Fudge factor subtracted from avatar base when comparing collision height",
640 0.1f ) ,
641 new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
642 2f ),
643 new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
644 0f ),
645 new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step",
646 0.8f ),
647 new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs",
648 1 ),
649
650 new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
651 1000.0f,
652 (s) => { return (float)VehicleMaxLinearVelocity; },
653 (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ),
654 new ParameterDefn<float>("VehicleMinLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
655 0.001f,
656 (s) => { return (float)VehicleMinLinearVelocity; },
657 (s,v) => { VehicleMinLinearVelocity = v; VehicleMinLinearVelocitySquared = v * v; } ),
658 new ParameterDefn<float>("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle",
659 12.0f,
660 (s) => { return (float)VehicleMaxAngularVelocity; },
661 (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ),
662 new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
663 0.0f ),
664 new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)",
665 new Vector3(1f, 1f, 1f) ),
666 new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)",
667 new Vector3(1f, 1f, 1f) ),
668 new ParameterDefn<Vector3>("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)",
669 new Vector3(1f, 1f, 1f) ),
670 new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)",
671 0.0f ),
672 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
673 0.0f ),
674 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
675 0.2f ),
676 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
677 60.0f ),
678 new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect",
679 true ),
680 new ParameterDefn<bool>("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles",
681 true ),
682 new ParameterDefn<bool>("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect",
683 true ),
684 new ParameterDefn<int>("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.",
685 0 ),
686 new ParameterDefn<bool>("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect",
687 true ),
688 new ParameterDefn<bool>("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect",
689 true ),
690
691 new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
692 0f,
693 (s) => { return MaxPersistantManifoldPoolSize; },
694 (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
695 new ParameterDefn<float>("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
696 0f,
697 (s) => { return MaxCollisionAlgorithmPoolSize; },
698 (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
699 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
700 false,
701 (s) => { return ShouldDisableContactPoolDynamicAllocation; },
702 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v;
703 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ),
704 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
705 false,
706 (s) => { return ShouldForceUpdateAllAabbs; },
707 (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ),
708 new ParameterDefn<bool>("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
709 true,
710 (s) => { return ShouldRandomizeSolverOrder; },
711 (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ),
712 new ParameterDefn<bool>("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
713 true,
714 (s) => { return ShouldSplitSimulationIslands; },
715 (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ),
716 new ParameterDefn<bool>("ShouldEnableFrictionCaching", "Enable friction computation caching",
717 true,
718 (s) => { return ShouldEnableFrictionCaching; },
719 (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ),
720 new ParameterDefn<float>("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
721 0f, // zero says use Bullet default
722 (s) => { return NumberOfSolverIterations; },
723 (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
724 new ParameterDefn<bool>("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.",
725 true,
726 (s) => { return UseSingleSidedMeshes; },
727 (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ),
728 new ParameterDefn<float>("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))",
729 0f,
730 (s) => { return GlobalContactBreakingThreshold; },
731 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
732 new ParameterDefn<float>("PhysicsUnmanLoggingFrames", "If non-zero, frames between output of detailed unmanaged physics statistics",
733 0f,
734 (s) => { return PhysicsUnmanLoggingFrames; },
735 (s,v) => { PhysicsUnmanLoggingFrames = v; s.UnmanagedParams[0].physicsLoggingFrames = v; } ),
736
737 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
738 7 ),
739 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
740 2 ),
741 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
742 5f ),
743 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
744 5f ),
745 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
746 32 ),
747 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
748 0f ),
749
750 new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull",
751 200f ),
752 new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh",
753 10f ),
754 new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls",
755 20f ),
756 new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull",
757 0.1f ),
758 new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be",
759 10f ),
760 new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors",
761 true ),
762 new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls",
763 true ),
764 new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces",
765 true ),
766 new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin",
767 false ),
768
769 new ParameterDefn<float>("WhichHACD", "zero if Bullet HACD, non-zero says VHACD",
770 0f ),
771 new ParameterDefn<float>("VHACDresolution", "max number of voxels generated during voxelization stage",
772 100000f ),
773 new ParameterDefn<float>("VHACDdepth", "max number of clipping stages",
774 20f ),
775 new ParameterDefn<float>("VHACDconcavity", "maximum concavity",
776 0.0025f ),
777 new ParameterDefn<float>("VHACDplaneDownsampling", "granularity of search for best clipping plane",
778 4f ),
779 new ParameterDefn<float>("VHACDconvexHullDownsampling", "precision of hull gen process",
780 4f ),
781 new ParameterDefn<float>("VHACDalpha", "bias toward clipping along symmetry planes",
782 0.05f ),
783 new ParameterDefn<float>("VHACDbeta", "bias toward clipping along revolution axis",
784 0.05f ),
785 new ParameterDefn<float>("VHACDgamma", "max concavity when merging",
786 0.00125f ),
787 new ParameterDefn<float>("VHACDpca", "on/off normalizing mesh before decomp",
788 0f ),
789 new ParameterDefn<float>("VHACDmode", "0:voxel based, 1: tetrahedron based",
790 0f ),
791 new ParameterDefn<float>("VHACDmaxNumVerticesPerCH", "max triangles per convex hull",
792 64f ),
793 new ParameterDefn<float>("VHACDminVolumePerCH", "sampling of generated convex hulls",
794 0.0001f ),
795
796 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
797 (float)BSLinkset.LinksetImplementation.Compound ),
798 new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same",
799 true ),
800 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
801 false ),
802 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
803 true ),
804 new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
805 5.0f ),
806 new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
807 0.1f ),
808 new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
809 0.1f ),
810 new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
811 0.1f ),
812 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
813 40 ),
814
815 new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
816 0,
817 (s) => { return s.PhysicsMetricDumpFrames; },
818 (s,v) => { s.PhysicsMetricDumpFrames = v; } ),
819 new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
820 0f,
821 (s) => { return 0f; },
822 (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ),
823 new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
824 0f,
825 (s) => { return 0f; },
826 (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ),
827 };
828
829 // Convert a boolean to our numeric true and false values
830 public static float NumericBool(bool b)
831 {
832 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
833 }
834
835 // Convert numeric true and false values to a boolean
836 public static bool BoolNumeric(float b)
837 {
838 return (b == ConfigurationParameters.numericTrue ? true : false);
839 }
840
841 // Search through the parameter definitions and return the matching
842 // ParameterDefn structure.
843 // Case does not matter as names are compared after converting to lower case.
844 // Returns 'false' if the parameter is not found.
845 internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn)
846 {
847 bool ret = false;
848 ParameterDefnBase foundDefn = null;
849 string pName = paramName.ToLower();
850
851 foreach (ParameterDefnBase parm in ParameterDefinitions)
852 {
853 if (pName == parm.name.ToLower())
854 {
855 foundDefn = parm;
856 ret = true;
857 break;
858 }
859 }
860 defn = foundDefn;
861 return ret;
862 }
863
864 // Pass through the settable parameters and set the default values
865 internal static void SetParameterDefaultValues(BSScene physicsScene)
866 {
867 foreach (ParameterDefnBase parm in ParameterDefinitions)
868 {
869 parm.AssignDefault(physicsScene);
870 }
871 }
872
873 // Get user set values out of the ini file.
874 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
875 {
876 foreach (ParameterDefnBase parm in ParameterDefinitions)
877 {
878 parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene)));
879 }
880 }
881
882 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
883
884 // This creates an array in the correct format for returning the list of
885 // parameters. This is used by the 'list' option of the 'physics' command.
886 internal static void BuildParameterTable()
887 {
888 if (SettableParameters.Length < ParameterDefinitions.Length)
889 {
890 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
891 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
892 {
893 ParameterDefnBase pd = ParameterDefinitions[ii];
894 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
895 }
896
897 // make the list alphabetical for ease of finding anything
898 entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); });
899
900 SettableParameters = entries.ToArray();
901 }
902 }
903
904 // =====================================================================
905 // =====================================================================
906 // There are parameters that, when set, cause things to happen in the physics engine.
907 // This causes the broadphase collision cache to be cleared.
908 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime)
909 {
910 BSScene physScene = pPhysScene;
911 physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate()
912 {
913 physScene.PE.ResetBroadphasePool(physScene.World);
914 });
915 }
916
917 // This causes the constraint solver cache to be cleared and reset.
918 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
919 {
920 BSScene physScene = pPhysScene;
921 physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate()
922 {
923 physScene.PE.ResetConstraintSolver(physScene.World);
924 });
925 }
926}
927}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
new file mode 100755
index 0000000..da3fc18
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
@@ -0,0 +1,620 @@
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.PhysicsModules.SharedBase;
34
35namespace OpenSim.Region.PhysicsModule.BulletS
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 one should only be referenced 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
58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
59public enum UpdatedProperties : uint
60{
61 Position = 1 << 0,
62 Orientation = 1 << 1,
63 Velocity = 1 << 2,
64 Acceleration = 1 << 3,
65 RotationalVelocity = 1 << 4,
66 EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity,
67}
68public abstract class BSPhysObject : PhysicsActor
69{
70 protected BSPhysObject()
71 {
72 }
73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
74 {
75 IsInitialized = false;
76
77 PhysScene = parentScene;
78 LocalID = localID;
79 PhysObjectName = name;
80 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
81 TypeName = typeName;
82
83 // Oddity if object is destroyed and recreated very quickly it could still have the old body.
84 if (!PhysBody.HasPhysicalBody)
85 PhysBody = new BulletBody(localID);
86
87 // Clean out anything that might be in the physical actor list.
88 // Again, a workaround for destroying and recreating an object very quickly.
89 PhysicalActors.Dispose();
90
91 UserSetCenterOfMassDisplacement = null;
92
93 PrimAssetState = PrimAssetCondition.Unknown;
94
95 // Initialize variables kept in base.
96 // Beware that these cause taints to be queued whch can cause race conditions on startup.
97 GravModifier = 1.0f;
98 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
99 HoverActive = false;
100
101 // Default material type. Also sets Friction, Restitution and Density.
102 SetMaterial((int)MaterialAttributes.Material.Wood);
103
104 CollisionsLastTickStep = -1;
105
106 SubscribedEventsMs = 0;
107 // Crazy values that will never be true
108 CollidingStep = BSScene.NotASimulationStep;
109 CollidingGroundStep = BSScene.NotASimulationStep;
110 CollisionAccumulation = BSScene.NotASimulationStep;
111 ColliderIsMoving = false;
112 CollisionScore = 0;
113
114 // All axis free.
115 LockedLinearAxis = LockedAxisFree;
116 LockedAngularAxis = LockedAxisFree;
117 }
118
119 // Tell the object to clean up.
120 public virtual void Destroy()
121 {
122 PhysicalActors.Enable(false);
123 PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate()
124 {
125 PhysicalActors.Dispose();
126 });
127 }
128
129 public BSScene PhysScene { get; protected set; }
130 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
131 public string PhysObjectName { get; protected set; }
132 public string TypeName { get; protected set; }
133
134 // Set to 'true' when the object is completely initialized.
135 // This mostly prevents property updates and collisions until the object is completely here.
136 public bool IsInitialized { get; protected set; }
137
138 // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed.
139 // This test is used to prevent some updates to the object when it only partially exists.
140 // There are several reasons and object might be incomplete:
141 // Its underlying mesh/sculpty is an asset which must be fetched from the asset store
142 // It is a linkset who is being added to or removed from
143 // It is changing state (static to physical, for instance) which requires rebuilding
144 // This is a computed value based on the underlying physical object construction
145 abstract public bool IsIncomplete { get; }
146
147 // Return the object mass without calculating it or having side effects
148 public abstract float RawMass { get; }
149 // Set the raw mass but also update physical mass properties (inertia, ...)
150 // 'inWorld' true if the object has already been added to the dynamic world.
151 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
152
153 // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
154 public virtual OMV.Vector3 Gravity { get; set; }
155 // The last value calculated for the prim's inertia
156 public OMV.Vector3 Inertia { get; set; }
157
158 // Reference to the physical body (btCollisionObject) of this object
159 public BulletBody PhysBody = new BulletBody(0);
160 // Reference to the physical shape (btCollisionShape) of this object
161 public BSShape PhysShape = new BSShapeNull();
162
163 // The physical representation of the prim might require an asset fetch.
164 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
165 public enum PrimAssetCondition
166 {
167 Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched
168 }
169 public PrimAssetCondition PrimAssetState { get; set; }
170 public virtual bool AssetFailed()
171 {
172 return ( (this.PrimAssetState == PrimAssetCondition.FailedAssetFetch)
173 || (this.PrimAssetState == PrimAssetCondition.FailedMeshing) );
174 }
175
176 // The objects base shape information. Null if not a prim type shape.
177 public PrimitiveBaseShape BaseShape { get; protected set; }
178
179 // When the physical properties are updated, an EntityProperty holds the update values.
180 // Keep the current and last EntityProperties to enable computation of differences
181 // between the current update and the previous values.
182 public EntityProperties CurrentEntityProperties { get; set; }
183 public EntityProperties LastEntityProperties { get; set; }
184
185 public virtual OMV.Vector3 Scale { get; set; }
186
187 // It can be confusing for an actor to know if it should move or update an object
188 // depeneding on the setting of 'selected', 'physical, ...
189 // This flag is the true test -- if true, the object is being acted on in the physical world
190 public abstract bool IsPhysicallyActive { get; }
191
192 // Detailed state of the object.
193 public abstract bool IsSolid { get; }
194 public abstract bool IsStatic { get; }
195 public abstract bool IsSelected { get; }
196 public abstract bool IsVolumeDetect { get; }
197
198 // Materialness
199 public MaterialAttributes.Material Material { get; private set; }
200 public override void SetMaterial(int material)
201 {
202 Material = (MaterialAttributes.Material)material;
203
204 // Setting the material sets the material attributes also.
205 // TODO: decide if this is necessary -- the simulator does this.
206 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
207 Friction = matAttrib.friction;
208 Restitution = matAttrib.restitution;
209 Density = matAttrib.density;
210 // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
211 }
212
213 public override float Density
214 {
215 get
216 {
217 return base.Density;
218 }
219 set
220 {
221 DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value);
222 base.Density = value;
223 }
224 }
225
226 // Stop all physical motion.
227 public abstract void ZeroMotion(bool inTaintTime);
228 public abstract void ZeroAngularMotion(bool inTaintTime);
229
230 // Update the physical location and motion of the object. Called with data from Bullet.
231 public abstract void UpdateProperties(EntityProperties entprop);
232
233 public virtual OMV.Vector3 RawPosition { get; set; }
234 public abstract OMV.Vector3 ForcePosition { get; set; }
235
236 public virtual OMV.Quaternion RawOrientation { get; set; }
237 public abstract OMV.Quaternion ForceOrientation { get; set; }
238
239 public virtual OMV.Vector3 RawVelocity { get; set; }
240 public abstract OMV.Vector3 ForceVelocity { get; set; }
241
242 public OMV.Vector3 RawForce { get; set; }
243 public OMV.Vector3 RawTorque { get; set; }
244 public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
245 {
246 AddAngularForce(force, pushforce, false);
247 }
248 public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
249 public abstract void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
250
251 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
252
253 public abstract float ForceBuoyancy { get; set; }
254
255 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
256
257 public override bool PIDActive
258 {
259 get { return MoveToTargetActive; }
260 set { MoveToTargetActive = value; }
261 }
262
263 public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
264 public override float PIDTau { set { MoveToTargetTau = value; } }
265
266 public bool MoveToTargetActive { get; set; }
267 public OMV.Vector3 MoveToTargetTarget { get; set; }
268 public float MoveToTargetTau { get; set; }
269
270 // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
271 public override bool PIDHoverActive { set { HoverActive = value; } }
272 public override float PIDHoverHeight { set { HoverHeight = value; } }
273 public override PIDHoverType PIDHoverType { set { HoverType = value; } }
274 public override float PIDHoverTau { set { HoverTau = value; } }
275
276 public bool HoverActive { get; set; }
277 public float HoverHeight { get; set; }
278 public PIDHoverType HoverType { get; set; }
279 public float HoverTau { get; set; }
280
281 // For RotLookAt
282 public override OMV.Quaternion APIDTarget { set { return; } }
283 public override bool APIDActive { set { return; } }
284 public override float APIDStrength { set { return; } }
285 public override float APIDDamping { set { return; } }
286
287 // The current velocity forward
288 public virtual float ForwardSpeed
289 {
290 get
291 {
292 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
293 return characterOrientedVelocity.X;
294 }
295 }
296 // The forward speed we are trying to achieve (TargetVelocity)
297 public virtual float TargetVelocitySpeed
298 {
299 get
300 {
301 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
302 return characterOrientedVelocity.X;
303 }
304 }
305
306 // The user can optionally set the center of mass. The user's setting will override any
307 // computed center-of-mass (like in linksets).
308 // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
309 public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
310
311 public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free.
312 public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free.
313 public const float FreeAxis = 1f;
314 public const float LockedAxis = 0f;
315 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free
316
317 // If an axis is locked (flagged above) then the limits of that axis are specified here.
318 // Linear axis limits are relative to the object's starting coordinates.
319 // Angular limits are limited to -PI to +PI
320 public OMV.Vector3 LockedLinearAxisLow;
321 public OMV.Vector3 LockedLinearAxisHigh;
322 public OMV.Vector3 LockedAngularAxisLow;
323 public OMV.Vector3 LockedAngularAxisHigh;
324
325 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
326 // they need waking up when parameters are changed.
327 // Called in taint-time!!
328 public void ActivateIfPhysical(bool forceIt)
329 {
330 if (PhysBody.HasPhysicalBody)
331 {
332 if (IsPhysical)
333 {
334 // Physical objects might need activating
335 PhysScene.PE.Activate(PhysBody, forceIt);
336 }
337 else
338 {
339 // Clear the collision cache since we've changed some properties.
340 PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody);
341 }
342 }
343 }
344
345 // 'actors' act on the physical object to change or constrain its motion. These can range from
346 // hovering to complex vehicle motion.
347 // May be called at non-taint time as this just adds the actor to the action list and the real
348 // work is done during the simulation step.
349 // Note that, if the actor is already in the list and we are disabling same, the actor is just left
350 // in the list disabled.
351 public delegate BSActor CreateActor();
352 public void EnableActor(bool enableActor, string actorName, CreateActor creator)
353 {
354 lock (PhysicalActors)
355 {
356 BSActor theActor;
357 if (PhysicalActors.TryGetActor(actorName, out theActor))
358 {
359 // The actor already exists so just turn it on or off
360 DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
361 theActor.Enabled = enableActor;
362 }
363 else
364 {
365 // The actor does not exist. If it should, create it.
366 if (enableActor)
367 {
368 DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
369 theActor = creator();
370 PhysicalActors.Add(actorName, theActor);
371 theActor.Enabled = true;
372 }
373 else
374 {
375 DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
376 }
377 }
378 }
379 }
380
381 #region Collisions
382
383 // Requested number of milliseconds between collision events. Zero means disabled.
384 protected int SubscribedEventsMs { get; set; }
385 // Given subscription, the time that a collision may be passed up
386 protected int NextCollisionOkTime { get; set; }
387 // The simulation step that last had a collision
388 protected long CollidingStep { get; set; }
389 // The simulation step that last had a collision with the ground
390 protected long CollidingGroundStep { get; set; }
391 // The simulation step that last collided with an object
392 protected long CollidingObjectStep { get; set; }
393 // The collision flags we think are set in Bullet
394 protected CollisionFlags CurrentCollisionFlags { get; set; }
395 // On a collision, check the collider and remember if the last collider was moving
396 // Used to modify the standing of avatars (avatars on stationary things stand still)
397 public bool ColliderIsMoving;
398 // 'true' if the last collider was a volume detect object
399 public bool ColliderIsVolumeDetect;
400 // Used by BSCharacter to manage standing (and not slipping)
401 public bool IsStationary;
402
403 // Count of collisions for this object
404 protected long CollisionAccumulation { get; set; }
405
406 public override bool IsColliding {
407 get { return (CollidingStep == PhysScene.SimulationStep); }
408 set {
409 if (value)
410 CollidingStep = PhysScene.SimulationStep;
411 else
412 CollidingStep = BSScene.NotASimulationStep;
413 }
414 }
415 // Complex objects (like linksets) need to know if there is a collision on any part of
416 // their shape. 'IsColliding' has an existing definition of reporting a collision on
417 // only this specific prim or component of linksets.
418 // 'HasSomeCollision' is defined as reporting if there is a collision on any part of
419 // the complex body that this prim is the root of.
420 public virtual bool HasSomeCollision
421 {
422 get { return IsColliding; }
423 set { IsColliding = value; }
424 }
425 public override bool CollidingGround {
426 get { return (CollidingGroundStep == PhysScene.SimulationStep); }
427 set
428 {
429 if (value)
430 CollidingGroundStep = PhysScene.SimulationStep;
431 else
432 CollidingGroundStep = BSScene.NotASimulationStep;
433 }
434 }
435 public override bool CollidingObj {
436 get { return (CollidingObjectStep == PhysScene.SimulationStep); }
437 set {
438 if (value)
439 CollidingObjectStep = PhysScene.SimulationStep;
440 else
441 CollidingObjectStep = BSScene.NotASimulationStep;
442 }
443 }
444
445 // The collisions that have been collected for the next collision reporting (throttled by subscription)
446 protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate();
447 // This is the collision collection last reported to the Simulator.
448 public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate();
449 // Remember the collisions recorded in the last tick for fancy collision checking
450 // (like a BSCharacter walking up stairs).
451 public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate();
452 private long CollisionsLastTickStep = -1;
453
454 // The simulation step is telling this object about a collision.
455 // Return 'true' if a collision was processed and should be sent up.
456 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
457 // Called at taint time from within the Step() function
458 public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
459 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
460 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
461 {
462 bool ret = false;
463
464 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
465 CollidingStep = PhysScene.SimulationStep;
466 if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
467 {
468 CollidingGroundStep = PhysScene.SimulationStep;
469 }
470 else
471 {
472 CollidingObjectStep = PhysScene.SimulationStep;
473 }
474
475 CollisionAccumulation++;
476
477 // For movement tests, remember if we are colliding with an object that is moving.
478 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
479 ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false;
480
481 // Make a collection of the collisions that happened the last simulation tick.
482 // This is different than the collection created for sending up to the simulator as it is cleared every tick.
483 if (CollisionsLastTickStep != PhysScene.SimulationStep)
484 {
485 CollisionsLastTick = new CollisionEventUpdate();
486 CollisionsLastTickStep = PhysScene.SimulationStep;
487 }
488 CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
489
490 // If someone has subscribed for collision events log the collision so it will be reported up
491 if (SubscribedEvents()) {
492 lock (PhysScene.CollisionLock)
493 {
494 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
495 }
496 DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
497 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
498
499 ret = true;
500 }
501 return ret;
502 }
503
504 // Send the collected collisions into the simulator.
505 // Called at taint time from within the Step() function thus no locking problems
506 // with CollisionCollection and ObjectsWithNoMoreCollisions.
507 // Called with BSScene.CollisionLock locked to protect the collision lists.
508 // Return 'true' if there were some actual collisions passed up
509 public virtual bool SendCollisions()
510 {
511 bool ret = true;
512
513 // If no collisions this call but there were collisions last call, force the collision
514 // event to be happen right now so quick collision_end.
515 bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
516
517 // throttle the collisions to the number of milliseconds specified in the subscription
518 if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
519 {
520 NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
521
522 // We are called if we previously had collisions. If there are no collisions
523 // this time, send up one last empty event so OpenSim can sense collision end.
524 if (CollisionCollection.Count == 0)
525 {
526 // If I have no collisions this time, remove me from the list of objects with collisions.
527 ret = false;
528 }
529
530 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
531 base.SendCollisionUpdate(CollisionCollection);
532
533 // Remember the collisions from this tick for some collision specific processing.
534 CollisionsLastReported = CollisionCollection;
535
536 // The CollisionCollection instance is passed around in the simulator.
537 // Make sure we don't have a handle to that one and that a new one is used for next time.
538 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
539 // a race condition is created for the other users of this instance.
540 CollisionCollection = new CollisionEventUpdate();
541 }
542 return ret;
543 }
544
545 // Subscribe for collision events.
546 // Parameter is the millisecond rate the caller wishes collision events to occur.
547 public override void SubscribeEvents(int ms) {
548 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
549 SubscribedEventsMs = ms;
550 if (ms > 0)
551 {
552 // make sure first collision happens
553 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
554
555 PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate()
556 {
557 if (PhysBody.HasPhysicalBody)
558 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
559 });
560 }
561 else
562 {
563 // Subscribing for zero or less is the same as unsubscribing
564 UnSubscribeEvents();
565 }
566 }
567 public override void UnSubscribeEvents() {
568 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
569 SubscribedEventsMs = 0;
570 PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate()
571 {
572 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
573 if (PhysBody.HasPhysicalBody)
574 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
575 });
576 }
577 // Return 'true' if the simulator wants collision events
578 public override bool SubscribedEvents() {
579 return (SubscribedEventsMs > 0);
580 }
581 // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
582 // each time called. So this is built to be light weight for each collision and to do
583 // all the processing when the user asks for the info.
584 public void ComputeCollisionScore()
585 {
586 // Scale the collision count by the time since the last collision.
587 // The "+1" prevents dividing by zero.
588 long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
589 CollisionScore = CollisionAccumulation / timeAgo;
590 }
591 public override float CollisionScore { get; set; }
592
593 #endregion // Collisions
594
595 #region Per Simulation Step actions
596
597 public BSActorCollection PhysicalActors = new BSActorCollection();
598
599 // When an update to the physical properties happens, this event is fired to let
600 // different actors to modify the update before it is passed around
601 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
602 public event PreUpdatePropertyAction OnPreUpdateProperty;
603 protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
604 {
605 PreUpdatePropertyAction actions = OnPreUpdateProperty;
606 if (actions != null)
607 actions(ref entprop);
608 }
609
610 #endregion // Per Simulation Step actions
611
612 // High performance detailed logging routine used by the physical objects.
613 protected void DetailLog(string msg, params Object[] args)
614 {
615 if (PhysScene.PhysicsLogging.Enabled)
616 PhysScene.DetailLog(msg, args);
617 }
618
619}
620}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
new file mode 100644
index 0000000..6f27ac7
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
@@ -0,0 +1,1895 @@
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.PhysicsModules.SharedBase;
36using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet;
37
38namespace OpenSim.Region.PhysicsModule.BulletS
39{
40
41 [Serializable]
42public class BSPrim : BSPhysObject
43{
44 protected 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
54 private float _mass; // the mass of this object
55 private OMV.Vector3 _acceleration;
56 private int _physicsActorType;
57 private bool _isPhysical;
58 private bool _flying;
59 private bool _setAlwaysRun;
60 private bool _throttleUpdates;
61 private bool _floatOnWater;
62 private OMV.Vector3 _rotationalVelocity;
63 private bool _kinematic;
64 private float _buoyancy;
65
66 private int CrossingFailures { get; set; }
67
68 // Keep a handle to the vehicle actor so it is easy to set parameters on same.
69 public const string VehicleActorName = "BasicVehicle";
70
71 // Parameters for the hover actor
72 public const string HoverActorName = "BSPrim.HoverActor";
73 // Parameters for the axis lock actor
74 public const String LockedAxisActorName = "BSPrim.LockedAxis";
75 // Parameters for the move to target actor
76 public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor";
77 // Parameters for the setForce and setTorque actors
78 public const string SetForceActorName = "BSPrim.SetForceActor";
79 public const string SetTorqueActorName = "BSPrim.SetTorqueActor";
80
81 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
82 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
83 : base(parent_scene, localID, primName, "BSPrim")
84 {
85 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
86 _physicsActorType = (int)ActorTypes.Prim;
87 RawPosition = pos;
88 _size = size;
89 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
90 RawOrientation = rotation;
91 _buoyancy = 0f;
92 RawVelocity = OMV.Vector3.Zero;
93 _rotationalVelocity = OMV.Vector3.Zero;
94 BaseShape = pbs;
95 _isPhysical = pisPhysical;
96 _isVolumeDetect = false;
97
98 _mass = CalculateMass();
99
100 DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs));
101 // DetailLog("{0},BSPrim.constructor,call", LocalID);
102 // do the actual object creation at taint time
103 PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate()
104 {
105 // Make sure the object is being created with some sanity.
106 ExtremeSanityCheck(true /* inTaintTime */);
107
108 CreateGeomAndObject(true);
109
110 CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
111
112 IsInitialized = true;
113 });
114 }
115
116 // called when this prim is being destroyed and we should free all the resources
117 public override void Destroy()
118 {
119 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
120 IsInitialized = false;
121
122 base.Destroy();
123
124 // Undo any vehicle properties
125 this.VehicleType = (int)Vehicle.TYPE_NONE;
126
127 PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate()
128 {
129 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
130 // If there are physical body and shape, release my use of same.
131 PhysScene.Shapes.DereferenceBody(PhysBody, null);
132 PhysBody.Clear();
133 PhysShape.Dereference(PhysScene);
134 PhysShape = new BSShapeNull();
135 });
136 }
137
138 // No one uses this property.
139 public override bool Stopped {
140 get { return false; }
141 }
142
143 public override bool IsIncomplete {
144 get {
145 return ShapeRebuildScheduled;
146 }
147 }
148
149 // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued.
150 // The prim is still available but its underlying shape will change soon.
151 // This is protected by a 'lock(this)'.
152 public bool ShapeRebuildScheduled { get; protected set; }
153
154 public override OMV.Vector3 Size {
155 get { return _size; }
156 set {
157 // We presume the scale and size are the same. If scale must be changed for
158 // the physical shape, that is done when the geometry is built.
159 _size = value;
160 Scale = _size;
161 ForceBodyShapeRebuild(false);
162 }
163 }
164
165 public override PrimitiveBaseShape Shape {
166 set {
167 BaseShape = value;
168 DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape));
169 PrimAssetState = PrimAssetCondition.Unknown;
170 ForceBodyShapeRebuild(false);
171 }
172 }
173 // Cause the body and shape of the prim to be rebuilt if necessary.
174 // If there are no changes required, this is quick and does not make changes to the prim.
175 // If rebuilding is necessary (like changing from static to physical), that will happen.
176 // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly.
177 // The return parameter is not used by anyone.
178 public override bool ForceBodyShapeRebuild(bool inTaintTime)
179 {
180 if (inTaintTime)
181 {
182 // If called in taint time, do the operation immediately
183 _mass = CalculateMass(); // changing the shape changes the mass
184 CreateGeomAndObject(true);
185 }
186 else
187 {
188 lock (this)
189 {
190 // If a rebuild is not already in the queue
191 if (!ShapeRebuildScheduled)
192 {
193 // Remember that a rebuild is queued -- this is used to flag an incomplete object
194 ShapeRebuildScheduled = true;
195 PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate()
196 {
197 _mass = CalculateMass(); // changing the shape changes the mass
198 CreateGeomAndObject(true);
199 ShapeRebuildScheduled = false;
200 });
201 }
202 }
203 }
204 return true;
205 }
206 public override bool Grabbed {
207 set { _grabbed = value;
208 }
209 }
210 public override bool Selected {
211 set
212 {
213 if (value != _isSelected)
214 {
215 _isSelected = value;
216 PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate()
217 {
218 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
219 SetObjectDynamic(false);
220 });
221 }
222 }
223 }
224 public override bool IsSelected
225 {
226 get { return _isSelected; }
227 }
228
229 public override void CrossingFailure()
230 {
231 CrossingFailures++;
232 if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds)
233 {
234 base.RaiseOutOfBounds(RawPosition);
235 }
236 else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds)
237 {
238 m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name);
239 }
240 return;
241 }
242
243 // link me to the specified parent
244 public override void link(PhysicsActor obj) {
245 }
246
247 // delink me from my linkset
248 public override void delink() {
249 }
250
251 // Set motion values to zero.
252 // Do it to the properties so the values get set in the physics engine.
253 // Push the setting of the values to the viewer.
254 // Called at taint time!
255 public override void ZeroMotion(bool inTaintTime)
256 {
257 RawVelocity = OMV.Vector3.Zero;
258 _acceleration = OMV.Vector3.Zero;
259 _rotationalVelocity = OMV.Vector3.Zero;
260
261 // Zero some other properties in the physics engine
262 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
263 {
264 if (PhysBody.HasPhysicalBody)
265 PhysScene.PE.ClearAllForces(PhysBody);
266 });
267 }
268 public override void ZeroAngularMotion(bool inTaintTime)
269 {
270 _rotationalVelocity = OMV.Vector3.Zero;
271 // Zero some other properties in the physics engine
272 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
273 {
274 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
275 if (PhysBody.HasPhysicalBody)
276 {
277 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
278 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
279 }
280 });
281 }
282
283 public override void LockAngularMotion(OMV.Vector3 axis)
284 {
285 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
286
287 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
288 if (axis.X != 1)
289 {
290 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f);
291 }
292 if (axis.Y != 1)
293 {
294 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f);
295 }
296 if (axis.Z != 1)
297 {
298 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f);
299 }
300
301 InitializeAxisActor();
302
303 return;
304 }
305
306 public override OMV.Vector3 Position {
307 get {
308 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
309 // RawPosition = ForcePosition;
310 return RawPosition;
311 }
312 set {
313 // If the position must be forced into the physics engine, use ForcePosition.
314 // All positions are given in world positions.
315 if (RawPosition == value)
316 {
317 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
318 return;
319 }
320 RawPosition = value;
321 PositionSanityCheck(false);
322
323 PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate()
324 {
325 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
326 ForcePosition = RawPosition;
327 });
328 }
329 }
330
331 // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity.
332 public override OMV.Vector3 ForcePosition {
333 get {
334 RawPosition = PhysScene.PE.GetPosition(PhysBody);
335 return RawPosition;
336 }
337 set {
338 RawPosition = value;
339 if (PhysBody.HasPhysicalBody)
340 {
341 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
342 ActivateIfPhysical(false);
343 }
344 }
345 }
346
347 // Check that the current position is sane and, if not, modify the position to make it so.
348 // Check for being below terrain and being out of bounds.
349 // Returns 'true' of the position was made sane by some action.
350 private bool PositionSanityCheck(bool inTaintTime)
351 {
352 bool ret = false;
353
354 // We don't care where non-physical items are placed
355 if (!IsPhysicallyActive)
356 return ret;
357
358 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
359 {
360 // The physical object is out of the known/simulated area.
361 // Upper levels of code will handle the transition to other areas so, for
362 // the time, we just ignore the position.
363 return ret;
364 }
365
366 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
367 OMV.Vector3 upForce = OMV.Vector3.Zero;
368 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
369 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
370 {
371 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
372 float targetHeight = terrainHeight + (Size.Z / 2f);
373 // If the object is below ground it just has to be moved up because pushing will
374 // not get it through the terrain
375 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight);
376 if (inTaintTime)
377 {
378 ForcePosition = RawPosition;
379 }
380 // If we are throwing the object around, zero its other forces
381 ZeroMotion(inTaintTime);
382 ret = true;
383 }
384
385 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
386 {
387 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
388 // TODO: a floating motor so object will bob in the water
389 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
390 {
391 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
392 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
393
394 // Apply upforce and overcome gravity.
395 OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
396 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce);
397 AddForce(correctionForce, false, inTaintTime);
398 ret = true;
399 }
400 }
401
402 return ret;
403 }
404
405 // Occasionally things will fly off and really get lost.
406 // Find the wanderers and bring them back.
407 // Return 'true' if some parameter need some sanity.
408 private bool ExtremeSanityCheck(bool inTaintTime)
409 {
410 bool ret = false;
411
412 int wayOverThere = -1000;
413 int wayOutThere = 10000;
414 // There have been instances of objects getting thrown way out of bounds and crashing
415 // the border crossing code.
416 if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere
417 || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere
418 || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere)
419 {
420 RawPosition = new OMV.Vector3(10, 10, 50);
421 ZeroMotion(inTaintTime);
422 ret = true;
423 }
424 if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared)
425 {
426 RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
427 ret = true;
428 }
429 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
430 {
431 _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
432 ret = true;
433 }
434
435 return ret;
436 }
437
438 // Return the effective mass of the object.
439 // The definition of this call is to return the mass of the prim.
440 // If the simulator cares about the mass of the linkset, it will sum it itself.
441 public override float Mass
442 {
443 get { return _mass; }
444 }
445 // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
446 public virtual float TotalMass
447 {
448 get { return _mass; }
449 }
450 // used when we only want this prim's mass and not the linkset thing
451 public override float RawMass {
452 get { return _mass; }
453 }
454 // Set the physical mass to the passed mass.
455 // Note that this does not change _mass!
456 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
457 {
458 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
459 {
460 if (IsStatic)
461 {
462 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
463 Inertia = OMV.Vector3.Zero;
464 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
465 PhysScene.PE.UpdateInertiaTensor(PhysBody);
466 }
467 else
468 {
469 if (inWorld)
470 {
471 // Changing interesting properties doesn't change proxy and collision cache
472 // information. The Bullet solution is to re-add the object to the world
473 // after parameters are changed.
474 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
475 }
476
477 // The computation of mass props requires gravity to be set on the object.
478 Gravity = ComputeGravity(Buoyancy);
479 PhysScene.PE.SetGravity(PhysBody, Gravity);
480
481 // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
482 // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
483
484 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
485 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
486 PhysScene.PE.UpdateInertiaTensor(PhysBody);
487
488 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
489 LocalID, physMass, Inertia, Gravity, inWorld);
490
491 if (inWorld)
492 {
493 AddObjectToPhysicalWorld();
494 }
495 }
496 }
497 }
498
499 // Return what gravity should be set to this very moment
500 public OMV.Vector3 ComputeGravity(float buoyancy)
501 {
502 OMV.Vector3 ret = PhysScene.DefaultGravity;
503
504 if (!IsStatic)
505 {
506 ret *= (1f - buoyancy);
507 ret *= GravModifier;
508 }
509
510 return ret;
511 }
512
513 // Is this used?
514 public override OMV.Vector3 CenterOfMass
515 {
516 get { return RawPosition; }
517 }
518
519 // Is this used?
520 public override OMV.Vector3 GeometricCenter
521 {
522 get { return RawPosition; }
523 }
524
525 public override OMV.Vector3 Force {
526 get { return RawForce; }
527 set {
528 RawForce = value;
529 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
530 {
531 return new BSActorSetForce(PhysScene, this, SetForceActorName);
532 });
533
534 // Call update so actor Refresh() is called to start things off
535 PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate()
536 {
537 UpdatePhysicalParameters();
538 });
539 }
540 }
541
542 // Find and return a handle to the current vehicle actor.
543 // Return 'null' if there is no vehicle actor.
544 public BSDynamics GetVehicleActor(bool createIfNone)
545 {
546 BSDynamics ret = null;
547 BSActor actor;
548 if (PhysicalActors.TryGetActor(VehicleActorName, out actor))
549 {
550 ret = actor as BSDynamics;
551 }
552 else
553 {
554 if (createIfNone)
555 {
556 ret = new BSDynamics(PhysScene, this, VehicleActorName);
557 PhysicalActors.Add(ret.ActorName, ret);
558 }
559 }
560 return ret;
561 }
562
563 public override int VehicleType {
564 get {
565 int ret = (int)Vehicle.TYPE_NONE;
566 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
567 if (vehicleActor != null)
568 ret = (int)vehicleActor.Type;
569 return ret;
570 }
571 set {
572 Vehicle type = (Vehicle)value;
573
574 PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
575 {
576 // Some vehicle scripts change vehicle type on the fly as an easy way to
577 // change all the parameters. Like a plane changing to CAR when on the
578 // ground. In this case, don't want to zero motion.
579 // ZeroMotion(true /* inTaintTime */);
580 if (type == Vehicle.TYPE_NONE)
581 {
582 // Vehicle type is 'none' so get rid of any actor that may have been allocated.
583 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
584 if (vehicleActor != null)
585 {
586 PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
587 }
588 }
589 else
590 {
591 // Vehicle type is not 'none' so create an actor and set it running.
592 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
593 if (vehicleActor != null)
594 {
595 vehicleActor.ProcessTypeChange(type);
596 ActivateIfPhysical(false);
597 }
598 }
599 });
600 }
601 }
602 public override void VehicleFloatParam(int param, float value)
603 {
604 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
605 {
606 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
607 if (vehicleActor != null)
608 {
609 vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
610 ActivateIfPhysical(false);
611 }
612 });
613 }
614 public override void VehicleVectorParam(int param, OMV.Vector3 value)
615 {
616 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
617 {
618 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
619 if (vehicleActor != null)
620 {
621 vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
622 ActivateIfPhysical(false);
623 }
624 });
625 }
626 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
627 {
628 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
629 {
630 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
631 if (vehicleActor != null)
632 {
633 vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
634 ActivateIfPhysical(false);
635 }
636 });
637 }
638 public override void VehicleFlags(int param, bool remove)
639 {
640 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
641 {
642 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
643 if (vehicleActor != null)
644 {
645 vehicleActor.ProcessVehicleFlags(param, remove);
646 }
647 });
648 }
649
650 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
651 public override void SetVolumeDetect(int param) {
652 bool newValue = (param != 0);
653 if (_isVolumeDetect != newValue)
654 {
655 _isVolumeDetect = newValue;
656 PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
657 {
658 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
659 SetObjectDynamic(true);
660 });
661 }
662 return;
663 }
664 public override bool IsVolumeDetect
665 {
666 get { return _isVolumeDetect; }
667 }
668 public override void SetMaterial(int material)
669 {
670 base.SetMaterial(material);
671 PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
672 {
673 UpdatePhysicalParameters();
674 });
675 }
676 public override float Friction
677 {
678 get { return base.Friction; }
679 set
680 {
681 if (base.Friction != value)
682 {
683 base.Friction = value;
684 PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
685 {
686 UpdatePhysicalParameters();
687 });
688 }
689 }
690 }
691 public override float Restitution
692 {
693 get { return base.Restitution; }
694 set
695 {
696 if (base.Restitution != value)
697 {
698 base.Restitution = value;
699 PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
700 {
701 UpdatePhysicalParameters();
702 });
703 }
704 }
705 }
706 // The simulator/viewer keep density as 100kg/m3.
707 // Remember to use BSParam.DensityScaleFactor to create the physical density.
708 public override float Density
709 {
710 get { return base.Density; }
711 set
712 {
713 if (base.Density != value)
714 {
715 base.Density = value;
716 PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
717 {
718 UpdatePhysicalParameters();
719 });
720 }
721 }
722 }
723 public override float GravModifier
724 {
725 get { return base.GravModifier; }
726 set
727 {
728 if (base.GravModifier != value)
729 {
730 base.GravModifier = value;
731 PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
732 {
733 UpdatePhysicalParameters();
734 });
735 }
736 }
737 }
738 public override OMV.Vector3 Velocity {
739 get { return RawVelocity; }
740 set {
741 RawVelocity = value;
742 PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
743 {
744 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
745 ForceVelocity = RawVelocity;
746 });
747 }
748 }
749 public override OMV.Vector3 ForceVelocity {
750 get { return RawVelocity; }
751 set {
752 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
753
754 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
755 if (PhysBody.HasPhysicalBody)
756 {
757 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
758 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
759 ActivateIfPhysical(false);
760 }
761 }
762 }
763 public override OMV.Vector3 Torque {
764 get { return RawTorque; }
765 set {
766 RawTorque = value;
767 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
768 {
769 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
770 });
771 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
772
773 // Call update so actor Refresh() is called to start things off
774 PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate()
775 {
776 UpdatePhysicalParameters();
777 });
778 }
779 }
780 public override OMV.Vector3 Acceleration {
781 get { return _acceleration; }
782 set { _acceleration = value; }
783 }
784
785 public override OMV.Quaternion Orientation {
786 get {
787 return RawOrientation;
788 }
789 set {
790 if (RawOrientation == value)
791 return;
792 RawOrientation = value;
793
794 PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
795 {
796 ForceOrientation = RawOrientation;
797 });
798 }
799 }
800 // Go directly to Bullet to get/set the value.
801 public override OMV.Quaternion ForceOrientation
802 {
803 get
804 {
805 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
806 return RawOrientation;
807 }
808 set
809 {
810 RawOrientation = value;
811 if (PhysBody.HasPhysicalBody)
812 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
813 }
814 }
815 public override int PhysicsActorType {
816 get { return _physicsActorType; }
817 set { _physicsActorType = value; }
818 }
819 public override bool IsPhysical {
820 get { return _isPhysical; }
821 set {
822 if (_isPhysical != value)
823 {
824 _isPhysical = value;
825 PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
826 {
827 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
828 SetObjectDynamic(true);
829 // whether phys-to-static or static-to-phys, the object is not moving.
830 ZeroMotion(true);
831
832 });
833 }
834 }
835 }
836
837 // An object is static (does not move) if selected or not physical
838 public override bool IsStatic
839 {
840 get { return _isSelected || !IsPhysical; }
841 }
842
843 // An object is solid if it's not phantom and if it's not doing VolumeDetect
844 public override bool IsSolid
845 {
846 get { return !IsPhantom && !_isVolumeDetect; }
847 }
848
849 // The object is moving and is actively being dynamic in the physical world
850 public override bool IsPhysicallyActive
851 {
852 get { return !_isSelected && IsPhysical; }
853 }
854
855 // Make gravity work if the object is physical and not selected
856 // Called at taint-time!!
857 private void SetObjectDynamic(bool forceRebuild)
858 {
859 // Recreate the physical object if necessary
860 CreateGeomAndObject(forceRebuild);
861 }
862
863 // Convert the simulator's physical properties into settings on BulletSim objects.
864 // There are four flags we're interested in:
865 // IsStatic: Object does not move, otherwise the object has mass and moves
866 // isSolid: other objects bounce off of this object
867 // isVolumeDetect: other objects pass through but can generate collisions
868 // collisionEvents: whether this object returns collision events
869 // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
870 public virtual void UpdatePhysicalParameters()
871 {
872 if (!PhysBody.HasPhysicalBody)
873 {
874 // This would only happen if updates are called for during initialization when the body is not set up yet.
875 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
876 return;
877 }
878
879 // Mangling all the physical properties requires the object not be in the physical world.
880 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
881 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
882
883 // Set up the object physicalness (does gravity and collisions move this object)
884 MakeDynamic(IsStatic);
885
886 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
887 PhysicalActors.Refresh();
888
889 // Arrange for collision events if the simulator wants them
890 EnableCollisions(SubscribedEvents());
891
892 // Make solid or not (do things bounce off or pass through this object).
893 MakeSolid(IsSolid);
894
895 AddObjectToPhysicalWorld();
896
897 // Rebuild its shape
898 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
899
900 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
901 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
902 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
903 }
904
905 // "Making dynamic" means changing to and from static.
906 // When static, gravity does not effect the object and it is fixed in space.
907 // When dynamic, the object can fall and be pushed by others.
908 // This is independent of its 'solidness' which controls what passes through
909 // this object and what interacts with it.
910 protected virtual void MakeDynamic(bool makeStatic)
911 {
912 if (makeStatic)
913 {
914 // Become a Bullet 'static' object type
915 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
916 // Stop all movement
917 ZeroMotion(true);
918
919 // Set various physical properties so other object interact properly
920 PhysScene.PE.SetFriction(PhysBody, Friction);
921 PhysScene.PE.SetRestitution(PhysBody, Restitution);
922 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
923
924 // Mass is zero which disables a bunch of physics stuff in Bullet
925 UpdatePhysicalMassProperties(0f, false);
926 // Set collision detection parameters
927 if (BSParam.CcdMotionThreshold > 0f)
928 {
929 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
930 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
931 }
932
933 // The activation state is 'disabled' so Bullet will not try to act on it.
934 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
935 // Start it out sleeping and physical actions could wake it up.
936 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
937
938 // This collides like a static object
939 PhysBody.collisionType = CollisionType.Static;
940 }
941 else
942 {
943 // Not a Bullet static object
944 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
945
946 // Set various physical properties so other object interact properly
947 PhysScene.PE.SetFriction(PhysBody, Friction);
948 PhysScene.PE.SetRestitution(PhysBody, Restitution);
949 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
950
951 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
952 // Since this can be called multiple times, only zero forces when becoming physical
953 // PhysicsScene.PE.ClearAllForces(BSBody);
954
955 // For good measure, make sure the transform is set through to the motion state
956 ForcePosition = RawPosition;
957 ForceVelocity = RawVelocity;
958 ForceRotationalVelocity = _rotationalVelocity;
959
960 // A dynamic object has mass
961 UpdatePhysicalMassProperties(RawMass, false);
962
963 // Set collision detection parameters
964 if (BSParam.CcdMotionThreshold > 0f)
965 {
966 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
967 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
968 }
969
970 // Various values for simulation limits
971 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
972 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
973 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
974 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
975
976 // This collides like an object.
977 PhysBody.collisionType = CollisionType.Dynamic;
978
979 // Force activation of the object so Bullet will act on it.
980 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
981 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
982 }
983 }
984
985 // "Making solid" means that other object will not pass through this object.
986 // To make transparent, we create a Bullet ghost object.
987 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
988 // the functions after this one set up the state of a possibly newly created collision body.
989 private void MakeSolid(bool makeSolid)
990 {
991 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
992 if (makeSolid)
993 {
994 // Verify the previous code created the correct shape for this type of thing.
995 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
996 {
997 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
998 }
999 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1000 }
1001 else
1002 {
1003 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
1004 {
1005 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
1006 }
1007 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1008
1009 // Change collision info from a static object to a ghosty collision object
1010 PhysBody.collisionType = CollisionType.VolumeDetect;
1011 }
1012 }
1013
1014 // Turn on or off the flag controlling whether collision events are returned to the simulator.
1015 private void EnableCollisions(bool wantsCollisionEvents)
1016 {
1017 if (wantsCollisionEvents)
1018 {
1019 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1020 }
1021 else
1022 {
1023 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1024 }
1025 }
1026
1027 // Add me to the physical world.
1028 // Object MUST NOT already be in the world.
1029 // This routine exists because some assorted properties get mangled by adding to the world.
1030 internal void AddObjectToPhysicalWorld()
1031 {
1032 if (PhysBody.HasPhysicalBody)
1033 {
1034 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
1035 }
1036 else
1037 {
1038 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
1039 DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
1040 }
1041 }
1042
1043 // prims don't fly
1044 public override bool Flying {
1045 get { return _flying; }
1046 set {
1047 _flying = value;
1048 }
1049 }
1050 public override bool SetAlwaysRun {
1051 get { return _setAlwaysRun; }
1052 set { _setAlwaysRun = value; }
1053 }
1054 public override bool ThrottleUpdates {
1055 get { return _throttleUpdates; }
1056 set { _throttleUpdates = value; }
1057 }
1058 public bool IsPhantom {
1059 get {
1060 // SceneObjectPart removes phantom objects from the physics scene
1061 // so, although we could implement touching and such, we never
1062 // are invoked as a phantom object
1063 return false;
1064 }
1065 }
1066 public override bool FloatOnWater {
1067 set {
1068 _floatOnWater = value;
1069 PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
1070 {
1071 if (_floatOnWater)
1072 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1073 else
1074 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1075 });
1076 }
1077 }
1078 public override OMV.Vector3 RotationalVelocity {
1079 get {
1080 return _rotationalVelocity;
1081 }
1082 set {
1083 _rotationalVelocity = value;
1084 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1085 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1086 PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
1087 {
1088 ForceRotationalVelocity = _rotationalVelocity;
1089 });
1090 }
1091 }
1092 public override OMV.Vector3 ForceRotationalVelocity {
1093 get {
1094 return _rotationalVelocity;
1095 }
1096 set {
1097 _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
1098 if (PhysBody.HasPhysicalBody)
1099 {
1100 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1101 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1102 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1103 ActivateIfPhysical(false);
1104 }
1105 }
1106 }
1107 public override bool Kinematic {
1108 get { return _kinematic; }
1109 set { _kinematic = value;
1110 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
1111 }
1112 }
1113 public override float Buoyancy {
1114 get { return _buoyancy; }
1115 set {
1116 _buoyancy = value;
1117 PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
1118 {
1119 ForceBuoyancy = _buoyancy;
1120 });
1121 }
1122 }
1123 public override float ForceBuoyancy {
1124 get { return _buoyancy; }
1125 set {
1126 _buoyancy = value;
1127 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
1128 // Force the recalculation of the various inertia,etc variables in the object
1129 UpdatePhysicalMassProperties(RawMass, true);
1130 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
1131 ActivateIfPhysical(false);
1132 }
1133 }
1134
1135 public override bool PIDActive
1136 {
1137 get
1138 {
1139 return MoveToTargetActive;
1140 }
1141
1142 set
1143 {
1144 MoveToTargetActive = value;
1145
1146 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1147 {
1148 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1149 });
1150
1151 // Call update so actor Refresh() is called to start things off
1152 PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate()
1153 {
1154 UpdatePhysicalParameters();
1155 });
1156 }
1157 }
1158
1159 public override OMV.Vector3 PIDTarget
1160 {
1161 set
1162 {
1163 base.PIDTarget = value;
1164 BSActor actor;
1165 if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
1166 {
1167 // if the actor exists, tell it to refresh its values.
1168 actor.Refresh();
1169 }
1170
1171 }
1172 }
1173 // Used for llSetHoverHeight and maybe vehicle height
1174 // Hover Height will override MoveTo target's Z
1175 public override bool PIDHoverActive {
1176 set {
1177 base.HoverActive = value;
1178 EnableActor(HoverActive, HoverActorName, delegate()
1179 {
1180 return new BSActorHover(PhysScene, this, HoverActorName);
1181 });
1182
1183 // Call update so actor Refresh() is called to start things off
1184 PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate()
1185 {
1186 UpdatePhysicalParameters();
1187 });
1188 }
1189 }
1190
1191 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1192 // Per documentation, max force is limited.
1193 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1194
1195 // Since this force is being applied in only one step, make this a force per second.
1196 addForce /= PhysScene.LastTimeStep;
1197 AddForce(addForce, pushforce, false /* inTaintTime */);
1198 }
1199
1200 // Applying a force just adds this to the total force on the object.
1201 // This added force will only last the next simulation tick.
1202 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1203 // for an object, doesn't matter if force is a pushforce or not
1204 if (IsPhysicallyActive)
1205 {
1206 if (force.IsFinite())
1207 {
1208 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1209
1210 OMV.Vector3 addForce = force;
1211 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
1212 {
1213 // Bullet adds this central force to the total force for this tick.
1214 // Deep down in Bullet:
1215 // linearVelocity += totalForce / mass * timeStep;
1216 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1217 if (PhysBody.HasPhysicalBody)
1218 {
1219 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1220 ActivateIfPhysical(false);
1221 }
1222 });
1223 }
1224 else
1225 {
1226 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1227 return;
1228 }
1229 }
1230 }
1231
1232 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
1233 // for an object, doesn't matter if force is a pushforce or not
1234 if (!IsPhysicallyActive)
1235 {
1236 if (impulse.IsFinite())
1237 {
1238 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1239 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1240
1241 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
1242 {
1243 // Bullet adds this impulse immediately to the velocity
1244 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1245 if (PhysBody.HasPhysicalBody)
1246 {
1247 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1248 ActivateIfPhysical(false);
1249 }
1250 });
1251 }
1252 else
1253 {
1254 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1255 return;
1256 }
1257 }
1258 }
1259
1260 // BSPhysObject.AddAngularForce()
1261 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1262 {
1263 if (force.IsFinite())
1264 {
1265 OMV.Vector3 angForce = force;
1266 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
1267 {
1268 if (PhysBody.HasPhysicalBody)
1269 {
1270 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1271 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1272 ActivateIfPhysical(false);
1273 }
1274 });
1275 }
1276 else
1277 {
1278 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1279 return;
1280 }
1281 }
1282
1283 // A torque impulse.
1284 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1285 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1286 // Computed as: angularVelocity += impulse * inertia;
1287 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1288 {
1289 OMV.Vector3 applyImpulse = impulse;
1290 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
1291 {
1292 if (PhysBody.HasPhysicalBody)
1293 {
1294 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1295 ActivateIfPhysical(false);
1296 }
1297 });
1298 }
1299
1300 public override void SetMomentum(OMV.Vector3 momentum) {
1301 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1302 }
1303 #region Mass Calculation
1304
1305 private float CalculateMass()
1306 {
1307 float volume = _size.X * _size.Y * _size.Z; // default
1308 float tmp;
1309
1310 float returnMass = 0;
1311 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1312 float hollowVolume = hollowAmount * hollowAmount;
1313
1314 switch (BaseShape.ProfileShape)
1315 {
1316 case ProfileShape.Square:
1317 // default box
1318
1319 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1320 {
1321 if (hollowAmount > 0.0)
1322 {
1323 switch (BaseShape.HollowShape)
1324 {
1325 case HollowShape.Square:
1326 case HollowShape.Same:
1327 break;
1328
1329 case HollowShape.Circle:
1330
1331 hollowVolume *= 0.78539816339f;
1332 break;
1333
1334 case HollowShape.Triangle:
1335
1336 hollowVolume *= (0.5f * .5f);
1337 break;
1338
1339 default:
1340 hollowVolume = 0;
1341 break;
1342 }
1343 volume *= (1.0f - hollowVolume);
1344 }
1345 }
1346
1347 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1348 {
1349 //a tube
1350
1351 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1352 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1353 volume -= volume*tmp*tmp;
1354
1355 if (hollowAmount > 0.0)
1356 {
1357 hollowVolume *= hollowAmount;
1358
1359 switch (BaseShape.HollowShape)
1360 {
1361 case HollowShape.Square:
1362 case HollowShape.Same:
1363 break;
1364
1365 case HollowShape.Circle:
1366 hollowVolume *= 0.78539816339f;;
1367 break;
1368
1369 case HollowShape.Triangle:
1370 hollowVolume *= 0.5f * 0.5f;
1371 break;
1372 default:
1373 hollowVolume = 0;
1374 break;
1375 }
1376 volume *= (1.0f - hollowVolume);
1377 }
1378 }
1379
1380 break;
1381
1382 case ProfileShape.Circle:
1383
1384 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1385 {
1386 volume *= 0.78539816339f; // elipse base
1387
1388 if (hollowAmount > 0.0)
1389 {
1390 switch (BaseShape.HollowShape)
1391 {
1392 case HollowShape.Same:
1393 case HollowShape.Circle:
1394 break;
1395
1396 case HollowShape.Square:
1397 hollowVolume *= 0.5f * 2.5984480504799f;
1398 break;
1399
1400 case HollowShape.Triangle:
1401 hollowVolume *= .5f * 1.27323954473516f;
1402 break;
1403
1404 default:
1405 hollowVolume = 0;
1406 break;
1407 }
1408 volume *= (1.0f - hollowVolume);
1409 }
1410 }
1411
1412 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1413 {
1414 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1415 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1416 volume *= (1.0f - tmp * tmp);
1417
1418 if (hollowAmount > 0.0)
1419 {
1420
1421 // calculate the hollow volume by it's shape compared to the prim shape
1422 hollowVolume *= hollowAmount;
1423
1424 switch (BaseShape.HollowShape)
1425 {
1426 case HollowShape.Same:
1427 case HollowShape.Circle:
1428 break;
1429
1430 case HollowShape.Square:
1431 hollowVolume *= 0.5f * 2.5984480504799f;
1432 break;
1433
1434 case HollowShape.Triangle:
1435 hollowVolume *= .5f * 1.27323954473516f;
1436 break;
1437
1438 default:
1439 hollowVolume = 0;
1440 break;
1441 }
1442 volume *= (1.0f - hollowVolume);
1443 }
1444 }
1445 break;
1446
1447 case ProfileShape.HalfCircle:
1448 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1449 {
1450 volume *= 0.52359877559829887307710723054658f;
1451 }
1452 break;
1453
1454 case ProfileShape.EquilateralTriangle:
1455
1456 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1457 {
1458 volume *= 0.32475953f;
1459
1460 if (hollowAmount > 0.0)
1461 {
1462
1463 // calculate the hollow volume by it's shape compared to the prim shape
1464 switch (BaseShape.HollowShape)
1465 {
1466 case HollowShape.Same:
1467 case HollowShape.Triangle:
1468 hollowVolume *= .25f;
1469 break;
1470
1471 case HollowShape.Square:
1472 hollowVolume *= 0.499849f * 3.07920140172638f;
1473 break;
1474
1475 case HollowShape.Circle:
1476 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1477 // Cyllinder hollow volume calculation
1478
1479 hollowVolume *= 0.1963495f * 3.07920140172638f;
1480 break;
1481
1482 default:
1483 hollowVolume = 0;
1484 break;
1485 }
1486 volume *= (1.0f - hollowVolume);
1487 }
1488 }
1489 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1490 {
1491 volume *= 0.32475953f;
1492 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1493 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1494 volume *= (1.0f - tmp * tmp);
1495
1496 if (hollowAmount > 0.0)
1497 {
1498
1499 hollowVolume *= hollowAmount;
1500
1501 switch (BaseShape.HollowShape)
1502 {
1503 case HollowShape.Same:
1504 case HollowShape.Triangle:
1505 hollowVolume *= .25f;
1506 break;
1507
1508 case HollowShape.Square:
1509 hollowVolume *= 0.499849f * 3.07920140172638f;
1510 break;
1511
1512 case HollowShape.Circle:
1513
1514 hollowVolume *= 0.1963495f * 3.07920140172638f;
1515 break;
1516
1517 default:
1518 hollowVolume = 0;
1519 break;
1520 }
1521 volume *= (1.0f - hollowVolume);
1522 }
1523 }
1524 break;
1525
1526 default:
1527 break;
1528 }
1529
1530
1531
1532 float taperX1;
1533 float taperY1;
1534 float taperX;
1535 float taperY;
1536 float pathBegin;
1537 float pathEnd;
1538 float profileBegin;
1539 float profileEnd;
1540
1541 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1542 {
1543 taperX1 = BaseShape.PathScaleX * 0.01f;
1544 if (taperX1 > 1.0f)
1545 taperX1 = 2.0f - taperX1;
1546 taperX = 1.0f - taperX1;
1547
1548 taperY1 = BaseShape.PathScaleY * 0.01f;
1549 if (taperY1 > 1.0f)
1550 taperY1 = 2.0f - taperY1;
1551 taperY = 1.0f - taperY1;
1552 }
1553 else
1554 {
1555 taperX = BaseShape.PathTaperX * 0.01f;
1556 if (taperX < 0.0f)
1557 taperX = -taperX;
1558 taperX1 = 1.0f - taperX;
1559
1560 taperY = BaseShape.PathTaperY * 0.01f;
1561 if (taperY < 0.0f)
1562 taperY = -taperY;
1563 taperY1 = 1.0f - taperY;
1564
1565 }
1566
1567
1568 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1569
1570 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1571 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1572 volume *= (pathEnd - pathBegin);
1573
1574 // this is crude aproximation
1575 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1576 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1577 volume *= (profileEnd - profileBegin);
1578
1579 returnMass = Density * BSParam.DensityScaleFactor * volume;
1580
1581 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1582 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1583 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
1584 LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
1585
1586 return returnMass;
1587 }// end CalculateMass
1588 #endregion Mass Calculation
1589
1590 // Rebuild the geometry and object.
1591 // This is called when the shape changes so we need to recreate the mesh/hull.
1592 // Called at taint-time!!!
1593 public void CreateGeomAndObject(bool forceRebuild)
1594 {
1595 // Create the correct physical representation for this type of object.
1596 // Updates base.PhysBody and base.PhysShape with the new information.
1597 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1598 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1599 {
1600 // Called if the current prim body is about to be destroyed.
1601 // Remove all the physical dependencies on the old body.
1602 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1603 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1604 RemoveDependencies();
1605 });
1606
1607 // Make sure the properties are set on the new object
1608 UpdatePhysicalParameters();
1609 return;
1610 }
1611
1612 // Called at taint-time
1613 protected virtual void RemoveDependencies()
1614 {
1615 PhysicalActors.RemoveDependencies();
1616 }
1617
1618 #region Extension
1619 public override object Extension(string pFunct, params object[] pParams)
1620 {
1621 DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
1622 object ret = null;
1623 switch (pFunct)
1624 {
1625 case ExtendedPhysics.PhysFunctAxisLockLimits:
1626 ret = SetAxisLockLimitsExtension(pParams);
1627 break;
1628 default:
1629 ret = base.Extension(pFunct, pParams);
1630 break;
1631 }
1632 return ret;
1633 }
1634
1635 private void InitializeAxisActor()
1636 {
1637 EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree,
1638 LockedAxisActorName, delegate()
1639 {
1640 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
1641 });
1642
1643 // Update parameters so the new actor's Refresh() action is called at the right time.
1644 PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate()
1645 {
1646 UpdatePhysicalParameters();
1647 });
1648 }
1649
1650 // Passed an array of an array of parameters, set the axis locking.
1651 // This expects an int (PHYS_AXIS_*) followed by none or two limit floats
1652 // followed by another int and floats, etc.
1653 private object SetAxisLockLimitsExtension(object[] pParams)
1654 {
1655 DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0));
1656 object ret = null;
1657 try
1658 {
1659 if (pParams.GetLength(0) > 1)
1660 {
1661 int index = 2;
1662 while (index < pParams.GetLength(0))
1663 {
1664 var funct = pParams[index];
1665 DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index);
1666 if (funct is Int32 || funct is Int64)
1667 {
1668 switch ((int)funct)
1669 {
1670 // Those that take no parameters
1671 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1672 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1673 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1674 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1675 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1676 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1677 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1678 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1679 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1680 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1681 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1682 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1683 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1684 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1685 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1686 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1687 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1688 ApplyAxisLimits((int)funct, 0f, 0f);
1689 index += 1;
1690 break;
1691 // Those that take two parameters (the limits)
1692 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1693 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1694 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1695 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1696 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1697 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1698 ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]);
1699 index += 3;
1700 break;
1701 default:
1702 m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct);
1703 index += 1;
1704 break;
1705 }
1706 }
1707 }
1708 InitializeAxisActor();
1709 ret = (object)index;
1710 }
1711 }
1712 catch (Exception e)
1713 {
1714 m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e);
1715 ret = null;
1716 }
1717 return ret; // not implemented yet
1718 }
1719
1720 // Set the locking parameters.
1721 // If an axis is locked, the limits for the axis are set to zero,
1722 // If the axis is being constrained, the high and low value are passed and set.
1723 // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range.
1724 protected void ApplyAxisLimits(int funct, float low, float high)
1725 {
1726 DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high);
1727 float linearMax = 23000f;
1728 float angularMax = (float)Math.PI;
1729
1730 switch (funct)
1731 {
1732 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1733 this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1734 this.LockedLinearAxisLow = OMV.Vector3.Zero;
1735 this.LockedLinearAxisHigh = OMV.Vector3.Zero;
1736 break;
1737 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1738 this.LockedLinearAxis.X = LockedAxis;
1739 this.LockedLinearAxisLow.X = 0f;
1740 this.LockedLinearAxisHigh.X = 0f;
1741 break;
1742 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1743 this.LockedLinearAxis.X = LockedAxis;
1744 this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax);
1745 this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax);
1746 break;
1747 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1748 this.LockedLinearAxis.Y = LockedAxis;
1749 this.LockedLinearAxisLow.Y = 0f;
1750 this.LockedLinearAxisHigh.Y = 0f;
1751 break;
1752 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1753 this.LockedLinearAxis.Y = LockedAxis;
1754 this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax);
1755 this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax);
1756 break;
1757 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1758 this.LockedLinearAxis.Z = LockedAxis;
1759 this.LockedLinearAxisLow.Z = 0f;
1760 this.LockedLinearAxisHigh.Z = 0f;
1761 break;
1762 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1763 this.LockedLinearAxis.Z = LockedAxis;
1764 this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax);
1765 this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax);
1766 break;
1767 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1768 this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1769 this.LockedAngularAxisLow = OMV.Vector3.Zero;
1770 this.LockedAngularAxisHigh = OMV.Vector3.Zero;
1771 break;
1772 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1773 this.LockedAngularAxis.X = LockedAxis;
1774 this.LockedAngularAxisLow.X = 0;
1775 this.LockedAngularAxisHigh.X = 0;
1776 break;
1777 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1778 this.LockedAngularAxis.X = LockedAxis;
1779 this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax);
1780 this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax);
1781 break;
1782 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1783 this.LockedAngularAxis.Y = LockedAxis;
1784 this.LockedAngularAxisLow.Y = 0;
1785 this.LockedAngularAxisHigh.Y = 0;
1786 break;
1787 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1788 this.LockedAngularAxis.Y = LockedAxis;
1789 this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax);
1790 this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax);
1791 break;
1792 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1793 this.LockedAngularAxis.Z = LockedAxis;
1794 this.LockedAngularAxisLow.Z = 0;
1795 this.LockedAngularAxisHigh.Z = 0;
1796 break;
1797 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1798 this.LockedAngularAxis.Z = LockedAxis;
1799 this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax);
1800 this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax);
1801 break;
1802 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1803 this.LockedLinearAxis = LockedAxisFree;
1804 this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax);
1805 this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax);
1806 break;
1807 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1808 this.LockedLinearAxis.X = FreeAxis;
1809 this.LockedLinearAxisLow.X = -linearMax;
1810 this.LockedLinearAxisHigh.X = linearMax;
1811 break;
1812 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1813 this.LockedLinearAxis.Y = FreeAxis;
1814 this.LockedLinearAxisLow.Y = -linearMax;
1815 this.LockedLinearAxisHigh.Y = linearMax;
1816 break;
1817 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1818 this.LockedLinearAxis.Z = FreeAxis;
1819 this.LockedLinearAxisLow.Z = -linearMax;
1820 this.LockedLinearAxisHigh.Z = linearMax;
1821 break;
1822 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1823 this.LockedAngularAxis = LockedAxisFree;
1824 this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax);
1825 this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax);
1826 break;
1827 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1828 this.LockedAngularAxis.X = FreeAxis;
1829 this.LockedAngularAxisLow.X = -angularMax;
1830 this.LockedAngularAxisHigh.X = angularMax;
1831 break;
1832 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1833 this.LockedAngularAxis.Y = FreeAxis;
1834 this.LockedAngularAxisLow.Y = -angularMax;
1835 this.LockedAngularAxisHigh.Y = angularMax;
1836 break;
1837 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1838 this.LockedAngularAxis.Z = FreeAxis;
1839 this.LockedAngularAxisLow.Z = -angularMax;
1840 this.LockedAngularAxisHigh.Z = angularMax;
1841 break;
1842 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1843 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f);
1844 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
1845 break;
1846 default:
1847 break;
1848 }
1849 return;
1850 }
1851 #endregion // Extension
1852
1853 // The physics engine says that properties have updated. Update same and inform
1854 // the world that things have changed.
1855 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
1856 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
1857 public override void UpdateProperties(EntityProperties entprop)
1858 {
1859 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1860 TriggerPreUpdatePropertyAction(ref entprop);
1861
1862 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1863
1864 // Assign directly to the local variables so the normal set actions do not happen
1865 RawPosition = entprop.Position;
1866 RawOrientation = entprop.Rotation;
1867 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1868 // very sensitive to velocity changes.
1869 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1870 RawVelocity = entprop.Velocity;
1871 _acceleration = entprop.Acceleration;
1872 _rotationalVelocity = entprop.RotationalVelocity;
1873
1874 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1875
1876 // The sanity check can change the velocity and/or position.
1877 if (PositionSanityCheck(true /* inTaintTime */ ))
1878 {
1879 entprop.Position = RawPosition;
1880 entprop.Velocity = RawVelocity;
1881 entprop.RotationalVelocity = _rotationalVelocity;
1882 entprop.Acceleration = _acceleration;
1883 }
1884
1885 OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
1886 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1887
1888 // remember the current and last set values
1889 LastEntityProperties = CurrentEntityProperties;
1890 CurrentEntityProperties = entprop;
1891
1892 PhysScene.PostUpdate(this);
1893 }
1894}
1895}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
new file mode 100755
index 0000000..d8ed56b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
@@ -0,0 +1,182 @@
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 OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.PhysicsModules.SharedBase;
35
36using OMV = OpenMetaverse;
37
38namespace OpenSim.Region.PhysicsModule.BulletS
39{
40public class BSPrimDisplaced : BSPrim
41{
42 // The purpose of this subclass is to do any mapping between what the simulator thinks
43 // the prim position and orientation is and what the physical position/orientation.
44 // This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
45 // of the prim/linkset. The simulator, on the other hand, tracks the location of
46 // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere
47 // but the origin of the root prim, the physical origin is displaced from the simulator origin.
48 //
49 // This routine works by capturing ForcePosition and
50 // adjusting the simulator values (being set) into the physical values.
51 // The conversion is also done in the opposite direction (physical origin -> simulator origin).
52 //
53 // The updateParameter call is also captured and the values from the physics engine
54 // are converted into simulator origin values before being passed to the base
55 // class.
56
57 // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass.
58 public virtual OMV.Vector3 PositionDisplacement { get; set; }
59
60 public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
61 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
62 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
63 {
64 ClearDisplacement();
65 }
66
67 // Clears any center-of-mass displacement introduced by linksets, etc.
68 // Does not clear the displacement set by the user.
69 public void ClearDisplacement()
70 {
71 if (UserSetCenterOfMassDisplacement.HasValue)
72 PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement;
73 else
74 PositionDisplacement = OMV.Vector3.Zero;
75 }
76
77 // Set this sets and computes the displacement from the passed prim to the center-of-mass.
78 // A user set value for center-of-mass overrides whatever might be passed in here.
79 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
80 // Returns the relative offset from the root position to the center-of-mass.
81 // Called at taint time.
82 public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement)
83 {
84 PhysScene.AssertInTaintTime("BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement");
85 Vector3 comDisp;
86 if (UserSetCenterOfMassDisplacement.HasValue)
87 comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement;
88 else
89 comDisp = centerOfMassDisplacement;
90
91 // Eliminate any jitter caused be very slight differences in masses and positions
92 if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) )
93 comDisp = Vector3.Zero;
94
95 DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}",
96 LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp);
97 if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) )
98 {
99 // Displacement setting is changing.
100 // The relationship between the physical object and simulated object must be aligned.
101 PositionDisplacement = comDisp;
102 this.ForcePosition = RawPosition;
103 }
104
105 return PositionDisplacement;
106 }
107
108 // 'ForcePosition' is the one way to set the physical position of the body in the physics engine.
109 // Displace the simulator idea of position (center of root prim) to the physical position.
110 public override Vector3 ForcePosition
111 {
112 get {
113 OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody);
114 if (PositionDisplacement != OMV.Vector3.Zero)
115 {
116 // If there is some displacement, return the physical position (center-of-mass)
117 // location minus the displacement to give the center of the root prim.
118 OMV.Vector3 displacement = PositionDisplacement * ForceOrientation;
119 DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}",
120 LocalID, physPosition, displacement, physPosition - displacement);
121 physPosition -= displacement;
122 }
123 RawPosition = physPosition;
124 return physPosition;
125 }
126 set
127 {
128 if (PositionDisplacement != OMV.Vector3.Zero)
129 {
130 // This value is the simulator's idea of where the prim is: the center of the root prim
131 RawPosition = value;
132
133 // Move the passed root prim postion to the center-of-mass position and set in the physics engine.
134 OMV.Vector3 displacement = PositionDisplacement * RawOrientation;
135 OMV.Vector3 displacedPos = RawPosition + displacement;
136 DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}",
137 LocalID, RawPosition, displacement, displacedPos);
138 if (PhysBody.HasPhysicalBody)
139 {
140 PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation);
141 ActivateIfPhysical(false);
142 }
143 }
144 else
145 {
146 base.ForcePosition = value;
147 }
148 }
149 }
150
151 // These are also overridden by BSPrimLinkable if the prim can be part of a linkset
152 public override OMV.Vector3 CenterOfMass
153 {
154 get { return RawPosition; }
155 }
156
157 public override OMV.Vector3 GeometricCenter
158 {
159 get { return RawPosition; }
160 }
161
162 public override void UpdateProperties(EntityProperties entprop)
163 {
164 // Undo any center-of-mass displacement that might have been done.
165 if (PositionDisplacement != OMV.Vector3.Zero)
166 {
167 // The origional shape was offset from 'zero' by PositionDisplacement.
168 // These physical location must be back converted to be centered around the displaced
169 // root shape.
170
171 // Move the returned center-of-mass location to the root prim location.
172 OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation;
173 OMV.Vector3 displacedPos = entprop.Position - displacement;
174 DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}",
175 LocalID, entprop.Position, displacement, displacedPos);
176 entprop.Position = displacedPos;
177 }
178
179 base.UpdateProperties(entprop);
180 }
181}
182}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
new file mode 100755
index 0000000..55b5da0
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
@@ -0,0 +1,349 @@
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.Linq;
30using System.Text;
31
32using OpenSim.Framework;
33
34using OMV = OpenMetaverse;
35
36namespace OpenSim.Region.PhysicsModule.BulletS
37{
38public class BSPrimLinkable : BSPrimDisplaced
39{
40 // The purpose of this subclass is to add linkset functionality to the prim. This overrides
41 // operations necessary for keeping the linkset created and, additionally, this
42 // calls the linkset implementation for its creation and management.
43
44#pragma warning disable 414
45 private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]";
46#pragma warning restore 414
47
48 // This adds the overrides for link() and delink() so the prim is linkable.
49
50 public BSLinkset Linkset { get; set; }
51 // The index of this child prim.
52 public int LinksetChildIndex { get; set; }
53
54 public BSLinkset.LinksetImplementation LinksetType { get; set; }
55
56 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
57 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
58 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
59 {
60 // Default linkset implementation for this prim
61 LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation;
62
63 Linkset = BSLinkset.Factory(PhysScene, this);
64
65 Linkset.Refresh(this);
66 }
67
68 public override void Destroy()
69 {
70 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */);
71 base.Destroy();
72 }
73
74 public override void link(OpenSim.Region.PhysicsModules.SharedBase.PhysicsActor obj)
75 {
76 BSPrimLinkable parent = obj as BSPrimLinkable;
77 if (parent != null)
78 {
79 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
80 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
81
82 Linkset = parent.Linkset.AddMeToLinkset(this);
83
84 DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
85 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
86 }
87 return;
88 }
89
90 public override void delink()
91 {
92 // TODO: decide if this parent checking needs to happen at taint time
93 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
94
95 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
96 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
97
98 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/);
99
100 DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
101 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
102 return;
103 }
104
105 // When simulator changes position, this might be moving a child of the linkset.
106 public override OMV.Vector3 Position
107 {
108 get { return base.Position; }
109 set
110 {
111 base.Position = value;
112 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate()
113 {
114 Linkset.UpdateProperties(UpdatedProperties.Position, this);
115 });
116 }
117 }
118
119 // When simulator changes orientation, this might be moving a child of the linkset.
120 public override OMV.Quaternion Orientation
121 {
122 get { return base.Orientation; }
123 set
124 {
125 base.Orientation = value;
126 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate()
127 {
128 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
129 });
130 }
131 }
132
133 public override float TotalMass
134 {
135 get { return Linkset.LinksetMass; }
136 }
137
138 public override OMV.Vector3 CenterOfMass
139 {
140 get { return Linkset.CenterOfMass; }
141 }
142
143 public override OMV.Vector3 GeometricCenter
144 {
145 get { return Linkset.GeometricCenter; }
146 }
147
148 // Refresh the linkset structure and parameters when the prim's physical parameters are changed.
149 public override void UpdatePhysicalParameters()
150 {
151 base.UpdatePhysicalParameters();
152 // Recompute any linkset parameters.
153 // When going from non-physical to physical, this re-enables the constraints that
154 // had been automatically disabled when the mass was set to zero.
155 // For compound based linksets, this enables and disables interactions of the children.
156 if (Linkset != null) // null can happen during initialization
157 Linkset.Refresh(this);
158 }
159
160 // When the prim is made dynamic or static, the linkset needs to change.
161 protected override void MakeDynamic(bool makeStatic)
162 {
163 base.MakeDynamic(makeStatic);
164 if (Linkset != null) // null can happen during initialization
165 {
166 if (makeStatic)
167 Linkset.MakeStatic(this);
168 else
169 Linkset.MakeDynamic(this);
170 }
171 }
172
173 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
174 protected override void RemoveDependencies()
175 {
176 Linkset.RemoveDependencies(this);
177 base.RemoveDependencies();
178 }
179
180 // Called after a simulation step for the changes in physical object properties.
181 // Do any filtering/modification needed for linksets.
182 public override void UpdateProperties(EntityProperties entprop)
183 {
184 if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this))
185 {
186 // Properties are only updated for the roots of a linkset.
187 // TODO: this will have to change when linksets are articulated.
188 base.UpdateProperties(entprop);
189 }
190 /*
191 else
192 {
193 // For debugging, report the movement of children
194 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
195 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
196 entprop.Acceleration, entprop.RotationalVelocity);
197 }
198 */
199 // The linkset might like to know about changing locations
200 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
201 }
202
203 // Called after a simulation step to post a collision with this object.
204 // This returns 'true' if the collision has been queued and the SendCollisions call must
205 // be made at the end of the simulation step.
206 public override bool Collide(uint collidingWith, BSPhysObject collidee,
207 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
208 {
209 bool ret = false;
210 // Ask the linkset if it wants to handle the collision
211 if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth))
212 {
213 // The linkset didn't handle it so pass the collision through normal processing
214 ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
215 }
216 return ret;
217 }
218
219 // A linkset reports any collision on any part of the linkset.
220 public long SomeCollisionSimulationStep = 0;
221 public override bool HasSomeCollision
222 {
223 get
224 {
225 return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding;
226 }
227 set
228 {
229 if (value)
230 SomeCollisionSimulationStep = PhysScene.SimulationStep;
231 else
232 SomeCollisionSimulationStep = 0;
233
234 base.HasSomeCollision = value;
235 }
236 }
237
238 // Convert the existing linkset of this prim into a new type.
239 public bool ConvertLinkset(BSLinkset.LinksetImplementation newType)
240 {
241 bool ret = false;
242 if (LinksetType != newType)
243 {
244 DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType);
245
246 // Set the implementation type first so the call to BSLinkset.Factory gets the new type.
247 this.LinksetType = newType;
248
249 BSLinkset oldLinkset = this.Linkset;
250 BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this);
251
252 this.Linkset = newLinkset;
253
254 // Pick up any physical dependencies this linkset might have in the physics engine.
255 oldLinkset.RemoveDependencies(this);
256
257 // Create a list of the children (mainly because can't interate through a list that's changing)
258 List<BSPrimLinkable> children = new List<BSPrimLinkable>();
259 oldLinkset.ForEachMember((child) =>
260 {
261 if (!oldLinkset.IsRoot(child))
262 children.Add(child);
263 return false; // 'false' says to continue to next member
264 });
265
266 // Remove the children from the old linkset and add to the new (will be a new instance from the factory)
267 foreach (BSPrimLinkable child in children)
268 {
269 oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/);
270 }
271 foreach (BSPrimLinkable child in children)
272 {
273 newLinkset.AddMeToLinkset(child);
274 child.Linkset = newLinkset;
275 }
276
277 // Force the shape and linkset to get reconstructed
278 newLinkset.Refresh(this);
279 this.ForceBodyShapeRebuild(true /* inTaintTime */);
280 }
281 return ret;
282 }
283
284 #region Extension
285 public override object Extension(string pFunct, params object[] pParams)
286 {
287 DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length);
288 object ret = null;
289 switch (pFunct)
290 {
291 // physGetLinksetType();
292 // pParams = [ BSPhysObject root, null ]
293 case ExtendedPhysics.PhysFunctGetLinksetType:
294 {
295 ret = (object)LinksetType;
296 DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret);
297 break;
298 }
299 // physSetLinksetType(type);
300 // pParams = [ BSPhysObject root, null, integer type ]
301 case ExtendedPhysics.PhysFunctSetLinksetType:
302 {
303 if (pParams.Length > 2)
304 {
305 BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2];
306 if (Linkset.IsRoot(this))
307 {
308 PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate()
309 {
310 // Cause the linkset type to change
311 DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}",
312 LocalID, Linkset.LinksetImpl, linksetType);
313 ConvertLinkset(linksetType);
314 });
315 }
316 ret = (object)(int)linksetType;
317 }
318 break;
319 }
320 // physChangeLinkType(linknum, typeCode);
321 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
322 case ExtendedPhysics.PhysFunctChangeLinkType:
323 {
324 ret = Linkset.Extension(pFunct, pParams);
325 break;
326 }
327 // physGetLinkType(linknum);
328 // pParams = [ BSPhysObject root, BSPhysObject child ]
329 case ExtendedPhysics.PhysFunctGetLinkType:
330 {
331 ret = Linkset.Extension(pFunct, pParams);
332 break;
333 }
334 // physChangeLinkParams(linknum, [code, value, code, value, ...]);
335 // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ]
336 case ExtendedPhysics.PhysFunctChangeLinkParams:
337 {
338 ret = Linkset.Extension(pFunct, pParams);
339 break;
340 }
341 default:
342 ret = base.Extension(pFunct, pParams);
343 break;
344 }
345 return ret;
346 }
347 #endregion // Extension
348}
349}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
new file mode 100644
index 0000000..452ce55
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
@@ -0,0 +1,1333 @@
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.Linq;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using System.Text;
33using System.Threading;
34using OpenSim.Framework;
35using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.PhysicsModules.SharedBase;
39using Nini.Config;
40using log4net;
41using OpenMetaverse;
42using Mono.Addins;
43
44namespace OpenSim.Region.PhysicsModule.BulletS
45{
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BulletSPhysicsScene")]
47 public sealed class BSScene : PhysicsScene, IPhysicsParameters, INonSharedRegionModule
48 {
49 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
50 internal static readonly string LogHeader = "[BULLETS SCENE]";
51
52 private bool m_Enabled = false;
53 private IConfigSource m_Config;
54
55 // The name of the region we're working for.
56 public string RegionName { get; private set; }
57
58 public string BulletSimVersion = "?";
59
60 // The handle to the underlying managed or unmanaged version of Bullet being used.
61 public string BulletEngineName { get; private set; }
62 public BSAPITemplate PE;
63
64 // If the physics engine is running on a separate thread
65 public Thread m_physicsThread;
66
67 public Dictionary<uint, BSPhysObject> PhysObjects;
68 public BSShapeCollection Shapes;
69
70 // Keeping track of the objects with collisions so we can report begin and end of a collision
71 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
72 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
73
74 // All the collision processing is protected with this lock object
75 public Object CollisionLock = new Object();
76
77 // Properties are updated here
78 public Object UpdateLock = new Object();
79 public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>();
80
81 // Keep track of all the avatars so we can send them a collision event
82 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> AvatarsInScene = new HashSet<BSPhysObject>();
84 private Object AvatarsInSceneLock = new Object();
85
86 // let my minuions use my logger
87 public ILog Logger { get { return m_log; } }
88
89 public IMesher mesher;
90 public uint WorldID { get; private set; }
91 public BulletWorld World { get; private set; }
92
93 // All the constraints that have been allocated in this instance.
94 public BSConstraintCollection Constraints { get; private set; }
95
96 // Simulation parameters
97 //internal float m_physicsStepTime; // if running independently, the interval simulated by default
98
99 internal int m_maxSubSteps;
100 internal float m_fixedTimeStep;
101
102 internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc.
103
104 internal long m_simulationStep = 0; // The current simulation step.
105 public long SimulationStep { get { return m_simulationStep; } }
106 // A number to use for SimulationStep that is probably not any step value
107 // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step.
108 public static long NotASimulationStep = -1234;
109
110 internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate()
111
112 internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to
113
114 // Physical objects can register for prestep or poststep events
115 public delegate void PreStepAction(float timeStep);
116 public delegate void PostStepAction(float timeStep);
117 public event PreStepAction BeforeStep;
118 public event PostStepAction AfterStep;
119
120 // A value of the time 'now' so all the collision and update routines do not have to get their own
121 // Set to 'now' just before all the prims and actors are called for collisions and updates
122 public int SimulationNowTime { get; private set; }
123
124 // True if initialized and ready to do simulation steps
125 private bool m_initialized = false;
126
127 // Flag which is true when processing taints.
128 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
129 public bool InTaintTime { get; private set; }
130
131 // Pinned memory used to pass step information between managed and unmanaged
132 internal int m_maxCollisionsPerFrame;
133 internal CollisionDesc[] m_collisionArray;
134
135 internal int m_maxUpdatesPerFrame;
136 internal EntityProperties[] m_updateArray;
137
138 /// <summary>
139 /// Used to control physics simulation timing if Bullet is running on its own thread.
140 /// </summary>
141 private ManualResetEvent m_updateWaitEvent;
142
143 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
144 public const uint GROUNDPLANE_ID = 1;
145 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
146
147 public float SimpleWaterLevel { get; set; }
148 public BSTerrainManager TerrainManager { get; private set; }
149
150 public ConfigurationParameters Params
151 {
152 get { return UnmanagedParams[0]; }
153 }
154 public Vector3 DefaultGravity
155 {
156 get { return new Vector3(0f, 0f, Params.gravity); }
157 }
158 // Just the Z value of the gravity
159 public float DefaultGravityZ
160 {
161 get { return Params.gravity; }
162 }
163
164 // When functions in the unmanaged code must be called, it is only
165 // done at a known time just before the simulation step. The taint
166 // system saves all these function calls and executes them in
167 // order before the simulation.
168 public delegate void TaintCallback();
169 private struct TaintCallbackEntry
170 {
171 public String originator;
172 public String ident;
173 public TaintCallback callback;
174 public TaintCallbackEntry(string pIdent, TaintCallback pCallBack)
175 {
176 originator = BSScene.DetailLogZero;
177 ident = pIdent;
178 callback = pCallBack;
179 }
180 public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack)
181 {
182 originator = pOrigin;
183 ident = pIdent;
184 callback = pCallBack;
185 }
186 }
187 private Object _taintLock = new Object(); // lock for using the next object
188 private List<TaintCallbackEntry> _taintOperations;
189 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
190 private List<TaintCallbackEntry> _postStepOperations;
191
192 // A pointer to an instance if this structure is passed to the C++ code
193 // Used to pass basic configuration values to the unmanaged code.
194 internal ConfigurationParameters[] UnmanagedParams;
195
196 // Sometimes you just have to log everything.
197 public LogWriter PhysicsLogging;
198 private bool m_physicsLoggingEnabled;
199 private string m_physicsLoggingDir;
200 private string m_physicsLoggingPrefix;
201 private int m_physicsLoggingFileMinutes;
202 private bool m_physicsLoggingDoFlush;
203 private bool m_physicsPhysicalDumpEnabled;
204 public int PhysicsMetricDumpFrames { get; set; }
205 // 'true' of the vehicle code is to log lots of details
206 public bool VehicleLoggingEnabled { get; private set; }
207 public bool VehiclePhysicalLoggingEnabled { get; private set; }
208
209 #region INonSharedRegionModule
210 public string Name
211 {
212 get { return "BulletSim"; }
213 }
214
215 public Type ReplaceableInterface
216 {
217 get { return null; }
218 }
219
220 public void Initialise(IConfigSource source)
221 {
222 // TODO: Move this out of Startup
223 IConfig config = source.Configs["Startup"];
224 if (config != null)
225 {
226 string physics = config.GetString("physics", string.Empty);
227 if (physics == Name)
228 {
229 m_Enabled = true;
230 m_Config = source;
231 }
232 }
233
234 }
235
236 public void Close()
237 {
238 }
239
240 public void AddRegion(Scene scene)
241 {
242 if (!m_Enabled)
243 return;
244
245 EngineType = Name;
246 RegionName = scene.RegionInfo.RegionName;
247 PhysicsSceneName = EngineType + "/" + RegionName;
248
249 scene.RegisterModuleInterface<PhysicsScene>(this);
250 Vector3 extent = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, scene.RegionInfo.RegionSizeZ);
251 Initialise(m_Config, extent);
252
253 base.Initialise(scene.PhysicsRequestAsset,
254 (scene.Heightmap != null ? scene.Heightmap.GetFloatsSerialised() : new float[scene.RegionInfo.RegionSizeX * scene.RegionInfo.RegionSizeY]),
255 (float)scene.RegionInfo.RegionSettings.WaterHeight);
256
257 }
258
259 public void RemoveRegion(Scene scene)
260 {
261 if (!m_Enabled)
262 return;
263 }
264
265 public void RegionLoaded(Scene scene)
266 {
267 if (!m_Enabled)
268 return;
269
270 mesher = scene.RequestModuleInterface<IMesher>();
271 if (mesher == null)
272 m_log.WarnFormat("{0} No mesher. Things will not work well.", LogHeader);
273
274 scene.PhysicsEnabled = true;
275 }
276 #endregion
277
278 #region Initialization
279
280 private void Initialise(IConfigSource config, Vector3 regionExtent)
281 {
282 _taintOperations = new List<TaintCallbackEntry>();
283 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
284 _postStepOperations = new List<TaintCallbackEntry>();
285 PhysObjects = new Dictionary<uint, BSPhysObject>();
286 Shapes = new BSShapeCollection(this);
287
288 m_simulatedTime = 0f;
289 LastTimeStep = 0.1f;
290
291 // Allocate pinned memory to pass parameters.
292 UnmanagedParams = new ConfigurationParameters[1];
293
294 // Set default values for physics parameters plus any overrides from the ini file
295 GetInitialParameterValues(config);
296
297 // Force some parameters to values depending on other configurations
298 // Only use heightmap terrain implementation if terrain larger than legacy size
299 if ((uint)regionExtent.X > Constants.RegionSize || (uint)regionExtent.Y > Constants.RegionSize)
300 {
301 m_log.WarnFormat("{0} Forcing terrain implementation to heightmap for large region", LogHeader);
302 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
303 }
304
305 // Get the connection to the physics engine (could be native or one of many DLLs)
306 PE = SelectUnderlyingBulletEngine(BulletEngineName);
307
308 // Enable very detailed logging.
309 // By creating an empty logger when not logging, the log message invocation code
310 // can be left in and every call doesn't have to check for null.
311 if (m_physicsLoggingEnabled)
312 {
313 PhysicsLogging = new LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush);
314 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages.
315 }
316 else
317 {
318 PhysicsLogging = new LogWriter();
319 }
320
321 // Allocate memory for returning of the updates and collisions from the physics engine
322 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
323 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
324
325 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
326 // a child in a mega-region.
327 // Bullet actually doesn't care about the extents of the simulated
328 // area. It tracks active objects no matter where they are.
329 Vector3 worldExtent = regionExtent;
330
331 World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
332
333 Constraints = new BSConstraintCollection(World);
334
335 TerrainManager = new BSTerrainManager(this, worldExtent);
336 TerrainManager.CreateInitialGroundPlaneAndTerrain();
337
338 // Put some informational messages into the log file.
339 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
340
341 InTaintTime = false;
342 m_initialized = true;
343
344 // If the physics engine runs on its own thread, start same.
345 if (BSParam.UseSeparatePhysicsThread)
346 {
347 // The physics simulation should happen independently of the heartbeat loop
348 m_physicsThread
349 = WorkManager.StartThread(
350 BulletSPluginPhysicsThread,
351 string.Format("{0} ({1})", BulletEngineName, RegionName),
352 ThreadPriority.Normal,
353 true,
354 true);
355 }
356 }
357
358 // All default parameter values are set here. There should be no values set in the
359 // variable definitions.
360 private void GetInitialParameterValues(IConfigSource config)
361 {
362 ConfigurationParameters parms = new ConfigurationParameters();
363 UnmanagedParams[0] = parms;
364
365 BSParam.SetParameterDefaultValues(this);
366
367 if (config != null)
368 {
369 // If there are specifications in the ini file, use those values
370 IConfig pConfig = config.Configs["BulletSim"];
371 if (pConfig != null)
372 {
373 BSParam.SetParameterConfigurationValues(this, pConfig);
374
375 // There are two Bullet implementations to choose from
376 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
377
378 // Very detailed logging for physics debugging
379 // TODO: the boolean values can be moved to the normal parameter processing.
380 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
381 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
382 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
383 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
384 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
385 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
386 // Very detailed logging for vehicle debugging
387 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
388 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
389
390 // Do any replacements in the parameters
391 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
392 }
393 else
394 {
395 // Nothing in the configuration INI file so assume unmanaged and other defaults.
396 BulletEngineName = "BulletUnmanaged";
397 m_physicsLoggingEnabled = false;
398 VehicleLoggingEnabled = false;
399 }
400
401 // The material characteristics.
402 BSMaterials.InitializeFromDefaults(Params);
403 if (pConfig != null)
404 {
405 // Let the user add new and interesting material property values.
406 BSMaterials.InitializefromParameters(pConfig);
407 }
408 }
409 }
410
411 // A helper function that handles a true/false parameter and returns the proper float number encoding
412 float ParamBoolean(IConfig config, string parmName, float deflt)
413 {
414 float ret = deflt;
415 if (config.Contains(parmName))
416 {
417 ret = ConfigurationParameters.numericFalse;
418 if (config.GetBoolean(parmName, false))
419 {
420 ret = ConfigurationParameters.numericTrue;
421 }
422 }
423 return ret;
424 }
425
426 // Select the connection to the actual Bullet implementation.
427 // The main engine selection is the engineName up to the first hypen.
428 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
429 // is passed to the engine to do its special selection, etc.
430 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
431 {
432 // For the moment, do a simple switch statement.
433 // Someday do fancyness with looking up the interfaces in the assembly.
434 BSAPITemplate ret = null;
435
436 string selectionName = engineName.ToLower();
437 int hyphenIndex = engineName.IndexOf("-");
438 if (hyphenIndex > 0)
439 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
440
441 switch (selectionName)
442 {
443 case "bullet":
444 case "bulletunmanaged":
445 ret = new BSAPIUnman(engineName, this);
446 break;
447 case "bulletxna":
448 ret = new BSAPIXNA(engineName, this);
449 // Disable some features that are not implemented in BulletXNA
450 m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
451 m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader);
452 BSParam.ShouldUseBulletHACD = false;
453 m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader);
454 BSParam.ShouldUseSingleConvexHullForPrims = false;
455 m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader);
456 BSParam.ShouldUseGImpactShapeForPrims = false;
457 m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader);
458 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
459 break;
460 }
461
462 if (ret == null)
463 {
464 m_log.ErrorFormat("{0} COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
465 }
466 else
467 {
468 m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
469 }
470
471 return ret;
472 }
473
474 public override void Dispose()
475 {
476 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
477
478 // make sure no stepping happens while we're deleting stuff
479 m_initialized = false;
480
481 lock (PhysObjects)
482 {
483 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
484 {
485 kvp.Value.Destroy();
486 }
487 PhysObjects.Clear();
488 }
489
490 // Now that the prims are all cleaned up, there should be no constraints left
491 if (Constraints != null)
492 {
493 Constraints.Dispose();
494 Constraints = null;
495 }
496
497 if (Shapes != null)
498 {
499 Shapes.Dispose();
500 Shapes = null;
501 }
502
503 if (TerrainManager != null)
504 {
505 TerrainManager.ReleaseGroundPlaneAndTerrain();
506 TerrainManager.Dispose();
507 TerrainManager = null;
508 }
509
510 // Anything left in the unmanaged code should be cleaned out
511 PE.Shutdown(World);
512
513 // Not logging any more
514 PhysicsLogging.Close();
515 }
516 #endregion // Construction and Initialization
517
518 #region Prim and Avatar addition and removal
519
520 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
521 {
522 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
523 return null;
524 }
525
526 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
527 {
528 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
529
530 if (!m_initialized) return null;
531
532 BSCharacter actor = new BSCharacter(localID, avName, this, position, velocity, size, isFlying);
533 lock (PhysObjects)
534 PhysObjects.Add(localID, actor);
535
536 // TODO: Remove kludge someday.
537 // We must generate a collision for avatars whether they collide or not.
538 // This is required by OpenSim to update avatar animations, etc.
539 lock (AvatarsInSceneLock)
540 AvatarsInScene.Add(actor);
541
542 return actor;
543 }
544
545 public override void RemoveAvatar(PhysicsActor actor)
546 {
547 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
548
549 if (!m_initialized) return;
550
551 BSCharacter bsactor = actor as BSCharacter;
552 if (bsactor != null)
553 {
554 try
555 {
556 lock (PhysObjects)
557 PhysObjects.Remove(bsactor.LocalID);
558 // Remove kludge someday
559 lock (AvatarsInSceneLock)
560 AvatarsInScene.Remove(bsactor);
561 }
562 catch (Exception e)
563 {
564 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
565 }
566 bsactor.Destroy();
567 // bsactor.dispose();
568 }
569 else
570 {
571 m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}",
572 LogHeader, actor.LocalID, actor.GetType().Name);
573 }
574 }
575
576 public override void RemovePrim(PhysicsActor prim)
577 {
578 if (!m_initialized) return;
579
580 BSPhysObject bsprim = prim as BSPhysObject;
581 if (bsprim != null)
582 {
583 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
584 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
585 try
586 {
587 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
588 }
589 catch (Exception e)
590 {
591 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
592 }
593 bsprim.Destroy();
594 // bsprim.dispose();
595 }
596 else
597 {
598 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
599 }
600 }
601
602 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
603 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
604 {
605 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
606
607 if (!m_initialized) return null;
608
609 // DetailLog("{0},BSScene.AddPrimShape,call", localID);
610
611 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
612 lock (PhysObjects) PhysObjects.Add(localID, prim);
613 return prim;
614 }
615
616 // This is a call from the simulator saying that some physical property has been updated.
617 // The BulletSim driver senses the changing of relevant properties so this taint
618 // information call is not needed.
619 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
620
621 #endregion // Prim and Avatar addition and removal
622
623 #region Simulation
624
625 // Call from the simulator to send physics information to the simulator objects.
626 // This pushes all the collision and property update events into the objects in
627 // the simulator and, since it is on the heartbeat thread, there is an implicit
628 // locking of those data structures from other heartbeat events.
629 // If the physics engine is running on a separate thread, the update information
630 // will be in the ObjectsWithCollions and ObjectsWithUpdates structures.
631 public override float Simulate(float timeStep)
632 {
633 if (!BSParam.UseSeparatePhysicsThread)
634 {
635 DoPhysicsStep(timeStep);
636 }
637 return SendUpdatesToSimulator(timeStep);
638 }
639
640 // Call the physics engine to do one 'timeStep' and collect collisions and updates
641 // into ObjectsWithCollisions and ObjectsWithUpdates data structures.
642 private void DoPhysicsStep(float timeStep)
643 {
644 // prevent simulation until we've been initialized
645 if (!m_initialized) return;
646
647 LastTimeStep = timeStep;
648
649 int updatedEntityCount = 0;
650 int collidersCount = 0;
651
652 int beforeTime = Util.EnvironmentTickCount();
653 int simTime = 0;
654
655 int numTaints = _taintOperations.Count;
656 InTaintTime = true; // Only used for debugging so locking is not necessary.
657
658 // update the prim states while we know the physics engine is not busy
659 ProcessTaints();
660
661 // Some of the physical objects requre individual, pre-step calls
662 // (vehicles and avatar movement, in particular)
663 TriggerPreStepEvent(timeStep);
664
665 // the prestep actions might have added taints
666 numTaints += _taintOperations.Count;
667 ProcessTaints();
668
669 InTaintTime = false; // Only used for debugging so locking is not necessary.
670
671 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
672 // Only enable this in a limited test world with few objects.
673 if (m_physicsPhysicalDumpEnabled)
674 PE.DumpAllInfo(World);
675
676 // step the physical world one interval
677 m_simulationStep++;
678 int numSubSteps = 0;
679 try
680 {
681 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
682
683 }
684 catch (Exception e)
685 {
686 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
687 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
688 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
689 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
690 updatedEntityCount = 0;
691 collidersCount = 0;
692 }
693
694 // Make the physics engine dump useful statistics periodically
695 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
696 PE.DumpPhysicsStatistics(World);
697
698 // Get a value for 'now' so all the collision and update routines don't have to get their own.
699 SimulationNowTime = Util.EnvironmentTickCount();
700
701 // Send collision information to the colliding objects. The objects decide if the collision
702 // is 'real' (like linksets don't collide with themselves) and the individual objects
703 // know if the simulator has subscribed to collisions.
704 lock (CollisionLock)
705 {
706 if (collidersCount > 0)
707 {
708 lock (PhysObjects)
709 {
710 for (int ii = 0; ii < collidersCount; ii++)
711 {
712 uint cA = m_collisionArray[ii].aID;
713 uint cB = m_collisionArray[ii].bID;
714 Vector3 point = m_collisionArray[ii].point;
715 Vector3 normal = m_collisionArray[ii].normal;
716 float penetration = m_collisionArray[ii].penetration;
717 SendCollision(cA, cB, point, normal, penetration);
718 SendCollision(cB, cA, point, -normal, penetration);
719 }
720 }
721 }
722 }
723
724 // If any of the objects had updated properties, tell the managed objects about the update
725 // and remember that there was a change so it will be passed to the simulator.
726 lock (UpdateLock)
727 {
728 if (updatedEntityCount > 0)
729 {
730 lock (PhysObjects)
731 {
732 for (int ii = 0; ii < updatedEntityCount; ii++)
733 {
734 EntityProperties entprop = m_updateArray[ii];
735 BSPhysObject pobj;
736 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
737 {
738 if (pobj.IsInitialized)
739 pobj.UpdateProperties(entprop);
740 }
741 }
742 }
743 }
744 }
745
746 // Some actors want to know when the simulation step is complete.
747 TriggerPostStepEvent(timeStep);
748
749 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
750 if (PhysicsLogging.Enabled)
751 {
752 DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
753 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
754 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
755 }
756
757 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
758 // Only enable this in a limited test world with few objects.
759 if (m_physicsPhysicalDumpEnabled)
760 PE.DumpAllInfo(World);
761
762 // The physics engine returns the number of milliseconds it simulated this call.
763 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
764 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
765 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
766 }
767
768 // Called by a BSPhysObject to note that it has changed properties and this information
769 // should be passed up to the simulator at the proper time.
770 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
771 // this is is under UpdateLock.
772 public void PostUpdate(BSPhysObject updatee)
773 {
774 lock (UpdateLock)
775 {
776 ObjectsWithUpdates.Add(updatee);
777 }
778 }
779
780 // The simulator thinks it is physics time so return all the collisions and position
781 // updates that were collected in actual physics simulation.
782 private float SendUpdatesToSimulator(float timeStep)
783 {
784 if (!m_initialized) return 5.0f;
785
786 DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
787 BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
788 // Push the collisions into the simulator.
789 lock (CollisionLock)
790 {
791 if (ObjectsWithCollisions.Count > 0)
792 {
793 foreach (BSPhysObject bsp in ObjectsWithCollisions)
794 if (!bsp.SendCollisions())
795 {
796 // If the object is done colliding, see that it's removed from the colliding list
797 ObjectsWithNoMoreCollisions.Add(bsp);
798 }
799 }
800
801 // This is a kludge to get avatar movement updates.
802 // The simulator expects collisions for avatars even if there are have been no collisions.
803 // The event updates avatar animations and stuff.
804 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
805 // Note that we get a copy of the list to search because SendCollision() can take a while.
806 HashSet<BSPhysObject> tempAvatarsInScene;
807 lock (AvatarsInSceneLock)
808 {
809 tempAvatarsInScene = new HashSet<BSPhysObject>(AvatarsInScene);
810 }
811 foreach (BSPhysObject actor in tempAvatarsInScene)
812 {
813 if (!ObjectsWithCollisions.Contains(actor)) // don't call avatars twice
814 actor.SendCollisions();
815 }
816 tempAvatarsInScene = null;
817
818 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
819 // Not done above because it is inside an iteration of ObjectWithCollisions.
820 // This complex collision processing is required to create an empty collision
821 // event call after all real collisions have happened on an object. This allows
822 // the simulator to generate the 'collision end' event.
823 if (ObjectsWithNoMoreCollisions.Count > 0)
824 {
825 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
826 ObjectsWithCollisions.Remove(po);
827 ObjectsWithNoMoreCollisions.Clear();
828 }
829 }
830
831 // Call the simulator for each object that has physics property updates.
832 HashSet<BSPhysObject> updatedObjects = null;
833 lock (UpdateLock)
834 {
835 if (ObjectsWithUpdates.Count > 0)
836 {
837 updatedObjects = ObjectsWithUpdates;
838 ObjectsWithUpdates = new HashSet<BSPhysObject>();
839 }
840 }
841 if (updatedObjects != null)
842 {
843 foreach (BSPhysObject obj in updatedObjects)
844 {
845 obj.RequestPhysicsterseUpdate();
846 }
847 updatedObjects.Clear();
848 }
849
850 // Return the framerate simulated to give the above returned results.
851 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
852 float simTime = m_simulatedTime;
853 m_simulatedTime = 0f;
854 return simTime;
855 }
856
857 // Something has collided
858 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
859 {
860 if (localID <= TerrainManager.HighestTerrainID)
861 {
862 return; // don't send collisions to the terrain
863 }
864
865 BSPhysObject collider;
866 // NOTE that PhysObjects was locked before the call to SendCollision().
867 if (!PhysObjects.TryGetValue(localID, out collider))
868 {
869 // If the object that is colliding cannot be found, just ignore the collision.
870 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
871 return;
872 }
873
874 // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
875 BSPhysObject collidee = null;
876 PhysObjects.TryGetValue(collidingWith, out collidee);
877
878 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
879
880 if (collider.IsInitialized)
881 {
882 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
883 {
884 // If a collision was 'good', remember to send it to the simulator
885 lock (CollisionLock)
886 {
887 ObjectsWithCollisions.Add(collider);
888 }
889 }
890 }
891
892 return;
893 }
894
895 public void BulletSPluginPhysicsThread()
896 {
897 Thread.CurrentThread.Priority = ThreadPriority.Highest;
898 m_updateWaitEvent = new ManualResetEvent(false);
899
900 while (m_initialized)
901 {
902 int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
903
904 if (BSParam.Active)
905 DoPhysicsStep(BSParam.PhysicsTimeStep);
906
907 int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
908 int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
909
910 if (simulationTimeVsRealtimeDifferenceMS > 0)
911 {
912 // The simulation of the time interval took less than realtime.
913 // Do a wait for the rest of realtime.
914 m_updateWaitEvent.WaitOne(simulationTimeVsRealtimeDifferenceMS);
915 //Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
916 }
917 else
918 {
919 // The simulation took longer than realtime.
920 // Do some scaling of simulation time.
921 // TODO.
922 DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
923 }
924
925 Watchdog.UpdateThread();
926 }
927
928 Watchdog.RemoveThread();
929 }
930
931 #endregion // Simulation
932
933 public override void GetResults() { }
934
935 #region Terrain
936
937 public override void SetTerrain(float[] heightMap) {
938 TerrainManager.SetTerrain(heightMap);
939 }
940
941 public override void SetWaterLevel(float baseheight)
942 {
943 SimpleWaterLevel = baseheight;
944 }
945
946 public override void DeleteTerrain()
947 {
948 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
949 }
950
951 // Although no one seems to check this, I do support combining.
952 public override bool SupportsCombining()
953 {
954 return TerrainManager.SupportsCombining();
955 }
956 // This call says I am a child to region zero in a mega-region. 'pScene' is that
957 // of region zero, 'offset' is my offset from regions zero's origin, and
958 // 'extents' is the largest XY that is handled in my region.
959 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
960 {
961 TerrainManager.Combine(pScene, offset, extents);
962 }
963
964 // Unhook all the combining that I know about.
965 public override void UnCombine(PhysicsScene pScene)
966 {
967 TerrainManager.UnCombine(pScene);
968 }
969
970 #endregion // Terrain
971
972 public override Dictionary<uint, float> GetTopColliders()
973 {
974 Dictionary<uint, float> topColliders;
975
976 lock (PhysObjects)
977 {
978 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
979 {
980 kvp.Value.ComputeCollisionScore();
981 }
982
983 List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values);
984 orderedPrims.OrderByDescending(p => p.CollisionScore);
985 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
986 }
987
988 return topColliders;
989 }
990
991 public override bool IsThreaded { get { return false; } }
992
993 #region Extensions
994 public override object Extension(string pFunct, params object[] pParams)
995 {
996 DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct);
997 return base.Extension(pFunct, pParams);
998 }
999 #endregion // Extensions
1000
1001 public static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs)
1002 {
1003 float pathShearX = pbs.PathShearX < 128 ? (float)pbs.PathShearX * 0.01f : (float)(pbs.PathShearX - 256) * 0.01f;
1004 float pathShearY = pbs.PathShearY < 128 ? (float)pbs.PathShearY * 0.01f : (float)(pbs.PathShearY - 256) * 0.01f;
1005 float pathBegin = (float)pbs.PathBegin * 2.0e-5f;
1006 float pathEnd = 1.0f - (float)pbs.PathEnd * 2.0e-5f;
1007 float pathScaleX = (float)(200 - pbs.PathScaleX) * 0.01f;
1008 float pathScaleY = (float)(200 - pbs.PathScaleY) * 0.01f;
1009 float pathTaperX = pbs.PathTaperX * 0.01f;
1010 float pathTaperY = pbs.PathTaperY * 0.01f;
1011
1012 float profileBegin = (float)pbs.ProfileBegin * 2.0e-5f;
1013 float profileEnd = 1.0f - (float)pbs.ProfileEnd * 2.0e-5f;
1014 float profileHollow = (float)pbs.ProfileHollow * 2.0e-5f;
1015 if (profileHollow > 0.95f)
1016 profileHollow = 0.95f;
1017
1018 StringBuilder buff = new StringBuilder();
1019 buff.Append("shape=");
1020 buff.Append(((ProfileShape)pbs.ProfileShape).ToString());
1021 buff.Append(",");
1022 buff.Append("hollow=");
1023 buff.Append(((HollowShape)pbs.HollowShape).ToString());
1024 buff.Append(",");
1025 buff.Append("pathCurve=");
1026 buff.Append(((Extrusion)pbs.PathCurve).ToString());
1027 buff.Append(",");
1028 buff.Append("profCurve=");
1029 buff.Append(((Extrusion)pbs.ProfileCurve).ToString());
1030 buff.Append(",");
1031 buff.Append("profHollow=");
1032 buff.Append(profileHollow.ToString());
1033 buff.Append(",");
1034 buff.Append("pathBegEnd=");
1035 buff.Append(pathBegin.ToString());
1036 buff.Append("/");
1037 buff.Append(pathEnd.ToString());
1038 buff.Append(",");
1039 buff.Append("profileBegEnd=");
1040 buff.Append(profileBegin.ToString());
1041 buff.Append("/");
1042 buff.Append(profileEnd.ToString());
1043 buff.Append(",");
1044 buff.Append("scaleXY=");
1045 buff.Append(pathScaleX.ToString());
1046 buff.Append("/");
1047 buff.Append(pathScaleY.ToString());
1048 buff.Append(",");
1049 buff.Append("shearXY=");
1050 buff.Append(pathShearX.ToString());
1051 buff.Append("/");
1052 buff.Append(pathShearY.ToString());
1053 buff.Append(",");
1054 buff.Append("taperXY=");
1055 buff.Append(pbs.PathTaperX.ToString());
1056 buff.Append("/");
1057 buff.Append(pbs.PathTaperY.ToString());
1058 buff.Append(",");
1059 buff.Append("skew=");
1060 buff.Append(pbs.PathSkew.ToString());
1061 buff.Append(",");
1062 buff.Append("twist/Beg=");
1063 buff.Append(pbs.PathTwist.ToString());
1064 buff.Append("/");
1065 buff.Append(pbs.PathTwistBegin.ToString());
1066
1067 return buff.ToString();
1068 }
1069
1070 #region Taints
1071 // The simulation execution order is:
1072 // Simulate()
1073 // DoOneTimeTaints
1074 // TriggerPreStepEvent
1075 // DoOneTimeTaints
1076 // Step()
1077 // ProcessAndSendToSimulatorCollisions
1078 // ProcessAndSendToSimulatorPropertyUpdates
1079 // TriggerPostStepEvent
1080
1081 // Calls to the PhysicsActors can't directly call into the physics engine
1082 // because it might be busy. We delay changes to a known time.
1083 // We rely on C#'s closure to save and restore the context for the delegate.
1084 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
1085 {
1086 TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback);
1087 }
1088 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
1089 {
1090 TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1091 }
1092 public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1093 {
1094 TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
1095 }
1096 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1097 {
1098 TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1099 }
1100 // Sometimes a potentially tainted operation can be used in and out of taint time.
1101 // This routine executes the command immediately if in taint-time otherwise it is queued.
1102 public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback)
1103 {
1104 if (!m_initialized) return;
1105
1106 if (inTaintTime)
1107 pCallback();
1108 else
1109 {
1110 lock (_taintLock)
1111 {
1112 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
1113 }
1114 }
1115 }
1116
1117 private void TriggerPreStepEvent(float timeStep)
1118 {
1119 PreStepAction actions = BeforeStep;
1120 if (actions != null)
1121 actions(timeStep);
1122
1123 }
1124
1125 private void TriggerPostStepEvent(float timeStep)
1126 {
1127 PostStepAction actions = AfterStep;
1128 if (actions != null)
1129 actions(timeStep);
1130
1131 }
1132
1133 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
1134 // a callback into itself to do the actual property change. That callback is called
1135 // here just before the physics engine is called to step the simulation.
1136 public void ProcessTaints()
1137 {
1138 ProcessRegularTaints();
1139 ProcessPostTaintTaints();
1140 }
1141
1142 private void ProcessRegularTaints()
1143 {
1144 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
1145 {
1146 // swizzle a new list into the list location so we can process what's there
1147 List<TaintCallbackEntry> oldList;
1148 lock (_taintLock)
1149 {
1150 oldList = _taintOperations;
1151 _taintOperations = new List<TaintCallbackEntry>();
1152 }
1153
1154 foreach (TaintCallbackEntry tcbe in oldList)
1155 {
1156 try
1157 {
1158 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
1159 tcbe.callback();
1160 }
1161 catch (Exception e)
1162 {
1163 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
1164 }
1165 }
1166 oldList.Clear();
1167 }
1168 }
1169
1170 // Schedule an update to happen after all the regular taints are processed.
1171 // Note that new requests for the same operation ("ident") for the same object ("ID")
1172 // will replace any previous operation by the same object.
1173 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
1174 {
1175 string IDAsString = ID.ToString();
1176 string uniqueIdent = ident + "-" + IDAsString;
1177 lock (_taintLock)
1178 {
1179 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback);
1180 }
1181
1182 return;
1183 }
1184
1185 // Taints that happen after the normal taint processing but before the simulation step.
1186 private void ProcessPostTaintTaints()
1187 {
1188 if (m_initialized && _postTaintOperations.Count > 0)
1189 {
1190 Dictionary<string, TaintCallbackEntry> oldList;
1191 lock (_taintLock)
1192 {
1193 oldList = _postTaintOperations;
1194 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
1195 }
1196
1197 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
1198 {
1199 try
1200 {
1201 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
1202 kvp.Value.callback();
1203 }
1204 catch (Exception e)
1205 {
1206 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
1207 }
1208 }
1209 oldList.Clear();
1210 }
1211 }
1212
1213 // Only used for debugging. Does not change state of anything so locking is not necessary.
1214 public bool AssertInTaintTime(string whereFrom)
1215 {
1216 if (!InTaintTime)
1217 {
1218 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
1219 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
1220 // Util.PrintCallStack(DetailLog);
1221 }
1222 return InTaintTime;
1223 }
1224
1225 #endregion // Taints
1226
1227 #region IPhysicsParameters
1228 // Get the list of parameters this physics engine supports
1229 public PhysParameterEntry[] GetParameterList()
1230 {
1231 BSParam.BuildParameterTable();
1232 return BSParam.SettableParameters;
1233 }
1234
1235 // Set parameter on a specific or all instances.
1236 // Return 'false' if not able to set the parameter.
1237 // Setting the value in the m_params block will change the value the physics engine
1238 // will use the next time since it's pinned and shared memory.
1239 // Some of the values require calling into the physics engine to get the new
1240 // value activated ('terrainFriction' for instance).
1241 public bool SetPhysicsParameter(string parm, string val, uint localID)
1242 {
1243 bool ret = false;
1244
1245 BSParam.ParameterDefnBase theParam;
1246 if (BSParam.TryGetParameter(parm, out theParam))
1247 {
1248 // Set the value in the C# code
1249 theParam.SetValue(this, val);
1250
1251 // Optionally set the parameter in the unmanaged code
1252 if (theParam.HasSetOnObject)
1253 {
1254 // update all the localIDs specified
1255 // If the local ID is APPLY_TO_NONE, just change the default value
1256 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1257 // If the localID is a specific object, apply the parameter change to only that object
1258 List<uint> objectIDs = new List<uint>();
1259 switch (localID)
1260 {
1261 case PhysParameterEntry.APPLY_TO_NONE:
1262 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1263 objectIDs.Add(TERRAIN_ID);
1264 TaintedUpdateParameter(parm, objectIDs, val);
1265 break;
1266 case PhysParameterEntry.APPLY_TO_ALL:
1267 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1268 TaintedUpdateParameter(parm, objectIDs, val);
1269 break;
1270 default:
1271 // setting only one localID
1272 objectIDs.Add(localID);
1273 TaintedUpdateParameter(parm, objectIDs, val);
1274 break;
1275 }
1276 }
1277
1278 ret = true;
1279 }
1280 return ret;
1281 }
1282
1283 // schedule the actual updating of the paramter to when the phys engine is not busy
1284 private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val)
1285 {
1286 string xval = val;
1287 List<uint> xlIDs = lIDs;
1288 string xparm = parm;
1289 TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() {
1290 BSParam.ParameterDefnBase thisParam;
1291 if (BSParam.TryGetParameter(xparm, out thisParam))
1292 {
1293 if (thisParam.HasSetOnObject)
1294 {
1295 foreach (uint lID in xlIDs)
1296 {
1297 BSPhysObject theObject = null;
1298 if (PhysObjects.TryGetValue(lID, out theObject))
1299 thisParam.SetOnObject(this, theObject);
1300 }
1301 }
1302 }
1303 });
1304 }
1305
1306 // Get parameter.
1307 // Return 'false' if not able to get the parameter.
1308 public bool GetPhysicsParameter(string parm, out string value)
1309 {
1310 string val = String.Empty;
1311 bool ret = false;
1312 BSParam.ParameterDefnBase theParam;
1313 if (BSParam.TryGetParameter(parm, out theParam))
1314 {
1315 val = theParam.GetValue(this);
1316 ret = true;
1317 }
1318 value = val;
1319 return ret;
1320 }
1321
1322 #endregion IPhysicsParameters
1323
1324 // Invoke the detailed logger and output something if it's enabled.
1325 public void DetailLog(string msg, params Object[] args)
1326 {
1327 PhysicsLogging.Write(msg, args);
1328 }
1329 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1330 public const string DetailLogZero = "0000000000";
1331
1332 }
1333}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
new file mode 100755
index 0000000..b100273
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
@@ -0,0 +1,425 @@
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.PhysicsModules.SharedBase;
33using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.PhysicsModule.BulletS
36{
37public sealed class BSShapeCollection : IDisposable
38{
39#pragma warning disable 414
40 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
41#pragma warning restore 414
42
43 private BSScene m_physicsScene { get; set; }
44
45 private Object m_collectionActivityLock = new Object();
46
47 private bool DDetail = false;
48
49 public BSShapeCollection(BSScene physScene)
50 {
51 m_physicsScene = physScene;
52 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
53 // While detailed debugging is still active, this is better than commenting out all the
54 // DetailLog statements. When debugging slows down, this and the protected logging
55 // statements can be commented/removed.
56 DDetail = true;
57 }
58
59 public void Dispose()
60 {
61 // TODO!!!!!!!!!
62 }
63
64 // Callbacks called just before either the body or shape is destroyed.
65 // Mostly used for changing bodies out from under Linksets.
66 // Useful for other cases where parameters need saving.
67 // Passing 'null' says no callback.
68 public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape);
69
70 // Called to update/change the body and shape for an object.
71 // The object has some shape and body on it. Here we decide if that is the correct shape
72 // for the current state of the object (static/dynamic/...).
73 // If bodyCallback is not null, it is called if either the body or the shape are changed
74 // so dependencies (like constraints) can be removed before the physical object is dereferenced.
75 // Return 'true' if either the body or the shape changed.
76 // Called at taint-time.
77 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
78 {
79 m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
80
81 bool ret = false;
82
83 // This lock could probably be pushed down lower but building shouldn't take long
84 lock (m_collectionActivityLock)
85 {
86 // Do we have the correct geometry for this type of object?
87 // Updates prim.BSShape with information/pointers to shape.
88 // Returns 'true' of BSShape is changed to a new shape.
89 bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
90 // If we had to select a new shape geometry for the object,
91 // rebuild the body around it.
92 // Updates prim.BSBody with information/pointers to requested body
93 // Returns 'true' if BSBody was changed.
94 bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
95 ret = newGeom || newBody;
96 }
97 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
98 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
99
100 return ret;
101 }
102
103 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
104 {
105 return GetBodyAndShape(forceRebuild, sim, prim, null);
106 }
107
108 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
109 // before replacing it.
110 private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
111 {
112 if (prim.PhysShape.HasPhysicalShape)
113 {
114 if (shapeCallback != null)
115 shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
116 prim.PhysShape.Dereference(m_physicsScene);
117 }
118 prim.PhysShape = new BSShapeNull();
119 }
120
121 // Create the geometry information in Bullet for later use.
122 // The objects needs a hull if it's physical otherwise a mesh is enough.
123 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
124 // shared geometries will be used. If the parameters of the existing shape are the same
125 // as this request, the shape is not rebuilt.
126 // Info in prim.BSShape is updated to the new shape.
127 // Returns 'true' if the geometry was rebuilt.
128 // Called at taint-time!
129 public const int AvatarShapeCapsule = 0;
130 public const int AvatarShapeCube = 1;
131 public const int AvatarShapeOvoid = 2;
132 public const int AvatarShapeMesh = 3;
133 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
134 {
135 bool ret = false;
136 bool haveShape = false;
137 bool nativeShapePossible = true;
138 PrimitiveBaseShape pbs = prim.BaseShape;
139
140 // Kludge to create the capsule for the avatar.
141 // TDOD: Remove/redo this when BSShapeAvatar is working!!
142 BSCharacter theChar = prim as BSCharacter;
143 if (theChar != null)
144 {
145 DereferenceExistingShape(prim, shapeCallback);
146 switch (BSParam.AvatarShape)
147 {
148 case AvatarShapeCapsule:
149 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
150 BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
151 ret = true;
152 haveShape = true;
153 break;
154 case AvatarShapeCube:
155 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
156 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE);
157 ret = true;
158 haveShape = true;
159 break;
160 case AvatarShapeOvoid:
161 // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape
162 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
163 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE);
164 ret = true;
165 haveShape = true;
166 break;
167 case AvatarShapeMesh:
168 break;
169 default:
170 break;
171 }
172 }
173
174 // If the prim attributes are simple, this could be a simple Bullet native shape
175 // Native shapes work whether to object is static or physical.
176 if (!haveShape
177 && nativeShapePossible
178 && pbs != null
179 && PrimHasNoCuts(pbs)
180 && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) )
181 )
182 {
183 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
184 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
185 if (prim.PhysShape.HasPhysicalShape)
186 scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
187
188 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
189 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
190
191 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
192 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
193 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
194 {
195 haveShape = true;
196 if (forceRebuild
197 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
198 )
199 {
200 DereferenceExistingShape(prim, shapeCallback);
201 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
202 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
203 ret = true;
204 }
205 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
206 prim.LocalID, forceRebuild, ret, prim.PhysShape);
207 }
208 // If we didn't make a sphere, maybe a box will work.
209 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
210 {
211 haveShape = true;
212 if (forceRebuild
213 || prim.Scale != scaleOfExistingShape
214 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
215 )
216 {
217 DereferenceExistingShape(prim, shapeCallback);
218 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
219 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
220 ret = true;
221 }
222 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
223 prim.LocalID, forceRebuild, ret, prim.PhysShape);
224 }
225 }
226
227 // If a simple shape is not happening, create a mesh and possibly a hull.
228 if (!haveShape && pbs != null)
229 {
230 ret = CreateGeomMeshOrHull(prim, shapeCallback);
231 }
232
233 return ret;
234 }
235
236 // return 'true' if this shape description does not include any cutting or twisting.
237 public static bool PrimHasNoCuts(PrimitiveBaseShape pbs)
238 {
239 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
240 && pbs.ProfileHollow == 0
241 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
242 && pbs.PathBegin == 0 && pbs.PathEnd == 0
243 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
244 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
245 && pbs.PathShearX == 0 && pbs.PathShearY == 0;
246 }
247
248 // return 'true' if the prim's shape was changed.
249 private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
250 {
251
252 bool ret = false;
253 // Note that if it's a native shape, the check for physical/non-physical is not
254 // made. Native shapes work in either case.
255 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
256 {
257 // Use a simple, single mesh convex hull shape if the object is simple enough
258 BSShape potentialHull = null;
259
260 PrimitiveBaseShape pbs = prim.BaseShape;
261 // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists)
262 if (BSParam.ShouldUseSingleConvexHullForPrims
263 && pbs != null
264 && !pbs.SculptEntry
265 && PrimHasNoCuts(pbs)
266 )
267 {
268 potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim);
269 }
270 // Use the GImpact shape if it is a prim that has some concaveness
271 if (potentialHull == null
272 && BSParam.ShouldUseGImpactShapeForPrims
273 && pbs != null
274 && !pbs.SculptEntry
275 )
276 {
277 potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim);
278 }
279 // If not any of the simple cases, just make a hull
280 if (potentialHull == null)
281 {
282 potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
283 }
284
285 // If the current shape is not what is on the prim at the moment, time to change.
286 if (!prim.PhysShape.HasPhysicalShape
287 || potentialHull.ShapeType != prim.PhysShape.ShapeType
288 || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
289 {
290 DereferenceExistingShape(prim, shapeCallback);
291 prim.PhysShape = potentialHull;
292 ret = true;
293 }
294 else
295 {
296 // The current shape on the prim is the correct one. We don't need the potential reference.
297 potentialHull.Dereference(m_physicsScene);
298 }
299 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
300 }
301 else
302 {
303 // Non-physical objects should be just meshes.
304 BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
305 // If the current shape is not what is on the prim at the moment, time to change.
306 if (!prim.PhysShape.HasPhysicalShape
307 || potentialMesh.ShapeType != prim.PhysShape.ShapeType
308 || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
309 {
310 DereferenceExistingShape(prim, shapeCallback);
311 prim.PhysShape = potentialMesh;
312 ret = true;
313 }
314 else
315 {
316 // We don't need this reference to the mesh that is already being using.
317 potentialMesh.Dereference(m_physicsScene);
318 }
319 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
320 }
321 return ret;
322 }
323
324 // Track another user of a body.
325 // We presume the caller has allocated the body.
326 // Bodies only have one user so the body is just put into the world if not already there.
327 private void ReferenceBody(BulletBody body)
328 {
329 lock (m_collectionActivityLock)
330 {
331 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
332 if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body))
333 {
334 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body);
335 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
336 }
337 }
338 }
339
340 // Release the usage of a body.
341 // Called when releasing use of a BSBody. BSShape is handled separately.
342 // Called in taint time.
343 public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback )
344 {
345 if (!body.HasPhysicalBody)
346 return;
347
348 m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
349
350 lock (m_collectionActivityLock)
351 {
352 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
353 // If the caller needs to know the old body is going away, pass the event up.
354 if (bodyCallback != null)
355 bodyCallback(body, null);
356
357 // Removing an object not in the world is a NOOP
358 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);
359
360 // Zero any reference to the shape so it is not freed when the body is deleted.
361 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);
362
363 m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
364 }
365 }
366
367 // Create a body object in Bullet.
368 // Updates prim.BSBody with the information about the new body if one is created.
369 // Returns 'true' if an object was actually created.
370 // Called at taint-time.
371 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback)
372 {
373 bool ret = false;
374
375 // the mesh, hull or native shape must have already been created in Bullet
376 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
377
378 // If there is an existing body, verify it's of an acceptable type.
379 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
380 if (!mustRebuild)
381 {
382 CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody);
383 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
384 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
385 {
386 // If the collisionObject is not the correct type for solidness, rebuild what's there
387 mustRebuild = true;
388 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType);
389 }
390 }
391
392 if (mustRebuild || forceRebuild)
393 {
394 // Free any old body
395 DereferenceBody(prim.PhysBody, bodyCallback);
396
397 BulletBody aBody;
398 if (prim.IsSolid)
399 {
400 aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
401 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
402 }
403 else
404 {
405 aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
406 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
407 }
408
409 ReferenceBody(aBody);
410
411 prim.PhysBody = aBody;
412
413 ret = true;
414 }
415
416 return ret;
417 }
418
419 private void DetailLog(string msg, params Object[] args)
420 {
421 if (m_physicsScene.PhysicsLogging.Enabled)
422 m_physicsScene.DetailLog(msg, args);
423 }
424}
425}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs
new file mode 100755
index 0000000..086a412
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs
@@ -0,0 +1,1463 @@
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.Text;
31
32using OpenSim.Framework;
33using OpenSim.Region.PhysicsModules.SharedBase;
34using OpenSim.Region.PhysicsModules.Meshing;
35using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet;
36
37using OMV = OpenMetaverse;
38
39namespace OpenSim.Region.PhysicsModule.BulletS
40{
41// Information class that holds stats for the shape. Which values mean
42// something depends on the type of shape.
43// This information is used for debugging and stats and is not used
44// for operational things.
45public class ShapeInfoInfo
46{
47 public int Vertices { get; set; }
48 private int m_hullCount;
49 private int[] m_verticesPerHull;
50 public ShapeInfoInfo()
51 {
52 Vertices = 0;
53 m_hullCount = 0;
54 m_verticesPerHull = null;
55 }
56 public int HullCount
57 {
58 set
59 {
60 m_hullCount = value;
61 m_verticesPerHull = new int[m_hullCount];
62 Array.Clear(m_verticesPerHull, 0, m_hullCount);
63 }
64 get { return m_hullCount; }
65 }
66 public void SetVerticesPerHull(int hullNum, int vertices)
67 {
68 if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
69 {
70 m_verticesPerHull[hullNum] = vertices;
71 }
72 }
73 public int GetVerticesPerHull(int hullNum)
74 {
75 if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
76 {
77 return m_verticesPerHull[hullNum];
78 }
79 return 0;
80 }
81 public override string ToString()
82 {
83 StringBuilder buff = new StringBuilder();
84 // buff.Append("ShapeInfo=<");
85 buff.Append("<");
86 if (Vertices > 0)
87 {
88 buff.Append("verts=");
89 buff.Append(Vertices.ToString());
90 }
91
92 if (Vertices > 0 && HullCount > 0) buff.Append(",");
93
94 if (HullCount > 0)
95 {
96 buff.Append("nHulls=");
97 buff.Append(HullCount.ToString());
98 buff.Append(",");
99 buff.Append("hullVerts=");
100 for (int ii = 0; ii < HullCount; ii++)
101 {
102 if (ii != 0) buff.Append(",");
103 buff.Append(GetVerticesPerHull(ii).ToString());
104 }
105 }
106 buff.Append(">");
107 return buff.ToString();
108 }
109}
110
111public abstract class BSShape
112{
113 private static string LogHeader = "[BULLETSIM SHAPE]";
114
115 public int referenceCount { get; set; }
116 public DateTime lastReferenced { get; set; }
117 public BulletShape physShapeInfo { get; set; }
118 public ShapeInfoInfo shapeInfo { get; private set; }
119
120 public BSShape()
121 {
122 referenceCount = 1;
123 lastReferenced = DateTime.Now;
124 physShapeInfo = new BulletShape();
125 shapeInfo = new ShapeInfoInfo();
126 }
127 public BSShape(BulletShape pShape)
128 {
129 referenceCount = 1;
130 lastReferenced = DateTime.Now;
131 physShapeInfo = pShape;
132 shapeInfo = new ShapeInfoInfo();
133 }
134
135 // Get another reference to this shape.
136 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
137
138 // Called when this shape is being used again.
139 // Used internally. External callers should call instance.GetReference() to properly copy/reference
140 // the shape.
141 protected virtual void IncrementReference()
142 {
143 referenceCount++;
144 lastReferenced = DateTime.Now;
145 }
146
147 // Called when this shape is done being used.
148 protected virtual void DecrementReference()
149 {
150 referenceCount--;
151 lastReferenced = DateTime.Now;
152 }
153
154 // Release the use of a physical shape.
155 public abstract void Dereference(BSScene physicsScene);
156
157 // Return 'true' if there is an allocated physics physical shape under this class instance.
158 public virtual bool HasPhysicalShape
159 {
160 get
161 {
162 if (physShapeInfo != null)
163 return physShapeInfo.HasPhysicalShape;
164 return false;
165 }
166 }
167 public virtual BSPhysicsShapeType ShapeType
168 {
169 get
170 {
171 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
172 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
173 ret = physShapeInfo.shapeType;
174 return ret;
175 }
176 }
177
178 // Returns a string for debugging that uniquily identifies the memory used by this instance
179 public virtual string AddrString
180 {
181 get
182 {
183 if (physShapeInfo != null)
184 return physShapeInfo.AddrString;
185 return "unknown";
186 }
187 }
188
189 public override string ToString()
190 {
191 StringBuilder buff = new StringBuilder();
192 if (physShapeInfo == null)
193 {
194 buff.Append("<noPhys");
195 }
196 else
197 {
198 buff.Append("<phy=");
199 buff.Append(physShapeInfo.ToString());
200 }
201 buff.Append(",c=");
202 buff.Append(referenceCount.ToString());
203 buff.Append(">");
204 return buff.ToString();
205 }
206
207 #region Common shape routines
208 // Create a hash of all the shape parameters to be used as a key for this particular shape.
209 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
210 {
211 // level of detail based on size and type of the object
212 float lod = BSParam.MeshLOD;
213 if (pbs.SculptEntry)
214 lod = BSParam.SculptLOD;
215
216 // Mega prims usually get more detail because one can interact with shape approximations at this size.
217 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
218 if (maxAxis > BSParam.MeshMegaPrimThreshold)
219 lod = BSParam.MeshMegaPrimLOD;
220
221 retLod = lod;
222 return pbs.GetMeshKey(size, lod);
223 }
224
225 // The creation of a mesh or hull can fail if an underlying asset is not available.
226 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
227 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
228 // The first case causes the asset to be fetched. The second case requires
229 // us to not loop forever.
230 // Called after creating a physical mesh or hull. If the physical shape was created,
231 // just return.
232 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
233 {
234 // If the shape was successfully created, nothing more to do
235 if (newShape.HasPhysicalShape)
236 return newShape;
237
238 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
239 // fetched but we end up here again, the meshing of the asset must have failed.
240 // Prevent trying to keep fetching the mesh by declaring failure.
241 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
242 {
243 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
244 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}",
245 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
246 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}",
247 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
248 }
249 else
250 {
251 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
252 if (prim.BaseShape.SculptEntry
253 && !prim.AssetFailed()
254 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
255 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
256 )
257 {
258 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
259 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
260 // Multiple requestors will know we're waiting for this asset
261 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
262
263 BSPhysObject xprim = prim;
264 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
265 if (assetProvider != null)
266 {
267 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
268 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
269 {
270 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
271 bool assetFound = false;
272 string mismatchIDs = String.Empty; // DEBUG DEBUG
273 if (asset != null && yprim.BaseShape.SculptEntry)
274 {
275 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
276 {
277 yprim.BaseShape.SculptData = asset.Data;
278 // This will cause the prim to see that the filler shape is not the right
279 // one and try again to build the object.
280 // No race condition with the normal shape setting since the rebuild is at taint time.
281 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
282 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
283 assetFound = true;
284 }
285 else
286 {
287 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
288 }
289 }
290 if (!assetFound)
291 {
292 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
293 }
294 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
295 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
296 });
297 }
298 else
299 {
300 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
301 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
302 LogHeader, physicsScene.PhysicsSceneName);
303 }
304 }
305 else
306 {
307 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
308 {
309 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}",
310 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
311 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}",
312 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
313 }
314 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing)
315 {
316 physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}",
317 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
318 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}",
319 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
320 }
321 }
322 }
323
324 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
325 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
326 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
327
328 return fillShape.physShapeInfo;
329 }
330
331 public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim)
332 {
333 StringBuilder buff = new StringBuilder(prim.PhysObjectName);
334 buff.Append("/pos=");
335 buff.Append(prim.RawPosition.ToString());
336 if (pScene != null)
337 {
338 buff.Append("/rgn=");
339 buff.Append(pScene.PhysicsSceneName);
340 }
341 return buff.ToString();
342 }
343
344 #endregion // Common shape routines
345}
346
347// ============================================================================================================
348public class BSShapeNull : BSShape
349{
350 public BSShapeNull() : base()
351 {
352 }
353 public static BSShape GetReference() { return new BSShapeNull(); }
354 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
355 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
356}
357
358// ============================================================================================================
359// BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere.
360// They are odd in that they don't allocate meshes but are computated/procedural.
361// This means allocation and freeing is different than meshes.
362public class BSShapeNative : BSShape
363{
364 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
365 public BSShapeNative(BulletShape pShape) : base(pShape)
366 {
367 }
368
369 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
370 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
371 {
372 // Native shapes are not shared and are always built anew.
373 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
374 }
375
376 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
377 {
378 // Native shapes are not shared so we return a new shape.
379 BSShape ret = null;
380 lock (physShapeInfo)
381 {
382 ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
383 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
384 }
385 return ret;
386 }
387
388 // Make this reference to the physical shape go away since native shapes are not shared.
389 public override void Dereference(BSScene physicsScene)
390 {
391 // Native shapes are not tracked and are released immediately
392 lock (physShapeInfo)
393 {
394 if (physShapeInfo.HasPhysicalShape)
395 {
396 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
397 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
398 }
399 physShapeInfo.Clear();
400 // Garbage collection will free up this instance.
401 }
402 }
403
404 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
405 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
406 {
407 BulletShape newShape;
408
409 ShapeData nativeShapeData = new ShapeData();
410 nativeShapeData.Type = shapeType;
411 nativeShapeData.ID = prim.LocalID;
412 nativeShapeData.Scale = prim.Scale;
413 nativeShapeData.Size = prim.Scale;
414 nativeShapeData.MeshKey = (ulong)shapeKey;
415 nativeShapeData.HullKey = (ulong)shapeKey;
416
417 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
418 {
419 newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
420 physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
421 }
422 else
423 {
424 newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
425 }
426 if (!newShape.HasPhysicalShape)
427 {
428 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
429 LogHeader, prim.LocalID, shapeType);
430 }
431 newShape.shapeType = shapeType;
432 newShape.isNativeShape = true;
433 newShape.shapeKey = (UInt64)shapeKey;
434 return newShape;
435 }
436
437}
438
439// ============================================================================================================
440// BSShapeMesh is a simple mesh.
441public class BSShapeMesh : BSShape
442{
443 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
444 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
445
446 public BSShapeMesh(BulletShape pShape) : base(pShape)
447 {
448 }
449 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
450 {
451 float lod;
452 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
453
454 BSShapeMesh retMesh = null;
455 lock (Meshes)
456 {
457 if (Meshes.TryGetValue(newMeshKey, out retMesh))
458 {
459 // The mesh has already been created. Return a new reference to same.
460 retMesh.IncrementReference();
461 }
462 else
463 {
464 retMesh = new BSShapeMesh(new BulletShape());
465 // An instance of this mesh has not been created. Build and remember same.
466 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
467
468 // Check to see if mesh was created (might require an asset).
469 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
470 if (!newShape.isNativeShape || prim.AssetFailed() )
471 {
472 // If a mesh was what was created, remember the built shape for later sharing.
473 // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
474 Meshes.Add(newMeshKey, retMesh);
475 }
476
477 retMesh.physShapeInfo = newShape;
478 }
479 }
480 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
481 return retMesh;
482 }
483 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
484 {
485 BSShape ret = null;
486 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
487 // and we must create a copy of the native shape since they are never shared.
488 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
489 {
490 // TODO: decide when the native shapes should be freed. Check in Dereference?
491 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
492 }
493 else
494 {
495 // Another reference to this shape is just counted.
496 IncrementReference();
497 ret = this;
498 }
499 return ret;
500 }
501 public override void Dereference(BSScene physicsScene)
502 {
503 lock (Meshes)
504 {
505 this.DecrementReference();
506 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
507 // TODO: schedule aging and destruction of unused meshes.
508 }
509 }
510 // Loop through all the known meshes and return the description based on the physical address.
511 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
512 {
513 bool ret = false;
514 BSShapeMesh foundDesc = null;
515 lock (Meshes)
516 {
517 foreach (BSShapeMesh sm in Meshes.Values)
518 {
519 if (sm.physShapeInfo.ReferenceSame(pShape))
520 {
521 foundDesc = sm;
522 ret = true;
523 break;
524 }
525
526 }
527 }
528 outMesh = foundDesc;
529 return ret;
530 }
531
532 public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
533 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
534 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
535 {
536 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
537 (w, iC, i, vC, v) =>
538 {
539 shapeInfo.Vertices = vC;
540 return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v);
541 });
542 }
543
544 // Code that uses the mesher to create the index/vertices info for a trimesh shape.
545 // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
546 // The actual build call is passed so this logic can be used by several of the shapes that use a
547 // simple mesh as their base shape.
548 public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
549 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
550 {
551 BulletShape newShape = new BulletShape();
552
553 IMesh meshData = null;
554 lock (physicsScene.mesher)
555 {
556 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
557 false, // say it is not physical so a bounding box is not built
558 false // do not cache the mesh and do not use previously built versions
559 );
560 }
561
562 if (meshData != null)
563 {
564 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
565 {
566 // Release the fetched asset data once it has been used.
567 pbs.SculptData = new byte[0];
568 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
569 }
570
571 int[] indices = meshData.getIndexListAsInt();
572 int realIndicesIndex = indices.Length;
573 float[] verticesAsFloats = meshData.getVertexListAsFloat();
574
575 if (BSParam.ShouldRemoveZeroWidthTriangles)
576 {
577 // Remove degenerate triangles. These are triangles with two of the vertices
578 // are the same. This is complicated by the problem that vertices are not
579 // made unique in sculpties so we have to compare the values in the vertex.
580 realIndicesIndex = 0;
581 for (int tri = 0; tri < indices.Length; tri += 3)
582 {
583 // Compute displacements into vertex array for each vertex of the triangle
584 int v1 = indices[tri + 0] * 3;
585 int v2 = indices[tri + 1] * 3;
586 int v3 = indices[tri + 2] * 3;
587 // Check to see if any two of the vertices are the same
588 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
589 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
590 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
591 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
592 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
593 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
594 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
595 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
596 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
597 )
598 {
599 // None of the vertices of the triangles are the same. This is a good triangle;
600 indices[realIndicesIndex + 0] = indices[tri + 0];
601 indices[realIndicesIndex + 1] = indices[tri + 1];
602 indices[realIndicesIndex + 2] = indices[tri + 2];
603 realIndicesIndex += 3;
604 }
605 }
606 }
607 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
608 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
609
610 if (realIndicesIndex != 0)
611 {
612 newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
613 }
614 else
615 {
616 // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
617 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
618 physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) );
619 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
620 }
621 }
622 newShape.shapeKey = newMeshKey;
623
624 return newShape;
625 }
626}
627
628// ============================================================================================================
629// BSShapeHull is a physical shape representation htat is made up of many convex hulls.
630// The convex hulls are either supplied with the asset or are approximated by one of the
631// convex hull creation routines (in OpenSim or in Bullet).
632public class BSShapeHull : BSShape
633{
634#pragma warning disable 414
635 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
636#pragma warning restore 414
637
638 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
639
640
641 public BSShapeHull(BulletShape pShape) : base(pShape)
642 {
643 }
644 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
645 {
646 float lod;
647 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
648
649 BSShapeHull retHull = null;
650 lock (Hulls)
651 {
652 if (Hulls.TryGetValue(newHullKey, out retHull))
653 {
654 // The mesh has already been created. Return a new reference to same.
655 retHull.IncrementReference();
656 }
657 else
658 {
659 retHull = new BSShapeHull(new BulletShape());
660 // An instance of this mesh has not been created. Build and remember same.
661 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
662
663 // Check to see if hull was created (might require an asset).
664 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
665 if (!newShape.isNativeShape || prim.AssetFailed())
666 {
667 // If a mesh was what was created, remember the built shape for later sharing.
668 Hulls.Add(newHullKey, retHull);
669 }
670 retHull.physShapeInfo = newShape;
671 }
672 }
673 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
674 return retHull;
675 }
676 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
677 {
678 BSShape ret = null;
679 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
680 // and we must create a copy of the native shape since they are never shared.
681 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
682 {
683 // TODO: decide when the native shapes should be freed. Check in Dereference?
684 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
685 }
686 else
687 {
688 // Another reference to this shape is just counted.
689 IncrementReference();
690 ret = this;
691 }
692 return ret;
693 }
694 public override void Dereference(BSScene physicsScene)
695 {
696 lock (Hulls)
697 {
698 this.DecrementReference();
699 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
700 // TODO: schedule aging and destruction of unused meshes.
701 }
702 }
703
704 List<ConvexResult> m_hulls;
705 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
706 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
707 {
708 BulletShape newShape = new BulletShape();
709
710 IMesh meshData = null;
711 List<List<OMV.Vector3>> allHulls = null;
712 lock (physicsScene.mesher)
713 {
714 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
715 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
716
717 // If we should use the asset's hull info, fetch it out of the locked mesher
718 if (meshData != null && BSParam.ShouldUseAssetHulls)
719 {
720 Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
721 if (realMesher != null)
722 {
723 allHulls = realMesher.GetConvexHulls(size);
724 }
725 if (allHulls == null)
726 {
727 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
728 }
729 }
730 }
731
732 // If there is hull data in the mesh asset, build the hull from that
733 if (allHulls != null && BSParam.ShouldUseAssetHulls)
734 {
735 int hullCount = allHulls.Count;
736 shapeInfo.HullCount = hullCount;
737 int totalVertices = 1; // include one for the count of the hulls
738 // Using the structure described for HACD hulls, create the memory sturcture
739 // to pass the hull data to the creater.
740 foreach (List<OMV.Vector3> hullVerts in allHulls)
741 {
742 totalVertices += 4; // add four for the vertex count and centroid
743 totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
744 }
745 float[] convHulls = new float[totalVertices];
746
747 convHulls[0] = (float)hullCount;
748 int jj = 1;
749 int hullIndex = 0;
750 foreach (List<OMV.Vector3> hullVerts in allHulls)
751 {
752 convHulls[jj + 0] = hullVerts.Count;
753 convHulls[jj + 1] = 0f; // centroid x,y,z
754 convHulls[jj + 2] = 0f;
755 convHulls[jj + 3] = 0f;
756 jj += 4;
757 foreach (OMV.Vector3 oneVert in hullVerts)
758 {
759 convHulls[jj + 0] = oneVert.X;
760 convHulls[jj + 1] = oneVert.Y;
761 convHulls[jj + 2] = oneVert.Z;
762 jj += 3;
763 }
764 shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count);
765 hullIndex++;
766 }
767
768 // create the hull data structure in Bullet
769 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
770
771 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
772 prim.LocalID, hullCount, totalVertices, newShape);
773 }
774
775 // If no hull specified in the asset and we should use Bullet's HACD approximation...
776 if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
777 {
778 // Build the hull shape from an existing mesh shape.
779 // The mesh should have already been created in Bullet.
780 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
781 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
782
783 if (meshShape.physShapeInfo.HasPhysicalShape)
784 {
785 HACDParams parms = new HACDParams();
786 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
787 parms.minClusters = BSParam.BHullMinClusters;
788 parms.compacityWeight = BSParam.BHullCompacityWeight;
789 parms.volumeWeight = BSParam.BHullVolumeWeight;
790 parms.concavity = BSParam.BHullConcavity;
791 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
792 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
793 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
794 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
795 parms.whichHACD = 0; // Use the HACD routine that comes with Bullet
796
797 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
798 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
799 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
800
801 // Now done with the mesh shape.
802 shapeInfo.HullCount = 1;
803 BSShapeMesh maybeMesh = meshShape as BSShapeMesh;
804 if (maybeMesh != null)
805 shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices);
806 meshShape.Dereference(physicsScene);
807 }
808 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
809 }
810
811 // If no other hull specifications, use our HACD hull approximation.
812 if (!newShape.HasPhysicalShape && meshData != null)
813 {
814 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
815 {
816 // Release the fetched asset data once it has been used.
817 pbs.SculptData = new byte[0];
818 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
819 }
820
821 int[] indices = meshData.getIndexListAsInt();
822 List<OMV.Vector3> vertices = meshData.getVertexList();
823
824 //format conversion from IMesh format to DecompDesc format
825 List<int> convIndices = new List<int>();
826 List<float3> convVertices = new List<float3>();
827 for (int ii = 0; ii < indices.GetLength(0); ii++)
828 {
829 convIndices.Add(indices[ii]);
830 }
831 foreach (OMV.Vector3 vv in vertices)
832 {
833 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
834 }
835
836 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
837 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
838 {
839 // Simple primitive shapes we know are convex so they are better implemented with
840 // fewer hulls.
841 // Check for simple shape (prim without cuts) and reduce split parameter if so.
842 if (BSShapeCollection.PrimHasNoCuts(pbs))
843 {
844 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
845 }
846 }
847
848 // setup and do convex hull conversion
849 m_hulls = new List<ConvexResult>();
850 DecompDesc dcomp = new DecompDesc();
851 dcomp.mIndices = convIndices;
852 dcomp.mVertices = convVertices;
853 dcomp.mDepth = maxDepthSplit;
854 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
855 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
856 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
857 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
858 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
859 // create the hull into the _hulls variable
860 convexBuilder.process(dcomp);
861
862 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
863 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
864
865 // Convert the vertices and indices for passing to unmanaged.
866 // The hull information is passed as a large floating point array.
867 // The format is:
868 // convHulls[0] = number of hulls
869 // convHulls[1] = number of vertices in first hull
870 // convHulls[2] = hull centroid X coordinate
871 // convHulls[3] = hull centroid Y coordinate
872 // convHulls[4] = hull centroid Z coordinate
873 // convHulls[5] = first hull vertex X
874 // convHulls[6] = first hull vertex Y
875 // convHulls[7] = first hull vertex Z
876 // convHulls[8] = second hull vertex X
877 // ...
878 // convHulls[n] = number of vertices in second hull
879 // convHulls[n+1] = second hull centroid X coordinate
880 // ...
881 //
882 // TODO: is is very inefficient. Someday change the convex hull generator to return
883 // data structures that do not need to be converted in order to pass to Bullet.
884 // And maybe put the values directly into pinned memory rather than marshaling.
885 int hullCount = m_hulls.Count;
886 int totalVertices = 1; // include one for the count of the hulls
887 foreach (ConvexResult cr in m_hulls)
888 {
889 totalVertices += 4; // add four for the vertex count and centroid
890 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
891 }
892 float[] convHulls = new float[totalVertices];
893
894 convHulls[0] = (float)hullCount;
895 int jj = 1;
896 foreach (ConvexResult cr in m_hulls)
897 {
898 // copy vertices for index access
899 float3[] verts = new float3[cr.HullVertices.Count];
900 int kk = 0;
901 foreach (float3 ff in cr.HullVertices)
902 {
903 verts[kk++] = ff;
904 }
905
906 // add to the array one hull's worth of data
907 convHulls[jj++] = cr.HullIndices.Count;
908 convHulls[jj++] = 0f; // centroid x,y,z
909 convHulls[jj++] = 0f;
910 convHulls[jj++] = 0f;
911 foreach (int ind in cr.HullIndices)
912 {
913 convHulls[jj++] = verts[ind].x;
914 convHulls[jj++] = verts[ind].y;
915 convHulls[jj++] = verts[ind].z;
916 }
917 }
918 // create the hull data structure in Bullet
919 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
920 }
921 newShape.shapeKey = newHullKey;
922 return newShape;
923 }
924 // Callback from convex hull creater with a newly created hull.
925 // Just add it to our collection of hulls for this shape.
926 private void HullReturn(ConvexResult result)
927 {
928 m_hulls.Add(result);
929 return;
930 }
931 // Loop through all the known hulls and return the description based on the physical address.
932 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
933 {
934 bool ret = false;
935 BSShapeHull foundDesc = null;
936 lock (Hulls)
937 {
938 foreach (BSShapeHull sh in Hulls.Values)
939 {
940 if (sh.physShapeInfo.ReferenceSame(pShape))
941 {
942 foundDesc = sh;
943 ret = true;
944 break;
945 }
946
947 }
948 }
949 outHull = foundDesc;
950 return ret;
951 }
952}
953
954// ============================================================================================================
955// BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate
956// meshes. Used by BulletSim for complex shapes like linksets.
957public class BSShapeCompound : BSShape
958{
959 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
960 public static Dictionary<string, BSShapeCompound> CompoundShapes = new Dictionary<string, BSShapeCompound>();
961
962 public BSShapeCompound(BulletShape pShape) : base(pShape)
963 {
964 }
965 public static BSShape GetReference(BSScene physicsScene)
966 {
967 // Base compound shapes are not shared so this returns a raw shape.
968 // A built compound shape can be reused in linksets.
969 BSShapeCompound ret = new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
970 CompoundShapes.Add(ret.AddrString, ret);
971 return ret;
972 }
973 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
974 {
975 // Calling this reference means we want another handle to an existing compound shape
976 // (usually linksets) so return this copy.
977 IncrementReference();
978 return this;
979 }
980 // Dereferencing a compound shape releases the hold on all the child shapes.
981 public override void Dereference(BSScene physicsScene)
982 {
983 lock (physShapeInfo)
984 {
985 this.DecrementReference();
986 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
987 if (referenceCount <= 0)
988 {
989 if (!physicsScene.PE.IsCompound(physShapeInfo))
990 {
991 // Failed the sanity check!!
992 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
993 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
994 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
995 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
996 return;
997 }
998
999 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
1000 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
1001 BSScene.DetailLogZero, physShapeInfo, numChildren);
1002
1003 // Loop through all the children dereferencing each.
1004 for (int ii = numChildren - 1; ii >= 0; ii--)
1005 {
1006 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
1007 DereferenceAnonCollisionShape(physicsScene, childShape);
1008 }
1009
1010 lock (CompoundShapes)
1011 CompoundShapes.Remove(physShapeInfo.AddrString);
1012 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
1013 }
1014 }
1015 }
1016 public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound)
1017 {
1018 lock (CompoundShapes)
1019 {
1020 string addr = pShape.AddrString;
1021 return CompoundShapes.TryGetValue(addr, out outCompound);
1022 }
1023 }
1024 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
1025 {
1026 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
1027 return cShape;
1028 }
1029 // Sometimes we have a pointer to a collision shape but don't know what type it is.
1030 // Figure out type and call the correct dereference routine.
1031 // Called at taint-time.
1032 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
1033 {
1034 // TODO: figure a better way to go through all the shape types and find a possible instance.
1035 physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}",
1036 BSScene.DetailLogZero, pShape);
1037 BSShapeMesh meshDesc;
1038 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
1039 {
1040 meshDesc.Dereference(physicsScene);
1041 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape);
1042 }
1043 else
1044 {
1045 BSShapeHull hullDesc;
1046 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
1047 {
1048 hullDesc.Dereference(physicsScene);
1049 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape);
1050 }
1051 else
1052 {
1053 BSShapeConvexHull chullDesc;
1054 if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc))
1055 {
1056 chullDesc.Dereference(physicsScene);
1057 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape);
1058 }
1059 else
1060 {
1061 BSShapeGImpact gImpactDesc;
1062 if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
1063 {
1064 gImpactDesc.Dereference(physicsScene);
1065 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape);
1066 }
1067 else
1068 {
1069 // Didn't find it in the lists of specific types. It could be compound.
1070 BSShapeCompound compoundDesc;
1071 if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc))
1072 {
1073 compoundDesc.Dereference(physicsScene);
1074 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape);
1075 }
1076 else
1077 {
1078 // If none of the above, maybe it is a simple native shape.
1079 if (physicsScene.PE.IsNativeShape(pShape))
1080 {
1081 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape);
1082 BSShapeNative nativeShape = new BSShapeNative(pShape);
1083 nativeShape.Dereference(physicsScene);
1084 }
1085 else
1086 {
1087 physicsScene.Logger.WarnFormat("{0} DereferenceAnonCollisionShape. Did not find shape. {1}",
1088 LogHeader, pShape);
1089 }
1090 }
1091 }
1092 }
1093 }
1094 }
1095 }
1096}
1097
1098// ============================================================================================================
1099// BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex
1100// hull shapes. This is used for simple prims that are convex and thus can be made into a simple
1101// collision shape (a single hull). More complex physical shapes will be BSShapeHull's.
1102public class BSShapeConvexHull : BSShape
1103{
1104#pragma warning disable 414
1105 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
1106#pragma warning restore 414
1107
1108 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
1109
1110 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
1111 {
1112 }
1113 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1114 {
1115 float lod;
1116 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1117
1118 physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}",
1119 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1120
1121 BSShapeConvexHull retConvexHull = null;
1122 lock (ConvexHulls)
1123 {
1124 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
1125 {
1126 // The mesh has already been created. Return a new reference to same.
1127 retConvexHull.IncrementReference();
1128 }
1129 else
1130 {
1131 retConvexHull = new BSShapeConvexHull(new BulletShape());
1132 BulletShape convexShape = null;
1133
1134 // Get a handle to a mesh to build the hull from
1135 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
1136 if (baseMesh.physShapeInfo.isNativeShape)
1137 {
1138 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
1139 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
1140 // get back to this code with a buildable mesh.
1141 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
1142 convexShape = baseMesh.physShapeInfo;
1143 }
1144 else
1145 {
1146 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
1147 convexShape.shapeKey = newMeshKey;
1148 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
1149 physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}",
1150 BSScene.DetailLogZero, convexShape);
1151 }
1152
1153 // Done with the base mesh
1154 baseMesh.Dereference(physicsScene);
1155
1156 retConvexHull.physShapeInfo = convexShape;
1157 }
1158 }
1159 return retConvexHull;
1160 }
1161 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
1162 {
1163 // Calling this reference means we want another handle to an existing shape
1164 // (usually linksets) so return this copy.
1165 IncrementReference();
1166 return this;
1167 }
1168 // Dereferencing a compound shape releases the hold on all the child shapes.
1169 public override void Dereference(BSScene physicsScene)
1170 {
1171 lock (ConvexHulls)
1172 {
1173 this.DecrementReference();
1174 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
1175 // TODO: schedule aging and destruction of unused meshes.
1176 }
1177 }
1178 // Loop through all the known hulls and return the description based on the physical address.
1179 public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
1180 {
1181 bool ret = false;
1182 BSShapeConvexHull foundDesc = null;
1183 lock (ConvexHulls)
1184 {
1185 foreach (BSShapeConvexHull sh in ConvexHulls.Values)
1186 {
1187 if (sh.physShapeInfo.ReferenceSame(pShape))
1188 {
1189 foundDesc = sh;
1190 ret = true;
1191 break;
1192 }
1193
1194 }
1195 }
1196 outHull = foundDesc;
1197 return ret;
1198 }
1199}
1200// ============================================================================================================
1201// BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that
1202// can handle concave as well as convex shapes. Much slower computationally but creates smoother
1203// shapes than multiple convex hull approximations.
1204public class BSShapeGImpact : BSShape
1205{
1206#pragma warning disable 414
1207 private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]";
1208#pragma warning restore 414
1209
1210 public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>();
1211
1212 public BSShapeGImpact(BulletShape pShape) : base(pShape)
1213 {
1214 }
1215 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1216 {
1217 float lod;
1218 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1219
1220 physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}",
1221 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1222
1223 BSShapeGImpact retGImpact = null;
1224 lock (GImpacts)
1225 {
1226 if (GImpacts.TryGetValue(newMeshKey, out retGImpact))
1227 {
1228 // The mesh has already been created. Return a new reference to same.
1229 retGImpact.IncrementReference();
1230 }
1231 else
1232 {
1233 retGImpact = new BSShapeGImpact(new BulletShape());
1234 BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
1235
1236 // Check to see if mesh was created (might require an asset).
1237 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
1238 newShape.shapeKey = newMeshKey;
1239 if (!newShape.isNativeShape || prim.AssetFailed())
1240 {
1241 // If a mesh was what was created, remember the built shape for later sharing.
1242 // Also note that if meshing failed we put it in the mesh list as there is nothing
1243 // else to do about the mesh.
1244 GImpacts.Add(newMeshKey, retGImpact);
1245 }
1246
1247 retGImpact.physShapeInfo = newShape;
1248 }
1249 }
1250 return retGImpact;
1251 }
1252
1253 private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
1254 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
1255 {
1256 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
1257 (w, iC, i, vC, v) =>
1258 {
1259 shapeInfo.Vertices = vC;
1260 return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v);
1261 });
1262 }
1263
1264 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1265 {
1266 BSShape ret = null;
1267 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
1268 // and we must create a copy of the native shape since they are never shared.
1269 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
1270 {
1271 // TODO: decide when the native shapes should be freed. Check in Dereference?
1272 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
1273 }
1274 else
1275 {
1276 // Another reference to this shape is just counted.
1277 IncrementReference();
1278 ret = this;
1279 }
1280 return ret;
1281 }
1282 // Dereferencing a compound shape releases the hold on all the child shapes.
1283 public override void Dereference(BSScene physicsScene)
1284 {
1285 lock (GImpacts)
1286 {
1287 this.DecrementReference();
1288 physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this);
1289 // TODO: schedule aging and destruction of unused meshes.
1290 }
1291 }
1292 // Loop through all the known hulls and return the description based on the physical address.
1293 public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
1294 {
1295 bool ret = false;
1296 BSShapeGImpact foundDesc = null;
1297 lock (GImpacts)
1298 {
1299 foreach (BSShapeGImpact sh in GImpacts.Values)
1300 {
1301 if (sh.physShapeInfo.ReferenceSame(pShape))
1302 {
1303 foundDesc = sh;
1304 ret = true;
1305 break;
1306 }
1307
1308 }
1309 }
1310 outHull = foundDesc;
1311 return ret;
1312 }
1313}
1314
1315// ============================================================================================================
1316// BSShapeAvatar is a specialized mesh shape for avatars.
1317public class BSShapeAvatar : BSShape
1318{
1319#pragma warning disable 414
1320 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
1321#pragma warning restore 414
1322
1323 public BSShapeAvatar()
1324 : base()
1325 {
1326 }
1327 public static BSShape GetReference(BSPhysObject prim)
1328 {
1329 return new BSShapeNull();
1330 }
1331 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1332 {
1333 return new BSShapeNull();
1334 }
1335 public override void Dereference(BSScene physicsScene) { }
1336
1337 // From the front:
1338 // A---A
1339 // / \
1340 // B-------B
1341 // / \ +Z
1342 // C-----------C |
1343 // \ / -Y --+-- +Y
1344 // \ / |
1345 // \ / -Z
1346 // D-----D
1347 // \ /
1348 // E-E
1349
1350 // From the top A and E are just lines.
1351 // B, C and D are hexagons:
1352 //
1353 // C1--C2 +X
1354 // / \ |
1355 // C0 C3 -Y --+-- +Y
1356 // \ / |
1357 // C5--C4 -X
1358
1359 // Zero goes directly through the middle so the offsets are from that middle axis
1360 // and up and down from a middle horizon (A and E are the same distance from the zero).
1361 // The height, width and depth is one. All scaling is done by the simulator.
1362
1363 // Z component -- how far the level is from the middle zero
1364 private const float Aup = 0.5f;
1365 private const float Bup = 0.4f;
1366 private const float Cup = 0.3f;
1367 private const float Dup = -0.4f;
1368 private const float Eup = -0.5f;
1369
1370 // Y component -- distance from center to x0 and x3
1371 private const float Awid = 0.25f;
1372 private const float Bwid = 0.3f;
1373 private const float Cwid = 0.5f;
1374 private const float Dwid = 0.3f;
1375 private const float Ewid = 0.2f;
1376
1377 // Y component -- distance from center to x1, x2, x4 and x5
1378 private const float Afwid = 0.0f;
1379 private const float Bfwid = 0.2f;
1380 private const float Cfwid = 0.4f;
1381 private const float Dfwid = 0.2f;
1382 private const float Efwid = 0.0f;
1383
1384 // X component -- distance from zero to the front or back of a level
1385 private const float Adep = 0f;
1386 private const float Bdep = 0.3f;
1387 private const float Cdep = 0.5f;
1388 private const float Ddep = 0.2f;
1389 private const float Edep = 0f;
1390
1391 private OMV.Vector3[] avatarVertices = {
1392 new OMV.Vector3( 0.0f, -Awid, Aup), // A0
1393 new OMV.Vector3( 0.0f, +Awid, Aup), // A3
1394
1395 new OMV.Vector3( 0.0f, -Bwid, Bup), // B0
1396 new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1
1397 new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2
1398 new OMV.Vector3( 0.0f, +Bwid, Bup), // B3
1399 new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4
1400 new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5
1401
1402 new OMV.Vector3( 0.0f, -Cwid, Cup), // C0
1403 new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1
1404 new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2
1405 new OMV.Vector3( 0.0f, +Cwid, Cup), // C3
1406 new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4
1407 new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5
1408
1409 new OMV.Vector3( 0.0f, -Dwid, Dup), // D0
1410 new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1
1411 new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2
1412 new OMV.Vector3( 0.0f, +Dwid, Dup), // D3
1413 new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4
1414 new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5
1415
1416 new OMV.Vector3( 0.0f, -Ewid, Eup), // E0
1417 new OMV.Vector3( 0.0f, +Ewid, Eup), // E3
1418 };
1419
1420 // Offsets of the vertices in the vertices array
1421 private enum Ind : int
1422 {
1423 A0, A3,
1424 B0, B1, B2, B3, B4, B5,
1425 C0, C1, C2, C3, C4, C5,
1426 D0, D1, D2, D3, D4, D5,
1427 E0, E3
1428 }
1429
1430 // Comments specify trianges and quads in clockwise direction
1431 private Ind[] avatarIndices = {
1432 Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1
1433 Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3
1434 Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3
1435 Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4
1436 Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0
1437 Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0
1438
1439 Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1
1440 Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2
1441 Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3
1442 Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4
1443 Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5
1444 Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0
1445
1446 Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1
1447 Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2
1448 Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3
1449 Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4
1450 Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5
1451 Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0
1452
1453 Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1
1454 Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3
1455 Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3
1456 Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4
1457 Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0
1458 Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0
1459
1460 };
1461
1462}
1463}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
new file mode 100755
index 0000000..42fc11b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
@@ -0,0 +1,169 @@
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.PhysicsModules.SharedBase;
34
35using Nini.Config;
36using log4net;
37
38using OpenMetaverse;
39
40namespace OpenSim.Region.PhysicsModule.BulletS
41{
42public sealed class BSTerrainHeightmap : BSTerrainPhys
43{
44 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
45
46 BulletHMapInfo m_mapInfo = null;
47
48 // Constructor to build a default, flat heightmap terrain.
49 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
50 : base(physicsScene, regionBase, id)
51 {
52 Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
53 Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
54 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
55 float[] initialMap = new float[totalHeights];
56 for (int ii = 0; ii < totalHeights; ii++)
57 {
58 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
59 }
60 m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y);
61 m_mapInfo.minCoords = minTerrainCoords;
62 m_mapInfo.maxCoords = maxTerrainCoords;
63 m_mapInfo.terrainRegionBase = TerrainBase;
64 // Don't have to free any previous since we just got here.
65 BuildHeightmapTerrain();
66 }
67
68 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
69 // are the high and low points of the heightmap).
70 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
71 Vector3 minCoords, Vector3 maxCoords)
72 : base(physicsScene, regionBase, id)
73 {
74 m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y);
75 m_mapInfo.minCoords = minCoords;
76 m_mapInfo.maxCoords = maxCoords;
77 m_mapInfo.minZ = minCoords.Z;
78 m_mapInfo.maxZ = maxCoords.Z;
79 m_mapInfo.terrainRegionBase = TerrainBase;
80
81 // Don't have to free any previous since we just got here.
82 BuildHeightmapTerrain();
83 }
84
85 public override void Dispose()
86 {
87 ReleaseHeightMapTerrain();
88 }
89
90 // Using the information in m_mapInfo, create the physical representation of the heightmap.
91 private void BuildHeightmapTerrain()
92 {
93 // Create the terrain shape from the mapInfo
94 m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
95 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
96 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
97
98
99 // The terrain object initial position is at the center of the object
100 Vector3 centerPos;
101 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
102 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
103 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
104
105 m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
106 m_mapInfo.ID, centerPos, Quaternion.Identity);
107
108 // Set current terrain attributes
109 m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
110 m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
111 m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
112 m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
113
114 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
115
116 // Return the new terrain to the world of physical objects
117 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody);
118
119 // redo its bounding box now that it is in the world
120 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody);
121
122 // Make it so the terrain will not move or be considered for movement.
123 m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
124
125 return;
126 }
127
128 // If there is information in m_mapInfo pointing to physical structures, release same.
129 private void ReleaseHeightMapTerrain()
130 {
131 if (m_mapInfo != null)
132 {
133 if (m_mapInfo.terrainBody.HasPhysicalBody)
134 {
135 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody);
136 // Frees both the body and the shape.
137 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody);
138 }
139 }
140 m_mapInfo = null;
141 }
142
143 // The passed position is relative to the base of the region.
144 public override float GetTerrainHeightAtXYZ(Vector3 pos)
145 {
146 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
147
148 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
149 try
150 {
151 ret = m_mapInfo.heightMap[mapIndex];
152 }
153 catch
154 {
155 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
156 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
157 LogHeader, m_mapInfo.terrainRegionBase, pos);
158 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
159 }
160 return ret;
161 }
162
163 // The passed position is relative to the base of the region.
164 public override float GetWaterLevelAtXYZ(Vector3 pos)
165 {
166 return m_physicsScene.SimpleWaterLevel;
167 }
168}
169}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
new file mode 100755
index 0000000..d11baa6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
@@ -0,0 +1,584 @@
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.PhysicsModules.SharedBase;
34
35using Nini.Config;
36using log4net;
37
38using OpenMetaverse;
39
40namespace OpenSim.Region.PhysicsModule.BulletS
41{
42
43// The physical implementation of the terrain is wrapped in this class.
44public abstract class BSTerrainPhys : IDisposable
45{
46 public enum TerrainImplementation
47 {
48 Heightmap = 0,
49 Mesh = 1
50 }
51
52 protected BSScene m_physicsScene { get; private set; }
53 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
54 public Vector3 TerrainBase { get; private set; }
55 public uint ID { get; private set; }
56
57 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
58 {
59 m_physicsScene = physicsScene;
60 TerrainBase = regionBase;
61 ID = id;
62 }
63 public abstract void Dispose();
64 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
65 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
66}
67
68// ==========================================================================================
69public sealed class BSTerrainManager : IDisposable
70{
71 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
72
73 // These height values are fractional so the odd values will be
74 // noticable when debugging.
75 public const float HEIGHT_INITIALIZATION = 24.987f;
76 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
77 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
78 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
79
80 // If the min and max height are equal, we reduce the min by this
81 // amount to make sure that a bounding box is built for the terrain.
82 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
83
84 // Until the whole simulator is changed to pass us the region size, we rely on constants.
85 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
86
87 // The scene that I am part of
88 private BSScene m_physicsScene { get; set; }
89
90 // The ground plane created to keep thing from falling to infinity.
91 private BulletBody m_groundPlane;
92
93 // If doing mega-regions, if we're region zero we will be managing multiple
94 // region terrains since region zero does the physics for the whole mega-region.
95 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
96
97 // Flags used to know when to recalculate the height.
98 private bool m_terrainModified = false;
99
100 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
101 // This is incremented before assigning to new region so it is the last ID allocated.
102 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
103 public uint HighestTerrainID { get {return m_terrainCount; } }
104
105 // If doing mega-regions, this holds our offset from region zero of
106 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
107 private Vector3 m_worldOffset;
108 // If the parent region (region 0), this is the extent of the combined regions
109 // relative to the origin of region zero
110 private Vector3 m_worldMax;
111 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
112
113 public BSTerrainManager(BSScene physicsScene, Vector3 regionSize)
114 {
115 m_physicsScene = physicsScene;
116 DefaultRegionSize = regionSize;
117
118 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
119
120 // Assume one region of default size
121 m_worldOffset = Vector3.Zero;
122 m_worldMax = new Vector3(DefaultRegionSize);
123 MegaRegionParentPhysicsScene = null;
124 }
125
126 public void Dispose()
127 {
128 ReleaseGroundPlaneAndTerrain();
129 }
130
131 // Create the initial instance of terrain and the underlying ground plane.
132 // This is called from the initialization routine so we presume it is
133 // safe to call Bullet in real time. We hope no one is moving prims around yet.
134 public void CreateInitialGroundPlaneAndTerrain()
135 {
136 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
137 // The ground plane is here to catch things that are trying to drop to negative infinity
138 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
139 Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane);
140 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
141 BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity);
142
143 // Everything collides with the ground plane.
144 m_groundPlane.collisionType = CollisionType.Groundplane;
145
146 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
148
149 // Ground plane does not move
150 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
151
152 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
153 lock (m_terrains)
154 {
155 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
156 m_terrains.Add(Vector3.Zero, initialTerrain);
157 }
158 }
159
160 // Release all the terrain structures we might have allocated
161 public void ReleaseGroundPlaneAndTerrain()
162 {
163 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
164 if (m_groundPlane.HasPhysicalBody)
165 {
166 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
167 {
168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
169 }
170 m_groundPlane.Clear();
171 }
172
173 ReleaseTerrain();
174 }
175
176 // Release all the terrain we have allocated
177 public void ReleaseTerrain()
178 {
179 lock (m_terrains)
180 {
181 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
182 {
183 kvp.Value.Dispose();
184 }
185 m_terrains.Clear();
186 }
187 }
188
189 // The simulator wants to set a new heightmap for the terrain.
190 public void SetTerrain(float[] heightMap) {
191 float[] localHeightMap = heightMap;
192 // If there are multiple requests for changes to the same terrain between ticks,
193 // only do that last one.
194 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
195 {
196 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
197 {
198 // If a child of a mega-region, we shouldn't have any terrain allocated for us
199 ReleaseGroundPlaneAndTerrain();
200 // If doing the mega-prim stuff and we are the child of the zero region,
201 // the terrain is added to our parent
202 if (MegaRegionParentPhysicsScene is BSScene)
203 {
204 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
205 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
206 BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
207 }
208 }
209 else
210 {
211 // If not doing the mega-prim thing, just change the terrain
212 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
213
214 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
215 }
216 });
217 }
218
219 // Another region is calling this region and passing a terrain.
220 // A region that is not the mega-region root will pass its terrain to the root region so the root region
221 // physics engine will have all the terrains.
222 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
223 {
224 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
225 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
226 {
227 UpdateTerrain(id, heightMap, minCoords, maxCoords);
228 });
229 }
230
231 // If called for terrain has has not been previously allocated, a new terrain will be built
232 // based on the passed information. The 'id' should be either the terrain id or
233 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
234 // The latter feature is for creating child terrains for mega-regions.
235 // If there is an existing terrain body, a new
236 // terrain shape is created and added to the body.
237 // This call is most often used to update the heightMap and parameters of the terrain.
238 // (The above does suggest that some simplification/refactoring is in order.)
239 // Called during taint-time.
240 private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
241 {
242 // Find high and low points of passed heightmap.
243 // The min and max passed in is usually the area objects can be in (maximum
244 // object height, for instance). The terrain wants the bounding box for the
245 // terrain so replace passed min and max Z with the actual terrain min/max Z.
246 float minZ = float.MaxValue;
247 float maxZ = float.MinValue;
248 foreach (float height in heightMap)
249 {
250 if (height < minZ) minZ = height;
251 if (height > maxZ) maxZ = height;
252 }
253 if (minZ == maxZ)
254 {
255 // If min and max are the same, reduce min a little bit so a good bounding box is created.
256 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
257 }
258 minCoords.Z = minZ;
259 maxCoords.Z = maxZ;
260
261 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
262 BSScene.DetailLogZero, id, minCoords, maxCoords);
263
264 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
265
266 lock (m_terrains)
267 {
268 BSTerrainPhys terrainPhys;
269 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
270 {
271 // There is already a terrain in this spot. Free the old and build the new.
272 DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
273 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords);
274
275 // Remove old terrain from the collection
276 m_terrains.Remove(terrainRegionBase);
277 // Release any physical memory it may be using.
278 terrainPhys.Dispose();
279
280 if (MegaRegionParentPhysicsScene == null)
281 {
282 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
283 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
284 m_terrains.Add(terrainRegionBase, newTerrainPhys);
285
286 m_terrainModified = true;
287 }
288 else
289 {
290 // It's possible that Combine() was called after this code was queued.
291 // If we are a child of combined regions, we don't create any terrain for us.
292 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
293
294 // Get rid of any terrain that may have been allocated for us.
295 ReleaseGroundPlaneAndTerrain();
296
297 // I hate doing this, but just bail
298 return;
299 }
300 }
301 else
302 {
303 // We don't know about this terrain so either we are creating a new terrain or
304 // our mega-prim child is giving us a new terrain to add to the phys world
305
306 // if this is a child terrain, calculate a unique terrain id
307 uint newTerrainID = id;
308 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
309 newTerrainID = ++m_terrainCount;
310
311 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
312 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
313 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
314 m_terrains.Add(terrainRegionBase, newTerrainPhys);
315
316 m_terrainModified = true;
317 }
318 }
319 }
320
321 // TODO: redo terrain implementation selection to allow other base types than heightMap.
322 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
323 {
324 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
325 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
326 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
327 BSTerrainPhys newTerrainPhys = null;
328 switch ((int)BSParam.TerrainImplementation)
329 {
330 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
331 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
332 heightMap, minCoords, maxCoords);
333 break;
334 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
335 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
336 heightMap, minCoords, maxCoords);
337 break;
338 default:
339 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
340 LogHeader,
341 (int)BSParam.TerrainImplementation,
342 BSParam.TerrainImplementation,
343 m_physicsScene.RegionName, terrainRegionBase);
344 break;
345 }
346 return newTerrainPhys;
347 }
348
349 // Return 'true' of this position is somewhere in known physical terrain space
350 public bool IsWithinKnownTerrain(Vector3 pos)
351 {
352 Vector3 terrainBaseXYZ;
353 BSTerrainPhys physTerrain;
354 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
355 }
356
357 // Return a new position that is over known terrain if the position is outside our terrain.
358 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
359 {
360 float edgeEpsilon = 0.1f;
361
362 Vector3 ret = pPos;
363
364 // First, base addresses are never negative so correct for that possible problem.
365 if (ret.X < 0f || ret.Y < 0f)
366 {
367 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
368 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
369 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
370 BSScene.DetailLogZero, pPos, ret);
371 }
372
373 // Can't do this function if we don't know about any terrain.
374 if (m_terrains.Count == 0)
375 return ret;
376
377 int loopPrevention = 10;
378 Vector3 terrainBaseXYZ;
379 BSTerrainPhys physTerrain;
380 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
381 {
382 // The passed position is not within a known terrain area.
383 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
384
385 // Must be off the top of a region. Find an adjacent region to move into.
386 // The returned terrain is always 'lower'. That is, closer to <0,0>.
387 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
388
389 if (adjacentTerrainBase.X < terrainBaseXYZ.X)
390 {
391 // moving down into a new region in the X dimension. New position will be the max in the new base.
392 ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon;
393 }
394 if (adjacentTerrainBase.Y < terrainBaseXYZ.Y)
395 {
396 // moving down into a new region in the X dimension. New position will be the max in the new base.
397 ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon;
398 }
399 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
400 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
401
402 if (loopPrevention-- < 0f)
403 {
404 // The 'while' is a little dangerous so this prevents looping forever if the
405 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
406 // the list of terrains is in transition.
407 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
408 break;
409 }
410 }
411
412 return ret;
413 }
414
415 // Given an X and Y, find the height of the terrain.
416 // Since we could be handling multiple terrains for a mega-region,
417 // the base of the region is calcuated assuming all regions are
418 // the same size and that is the default.
419 // Once the heightMapInfo is found, we have all the information to
420 // compute the offset into the array.
421 private float lastHeightTX = 999999f;
422 private float lastHeightTY = 999999f;
423 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
424 public float GetTerrainHeightAtXYZ(Vector3 pos)
425 {
426 float tX = pos.X;
427 float tY = pos.Y;
428 // You'd be surprized at the number of times this routine is called
429 // with the same parameters as last time.
430 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
431 return lastHeight;
432 m_terrainModified = false;
433
434 lastHeightTX = tX;
435 lastHeightTY = tY;
436 float ret = HEIGHT_GETHEIGHT_RET;
437
438 Vector3 terrainBaseXYZ;
439 BSTerrainPhys physTerrain;
440 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
441 {
442 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
443 }
444 else
445 {
446 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
447 LogHeader, m_physicsScene.RegionName, tX, tY);
448 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
449 BSScene.DetailLogZero, pos, terrainBaseXYZ);
450 }
451
452 lastHeight = ret;
453 return ret;
454 }
455
456 public float GetWaterLevelAtXYZ(Vector3 pos)
457 {
458 float ret = WATER_HEIGHT_GETHEIGHT_RET;
459
460 Vector3 terrainBaseXYZ;
461 BSTerrainPhys physTerrain;
462 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
463 {
464 ret = physTerrain.GetWaterLevelAtXYZ(pos);
465 }
466 else
467 {
468 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
469 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
470 }
471 return ret;
472 }
473
474 // Given an address, return 'true' of there is a description of that terrain and output
475 // the descriptor class and the 'base' fo the addresses therein.
476 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
477 {
478 bool ret = false;
479
480 Vector3 terrainBaseXYZ = Vector3.Zero;
481 if (pos.X < 0f || pos.Y < 0f)
482 {
483 // We don't handle negative addresses so just make up a base that will not be found.
484 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
485 }
486 else
487 {
488 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
489 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
490 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
491 }
492
493 BSTerrainPhys physTerrain = null;
494 lock (m_terrains)
495 {
496 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
497 }
498 outTerrainBase = terrainBaseXYZ;
499 outPhysTerrain = physTerrain;
500 return ret;
501 }
502
503 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
504 // this one. Usually used to return an out of bounds object to a known place.
505 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
506 {
507 Vector3 ret = pTerrainBase;
508
509 // Can't do this function if we don't know about any terrain.
510 if (m_terrains.Count == 0)
511 return ret;
512
513 // Just some sanity
514 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
515 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
516 ret.Z = 0f;
517
518 lock (m_terrains)
519 {
520 // Once down to the <0,0> region, we have to be done.
521 while (ret.X > 0f || ret.Y > 0f)
522 {
523 if (ret.X > 0f)
524 {
525 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
526 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
527 if (m_terrains.ContainsKey(ret))
528 break;
529 }
530 if (ret.Y > 0f)
531 {
532 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
533 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
534 if (m_terrains.ContainsKey(ret))
535 break;
536 }
537 }
538 }
539
540 return ret;
541 }
542
543 // Although no one seems to check this, I do support combining.
544 public bool SupportsCombining()
545 {
546 return true;
547 }
548
549 // This routine is called two ways:
550 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
551 // extent of the combined regions. This is to inform the parent of the size
552 // of the combined regions.
553 // and one with 'offset' as the offset of the child region to the base region,
554 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
555 // child of its relative base and new parent.
556 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
557 {
558 m_worldOffset = offset;
559 m_worldMax = extents;
560 MegaRegionParentPhysicsScene = pScene;
561 if (pScene != null)
562 {
563 // We are a child.
564 // We want m_worldMax to be the highest coordinate of our piece of terrain.
565 m_worldMax = offset + DefaultRegionSize;
566 }
567 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
568 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
569 }
570
571 // Unhook all the combining that I know about.
572 public void UnCombine(PhysicsScene pScene)
573 {
574 // Just like ODE, we don't do anything yet.
575 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
576 }
577
578
579 private void DetailLog(string msg, params Object[] args)
580 {
581 m_physicsScene.PhysicsLogging.Write(msg, args);
582 }
583}
584}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
new file mode 100755
index 0000000..cd59b65
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
@@ -0,0 +1,440 @@
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.PhysicsModules.SharedBase;
34
35using Nini.Config;
36using log4net;
37
38using OpenMetaverse;
39
40namespace OpenSim.Region.PhysicsModule.BulletS
41{
42public sealed class BSTerrainMesh : BSTerrainPhys
43{
44 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
45
46 private float[] m_savedHeightMap;
47 int m_sizeX;
48 int m_sizeY;
49
50 BulletShape m_terrainShape;
51 BulletBody m_terrainBody;
52
53 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
54 : base(physicsScene, regionBase, id)
55 {
56 }
57
58 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
59 : base(physicsScene, regionBase, id)
60 {
61 }
62
63 // Create terrain mesh from a heightmap.
64 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
65 Vector3 minCoords, Vector3 maxCoords)
66 : base(physicsScene, regionBase, id)
67 {
68 int indicesCount;
69 int[] indices;
70 int verticesCount;
71 float[] vertices;
72
73 m_savedHeightMap = initialMap;
74
75 m_sizeX = (int)(maxCoords.X - minCoords.X);
76 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
77
78 bool meshCreationSuccess = false;
79 if (BSParam.TerrainMeshMagnification == 1)
80 {
81 // If a magnification of one, use the old routine that is tried and true.
82 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene,
83 initialMap, m_sizeX, m_sizeY, // input size
84 Vector3.Zero, // base for mesh
85 out indicesCount, out indices, out verticesCount, out vertices);
86 }
87 else
88 {
89 // Other magnifications use the newer routine
90 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene,
91 initialMap, m_sizeX, m_sizeY, // input size
92 BSParam.TerrainMeshMagnification,
93 physicsScene.TerrainManager.DefaultRegionSize,
94 Vector3.Zero, // base for mesh
95 out indicesCount, out indices, out verticesCount, out vertices);
96 }
97 if (!meshCreationSuccess)
98 {
99 // DISASTER!!
100 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
101 m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
102 // Something is very messed up and a crash is in our future.
103 return;
104 }
105
106 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
107 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
108
109 m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices);
110 if (!m_terrainShape.HasPhysicalShape)
111 {
112 // DISASTER!!
113 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
114 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
115 // Something is very messed up and a crash is in our future.
116 return;
117 }
118
119 Vector3 pos = regionBase;
120 Quaternion rot = Quaternion.Identity;
121
122 m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
123 if (!m_terrainBody.HasPhysicalBody)
124 {
125 // DISASTER!!
126 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
127 // Something is very messed up and a crash is in our future.
128 return;
129 }
130 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
131
132 // Set current terrain attributes
133 m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
134 m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
135 m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
136 m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
137 m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
138
139 // Static objects are not very massive.
140 m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
141
142 // Put the new terrain to the world of physical objects
143 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody);
144
145 // Redo its bounding box now that it is in the world
146 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody);
147
148 m_terrainBody.collisionType = CollisionType.Terrain;
149 m_terrainBody.ApplyCollisionMask(m_physicsScene);
150
151 if (BSParam.UseSingleSidedMeshes)
152 {
153 m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
154 m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
155 }
156
157 // Make it so the terrain will not move or be considered for movement.
158 m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
159 }
160
161 public override void Dispose()
162 {
163 if (m_terrainBody.HasPhysicalBody)
164 {
165 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody);
166 // Frees both the body and the shape.
167 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody);
168 m_terrainBody.Clear();
169 m_terrainShape.Clear();
170 }
171 }
172
173 public override float GetTerrainHeightAtXYZ(Vector3 pos)
174 {
175 // For the moment use the saved heightmap to get the terrain height.
176 // TODO: raycast downward to find the true terrain below the position.
177 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
178
179 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
180 try
181 {
182 ret = m_savedHeightMap[mapIndex];
183 }
184 catch
185 {
186 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
187 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
188 LogHeader, TerrainBase, pos);
189 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
190 }
191 return ret;
192 }
193
194 // The passed position is relative to the base of the region.
195 public override float GetWaterLevelAtXYZ(Vector3 pos)
196 {
197 return m_physicsScene.SimpleWaterLevel;
198 }
199
200 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
201 // Return 'true' if successfully created.
202 public static bool ConvertHeightmapToMesh( BSScene physicsScene,
203 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
204 Vector3 extentBase, // base to be added to all vertices
205 out int indicesCountO, out int[] indicesO,
206 out int verticesCountO, out float[] verticesO)
207 {
208 bool ret = false;
209
210 int indicesCount = 0;
211 int verticesCount = 0;
212 int[] indices = new int[0];
213 float[] vertices = new float[0];
214
215 // Simple mesh creation which assumes magnification == 1.
216 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
217
218 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
219 // from zero to <= sizeX). The triangle indices are then generated as two triangles
220 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
221 // column of vertices are used to complete the triangles of the last row and column
222 // of the heightmap.
223 try
224 {
225 // One vertice per heightmap value plus the vertices off the side and bottom edge.
226 int totalVertices = (sizeX + 1) * (sizeY + 1);
227 vertices = new float[totalVertices * 3];
228 int totalIndices = sizeX * sizeY * 6;
229 indices = new int[totalIndices];
230
231 if (physicsScene != null)
232 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
233 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
234 float minHeight = float.MaxValue;
235 // Note that sizeX+1 vertices are created since there is land between this and the next region.
236 for (int yy = 0; yy <= sizeY; yy++)
237 {
238 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
239 {
240 int offset = yy * sizeX + xx;
241 // Extend the height with the height from the last row or column
242 if (yy == sizeY) offset -= sizeX;
243 if (xx == sizeX) offset -= 1;
244 float height = heightMap[offset];
245 minHeight = Math.Min(minHeight, height);
246 vertices[verticesCount + 0] = (float)xx + extentBase.X;
247 vertices[verticesCount + 1] = (float)yy + extentBase.Y;
248 vertices[verticesCount + 2] = height + extentBase.Z;
249 verticesCount += 3;
250 }
251 }
252 verticesCount = verticesCount / 3;
253
254 for (int yy = 0; yy < sizeY; yy++)
255 {
256 for (int xx = 0; xx < sizeX; xx++)
257 {
258 int offset = yy * (sizeX + 1) + xx;
259 // Each vertices is presumed to be the upper left corner of a box of two triangles
260 indices[indicesCount + 0] = offset;
261 indices[indicesCount + 1] = offset + 1;
262 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
263 indices[indicesCount + 3] = offset + 1;
264 indices[indicesCount + 4] = offset + sizeX + 2;
265 indices[indicesCount + 5] = offset + sizeX + 1;
266 indicesCount += 6;
267 }
268 }
269
270 ret = true;
271 }
272 catch (Exception e)
273 {
274 if (physicsScene != null)
275 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
276 LogHeader, physicsScene.RegionName, extentBase, e);
277 }
278
279 indicesCountO = indicesCount;
280 indicesO = indices;
281 verticesCountO = verticesCount;
282 verticesO = vertices;
283
284 return ret;
285 }
286
287 private class HeightMapGetter
288 {
289 private float[] m_heightMap;
290 private int m_sizeX;
291 private int m_sizeY;
292 public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
293 {
294 m_heightMap = pHeightMap;
295 m_sizeX = pSizeX;
296 m_sizeY = pSizeY;
297 }
298 // The heightmap is extended as an infinite plane at the last height
299 public float GetHeight(int xx, int yy)
300 {
301 int offset = 0;
302 // Extend the height with the height from the last row or column
303 if (yy >= m_sizeY)
304 if (xx >= m_sizeX)
305 offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
306 else
307 offset = (m_sizeY - 1) * m_sizeX + xx;
308 else
309 if (xx >= m_sizeX)
310 offset = yy * m_sizeX + (m_sizeX - 1);
311 else
312 offset = yy * m_sizeX + xx;
313
314 return m_heightMap[offset];
315 }
316 }
317
318 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
319 // Version that handles magnification.
320 // Return 'true' if successfully created.
321 public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
322 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
323 int magnification, // number of vertices per heighmap step
324 Vector3 extent, // dimensions of the output mesh
325 Vector3 extentBase, // base to be added to all vertices
326 out int indicesCountO, out int[] indicesO,
327 out int verticesCountO, out float[] verticesO)
328 {
329 bool ret = false;
330
331 int indicesCount = 0;
332 int verticesCount = 0;
333 int[] indices = new int[0];
334 float[] vertices = new float[0];
335
336 HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
337
338 // The vertices dimension of the output mesh
339 int meshX = sizeX * magnification;
340 int meshY = sizeY * magnification;
341 // The output size of one mesh step
342 float meshXStep = extent.X / meshX;
343 float meshYStep = extent.Y / meshY;
344
345 // Create an array of vertices that is meshX+1 by meshY+1 (note the loop
346 // from zero to <= meshX). The triangle indices are then generated as two triangles
347 // per heightmap point. There are meshX by meshY of these squares. The extra row and
348 // column of vertices are used to complete the triangles of the last row and column
349 // of the heightmap.
350 try
351 {
352 // Vertices for the output heightmap plus one on the side and bottom to complete triangles
353 int totalVertices = (meshX + 1) * (meshY + 1);
354 vertices = new float[totalVertices * 3];
355 int totalIndices = meshX * meshY * 6;
356 indices = new int[totalIndices];
357
358 if (physicsScene != null)
359 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
360 BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
361 totalVertices, totalIndices, extentBase);
362
363 float minHeight = float.MaxValue;
364 // Note that sizeX+1 vertices are created since there is land between this and the next region.
365 // Loop through the output vertices and compute the mediun height in between the input vertices
366 for (int yy = 0; yy <= meshY; yy++)
367 {
368 for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
369 {
370 float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
371 int stepY = (int)offsetY;
372 float fractionalY = offsetY - (float)stepY;
373 float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
374 int stepX = (int)offsetX;
375 float fractionalX = offsetX - (float)stepX;
376
377 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
378 // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
379
380 // get the four corners of the heightmap square the mesh point is in
381 float heightUL = hmap.GetHeight(stepX , stepY );
382 float heightUR = hmap.GetHeight(stepX + 1, stepY );
383 float heightLL = hmap.GetHeight(stepX , stepY + 1);
384 float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
385
386 // bilinear interplolation
387 float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
388 + heightUR * fractionalX * (1 - fractionalY)
389 + heightLL * (1 - fractionalX) * fractionalY
390 + heightLR * fractionalX * fractionalY;
391
392 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
393 // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
394
395 minHeight = Math.Min(minHeight, height);
396
397 vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
398 vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
399 vertices[verticesCount + 2] = height + extentBase.Z;
400 verticesCount += 3;
401 }
402 }
403 // The number of vertices generated
404 verticesCount /= 3;
405
406 // Loop through all the heightmap squares and create indices for the two triangles for that square
407 for (int yy = 0; yy < meshY; yy++)
408 {
409 for (int xx = 0; xx < meshX; xx++)
410 {
411 int offset = yy * (meshX + 1) + xx;
412 // Each vertices is presumed to be the upper left corner of a box of two triangles
413 indices[indicesCount + 0] = offset;
414 indices[indicesCount + 1] = offset + 1;
415 indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
416 indices[indicesCount + 3] = offset + 1;
417 indices[indicesCount + 4] = offset + meshX + 2;
418 indices[indicesCount + 5] = offset + meshX + 1;
419 indicesCount += 6;
420 }
421 }
422
423 ret = true;
424 }
425 catch (Exception e)
426 {
427 if (physicsScene != null)
428 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
429 LogHeader, physicsScene.RegionName, extentBase, e);
430 }
431
432 indicesCountO = indicesCount;
433 indicesO = indices;
434 verticesCountO = verticesCount;
435 verticesO = vertices;
436
437 return ret;
438 }
439}
440}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
new file mode 100755
index 0000000..3329395
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
@@ -0,0 +1,277 @@
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.PhysicsModule.BulletS
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 shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false;
110 }
111 public BSPhysicsShapeType shapeType;
112 public System.UInt64 shapeKey;
113 public bool isNativeShape;
114
115 public virtual void Clear() { }
116 public virtual bool HasPhysicalShape { get { return false; } }
117
118 // Make another reference to this physical object.
119 public virtual BulletShape Clone() { return new BulletShape(); }
120
121 // Return 'true' if this and other refer to the same physical object
122 public virtual bool ReferenceSame(BulletShape xx) { return false; }
123
124 // Used for log messages for a unique display of the memory/object allocated to this instance
125 public virtual string AddrString
126 {
127 get { return "unknown"; }
128 }
129
130 public override string ToString()
131 {
132 StringBuilder buff = new StringBuilder();
133 buff.Append("<p=");
134 buff.Append(AddrString);
135 buff.Append(",s=");
136 buff.Append(shapeType.ToString());
137 buff.Append(",k=");
138 buff.Append(shapeKey.ToString("X"));
139 buff.Append(",n=");
140 buff.Append(isNativeShape.ToString());
141 buff.Append(">");
142 return buff.ToString();
143 }
144}
145
146// An allocated Bullet btConstraint
147public class BulletConstraint
148{
149 public BulletConstraint()
150 {
151 }
152 public virtual void Clear() { }
153 public virtual bool HasPhysicalConstraint { get { return false; } }
154
155 // Used for log messages for a unique display of the memory/object allocated to this instance
156 public virtual string AddrString
157 {
158 get { return "unknown"; }
159 }
160}
161
162// An allocated HeightMapThing which holds various heightmap info.
163// Made a class rather than a struct so there would be only one
164// instance of this and C# will pass around pointers rather
165// than making copies.
166public class BulletHMapInfo
167{
168 public BulletHMapInfo(uint id, float[] hm, float pSizeX, float pSizeY) {
169 ID = id;
170 heightMap = hm;
171 terrainRegionBase = OMV.Vector3.Zero;
172 minCoords = new OMV.Vector3(100f, 100f, 25f);
173 maxCoords = new OMV.Vector3(101f, 101f, 26f);
174 minZ = maxZ = 0f;
175 sizeX = pSizeX;
176 sizeY = pSizeY;
177 }
178 public uint ID;
179 public float[] heightMap;
180 public OMV.Vector3 terrainRegionBase;
181 public OMV.Vector3 minCoords;
182 public OMV.Vector3 maxCoords;
183 public float sizeX, sizeY;
184 public float minZ, maxZ;
185 public BulletShape terrainShape;
186 public BulletBody terrainBody;
187}
188
189// The general class of collsion object.
190public enum CollisionType
191{
192 Avatar,
193 PhantomToOthersAvatar, // An avatar that it phantom to other avatars but not to anything else
194 Groundplane,
195 Terrain,
196 Static,
197 Dynamic,
198 VolumeDetect,
199 // Linkset, // A linkset should be either Static or Dynamic
200 LinksetChild,
201 Unknown
202};
203
204// Hold specification of group and mask collision flags for a CollisionType
205public struct CollisionTypeFilterGroup
206{
207 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
208 {
209 type = t;
210 group = g;
211 mask = m;
212 }
213 public CollisionType type;
214 public uint group;
215 public uint mask;
216};
217
218public static class BulletSimData
219{
220
221// Map of collisionTypes to flags for collision groups and masks.
222// An object's 'group' is the collison groups this object belongs to
223// An object's 'filter' is the groups another object has to belong to in order to collide with me
224// A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0)
225//
226// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
227// but, instead, use references to this dictionary. Finding and debugging
228// collision flag problems will be made easier.
229public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
230 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
231{
232 { CollisionType.Avatar,
233 new CollisionTypeFilterGroup(CollisionType.Avatar,
234 (uint)CollisionFilterGroups.BCharacterGroup,
235 (uint)(CollisionFilterGroups.BAllGroup))
236 },
237 { CollisionType.PhantomToOthersAvatar,
238 new CollisionTypeFilterGroup(CollisionType.PhantomToOthersAvatar,
239 (uint)CollisionFilterGroups.BCharacterGroup,
240 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BCharacterGroup))
241 },
242 { CollisionType.Groundplane,
243 new CollisionTypeFilterGroup(CollisionType.Groundplane,
244 (uint)CollisionFilterGroups.BGroundPlaneGroup,
245 // (uint)CollisionFilterGroups.BAllGroup)
246 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
247 },
248 { CollisionType.Terrain,
249 new CollisionTypeFilterGroup(CollisionType.Terrain,
250 (uint)CollisionFilterGroups.BTerrainGroup,
251 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
252 },
253 { CollisionType.Static,
254 new CollisionTypeFilterGroup(CollisionType.Static,
255 (uint)CollisionFilterGroups.BStaticGroup,
256 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
257 },
258 { CollisionType.Dynamic,
259 new CollisionTypeFilterGroup(CollisionType.Dynamic,
260 (uint)CollisionFilterGroups.BSolidGroup,
261 (uint)(CollisionFilterGroups.BAllGroup))
262 },
263 { CollisionType.VolumeDetect,
264 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
265 (uint)CollisionFilterGroups.BSensorTrigger,
266 (uint)(~CollisionFilterGroups.BSensorTrigger))
267 },
268 { CollisionType.LinksetChild,
269 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
270 (uint)CollisionFilterGroups.BLinksetChildGroup,
271 (uint)(CollisionFilterGroups.BNoneGroup))
272 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
273 },
274};
275
276}
277}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt
new file mode 100755
index 0000000..0453376
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt
@@ -0,0 +1,379 @@
1CURRENT PROBLEMS TO FIX AND/OR LOOK AT
2=================================================
3Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass.
4 Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive?
5 Negative buoyancy computed correctly
6Center-of-gravity
7Computation of mesh mass. How done? How should it be done?
8Enable vehicle border crossings (at least as poorly as ODE)
9 Terrain skirts
10 Avatar created in previous region and not new region when crossing border
11 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
12User settable terrain mesh
13 Allow specifying as convex or concave and use different getHeight functions depending
14Boats, when turning nose down into the water
15 Acts like rotation around Z is also effecting rotation around X and Y
16Deleting a linkset while standing on the root will leave the physical shape of the root behind.
17 Not sure if it is because standing on it. Done with large prim linksets.
18Linkset child rotations.
19 Nebadon spiral tube has middle sections which are rotated wrong.
20 Select linked spiral tube. Delink and note where the middle section ends up.
21Teravus llMoveToTarget script debug
22 Mixing of hover, buoyancy/gravity, moveToTarget, into one force
23 Setting hover height to zero disables hover even if hover flags are on (from SL wiki)
24limitMotorUp calibration (more down?)
25llRotLookAt
26llLookAt
27Convert to avatar mesh capsule. Include rotation of capsule.
28Vehicle script tuning/debugging
29 Avanti speed script
30 Weapon shooter script
31Move material definitions (friction, ...) into simulator.
32osGetPhysicsEngineVerion() and create a version code for the C++ DLL
33One sided meshes? Should terrain be built into a closed shape?
34 When meshes get partially wedged into the terrain, they cannot push themselves out.
35 It is possible that Bullet processes collisions whether entering or leaving a mesh.
36 Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869
37Small physical objects do not interact correctly
38 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
39 The chain will fall apart and pairs will dance around on ground
40 Chains of 1x1x.2 will stay connected but will dance.
41 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
42
43VEHICLES TODO LIST:
44=================================================
45LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers.
46 What are the limits in SL?
47 Same for other velocity settings.
48UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims:
49 https://github.com/UbitUmarov/Ubit-opensim
50Some vehicles should not be able to turn if no speed or off ground.
51Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
52Neb car jiggling left and right
53 Happens on terrain and any other mesh object. Flat cubes are much smoother.
54 This has been reduced but not eliminated.
55Implement referenceFrame for all the motion routines.
56Verify llGetVel() is returning a smooth and good value for vehicle movement.
57llGetVel() should return the root's velocity if requested in a child prim.
58Implement function efficiency for lineaar and angular motion.
59Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
60Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
61 A kludge that isn't fixing the real problem of Bullet adding extra motion.
62Incorporate inter-relationship of angular corrections. For instance, angularDeflection
63 and angularMotorUp will compute same X or Y correction. When added together
64 creates over-correction and over-shoot and wabbling.
65Vehicle attributes are not restored when a vehicle is rezzed on region creation
66 Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized.
67What to do if vehicle and prim buoyancy differ?
68
69GENERAL TODO LIST:
70=================================================
71Resitution of a prim works on another prim but not on terrain.
72 The dropped prim doesn't bounce properly on the terrain.
73Add a sanity check for PIDTarget location.
74Level-of-detail for mesh creation. Prims with circular interiors require lod of 32.
75 Is much saved with lower LODs? At the moment, all set to 32.
76Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't.
77 If arrow show at prim, collision reported about 1/3 of time. If collision reported,
78 both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times.
79 Shooting 5m sphere "arrows" at 60m/s.
80llMoveToTarget objects are not effected by gravity until target is removed.
81Compute CCD parameters based on body size
82Can solver iterations be changed per body/shape? Can be for constraints but what
83 about regular vehicles?
84Implement llSetPhysicalMaterial.
85 extend it with Center-of-mass, rolling friction, density
86Implement llSetForceAndTorque.
87Change BSPrim.moveToTarget to used forces rather than changing position
88 Changing position allows one to move through walls
89Implement an avatar mesh shape. The Bullet capsule is way too limited.
90 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
91Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain.
92Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
93Duplicating a physical prim causes old prim to jump away
94 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
95Scenes with hundred of thousands of static objects take a lot of physics CPU time.
96Gun sending shooter flying.
97Collision margin (gap between physical objects lying on each other)
98Boundry checking (crashes related to crossing boundry)
99 Add check for border edge position for avatars and objects.
100 Verify the events are created for border crossings.
101Implement ShapeCollection.Dispose()
102Implement water as a plain or mesh so raycasting and collisions can happen with same.
103Add collision penetration return
104 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
105Linkset.Position and Linkset.Orientation requre rewrite to properly return
106 child position. LinksetConstraint acts like it's at taint time!!
107Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
108Should the different PID factors have non-equal contributions for different
109 values of Efficiency?
110Selecting and deselecting physical objects causes CPU processing time to jump
111 http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1
112 put thousand physical objects, select and deselect same. CPU time will be large.
113Re-implement buoyancy as a separate force on the object rather than diddling gravity.
114 Register a pre-step event to add the force.
115More efficient memory usage when passing hull information from BSPrim to BulletSim
116Physical and phantom will drop through the terrain
117
118
119LINKSETS
120======================================================
121Child prims do not report collisions
122Allow children of a linkset to be phantom:
123 http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html
124 Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast.
125Editing a child of a linkset causes the child to go phantom
126 Move a child prim once when it is physical and can never move it again without it going phantom
127Offset the center of the linkset to be the geometric center of all the prims
128 Not quite the same as the center-of-gravity
129Linksets should allow collisions to individual children
130 Add LocalID to children shapes in LinksetCompound and create events for individuals
131LinksetCompound: when one of the children changes orientation (like tires
132 turning on a vehicle, the whole compound object is rebuilt. Optimize this
133 so orientation/position of individual children can change without a rebuild.
134Verify/think through scripts in children of linksets. What do they reference
135 and return when getting position, velocity, ...
136Confirm constraint linksets still work after making all the changes for compound linksets.
137Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding
138Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
139 For compound linksets, add ability to remove or reposition individual child shapes.
140Speed up creation of large physical linksets
141 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
142 REALLY bad for very large physical linksets (freezes the sim for many seconds).
143Eliminate collisions between objects in a linkset. (LinksetConstraint)
144 Have UserPointer point to struct with localID and linksetID?
145 Objects in original linkset still collide with each other?
146
147MORE
148======================================================
149Compute avatar size and scale correctly. Now it is a bit off from the capsule size.
150Create tests for different interface components
151 Have test objects/scripts measure themselves and turn color if correct/bad
152 Test functions in SL and calibrate correctness there
153 Create auto rezzer and tracker to run through the tests
154Do we need to do convex hulls all the time? Can complex meshes be left meshes?
155 There is some problem with meshes and collisions
156 Hulls are not as detailed as meshes. Hulled vehicles insides are different shape.
157Debounce avatar contact so legs don't keep folding up when standing.
158Add border extensions to terrain to help region crossings and objects leaving region.
159Use a different capsule shape for avatar when sitting
160 LL uses a pyrimidal shape scaled by the avatar's bounding box
161 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
162Performance test with lots of avatars. Can BulletSim support a thousand?
163Optimize collisions in C++: only send up to the object subscribed to collisions.
164 Use collision subscription and remove the collsion(A,B) and collision(B,A)
165Check whether SimMotionState needs large if statement (see TODO).
166Implement 'top colliders' info.
167Avatar jump
168Performance measurement and changes to make quicker.
169Implement detailed physics stats (GetStats()).
170Measure performance improvement from hulls
171Test not using ghost objects for volume detect implementation.
172Performance of closures and delegates for taint processing
173 Are there faster ways?
174 Is any slowdown introduced by the existing implementation significant?
175Is there are more efficient method of implementing pre and post step actions?
176 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
177Physics Arena central pyramid: why is one side permiable?
178In SL, perfect spheres don't seem to have rolling friction. Add special case.
179Enforce physical parameter min/max:
180 Gravity: [-1, 28]
181 Friction: [0, 255]
182 Density: [1, 22587]
183 Restitution [0, 1]
184 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
185Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
186Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html
187
188INTERNAL IMPROVEMENT/CLEANUP
189=================================================
190Create the physical wrapper classes (BulletBody, BulletShape) by methods on
191 BSAPITemplate and make their actual implementation Bullet engine specific.
192 For the short term, just call the existing functions in ShapeCollection.
193Consider moving prim/character body and shape destruction in destroy()
194 to postTimeTime rather than protecting all the potential sets that
195 might have been queued up.
196Remove unused fields from ShapeData (not used in API2)
197Remove unused fields from pinned memory shared parameter block
198 Create parameter variables in BSScene to replace same.
199Breakout code for mesh/hull/compound/native into separate BSShape* classes
200 Standardize access to building and reference code.
201 The skeleton classes are in the sources but are not complete or linked in.
202Make BSBody and BSShape real classes to centralize creation/changin/destruction
203 Convert state and parameter calls from BulletSimAPI direct calls to
204 calls on BSBody and BSShape
205Generalize Dynamics and PID with standardized motors.
206Generalize Linkset and vehicles into PropertyManagers
207 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
208 Potentially add events for shape destruction, etc.
209Better mechanism for resetting linkset set and vehicle parameters when body rebuilt.
210 BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc.
211Implement linkset by setting position of children when root updated. (LinksetManual)
212 Linkset implementation using manual prim movement.
213LinkablePrim class? Would that simplify/centralize the linkset logic?
214BSScene.UpdateParameterSet() is broken. How to set params on objects?
215Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
216 bob at the water level. BSPrim.PositionSanityCheck()
217Should taints check for existance or activeness of target?
218 When destroying linksets/etc, taints can be generated for objects that are
219 actually gone when the taint happens. Crashes don't happen because the taint closure
220 keeps the object from being freed, but that is just an accident.
221 Possibly have an 'active' flag that is checked by the taint processor?
222Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
223Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
224There are TOO MANY interfaces from BulletSim core to Bullet itself
225 Think of something to eliminate one or more of the layers
226
227THREADING
228=================================================
229Do taint action immediately if not actually executing Bullet.
230 Add lock around Bullet execution and just do taint actions if simulation is not happening.
231
232DONE DONE DONE DONE
233=================================================
234Cleanup code in BSDynamics by using motors. (Resolution: started)
235Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
236 Would have better and adjustable resolution.
237Build terrain mesh so heighmap is height of the center of the square meter.
238 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
239Terrain as mesh. (Resolution: done)
240How are static linksets seen by the physics engine?
241 Resolution: they are not linked in physics. When moved, all the children are repositioned.
242Convert BSCharacter to use all API2 (Resolution: done)
243Avatar pushing difficult (too heavy?)
244Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
245Remove old code in DLL (all non-API2 stuff). (Resolution: done)
246Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
247Debug Bullet internal stats output (why is timing all wrong?)
248 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
249Implement meshes or just verify that they work. (Resolution: they do!)
250Do prim hash codes work for sculpties and meshes? (Resolution: yes)
251Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
252 Compound shapes will need the LocalID in the shapes and collision
253 processing to get it from there.
254Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
255Package Bullet source mods for Bullet internal stats output
256 (Resolution: move code into WorldData.h rather than relying on patches)
257Single prim vehicles don't seem to properly vehiclize.
258 (Resolution: mass was not getting set properly for single prim linksets)
259Add material type linkage and input all the material property definitions.
260 Skeleton classes and table are in the sources but are not filled or used.
261 (Resolution:
262Neb vehicle taking > 25ms of physics time!!
263 (Resolution: compound linksets were being rebuild WAY too often)
264Avatar height off after unsitting (floats off ground)
265 Editting appearance then moving restores.
266 Must not be initializing height when recreating capsule after unsit.
267 (Resolution: confusion of scale vs size for native objects removed)
268Light cycle falling over when driving (Resolution: implemented angularMotorUp)
269Should vehicle angular/linear movement friction happen after all the components
270 or does it only apply to the basic movement?
271 (Resolution: friction added before returning newly computed motor value.
272 What is expected by some vehicles (turning up friction to moderate speed))
273Tune terrain/object friction to be closer to SL.
274 (Resolution: added material type with friction and resolution)
275Smooth avatar movement with motor (DONE)
276 Should motor update be all at taint-time? (Yes, DONE)
277 Fix avatar slowly sliding when standing (zero motion when stopped) (DONE)
278 (Resolution: added BSVMotor for avatar starting and stopping)
279llApplyImpulse()
280 Compare mass/movement in OS and SL. Calibrate actions. (DONE)
281 (Resolution: tested on SL and OS. AddForce scales the force for timestep)
282llSetBuoyancy() (DONE)
283 (Resolution: Bullet resets object gravity when added to world. Moved set gravity)
284Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
285 (Resolution: set default density to 3.5 (from 60) which is closer to SL)
286Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
287 (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA
288Meshes rendering as bounding boxes (DONE)
289 (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box)
290llMoveToTarget (Resolution: added simple motor to update the position.)
291Angular motor direction is global coordinates rather than local coordinates (DONE)
292Add vehicle collisions so IsColliding is properly reported. (DONE)
293 Needed for banking, limitMotorUp, movementLimiting, ...
294 (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it)
295VehicleAddForce is not scaled by the simulation step but it is only
296 applied for one step. Should it be scaled? (DONE)
297 (Resolution: use force for timed things, Impulse for immediate, non-timed things)
298Complete implemention of preStepActions (DONE)
299 Replace vehicle step call with prestep event.
300 Is there a need for postStepActions? postStepTaints?
301Disable activity of passive linkset children. (DONE)
302 Since the linkset is a compound object, the old prims are left lying
303 around and need to be phantomized so they don't collide, ...
304Remove HeightmapInfo from terrain specification (DONE)
305 Since C++ code does not need terrain height, this structure et al are not needed.
306Surfboard go wonky when turning (DONE)
307 Angular motor direction is global coordinates rather than local coordinates?
308 (Resolution: made angular motor direction correct coordinate system)
309Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE)
310 Msg Kayaker on OSGrid when working
311 (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the
312 same in SL as in OS/BulletSim)
313Boats float low in the water (DONE)
314Boats floating at proper level (DONE)
315When is force introduced by SetForce removed? The prestep action could go forever. (DONE)
316 (Resolution: setForce registers a prestep action which keeps applying the force)
317Child movement in linkset (don't rebuild linkset) (DONE 20130122))
318Avatar standing on a moving object should start to move with the object. (DONE 20130125)
319Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
320 Verify that angular motion specified around Z moves in the vehicle coordinates.
321 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
322Nebadon vehicles turning funny in arena (DONE)
323Lock axis (DONE 20130401)
324Terrain detail: double terrain mesh detail (DONE)
325Use the HACD convex hull routine in Bullet rather than the C# version.
326 Speed up hullifying large meshes. (DONE)
327Vehicle ride, get up, ride again. Second time vehicle does not act correctly.
328 Have to rez new vehicle and delete the old to fix situation.
329 (DONE 20130520: normalize rotations)
330Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd
331 position state where it will not settle onto ground properly, etc
332 (DONE 20130520: normalize rotations)
333Two of Nebadon vehicles in a sim max the CPU. This is new.
334 (DONE 20130520: two problems: if asset failed to mesh, constantly refetched
335 asset; vehicle was sending too many messages to all linkset members)
336Add material densities to the material types. (WILL NOT BE DONE: not how it is done)
337Avatars walking up stairs (DONE)
338Avatar movement
339 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
340 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE)
341 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
342After getting off a vehicle, the root prim is phantom (can be walked through)
343 Need to force a position update for the root prim after compound shape destruction
344 (DONE)
345Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects.
346 Regular triangle meshes don't do physical collisions.
347 (DONE: discovered GImpact is VERY CPU intensive)
348Script changing rotation of child prim while vehicle moving (eg turning wheel) causes
349 the wheel to appear to jump back. Looks like sending position from previous update.
350 (DONE: redo of compound linksets fixed problem)
351Refarb compound linkset creation to create a pseudo-root for center-of-mass
352 Let children change their shape to physical indendently and just add shapes to compound
353 (DONE: redo of compound linkset fixed problem)
354Vehicle angular vertical attraction (DONE: vegaslon code)
355vehicle angular banking (DONE: vegaslon code)
356Vehicle angular deflection (DONE: vegaslon code)
357 Preferred orientation angular correction fix
358Vehicles (Move smoothly)
359For limitMotorUp, use raycast down to find if vehicle is in the air.
360 (WILL NOT BE DONE: gravity does the job well enough)
361BSPrim.Force should set a continious force on the prim. The force should be
362 applied each tick. Some limits?
363 (DONE: added physical actors. Implemented SetForce, SetTorque, ...)
364Implement LSL physics controls. Like STATUS_ROTATE_X. (DONE)
365Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
366Avatar rotation (check out changes to ScenePresence for physical rotation) (DONE)
367Avatar running (what does phys engine need to do?) (DONE: multiplies run factor by walking force)
368setForce should set a constant force. Different than AddImpulse. (DONE)
369Add PID motor for avatar movement (slow to stop, ...) (WNBD: current works ok)
370Avatar movement motor check for zero or small movement. Somehow suppress small movements
371 when avatar has stopped and is just standing. Simple test for near zero has
372 the problem of preventing starting up (increase from zero) especially when falling.
373 (DONE: avatar movement actor knows if standing on stationary object and zeros motion)
374Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
375 BSScene.TaintedObject() could immediately execute the callback if already in taint time.
376 (DONE)
377
378
379
diff --git a/OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs b/OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs
new file mode 100755
index 0000000..2ba3c5a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs
@@ -0,0 +1,622 @@
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.Linq;
30using System.Reflection;
31using System.Text;
32using System.Threading;
33
34using OpenSim.Framework;
35using OpenSim.Region.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.PhysicsModules.SharedBase;
39
40using Mono.Addins;
41using Nini.Config;
42using log4net;
43using OpenMetaverse;
44
45namespace OpenSim.Region.PhysicsModule.BulletS
46{
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
48 public class ExtendedPhysics : INonSharedRegionModule
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 private static string LogHeader = "[EXTENDED PHYSICS]";
52
53 // =============================================================
54 // Since BulletSim is a plugin, this these values aren't defined easily in one place.
55 // This table must correspond to an identical table in BSScene.
56
57 // Per scene functions. See BSScene.
58
59 // Per avatar functions. See BSCharacter.
60
61 // Per prim functions. See BSPrim.
62 public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType";
63 public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
64 public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed";
65 public const string PhysFunctChangeLinkType = "BulletSim.ChangeLinkType";
66 public const string PhysFunctGetLinkType = "BulletSim.GetLinkType";
67 public const string PhysFunctChangeLinkParams = "BulletSim.ChangeLinkParams";
68 public const string PhysFunctAxisLockLimits = "BulletSim.AxisLockLimits";
69
70 // =============================================================
71
72 private IConfig Configuration { get; set; }
73 private bool Enabled { get; set; }
74 private Scene BaseScene { get; set; }
75 private IScriptModuleComms Comms { get; set; }
76
77 #region INonSharedRegionModule
78
79 public string Name { get { return this.GetType().Name; } }
80
81 public void Initialise(IConfigSource config)
82 {
83 BaseScene = null;
84 Enabled = false;
85 Configuration = null;
86 Comms = null;
87
88 try
89 {
90 if ((Configuration = config.Configs["ExtendedPhysics"]) != null)
91 {
92 Enabled = Configuration.GetBoolean("Enabled", Enabled);
93 }
94 }
95 catch (Exception e)
96 {
97 m_log.ErrorFormat("{0} Initialization error: {0}", LogHeader, e);
98 }
99
100 m_log.InfoFormat("{0} module {1} enabled", LogHeader, (Enabled ? "is" : "is not"));
101 }
102
103 public void Close()
104 {
105 if (BaseScene != null)
106 {
107 BaseScene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene;
108 BaseScene.EventManager.OnSceneObjectPartUpdated -= EventManager_OnSceneObjectPartUpdated;
109 BaseScene = null;
110 }
111 }
112
113 public void AddRegion(Scene scene)
114 {
115 }
116
117 public void RemoveRegion(Scene scene)
118 {
119 if (BaseScene != null && BaseScene == scene)
120 {
121 Close();
122 }
123 }
124
125 public void RegionLoaded(Scene scene)
126 {
127 if (!Enabled) return;
128
129 BaseScene = scene;
130
131 Comms = BaseScene.RequestModuleInterface<IScriptModuleComms>();
132 if (Comms == null)
133 {
134 m_log.WarnFormat("{0} ScriptModuleComms interface not defined", LogHeader);
135 Enabled = false;
136
137 return;
138 }
139
140 // Register as LSL functions all the [ScriptInvocation] marked methods.
141 Comms.RegisterScriptInvocations(this);
142 Comms.RegisterConstants(this);
143
144 // When an object is modified, we might need to update its extended physics parameters
145 BaseScene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene;
146 BaseScene.EventManager.OnSceneObjectPartUpdated += EventManager_OnSceneObjectPartUpdated;
147
148 }
149
150 public Type ReplaceableInterface { get { return null; } }
151
152 #endregion // INonSharedRegionModule
153
154 private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj)
155 {
156 }
157
158 // Event generated when some property of a prim changes.
159 private void EventManager_OnSceneObjectPartUpdated(SceneObjectPart sop, bool isFullUpdate)
160 {
161 }
162
163 [ScriptConstant]
164 public const int PHYS_CENTER_OF_MASS = 1 << 0;
165
166 [ScriptInvocation]
167 public string physGetEngineType(UUID hostID, UUID scriptID)
168 {
169 string ret = string.Empty;
170
171 if (BaseScene.PhysicsScene != null)
172 {
173 ret = BaseScene.PhysicsScene.EngineType;
174 }
175
176 return ret;
177 }
178
179 // Code for specifying params.
180 // The choice if 14700 is arbitrary and only serves to catch parameter code misuse.
181 [ScriptConstant]
182 public const int PHYS_AXIS_LOCK_LINEAR = 14700;
183 [ScriptConstant]
184 public const int PHYS_AXIS_LOCK_LINEAR_X = 14701;
185 [ScriptConstant]
186 public const int PHYS_AXIS_LIMIT_LINEAR_X = 14702;
187 [ScriptConstant]
188 public const int PHYS_AXIS_LOCK_LINEAR_Y = 14703;
189 [ScriptConstant]
190 public const int PHYS_AXIS_LIMIT_LINEAR_Y = 14704;
191 [ScriptConstant]
192 public const int PHYS_AXIS_LOCK_LINEAR_Z = 14705;
193 [ScriptConstant]
194 public const int PHYS_AXIS_LIMIT_LINEAR_Z = 14706;
195 [ScriptConstant]
196 public const int PHYS_AXIS_LOCK_ANGULAR = 14707;
197 [ScriptConstant]
198 public const int PHYS_AXIS_LOCK_ANGULAR_X = 14708;
199 [ScriptConstant]
200 public const int PHYS_AXIS_LIMIT_ANGULAR_X = 14709;
201 [ScriptConstant]
202 public const int PHYS_AXIS_LOCK_ANGULAR_Y = 14710;
203 [ScriptConstant]
204 public const int PHYS_AXIS_LIMIT_ANGULAR_Y = 14711;
205 [ScriptConstant]
206 public const int PHYS_AXIS_LOCK_ANGULAR_Z = 14712;
207 [ScriptConstant]
208 public const int PHYS_AXIS_LIMIT_ANGULAR_Z = 14713;
209 [ScriptConstant]
210 public const int PHYS_AXIS_UNLOCK_LINEAR = 14714;
211 [ScriptConstant]
212 public const int PHYS_AXIS_UNLOCK_LINEAR_X = 14715;
213 [ScriptConstant]
214 public const int PHYS_AXIS_UNLOCK_LINEAR_Y = 14716;
215 [ScriptConstant]
216 public const int PHYS_AXIS_UNLOCK_LINEAR_Z = 14717;
217 [ScriptConstant]
218 public const int PHYS_AXIS_UNLOCK_ANGULAR = 14718;
219 [ScriptConstant]
220 public const int PHYS_AXIS_UNLOCK_ANGULAR_X = 14719;
221 [ScriptConstant]
222 public const int PHYS_AXIS_UNLOCK_ANGULAR_Y = 14720;
223 [ScriptConstant]
224 public const int PHYS_AXIS_UNLOCK_ANGULAR_Z = 14721;
225 [ScriptConstant]
226 public const int PHYS_AXIS_UNLOCK = 14722;
227 // physAxisLockLimits()
228 [ScriptInvocation]
229 public int physAxisLock(UUID hostID, UUID scriptID, object[] parms)
230 {
231 int ret = -1;
232 if (!Enabled) return ret;
233
234 PhysicsActor rootPhysActor;
235 if (GetRootPhysActor(hostID, out rootPhysActor))
236 {
237 object[] parms2 = AddToBeginningOfArray(rootPhysActor, null, parms);
238 ret = MakeIntError(rootPhysActor.Extension(PhysFunctAxisLockLimits, parms2));
239 }
240
241 return ret;
242 }
243
244 [ScriptConstant]
245 public const int PHYS_LINKSET_TYPE_CONSTRAINT = 0;
246 [ScriptConstant]
247 public const int PHYS_LINKSET_TYPE_COMPOUND = 1;
248 [ScriptConstant]
249 public const int PHYS_LINKSET_TYPE_MANUAL = 2;
250
251 [ScriptInvocation]
252 public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType)
253 {
254 int ret = -1;
255 if (!Enabled) return ret;
256
257 // The part that is requesting the change.
258 SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID);
259
260 if (requestingPart != null)
261 {
262 // The change is always made to the root of a linkset.
263 SceneObjectGroup containingGroup = requestingPart.ParentGroup;
264 SceneObjectPart rootPart = containingGroup.RootPart;
265
266 if (rootPart != null)
267 {
268 PhysicsActor rootPhysActor = rootPart.PhysActor;
269 if (rootPhysActor != null)
270 {
271 if (rootPhysActor.IsPhysical)
272 {
273 // Change a physical linkset by making non-physical, waiting for one heartbeat so all
274 // the prim and linkset state is updated, changing the type and making the
275 // linkset physical again.
276 containingGroup.ScriptSetPhysicsStatus(false);
277 Thread.Sleep(150); // longer than one heartbeat tick
278
279 // A kludge for the moment.
280 // Since compound linksets move the children but don't generate position updates to the
281 // simulator, it is possible for compound linkset children to have out-of-sync simulator
282 // and physical positions. The following causes the simulator to push the real child positions
283 // down into the physics engine to get everything synced.
284 containingGroup.UpdateGroupPosition(containingGroup.AbsolutePosition);
285 containingGroup.UpdateGroupRotationR(containingGroup.GroupRotation);
286
287 object[] parms2 = { rootPhysActor, null, linksetType };
288 ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2));
289 Thread.Sleep(150); // longer than one heartbeat tick
290
291 containingGroup.ScriptSetPhysicsStatus(true);
292 }
293 else
294 {
295 // Non-physical linksets don't have a physical instantiation so there is no state to
296 // worry about being updated.
297 object[] parms2 = { rootPhysActor, null, linksetType };
298 ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2));
299 }
300 }
301 else
302 {
303 m_log.WarnFormat("{0} physSetLinksetType: root part does not have a physics actor. rootName={1}, hostID={2}",
304 LogHeader, rootPart.Name, hostID);
305 }
306 }
307 else
308 {
309 m_log.WarnFormat("{0} physSetLinksetType: root part does not exist. RequestingPartName={1}, hostID={2}",
310 LogHeader, requestingPart.Name, hostID);
311 }
312 }
313 else
314 {
315 m_log.WarnFormat("{0} physSetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID);
316 }
317 return ret;
318 }
319
320 [ScriptInvocation]
321 public int physGetLinksetType(UUID hostID, UUID scriptID)
322 {
323 int ret = -1;
324 if (!Enabled) return ret;
325
326 PhysicsActor rootPhysActor;
327 if (GetRootPhysActor(hostID, out rootPhysActor))
328 {
329 object[] parms2 = { rootPhysActor, null };
330 ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType, parms2));
331 }
332 else
333 {
334 m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID);
335 }
336 return ret;
337 }
338
339 [ScriptConstant]
340 public const int PHYS_LINK_TYPE_FIXED = 1234;
341 [ScriptConstant]
342 public const int PHYS_LINK_TYPE_HINGE = 4;
343 [ScriptConstant]
344 public const int PHYS_LINK_TYPE_SPRING = 9;
345 [ScriptConstant]
346 public const int PHYS_LINK_TYPE_6DOF = 6;
347 [ScriptConstant]
348 public const int PHYS_LINK_TYPE_SLIDER = 7;
349
350 // physChangeLinkType(integer linkNum, integer typeCode)
351 [ScriptInvocation]
352 public int physChangeLinkType(UUID hostID, UUID scriptID, int linkNum, int typeCode)
353 {
354 int ret = -1;
355 if (!Enabled) return ret;
356
357 PhysicsActor rootPhysActor;
358 PhysicsActor childPhysActor;
359
360 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
361 {
362 object[] parms2 = { rootPhysActor, childPhysActor, typeCode };
363 ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2));
364 }
365
366 return ret;
367 }
368
369 // physGetLinkType(integer linkNum)
370 [ScriptInvocation]
371 public int physGetLinkType(UUID hostID, UUID scriptID, int linkNum)
372 {
373 int ret = -1;
374 if (!Enabled) return ret;
375
376 PhysicsActor rootPhysActor;
377 PhysicsActor childPhysActor;
378
379 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
380 {
381 object[] parms2 = { rootPhysActor, childPhysActor };
382 ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, parms2));
383 }
384
385 return ret;
386 }
387
388 // physChangeLinkFixed(integer linkNum)
389 // Change the link between the root and the linkNum into a fixed, static physical connection.
390 [ScriptInvocation]
391 public int physChangeLinkFixed(UUID hostID, UUID scriptID, int linkNum)
392 {
393 int ret = -1;
394 if (!Enabled) return ret;
395
396 PhysicsActor rootPhysActor;
397 PhysicsActor childPhysActor;
398
399 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
400 {
401 object[] parms2 = { rootPhysActor, childPhysActor , PHYS_LINK_TYPE_FIXED };
402 ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2));
403 }
404
405 return ret;
406 }
407
408 // Code for specifying params.
409 // The choice if 14400 is arbitrary and only serves to catch parameter code misuse.
410 public const int PHYS_PARAM_MIN = 14401;
411
412 [ScriptConstant]
413 public const int PHYS_PARAM_FRAMEINA_LOC = 14401;
414 [ScriptConstant]
415 public const int PHYS_PARAM_FRAMEINA_ROT = 14402;
416 [ScriptConstant]
417 public const int PHYS_PARAM_FRAMEINB_LOC = 14403;
418 [ScriptConstant]
419 public const int PHYS_PARAM_FRAMEINB_ROT = 14404;
420 [ScriptConstant]
421 public const int PHYS_PARAM_LINEAR_LIMIT_LOW = 14405;
422 [ScriptConstant]
423 public const int PHYS_PARAM_LINEAR_LIMIT_HIGH = 14406;
424 [ScriptConstant]
425 public const int PHYS_PARAM_ANGULAR_LIMIT_LOW = 14407;
426 [ScriptConstant]
427 public const int PHYS_PARAM_ANGULAR_LIMIT_HIGH = 14408;
428 [ScriptConstant]
429 public const int PHYS_PARAM_USE_FRAME_OFFSET = 14409;
430 [ScriptConstant]
431 public const int PHYS_PARAM_ENABLE_TRANSMOTOR = 14410;
432 [ScriptConstant]
433 public const int PHYS_PARAM_TRANSMOTOR_MAXVEL = 14411;
434 [ScriptConstant]
435 public const int PHYS_PARAM_TRANSMOTOR_MAXFORCE = 14412;
436 [ScriptConstant]
437 public const int PHYS_PARAM_CFM = 14413;
438 [ScriptConstant]
439 public const int PHYS_PARAM_ERP = 14414;
440 [ScriptConstant]
441 public const int PHYS_PARAM_SOLVER_ITERATIONS = 14415;
442 [ScriptConstant]
443 public const int PHYS_PARAM_SPRING_AXIS_ENABLE = 14416;
444 [ScriptConstant]
445 public const int PHYS_PARAM_SPRING_DAMPING = 14417;
446 [ScriptConstant]
447 public const int PHYS_PARAM_SPRING_STIFFNESS = 14418;
448 [ScriptConstant]
449 public const int PHYS_PARAM_LINK_TYPE = 14419;
450 [ScriptConstant]
451 public const int PHYS_PARAM_USE_LINEAR_FRAMEA = 14420;
452 [ScriptConstant]
453 public const int PHYS_PARAM_SPRING_EQUILIBRIUM_POINT = 14421;
454
455 public const int PHYS_PARAM_MAX = 14421;
456
457 // Used when specifying a parameter that has settings for the three linear and three angular axis
458 [ScriptConstant]
459 public const int PHYS_AXIS_ALL = -1;
460 [ScriptConstant]
461 public const int PHYS_AXIS_LINEAR_ALL = -2;
462 [ScriptConstant]
463 public const int PHYS_AXIS_ANGULAR_ALL = -3;
464 [ScriptConstant]
465 public const int PHYS_AXIS_LINEAR_X = 0;
466 [ScriptConstant]
467 public const int PHYS_AXIS_LINEAR_Y = 1;
468 [ScriptConstant]
469 public const int PHYS_AXIS_LINEAR_Z = 2;
470 [ScriptConstant]
471 public const int PHYS_AXIS_ANGULAR_X = 3;
472 [ScriptConstant]
473 public const int PHYS_AXIS_ANGULAR_Y = 4;
474 [ScriptConstant]
475 public const int PHYS_AXIS_ANGULAR_Z = 5;
476
477 // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...])
478 [ScriptInvocation]
479 public int physChangeLinkParams(UUID hostID, UUID scriptID, int linkNum, object[] parms)
480 {
481 int ret = -1;
482 if (!Enabled) return ret;
483
484 PhysicsActor rootPhysActor;
485 PhysicsActor childPhysActor;
486
487 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
488 {
489 object[] parms2 = AddToBeginningOfArray(rootPhysActor, childPhysActor, parms);
490 ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, parms2));
491 }
492
493 return ret;
494 }
495
496 private bool GetRootPhysActor(UUID hostID, out PhysicsActor rootPhysActor)
497 {
498 SceneObjectGroup containingGroup;
499 SceneObjectPart rootPart;
500 return GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor);
501 }
502
503 private bool GetRootPhysActor(UUID hostID, out SceneObjectGroup containingGroup, out SceneObjectPart rootPart, out PhysicsActor rootPhysActor)
504 {
505 bool ret = false;
506 rootPhysActor = null;
507 containingGroup = null;
508 rootPart = null;
509
510 SceneObjectPart requestingPart;
511
512 requestingPart = BaseScene.GetSceneObjectPart(hostID);
513 if (requestingPart != null)
514 {
515 // The type is is always on the root of a linkset.
516 containingGroup = requestingPart.ParentGroup;
517 if (containingGroup != null && !containingGroup.IsDeleted)
518 {
519 rootPart = containingGroup.RootPart;
520 if (rootPart != null)
521 {
522 rootPhysActor = rootPart.PhysActor;
523 if (rootPhysActor != null)
524 {
525 ret = true;
526 }
527 else
528 {
529 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}",
530 LogHeader, rootPart.Name, hostID);
531 }
532 }
533 else
534 {
535 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not exist. RequestingPartName={1}, hostID={2}",
536 LogHeader, requestingPart.Name, hostID);
537 }
538 }
539 else
540 {
541 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Containing group missing or deleted. hostID={1}", LogHeader, hostID);
542 }
543 }
544 else
545 {
546 m_log.WarnFormat("{0} GetRootAndChildPhysActors: cannot find script object in scene. hostID={1}", LogHeader, hostID);
547 }
548
549 return ret;
550 }
551
552 // Find the root and child PhysActors based on the linkNum.
553 // Return 'true' if both are found and returned.
554 private bool GetRootAndChildPhysActors(UUID hostID, int linkNum, out PhysicsActor rootPhysActor, out PhysicsActor childPhysActor)
555 {
556 bool ret = false;
557 rootPhysActor = null;
558 childPhysActor = null;
559
560 SceneObjectGroup containingGroup;
561 SceneObjectPart rootPart;
562
563 if (GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor))
564 {
565 SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum);
566 if (linkPart != null)
567 {
568 childPhysActor = linkPart.PhysActor;
569 if (childPhysActor != null)
570 {
571 ret = true;
572 }
573 else
574 {
575 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}",
576 LogHeader, rootPart.Name, hostID, linkNum);
577 }
578 }
579 else
580 {
581 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}",
582 LogHeader, rootPart.Name, hostID, linkNum);
583 }
584 }
585 else
586 {
587 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}",
588 LogHeader, rootPart.Name, hostID);
589 }
590
591 return ret;
592 }
593
594 // Return an array of objects with the passed object as the first object of a new array
595 private object[] AddToBeginningOfArray(object firstOne, object secondOne, object[] prevArray)
596 {
597 object[] newArray = new object[2 + prevArray.Length];
598 newArray[0] = firstOne;
599 newArray[1] = secondOne;
600 prevArray.CopyTo(newArray, 2);
601 return newArray;
602 }
603
604 // Extension() returns an object. Convert that object into the integer error we expect to return.
605 private int MakeIntError(object extensionRet)
606 {
607 int ret = -1;
608 if (extensionRet != null)
609 {
610 try
611 {
612 ret = (int)extensionRet;
613 }
614 catch
615 {
616 ret = -1;
617 }
618 }
619 return ret;
620 }
621 }
622}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..698be39
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4using Mono.Addins;
5
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Region.Physics.BulletSPlugin")]
10[assembly: AssemblyDescription("")]
11[assembly: AssemblyConfiguration("")]
12[assembly: AssemblyCompany("http://opensimulator.org")]
13[assembly: AssemblyProduct("OpenSim")]
14[assembly: AssemblyCopyright("OpenSimulator developers")]
15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")]
17
18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)]
22
23// The following GUID is for the ID of the typelib if this project is exposed to COM
24[assembly: Guid("520ea11b-20cb-449d-ba05-c01015fed841")]
25
26// Version information for an assembly consists of the following four values:
27//
28// Major Version
29// Minor Version
30// Build Number
31// Revision
32//
33[assembly: AssemblyVersion("0.8.3.*")]
34
35[assembly: Addin("OpenSim.Region.PhysicsModule.BulletS", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs
new file mode 100755
index 0000000..35eba29
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs
@@ -0,0 +1,156 @@
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.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Framework;
37using OpenSim.Region.PhysicsModule.BulletS;
38using OpenSim.Region.PhysicsModules.SharedBase;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.PhysicsModule.BulletS.Tests
44{
45[TestFixture]
46public class BasicVehicles : OpenSimTestCase
47{
48 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
49 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
50
51 BSScene PhysicsScene { get; set; }
52 BSPrim TestVehicle { get; set; }
53 Vector3 TestVehicleInitPosition { get; set; }
54 float simulationTimeStep = 0.089f;
55
56 [TestFixtureSetUp]
57 public void Init()
58 {
59 Dictionary<string, string> engineParams = new Dictionary<string, string>();
60 engineParams.Add("VehicleEnableAngularVerticalAttraction", "true");
61 engineParams.Add("VehicleAngularVerticalAttractionAlgorithm", "1");
62 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
63
64 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere();
65 Vector3 pos = new Vector3(100.0f, 100.0f, 0f);
66 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f;
67 TestVehicleInitPosition = pos;
68 Vector3 size = new Vector3(1f, 1f, 1f);
69 pbs.Scale = size;
70 Quaternion rot = Quaternion.Identity;
71 bool isPhys = false;
72 uint localID = 123;
73
74 PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID);
75 TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID];
76 // The actual prim shape creation happens at taint time
77 PhysicsScene.ProcessTaints();
78
79 }
80
81 [TestFixtureTearDown]
82 public void TearDown()
83 {
84 if (PhysicsScene != null)
85 {
86 // The Dispose() will also free any physical objects in the scene
87 PhysicsScene.Dispose();
88 PhysicsScene = null;
89 }
90 }
91
92 [TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)]
93 [TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)]
94 [TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)]
95 [TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)]
96 // [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */]
97 // [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */]
98 // [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */]
99 // [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */]
100 // [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */]
101 // [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */]
102 // [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */]
103 // [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */]
104 public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw)
105 {
106 // Enough simulation steps to cover the timescale the operation should take
107 int simSteps = (int)(timeScale / simulationTimeStep) + 1;
108
109 // Tip the vehicle
110 Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw);
111 TestVehicle.Orientation = initOrientation;
112
113 TestVehicle.Position = TestVehicleInitPosition;
114
115 // The vehicle controller is not enabled directly (by setting a vehicle type).
116 // Instead the appropriate values are set and calls are made just the parts of the
117 // controller we want to exercise. Stepping the physics engine then applies
118 // the actions of that one feature.
119 BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */);
120 if (vehicleActor != null)
121 {
122 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
123 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale);
124 // vehicleActor.enableAngularVerticalAttraction = true;
125
126 TestVehicle.IsPhysical = true;
127 PhysicsScene.ProcessTaints();
128
129 // Step the simulator a bunch of times and vertical attraction should orient the vehicle up
130 for (int ii = 0; ii < simSteps; ii++)
131 {
132 vehicleActor.ForgetKnownVehicleProperties();
133 vehicleActor.ComputeAngularVerticalAttraction();
134 vehicleActor.PushKnownChanged();
135
136 PhysicsScene.Simulate(simulationTimeStep);
137 }
138 }
139
140 TestVehicle.IsPhysical = false;
141 PhysicsScene.ProcessTaints();
142
143 // After these steps, the vehicle should be upright
144 /*
145 float finalRoll, finalPitch, finalYaw;
146 TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw);
147 Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f));
148 Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f));
149 Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f));
150 */
151
152 Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation;
153 Assert.That(upPointer.Z, Is.GreaterThan(0.99f));
154 }
155}
156} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs
new file mode 100755
index 0000000..0be1f4c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs
@@ -0,0 +1,56 @@
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.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Tests.Common;
37
38namespace OpenSim.Region.PhysicsModule.BulletS.Tests
39{
40[TestFixture]
41public class BulletSimTests : OpenSimTestCase
42{
43 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
44 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
45
46 [TestFixtureSetUp]
47 public void Init()
48 {
49 }
50
51 [TestFixtureTearDown]
52 public void TearDown()
53 {
54 }
55}
56}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs
new file mode 100755
index 0000000..4eeea4d
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs
@@ -0,0 +1,109 @@
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.IO;
30using System.Collections.Generic;
31using System.Text;
32
33using Nini.Config;
34
35using OpenSim.Framework;
36using OpenSim.Region.PhysicsModules.SharedBase;
37using OpenSim.Region.PhysicsModules.Meshing;
38using OpenSim.Region.Framework.Interfaces;
39
40using OpenMetaverse;
41
42namespace OpenSim.Region.PhysicsModule.BulletS.Tests
43{
44// Utility functions for building up and tearing down the sample physics environments
45public static class BulletSimTestsUtil
46{
47 // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA"
48 // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults)
49 // May be 'null' if there are no overrides.
50 public static BSScene CreateBasicPhysicsEngine(Dictionary<string,string> paramOverrides)
51 {
52 IConfigSource openSimINI = new IniConfigSource();
53 IConfig startupConfig = openSimINI.AddConfig("Startup");
54 startupConfig.Set("physics", "BulletSim");
55 startupConfig.Set("meshing", "Meshmerizer");
56 startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps
57
58 IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim");
59 // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged".
60 // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged");
61 // bulletSimConfig.Set("BulletEngine", "BulletXNA");
62 bulletSimConfig.Set("MeshSculptedPrim", "false");
63 bulletSimConfig.Set("ForceSimplePrimMeshing", "true");
64 if (paramOverrides != null)
65 {
66 foreach (KeyValuePair<string, string> kvp in paramOverrides)
67 {
68 bulletSimConfig.Set(kvp.Key, kvp.Value);
69 }
70 }
71
72 // If a special directory exists, put detailed logging therein.
73 // This allows local testing/debugging without having to worry that the build engine will output logs.
74 if (Directory.Exists("physlogs"))
75 {
76 bulletSimConfig.Set("PhysicsLoggingDir","./physlogs");
77 bulletSimConfig.Set("PhysicsLoggingEnabled","True");
78 bulletSimConfig.Set("PhysicsLoggingDoFlush","True");
79 bulletSimConfig.Set("VehicleLoggingEnabled","True");
80 }
81
82 Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
83
84 RegionInfo info = new RegionInfo();
85 info.RegionName = "BSTestRegion";
86 info.RegionSizeX = info.RegionSizeY = info.RegionSizeZ = Constants.RegionSize;
87 OpenSim.Region.Framework.Scenes.Scene scene = new OpenSim.Region.Framework.Scenes.Scene(info);
88
89 IMesher mesher = new OpenSim.Region.PhysicsModules.Meshing.Meshmerizer();
90 INonSharedRegionModule mod = mesher as INonSharedRegionModule;
91 mod.Initialise(openSimINI);
92 mod.AddRegion(scene);
93 mod.RegionLoaded(scene);
94
95 BSScene pScene = new BSScene();
96 mod = (pScene as INonSharedRegionModule);
97 mod.Initialise(openSimINI);
98 mod.AddRegion(scene);
99 mod.RegionLoaded(scene);
100
101 // Since the asset requestor is not initialized, any mesh or sculptie will be a cube.
102 // In the future, add a fake asset fetcher to get meshes and sculpts.
103 // bsScene.RequestAssetMethod = ???;
104
105 return pScene;
106 }
107
108}
109}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs
new file mode 100644
index 0000000..c0cf19a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs
@@ -0,0 +1,205 @@
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.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Framework;
37using OpenSim.Region.PhysicsModule.BulletS;
38using OpenSim.Region.PhysicsModules.SharedBase;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.PhysicsModule.BulletS.Tests
44{
45[TestFixture]
46public class HullCreation : OpenSimTestCase
47{
48 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
49 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
50
51 BSScene PhysicsScene { get; set; }
52 Vector3 ObjectInitPosition;
53
54 [TestFixtureSetUp]
55 public void Init()
56 {
57
58 }
59
60 [TestFixtureTearDown]
61 public void TearDown()
62 {
63 if (PhysicsScene != null)
64 {
65 // The Dispose() will also free any physical objects in the scene
66 PhysicsScene.Dispose();
67 PhysicsScene = null;
68 }
69 }
70
71 [TestCase(7, 2, 5f, 5f, 32, 0f)] /* default hull parameters */
72 public void GeomHullConvexDecomp( int maxDepthSplit,
73 int maxDepthSplitForSimpleShapes,
74 float concavityThresholdPercent,
75 float volumeConservationThresholdPercent,
76 int maxVertices,
77 float maxSkinWidth)
78 {
79 // Setup the physics engine to use the C# version of convex decomp
80 Dictionary<string, string> engineParams = new Dictionary<string, string>();
81 engineParams.Add("MeshSculptedPrim", "true"); // ShouldMeshSculptedPrim
82 engineParams.Add("ForceSimplePrimMeshing", "false"); // ShouldForceSimplePrimMeshing
83 engineParams.Add("UseHullsForPhysicalObjects", "true"); // ShouldUseHullsForPhysicalObjects
84 engineParams.Add("ShouldRemoveZeroWidthTriangles", "true");
85 engineParams.Add("ShouldUseBulletHACD", "false");
86 engineParams.Add("ShouldUseSingleConvexHullForPrims", "true");
87 engineParams.Add("ShouldUseGImpactShapeForPrims", "false");
88 engineParams.Add("ShouldUseAssetHulls", "true");
89
90 engineParams.Add("CSHullMaxDepthSplit", maxDepthSplit.ToString());
91 engineParams.Add("CSHullMaxDepthSplitForSimpleShapes", maxDepthSplitForSimpleShapes.ToString());
92 engineParams.Add("CSHullConcavityThresholdPercent", concavityThresholdPercent.ToString());
93 engineParams.Add("CSHullVolumeConservationThresholdPercent", volumeConservationThresholdPercent.ToString());
94 engineParams.Add("CSHullMaxVertices", maxVertices.ToString());
95 engineParams.Add("CSHullMaxSkinWidth", maxSkinWidth.ToString());
96
97 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
98
99 PrimitiveBaseShape pbs;
100 Vector3 pos;
101 Vector3 size;
102 Quaternion rot;
103 bool isPhys;
104
105 // Cylinder
106 pbs = PrimitiveBaseShape.CreateCylinder();
107 pos = new Vector3(100.0f, 100.0f, 0f);
108 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f;
109 ObjectInitPosition = pos;
110 size = new Vector3(2f, 2f, 2f);
111 pbs.Scale = size;
112 rot = Quaternion.Identity;
113 isPhys = true;
114 uint cylinderLocalID = 123;
115 PhysicsScene.AddPrimShape("testCylinder", pbs, pos, size, rot, isPhys, cylinderLocalID);
116 BSPrim primTypeCylinder = (BSPrim)PhysicsScene.PhysObjects[cylinderLocalID];
117
118 // Hollow Cylinder
119 pbs = PrimitiveBaseShape.CreateCylinder();
120 pbs.ProfileHollow = (ushort)(0.70f * 50000);
121 pos = new Vector3(110.0f, 110.0f, 0f);
122 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f;
123 ObjectInitPosition = pos;
124 size = new Vector3(2f, 2f, 2f);
125 pbs.Scale = size;
126 rot = Quaternion.Identity;
127 isPhys = true;
128 uint hollowCylinderLocalID = 124;
129 PhysicsScene.AddPrimShape("testHollowCylinder", pbs, pos, size, rot, isPhys, hollowCylinderLocalID);
130 BSPrim primTypeHollowCylinder = (BSPrim)PhysicsScene.PhysObjects[hollowCylinderLocalID];
131
132 // Torus
133 // ProfileCurve = Circle, PathCurve = Curve1
134 pbs = PrimitiveBaseShape.CreateSphere();
135 pbs.ProfileShape = (byte)ProfileShape.Circle;
136 pbs.PathCurve = (byte)Extrusion.Curve1;
137 pbs.PathScaleX = 100; // default hollow info as set in the viewer
138 pbs.PathScaleY = (int)(.25f / 0.01f) + 200;
139 pos = new Vector3(120.0f, 120.0f, 0f);
140 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f;
141 ObjectInitPosition = pos;
142 size = new Vector3(2f, 4f, 4f);
143 pbs.Scale = size;
144 rot = Quaternion.Identity;
145 isPhys = true;
146 uint torusLocalID = 125;
147 PhysicsScene.AddPrimShape("testTorus", pbs, pos, size, rot, isPhys, torusLocalID);
148 BSPrim primTypeTorus = (BSPrim)PhysicsScene.PhysObjects[torusLocalID];
149
150 // The actual prim shape creation happens at taint time
151 PhysicsScene.ProcessTaints();
152
153 // Check out the created hull shapes and report their characteristics
154 ReportShapeGeom(primTypeCylinder);
155 ReportShapeGeom(primTypeHollowCylinder);
156 ReportShapeGeom(primTypeTorus);
157 }
158
159 [TestCase]
160 public void GeomHullBulletHACD()
161 {
162 // Cylinder
163 // Hollow Cylinder
164 // Torus
165 }
166
167 private void ReportShapeGeom(BSPrim prim)
168 {
169 if (prim != null)
170 {
171 if (prim.PhysShape.HasPhysicalShape)
172 {
173 BSShape physShape = prim.PhysShape;
174 string shapeType = physShape.GetType().ToString();
175 switch (shapeType)
176 {
177 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeNative":
178 BSShapeNative nShape = physShape as BSShapeNative;
179 prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType);
180 break;
181 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeMesh":
182 BSShapeMesh mShape = physShape as BSShapeMesh;
183 prim.PhysScene.DetailLog("{0}, mesh, shapeInfo={1}", prim.Name, mShape.shapeInfo);
184 break;
185 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeHull":
186 // BSShapeHull hShape = physShape as BSShapeHull;
187 // prim.PhysScene.DetailLog("{0}, hull, shapeInfo={1}", prim.Name, hShape.shapeInfo);
188 break;
189 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeConvexHull":
190 BSShapeConvexHull chShape = physShape as BSShapeConvexHull;
191 prim.PhysScene.DetailLog("{0}, convexHull, shapeInfo={1}", prim.Name, chShape.shapeInfo);
192 break;
193 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeCompound":
194 BSShapeCompound cShape = physShape as BSShapeCompound;
195 prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType);
196 break;
197 default:
198 prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType);
199 break;
200 }
201 }
202 }
203 }
204}
205} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/CTri.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/CTri.cs
new file mode 100644
index 0000000..7ad689e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/CTri.cs
@@ -0,0 +1,341 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs
new file mode 100644
index 0000000..4140d25
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs
@@ -0,0 +1,233 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs
new file mode 100644
index 0000000..70c3a2b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs
@@ -0,0 +1,411 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs
new file mode 100644
index 0000000..5046bce
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs
@@ -0,0 +1,200 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs
new file mode 100644
index 0000000..44e3e50
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs
@@ -0,0 +1,74 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs
new file mode 100644
index 0000000..8a0164e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs
@@ -0,0 +1,171 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs
new file mode 100644
index 0000000..d3f0052
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs
@@ -0,0 +1,99 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs
new file mode 100644
index 0000000..3903254
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs
@@ -0,0 +1,1868 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/LICENSE.txt b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/LICENSE.txt
new file mode 100644
index 0000000..714ae89
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/LICENSE.txt
@@ -0,0 +1,28 @@
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/PhysicsModules/ConvexDecompositionDotNet/Plane.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Plane.cs
new file mode 100644
index 0000000..da9ae0c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Plane.cs
@@ -0,0 +1,99 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs
new file mode 100644
index 0000000..42f7a22
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs
@@ -0,0 +1,211 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..b9cd6f5
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
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.8.3.*")]
36
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs
new file mode 100644
index 0000000..045f620
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs
@@ -0,0 +1,209 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/README.txt b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/README.txt
new file mode 100644
index 0000000..fc53ae7
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/README.txt
@@ -0,0 +1,7 @@
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/PhysicsModules/ConvexDecompositionDotNet/SplitPlane.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/SplitPlane.cs
new file mode 100644
index 0000000..9f56bc5
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/SplitPlane.cs
@@ -0,0 +1,265 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs
new file mode 100644
index 0000000..bfe11e5
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs
@@ -0,0 +1,70 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/float2.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs
new file mode 100644
index 0000000..e7358c1
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs
@@ -0,0 +1,70 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/float3.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs
new file mode 100644
index 0000000..fde9b32
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs
@@ -0,0 +1,444 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs
new file mode 100644
index 0000000..c420fde
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs
@@ -0,0 +1,195 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/float4.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs
new file mode 100644
index 0000000..b2b6fd3
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs
@@ -0,0 +1,170 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs
new file mode 100644
index 0000000..087eba7
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs
@@ -0,0 +1,284 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/int3.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs
new file mode 100644
index 0000000..90624eb
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs
@@ -0,0 +1,128 @@
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.PhysicsModule.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/PhysicsModules/ConvexDecompositionDotNet/int4.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs
new file mode 100644
index 0000000..e9320c0
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs
@@ -0,0 +1,66 @@
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.PhysicsModule.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/PhysicsModules/Meshing/Meshmerizer/HelperTypes.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/HelperTypes.cs
new file mode 100644
index 0000000..34a925d
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/HelperTypes.cs
@@ -0,0 +1,436 @@
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.PhysicsModules.SharedBase;
34using OpenSim.Region.PhysicsModules.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/PhysicsModules/Meshing/Meshmerizer/Mesh.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs
new file mode 100644
index 0000000..bf397ee
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Mesh.cs
@@ -0,0 +1,333 @@
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.PhysicsModules.SharedBase;
33using PrimMesher;
34using OpenMetaverse;
35
36namespace OpenSim.Region.PhysicsModules.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 public 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/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs
new file mode 100644
index 0000000..4d25bf3
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/Meshmerizer.cs
@@ -0,0 +1,1010 @@
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 System.Reflection;
32using System.IO;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Scenes;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.PhysicsModules.SharedBase;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39using System.Drawing;
40using System.Drawing.Imaging;
41using System.IO.Compression;
42using PrimMesher;
43using log4net;
44using Nini.Config;
45using Mono.Addins;
46
47namespace OpenSim.Region.PhysicsModules.Meshing
48{
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "Meshmerizer")]
50 public class Meshmerizer : IMesher, INonSharedRegionModule
51 {
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 private static string LogHeader = "[MESH]";
54
55 // Setting baseDir to a path will enable the dumping of raw files
56 // raw files can be imported by blender so a visual inspection of the results can be done
57#if SPAM
58 const string baseDir = "rawFiles";
59#else
60 private const string baseDir = null; //"rawFiles";
61#endif
62 private bool m_Enabled = false;
63
64 // If 'true', lots of DEBUG logging of asset parsing details
65 private bool debugDetail = false;
66
67 private bool cacheSculptMaps = true;
68 private string decodedSculptMapPath = null;
69 private bool useMeshiesPhysicsMesh = false;
70
71 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
72
73 private List<List<Vector3>> mConvexHulls = null;
74 private List<Vector3> mBoundingHull = null;
75
76 // Mesh cache. Static so it can be shared across instances of this class
77 private static Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
78
79 #region INonSharedRegionModule
80 public string Name
81 {
82 get { return "Meshmerizer"; }
83 }
84
85 public Type ReplaceableInterface
86 {
87 get { return null; }
88 }
89
90 public void Initialise(IConfigSource source)
91 {
92 IConfig config = source.Configs["Startup"];
93 if (config != null)
94 {
95 string mesher = config.GetString("meshing", string.Empty);
96 if (mesher == Name)
97 {
98 m_Enabled = true;
99
100 IConfig mesh_config = source.Configs["Mesh"];
101
102 decodedSculptMapPath = config.GetString("DecodedSculptMapPath", "j2kDecodeCache");
103 cacheSculptMaps = config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
104 if (mesh_config != null)
105 {
106 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
107 debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail);
108 }
109
110 try
111 {
112 if (!Directory.Exists(decodedSculptMapPath))
113 Directory.CreateDirectory(decodedSculptMapPath);
114 }
115 catch (Exception e)
116 {
117 m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message);
118 }
119
120 }
121 }
122 }
123
124 public void Close()
125 {
126 }
127
128 public void AddRegion(Scene scene)
129 {
130 if (!m_Enabled)
131 return;
132
133 scene.RegisterModuleInterface<IMesher>(this);
134 }
135
136 public void RemoveRegion(Scene scene)
137 {
138 if (!m_Enabled)
139 return;
140
141 scene.UnregisterModuleInterface<IMesher>(this);
142 }
143
144 public void RegionLoaded(Scene scene)
145 {
146 if (!m_Enabled)
147 return;
148 }
149 #endregion
150
151
152 /// <summary>
153 /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may
154 /// be useful as a backup proxy when level of detail is not needed or when more complex meshes fail
155 /// for some reason
156 /// </summary>
157 /// <param name="minX"></param>
158 /// <param name="maxX"></param>
159 /// <param name="minY"></param>
160 /// <param name="maxY"></param>
161 /// <param name="minZ"></param>
162 /// <param name="maxZ"></param>
163 /// <returns></returns>
164 private static Mesh CreateSimpleBoxMesh(float minX, float maxX, float minY, float maxY, float minZ, float maxZ)
165 {
166 Mesh box = new Mesh();
167 List<Vertex> vertices = new List<Vertex>();
168 // bottom
169
170 vertices.Add(new Vertex(minX, maxY, minZ));
171 vertices.Add(new Vertex(maxX, maxY, minZ));
172 vertices.Add(new Vertex(maxX, minY, minZ));
173 vertices.Add(new Vertex(minX, minY, minZ));
174
175 box.Add(new Triangle(vertices[0], vertices[1], vertices[2]));
176 box.Add(new Triangle(vertices[0], vertices[2], vertices[3]));
177
178 // top
179
180 vertices.Add(new Vertex(maxX, maxY, maxZ));
181 vertices.Add(new Vertex(minX, maxY, maxZ));
182 vertices.Add(new Vertex(minX, minY, maxZ));
183 vertices.Add(new Vertex(maxX, minY, maxZ));
184
185 box.Add(new Triangle(vertices[4], vertices[5], vertices[6]));
186 box.Add(new Triangle(vertices[4], vertices[6], vertices[7]));
187
188 // sides
189
190 box.Add(new Triangle(vertices[5], vertices[0], vertices[3]));
191 box.Add(new Triangle(vertices[5], vertices[3], vertices[6]));
192
193 box.Add(new Triangle(vertices[1], vertices[0], vertices[5]));
194 box.Add(new Triangle(vertices[1], vertices[5], vertices[4]));
195
196 box.Add(new Triangle(vertices[7], vertices[1], vertices[4]));
197 box.Add(new Triangle(vertices[7], vertices[2], vertices[1]));
198
199 box.Add(new Triangle(vertices[3], vertices[2], vertices[7]));
200 box.Add(new Triangle(vertices[3], vertices[7], vertices[6]));
201
202 return box;
203 }
204
205 /// <summary>
206 /// Creates a simple bounding box mesh for a complex input mesh
207 /// </summary>
208 /// <param name="meshIn"></param>
209 /// <returns></returns>
210 private static Mesh CreateBoundingBoxMesh(Mesh meshIn)
211 {
212 float minX = float.MaxValue;
213 float maxX = float.MinValue;
214 float minY = float.MaxValue;
215 float maxY = float.MinValue;
216 float minZ = float.MaxValue;
217 float maxZ = float.MinValue;
218
219 foreach (Vector3 v in meshIn.getVertexList())
220 {
221 if (v.X < minX) minX = v.X;
222 if (v.Y < minY) minY = v.Y;
223 if (v.Z < minZ) minZ = v.Z;
224
225 if (v.X > maxX) maxX = v.X;
226 if (v.Y > maxY) maxY = v.Y;
227 if (v.Z > maxZ) maxZ = v.Z;
228 }
229
230 return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ);
231 }
232
233 private void ReportPrimError(string message, string primName, PrimMesh primMesh)
234 {
235 m_log.Error(message);
236 m_log.Error("\nPrim Name: " + primName);
237 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
238 }
239
240 /// <summary>
241 /// Add a submesh to an existing list of coords and faces.
242 /// </summary>
243 /// <param name="subMeshData"></param>
244 /// <param name="size">Size of entire object</param>
245 /// <param name="coords"></param>
246 /// <param name="faces"></param>
247 private void AddSubMesh(OSDMap subMeshData, Vector3 size, List<Coord> coords, List<Face> faces)
248 {
249 // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap));
250
251 // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level
252 // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no
253 // geometry for this submesh.
254 if (subMeshData.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshData["NoGeometry"]))
255 return;
256
257 OpenMetaverse.Vector3 posMax = ((OSDMap)subMeshData["PositionDomain"])["Max"].AsVector3();
258 OpenMetaverse.Vector3 posMin = ((OSDMap)subMeshData["PositionDomain"])["Min"].AsVector3();
259 ushort faceIndexOffset = (ushort)coords.Count;
260
261 byte[] posBytes = subMeshData["Position"].AsBinary();
262 for (int i = 0; i < posBytes.Length; i += 6)
263 {
264 ushort uX = Utils.BytesToUInt16(posBytes, i);
265 ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
266 ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
267
268 Coord c = new Coord(
269 Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X,
270 Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y,
271 Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z);
272
273 coords.Add(c);
274 }
275
276 byte[] triangleBytes = subMeshData["TriangleList"].AsBinary();
277 for (int i = 0; i < triangleBytes.Length; i += 6)
278 {
279 ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset);
280 ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset);
281 ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset);
282 Face f = new Face(v1, v2, v3);
283 faces.Add(f);
284 }
285 }
286
287 /// <summary>
288 /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type.
289 /// </summary>
290 /// <param name="primName"></param>
291 /// <param name="primShape"></param>
292 /// <param name="size"></param>
293 /// <param name="lod"></param>
294 /// <returns></returns>
295 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
296 {
297// m_log.DebugFormat(
298// "[MESH]: Creating physics proxy for {0}, shape {1}",
299// primName, (OpenMetaverse.SculptType)primShape.SculptType);
300
301 List<Coord> coords;
302 List<Face> faces;
303
304 if (primShape.SculptEntry)
305 {
306 if (((OpenMetaverse.SculptType)primShape.SculptType) == SculptType.Mesh)
307 {
308 if (!useMeshiesPhysicsMesh)
309 return null;
310
311 if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces))
312 return null;
313 }
314 else
315 {
316 if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces))
317 return null;
318 }
319 }
320 else
321 {
322 if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces))
323 return null;
324 }
325
326 // Remove the reference to any JPEG2000 sculpt data so it can be GCed
327 primShape.SculptData = Utils.EmptyBytes;
328
329 int numCoords = coords.Count;
330 int numFaces = faces.Count;
331
332 // Create the list of vertices
333 List<Vertex> vertices = new List<Vertex>();
334 for (int i = 0; i < numCoords; i++)
335 {
336 Coord c = coords[i];
337 vertices.Add(new Vertex(c.X, c.Y, c.Z));
338 }
339
340 Mesh mesh = new Mesh();
341 // Add the corresponding triangles to the mesh
342 for (int i = 0; i < numFaces; i++)
343 {
344 Face f = faces[i];
345 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
346 }
347
348 return mesh;
349 }
350
351 /// <summary>
352 /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim.
353 /// </summary>
354 /// <param name="primName"></param>
355 /// <param name="primShape"></param>
356 /// <param name="size"></param>
357 /// <param name="coords">Coords are added to this list by the method.</param>
358 /// <param name="faces">Faces are added to this list by the method.</param>
359 /// <returns>true if coords and faces were successfully generated, false if not</returns>
360 private bool GenerateCoordsAndFacesFromPrimMeshData(
361 string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces)
362 {
363// m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
364
365 coords = new List<Coord>();
366 faces = new List<Face>();
367 OSD meshOsd = null;
368
369 mConvexHulls = null;
370 mBoundingHull = null;
371
372 if (primShape.SculptData.Length <= 0)
373 {
374 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
375 // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
376 // The first time will always call with unloaded SculptData if this needs to be uploaded.
377// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
378 return false;
379 }
380
381 long start = 0;
382 using (MemoryStream data = new MemoryStream(primShape.SculptData))
383 {
384 try
385 {
386 OSD osd = OSDParser.DeserializeLLSDBinary(data);
387 if (osd is OSDMap)
388 meshOsd = (OSDMap)osd;
389 else
390 {
391 m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
392 return false;
393 }
394 }
395 catch (Exception e)
396 {
397 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
398 }
399
400 start = data.Position;
401 }
402
403 if (meshOsd is OSDMap)
404 {
405 OSDMap physicsParms = null;
406 OSDMap map = (OSDMap)meshOsd;
407 if (map.ContainsKey("physics_shape"))
408 {
409 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
410 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName);
411 }
412 else if (map.ContainsKey("physics_mesh"))
413 {
414 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
415 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName);
416 }
417 else if (map.ContainsKey("medium_lod"))
418 {
419 physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh
420 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName);
421 }
422 else if (map.ContainsKey("high_lod"))
423 {
424 physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :)
425 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName);
426 }
427
428 if (map.ContainsKey("physics_convex"))
429 { // pull this out also in case physics engine can use it
430 OSD convexBlockOsd = null;
431 try
432 {
433 OSDMap convexBlock = (OSDMap)map["physics_convex"];
434 {
435 int convexOffset = convexBlock["offset"].AsInteger() + (int)start;
436 int convexSize = convexBlock["size"].AsInteger();
437
438 byte[] convexBytes = new byte[convexSize];
439
440 System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize);
441
442 try
443 {
444 convexBlockOsd = DecompressOsd(convexBytes);
445 }
446 catch (Exception e)
447 {
448 m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e);
449 //return false;
450 }
451 }
452
453 if (convexBlockOsd != null && convexBlockOsd is OSDMap)
454 {
455 convexBlock = convexBlockOsd as OSDMap;
456
457 if (debugDetail)
458 {
459 string keys = LogHeader + " keys found in convexBlock: ";
460 foreach (KeyValuePair<string, OSD> kvp in convexBlock)
461 keys += "'" + kvp.Key + "' ";
462 m_log.Debug(keys);
463 }
464
465 Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f);
466 if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3();
467 Vector3 max = new Vector3(0.5f, 0.5f, 0.5f);
468 if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3();
469
470 List<Vector3> boundingHull = null;
471
472 if (convexBlock.ContainsKey("BoundingVerts"))
473 {
474 byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary();
475 boundingHull = new List<Vector3>();
476 for (int i = 0; i < boundingVertsBytes.Length; )
477 {
478 ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
479 ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
480 ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
481
482 Vector3 pos = new Vector3(
483 Utils.UInt16ToFloat(uX, min.X, max.X),
484 Utils.UInt16ToFloat(uY, min.Y, max.Y),
485 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
486 );
487
488 boundingHull.Add(pos);
489 }
490
491 mBoundingHull = boundingHull;
492 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count);
493 }
494
495 if (convexBlock.ContainsKey("HullList"))
496 {
497 byte[] hullList = convexBlock["HullList"].AsBinary();
498
499 byte[] posBytes = convexBlock["Positions"].AsBinary();
500
501 List<List<Vector3>> hulls = new List<List<Vector3>>();
502 int posNdx = 0;
503
504 foreach (byte cnt in hullList)
505 {
506 int count = cnt == 0 ? 256 : cnt;
507 List<Vector3> hull = new List<Vector3>();
508
509 for (int i = 0; i < count; i++)
510 {
511 ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
512 ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
513 ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
514
515 Vector3 pos = new Vector3(
516 Utils.UInt16ToFloat(uX, min.X, max.X),
517 Utils.UInt16ToFloat(uY, min.Y, max.Y),
518 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
519 );
520
521 hull.Add(pos);
522 }
523
524 hulls.Add(hull);
525 }
526
527 mConvexHulls = hulls;
528 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count);
529 }
530 else
531 {
532 if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName);
533 }
534 }
535 }
536 catch (Exception e)
537 {
538 m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e);
539 }
540 }
541
542 if (physicsParms == null)
543 {
544 m_log.WarnFormat("[MESH]: No recognized physics mesh found in mesh asset for {0}", primName);
545 return false;
546 }
547
548 int physOffset = physicsParms["offset"].AsInteger() + (int)start;
549 int physSize = physicsParms["size"].AsInteger();
550
551 if (physOffset < 0 || physSize == 0)
552 return false; // no mesh data in asset
553
554 OSD decodedMeshOsd = new OSD();
555 byte[] meshBytes = new byte[physSize];
556 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
557 // byte[] decompressed = new byte[physSize * 5];
558 try
559 {
560 decodedMeshOsd = DecompressOsd(meshBytes);
561 }
562 catch (Exception e)
563 {
564 m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e);
565 return false;
566 }
567
568 OSDArray decodedMeshOsdArray = null;
569
570 // physics_shape is an array of OSDMaps, one for each submesh
571 if (decodedMeshOsd is OSDArray)
572 {
573 // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
574
575 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
576 foreach (OSD subMeshOsd in decodedMeshOsdArray)
577 {
578 if (subMeshOsd is OSDMap)
579 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
580 }
581 if (debugDetail)
582 m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}",
583 LogHeader, primName, physOffset, physSize, coords.Count, faces.Count);
584 }
585 }
586
587 return true;
588 }
589
590 /// <summary>
591 /// decompresses a gzipped OSD object
592 /// </summary>
593 /// <param name="decodedOsd"></param> the OSD object
594 /// <param name="meshBytes"></param>
595 /// <returns></returns>
596 private static OSD DecompressOsd(byte[] meshBytes)
597 {
598 OSD decodedOsd = null;
599
600 using (MemoryStream inMs = new MemoryStream(meshBytes))
601 {
602 using (MemoryStream outMs = new MemoryStream())
603 {
604 using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress))
605 {
606 byte[] readBuffer = new byte[2048];
607 inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header
608 int readLen = 0;
609
610 while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
611 outMs.Write(readBuffer, 0, readLen);
612
613 outMs.Flush();
614
615 outMs.Seek(0, SeekOrigin.Begin);
616
617 byte[] decompressedBuf = outMs.GetBuffer();
618
619 decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
620 }
621 }
622 }
623 return decodedOsd;
624 }
625
626 /// <summary>
627 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
628 /// </summary>
629 /// <param name="primName"></param>
630 /// <param name="primShape"></param>
631 /// <param name="size"></param>
632 /// <param name="lod"></param>
633 /// <param name="coords">Coords are added to this list by the method.</param>
634 /// <param name="faces">Faces are added to this list by the method.</param>
635 /// <returns>true if coords and faces were successfully generated, false if not</returns>
636 private bool GenerateCoordsAndFacesFromPrimSculptData(
637 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
638 {
639 coords = new List<Coord>();
640 faces = new List<Face>();
641 PrimMesher.SculptMesh sculptMesh;
642 Image idata = null;
643 string decodedSculptFileName = "";
644
645 if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero)
646 {
647 decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString());
648 try
649 {
650 if (File.Exists(decodedSculptFileName))
651 {
652 idata = Image.FromFile(decodedSculptFileName);
653 }
654 }
655 catch (Exception e)
656 {
657 m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message);
658
659 }
660 //if (idata != null)
661 // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString());
662 }
663
664 if (idata == null)
665 {
666 if (primShape.SculptData == null || primShape.SculptData.Length == 0)
667 return false;
668
669 try
670 {
671 OpenMetaverse.Imaging.ManagedImage managedImage;
672
673 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out managedImage);
674
675 if (managedImage == null)
676 {
677 // In some cases it seems that the decode can return a null bitmap without throwing
678 // an exception
679 m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
680
681 return false;
682 }
683
684 if ((managedImage.Channels & OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha) != 0)
685 managedImage.ConvertChannels(managedImage.Channels & ~OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha);
686
687 Bitmap imgData = OpenMetaverse.Imaging.LoadTGAClass.LoadTGA(new MemoryStream(managedImage.ExportTGA()));
688 idata = (Image)imgData;
689 managedImage = null;
690
691 if (cacheSculptMaps)
692 {
693 try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
694 catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
695 }
696 }
697 catch (DllNotFoundException)
698 {
699 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!");
700 return false;
701 }
702 catch (IndexOutOfRangeException)
703 {
704 m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
705 return false;
706 }
707 catch (Exception ex)
708 {
709 m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
710 return false;
711 }
712 }
713
714 PrimMesher.SculptMesh.SculptType sculptType;
715 switch ((OpenMetaverse.SculptType)primShape.SculptType)
716 {
717 case OpenMetaverse.SculptType.Cylinder:
718 sculptType = PrimMesher.SculptMesh.SculptType.cylinder;
719 break;
720 case OpenMetaverse.SculptType.Plane:
721 sculptType = PrimMesher.SculptMesh.SculptType.plane;
722 break;
723 case OpenMetaverse.SculptType.Torus:
724 sculptType = PrimMesher.SculptMesh.SculptType.torus;
725 break;
726 case OpenMetaverse.SculptType.Sphere:
727 sculptType = PrimMesher.SculptMesh.SculptType.sphere;
728 break;
729 default:
730 sculptType = PrimMesher.SculptMesh.SculptType.plane;
731 break;
732 }
733
734 bool mirror = ((primShape.SculptType & 128) != 0);
735 bool invert = ((primShape.SculptType & 64) != 0);
736
737 sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert);
738
739 idata.Dispose();
740
741 sculptMesh.DumpRaw(baseDir, primName, "primMesh");
742
743 sculptMesh.Scale(size.X, size.Y, size.Z);
744
745 coords = sculptMesh.coords;
746 faces = sculptMesh.faces;
747
748 return true;
749 }
750
751 /// <summary>
752 /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim.
753 /// </summary>
754 /// <param name="primName"></param>
755 /// <param name="primShape"></param>
756 /// <param name="size"></param>
757 /// <param name="coords">Coords are added to this list by the method.</param>
758 /// <param name="faces">Faces are added to this list by the method.</param>
759 /// <returns>true if coords and faces were successfully generated, false if not</returns>
760 private bool GenerateCoordsAndFacesFromPrimShapeData(
761 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
762 {
763 PrimMesh primMesh;
764 coords = new List<Coord>();
765 faces = new List<Face>();
766
767 float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
768 float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
769 float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
770 float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
771 float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
772 float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;
773
774 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
775 float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
776 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
777 if (profileHollow > 0.95f)
778 profileHollow = 0.95f;
779
780 int sides = 4;
781 LevelOfDetail iLOD = (LevelOfDetail)lod;
782 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
783 sides = 3;
784 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
785 {
786 switch (iLOD)
787 {
788 case LevelOfDetail.High: sides = 24; break;
789 case LevelOfDetail.Medium: sides = 12; break;
790 case LevelOfDetail.Low: sides = 6; break;
791 case LevelOfDetail.VeryLow: sides = 3; break;
792 default: sides = 24; break;
793 }
794 }
795 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
796 { // half circle, prim is a sphere
797 switch (iLOD)
798 {
799 case LevelOfDetail.High: sides = 24; break;
800 case LevelOfDetail.Medium: sides = 12; break;
801 case LevelOfDetail.Low: sides = 6; break;
802 case LevelOfDetail.VeryLow: sides = 3; break;
803 default: sides = 24; break;
804 }
805
806 profileBegin = 0.5f * profileBegin + 0.5f;
807 profileEnd = 0.5f * profileEnd + 0.5f;
808 }
809
810 int hollowSides = sides;
811 if (primShape.HollowShape == HollowShape.Circle)
812 {
813 switch (iLOD)
814 {
815 case LevelOfDetail.High: hollowSides = 24; break;
816 case LevelOfDetail.Medium: hollowSides = 12; break;
817 case LevelOfDetail.Low: hollowSides = 6; break;
818 case LevelOfDetail.VeryLow: hollowSides = 3; break;
819 default: hollowSides = 24; break;
820 }
821 }
822 else if (primShape.HollowShape == HollowShape.Square)
823 hollowSides = 4;
824 else if (primShape.HollowShape == HollowShape.Triangle)
825 hollowSides = 3;
826
827 primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
828
829 if (primMesh.errorMessage != null)
830 if (primMesh.errorMessage.Length > 0)
831 m_log.Error("[ERROR] " + primMesh.errorMessage);
832
833 primMesh.topShearX = pathShearX;
834 primMesh.topShearY = pathShearY;
835 primMesh.pathCutBegin = pathBegin;
836 primMesh.pathCutEnd = pathEnd;
837
838 if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible)
839 {
840 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
841 primMesh.twistEnd = primShape.PathTwist * 18 / 10;
842 primMesh.taperX = pathScaleX;
843 primMesh.taperY = pathScaleY;
844
845 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
846 {
847 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
848 if (profileBegin < 0.0f) profileBegin = 0.0f;
849 if (profileEnd > 1.0f) profileEnd = 1.0f;
850 }
851#if SPAM
852 m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
853#endif
854 try
855 {
856 primMesh.ExtrudeLinear();
857 }
858 catch (Exception ex)
859 {
860 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
861 return false;
862 }
863 }
864 else
865 {
866 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
867 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
868 primMesh.radius = 0.01f * primShape.PathRadiusOffset;
869 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
870 primMesh.skew = 0.01f * primShape.PathSkew;
871 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10;
872 primMesh.twistEnd = primShape.PathTwist * 36 / 10;
873 primMesh.taperX = primShape.PathTaperX * 0.01f;
874 primMesh.taperY = primShape.PathTaperY * 0.01f;
875
876 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
877 {
878 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
879 if (profileBegin < 0.0f) profileBegin = 0.0f;
880 if (profileEnd > 1.0f) profileEnd = 1.0f;
881 }
882#if SPAM
883 m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
884#endif
885 try
886 {
887 primMesh.ExtrudeCircular();
888 }
889 catch (Exception ex)
890 {
891 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
892 return false;
893 }
894 }
895
896 primMesh.DumpRaw(baseDir, primName, "primMesh");
897
898 primMesh.Scale(size.X, size.Y, size.Z);
899
900 coords = primMesh.coords;
901 faces = primMesh.faces;
902
903 return true;
904 }
905
906 /// <summary>
907 /// temporary prototype code - please do not use until the interface has been finalized!
908 /// </summary>
909 /// <param name="size">value to scale the hull points by</param>
910 /// <returns>a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null</returns>
911 public List<Vector3> GetBoundingHull(Vector3 size)
912 {
913 if (mBoundingHull == null)
914 return null;
915
916 List<Vector3> verts = new List<Vector3>();
917 foreach (var vert in mBoundingHull)
918 verts.Add(vert * size);
919
920 return verts;
921 }
922
923 /// <summary>
924 /// temporary prototype code - please do not use until the interface has been finalized!
925 /// </summary>
926 /// <param name="size">value to scale the hull points by</param>
927 /// <returns>a list of hulls if they exist and have been successfully decoded, otherwise null</returns>
928 public List<List<Vector3>> GetConvexHulls(Vector3 size)
929 {
930 if (mConvexHulls == null)
931 return null;
932
933 List<List<Vector3>> hulls = new List<List<Vector3>>();
934 foreach (var hull in mConvexHulls)
935 {
936 List<Vector3> verts = new List<Vector3>();
937 foreach (var vert in hull)
938 verts.Add(vert * size);
939 hulls.Add(verts);
940 }
941
942 return hulls;
943 }
944
945 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
946 {
947 return CreateMesh(primName, primShape, size, lod, false, true);
948 }
949
950 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
951 {
952 return CreateMesh(primName, primShape, size, lod, isPhysical, true);
953 }
954
955 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
956 {
957#if SPAM
958 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
959#endif
960
961 Mesh mesh = null;
962 ulong key = 0;
963
964 // If this mesh has been created already, return it instead of creating another copy
965 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
966 if (shouldCache)
967 {
968 key = primShape.GetMeshKey(size, lod);
969 lock (m_uniqueMeshes)
970 {
971 if (m_uniqueMeshes.TryGetValue(key, out mesh))
972 return mesh;
973 }
974 }
975
976 if (size.X < 0.01f) size.X = 0.01f;
977 if (size.Y < 0.01f) size.Y = 0.01f;
978 if (size.Z < 0.01f) size.Z = 0.01f;
979
980 mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
981
982 if (mesh != null)
983 {
984 if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh)
985 {
986#if SPAM
987 m_log.Debug("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " +
988 minSizeForComplexMesh.ToString() + " - creating simple bounding box");
989#endif
990 mesh = CreateBoundingBoxMesh(mesh);
991 mesh.DumpRaw(baseDir, primName, "Z extruded");
992 }
993
994 // trim the vertex and triangle lists to free up memory
995 mesh.TrimExcess();
996
997 if (shouldCache)
998 {
999 lock (m_uniqueMeshes)
1000 {
1001 m_uniqueMeshes.Add(key, mesh);
1002 }
1003 }
1004 }
1005
1006 return mesh;
1007 }
1008
1009 }
1010}
diff --git a/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/PrimMesher.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/PrimMesher.cs
new file mode 100644
index 0000000..4049ee1
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/PrimMesher.cs
@@ -0,0 +1,2324 @@
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/PhysicsModules/Meshing/Meshmerizer/SculptMap.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMap.cs
new file mode 100644
index 0000000..740424e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMap.cs
@@ -0,0 +1,183 @@
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/PhysicsModules/Meshing/Meshmerizer/SculptMesh.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMesh.cs
new file mode 100644
index 0000000..4a7f3ad
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer/SculptMesh.cs
@@ -0,0 +1,646 @@
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/PhysicsModules/Meshing/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..b4bdb5a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4using Mono.Addins;
5
6// General Information about an assembly is controlled through the following
7// set of attributes. Change these attribute values to modify the information
8// associated with an assembly.
9[assembly: AssemblyTitle("OpenSim.Region.PhysicsModules.Meshing")]
10[assembly: AssemblyDescription("")]
11[assembly: AssemblyConfiguration("")]
12[assembly: AssemblyCompany("http://opensimulator.org")]
13[assembly: AssemblyProduct("OpenSim")]
14[assembly: AssemblyCopyright("OpenSimulator developers")]
15[assembly: AssemblyTrademark("")]
16[assembly: AssemblyCulture("")]
17
18// Setting ComVisible to false makes the types in this assembly not visible
19// to COM components. If you need to access a type in this assembly from
20// COM, set the ComVisible attribute to true on that type.
21[assembly: ComVisible(false)]
22
23// The following GUID is for the ID of the typelib if this project is exposed to COM
24[assembly: Guid("4b7e35c2-a9dd-4b10-b778-eb417f4f6884")]
25
26// Version information for an assembly consists of the following four values:
27//
28// Major Version
29// Minor Version
30// Build Number
31// Revision
32//
33[assembly: AssemblyVersion("0.8.3.*")]
34
35[assembly: Addin("OpenSim.Region.PhysicsModules.Meshing", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/PhysicsModules/Meshing/ZeroMesher.cs b/OpenSim/Region/PhysicsModules/Meshing/ZeroMesher.cs
new file mode 100644
index 0000000..0a3b3a4
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/ZeroMesher.cs
@@ -0,0 +1,132 @@
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.Reflection;
30using OpenSim.Framework;
31using OpenSim.Region.Framework.Scenes;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.PhysicsModules.SharedBase;
34using OpenMetaverse;
35using Nini.Config;
36using Mono.Addins;
37using log4net;
38
39/*
40 * This is the zero mesher.
41 * Whatever you want him to mesh, he can't, telling you that by responding with a null pointer.
42 * Effectivly this is for switching off meshing and for testing as each physics machine should deal
43 * with the null pointer situation.
44 * But it's also a convenience thing, as physics machines can rely on having a mesher in any situation, even
45 * if it's a dump one like this.
46 * Note, that this mesher is *not* living in a module but in the manager itself, so
47 * it's always availabe and thus the default in case of configuration errors
48*/
49
50namespace OpenSim.Region.PhysicsModules.Meshing
51{
52
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ZeroMesher")]
54 public class ZeroMesher : IMesher, INonSharedRegionModule
55 {
56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57 private bool m_Enabled = false;
58
59 #region INonSharedRegionModule
60 public string Name
61 {
62 get { return "ZeroMesher"; }
63 }
64
65 public Type ReplaceableInterface
66 {
67 get { return null; }
68 }
69
70 public void Initialise(IConfigSource source)
71 {
72 // TODO: Move this out of Startup
73 IConfig config = source.Configs["Startup"];
74 if (config != null)
75 {
76 // This is the default Mesher
77 string mesher = config.GetString("meshing", Name);
78 if (mesher == Name)
79 m_Enabled = true;
80 }
81 }
82
83 public void Close()
84 {
85 }
86
87 public void AddRegion(Scene scene)
88 {
89 if (!m_Enabled)
90 return;
91
92 scene.RegisterModuleInterface<IMesher>(this);
93 }
94
95 public void RemoveRegion(Scene scene)
96 {
97 if (!m_Enabled)
98 return;
99
100 scene.UnregisterModuleInterface<IMesher>(this);
101 }
102
103 public void RegionLoaded(Scene scene)
104 {
105 if (!m_Enabled)
106 return;
107 }
108 #endregion
109
110 #region IMesher
111 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
112 {
113 return CreateMesh(primName, primShape, size, lod, false, false);
114 }
115
116 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
117 {
118 return CreateMesh(primName, primShape, size, lod, false, false);
119 }
120
121 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
122 {
123 // Remove the reference to the encoded JPEG2000 data so it can be GCed
124 primShape.SculptData = OpenMetaverse.Utils.EmptyBytes;
125
126 return null;
127 }
128 #endregion
129
130
131 }
132}
diff --git a/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs
new file mode 100644
index 0000000..7869739
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs
@@ -0,0 +1,62 @@
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;
30using Mono.Addins;
31
32// Information about this assembly is defined by the following
33// attributes.
34//
35// change them to the information which is associated with the assembly
36// you compile.
37
38[assembly : AssemblyTitle("OdePlugin")]
39[assembly : AssemblyDescription("")]
40[assembly : AssemblyConfiguration("")]
41[assembly : AssemblyCompany("http://opensimulator.org")]
42[assembly : AssemblyProduct("OdePlugin")]
43[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
44[assembly : AssemblyTrademark("")]
45[assembly : AssemblyCulture("")]
46
47// This sets the default COM visibility of types in the assembly to invisible.
48// If you need to expose a type to COM, use [ComVisible(true)] on that type.
49
50[assembly : ComVisible(false)]
51
52// The assembly version has following format :
53//
54// Major.Minor.Build.Revision
55//
56// You can specify all values by your own or you can build default build and revision
57// numbers with the '*' character (the default):
58
59[assembly : AssemblyVersion("0.8.2.*")]
60
61[assembly: Addin("OpenSim.Region.PhysicsModule.ODE", OpenSim.VersionInfo.VersionNumber)]
62[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs b/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs
new file mode 100644
index 0000000..b35c299
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs
@@ -0,0 +1,1409 @@
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.PhysicsModules.SharedBase;
35using log4net;
36
37namespace OpenSim.Region.PhysicsModule.ODE
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="vel"></param>
171 /// <param name="size"></param>
172 /// <param name="pid_d"></param>
173 /// <param name="pid_p"></param>
174 /// <param name="capsule_radius"></param>
175 /// <param name="tensor"></param>
176 /// <param name="density">
177 /// Only used right now to return information to LSL. Not actually used to set mass in ODE!
178 /// </param>
179 /// <param name="walk_divisor"></param>
180 /// <param name="rundivisor"></param>
181 public OdeCharacter(
182 String avName, OdeScene parent_scene, Vector3 pos, Vector3 vel, Vector3 size, float pid_d, float pid_p,
183 float capsule_radius, float tensor, float density,
184 float walk_divisor, float rundivisor)
185 {
186 m_uuid = UUID.Random();
187
188 if (pos.IsFinite())
189 {
190 if (pos.Z > 9999999f)
191 {
192 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
193 }
194 if (pos.Z < -90000f)
195 {
196 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
197 }
198
199 _position = pos;
200 m_taintPosition = pos;
201 }
202 else
203 {
204 _position
205 = new Vector3(
206 (float)_parent_scene.WorldExtents.X * 0.5f,
207 (float)_parent_scene.WorldExtents.Y * 0.5f,
208 parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f);
209 m_taintPosition = _position;
210
211 m_log.WarnFormat("[ODE CHARACTER]: Got NaN Position on Character Create for {0}", avName);
212 }
213
214 _velocity = vel;
215 m_taintTargetVelocity = vel;
216
217 _parent_scene = parent_scene;
218
219 PID_D = pid_d;
220 PID_P = pid_p;
221 CAPSULE_RADIUS = capsule_radius;
222 m_tensor = tensor;
223 m_density = density;
224// heightFudgeFactor = height_fudge_factor;
225 walkDivisor = walk_divisor;
226 runDivisor = rundivisor;
227
228 // m_StandUpRotation =
229 // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f,
230 // 0.5f);
231
232 // We can set taint and actual to be the same here, since the entire character will be set up when the
233 // m_tainted_isPhysical is processed.
234 SetTaintedCapsuleLength(size);
235 CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
236
237 m_isPhysical = false; // current status: no ODE information exists
238 m_tainted_isPhysical = true; // new tainted status: need to create ODE information
239
240 _parent_scene.AddPhysicsActorTaint(this);
241
242 Name = avName;
243 }
244
245 public override int PhysicsActorType
246 {
247 get { return (int) ActorTypes.Agent; }
248 set { return; }
249 }
250
251 /// <summary>
252 /// If this is set, the avatar will move faster
253 /// </summary>
254 public override bool SetAlwaysRun
255 {
256 get { return m_alwaysRun; }
257 set { m_alwaysRun = value; }
258 }
259
260 public override bool Grabbed
261 {
262 set { return; }
263 }
264
265 public override bool Selected
266 {
267 set { return; }
268 }
269
270 public override float Buoyancy
271 {
272 get { return m_buoyancy; }
273 set { m_buoyancy = value; }
274 }
275
276 public override bool FloatOnWater
277 {
278 set { return; }
279 }
280
281 public override bool IsPhysical
282 {
283 get { return false; }
284 set { return; }
285 }
286
287 public override bool ThrottleUpdates
288 {
289 get { return false; }
290 set { return; }
291 }
292
293 public override bool Flying
294 {
295 get { return flying; }
296 set
297 {
298 flying = value;
299// m_log.DebugFormat("[ODE CHARACTER]: Set OdeCharacter Flying to {0}", flying);
300 }
301 }
302
303 /// <summary>
304 /// Returns if the avatar is colliding in general.
305 /// This includes the ground and objects and avatar.
306 /// </summary>
307 public override bool IsColliding
308 {
309 get { return m_iscolliding; }
310 set
311 {
312 int i;
313 int truecount = 0;
314 int falsecount = 0;
315
316 if (m_colliderarr.Length >= 10)
317 {
318 for (i = 0; i < 10; i++)
319 {
320 m_colliderarr[i] = m_colliderarr[i + 1];
321 }
322 }
323 m_colliderarr[10] = value;
324
325 for (i = 0; i < 11; i++)
326 {
327 if (m_colliderarr[i])
328 {
329 truecount++;
330 }
331 else
332 {
333 falsecount++;
334 }
335 }
336
337 // Equal truecounts and false counts means we're colliding with something.
338
339 if (falsecount > 1.2*truecount)
340 {
341 m_iscolliding = false;
342 }
343 else
344 {
345 m_iscolliding = true;
346 }
347
348 if (m_wascolliding != m_iscolliding)
349 {
350 //base.SendCollisionUpdate(new CollisionEventUpdate());
351 }
352
353 m_wascolliding = m_iscolliding;
354 }
355 }
356
357 /// <summary>
358 /// Returns if an avatar is colliding with the ground
359 /// </summary>
360 public override bool CollidingGround
361 {
362 get { return m_iscollidingGround; }
363 set
364 {
365 // Collisions against the ground are not really reliable
366 // So, to get a consistant value we have to average the current result over time
367 // Currently we use 1 second = 10 calls to this.
368 int i;
369 int truecount = 0;
370 int falsecount = 0;
371
372 if (m_colliderGroundarr.Length >= 10)
373 {
374 for (i = 0; i < 10; i++)
375 {
376 m_colliderGroundarr[i] = m_colliderGroundarr[i + 1];
377 }
378 }
379 m_colliderGroundarr[10] = value;
380
381 for (i = 0; i < 11; i++)
382 {
383 if (m_colliderGroundarr[i])
384 {
385 truecount++;
386 }
387 else
388 {
389 falsecount++;
390 }
391 }
392
393 // Equal truecounts and false counts means we're colliding with something.
394
395 if (falsecount > 1.2*truecount)
396 {
397 m_iscollidingGround = false;
398 }
399 else
400 {
401 m_iscollidingGround = true;
402 }
403 if (m_wascollidingGround != m_iscollidingGround)
404 {
405 //base.SendCollisionUpdate(new CollisionEventUpdate());
406 }
407 m_wascollidingGround = m_iscollidingGround;
408 }
409 }
410
411 /// <summary>
412 /// Returns if the avatar is colliding with an object
413 /// </summary>
414 public override bool CollidingObj
415 {
416 get { return m_iscollidingObj; }
417 set
418 {
419 m_iscollidingObj = value;
420 if (value && !m_avatarplanted)
421 m_pidControllerActive = false;
422 else
423 m_pidControllerActive = true;
424 }
425 }
426
427 /// <summary>
428 /// turn the PID controller on or off.
429 /// The PID Controller will turn on all by itself in many situations
430 /// </summary>
431 /// <param name="status"></param>
432 public void SetPidStatus(bool status)
433 {
434 m_pidControllerActive = status;
435 }
436
437 public override bool Stopped
438 {
439 get { return _zeroFlag; }
440 }
441
442 /// <summary>
443 /// This 'puts' an avatar somewhere in the physics space.
444 /// Not really a good choice unless you 'know' it's a good
445 /// spot otherwise you're likely to orbit the avatar.
446 /// </summary>
447 public override Vector3 Position
448 {
449 get { return _position; }
450 set
451 {
452 if (Body == IntPtr.Zero || Shell == IntPtr.Zero)
453 {
454 if (value.IsFinite())
455 {
456 if (value.Z > 9999999f)
457 {
458 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
459 }
460 if (value.Z < -90000f)
461 {
462 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
463 }
464
465 m_taintPosition = value;
466 _parent_scene.AddPhysicsActorTaint(this);
467 }
468 else
469 {
470 m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Position from Scene on character {0}", Name);
471 }
472 }
473 }
474 }
475
476 public override Vector3 RotationalVelocity
477 {
478 get { return m_rotationalVelocity; }
479 set { m_rotationalVelocity = value; }
480 }
481
482 /// <summary>
483 /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight
484 /// and use it to offset landings properly
485 /// </summary>
486 public override Vector3 Size
487 {
488 get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); }
489 set
490 {
491 SetTaintedCapsuleLength(value);
492
493 // If we reset velocity here, then an avatar stalls when it crosses a border for the first time
494 // (as the height of the new root agent is set).
495// Velocity = Vector3.Zero;
496
497 _parent_scene.AddPhysicsActorTaint(this);
498 }
499 }
500
501 private void SetTaintedCapsuleLength(Vector3 size)
502 {
503 if (size.IsFinite())
504 {
505 m_pidControllerActive = true;
506
507 m_tainted_CAPSULE_LENGTH = size.Z - CAPSULE_RADIUS * 2.0f;
508
509 // m_log.InfoFormat("[ODE CHARACTER]: Size = {0}, Capsule Length = {1} (Capsule Radius = {2})",
510 // size, m_tainted_CAPSULE_LENGTH, CAPSULE_RADIUS);
511 }
512 else
513 {
514 m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Size for {0} in {1}", Name, _parent_scene.PhysicsSceneName);
515 }
516 }
517
518 private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector)
519 {
520 movementVector.Z = 0f;
521 float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y));
522 if (magnitude < 0.1f) return;
523
524 // normalize the velocity vector
525 float invMagnitude = 1.0f / magnitude;
526 movementVector.X *= invMagnitude;
527 movementVector.Y *= invMagnitude;
528
529 // if we change the capsule heading too often, the capsule can fall down
530 // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw),
531 // meaning only 4 possible capsule tilt orientations
532 if (movementVector.X > 0)
533 {
534 // east
535 if (movementVector.Y > 0)
536 {
537 // northeast
538 movementVector.X = m_tiltBaseMovement;
539 movementVector.Y = m_tiltBaseMovement;
540 }
541 else
542 {
543 // southeast
544 movementVector.X = m_tiltBaseMovement;
545 movementVector.Y = -m_tiltBaseMovement;
546 }
547 }
548 else
549 {
550 // west
551 if (movementVector.Y > 0)
552 {
553 // northwest
554 movementVector.X = -m_tiltBaseMovement;
555 movementVector.Y = m_tiltBaseMovement;
556 }
557 else
558 {
559 // southwest
560 movementVector.X = -m_tiltBaseMovement;
561 movementVector.Y = -m_tiltBaseMovement;
562 }
563 }
564
565 // movementVector.Z is zero
566
567 // calculate tilt components based on desired amount of tilt and current (snapped) heading.
568 // the "-" sign is to force the tilt to be OPPOSITE the direction of movement.
569 float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane;
570 float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane;
571
572 //m_log.Debug("[ODE CHARACTER]: changing avatar tilt");
573 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent);
574 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced
575 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent);
576 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop
577 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
578 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
579 }
580
581 /// <summary>
582 /// Uses the capped cyllinder volume formula to calculate the avatar's mass.
583 /// This may be used in calculations in the scene/scenepresence
584 /// </summary>
585 public override float Mass
586 {
587 get
588 {
589 float AVvolume = (float)(Math.PI * Math.Pow(CAPSULE_RADIUS, 2) * CAPSULE_LENGTH);
590 return m_density * AVvolume;
591 }
592 }
593
594 public override void link(PhysicsActor obj) {}
595
596 public override void delink() {}
597
598 public override void LockAngularMotion(Vector3 axis) {}
599
600// This code is very useful. Written by DanX0r. We're just not using it right now.
601// Commented out to prevent a warning.
602//
603// private void standupStraight()
604// {
605// // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air.
606// // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you
607// // change appearance and when you enter the simulator
608// // After this routine is done, the amotor stabilizes much quicker
609// d.Vector3 feet;
610// d.Vector3 head;
611// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet);
612// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head);
613// float posture = head.Z - feet.Z;
614
615// // restoring force proportional to lack of posture:
616// float servo = (2.5f - posture) * POSTURE_SERVO;
617// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f);
618// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f);
619// //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
620// //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyFArotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
621// }
622
623 public override Vector3 Force
624 {
625 get { return _target_velocity; }
626 set { return; }
627 }
628
629 public override int VehicleType
630 {
631 get { return 0; }
632 set { return; }
633 }
634
635 public override void VehicleFloatParam(int param, float value)
636 {
637 }
638
639 public override void VehicleVectorParam(int param, Vector3 value)
640 {
641 }
642
643 public override void VehicleRotationParam(int param, Quaternion rotation)
644 {
645 }
646
647 public override void VehicleFlags(int param, bool remove)
648 {
649 }
650
651 public override void SetVolumeDetect(int param)
652 {
653 }
654
655 public override Vector3 CenterOfMass
656 {
657 get { return Vector3.Zero; }
658 }
659
660 public override Vector3 GeometricCenter
661 {
662 get { return Vector3.Zero; }
663 }
664
665 public override PrimitiveBaseShape Shape
666 {
667 set { return; }
668 }
669
670 public override Vector3 TargetVelocity
671 {
672 get
673 {
674 return m_taintTargetVelocity;
675 }
676
677 set
678 {
679 Velocity = value;
680 }
681 }
682
683
684 public override Vector3 Velocity
685 {
686 get
687 {
688 // There's a problem with Vector3.Zero! Don't Use it Here!
689 if (_zeroFlag)
690 return Vector3.Zero;
691 m_lastUpdateSent = false;
692 return _velocity;
693 }
694
695 set
696 {
697 if (value.IsFinite())
698 {
699 m_pidControllerActive = true;
700 m_taintTargetVelocity = value;
701 _parent_scene.AddPhysicsActorTaint(this);
702 }
703 else
704 {
705 m_log.WarnFormat("[ODE CHARACTER]: Got a NaN velocity from Scene for {0}", Name);
706 }
707
708// m_log.DebugFormat("[PHYSICS]: Set target velocity of {0}", m_taintTargetVelocity);
709 }
710 }
711
712 public override Vector3 Torque
713 {
714 get { return Vector3.Zero; }
715 set { return; }
716 }
717
718 public override float CollisionScore
719 {
720 get { return 0f; }
721 set { }
722 }
723
724 public override bool Kinematic
725 {
726 get { return false; }
727 set { }
728 }
729
730 public override Quaternion Orientation
731 {
732 get { return Quaternion.Identity; }
733 set {
734 //Matrix3 or = Orientation.ToRotationMatrix();
735 //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22);
736 //d.BodySetRotation(Body, ref ord);
737 }
738 }
739
740 public override Vector3 Acceleration
741 {
742 get { return _acceleration; }
743 set { _acceleration = value; }
744 }
745
746 /// <summary>
747 /// Adds the force supplied to the Target Velocity
748 /// The PID controller takes this target velocity and tries to make it a reality
749 /// </summary>
750 /// <param name="force"></param>
751 public override void AddForce(Vector3 force, bool pushforce)
752 {
753 if (force.IsFinite())
754 {
755 if (pushforce)
756 {
757 m_pidControllerActive = false;
758 force *= 100f;
759 m_taintForce += force;
760 _parent_scene.AddPhysicsActorTaint(this);
761
762 // If uncommented, things get pushed off world
763 //
764 // m_log.Debug("Push!");
765 // m_taintTargetVelocity.X += force.X;
766 // m_taintTargetVelocity.Y += force.Y;
767 // m_taintTargetVelocity.Z += force.Z;
768 }
769 else
770 {
771 m_pidControllerActive = true;
772 m_taintTargetVelocity += force;
773 }
774 }
775 else
776 {
777 m_log.WarnFormat("[ODE CHARACTER]: Got a NaN force applied to {0}", Name);
778 }
779 //m_lastUpdateSent = false;
780 }
781
782 public override void AddAngularForce(Vector3 force, bool pushforce)
783 {
784 }
785
786 public override void SetMomentum(Vector3 momentum)
787 {
788 }
789
790 /// <summary>
791 /// Called from Simulate
792 /// This is the avatar's movement control + PID Controller
793 /// </summary>
794 /// <param name="defects">The character will be added to this list if there is something wrong (non-finite
795 /// position or velocity).
796 /// </param>
797 internal void Move(List<OdeCharacter> defects)
798 {
799 // no lock; for now it's only called from within Simulate()
800
801 // If the PID Controller isn't active then we set our force
802 // calculating base velocity to the current position
803
804 if (Body == IntPtr.Zero)
805 return;
806
807 if (m_pidControllerActive == false)
808 {
809 _zeroPosition = d.BodyGetPosition(Body);
810 }
811 //PidStatus = true;
812
813 d.Vector3 localpos = d.BodyGetPosition(Body);
814 Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z);
815
816 if (!localPos.IsFinite())
817 {
818 m_log.WarnFormat(
819 "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.",
820 localPos, Name);
821
822 defects.Add(this);
823
824 return;
825 }
826
827 Vector3 vec = Vector3.Zero;
828 d.Vector3 vel = d.BodyGetLinearVel(Body);
829
830// m_log.DebugFormat(
831// "[ODE CHARACTER]: Current velocity in Move() is <{0},{1},{2}>, target {3} for {4}",
832// vel.X, vel.Y, vel.Z, _target_velocity, Name);
833
834 float movementdivisor = 1f;
835
836 if (!m_alwaysRun)
837 {
838 movementdivisor = walkDivisor;
839 }
840 else
841 {
842 movementdivisor = runDivisor;
843 }
844
845 // if velocity is zero, use position control; otherwise, velocity control
846 if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding)
847 {
848 // keep track of where we stopped. No more slippin' & slidin'
849 if (!_zeroFlag)
850 {
851 _zeroFlag = true;
852 _zeroPosition = d.BodyGetPosition(Body);
853 }
854
855 if (m_pidControllerActive)
856 {
857 // We only want to deactivate the PID Controller if we think we want to have our surrogate
858 // react to the physics scene by moving it's position.
859 // Avatar to Avatar collisions
860 // Prim to avatar collisions
861
862 d.Vector3 pos = d.BodyGetPosition(Body);
863 vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
864 vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y)* (PID_P * 2);
865 if (flying)
866 {
867 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
868 }
869 }
870 //PidStatus = true;
871 }
872 else
873 {
874 m_pidControllerActive = true;
875 _zeroFlag = false;
876 if (m_iscolliding && !flying)
877 {
878 // We're standing on something
879 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D);
880 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D);
881 }
882 else if (m_iscolliding && flying)
883 {
884 // We're flying and colliding with something
885 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16);
886 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16);
887 }
888 else if (!m_iscolliding && flying)
889 {
890 // we're in mid air suspended
891 vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6);
892 vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6);
893
894// m_log.DebugFormat(
895// "[ODE CHARACTER]: !m_iscolliding && flying, vec {0}, _target_velocity {1}, movementdivisor {2}, vel {3}",
896// vec, _target_velocity, movementdivisor, vel);
897 }
898
899 if (flying)
900 {
901 // This also acts as anti-gravity so that we hover when flying rather than fall.
902 vec.Z = (_target_velocity.Z - vel.Z) * (PID_D);
903 }
904 else
905 {
906 if (m_iscolliding && _target_velocity.Z > 0.0f)
907 {
908 // We're colliding with something and we're not flying but we're moving
909 // This means we're walking or running.
910 d.Vector3 pos = d.BodyGetPosition(Body);
911 vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P;
912 vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D;
913 vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D;
914 }
915 else if (!m_iscolliding)
916 {
917 // we're not colliding and we're not flying so that means we're falling!
918 // m_iscolliding includes collisions with the ground.
919 vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D;
920 vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D;
921 }
922 }
923 }
924
925 if (flying)
926 {
927 // Anti-gravity so that we hover when flying rather than fall.
928 vec.Z += ((-1 * _parent_scene.gravityz) * m_mass);
929
930 //Added for auto fly height. Kitto Flora
931 //d.Vector3 pos = d.BodyGetPosition(Body);
932 float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset;
933
934 if (_position.Z < target_altitude)
935 {
936 vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f;
937 }
938 // end add Kitto Flora
939 }
940
941 if (vec.IsFinite())
942 {
943 // Apply the total force acting on this avatar
944 d.BodyAddForce(Body, vec.X, vec.Y, vec.Z);
945
946 if (!_zeroFlag)
947 AlignAvatarTiltWithCurrentDirectionOfMovement(vec);
948 }
949 else
950 {
951 m_log.WarnFormat(
952 "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.",
953 vec, Name);
954
955 defects.Add(this);
956
957 return;
958 }
959
960 d.Vector3 newVel = d.BodyGetLinearVel(Body);
961 if (newVel.X >= 256 || newVel.X <= 256 || newVel.Y >= 256 || newVel.Y <= 256 || newVel.Z >= 256 || newVel.Z <= 256)
962 {
963// m_log.DebugFormat(
964// "[ODE CHARACTER]: Limiting falling velocity from {0} to {1} for {2}", newVel.Z, -9.8, Name);
965
966 newVel.X = Util.Clamp<float>(newVel.X, -255f, 255f);
967 newVel.Y = Util.Clamp<float>(newVel.Y, -255f, 255f);
968
969 if (!flying)
970 newVel.Z
971 = Util.Clamp<float>(
972 newVel.Z, -_parent_scene.AvatarTerminalVelocity, _parent_scene.AvatarTerminalVelocity);
973 else
974 newVel.Z = Util.Clamp<float>(newVel.Z, -255f, 255f);
975
976 d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z);
977 }
978 }
979
980 /// <summary>
981 /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence.
982 /// </summary>
983 /// <param name="defects">The character will be added to this list if there is something wrong (non-finite
984 /// position or velocity).
985 /// </param>
986 internal void UpdatePositionAndVelocity(List<OdeCharacter> defects)
987 {
988 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
989 d.Vector3 newPos;
990 try
991 {
992 newPos = d.BodyGetPosition(Body);
993 }
994 catch (NullReferenceException)
995 {
996 bad = true;
997 defects.Add(this);
998 newPos = new d.Vector3(_position.X, _position.Y, _position.Z);
999 base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem!
1000 m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid);
1001
1002 return;
1003 }
1004
1005 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
1006 if (newPos.X < 0.0f) newPos.X = 0.0f;
1007 if (newPos.Y < 0.0f) newPos.Y = 0.0f;
1008 if (newPos.X > (int)_parent_scene.WorldExtents.X - 0.05f) newPos.X = (int)_parent_scene.WorldExtents.X - 0.05f;
1009 if (newPos.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) newPos.Y = (int)_parent_scene.WorldExtents.Y - 0.05f;
1010
1011 _position.X = newPos.X;
1012 _position.Y = newPos.Y;
1013 _position.Z = newPos.Z;
1014
1015 // I think we need to update the taintPosition too -- Diva 12/24/10
1016 m_taintPosition = _position;
1017
1018 // Did we move last? = zeroflag
1019 // This helps keep us from sliding all over
1020
1021 if (_zeroFlag)
1022 {
1023 _velocity = Vector3.Zero;
1024
1025 // Did we send out the 'stopped' message?
1026 if (!m_lastUpdateSent)
1027 {
1028 m_lastUpdateSent = true;
1029 //base.RequestPhysicsterseUpdate();
1030 }
1031 }
1032 else
1033 {
1034 m_lastUpdateSent = false;
1035 d.Vector3 newVelocity;
1036
1037 try
1038 {
1039 newVelocity = d.BodyGetLinearVel(Body);
1040 }
1041 catch (NullReferenceException)
1042 {
1043 newVelocity.X = _velocity.X;
1044 newVelocity.Y = _velocity.Y;
1045 newVelocity.Z = _velocity.Z;
1046 }
1047
1048 _velocity.X = newVelocity.X;
1049 _velocity.Y = newVelocity.Y;
1050 _velocity.Z = newVelocity.Z;
1051
1052 if (_velocity.Z < -6 && !m_hackSentFall)
1053 {
1054 m_hackSentFall = true;
1055 m_pidControllerActive = false;
1056 }
1057 else if (flying && !m_hackSentFly)
1058 {
1059 //m_hackSentFly = true;
1060 //base.SendCollisionUpdate(new CollisionEventUpdate());
1061 }
1062 else
1063 {
1064 m_hackSentFly = false;
1065 m_hackSentFall = false;
1066 }
1067 }
1068 }
1069
1070 /// <summary>
1071 /// This creates the Avatar's physical Surrogate in ODE at the position supplied
1072 /// </summary>
1073 /// <remarks>
1074 /// WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access
1075 /// to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only
1076 /// place that is safe to call this routine AvatarGeomAndBodyCreation.
1077 /// </remarks>
1078 /// <param name="npositionX"></param>
1079 /// <param name="npositionY"></param>
1080 /// <param name="npositionZ"></param>
1081 /// <param name="tensor"></param>
1082 private void CreateOdeStructures(float npositionX, float npositionY, float npositionZ, float tensor)
1083 {
1084 if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero))
1085 {
1086 m_log.ErrorFormat(
1087 "[ODE CHARACTER]: Creating ODE structures for {0} even though some already exist. Shell = {1}, Body = {2}, Amotor = {3}",
1088 Name, Shell, Body, Amotor);
1089 }
1090
1091 int dAMotorEuler = 1;
1092// _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1093 if (CAPSULE_LENGTH <= 0)
1094 {
1095 m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
1096 CAPSULE_LENGTH = 0.01f;
1097 }
1098
1099 if (CAPSULE_RADIUS <= 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_RADIUS = 0.01f;
1103 }
1104
1105// lock (OdeScene.UniversalColliderSyncObject)
1106 Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
1107
1108 d.GeomSetCategoryBits(Shell, (int)m_collisionCategories);
1109 d.GeomSetCollideBits(Shell, (int)m_collisionFlags);
1110
1111 d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH);
1112 Body = d.BodyCreate(_parent_scene.world);
1113 d.BodySetPosition(Body, npositionX, npositionY, npositionZ);
1114
1115 _position.X = npositionX;
1116 _position.Y = npositionY;
1117 _position.Z = npositionZ;
1118
1119 m_taintPosition = _position;
1120
1121 d.BodySetMass(Body, ref ShellMass);
1122 d.Matrix3 m_caprot;
1123 // 90 Stand up on the cap of the capped cyllinder
1124 if (_parent_scene.IsAvCapsuleTilted)
1125 {
1126 d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2));
1127 }
1128 else
1129 {
1130 d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2));
1131 }
1132
1133 d.GeomSetRotation(Shell, ref m_caprot);
1134 d.BodySetRotation(Body, ref m_caprot);
1135
1136 d.GeomSetBody(Shell, Body);
1137
1138 // The purpose of the AMotor here is to keep the avatar's physical
1139 // surrogate from rotating while moving
1140 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
1141 d.JointAttach(Amotor, Body, IntPtr.Zero);
1142 d.JointSetAMotorMode(Amotor, dAMotorEuler);
1143 d.JointSetAMotorNumAxes(Amotor, 3);
1144 d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0);
1145 d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0);
1146 d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1);
1147 d.JointSetAMotorAngle(Amotor, 0, 0);
1148 d.JointSetAMotorAngle(Amotor, 1, 0);
1149 d.JointSetAMotorAngle(Amotor, 2, 0);
1150
1151 // These lowstops and high stops are effectively (no wiggle room)
1152 if (_parent_scene.IsAvCapsuleTilted)
1153 {
1154 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f);
1155 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f);
1156 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f);
1157 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f);
1158 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f);
1159 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f);
1160 }
1161 else
1162 {
1163 #region Documentation of capsule motor LowStop and HighStop parameters
1164 // Intentionally introduce some tilt into the capsule by setting
1165 // the motor stops to small epsilon values. This small tilt prevents
1166 // the capsule from falling into the terrain; a straight-up capsule
1167 // (with -0..0 motor stops) falls into the terrain for reasons yet
1168 // to be comprehended in their entirety.
1169 #endregion
1170 AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero);
1171 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f);
1172 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f);
1173 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f);
1174 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced
1175 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
1176 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop
1177 }
1178
1179 // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the
1180 // capped cyllinder will fall over
1181 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
1182 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor);
1183
1184 //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
1185 //d.QfromR(
1186 //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068,
1187 //
1188 //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
1189 //standupStraight();
1190
1191 _parent_scene.geom_name_map[Shell] = Name;
1192 _parent_scene.actor_name_map[Shell] = this;
1193 }
1194
1195 /// <summary>
1196 /// Cleanup the things we use in the scene.
1197 /// </summary>
1198 internal void Destroy()
1199 {
1200 m_tainted_isPhysical = false;
1201 _parent_scene.AddPhysicsActorTaint(this);
1202 }
1203
1204 /// <summary>
1205 /// Used internally to destroy the ODE structures associated with this character.
1206 /// </summary>
1207 internal void DestroyOdeStructures()
1208 {
1209 // Create avatar capsule and related ODE data
1210 if (Shell == IntPtr.Zero || Body == IntPtr.Zero || Amotor == IntPtr.Zero)
1211 {
1212 m_log.ErrorFormat(
1213 "[ODE CHARACTER]: Destroying ODE structures for {0} even though some are already null. Shell = {1}, Body = {2}, Amotor = {3}",
1214 Name, Shell, Body, Amotor);
1215 }
1216
1217 // destroy avatar capsule and related ODE data
1218 if (Amotor != IntPtr.Zero)
1219 {
1220 // Kill the Amotor
1221 d.JointDestroy(Amotor);
1222 Amotor = IntPtr.Zero;
1223 }
1224
1225 //kill the Geometry
1226// _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1227
1228 if (Body != IntPtr.Zero)
1229 {
1230 //kill the body
1231 d.BodyDestroy(Body);
1232 Body = IntPtr.Zero;
1233 }
1234
1235 if (Shell != IntPtr.Zero)
1236 {
1237// lock (OdeScene.UniversalColliderSyncObject)
1238 d.GeomDestroy(Shell);
1239
1240 _parent_scene.geom_name_map.Remove(Shell);
1241 _parent_scene.actor_name_map.Remove(Shell);
1242
1243 Shell = IntPtr.Zero;
1244 }
1245 }
1246
1247 public override void CrossingFailure()
1248 {
1249 }
1250
1251 public override Vector3 PIDTarget { set { return; } }
1252 public override bool PIDActive
1253 {
1254 get { return false; }
1255 set { return; }
1256 }
1257 public override float PIDTau { set { return; } }
1258
1259 public override float PIDHoverHeight { set { return; } }
1260 public override bool PIDHoverActive { set { return; } }
1261 public override PIDHoverType PIDHoverType { set { return; } }
1262 public override float PIDHoverTau { set { return; } }
1263
1264 public override Quaternion APIDTarget{ set { return; } }
1265
1266 public override bool APIDActive{ set { return; } }
1267
1268 public override float APIDStrength{ set { return; } }
1269
1270 public override float APIDDamping{ set { return; } }
1271
1272 public override void SubscribeEvents(int ms)
1273 {
1274 m_requestedUpdateFrequency = ms;
1275 m_eventsubscription = ms;
1276
1277 // Don't clear collision event reporting here. This is called directly from scene code and so can lead
1278 // to a race condition with the simulate loop
1279
1280 _parent_scene.AddCollisionEventReporting(this);
1281 }
1282
1283 public override void UnSubscribeEvents()
1284 {
1285 _parent_scene.RemoveCollisionEventReporting(this);
1286
1287 // Don't clear collision event reporting here. This is called directly from scene code and so can lead
1288 // to a race condition with the simulate loop
1289
1290 m_requestedUpdateFrequency = 0;
1291 m_eventsubscription = 0;
1292 }
1293
1294 internal void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
1295 {
1296 if (m_eventsubscription > 0)
1297 {
1298// m_log.DebugFormat(
1299// "[PHYSICS]: Adding collision event for {0}, collidedWith {1}, contact {2}", "", CollidedWith, contact);
1300
1301 CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
1302 }
1303 }
1304
1305 internal void SendCollisions()
1306 {
1307 if (m_eventsubscription > m_requestedUpdateFrequency)
1308 {
1309 base.SendCollisionUpdate(CollisionEventsThisFrame);
1310
1311 CollisionEventsThisFrame.Clear();
1312 m_eventsubscription = 0;
1313 }
1314 }
1315
1316 public override bool SubscribedEvents()
1317 {
1318 if (m_eventsubscription > 0)
1319 return true;
1320 return false;
1321 }
1322
1323 internal void ProcessTaints()
1324 {
1325 if (m_taintPosition != _position)
1326 {
1327 if (Body != IntPtr.Zero)
1328 {
1329 d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z);
1330 _position = m_taintPosition;
1331 }
1332 }
1333
1334 if (m_taintForce != Vector3.Zero)
1335 {
1336 if (Body != IntPtr.Zero)
1337 {
1338 // FIXME: This is not a good solution since it's subject to a race condition if a force is another
1339 // thread sets a new force while we're in this loop (since it could be obliterated by
1340 // m_taintForce = Vector3.Zero. Need to lock ProcessTaints() when we set a new tainted force.
1341 d.BodyAddForce(Body, m_taintForce.X, m_taintForce.Y, m_taintForce.Z);
1342 }
1343
1344 m_taintForce = Vector3.Zero;
1345 }
1346
1347 if (m_taintTargetVelocity != _target_velocity)
1348 _target_velocity = m_taintTargetVelocity;
1349
1350 if (m_tainted_isPhysical != m_isPhysical)
1351 {
1352 if (m_tainted_isPhysical)
1353 {
1354 CreateOdeStructures(_position.X, _position.Y, _position.Z, m_tensor);
1355 _parent_scene.AddCharacter(this);
1356 }
1357 else
1358 {
1359 _parent_scene.RemoveCharacter(this);
1360 DestroyOdeStructures();
1361 }
1362
1363 m_isPhysical = m_tainted_isPhysical;
1364 }
1365
1366 if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH)
1367 {
1368 if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero)
1369 {
1370// m_log.DebugFormat(
1371// "[ODE CHARACTER]: Changing capsule size from {0} to {1} for {2}",
1372// CAPSULE_LENGTH, m_tainted_CAPSULE_LENGTH, Name);
1373
1374 m_pidControllerActive = true;
1375
1376 // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate()
1377 DestroyOdeStructures();
1378
1379 float prevCapsule = CAPSULE_LENGTH;
1380 CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
1381
1382 CreateOdeStructures(
1383 _position.X,
1384 _position.Y,
1385 _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor);
1386
1387 // As with Size, we reset velocity. However, this isn't strictly necessary since it doesn't
1388 // appear to stall initial region crossings when done here. Being done for consistency.
1389// Velocity = Vector3.Zero;
1390 }
1391 else
1392 {
1393 m_log.Warn("[ODE CHARACTER]: trying to change capsule size for " + Name + ", but the following ODE data is missing - "
1394 + (Shell==IntPtr.Zero ? "Shell ":"")
1395 + (Body==IntPtr.Zero ? "Body ":"")
1396 + (Amotor==IntPtr.Zero ? "Amotor ":""));
1397 }
1398 }
1399 }
1400
1401 internal void AddCollisionFrameTime(int p)
1402 {
1403 // protect it from overflow crashing
1404 if (m_eventsubscription + p >= int.MaxValue)
1405 m_eventsubscription = 0;
1406 m_eventsubscription += p;
1407 }
1408 }
1409}
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments
new file mode 100644
index 0000000..1060aa6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments
@@ -0,0 +1,630 @@
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/PhysicsModules/Ode/ODEDynamics.cs b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs
new file mode 100644
index 0000000..8f8e2bd
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs
@@ -0,0 +1,974 @@
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.PhysicsModules.SharedBase;
50
51namespace OpenSim.Region.PhysicsModule.ODE
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/PhysicsModules/Ode/ODEPrim.cs b/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs
new file mode 100644
index 0000000..0b9c45f
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs
@@ -0,0 +1,3382 @@
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.PhysicsModules.SharedBase;
54
55namespace OpenSim.Region.PhysicsModule.ODE
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 bool m_assetFailed = false;
112
113 private Vector3 m_PIDTarget;
114 private float m_PIDTau;
115 private float PID_D = 35f;
116 private float PID_G = 25f;
117
118 // KF: These next 7 params apply to llSetHoverHeight(float height, integer water, float tau),
119 // and are for non-VEHICLES only.
120
121 private float m_PIDHoverHeight;
122 private float m_PIDHoverTau;
123 private bool m_useHoverPID;
124 private PIDHoverType m_PIDHoverType = PIDHoverType.Ground;
125 private float m_targetHoverHeight;
126 private float m_groundHeight;
127 private float m_waterHeight;
128 private float m_buoyancy; //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle.
129
130 // private float m_tensor = 5f;
131 private int body_autodisable_frames = 20;
132
133
134 private const CollisionCategories m_default_collisionFlags = (CollisionCategories.Geom
135 | CollisionCategories.Space
136 | CollisionCategories.Body
137 | CollisionCategories.Character
138 );
139 private bool m_taintshape;
140 private bool m_taintPhysics;
141 private bool m_collidesLand = true;
142 private bool m_collidesWater;
143
144 // Default we're a Geometry
145 private CollisionCategories m_collisionCategories = (CollisionCategories.Geom);
146
147 // Default, Collide with Other Geometries, spaces and Bodies
148 private CollisionCategories m_collisionFlags = m_default_collisionFlags;
149
150 public bool m_taintremove { get; private set; }
151 public bool m_taintdisable { get; private set; }
152 internal bool m_disabled;
153 public bool m_taintadd { get; private set; }
154 public bool m_taintselected { get; private set; }
155 public bool m_taintCollidesWater { get; private set; }
156
157 private bool m_taintforce = false;
158 private bool m_taintaddangularforce = false;
159 private Vector3 m_force;
160 private List<Vector3> m_forcelist = new List<Vector3>();
161 private List<Vector3> m_angularforcelist = new List<Vector3>();
162
163 private PrimitiveBaseShape _pbs;
164 private OdeScene _parent_scene;
165
166 /// <summary>
167 /// The physics space which contains prim geometries
168 /// </summary>
169 public IntPtr m_targetSpace = IntPtr.Zero;
170
171 /// <summary>
172 /// The prim geometry, used for collision detection.
173 /// </summary>
174 /// <remarks>
175 /// This is never null except for a brief period when the geometry needs to be replaced (due to resizing or
176 /// mesh change) or when the physical prim is being removed from the scene.
177 /// </remarks>
178 public IntPtr prim_geom { get; private set; }
179
180 public IntPtr _triMeshData { get; private set; }
181
182 private IntPtr _linkJointGroup = IntPtr.Zero;
183 private PhysicsActor _parent;
184 private PhysicsActor m_taintparent;
185
186 private List<OdePrim> childrenPrim = new List<OdePrim>();
187
188 private bool iscolliding;
189 private bool m_isSelected;
190
191 internal bool m_isVolumeDetect; // If true, this prim only detects collisions but doesn't collide actively
192
193 private bool m_throttleUpdates;
194 private int throttleCounter;
195 public int m_interpenetrationcount { get; private set; }
196 internal float m_collisionscore;
197 public int m_roundsUnderMotionThreshold { get; private set; }
198 private int m_crossingfailures;
199
200 public bool outofBounds { get; private set; }
201 private float m_density = 10.000006836f; // Aluminum g/cm3;
202
203 public bool _zeroFlag { get; private set; }
204 private bool m_lastUpdateSent;
205
206 public IntPtr Body = IntPtr.Zero;
207 private Vector3 _target_velocity;
208 private d.Mass pMass;
209
210 private int m_eventsubscription;
211 private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
212
213 /// <summary>
214 /// Signal whether there were collisions on the previous frame, so we know if we need to send the
215 /// empty CollisionEventsThisFrame to the prim so that it can detect the end of a collision.
216 /// </summary>
217 /// <remarks>
218 /// This is probably a temporary measure, pending storing this information consistently in CollisionEventUpdate itself.
219 /// </remarks>
220 private bool m_collisionsOnPreviousFrame;
221
222 private IntPtr m_linkJoint = IntPtr.Zero;
223
224 internal volatile bool childPrim;
225
226 private ODEDynamics m_vehicle;
227
228 internal int m_material = (int)Material.Wood;
229
230 public OdePrim(
231 String primName, OdeScene parent_scene, Vector3 pos, Vector3 size,
232 Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
233 {
234 Name = primName;
235 m_vehicle = new ODEDynamics();
236 //gc = GCHandle.Alloc(prim_geom, GCHandleType.Pinned);
237
238 if (!pos.IsFinite())
239 {
240 pos = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f),
241 parent_scene.GetTerrainHeightAtXY(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f)) + 0.5f);
242 m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Position for {0}", Name);
243 }
244 _position = pos;
245 m_taintposition = pos;
246 PID_D = parent_scene.bodyPIDD;
247 PID_G = parent_scene.bodyPIDG;
248 m_density = parent_scene.geomDefaultDensity;
249 // m_tensor = parent_scene.bodyMotorJointMaxforceTensor;
250 body_autodisable_frames = parent_scene.bodyFramesAutoDisable;
251
252 prim_geom = IntPtr.Zero;
253
254 if (!pos.IsFinite())
255 {
256 size = new Vector3(0.5f, 0.5f, 0.5f);
257 m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Size for {0}", Name);
258 }
259
260 if (size.X <= 0) size.X = 0.01f;
261 if (size.Y <= 0) size.Y = 0.01f;
262 if (size.Z <= 0) size.Z = 0.01f;
263
264 _size = size;
265 m_taintsize = _size;
266
267 if (!QuaternionIsFinite(rotation))
268 {
269 rotation = Quaternion.Identity;
270 m_log.WarnFormat("[PHYSICS]: Got nonFinite Object create Rotation for {0}", Name);
271 }
272
273 _orientation = rotation;
274 m_taintrot = _orientation;
275 _pbs = pbs;
276
277 _parent_scene = parent_scene;
278 m_targetSpace = (IntPtr)0;
279
280 if (pos.Z < 0)
281 {
282 IsPhysical = false;
283 }
284 else
285 {
286 IsPhysical = pisPhysical;
287 // If we're physical, we need to be in the master space for now.
288 // linksets *should* be in a space together.. but are not currently
289 if (IsPhysical)
290 m_targetSpace = _parent_scene.space;
291 }
292
293 m_taintadd = true;
294 m_assetFailed = false;
295 _parent_scene.AddPhysicsActorTaint(this);
296 }
297
298 public override int PhysicsActorType
299 {
300 get { return (int) ActorTypes.Prim; }
301 set { return; }
302 }
303
304 public override bool SetAlwaysRun
305 {
306 get { return false; }
307 set { return; }
308 }
309
310 public override bool Grabbed
311 {
312 set { return; }
313 }
314
315 public override bool Selected
316 {
317 set
318 {
319 // This only makes the object not collidable if the object
320 // is physical or the object is modified somehow *IN THE FUTURE*
321 // without this, if an avatar selects prim, they can walk right
322 // through it while it's selected
323 m_collisionscore = 0;
324
325 if ((IsPhysical && !_zeroFlag) || !value)
326 {
327 m_taintselected = value;
328 _parent_scene.AddPhysicsActorTaint(this);
329 }
330 else
331 {
332 m_taintselected = value;
333 m_isSelected = value;
334 }
335
336 if (m_isSelected)
337 disableBodySoft();
338 }
339 }
340
341 /// <summary>
342 /// Set a new geometry for this prim.
343 /// </summary>
344 /// <param name="geom"></param>
345 private void SetGeom(IntPtr geom)
346 {
347 prim_geom = geom;
348//Console.WriteLine("SetGeom to " + prim_geom + " for " + Name);
349
350 if (m_assetFailed)
351 {
352 d.GeomSetCategoryBits(prim_geom, 0);
353 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
354 }
355 else
356 {
357 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
358 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
359 }
360
361 _parent_scene.geom_name_map[prim_geom] = Name;
362 _parent_scene.actor_name_map[prim_geom] = this;
363
364 if (childPrim)
365 {
366 if (_parent != null && _parent is OdePrim)
367 {
368 OdePrim parent = (OdePrim)_parent;
369//Console.WriteLine("SetGeom calls ChildSetGeom");
370 parent.ChildSetGeom(this);
371 }
372 }
373 //m_log.Warn("Setting Geom to: " + prim_geom);
374 }
375
376 private void enableBodySoft()
377 {
378 if (!childPrim)
379 {
380 if (IsPhysical && Body != IntPtr.Zero)
381 {
382 d.BodyEnable(Body);
383 if (m_vehicle.Type != Vehicle.TYPE_NONE)
384 m_vehicle.Enable(Body, _parent_scene);
385 }
386
387 m_disabled = false;
388 }
389 }
390
391 private void disableBodySoft()
392 {
393 m_disabled = true;
394
395 if (IsPhysical && Body != IntPtr.Zero)
396 {
397 d.BodyDisable(Body);
398 }
399 }
400
401 /// <summary>
402 /// Make a prim subject to physics.
403 /// </summary>
404 private void enableBody()
405 {
406 // Don't enable this body if we're a child prim
407 // this should be taken care of in the parent function not here
408 if (!childPrim)
409 {
410 // Sets the geom to a body
411 Body = d.BodyCreate(_parent_scene.world);
412
413 setMass();
414 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
415 d.Quaternion myrot = new d.Quaternion();
416 myrot.X = _orientation.X;
417 myrot.Y = _orientation.Y;
418 myrot.Z = _orientation.Z;
419 myrot.W = _orientation.W;
420 d.BodySetQuaternion(Body, ref myrot);
421 d.GeomSetBody(prim_geom, Body);
422
423 if (m_assetFailed)
424 {
425 d.GeomSetCategoryBits(prim_geom, 0);
426 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
427 }
428 else
429 {
430 m_collisionCategories |= CollisionCategories.Body;
431 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
432 }
433
434 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
435 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
436
437 d.BodySetAutoDisableFlag(Body, true);
438 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
439
440 // disconnect from world gravity so we can apply buoyancy
441 d.BodySetGravityMode (Body, false);
442
443 m_interpenetrationcount = 0;
444 m_collisionscore = 0;
445 m_disabled = false;
446
447 // The body doesn't already have a finite rotation mode set here
448 if ((!m_angularlock.ApproxEquals(Vector3.One, 0.0f)) && _parent == null)
449 {
450 createAMotor(m_angularlock);
451 }
452 if (m_vehicle.Type != Vehicle.TYPE_NONE)
453 {
454 m_vehicle.Enable(Body, _parent_scene);
455 }
456
457 _parent_scene.ActivatePrim(this);
458 }
459 }
460
461 #region Mass Calculation
462
463 private float CalculateMass()
464 {
465 float volume = _size.X * _size.Y * _size.Z; // default
466 float tmp;
467
468 float returnMass = 0;
469 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
470 float hollowVolume = hollowAmount * hollowAmount;
471
472 switch (_pbs.ProfileShape)
473 {
474 case ProfileShape.Square:
475 // default box
476
477 if (_pbs.PathCurve == (byte)Extrusion.Straight)
478 {
479 if (hollowAmount > 0.0)
480 {
481 switch (_pbs.HollowShape)
482 {
483 case HollowShape.Square:
484 case HollowShape.Same:
485 break;
486
487 case HollowShape.Circle:
488
489 hollowVolume *= 0.78539816339f;
490 break;
491
492 case HollowShape.Triangle:
493
494 hollowVolume *= (0.5f * .5f);
495 break;
496
497 default:
498 hollowVolume = 0;
499 break;
500 }
501 volume *= (1.0f - hollowVolume);
502 }
503 }
504
505 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
506 {
507 //a tube
508
509 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
510 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
511 volume -= volume*tmp*tmp;
512
513 if (hollowAmount > 0.0)
514 {
515 hollowVolume *= hollowAmount;
516
517 switch (_pbs.HollowShape)
518 {
519 case HollowShape.Square:
520 case HollowShape.Same:
521 break;
522
523 case HollowShape.Circle:
524 hollowVolume *= 0.78539816339f;;
525 break;
526
527 case HollowShape.Triangle:
528 hollowVolume *= 0.5f * 0.5f;
529 break;
530 default:
531 hollowVolume = 0;
532 break;
533 }
534 volume *= (1.0f - hollowVolume);
535 }
536 }
537
538 break;
539
540 case ProfileShape.Circle:
541
542 if (_pbs.PathCurve == (byte)Extrusion.Straight)
543 {
544 volume *= 0.78539816339f; // elipse base
545
546 if (hollowAmount > 0.0)
547 {
548 switch (_pbs.HollowShape)
549 {
550 case HollowShape.Same:
551 case HollowShape.Circle:
552 break;
553
554 case HollowShape.Square:
555 hollowVolume *= 0.5f * 2.5984480504799f;
556 break;
557
558 case HollowShape.Triangle:
559 hollowVolume *= .5f * 1.27323954473516f;
560 break;
561
562 default:
563 hollowVolume = 0;
564 break;
565 }
566 volume *= (1.0f - hollowVolume);
567 }
568 }
569
570 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
571 {
572 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
573 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
574 volume *= (1.0f - tmp * tmp);
575
576 if (hollowAmount > 0.0)
577 {
578
579 // calculate the hollow volume by it's shape compared to the prim shape
580 hollowVolume *= hollowAmount;
581
582 switch (_pbs.HollowShape)
583 {
584 case HollowShape.Same:
585 case HollowShape.Circle:
586 break;
587
588 case HollowShape.Square:
589 hollowVolume *= 0.5f * 2.5984480504799f;
590 break;
591
592 case HollowShape.Triangle:
593 hollowVolume *= .5f * 1.27323954473516f;
594 break;
595
596 default:
597 hollowVolume = 0;
598 break;
599 }
600 volume *= (1.0f - hollowVolume);
601 }
602 }
603 break;
604
605 case ProfileShape.HalfCircle:
606 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
607 {
608 volume *= 0.52359877559829887307710723054658f;
609 }
610 break;
611
612 case ProfileShape.EquilateralTriangle:
613
614 if (_pbs.PathCurve == (byte)Extrusion.Straight)
615 {
616 volume *= 0.32475953f;
617
618 if (hollowAmount > 0.0)
619 {
620
621 // calculate the hollow volume by it's shape compared to the prim shape
622 switch (_pbs.HollowShape)
623 {
624 case HollowShape.Same:
625 case HollowShape.Triangle:
626 hollowVolume *= .25f;
627 break;
628
629 case HollowShape.Square:
630 hollowVolume *= 0.499849f * 3.07920140172638f;
631 break;
632
633 case HollowShape.Circle:
634 // Hollow shape is a perfect cyllinder in respect to the cube's scale
635 // Cyllinder hollow volume calculation
636
637 hollowVolume *= 0.1963495f * 3.07920140172638f;
638 break;
639
640 default:
641 hollowVolume = 0;
642 break;
643 }
644 volume *= (1.0f - hollowVolume);
645 }
646 }
647 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
648 {
649 volume *= 0.32475953f;
650 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
651 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
652 volume *= (1.0f - tmp * tmp);
653
654 if (hollowAmount > 0.0)
655 {
656
657 hollowVolume *= hollowAmount;
658
659 switch (_pbs.HollowShape)
660 {
661 case HollowShape.Same:
662 case HollowShape.Triangle:
663 hollowVolume *= .25f;
664 break;
665
666 case HollowShape.Square:
667 hollowVolume *= 0.499849f * 3.07920140172638f;
668 break;
669
670 case HollowShape.Circle:
671
672 hollowVolume *= 0.1963495f * 3.07920140172638f;
673 break;
674
675 default:
676 hollowVolume = 0;
677 break;
678 }
679 volume *= (1.0f - hollowVolume);
680 }
681 }
682 break;
683
684 default:
685 break;
686 }
687
688 float taperX1;
689 float taperY1;
690 float taperX;
691 float taperY;
692 float pathBegin;
693 float pathEnd;
694 float profileBegin;
695 float profileEnd;
696
697 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
698 {
699 taperX1 = _pbs.PathScaleX * 0.01f;
700 if (taperX1 > 1.0f)
701 taperX1 = 2.0f - taperX1;
702 taperX = 1.0f - taperX1;
703
704 taperY1 = _pbs.PathScaleY * 0.01f;
705 if (taperY1 > 1.0f)
706 taperY1 = 2.0f - taperY1;
707 taperY = 1.0f - taperY1;
708 }
709 else
710 {
711 taperX = _pbs.PathTaperX * 0.01f;
712 if (taperX < 0.0f)
713 taperX = -taperX;
714 taperX1 = 1.0f - taperX;
715
716 taperY = _pbs.PathTaperY * 0.01f;
717 if (taperY < 0.0f)
718 taperY = -taperY;
719 taperY1 = 1.0f - taperY;
720 }
721
722 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
723
724 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
725 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
726 volume *= (pathEnd - pathBegin);
727
728// this is crude aproximation
729 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
730 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
731 volume *= (profileEnd - profileBegin);
732
733 returnMass = m_density * volume;
734
735 if (returnMass <= 0)
736 returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
737// else if (returnMass > _parent_scene.maximumMassObject)
738// returnMass = _parent_scene.maximumMassObject;
739
740 // Recursively calculate mass
741 bool HasChildPrim = false;
742 lock (childrenPrim)
743 {
744 if (childrenPrim.Count > 0)
745 {
746 HasChildPrim = true;
747 }
748 }
749
750 if (HasChildPrim)
751 {
752 OdePrim[] childPrimArr = new OdePrim[0];
753
754 lock (childrenPrim)
755 childPrimArr = childrenPrim.ToArray();
756
757 for (int i = 0; i < childPrimArr.Length; i++)
758 {
759 if (childPrimArr[i] != null && !childPrimArr[i].m_taintremove)
760 returnMass += childPrimArr[i].CalculateMass();
761 // failsafe, this shouldn't happen but with OpenSim, you never know :)
762 if (i > 256)
763 break;
764 }
765 }
766
767 if (returnMass > _parent_scene.maximumMassObject)
768 returnMass = _parent_scene.maximumMassObject;
769
770 return returnMass;
771 }
772
773 #endregion
774
775 private void setMass()
776 {
777 if (Body != (IntPtr) 0)
778 {
779 float newmass = CalculateMass();
780
781 //m_log.Info("[PHYSICS]: New Mass: " + newmass.ToString());
782
783 d.MassSetBoxTotal(out pMass, newmass, _size.X, _size.Y, _size.Z);
784 d.BodySetMass(Body, ref pMass);
785 }
786 }
787
788 private void setAngularVelocity(float x, float y, float z)
789 {
790 if (Body != (IntPtr)0)
791 {
792 d.BodySetAngularVel(Body, x, y, z);
793 }
794 }
795
796 /// <summary>
797 /// Stop a prim from being subject to physics.
798 /// </summary>
799 internal void disableBody()
800 {
801 //this kills the body so things like 'mesh' can re-create it.
802 lock (this)
803 {
804 if (!childPrim)
805 {
806 if (Body != IntPtr.Zero)
807 {
808 _parent_scene.DeactivatePrim(this);
809 m_collisionCategories &= ~CollisionCategories.Body;
810 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
811
812 if (m_assetFailed)
813 {
814 d.GeomSetCategoryBits(prim_geom, 0);
815 d.GeomSetCollideBits(prim_geom, 0);
816 }
817 else
818 {
819 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
820 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
821 }
822
823 d.BodyDestroy(Body);
824 lock (childrenPrim)
825 {
826 if (childrenPrim.Count > 0)
827 {
828 foreach (OdePrim prm in childrenPrim)
829 {
830 _parent_scene.DeactivatePrim(prm);
831 prm.Body = IntPtr.Zero;
832 }
833 }
834 }
835 Body = IntPtr.Zero;
836 }
837 }
838 else
839 {
840 _parent_scene.DeactivatePrim(this);
841
842 m_collisionCategories &= ~CollisionCategories.Body;
843 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
844
845 if (m_assetFailed)
846 {
847 d.GeomSetCategoryBits(prim_geom, 0);
848 d.GeomSetCollideBits(prim_geom, 0);
849 }
850 else
851 {
852
853 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
854 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
855 }
856
857 Body = IntPtr.Zero;
858 }
859 }
860
861 m_disabled = true;
862 m_collisionscore = 0;
863 }
864
865 private static Dictionary<IMesh, IntPtr> m_MeshToTriMeshMap = new Dictionary<IMesh, IntPtr>();
866
867 private void setMesh(OdeScene parent_scene, IMesh mesh)
868 {
869// m_log.DebugFormat("[ODE PRIM]: Setting mesh on {0} to {1}", Name, mesh);
870
871 // This sleeper is there to moderate how long it takes between
872 // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object
873
874 //Thread.Sleep(10);
875
876 //Kill Body so that mesh can re-make the geom
877 if (IsPhysical && Body != IntPtr.Zero)
878 {
879 if (childPrim)
880 {
881 if (_parent != null)
882 {
883 OdePrim parent = (OdePrim)_parent;
884 parent.ChildDelink(this);
885 }
886 }
887 else
888 {
889 disableBody();
890 }
891 }
892
893 IntPtr vertices, indices;
894 int vertexCount, indexCount;
895 int vertexStride, triStride;
896 mesh.getVertexListAsPtrToFloatArray(out vertices, out vertexStride, out vertexCount); // Note, that vertices are fixed in unmanaged heap
897 mesh.getIndexListAsPtrToIntArray(out indices, out triStride, out indexCount); // Also fixed, needs release after usage
898 m_expectedCollisionContacts = indexCount;
899 mesh.releaseSourceMeshData(); // free up the original mesh data to save memory
900
901 // We must lock here since m_MeshToTriMeshMap is static and multiple scene threads may call this method at
902 // the same time.
903 lock (m_MeshToTriMeshMap)
904 {
905 if (m_MeshToTriMeshMap.ContainsKey(mesh))
906 {
907 _triMeshData = m_MeshToTriMeshMap[mesh];
908 }
909 else
910 {
911 _triMeshData = d.GeomTriMeshDataCreate();
912
913 d.GeomTriMeshDataBuildSimple(_triMeshData, vertices, vertexStride, vertexCount, indices, indexCount, triStride);
914 d.GeomTriMeshDataPreprocess(_triMeshData);
915 m_MeshToTriMeshMap[mesh] = _triMeshData;
916 }
917 }
918
919// _parent_scene.waitForSpaceUnlock(m_targetSpace);
920 try
921 {
922 SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null));
923 }
924 catch (AccessViolationException)
925 {
926 m_log.ErrorFormat("[PHYSICS]: MESH LOCKED FOR {0}", Name);
927 return;
928 }
929
930 // if (IsPhysical && Body == (IntPtr) 0)
931 // {
932 // Recreate the body
933 // m_interpenetrationcount = 0;
934 // m_collisionscore = 0;
935
936 // enableBody();
937 // }
938 }
939
940 internal void ProcessTaints()
941 {
942#if SPAM
943Console.WriteLine("ZProcessTaints for " + Name);
944#endif
945
946 // This must be processed as the very first taint so that later operations have a prim_geom to work with
947 // if this is a new prim.
948 if (m_taintadd)
949 changeadd();
950
951 if (!_position.ApproxEquals(m_taintposition, 0f))
952 changemove();
953
954 if (m_taintrot != _orientation)
955 {
956 if (childPrim && IsPhysical) // For physical child prim...
957 {
958 rotate();
959 // KF: ODE will also rotate the parent prim!
960 // so rotate the root back to where it was
961 OdePrim parent = (OdePrim)_parent;
962 parent.rotate();
963 }
964 else
965 {
966 //Just rotate the prim
967 rotate();
968 }
969 }
970
971 if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent))
972 changePhysicsStatus();
973
974 if (!_size.ApproxEquals(m_taintsize, 0f))
975 changesize();
976
977 if (m_taintshape)
978 changeshape();
979
980 if (m_taintforce)
981 changeAddForce();
982
983 if (m_taintaddangularforce)
984 changeAddAngularForce();
985
986 if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f))
987 changeSetTorque();
988
989 if (m_taintdisable)
990 changedisable();
991
992 if (m_taintselected != m_isSelected)
993 changeSelectedStatus();
994
995 if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f))
996 changevelocity();
997
998 if (m_taintparent != _parent)
999 changelink();
1000
1001 if (m_taintCollidesWater != m_collidesWater)
1002 changefloatonwater();
1003
1004 if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f))
1005 changeAngularLock();
1006 }
1007
1008 /// <summary>
1009 /// Change prim in response to an angular lock taint.
1010 /// </summary>
1011 private void changeAngularLock()
1012 {
1013 // do we have a Physical object?
1014 if (Body != IntPtr.Zero)
1015 {
1016 //Check that we have a Parent
1017 //If we have a parent then we're not authorative here
1018 if (_parent == null)
1019 {
1020 if (!m_taintAngularLock.ApproxEquals(Vector3.One, 0f))
1021 {
1022 //d.BodySetFiniteRotationMode(Body, 0);
1023 //d.BodySetFiniteRotationAxis(Body,m_taintAngularLock.X,m_taintAngularLock.Y,m_taintAngularLock.Z);
1024 createAMotor(m_taintAngularLock);
1025 }
1026 else
1027 {
1028 if (Amotor != IntPtr.Zero)
1029 {
1030 d.JointDestroy(Amotor);
1031 Amotor = IntPtr.Zero;
1032 }
1033 }
1034 }
1035 }
1036
1037 // Store this for later in case we get turned into a separate body
1038 m_angularlock = m_taintAngularLock;
1039 }
1040
1041 /// <summary>
1042 /// Change prim in response to a link taint.
1043 /// </summary>
1044 private void changelink()
1045 {
1046 // If the newly set parent is not null
1047 // create link
1048 if (_parent == null && m_taintparent != null)
1049 {
1050 if (m_taintparent.PhysicsActorType == (int)ActorTypes.Prim)
1051 {
1052 OdePrim obj = (OdePrim)m_taintparent;
1053 //obj.disableBody();
1054//Console.WriteLine("changelink calls ParentPrim");
1055 obj.AddChildPrim(this);
1056
1057 /*
1058 if (obj.Body != (IntPtr)0 && Body != (IntPtr)0 && obj.Body != Body)
1059 {
1060 _linkJointGroup = d.JointGroupCreate(0);
1061 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1062 d.JointAttach(m_linkJoint, obj.Body, Body);
1063 d.JointSetFixed(m_linkJoint);
1064 }
1065 */
1066 }
1067 }
1068 // If the newly set parent is null
1069 // destroy link
1070 else if (_parent != null && m_taintparent == null)
1071 {
1072//Console.WriteLine(" changelink B");
1073
1074 if (_parent is OdePrim)
1075 {
1076 OdePrim obj = (OdePrim)_parent;
1077 obj.ChildDelink(this);
1078 childPrim = false;
1079 //_parent = null;
1080 }
1081
1082 /*
1083 if (Body != (IntPtr)0 && _linkJointGroup != (IntPtr)0)
1084 d.JointGroupDestroy(_linkJointGroup);
1085
1086 _linkJointGroup = (IntPtr)0;
1087 m_linkJoint = (IntPtr)0;
1088 */
1089 }
1090
1091 _parent = m_taintparent;
1092 m_taintPhysics = IsPhysical;
1093 }
1094
1095 /// <summary>
1096 /// Add a child prim to this parent prim.
1097 /// </summary>
1098 /// <param name="prim">Child prim</param>
1099 private void AddChildPrim(OdePrim prim)
1100 {
1101 if (LocalID == prim.LocalID)
1102 return;
1103
1104 if (Body == IntPtr.Zero)
1105 {
1106 Body = d.BodyCreate(_parent_scene.world);
1107 setMass();
1108 }
1109
1110 lock (childrenPrim)
1111 {
1112 if (childrenPrim.Contains(prim))
1113 return;
1114
1115// m_log.DebugFormat(
1116// "[ODE PRIM]: Linking prim {0} {1} to {2} {3}", prim.Name, prim.LocalID, Name, LocalID);
1117
1118 childrenPrim.Add(prim);
1119
1120 foreach (OdePrim prm in childrenPrim)
1121 {
1122 d.Mass m2;
1123 d.MassSetZero(out m2);
1124 d.MassSetBoxTotal(out m2, prm.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z);
1125
1126 d.Quaternion quat = new d.Quaternion();
1127 quat.W = prm._orientation.W;
1128 quat.X = prm._orientation.X;
1129 quat.Y = prm._orientation.Y;
1130 quat.Z = prm._orientation.Z;
1131
1132 d.Matrix3 mat = new d.Matrix3();
1133 d.RfromQ(out mat, ref quat);
1134 d.MassRotate(ref m2, ref mat);
1135 d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z);
1136 d.MassAdd(ref pMass, ref m2);
1137 }
1138
1139 foreach (OdePrim prm in childrenPrim)
1140 {
1141 prm.m_collisionCategories |= CollisionCategories.Body;
1142 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1143
1144//Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name);
1145 if (prm.m_assetFailed)
1146 {
1147 d.GeomSetCategoryBits(prm.prim_geom, 0);
1148 d.GeomSetCollideBits(prm.prim_geom, prm.BadMeshAssetCollideBits);
1149 }
1150 else
1151 {
1152 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories);
1153 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags);
1154 }
1155
1156 d.Quaternion quat = new d.Quaternion();
1157 quat.W = prm._orientation.W;
1158 quat.X = prm._orientation.X;
1159 quat.Y = prm._orientation.Y;
1160 quat.Z = prm._orientation.Z;
1161
1162 d.Matrix3 mat = new d.Matrix3();
1163 d.RfromQ(out mat, ref quat);
1164 if (Body != IntPtr.Zero)
1165 {
1166 d.GeomSetBody(prm.prim_geom, Body);
1167 prm.childPrim = true;
1168 d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z);
1169 //d.GeomSetOffsetPosition(prim.prim_geom,
1170 // (Position.X - prm.Position.X) - pMass.c.X,
1171 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1172 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1173 d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat);
1174 //d.GeomSetOffsetRotation(prm.prim_geom, ref mat);
1175 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1176 d.BodySetMass(Body, ref pMass);
1177 }
1178 else
1179 {
1180 m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name);
1181 }
1182
1183 prm.m_interpenetrationcount = 0;
1184 prm.m_collisionscore = 0;
1185 prm.m_disabled = false;
1186
1187 prm.Body = Body;
1188 _parent_scene.ActivatePrim(prm);
1189 }
1190
1191 m_collisionCategories |= CollisionCategories.Body;
1192 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1193
1194 if (m_assetFailed)
1195 {
1196 d.GeomSetCategoryBits(prim_geom, 0);
1197 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1198 }
1199 else
1200 {
1201 //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name);
1202 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1203 //Console.WriteLine(" Post GeomSetCategoryBits 2");
1204 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1205 }
1206
1207 d.Quaternion quat2 = new d.Quaternion();
1208 quat2.W = _orientation.W;
1209 quat2.X = _orientation.X;
1210 quat2.Y = _orientation.Y;
1211 quat2.Z = _orientation.Z;
1212
1213 d.Matrix3 mat2 = new d.Matrix3();
1214 d.RfromQ(out mat2, ref quat2);
1215 d.GeomSetBody(prim_geom, Body);
1216 d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z);
1217 //d.GeomSetOffsetPosition(prim.prim_geom,
1218 // (Position.X - prm.Position.X) - pMass.c.X,
1219 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1220 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1221 //d.GeomSetOffsetRotation(prim_geom, ref mat2);
1222 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1223 d.BodySetMass(Body, ref pMass);
1224
1225 d.BodySetAutoDisableFlag(Body, true);
1226 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1227
1228 m_interpenetrationcount = 0;
1229 m_collisionscore = 0;
1230 m_disabled = false;
1231
1232 // The body doesn't already have a finite rotation mode set here
1233 if ((!m_angularlock.ApproxEquals(Vector3.One, 0f)) && _parent == null)
1234 {
1235 createAMotor(m_angularlock);
1236 }
1237
1238 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1239
1240 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1241 m_vehicle.Enable(Body, _parent_scene);
1242
1243 _parent_scene.ActivatePrim(this);
1244 }
1245 }
1246
1247 private void ChildSetGeom(OdePrim odePrim)
1248 {
1249// m_log.DebugFormat(
1250// "[ODE PRIM]: ChildSetGeom {0} {1} for {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID);
1251
1252 //if (IsPhysical && Body != IntPtr.Zero)
1253 lock (childrenPrim)
1254 {
1255 foreach (OdePrim prm in childrenPrim)
1256 {
1257 //prm.childPrim = true;
1258 prm.disableBody();
1259 //prm.m_taintparent = null;
1260 //prm._parent = null;
1261 //prm.m_taintPhysics = false;
1262 //prm.m_disabled = true;
1263 //prm.childPrim = false;
1264 }
1265 }
1266
1267 disableBody();
1268
1269 // Spurious - Body == IntPtr.Zero after disableBody()
1270// if (Body != IntPtr.Zero)
1271// {
1272// _parent_scene.DeactivatePrim(this);
1273// }
1274
1275 lock (childrenPrim)
1276 {
1277 foreach (OdePrim prm in childrenPrim)
1278 {
1279//Console.WriteLine("ChildSetGeom calls ParentPrim");
1280 AddChildPrim(prm);
1281 }
1282 }
1283 }
1284
1285 private void ChildDelink(OdePrim odePrim)
1286 {
1287// m_log.DebugFormat(
1288// "[ODE PRIM]: Delinking prim {0} {1} from {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID);
1289
1290 // Okay, we have a delinked child.. need to rebuild the body.
1291 lock (childrenPrim)
1292 {
1293 foreach (OdePrim prm in childrenPrim)
1294 {
1295 prm.childPrim = true;
1296 prm.disableBody();
1297 //prm.m_taintparent = null;
1298 //prm._parent = null;
1299 //prm.m_taintPhysics = false;
1300 //prm.m_disabled = true;
1301 //prm.childPrim = false;
1302 }
1303 }
1304
1305 disableBody();
1306
1307 lock (childrenPrim)
1308 {
1309 //Console.WriteLine("childrenPrim.Remove " + odePrim);
1310 childrenPrim.Remove(odePrim);
1311 }
1312
1313 // Spurious - Body == IntPtr.Zero after disableBody()
1314// if (Body != IntPtr.Zero)
1315// {
1316// _parent_scene.DeactivatePrim(this);
1317// }
1318
1319 lock (childrenPrim)
1320 {
1321 foreach (OdePrim prm in childrenPrim)
1322 {
1323//Console.WriteLine("ChildDelink calls ParentPrim");
1324 AddChildPrim(prm);
1325 }
1326 }
1327 }
1328
1329 /// <summary>
1330 /// Change prim in response to a selection taint.
1331 /// </summary>
1332 private void changeSelectedStatus()
1333 {
1334 if (m_taintselected)
1335 {
1336 m_collisionCategories = CollisionCategories.Selected;
1337 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
1338
1339 // We do the body disable soft twice because 'in theory' a collision could have happened
1340 // in between the disabling and the collision properties setting
1341 // which would wake the physical body up from a soft disabling and potentially cause it to fall
1342 // through the ground.
1343
1344 // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select
1345 // just one part of the assembly, the rest of the assembly is non-selected and still simulating,
1346 // so that causes the selected part to wake up and continue moving.
1347
1348 // even if you select all parts of a jointed assembly, it is not guaranteed that the entire
1349 // assembly will stop simulating during the selection, because of the lack of atomicity
1350 // of select operations (their processing could be interrupted by a thread switch, causing
1351 // simulation to continue before all of the selected object notifications trickle down to
1352 // the physics engine).
1353
1354 // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are
1355 // selected and disabled. then, due to a thread switch, the selection processing is
1356 // interrupted and the physics engine continues to simulate, so the last 50 items, whose
1357 // selection was not yet processed, continues to simulate. this wakes up ALL of the
1358 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1359 // up, start simulating again, which in turn wakes up the last 50.
1360
1361 if (IsPhysical)
1362 {
1363 disableBodySoft();
1364 }
1365
1366 if (m_assetFailed)
1367 {
1368 d.GeomSetCategoryBits(prim_geom, 0);
1369 d.GeomSetCollideBits(prim_geom, 0);
1370 }
1371 else
1372 {
1373 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1374 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1375 }
1376
1377 if (IsPhysical)
1378 {
1379 disableBodySoft();
1380 }
1381 }
1382 else
1383 {
1384 m_collisionCategories = CollisionCategories.Geom;
1385
1386 if (IsPhysical)
1387 m_collisionCategories |= CollisionCategories.Body;
1388
1389 m_collisionFlags = m_default_collisionFlags;
1390
1391 if (m_collidesLand)
1392 m_collisionFlags |= CollisionCategories.Land;
1393 if (m_collidesWater)
1394 m_collisionFlags |= CollisionCategories.Water;
1395
1396 if (m_assetFailed)
1397 {
1398 d.GeomSetCategoryBits(prim_geom, 0);
1399 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1400 }
1401 else
1402 {
1403 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1404 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1405 }
1406
1407 if (IsPhysical)
1408 {
1409 if (Body != IntPtr.Zero)
1410 {
1411 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1412 d.BodySetForce(Body, 0, 0, 0);
1413 enableBodySoft();
1414 }
1415 }
1416 }
1417
1418 resetCollisionAccounting();
1419 m_isSelected = m_taintselected;
1420 }//end changeSelectedStatus
1421
1422 internal void ResetTaints()
1423 {
1424 m_taintposition = _position;
1425 m_taintrot = _orientation;
1426 m_taintPhysics = IsPhysical;
1427 m_taintselected = m_isSelected;
1428 m_taintsize = _size;
1429 m_taintshape = false;
1430 m_taintforce = false;
1431 m_taintdisable = false;
1432 m_taintVelocity = Vector3.Zero;
1433 }
1434
1435 /// <summary>
1436 /// Create a geometry for the given mesh in the given target space.
1437 /// </summary>
1438 /// <param name="m_targetSpace"></param>
1439 /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param>
1440 private void CreateGeom(IntPtr m_targetSpace, IMesh mesh)
1441 {
1442#if SPAM
1443Console.WriteLine("CreateGeom:");
1444#endif
1445 if (mesh != null)
1446 {
1447 setMesh(_parent_scene, mesh);
1448 }
1449 else
1450 {
1451 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
1452 {
1453 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
1454 {
1455 if (((_size.X / 2f) > 0f))
1456 {
1457// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1458 try
1459 {
1460//Console.WriteLine(" CreateGeom 1");
1461 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1462 m_expectedCollisionContacts = 3;
1463 }
1464 catch (AccessViolationException)
1465 {
1466 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1467 return;
1468 }
1469 }
1470 else
1471 {
1472// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1473 try
1474 {
1475//Console.WriteLine(" CreateGeom 2");
1476 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1477 m_expectedCollisionContacts = 4;
1478 }
1479 catch (AccessViolationException)
1480 {
1481 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1482 return;
1483 }
1484 }
1485 }
1486 else
1487 {
1488// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1489 try
1490 {
1491//Console.WriteLine(" CreateGeom 3");
1492 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1493 m_expectedCollisionContacts = 4;
1494 }
1495 catch (AccessViolationException)
1496 {
1497 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1498 return;
1499 }
1500 }
1501 }
1502 else
1503 {
1504// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1505 try
1506 {
1507//Console.WriteLine(" CreateGeom 4");
1508 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1509 m_expectedCollisionContacts = 4;
1510 }
1511 catch (AccessViolationException)
1512 {
1513 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1514 return;
1515 }
1516 }
1517 }
1518 }
1519
1520 /// <summary>
1521 /// Remove the existing geom from this prim.
1522 /// </summary>
1523 /// <param name="m_targetSpace"></param>
1524 /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param>
1525 /// <returns>true if the geom was successfully removed, false if it was already gone or the remove failed.</returns>
1526 internal bool RemoveGeom()
1527 {
1528 if (prim_geom != IntPtr.Zero)
1529 {
1530 try
1531 {
1532 _parent_scene.geom_name_map.Remove(prim_geom);
1533 _parent_scene.actor_name_map.Remove(prim_geom);
1534 d.GeomDestroy(prim_geom);
1535 m_expectedCollisionContacts = 0;
1536 prim_geom = IntPtr.Zero;
1537 }
1538 catch (System.AccessViolationException)
1539 {
1540 prim_geom = IntPtr.Zero;
1541 m_expectedCollisionContacts = 0;
1542 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
1543
1544 return false;
1545 }
1546
1547 return true;
1548 }
1549 else
1550 {
1551 m_log.WarnFormat(
1552 "[ODE PRIM]: Called RemoveGeom() on {0} {1} where geometry was already null.", Name, LocalID);
1553
1554 return false;
1555 }
1556 }
1557 /// <summary>
1558 /// Add prim in response to an add taint.
1559 /// </summary>
1560 private void changeadd()
1561 {
1562// m_log.DebugFormat("[ODE PRIM]: Adding prim {0}", Name);
1563
1564 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1565 IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position);
1566
1567 if (targetspace == IntPtr.Zero)
1568 targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
1569
1570 m_targetSpace = targetspace;
1571
1572 IMesh mesh = null;
1573
1574 if (_parent_scene.needsMeshing(_pbs))
1575 {
1576 // Don't need to re-enable body.. it's done in SetMesh
1577 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1578 // createmesh returns null when it's a shape that isn't a cube.
1579 // m_log.Debug(m_localID);
1580 if (mesh == null)
1581 CheckMeshAsset();
1582 else
1583 m_assetFailed = false;
1584 }
1585
1586#if SPAM
1587Console.WriteLine("changeadd 1");
1588#endif
1589 CreateGeom(m_targetSpace, mesh);
1590
1591 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1592 d.Quaternion myrot = new d.Quaternion();
1593 myrot.X = _orientation.X;
1594 myrot.Y = _orientation.Y;
1595 myrot.Z = _orientation.Z;
1596 myrot.W = _orientation.W;
1597 d.GeomSetQuaternion(prim_geom, ref myrot);
1598
1599 if (IsPhysical && Body == IntPtr.Zero)
1600 enableBody();
1601
1602 changeSelectedStatus();
1603
1604 m_taintadd = false;
1605 }
1606
1607 /// <summary>
1608 /// Move prim in response to a move taint.
1609 /// </summary>
1610 private void changemove()
1611 {
1612 if (IsPhysical)
1613 {
1614 if (!m_disabled && !m_taintremove && !childPrim)
1615 {
1616 if (Body == IntPtr.Zero)
1617 enableBody();
1618
1619 //Prim auto disable after 20 frames,
1620 //if you move it, re-enable the prim manually.
1621 if (_parent != null)
1622 {
1623 if (m_linkJoint != IntPtr.Zero)
1624 {
1625 d.JointDestroy(m_linkJoint);
1626 m_linkJoint = IntPtr.Zero;
1627 }
1628 }
1629
1630 if (Body != IntPtr.Zero)
1631 {
1632 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1633
1634 if (_parent != null)
1635 {
1636 OdePrim odParent = (OdePrim)_parent;
1637 if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body)
1638 {
1639// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used??
1640Console.WriteLine(" JointCreateFixed");
1641 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1642 d.JointAttach(m_linkJoint, Body, odParent.Body);
1643 d.JointSetFixed(m_linkJoint);
1644 }
1645 }
1646 d.BodyEnable(Body);
1647 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1648 {
1649 m_vehicle.Enable(Body, _parent_scene);
1650 }
1651 }
1652 else
1653 {
1654 m_log.WarnFormat("[PHYSICS]: Body for {0} still null after enableBody(). This is a crash scenario.", Name);
1655 }
1656 }
1657 //else
1658 // {
1659 //m_log.Debug("[BUG]: race!");
1660 //}
1661 }
1662
1663 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
1664 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1665// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1666
1667 IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
1668 m_targetSpace = tempspace;
1669
1670// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1671
1672 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1673
1674// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1675 d.SpaceAdd(m_targetSpace, prim_geom);
1676
1677 changeSelectedStatus();
1678
1679 resetCollisionAccounting();
1680 m_taintposition = _position;
1681 }
1682
1683 internal void Move(float timestep)
1684 {
1685 float fx = 0;
1686 float fy = 0;
1687 float fz = 0;
1688
1689 if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // KF: Only move root prims.
1690 {
1691 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1692 {
1693 // 'VEHICLES' are dealt with in ODEDynamics.cs
1694 m_vehicle.Step(timestep, _parent_scene);
1695 }
1696 else
1697 {
1698//Console.WriteLine("Move " + Name);
1699 if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009
1700 // NON-'VEHICLES' are dealt with here
1701// if (d.BodyIsEnabled(Body) && !m_angularlock.ApproxEquals(Vector3.Zero, 0.003f))
1702// {
1703// d.Vector3 avel2 = d.BodyGetAngularVel(Body);
1704// /*
1705// if (m_angularlock.X == 1)
1706// avel2.X = 0;
1707// if (m_angularlock.Y == 1)
1708// avel2.Y = 0;
1709// if (m_angularlock.Z == 1)
1710// avel2.Z = 0;
1711// d.BodySetAngularVel(Body, avel2.X, avel2.Y, avel2.Z);
1712// */
1713// }
1714 //float PID_P = 900.0f;
1715
1716 float m_mass = CalculateMass();
1717
1718// fz = 0f;
1719 //m_log.Info(m_collisionFlags.ToString());
1720
1721
1722 //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle.
1723 // would come from SceneObjectPart.cs, public void SetBuoyancy(float fvalue) , PhysActor.Buoyancy = fvalue; ??
1724 // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up
1725 // gravityz multiplier = 1 - m_buoyancy
1726 fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass;
1727
1728 if (PIDActive)
1729 {
1730//Console.WriteLine("PID " + Name);
1731 // KF - this is for object move? eg. llSetPos() ?
1732 //if (!d.BodyIsEnabled(Body))
1733 //d.BodySetForce(Body, 0f, 0f, 0f);
1734 // If we're using the PID controller, then we have no gravity
1735 //fz = (-1 * _parent_scene.gravityz) * m_mass; //KF: ?? Prims have no global gravity,so simply...
1736 fz = 0f;
1737
1738 // no lock; for now it's only called from within Simulate()
1739
1740 // If the PID Controller isn't active then we set our force
1741 // calculating base velocity to the current position
1742
1743 if ((m_PIDTau < 1) && (m_PIDTau != 0))
1744 {
1745 //PID_G = PID_G / m_PIDTau;
1746 m_PIDTau = 1;
1747 }
1748
1749 if ((PID_G - m_PIDTau) <= 0)
1750 {
1751 PID_G = m_PIDTau + 1;
1752 }
1753 //PidStatus = true;
1754
1755 // PhysicsVector vec = new PhysicsVector();
1756 d.Vector3 vel = d.BodyGetLinearVel(Body);
1757
1758 d.Vector3 pos = d.BodyGetPosition(Body);
1759 _target_velocity =
1760 new Vector3(
1761 (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep),
1762 (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep),
1763 (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep)
1764 );
1765
1766 // if velocity is zero, use position control; otherwise, velocity control
1767
1768 if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f))
1769 {
1770 // keep track of where we stopped. No more slippin' & slidin'
1771
1772 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1773 // react to the physics scene by moving it's position.
1774 // Avatar to Avatar collisions
1775 // Prim to avatar collisions
1776
1777 //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
1778 //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2);
1779 //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
1780 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
1781 d.BodySetLinearVel(Body, 0, 0, 0);
1782 d.BodyAddForce(Body, 0, 0, fz);
1783 return;
1784 }
1785 else
1786 {
1787 _zeroFlag = false;
1788
1789 // We're flying and colliding with something
1790 fx = ((_target_velocity.X) - vel.X) * (PID_D);
1791 fy = ((_target_velocity.Y) - vel.Y) * (PID_D);
1792
1793 // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P;
1794
1795 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
1796 }
1797 } // end if (PIDActive)
1798
1799 // Hover PID Controller needs to be mutually exlusive to MoveTo PID controller
1800 if (m_useHoverPID && !PIDActive)
1801 {
1802//Console.WriteLine("Hover " + Name);
1803
1804 // If we're using the PID controller, then we have no gravity
1805 fz = (-1 * _parent_scene.gravityz) * m_mass;
1806
1807 // no lock; for now it's only called from within Simulate()
1808
1809 // If the PID Controller isn't active then we set our force
1810 // calculating base velocity to the current position
1811
1812 if ((m_PIDTau < 1))
1813 {
1814 PID_G = PID_G / m_PIDTau;
1815 }
1816
1817 if ((PID_G - m_PIDTau) <= 0)
1818 {
1819 PID_G = m_PIDTau + 1;
1820 }
1821
1822 // Where are we, and where are we headed?
1823 d.Vector3 pos = d.BodyGetPosition(Body);
1824 d.Vector3 vel = d.BodyGetLinearVel(Body);
1825
1826 // Non-Vehicles have a limited set of Hover options.
1827 // determine what our target height really is based on HoverType
1828 switch (m_PIDHoverType)
1829 {
1830 case PIDHoverType.Ground:
1831 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
1832 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
1833 break;
1834 case PIDHoverType.GroundAndWater:
1835 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
1836 m_waterHeight = _parent_scene.GetWaterLevel();
1837 if (m_groundHeight > m_waterHeight)
1838 {
1839 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
1840 }
1841 else
1842 {
1843 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
1844 }
1845 break;
1846
1847 } // end switch (m_PIDHoverType)
1848
1849
1850 _target_velocity =
1851 new Vector3(0.0f, 0.0f,
1852 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
1853 );
1854
1855 // if velocity is zero, use position control; otherwise, velocity control
1856
1857 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
1858 {
1859 // keep track of where we stopped. No more slippin' & slidin'
1860
1861 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1862 // react to the physics scene by moving it's position.
1863 // Avatar to Avatar collisions
1864 // Prim to avatar collisions
1865
1866 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
1867 d.BodySetLinearVel(Body, vel.X, vel.Y, 0);
1868 d.BodyAddForce(Body, 0, 0, fz);
1869 return;
1870 }
1871 else
1872 {
1873 _zeroFlag = false;
1874
1875 // We're flying and colliding with something
1876 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
1877 }
1878 }
1879
1880 fx *= m_mass;
1881 fy *= m_mass;
1882 //fz *= m_mass;
1883
1884 fx += m_force.X;
1885 fy += m_force.Y;
1886 fz += m_force.Z;
1887
1888 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
1889 if (fx != 0 || fy != 0 || fz != 0)
1890 {
1891 //m_taintdisable = true;
1892 //base.RaiseOutOfBounds(Position);
1893 //d.BodySetLinearVel(Body, fx, fy, 0f);
1894 if (!d.BodyIsEnabled(Body))
1895 {
1896 // A physical body at rest on a surface will auto-disable after a while,
1897 // this appears to re-enable it incase the surface it is upon vanishes,
1898 // and the body should fall again.
1899 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1900 d.BodySetForce(Body, 0, 0, 0);
1901 enableBodySoft();
1902 }
1903
1904 // 35x10 = 350n times the mass per second applied maximum.
1905 float nmax = 35f * m_mass;
1906 float nmin = -35f * m_mass;
1907
1908 if (fx > nmax)
1909 fx = nmax;
1910 if (fx < nmin)
1911 fx = nmin;
1912 if (fy > nmax)
1913 fy = nmax;
1914 if (fy < nmin)
1915 fy = nmin;
1916 d.BodyAddForce(Body, fx, fy, fz);
1917//Console.WriteLine("AddForce " + fx + "," + fy + "," + fz);
1918 }
1919 }
1920 }
1921 else
1922 { // is not physical, or is not a body or is selected
1923 // _zeroPosition = d.BodyGetPosition(Body);
1924 return;
1925//Console.WriteLine("Nothing " + Name);
1926
1927 }
1928 }
1929
1930 private void rotate()
1931 {
1932 d.Quaternion myrot = new d.Quaternion();
1933 myrot.X = _orientation.X;
1934 myrot.Y = _orientation.Y;
1935 myrot.Z = _orientation.Z;
1936 myrot.W = _orientation.W;
1937 if (Body != IntPtr.Zero)
1938 {
1939 // KF: If this is a root prim do BodySet
1940 d.BodySetQuaternion(Body, ref myrot);
1941 if (IsPhysical)
1942 {
1943 if (!m_angularlock.ApproxEquals(Vector3.One, 0f))
1944 createAMotor(m_angularlock);
1945 }
1946 }
1947 else
1948 {
1949 // daughter prim, do Geom set
1950 d.GeomSetQuaternion(prim_geom, ref myrot);
1951 }
1952
1953 resetCollisionAccounting();
1954 m_taintrot = _orientation;
1955 }
1956
1957 private void resetCollisionAccounting()
1958 {
1959 m_collisionscore = 0;
1960 m_interpenetrationcount = 0;
1961 m_disabled = false;
1962 }
1963
1964 /// <summary>
1965 /// Change prim in response to a disable taint.
1966 /// </summary>
1967 private void changedisable()
1968 {
1969 m_disabled = true;
1970 if (Body != IntPtr.Zero)
1971 {
1972 d.BodyDisable(Body);
1973 Body = IntPtr.Zero;
1974 }
1975
1976 m_taintdisable = false;
1977 }
1978
1979 /// <summary>
1980 /// Change prim in response to a physics status taint
1981 /// </summary>
1982 private void changePhysicsStatus()
1983 {
1984 if (IsPhysical)
1985 {
1986 if (Body == IntPtr.Zero)
1987 {
1988 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
1989 {
1990 changeshape();
1991 }
1992 else
1993 {
1994 enableBody();
1995 }
1996 }
1997 }
1998 else
1999 {
2000 if (Body != IntPtr.Zero)
2001 {
2002 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2003 {
2004 RemoveGeom();
2005
2006//Console.WriteLine("changePhysicsStatus for " + Name);
2007 changeadd();
2008 }
2009
2010 if (childPrim)
2011 {
2012 if (_parent != null)
2013 {
2014 OdePrim parent = (OdePrim)_parent;
2015 parent.ChildDelink(this);
2016 }
2017 }
2018 else
2019 {
2020 disableBody();
2021 }
2022 }
2023 }
2024
2025 changeSelectedStatus();
2026
2027 resetCollisionAccounting();
2028 m_taintPhysics = IsPhysical;
2029 }
2030
2031 /// <summary>
2032 /// Change prim in response to a size taint.
2033 /// </summary>
2034 private void changesize()
2035 {
2036#if SPAM
2037 m_log.DebugFormat("[ODE PRIM]: Called changesize");
2038#endif
2039
2040 if (_size.X <= 0) _size.X = 0.01f;
2041 if (_size.Y <= 0) _size.Y = 0.01f;
2042 if (_size.Z <= 0) _size.Z = 0.01f;
2043
2044 //kill body to rebuild
2045 if (IsPhysical && Body != IntPtr.Zero)
2046 {
2047 if (childPrim)
2048 {
2049 if (_parent != null)
2050 {
2051 OdePrim parent = (OdePrim)_parent;
2052 parent.ChildDelink(this);
2053 }
2054 }
2055 else
2056 {
2057 disableBody();
2058 }
2059 }
2060
2061 if (d.SpaceQuery(m_targetSpace, prim_geom))
2062 {
2063// _parent_scene.waitForSpaceUnlock(m_targetSpace);
2064 d.SpaceRemove(m_targetSpace, prim_geom);
2065 }
2066
2067 RemoveGeom();
2068
2069 // we don't need to do space calculation because the client sends a position update also.
2070
2071 IMesh mesh = null;
2072
2073 // Construction of new prim
2074 if (_parent_scene.needsMeshing(_pbs))
2075 {
2076 float meshlod = _parent_scene.meshSculptLOD;
2077
2078 if (IsPhysical)
2079 meshlod = _parent_scene.MeshSculptphysicalLOD;
2080 // Don't need to re-enable body.. it's done in SetMesh
2081
2082 if (_parent_scene.needsMeshing(_pbs))
2083 {
2084 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
2085 if (mesh == null)
2086 CheckMeshAsset();
2087 else
2088 m_assetFailed = false;
2089 }
2090
2091 }
2092
2093 CreateGeom(m_targetSpace, mesh);
2094 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2095 d.Quaternion myrot = new d.Quaternion();
2096 myrot.X = _orientation.X;
2097 myrot.Y = _orientation.Y;
2098 myrot.Z = _orientation.Z;
2099 myrot.W = _orientation.W;
2100 d.GeomSetQuaternion(prim_geom, ref myrot);
2101
2102 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2103 if (IsPhysical && Body == IntPtr.Zero && !childPrim)
2104 {
2105 // Re creates body on size.
2106 // EnableBody also does setMass()
2107 enableBody();
2108 d.BodyEnable(Body);
2109 }
2110
2111 changeSelectedStatus();
2112
2113 if (childPrim)
2114 {
2115 if (_parent is OdePrim)
2116 {
2117 OdePrim parent = (OdePrim)_parent;
2118 parent.ChildSetGeom(this);
2119 }
2120 }
2121 resetCollisionAccounting();
2122 m_taintsize = _size;
2123 }
2124
2125 /// <summary>
2126 /// Change prim in response to a float on water taint.
2127 /// </summary>
2128 /// <param name="timestep"></param>
2129 private void changefloatonwater()
2130 {
2131 m_collidesWater = m_taintCollidesWater;
2132
2133 if (m_collidesWater)
2134 {
2135 m_collisionFlags |= CollisionCategories.Water;
2136 }
2137 else
2138 {
2139 m_collisionFlags &= ~CollisionCategories.Water;
2140 }
2141
2142 if (m_assetFailed)
2143 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
2144 else
2145
2146 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2147 }
2148 /// <summary>
2149 /// Change prim in response to a shape taint.
2150 /// </summary>
2151 private void changeshape()
2152 {
2153 m_taintshape = false;
2154
2155 // Cleanup of old prim geometry and Bodies
2156 if (IsPhysical && Body != IntPtr.Zero)
2157 {
2158 if (childPrim)
2159 {
2160 if (_parent != null)
2161 {
2162 OdePrim parent = (OdePrim)_parent;
2163 parent.ChildDelink(this);
2164 }
2165 }
2166 else
2167 {
2168 disableBody();
2169 }
2170 }
2171
2172 RemoveGeom();
2173
2174 // we don't need to do space calculation because the client sends a position update also.
2175 if (_size.X <= 0) _size.X = 0.01f;
2176 if (_size.Y <= 0) _size.Y = 0.01f;
2177 if (_size.Z <= 0) _size.Z = 0.01f;
2178 // Construction of new prim
2179
2180 IMesh mesh = null;
2181
2182
2183 if (_parent_scene.needsMeshing(_pbs))
2184 {
2185 // Don't need to re-enable body.. it's done in CreateMesh
2186 float meshlod = _parent_scene.meshSculptLOD;
2187
2188 if (IsPhysical)
2189 meshlod = _parent_scene.MeshSculptphysicalLOD;
2190
2191 // createmesh returns null when it doesn't mesh.
2192 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
2193 if (mesh == null)
2194 CheckMeshAsset();
2195 else
2196 m_assetFailed = false;
2197 }
2198
2199 CreateGeom(m_targetSpace, mesh);
2200 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2201 d.Quaternion myrot = new d.Quaternion();
2202 //myrot.W = _orientation.w;
2203 myrot.W = _orientation.W;
2204 myrot.X = _orientation.X;
2205 myrot.Y = _orientation.Y;
2206 myrot.Z = _orientation.Z;
2207 d.GeomSetQuaternion(prim_geom, ref myrot);
2208
2209 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2210 if (IsPhysical && Body == IntPtr.Zero)
2211 {
2212 // Re creates body on size.
2213 // EnableBody also does setMass()
2214 enableBody();
2215 if (Body != IntPtr.Zero)
2216 {
2217 d.BodyEnable(Body);
2218 }
2219 }
2220
2221 changeSelectedStatus();
2222
2223 if (childPrim)
2224 {
2225 if (_parent is OdePrim)
2226 {
2227 OdePrim parent = (OdePrim)_parent;
2228 parent.ChildSetGeom(this);
2229 }
2230 }
2231
2232 resetCollisionAccounting();
2233// m_taintshape = false;
2234 }
2235
2236 /// <summary>
2237 /// Change prim in response to an add force taint.
2238 /// </summary>
2239 private void changeAddForce()
2240 {
2241 if (!m_isSelected)
2242 {
2243 lock (m_forcelist)
2244 {
2245 //m_log.Info("[PHYSICS]: dequeing forcelist");
2246 if (IsPhysical)
2247 {
2248 Vector3 iforce = Vector3.Zero;
2249 int i = 0;
2250 try
2251 {
2252 for (i = 0; i < m_forcelist.Count; i++)
2253 {
2254
2255 iforce = iforce + (m_forcelist[i] * 100);
2256 }
2257 }
2258 catch (IndexOutOfRangeException)
2259 {
2260 m_forcelist = new List<Vector3>();
2261 m_collisionscore = 0;
2262 m_interpenetrationcount = 0;
2263 m_taintforce = false;
2264 return;
2265 }
2266 catch (ArgumentOutOfRangeException)
2267 {
2268 m_forcelist = new List<Vector3>();
2269 m_collisionscore = 0;
2270 m_interpenetrationcount = 0;
2271 m_taintforce = false;
2272 return;
2273 }
2274 d.BodyEnable(Body);
2275 d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
2276 }
2277 m_forcelist.Clear();
2278 }
2279
2280 m_collisionscore = 0;
2281 m_interpenetrationcount = 0;
2282 }
2283
2284 m_taintforce = false;
2285 }
2286
2287 /// <summary>
2288 /// Change prim in response to a torque taint.
2289 /// </summary>
2290 private void changeSetTorque()
2291 {
2292 if (!m_isSelected)
2293 {
2294 if (IsPhysical && Body != IntPtr.Zero)
2295 {
2296 d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z);
2297 }
2298 }
2299
2300 m_taintTorque = Vector3.Zero;
2301 }
2302
2303 /// <summary>
2304 /// Change prim in response to an angular force taint.
2305 /// </summary>
2306 private void changeAddAngularForce()
2307 {
2308 if (!m_isSelected)
2309 {
2310 lock (m_angularforcelist)
2311 {
2312 //m_log.Info("[PHYSICS]: dequeing forcelist");
2313 if (IsPhysical)
2314 {
2315 Vector3 iforce = Vector3.Zero;
2316 for (int i = 0; i < m_angularforcelist.Count; i++)
2317 {
2318 iforce = iforce + (m_angularforcelist[i] * 100);
2319 }
2320 d.BodyEnable(Body);
2321 d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z);
2322
2323 }
2324 m_angularforcelist.Clear();
2325 }
2326
2327 m_collisionscore = 0;
2328 m_interpenetrationcount = 0;
2329 }
2330
2331 m_taintaddangularforce = false;
2332 }
2333
2334 /// <summary>
2335 /// Change prim in response to a velocity taint.
2336 /// </summary>
2337 private void changevelocity()
2338 {
2339 if (!m_isSelected)
2340 {
2341 // Not sure exactly why this sleep is here, but from experimentation it appears to stop an avatar
2342 // walking through a default rez size prim if it keeps kicking it around - justincc.
2343 Thread.Sleep(20);
2344
2345 if (IsPhysical)
2346 {
2347 if (Body != IntPtr.Zero)
2348 {
2349 d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
2350 }
2351 }
2352
2353 //resetCollisionAccounting();
2354 }
2355
2356 m_taintVelocity = Vector3.Zero;
2357 }
2358
2359 internal void setPrimForRemoval()
2360 {
2361 m_taintremove = true;
2362 }
2363
2364 public override bool Flying
2365 {
2366 // no flying prims for you
2367 get { return false; }
2368 set { }
2369 }
2370
2371 public override bool IsColliding
2372 {
2373 get { return iscolliding; }
2374 set { iscolliding = value; }
2375 }
2376
2377 public override bool CollidingGround
2378 {
2379 get { return false; }
2380 set { return; }
2381 }
2382
2383 public override bool CollidingObj
2384 {
2385 get { return false; }
2386 set { return; }
2387 }
2388
2389 public override bool ThrottleUpdates
2390 {
2391 get { return m_throttleUpdates; }
2392 set { m_throttleUpdates = value; }
2393 }
2394
2395 public override bool Stopped
2396 {
2397 get { return _zeroFlag; }
2398 }
2399
2400 public override Vector3 Position
2401 {
2402 get { return _position; }
2403
2404 set { _position = value;
2405 //m_log.Info("[PHYSICS]: " + _position.ToString());
2406 }
2407 }
2408
2409 public override Vector3 Size
2410 {
2411 get { return _size; }
2412 set
2413 {
2414 if (value.IsFinite())
2415 {
2416 _size = value;
2417// m_log.DebugFormat("[PHYSICS]: Set size on {0} to {1}", Name, value);
2418 }
2419 else
2420 {
2421 m_log.WarnFormat("[PHYSICS]: Got NaN Size on object {0}", Name);
2422 }
2423 }
2424 }
2425
2426 public override float Mass
2427 {
2428 get { return CalculateMass(); }
2429 }
2430
2431 public override Vector3 Force
2432 {
2433 //get { return Vector3.Zero; }
2434 get { return m_force; }
2435 set
2436 {
2437 if (value.IsFinite())
2438 {
2439 m_force = value;
2440 }
2441 else
2442 {
2443 m_log.WarnFormat("[PHYSICS]: NaN in Force Applied to an Object {0}", Name);
2444 }
2445 }
2446 }
2447
2448 public override int VehicleType
2449 {
2450 get { return (int)m_vehicle.Type; }
2451 set { m_vehicle.ProcessTypeChange((Vehicle)value); }
2452 }
2453
2454 public override void VehicleFloatParam(int param, float value)
2455 {
2456 m_vehicle.ProcessFloatVehicleParam((Vehicle) param, value);
2457 }
2458
2459 public override void VehicleVectorParam(int param, Vector3 value)
2460 {
2461 m_vehicle.ProcessVectorVehicleParam((Vehicle) param, value);
2462 }
2463
2464 public override void VehicleRotationParam(int param, Quaternion rotation)
2465 {
2466 m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation);
2467 }
2468
2469 public override void VehicleFlags(int param, bool remove)
2470 {
2471 m_vehicle.ProcessVehicleFlags(param, remove);
2472 }
2473
2474 public override void SetVolumeDetect(int param)
2475 {
2476 // We have to lock the scene here so that an entire simulate loop either uses volume detect for all
2477 // possible collisions with this prim or for none of them.
2478 lock (_parent_scene.OdeLock)
2479 {
2480 m_isVolumeDetect = (param != 0);
2481 }
2482 }
2483
2484 public override Vector3 CenterOfMass
2485 {
2486 get { return Vector3.Zero; }
2487 }
2488
2489 public override Vector3 GeometricCenter
2490 {
2491 get { return Vector3.Zero; }
2492 }
2493
2494 public override PrimitiveBaseShape Shape
2495 {
2496 set
2497 {
2498 _pbs = value;
2499 m_assetFailed = false;
2500 m_taintshape = true;
2501 }
2502 }
2503
2504 public override Vector3 Velocity
2505 {
2506 get
2507 {
2508 // Average previous velocity with the new one so
2509 // client object interpolation works a 'little' better
2510 if (_zeroFlag)
2511 return Vector3.Zero;
2512
2513 Vector3 returnVelocity = Vector3.Zero;
2514 returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2'
2515 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f;
2516 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f;
2517 return returnVelocity;
2518 }
2519 set
2520 {
2521 if (value.IsFinite())
2522 {
2523 _velocity = value;
2524
2525 m_taintVelocity = value;
2526 _parent_scene.AddPhysicsActorTaint(this);
2527 }
2528 else
2529 {
2530 m_log.WarnFormat("[PHYSICS]: Got NaN Velocity in Object {0}", Name);
2531 }
2532
2533 }
2534 }
2535
2536 public override Vector3 Torque
2537 {
2538 get
2539 {
2540 if (!IsPhysical || Body == IntPtr.Zero)
2541 return Vector3.Zero;
2542
2543 return _torque;
2544 }
2545
2546 set
2547 {
2548 if (value.IsFinite())
2549 {
2550 m_taintTorque = value;
2551 _parent_scene.AddPhysicsActorTaint(this);
2552 }
2553 else
2554 {
2555 m_log.WarnFormat("[PHYSICS]: Got NaN Torque in Object {0}", Name);
2556 }
2557 }
2558 }
2559
2560 public override float CollisionScore
2561 {
2562 get { return m_collisionscore; }
2563 set { m_collisionscore = value; }
2564 }
2565
2566 public override bool Kinematic
2567 {
2568 get { return false; }
2569 set { }
2570 }
2571
2572 public override Quaternion Orientation
2573 {
2574 get { return _orientation; }
2575 set
2576 {
2577 if (QuaternionIsFinite(value))
2578 _orientation = value;
2579 else
2580 m_log.WarnFormat("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object {0}", Name);
2581 }
2582 }
2583
2584 private static bool QuaternionIsFinite(Quaternion q)
2585 {
2586 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
2587 return false;
2588 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
2589 return false;
2590 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
2591 return false;
2592 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
2593 return false;
2594 return true;
2595 }
2596
2597 public override Vector3 Acceleration
2598 {
2599 get { return _acceleration; }
2600 set { _acceleration = value; }
2601 }
2602
2603 public override void AddForce(Vector3 force, bool pushforce)
2604 {
2605 if (force.IsFinite())
2606 {
2607 lock (m_forcelist)
2608 m_forcelist.Add(force);
2609
2610 m_taintforce = true;
2611 }
2612 else
2613 {
2614 m_log.WarnFormat("[PHYSICS]: Got Invalid linear force vector from Scene in Object {0}", Name);
2615 }
2616 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
2617 }
2618
2619 public override void AddAngularForce(Vector3 force, bool pushforce)
2620 {
2621 if (force.IsFinite())
2622 {
2623 m_angularforcelist.Add(force);
2624 m_taintaddangularforce = true;
2625 }
2626 else
2627 {
2628 m_log.WarnFormat("[PHYSICS]: Got Invalid Angular force vector from Scene in Object {0}", Name);
2629 }
2630 }
2631
2632 public override Vector3 RotationalVelocity
2633 {
2634 get
2635 {
2636 Vector3 pv = Vector3.Zero;
2637 if (_zeroFlag)
2638 return pv;
2639 m_lastUpdateSent = false;
2640
2641 if (m_rotationalVelocity.ApproxEquals(pv, 0.2f))
2642 return pv;
2643
2644 return m_rotationalVelocity;
2645 }
2646 set
2647 {
2648 if (value.IsFinite())
2649 {
2650 m_rotationalVelocity = value;
2651 setAngularVelocity(value.X, value.Y, value.Z);
2652 }
2653 else
2654 {
2655 m_log.WarnFormat("[PHYSICS]: Got NaN RotationalVelocity in Object {0}", Name);
2656 }
2657 }
2658 }
2659
2660 public override void CrossingFailure()
2661 {
2662 m_crossingfailures++;
2663 if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds)
2664 {
2665 base.RaiseOutOfBounds(_position);
2666 return;
2667 }
2668 else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds)
2669 {
2670 m_log.Warn("[PHYSICS]: Too many crossing failures for: " + Name);
2671 }
2672 }
2673
2674 public override float Buoyancy
2675 {
2676 get { return m_buoyancy; }
2677 set { m_buoyancy = value; }
2678 }
2679
2680 public override void link(PhysicsActor obj)
2681 {
2682 m_taintparent = obj;
2683 }
2684
2685 public override void delink()
2686 {
2687 m_taintparent = null;
2688 }
2689
2690 public override void LockAngularMotion(Vector3 axis)
2691 {
2692 // reverse the zero/non zero values for ODE.
2693 if (axis.IsFinite())
2694 {
2695 axis.X = (axis.X > 0) ? 1f : 0f;
2696 axis.Y = (axis.Y > 0) ? 1f : 0f;
2697 axis.Z = (axis.Z > 0) ? 1f : 0f;
2698 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
2699 m_taintAngularLock = axis;
2700 }
2701 else
2702 {
2703 m_log.WarnFormat("[PHYSICS]: Got NaN locking axis from Scene on Object {0}", Name);
2704 }
2705 }
2706
2707 internal void UpdatePositionAndVelocity()
2708 {
2709 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
2710 if (_parent == null)
2711 {
2712 Vector3 pv = Vector3.Zero;
2713 bool lastZeroFlag = _zeroFlag;
2714 float m_minvelocity = 0;
2715 if (Body != (IntPtr)0) // FIXME -> or if it is a joint
2716 {
2717 d.Vector3 vec = d.BodyGetPosition(Body);
2718 d.Quaternion ori = d.BodyGetQuaternion(Body);
2719 d.Vector3 vel = d.BodyGetLinearVel(Body);
2720 d.Vector3 rotvel = d.BodyGetAngularVel(Body);
2721 d.Vector3 torque = d.BodyGetTorque(Body);
2722 _torque = new Vector3(torque.X, torque.Y, torque.Z);
2723 Vector3 l_position = Vector3.Zero;
2724 Quaternion l_orientation = Quaternion.Identity;
2725
2726 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
2727 //if (vec.X < 0.0f) { vec.X = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2728 //if (vec.Y < 0.0f) { vec.Y = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2729 //if (vec.X > 255.95f) { vec.X = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2730 //if (vec.Y > 255.95f) { vec.Y = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2731
2732 m_lastposition = _position;
2733 m_lastorientation = _orientation;
2734
2735 l_position.X = vec.X;
2736 l_position.Y = vec.Y;
2737 l_position.Z = vec.Z;
2738 l_orientation.X = ori.X;
2739 l_orientation.Y = ori.Y;
2740 l_orientation.Z = ori.Z;
2741 l_orientation.W = ori.W;
2742
2743 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)
2744 {
2745 //base.RaiseOutOfBounds(l_position);
2746
2747 if (m_crossingfailures < _parent_scene.geomCrossingFailuresBeforeOutofbounds)
2748 {
2749 _position = l_position;
2750 //_parent_scene.remActivePrim(this);
2751 if (_parent == null)
2752 base.RequestPhysicsterseUpdate();
2753 return;
2754 }
2755 else
2756 {
2757 if (_parent == null)
2758 base.RaiseOutOfBounds(l_position);
2759 return;
2760 }
2761 }
2762
2763 if (l_position.Z < 0)
2764 {
2765 // This is so prim that get lost underground don't fall forever and suck up
2766 //
2767 // Sim resources and memory.
2768 // Disables the prim's movement physics....
2769 // It's a hack and will generate a console message if it fails.
2770
2771 //IsPhysical = false;
2772 if (_parent == null)
2773 base.RaiseOutOfBounds(_position);
2774
2775 _acceleration.X = 0;
2776 _acceleration.Y = 0;
2777 _acceleration.Z = 0;
2778
2779 _velocity.X = 0;
2780 _velocity.Y = 0;
2781 _velocity.Z = 0;
2782 m_rotationalVelocity.X = 0;
2783 m_rotationalVelocity.Y = 0;
2784 m_rotationalVelocity.Z = 0;
2785
2786 if (_parent == null)
2787 base.RequestPhysicsterseUpdate();
2788
2789 m_throttleUpdates = false;
2790 throttleCounter = 0;
2791 _zeroFlag = true;
2792 //outofBounds = true;
2793 }
2794
2795 //float Adiff = 1.0f - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation));
2796//Console.WriteLine("Adiff " + Name + " = " + Adiff);
2797 if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
2798 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
2799 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02)
2800// && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.01))
2801 && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.0001)) // KF 0.01 is far to large
2802 {
2803 _zeroFlag = true;
2804//Console.WriteLine("ZFT 2");
2805 m_throttleUpdates = false;
2806 }
2807 else
2808 {
2809 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
2810 _zeroFlag = false;
2811 m_lastUpdateSent = false;
2812 //m_throttleUpdates = false;
2813 }
2814
2815 if (_zeroFlag)
2816 {
2817 _velocity.X = 0.0f;
2818 _velocity.Y = 0.0f;
2819 _velocity.Z = 0.0f;
2820
2821 _acceleration.X = 0;
2822 _acceleration.Y = 0;
2823 _acceleration.Z = 0;
2824
2825 //_orientation.w = 0f;
2826 //_orientation.X = 0f;
2827 //_orientation.Y = 0f;
2828 //_orientation.Z = 0f;
2829 m_rotationalVelocity.X = 0;
2830 m_rotationalVelocity.Y = 0;
2831 m_rotationalVelocity.Z = 0;
2832 if (!m_lastUpdateSent)
2833 {
2834 m_throttleUpdates = false;
2835 throttleCounter = 0;
2836 m_rotationalVelocity = pv;
2837
2838 if (_parent == null)
2839 {
2840 base.RequestPhysicsterseUpdate();
2841 }
2842
2843 m_lastUpdateSent = true;
2844 }
2845 }
2846 else
2847 {
2848 if (lastZeroFlag != _zeroFlag)
2849 {
2850 if (_parent == null)
2851 {
2852 base.RequestPhysicsterseUpdate();
2853 }
2854 }
2855
2856 m_lastVelocity = _velocity;
2857
2858 _position = l_position;
2859
2860 _velocity.X = vel.X;
2861 _velocity.Y = vel.Y;
2862 _velocity.Z = vel.Z;
2863
2864 _acceleration = ((_velocity - m_lastVelocity) / 0.1f);
2865 _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f);
2866 //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString());
2867
2868 // Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing...
2869 // it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large.
2870 // 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
2871 // adding these logical exclusion situations to maintain this where I think it was intended to be.
2872 if (m_throttleUpdates || PIDActive || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero))
2873 {
2874 m_minvelocity = 0.5f;
2875 }
2876 else
2877 {
2878 m_minvelocity = 0.02f;
2879 }
2880
2881 if (_velocity.ApproxEquals(pv, m_minvelocity))
2882 {
2883 m_rotationalVelocity = pv;
2884 }
2885 else
2886 {
2887 m_rotationalVelocity = new Vector3(rotvel.X, rotvel.Y, rotvel.Z);
2888 }
2889
2890 //m_log.Debug("ODE: " + m_rotationalVelocity.ToString());
2891 _orientation.X = ori.X;
2892 _orientation.Y = ori.Y;
2893 _orientation.Z = ori.Z;
2894 _orientation.W = ori.W;
2895 m_lastUpdateSent = false;
2896 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
2897 {
2898 if (_parent == null)
2899 {
2900 base.RequestPhysicsterseUpdate();
2901 }
2902 }
2903 else
2904 {
2905 throttleCounter++;
2906 }
2907 }
2908 m_lastposition = l_position;
2909 }
2910 else
2911 {
2912 // Not a body.. so Make sure the client isn't interpolating
2913 _velocity.X = 0;
2914 _velocity.Y = 0;
2915 _velocity.Z = 0;
2916
2917 _acceleration.X = 0;
2918 _acceleration.Y = 0;
2919 _acceleration.Z = 0;
2920
2921 m_rotationalVelocity.X = 0;
2922 m_rotationalVelocity.Y = 0;
2923 m_rotationalVelocity.Z = 0;
2924 _zeroFlag = true;
2925 }
2926 }
2927 }
2928
2929 public override bool FloatOnWater
2930 {
2931 set {
2932 m_taintCollidesWater = value;
2933 _parent_scene.AddPhysicsActorTaint(this);
2934 }
2935 }
2936
2937 public override void SetMomentum(Vector3 momentum)
2938 {
2939 }
2940
2941 public override Vector3 PIDTarget
2942 {
2943 set
2944 {
2945 if (value.IsFinite())
2946 {
2947 m_PIDTarget = value;
2948 }
2949 else
2950 m_log.WarnFormat("[PHYSICS]: Got NaN PIDTarget from Scene on Object {0}", Name);
2951 }
2952 }
2953 public override bool PIDActive { get; set; }
2954 public override float PIDTau { set { m_PIDTau = value; } }
2955
2956 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
2957 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
2958 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
2959 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
2960
2961 public override Quaternion APIDTarget{ set { return; } }
2962
2963 public override bool APIDActive{ set { return; } }
2964
2965 public override float APIDStrength{ set { return; } }
2966
2967 public override float APIDDamping{ set { return; } }
2968
2969 private void createAMotor(Vector3 axis)
2970 {
2971 if (Body == IntPtr.Zero)
2972 return;
2973
2974 if (Amotor != IntPtr.Zero)
2975 {
2976 d.JointDestroy(Amotor);
2977 Amotor = IntPtr.Zero;
2978 }
2979
2980 float axisnum = 3;
2981
2982 axisnum = (axisnum - (axis.X + axis.Y + axis.Z));
2983
2984 // PhysicsVector totalSize = new PhysicsVector(_size.X, _size.Y, _size.Z);
2985
2986
2987 // Inverse Inertia Matrix, set the X, Y, and/r Z inertia to 0 then invert it again.
2988 d.Mass objMass;
2989 d.MassSetZero(out objMass);
2990 DMassCopy(ref pMass, ref objMass);
2991
2992 //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);
2993
2994 Matrix4 dMassMat = FromDMass(objMass);
2995
2996 Matrix4 mathmat = Inverse(dMassMat);
2997
2998 /*
2999 //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]);
3000
3001 mathmat = Inverse(mathmat);
3002
3003
3004 objMass = FromMatrix4(mathmat, ref objMass);
3005 //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);
3006
3007 mathmat = Inverse(mathmat);
3008 */
3009 if (axis.X == 0)
3010 {
3011 mathmat.M33 = 50.0000001f;
3012 //objMass.I.M22 = 0;
3013 }
3014 if (axis.Y == 0)
3015 {
3016 mathmat.M22 = 50.0000001f;
3017 //objMass.I.M11 = 0;
3018 }
3019 if (axis.Z == 0)
3020 {
3021 mathmat.M11 = 50.0000001f;
3022 //objMass.I.M00 = 0;
3023 }
3024
3025
3026
3027 mathmat = Inverse(mathmat);
3028 objMass = FromMatrix4(mathmat, ref objMass);
3029 //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);
3030
3031 //return;
3032 if (d.MassCheck(ref objMass))
3033 {
3034 d.BodySetMass(Body, ref objMass);
3035 }
3036 else
3037 {
3038 //m_log.Debug("[PHYSICS]: Mass invalid, ignoring");
3039 }
3040
3041 if (axisnum <= 0)
3042 return;
3043 // int dAMotorEuler = 1;
3044
3045 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
3046 d.JointAttach(Amotor, Body, IntPtr.Zero);
3047 d.JointSetAMotorMode(Amotor, 0);
3048
3049 d.JointSetAMotorNumAxes(Amotor,(int)axisnum);
3050 int i = 0;
3051
3052 if (axis.X == 0)
3053 {
3054 d.JointSetAMotorAxis(Amotor, i, 0, 1, 0, 0);
3055 i++;
3056 }
3057
3058 if (axis.Y == 0)
3059 {
3060 d.JointSetAMotorAxis(Amotor, i, 0, 0, 1, 0);
3061 i++;
3062 }
3063
3064 if (axis.Z == 0)
3065 {
3066 d.JointSetAMotorAxis(Amotor, i, 0, 0, 0, 1);
3067 i++;
3068 }
3069
3070 for (int j = 0; j < (int)axisnum; j++)
3071 {
3072 //d.JointSetAMotorAngle(Amotor, j, 0);
3073 }
3074
3075 //d.JointSetAMotorAngle(Amotor, 1, 0);
3076 //d.JointSetAMotorAngle(Amotor, 2, 0);
3077
3078 // These lowstops and high stops are effectively (no wiggle room)
3079 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0f);
3080 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f);
3081 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0f);
3082 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f);
3083 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f);
3084 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f);
3085 //d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 9000f);
3086 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
3087 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, Mass * 50f);//
3088 }
3089
3090 private Matrix4 FromDMass(d.Mass pMass)
3091 {
3092 Matrix4 obj;
3093 obj.M11 = pMass.I.M00;
3094 obj.M12 = pMass.I.M01;
3095 obj.M13 = pMass.I.M02;
3096 obj.M14 = 0;
3097 obj.M21 = pMass.I.M10;
3098 obj.M22 = pMass.I.M11;
3099 obj.M23 = pMass.I.M12;
3100 obj.M24 = 0;
3101 obj.M31 = pMass.I.M20;
3102 obj.M32 = pMass.I.M21;
3103 obj.M33 = pMass.I.M22;
3104 obj.M34 = 0;
3105 obj.M41 = 0;
3106 obj.M42 = 0;
3107 obj.M43 = 0;
3108 obj.M44 = 1;
3109 return obj;
3110 }
3111
3112 private d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj)
3113 {
3114 obj.I.M00 = pMat[0, 0];
3115 obj.I.M01 = pMat[0, 1];
3116 obj.I.M02 = pMat[0, 2];
3117 obj.I.M10 = pMat[1, 0];
3118 obj.I.M11 = pMat[1, 1];
3119 obj.I.M12 = pMat[1, 2];
3120 obj.I.M20 = pMat[2, 0];
3121 obj.I.M21 = pMat[2, 1];
3122 obj.I.M22 = pMat[2, 2];
3123 return obj;
3124 }
3125
3126 public override void SubscribeEvents(int ms)
3127 {
3128 m_eventsubscription = ms;
3129 _parent_scene.AddCollisionEventReporting(this);
3130 }
3131
3132 public override void UnSubscribeEvents()
3133 {
3134 _parent_scene.RemoveCollisionEventReporting(this);
3135 m_eventsubscription = 0;
3136 }
3137
3138 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
3139 {
3140 CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
3141 }
3142
3143 public void SendCollisions()
3144 {
3145 if (m_collisionsOnPreviousFrame || CollisionEventsThisFrame.Count > 0)
3146 {
3147 base.SendCollisionUpdate(CollisionEventsThisFrame);
3148
3149 if (CollisionEventsThisFrame.Count > 0)
3150 {
3151 m_collisionsOnPreviousFrame = true;
3152 CollisionEventsThisFrame.Clear();
3153 }
3154 else
3155 {
3156 m_collisionsOnPreviousFrame = false;
3157 }
3158 }
3159 }
3160
3161 public override bool SubscribedEvents()
3162 {
3163 if (m_eventsubscription > 0)
3164 return true;
3165 return false;
3166 }
3167
3168 public static Matrix4 Inverse(Matrix4 pMat)
3169 {
3170 if (determinant3x3(pMat) == 0)
3171 {
3172 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible
3173 }
3174
3175 return (Adjoint(pMat) / determinant3x3(pMat));
3176 }
3177
3178 public static Matrix4 Adjoint(Matrix4 pMat)
3179 {
3180 Matrix4 adjointMatrix = new Matrix4();
3181 for (int i=0; i<4; i++)
3182 {
3183 for (int j=0; j<4; j++)
3184 {
3185 Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j)))));
3186 }
3187 }
3188
3189 adjointMatrix = Transpose(adjointMatrix);
3190 return adjointMatrix;
3191 }
3192
3193 public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol)
3194 {
3195 Matrix4 minor = new Matrix4();
3196 int m = 0, n = 0;
3197 for (int i = 0; i < 4; i++)
3198 {
3199 if (i == iRow)
3200 continue;
3201 n = 0;
3202 for (int j = 0; j < 4; j++)
3203 {
3204 if (j == iCol)
3205 continue;
3206 Matrix4SetValue(ref minor, m,n, matrix[i, j]);
3207 n++;
3208 }
3209 m++;
3210 }
3211
3212 return minor;
3213 }
3214
3215 public static Matrix4 Transpose(Matrix4 pMat)
3216 {
3217 Matrix4 transposeMatrix = new Matrix4();
3218 for (int i = 0; i < 4; i++)
3219 for (int j = 0; j < 4; j++)
3220 Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]);
3221 return transposeMatrix;
3222 }
3223
3224 public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val)
3225 {
3226 switch (r)
3227 {
3228 case 0:
3229 switch (c)
3230 {
3231 case 0:
3232 pMat.M11 = val;
3233 break;
3234 case 1:
3235 pMat.M12 = val;
3236 break;
3237 case 2:
3238 pMat.M13 = val;
3239 break;
3240 case 3:
3241 pMat.M14 = val;
3242 break;
3243 }
3244
3245 break;
3246 case 1:
3247 switch (c)
3248 {
3249 case 0:
3250 pMat.M21 = val;
3251 break;
3252 case 1:
3253 pMat.M22 = val;
3254 break;
3255 case 2:
3256 pMat.M23 = val;
3257 break;
3258 case 3:
3259 pMat.M24 = val;
3260 break;
3261 }
3262
3263 break;
3264 case 2:
3265 switch (c)
3266 {
3267 case 0:
3268 pMat.M31 = val;
3269 break;
3270 case 1:
3271 pMat.M32 = val;
3272 break;
3273 case 2:
3274 pMat.M33 = val;
3275 break;
3276 case 3:
3277 pMat.M34 = val;
3278 break;
3279 }
3280
3281 break;
3282 case 3:
3283 switch (c)
3284 {
3285 case 0:
3286 pMat.M41 = val;
3287 break;
3288 case 1:
3289 pMat.M42 = val;
3290 break;
3291 case 2:
3292 pMat.M43 = val;
3293 break;
3294 case 3:
3295 pMat.M44 = val;
3296 break;
3297 }
3298
3299 break;
3300 }
3301 }
3302
3303 private static float determinant3x3(Matrix4 pMat)
3304 {
3305 float det = 0;
3306 float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2];
3307 float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0];
3308 float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1];
3309 float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2];
3310 float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0];
3311 float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1];
3312
3313 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6);
3314 return det;
3315 }
3316
3317 private static void DMassCopy(ref d.Mass src, ref d.Mass dst)
3318 {
3319 dst.c.W = src.c.W;
3320 dst.c.X = src.c.X;
3321 dst.c.Y = src.c.Y;
3322 dst.c.Z = src.c.Z;
3323 dst.mass = src.mass;
3324 dst.I.M00 = src.I.M00;
3325 dst.I.M01 = src.I.M01;
3326 dst.I.M02 = src.I.M02;
3327 dst.I.M10 = src.I.M10;
3328 dst.I.M11 = src.I.M11;
3329 dst.I.M12 = src.I.M12;
3330 dst.I.M20 = src.I.M20;
3331 dst.I.M21 = src.I.M21;
3332 dst.I.M22 = src.I.M22;
3333 }
3334
3335 public override void SetMaterial(int pMaterial)
3336 {
3337 m_material = pMaterial;
3338 }
3339
3340 private void CheckMeshAsset()
3341 {
3342 if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero)
3343 {
3344 m_assetFailed = true;
3345 Util.FireAndForget(delegate
3346 {
3347 RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod;
3348 if (assetProvider != null)
3349 assetProvider(_pbs.SculptTexture, MeshAssetReceived);
3350 }, null, "ODEPrim.CheckMeshAsset");
3351 }
3352 }
3353
3354 private void MeshAssetReceived(AssetBase asset)
3355 {
3356 if (asset != null && asset.Data != null && asset.Data.Length > 0)
3357 {
3358 if (!_pbs.SculptEntry)
3359 return;
3360 if (_pbs.SculptTexture.ToString() != asset.ID)
3361 return;
3362
3363 _pbs.SculptData = new byte[asset.Data.Length];
3364 asset.Data.CopyTo(_pbs.SculptData, 0);
3365// m_assetFailed = false;
3366
3367// m_log.DebugFormat(
3368// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
3369// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
3370
3371 m_taintshape = true;
3372 _parent_scene.AddPhysicsActorTaint(this);
3373 }
3374 else
3375 {
3376 m_log.WarnFormat(
3377 "[ODE PRIM]: Could not get mesh/sculpt asset {0} for {1} at {2} in {3}",
3378 _pbs.SculptTexture, Name, _position, _parent_scene.PhysicsSceneName);
3379 }
3380 }
3381 }
3382} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs b/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs
new file mode 100644
index 0000000..8d610f7
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs
@@ -0,0 +1,441 @@
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.PhysicsModules.SharedBase;
35using Ode.NET;
36using log4net;
37
38namespace OpenSim.Region.PhysicsModule.ODE
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 // NOTE: limit ray length or collisions will take all avaiable stack space
176 // this value may still be too large, depending on machine configuration
177 // of maximum stack
178 float len = req.length;
179 if (len > 250f)
180 len = 250f;
181
182 // Create the ray
183 IntPtr ray = d.CreateRay(m_scene.space, req.length);
184 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
185
186 // Collide test
187 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
188
189 // Remove Ray
190 d.GeomDestroy(ray);
191
192 // Define default results
193 bool hitYN = false;
194 uint hitConsumerID = 0;
195 float distance = 999999999999f;
196 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
197 Vector3 snormal = Vector3.Zero;
198
199 // Find closest contact and object.
200 lock (m_contactResults)
201 {
202 foreach (ContactResult cResult in m_contactResults)
203 {
204 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
205 {
206 closestcontact = cResult.Pos;
207 hitConsumerID = cResult.ConsumerID;
208 distance = cResult.Depth;
209 hitYN = true;
210 snormal = cResult.Normal;
211 }
212 }
213
214 m_contactResults.Clear();
215 }
216
217 // Return results
218 if (req.callbackMethod != null)
219 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal);
220 }
221
222 /// <summary>
223 /// Method that actually initiates the raycast
224 /// </summary>
225 /// <param name="req"></param>
226 private void RayCast(ODERayRequest req)
227 {
228 // Create the ray
229 IntPtr ray = d.CreateRay(m_scene.space, req.length);
230 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
231
232 // Collide test
233 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
234
235 // Remove Ray
236 d.GeomDestroy(ray);
237
238 // Find closest contact and object.
239 lock (m_contactResults)
240 {
241 // Return results
242 if (req.callbackMethod != null)
243 req.callbackMethod(m_contactResults);
244 }
245 }
246
247 // This is the standard Near. Uses space AABBs to speed up detection.
248 private void near(IntPtr space, IntPtr g1, IntPtr g2)
249 {
250
251 //Don't test against heightfield Geom, or you'll be sorry!
252
253 /*
254 terminate called after throwing an instance of 'std::bad_alloc'
255 what(): std::bad_alloc
256 Stacktrace:
257
258 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004>
259 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff>
260 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280>
261 at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff
262 fffff>
263 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004>
264 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff>
265 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) <
266 0x00114>
267 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb>
268 at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6>
269 at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042>
270 at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e>
271 at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019>
272 at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff>
273
274 Native stacktrace:
275
276 mono [0x80d2a42]
277 [0xb7f5840c]
278 /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018]
279 /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988]
280 /usr/lib/libstdc++.so.6 [0xb45fa865]
281 /usr/lib/libstdc++.so.6 [0xb45fa8a2]
282 /usr/lib/libstdc++.so.6 [0xb45fa9da]
283 /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033]
284 /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d]
285 libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4]
286 libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b]
287 libode.so(dCollide+0x102) [0xb46571b2]
288 [0x95cfdec9]
289 [0x8ea07fe1]
290 [0xab260146]
291 libode.so [0xb465a5c4]
292 libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5]
293 libode.so(dSpaceCollide2+0x177) [0xb465ac67]
294 [0x95cf978e]
295 [0x8ea07945]
296 [0x95cf2bbc]
297 [0xab2787e7]
298 [0xab419fb3]
299 [0xab416657]
300 [0xab415bda]
301 [0xb609b08e]
302 mono(mono_runtime_delegate_invoke+0x34) [0x8192534]
303 mono [0x81a2f0f]
304 mono [0x81d28b6]
305 mono [0x81ea2c6]
306 /lib/i686/cmov/libpthread.so.0 [0xb7e744c0]
307 /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de]
308 */
309
310 // Exclude heightfield geom
311
312 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
313 return;
314 if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
315 return;
316
317 // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
318 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
319 {
320 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
321 return;
322
323 // Separating static prim geometry spaces.
324 // We'll be calling near recursivly if one
325 // of them is a space to find all of the
326 // contact points in the space
327 try
328 {
329 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
330 }
331 catch (AccessViolationException)
332 {
333 m_log.Warn("[PHYSICS]: Unable to collide test a space");
334 return;
335 }
336 //Colliding a space or a geom with a space or a geom. so drill down
337
338 //Collide all geoms in each space..
339 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
340 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
341 return;
342 }
343
344 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
345 return;
346
347 int count = 0;
348 try
349 {
350
351 if (g1 == g2)
352 return; // Can't collide with yourself
353
354 lock (contacts)
355 {
356 count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
357 }
358 }
359 catch (SEHException)
360 {
361 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.");
362 }
363 catch (Exception e)
364 {
365 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
366 return;
367 }
368
369 PhysicsActor p1 = null;
370 PhysicsActor p2 = null;
371
372 if (g1 != IntPtr.Zero)
373 m_scene.actor_name_map.TryGetValue(g1, out p1);
374
375 if (g2 != IntPtr.Zero)
376 m_scene.actor_name_map.TryGetValue(g1, out p2);
377
378 // Loop over contacts, build results.
379 for (int i = 0; i < count; i++)
380 {
381 if (p1 != null)
382 {
383 if (p1 is OdePrim)
384 {
385 ContactResult collisionresult = new ContactResult();
386
387 collisionresult.ConsumerID = p1.LocalID;
388 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
389 collisionresult.Depth = contacts[i].depth;
390 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
391 contacts[i].normal.Z);
392 lock (m_contactResults)
393 m_contactResults.Add(collisionresult);
394 }
395 }
396
397 if (p2 != null)
398 {
399 if (p2 is OdePrim)
400 {
401 ContactResult collisionresult = new ContactResult();
402
403 collisionresult.ConsumerID = p2.LocalID;
404 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
405 collisionresult.Depth = contacts[i].depth;
406 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
407 contacts[i].normal.Z);
408
409 lock (m_contactResults)
410 m_contactResults.Add(collisionresult);
411 }
412 }
413 }
414 }
415
416 /// <summary>
417 /// Dereference the creator scene so that it can be garbage collected if needed.
418 /// </summary>
419 internal void Dispose()
420 {
421 m_scene = null;
422 }
423 }
424
425 public struct ODERayCastRequest
426 {
427 public Vector3 Origin;
428 public Vector3 Normal;
429 public float length;
430 public RaycastCallback callbackMethod;
431 }
432
433 public struct ODERayRequest
434 {
435 public Vector3 Origin;
436 public Vector3 Normal;
437 public int Count;
438 public float length;
439 public RayCallback callbackMethod;
440 }
441} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs b/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs
new file mode 100644
index 0000000..2eb7ba6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs
@@ -0,0 +1,48 @@
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.PhysicsModules.SharedBase;
33using OpenSim.Region.PhysicsModule.ODE;
34
35namespace OpenSim.Region.PhysicsModule.ODE
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/PhysicsModules/Ode/OdeScene.cs b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs
new file mode 100644
index 0000000..8cc7f28
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs
@@ -0,0 +1,4117 @@
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// changes for varsize regions
29// note that raycasts need to have limited range
30// (even in normal regions)
31// or application thread stack may just blowup
32// see RayCast(ODERayCastRequest req)
33
34//#define USE_DRAWSTUFF
35//#define SPAM
36
37using System;
38using System.Collections.Generic;
39using System.Diagnostics;
40using System.IO;
41using System.Linq;
42using System.Reflection;
43using System.Runtime.InteropServices;
44using System.Threading;
45using log4net;
46using Nini.Config;
47using Mono.Addins;
48using Ode.NET;
49using OpenMetaverse;
50#if USE_DRAWSTUFF
51using Drawstuff.NET;
52#endif
53using OpenSim.Framework;
54using OpenSim.Region.PhysicsModules.SharedBase;
55using OpenSim.Region.Framework.Scenes;
56using OpenSim.Region.Framework.Interfaces;
57
58
59namespace OpenSim.Region.PhysicsModule.ODE
60{
61 public enum StatusIndicators : int
62 {
63 Generic = 0,
64 Start = 1,
65 End = 2
66 }
67
68// public struct sCollisionData
69// {
70// public uint ColliderLocalId;
71// public uint CollidedWithLocalId;
72// public int NumberOfCollisions;
73// public int CollisionType;
74// public int StatusIndicator;
75// public int lastframe;
76// }
77
78 [Flags]
79 public enum CollisionCategories : int
80 {
81 Disabled = 0,
82 Geom = 0x00000001,
83 Body = 0x00000002,
84 Space = 0x00000004,
85 Character = 0x00000008,
86 Land = 0x00000010,
87 Water = 0x00000020,
88 Wind = 0x00000040,
89 Sensor = 0x00000080,
90 Selected = 0x00000100
91 }
92
93 /// <summary>
94 /// Material type for a primitive
95 /// </summary>
96 public enum Material : int
97 {
98 /// <summary></summary>
99 Stone = 0,
100 /// <summary></summary>
101 Metal = 1,
102 /// <summary></summary>
103 Glass = 2,
104 /// <summary></summary>
105 Wood = 3,
106 /// <summary></summary>
107 Flesh = 4,
108 /// <summary></summary>
109 Plastic = 5,
110 /// <summary></summary>
111 Rubber = 6
112 }
113
114 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ODEPhysicsScene")]
115 public class OdeScene : PhysicsScene, INonSharedRegionModule
116 {
117 private readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString());
118 private bool m_Enabled = false;
119
120 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
121
122 /// <summary>
123 /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances.
124 /// </summary>
125 /// <remarks>
126 /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a
127 /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts
128 /// uses a static cache at the ODE level.
129 ///
130 /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar
131 /// to
132 ///
133 /// mono() [0x489171]
134 /// mono() [0x4d154f]
135 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60]
136 /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a]
137 ///
138 /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option
139 /// causes OpenSimulator to immediately crash with a native stack trace similar to
140 ///
141 /// mono() [0x489171]
142 /// mono() [0x4d154f]
143 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60]
144 /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82]
145 /// </remarks>
146 internal static Object UniversalColliderSyncObject = new Object();
147
148 /// <summary>
149 /// Is stats collecting enabled for this ODE scene?
150 /// </summary>
151 public bool CollectStats { get; set; }
152
153 /// <summary>
154 /// Statistics for this scene.
155 /// </summary>
156 private Dictionary<string, float> m_stats = new Dictionary<string, float>();
157
158 /// <summary>
159 /// Stat name for total number of avatars in this ODE scene.
160 /// </summary>
161 public const string ODETotalAvatarsStatName = "ODETotalAvatars";
162
163 /// <summary>
164 /// Stat name for total number of prims in this ODE scene.
165 /// </summary>
166 public const string ODETotalPrimsStatName = "ODETotalPrims";
167
168 /// <summary>
169 /// Stat name for total number of prims with active physics in this ODE scene.
170 /// </summary>
171 public const string ODEActivePrimsStatName = "ODEActivePrims";
172
173 /// <summary>
174 /// Stat name for the total time spent in ODE frame processing.
175 /// </summary>
176 /// <remarks>
177 /// A sanity check for the main scene loop physics time.
178 /// </remarks>
179 public const string ODETotalFrameMsStatName = "ODETotalFrameMS";
180
181 /// <summary>
182 /// Stat name for time spent processing avatar taints per frame
183 /// </summary>
184 public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS";
185
186 /// <summary>
187 /// Stat name for time spent processing prim taints per frame
188 /// </summary>
189 public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS";
190
191 /// <summary>
192 /// Stat name for time spent calculating avatar forces per frame.
193 /// </summary>
194 public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS";
195
196 /// <summary>
197 /// Stat name for time spent calculating prim forces per frame
198 /// </summary>
199 public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS";
200
201 /// <summary>
202 /// Stat name for time spent fulfilling raycasting requests per frame
203 /// </summary>
204 public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS";
205
206 /// <summary>
207 /// Stat name for time spent in native code that actually steps through the simulation.
208 /// </summary>
209 public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS";
210
211 /// <summary>
212 /// Stat name for the number of milliseconds that ODE spends in native space collision code.
213 /// </summary>
214 public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS";
215
216 /// <summary>
217 /// Stat name for milliseconds that ODE spends in native geom collision code.
218 /// </summary>
219 public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS";
220
221 /// <summary>
222 /// Time spent in collision processing that is not spent in native space or geom collision code.
223 /// </summary>
224 public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS";
225
226 /// <summary>
227 /// Stat name for time spent notifying listeners of collisions
228 /// </summary>
229 public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS";
230
231 /// <summary>
232 /// Stat name for milliseconds spent updating avatar position and velocity
233 /// </summary>
234 public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS";
235
236 /// <summary>
237 /// Stat name for the milliseconds spent updating prim position and velocity
238 /// </summary>
239 public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS";
240
241 /// <summary>
242 /// Stat name for avatar collisions with another entity.
243 /// </summary>
244 public const string ODEAvatarContactsStatsName = "ODEAvatarContacts";
245
246 /// <summary>
247 /// Stat name for prim collisions with another entity.
248 /// </summary>
249 public const string ODEPrimContactsStatName = "ODEPrimContacts";
250
251 /// <summary>
252 /// Used to hold tick numbers for stat collection purposes.
253 /// </summary>
254 private int m_nativeCollisionStartTick;
255
256 /// <summary>
257 /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback.
258 /// </summary>
259 private bool m_inCollisionTiming;
260
261 /// <summary>
262 /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object
263 /// collisions occured using the _perloopcontact if stats collection is enabled.
264 /// </summary>
265 private int m_tempAvatarCollisionsThisFrame;
266
267 /// <summary>
268 /// Used in calculating physics frame time dilation
269 /// </summary>
270 private int tickCountFrameRun;
271
272 /// <summary>
273 /// Used in calculating physics frame time dilation
274 /// </summary>
275 private int latertickcount;
276
277 private Random fluidRandomizer = new Random(Environment.TickCount);
278
279 public bool m_suportCombine = true;
280
281 private uint m_regionWidth = Constants.RegionSize;
282 private uint m_regionHeight = Constants.RegionSize;
283
284 private float ODE_STEPSIZE = 0.0178f;
285 private float metersInSpace = 29.9f;
286 private float m_timeDilation = 1.0f;
287
288 public float gravityx = 0f;
289 public float gravityy = 0f;
290 public float gravityz = -9.8f;
291
292 public float AvatarTerminalVelocity { get; set; }
293
294 private float contactsurfacelayer = 0.001f;
295
296 private int worldHashspaceLow = -4;
297 private int worldHashspaceHigh = 128;
298
299 private int smallHashspaceLow = -4;
300 private int smallHashspaceHigh = 66;
301
302 private float waterlevel = 0f;
303 private int framecount = 0;
304 //private int m_returncollisions = 10;
305
306 private IntPtr contactgroup;
307
308// internal IntPtr WaterGeom;
309
310 private float nmTerrainContactFriction = 255.0f;
311 private float nmTerrainContactBounce = 0.1f;
312 private float nmTerrainContactERP = 0.1025f;
313
314 private float mTerrainContactFriction = 75f;
315 private float mTerrainContactBounce = 0.1f;
316 private float mTerrainContactERP = 0.05025f;
317
318 private float nmAvatarObjectContactFriction = 250f;
319 private float nmAvatarObjectContactBounce = 0.1f;
320
321 private float mAvatarObjectContactFriction = 75f;
322 private float mAvatarObjectContactBounce = 0.1f;
323
324 private float avPIDD = 3200f;
325 private float avPIDP = 1400f;
326 private float avCapRadius = 0.37f;
327 private float avStandupTensor = 2000000f;
328
329 /// <summary>
330 /// true = old compatibility mode with leaning capsule; false = new corrected mode
331 /// </summary>
332 /// <remarks>
333 /// Even when set to false, the capsule still tilts but this is done in a different way.
334 /// </remarks>
335 public bool IsAvCapsuleTilted { get; private set; }
336
337 private float avDensity = 80f;
338// private float avHeightFudgeFactor = 0.52f;
339 private float avMovementDivisorWalk = 1.3f;
340 private float avMovementDivisorRun = 0.8f;
341 private float minimumGroundFlightOffset = 3f;
342 public float maximumMassObject = 10000.01f;
343
344 public bool meshSculptedPrim = true;
345 public bool forceSimplePrimMeshing = false;
346
347 public float meshSculptLOD = 32;
348 public float MeshSculptphysicalLOD = 16;
349
350 public float geomDefaultDensity = 10.000006836f;
351
352 public int geomContactPointsStartthrottle = 3;
353 public int geomUpdatesPerThrottledUpdate = 15;
354 private const int avatarExpectedContacts = 3;
355
356 public float bodyPIDD = 35f;
357 public float bodyPIDG = 25;
358
359 public int geomCrossingFailuresBeforeOutofbounds = 5;
360
361 public float bodyMotorJointMaxforceTensor = 2;
362
363 public int bodyFramesAutoDisable = 20;
364
365 private float[] _watermap;
366 private bool m_filterCollisions = true;
367
368 private d.NearCallback nearCallback;
369 public d.TriCallback triCallback;
370 public d.TriArrayCallback triArrayCallback;
371
372 /// <summary>
373 /// Avatars in the physics scene.
374 /// </summary>
375 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
376
377 /// <summary>
378 /// Prims in the physics scene.
379 /// </summary>
380 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
381
382 /// <summary>
383 /// Prims in the physics scene that are subject to physics, not just collisions.
384 /// </summary>
385 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
386
387 /// <summary>
388 /// Prims that the simulator has created/deleted/updated and so need updating in ODE.
389 /// </summary>
390 private readonly HashSet<OdePrim> _taintedPrims = new HashSet<OdePrim>();
391
392 /// <summary>
393 /// Record a character that has taints to be processed.
394 /// </summary>
395 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
396
397 /// <summary>
398 /// Keep record of contacts in the physics loop so that we can remove duplicates.
399 /// </summary>
400 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
401
402 /// <summary>
403 /// A dictionary of actors that should receive collision events.
404 /// </summary>
405 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActors = new Dictionary<uint, PhysicsActor>();
406
407 /// <summary>
408 /// A dictionary of collision event changes that are waiting to be processed.
409 /// </summary>
410 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActorsChanges = new Dictionary<uint, PhysicsActor>();
411
412 /// <summary>
413 /// Maps a unique geometry id (a memory location) to a physics actor name.
414 /// </summary>
415 /// <remarks>
416 /// Only actors participating in collisions have geometries. This has to be maintained separately from
417 /// actor_name_map because terrain and water currently don't conceptually have a physics actor of their own
418 /// apart from the singleton PANull
419 /// </remarks>
420 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
421
422 /// <summary>
423 /// Maps a unique geometry id (a memory location) to a physics actor.
424 /// </summary>
425 /// <remarks>
426 /// Only actors participating in collisions have geometries.
427 /// </remarks>
428 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
429
430 /// <summary>
431 /// Defects list to remove characters that no longer have finite positions due to some other bug.
432 /// </summary>
433 /// <remarks>
434 /// Used repeatedly in Simulate() but initialized once here.
435 /// </remarks>
436 private readonly List<OdeCharacter> defects = new List<OdeCharacter>();
437
438 private bool m_NINJA_physics_joints_enabled = false;
439 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
440 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
441 private d.ContactGeom[] contacts;
442
443 /// <summary>
444 /// Lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
445 /// </summary>
446 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>();
447
448 /// <summary>
449 /// can lock for longer. accessed only by OdeScene.
450 /// </summary>
451 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>();
452
453 /// <summary>
454 /// can lock for longer. accessed only by OdeScene.
455 /// </summary>
456 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>();
457
458 /// <summary>
459 /// lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
460 /// </summary>
461 private readonly List<string> requestedJointsToBeDeleted = new List<string>();
462
463 private Object externalJointRequestsLock = new Object();
464 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
465 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
466 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
467 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
468
469 private d.Contact contact;
470 private d.Contact TerrainContact;
471 private d.Contact AvatarMovementprimContact;
472 private d.Contact AvatarMovementTerrainContact;
473 private d.Contact WaterContact;
474 private d.Contact[,] m_materialContacts;
475
476//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
477//Ckrinke private int m_randomizeWater = 200;
478 private int m_physicsiterations = 10;
479 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
480 private readonly PhysicsActor PANull = new NullPhysicsActor();
481// private float step_time = 0.0f;
482//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
483//Ckrinke private int ms = 0;
484 public IntPtr world;
485 //private bool returncollisions = false;
486 // private uint obj1LocalID = 0;
487 private uint obj2LocalID = 0;
488 //private int ctype = 0;
489 private OdeCharacter cc1;
490 private OdePrim cp1;
491 private OdeCharacter cc2;
492 private OdePrim cp2;
493 private int p1ExpectedPoints = 0;
494 private int p2ExpectedPoints = 0;
495 //private int cStartStop = 0;
496 //private string cDictKey = "";
497
498 public IntPtr space;
499
500 //private IntPtr tmpSpace;
501 // split static geometry collision handling into spaces of 30 meters
502 public IntPtr[,] staticPrimspace;
503
504 /// <summary>
505 /// Used to lock the entire physics scene. Locked during the main part of Simulate()
506 /// </summary>
507 internal Object OdeLock = new Object();
508
509 private bool _worldInitialized = false;
510
511 public IMesher mesher;
512
513 private IConfigSource m_config;
514
515 public bool physics_logging = false;
516 public int physics_logging_interval = 0;
517 public bool physics_logging_append_existing_logfile = false;
518
519 private bool avplanted = false;
520 private bool av_av_collisions_off = false;
521
522 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
523 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
524
525 private volatile int m_global_contactcount = 0;
526
527 private Vector3 m_worldOffset = Vector3.Zero;
528 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
529 private PhysicsScene m_parentScene = null;
530
531 float spacesPerMeterX;
532 float spacesPerMeterY;
533 int spaceGridMaxX;
534 int spaceGridMaxY;
535
536 private ODERayCastRequestManager m_rayCastManager;
537
538
539 #region INonSharedRegionModule
540 public string Name
541 {
542 get { return "OpenDynamicsEngine"; }
543 }
544
545 public Type ReplaceableInterface
546 {
547 get { return null; }
548 }
549
550 public void Initialise(IConfigSource source)
551 {
552 // TODO: Move this out of Startup
553 IConfig config = source.Configs["Startup"];
554 if (config != null)
555 {
556 string physics = config.GetString("physics", string.Empty);
557 if (physics == Name)
558 {
559 m_Enabled = true;
560 m_config = source;
561
562 // We do this so that OpenSimulator on Windows loads the correct native ODE library depending on whether
563 // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports
564 // will find it already loaded later on.
565 //
566 // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be
567 // controlled in Ode.NET.dll.config
568 if (Util.IsWindows())
569 Util.LoadArchSpecificWindowsDll("ode.dll");
570
571 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to
572 // http://opensimulator.org/mantis/view.php?id=2750).
573 d.InitODE();
574
575 }
576 }
577
578 }
579
580 public void Close()
581 {
582 }
583
584 public void AddRegion(Scene scene)
585 {
586 if (!m_Enabled)
587 return;
588
589 EngineType = Name;
590 PhysicsSceneName = EngineType + "/" + scene.RegionInfo.RegionName;
591
592 scene.RegisterModuleInterface<PhysicsScene>(this);
593 Vector3 extent = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, scene.RegionInfo.RegionSizeZ);
594 Initialise(extent);
595 InitialiseFromConfig(m_config);
596
597 // This may not be that good since terrain may not be avaiable at this point
598 base.Initialise(scene.PhysicsRequestAsset,
599 (scene.Heightmap != null ? scene.Heightmap.GetFloatsSerialised() : new float[(int)(extent.X * extent.Y)]),
600 (float)scene.RegionInfo.RegionSettings.WaterHeight);
601
602 }
603
604 public void RemoveRegion(Scene scene)
605 {
606 if (!m_Enabled)
607 return;
608 }
609
610 public void RegionLoaded(Scene scene)
611 {
612 if (!m_Enabled)
613 return;
614
615 mesher = scene.RequestModuleInterface<IMesher>();
616 if (mesher == null)
617 m_log.WarnFormat("[ODE SCENE]: No mesher in {0}. Things will not work well.", PhysicsSceneName);
618 }
619 #endregion
620
621 /// <summary>
622 /// Initiailizes the scene
623 /// Sets many properties that ODE requires to be stable
624 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
625 /// </summary>
626 private void Initialise(Vector3 regionExtent)
627 {
628 WorldExtents.X = regionExtent.X;
629 m_regionWidth = (uint)regionExtent.X;
630 WorldExtents.Y = regionExtent.Y;
631 m_regionHeight = (uint)regionExtent.Y;
632
633 m_suportCombine = false;
634
635 nearCallback = near;
636 triCallback = TriCallback;
637 triArrayCallback = TriArrayCallback;
638 m_rayCastManager = new ODERayCastRequestManager(this);
639
640 // Create the world and the first space
641 world = d.WorldCreate();
642 space = d.HashSpaceCreate(IntPtr.Zero);
643
644 contactgroup = d.JointGroupCreate(0);
645
646 d.WorldSetAutoDisableFlag(world, false);
647
648 #if USE_DRAWSTUFF
649 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
650 viewthread.Start();
651 #endif
652
653 // _watermap = new float[258 * 258];
654
655 // Zero out the prim spaces array (we split our space into smaller spaces so
656 // we can hit test less.
657 }
658
659#if USE_DRAWSTUFF
660 public void startvisualization(object o)
661 {
662 ds.Functions fn;
663 fn.version = ds.VERSION;
664 fn.start = new ds.CallbackFunction(start);
665 fn.step = new ds.CallbackFunction(step);
666 fn.command = new ds.CallbackFunction(command);
667 fn.stop = null;
668 fn.path_to_textures = "./textures";
669 string[] args = new string[0];
670 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
671 }
672#endif
673
674 // Initialize from configs
675 private void InitialiseFromConfig(IConfigSource config)
676 {
677 InitializeExtraStats();
678
679 m_config = config;
680 // Defaults
681
682 if (Environment.OSVersion.Platform == PlatformID.Unix)
683 {
684 avPIDD = 3200.0f;
685 avPIDP = 1400.0f;
686 avStandupTensor = 2000000f;
687 }
688 else
689 {
690 avPIDD = 2200.0f;
691 avPIDP = 900.0f;
692 avStandupTensor = 550000f;
693 }
694
695 int contactsPerCollision = 80;
696
697 if (m_config != null)
698 {
699 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
700 if (physicsconfig != null)
701 {
702 CollectStats = physicsconfig.GetBoolean("collect_stats", false);
703
704 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
705 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
706 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
707
708 float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f);
709 AvatarTerminalVelocity = Util.Clamp<float>(avatarTerminalVelocity, 0, 255f);
710 if (AvatarTerminalVelocity != avatarTerminalVelocity)
711 {
712 m_log.WarnFormat(
713 "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}",
714 avatarTerminalVelocity, AvatarTerminalVelocity);
715 }
716
717 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
718 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
719
720 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
721 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
722 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
723
724 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
725
726 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
727 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
728 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
729
730 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
731 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
732 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
733
734 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
735 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
736
737 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
738 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
739
740 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE);
741 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
742
743 avDensity = physicsconfig.GetFloat("av_density", 80f);
744// avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
745 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
746 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
747 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
748 avplanted = physicsconfig.GetBoolean("av_planted", false);
749 av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
750
751 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
752
753 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
754
755 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5);
756 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
757 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
758
759 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
760 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
761
762 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
763 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
764
765 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
766 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
767 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
768 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
769 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
770
771
772
773 if (Environment.OSVersion.Platform == PlatformID.Unix)
774 {
775 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
776 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
777 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
778 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
779 }
780 else
781 {
782 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
783 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
784 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
785 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
786 }
787
788 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
789 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
790 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
791
792 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
793 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
794 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
795 }
796 }
797
798 contacts = new d.ContactGeom[contactsPerCollision];
799
800 spacesPerMeterX = 1.0f / metersInSpace;
801 spacesPerMeterY = 1.0f / metersInSpace;
802
803 spaceGridMaxX = (int)(WorldExtents.X * spacesPerMeterX);
804 spaceGridMaxY = (int)(WorldExtents.Y * spacesPerMeterY);
805
806 // note: limit number of spaces
807 if (spaceGridMaxX > 24)
808 {
809 spaceGridMaxX = 24;
810 spacesPerMeterX = spaceGridMaxX / WorldExtents.X;
811 }
812 if (spaceGridMaxY > 24)
813 {
814 spaceGridMaxY = 24;
815 spacesPerMeterY = spaceGridMaxY / WorldExtents.Y ;
816 }
817
818 staticPrimspace = new IntPtr[spaceGridMaxX, spaceGridMaxY];
819
820 // make this index limits
821 spaceGridMaxX--;
822 spaceGridMaxY--;
823
824
825
826 // Centeral contact friction and bounce
827 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
828 // an avatar falls through in Z but not in X or Y when walking on a prim.
829 contact.surface.mode |= d.ContactFlags.SoftERP;
830 contact.surface.mu = nmAvatarObjectContactFriction;
831 contact.surface.bounce = nmAvatarObjectContactBounce;
832 contact.surface.soft_cfm = 0.010f;
833 contact.surface.soft_erp = 0.010f;
834
835 // Terrain contact friction and Bounce
836 // This is the *non* moving version. Use this when an avatar
837 // isn't moving to keep it in place better
838 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
839 TerrainContact.surface.mu = nmTerrainContactFriction;
840 TerrainContact.surface.bounce = nmTerrainContactBounce;
841 TerrainContact.surface.soft_erp = nmTerrainContactERP;
842
843 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
844 WaterContact.surface.mu = 0f; // No friction
845 WaterContact.surface.bounce = 0.0f; // No bounce
846 WaterContact.surface.soft_cfm = 0.010f;
847 WaterContact.surface.soft_erp = 0.010f;
848
849 // Prim contact friction and bounce
850 // THis is the *non* moving version of friction and bounce
851 // Use this when an avatar comes in contact with a prim
852 // and is moving
853 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
854 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
855
856 // Terrain contact friction bounce and various error correcting calculations
857 // Use this when an avatar is in contact with the terrain and moving.
858 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
859 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
860 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
861 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
862
863 /*
864 <summary></summary>
865 Stone = 0,
866 /// <summary></summary>
867 Metal = 1,
868 /// <summary></summary>
869 Glass = 2,
870 /// <summary></summary>
871 Wood = 3,
872 /// <summary></summary>
873 Flesh = 4,
874 /// <summary></summary>
875 Plastic = 5,
876 /// <summary></summary>
877 Rubber = 6
878 */
879
880 m_materialContacts = new d.Contact[7,2];
881
882 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
883 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
884 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
885 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
886 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
887 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
888
889 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
890 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
891 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
892 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
893 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
894 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
895
896 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
897 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
898 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
899 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
900 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
901 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
902
903 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
904 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
905 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
906 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
907 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
908 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
909
910 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
911 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
912 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
913 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
914 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
915 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
916
917 /*
918 private float nmAvatarObjectContactFriction = 250f;
919 private float nmAvatarObjectContactBounce = 0.1f;
920
921 private float mAvatarObjectContactFriction = 75f;
922 private float mAvatarObjectContactBounce = 0.1f;
923 */
924 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
925 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
926 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
927 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
928 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
929 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
930
931 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
932 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
933 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
934 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
935 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
936 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
937
938 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
939 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
940 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
941 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
942 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
943 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
944
945 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
946 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
947 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
948 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
949 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
950 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
951
952 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
953 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
954 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
955 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
956 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
957 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
958
959 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
960 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
961 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
962 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
963 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
964 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
965
966 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
967 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
968 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
969 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
970 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
971 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
972
973 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
974 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
975 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
976 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
977 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
978 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
979
980 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
981 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
982 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
983 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
984 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
985 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
986
987 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
988
989 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
990
991 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
992 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
993
994 d.WorldSetLinearDamping(world, 256f);
995 d.WorldSetAngularDamping(world, 256f);
996 d.WorldSetAngularDampingThreshold(world, 256f);
997 d.WorldSetLinearDampingThreshold(world, 256f);
998 d.WorldSetMaxAngularSpeed(world, 256f);
999
1000 // Set how many steps we go without running collision testing
1001 // This is in addition to the step size.
1002 // Essentially Steps * m_physicsiterations
1003 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
1004 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
1005
1006 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
1007 {
1008 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
1009 {
1010 staticPrimspace[i, j] = IntPtr.Zero;
1011 }
1012 }
1013
1014 _worldInitialized = true;
1015 }
1016
1017// internal void waitForSpaceUnlock(IntPtr space)
1018// {
1019// //if (space != IntPtr.Zero)
1020// //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
1021// }
1022
1023// /// <summary>
1024// /// Debug space message for printing the space that a prim/avatar is in.
1025// /// </summary>
1026// /// <param name="pos"></param>
1027// /// <returns>Returns which split up space the given position is in.</returns>
1028// public string whichspaceamIin(Vector3 pos)
1029// {
1030// return calculateSpaceForGeom(pos).ToString();
1031// }
1032
1033 #region Collision Detection
1034
1035 /// <summary>
1036 /// Collides two geometries.
1037 /// </summary>
1038 /// <returns></returns>
1039 /// <param name='geom1'></param>
1040 /// <param name='geom2'>/param>
1041 /// <param name='maxContacts'></param>
1042 /// <param name='contactsArray'></param>
1043 /// <param name='contactGeomSize'></param>
1044 private int CollideGeoms(
1045 IntPtr geom1, IntPtr geom2, int maxContacts, Ode.NET.d.ContactGeom[] contactsArray, int contactGeomSize)
1046 {
1047 int count;
1048
1049 lock (OdeScene.UniversalColliderSyncObject)
1050 {
1051 // We do this inside the lock so that we don't count any delay in acquiring it
1052 if (CollectStats)
1053 m_nativeCollisionStartTick = Util.EnvironmentTickCount();
1054
1055 count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize);
1056 }
1057
1058 // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably
1059 // negligable
1060 if (CollectStats)
1061 m_stats[ODENativeGeomCollisionFrameMsStatName]
1062 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
1063
1064 return count;
1065 }
1066
1067 /// <summary>
1068 /// Collide two spaces or a space and a geometry.
1069 /// </summary>
1070 /// <param name='space1'></param>
1071 /// <param name='space2'>/param>
1072 /// <param name='data'></param>
1073 private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data)
1074 {
1075 if (CollectStats)
1076 {
1077 m_inCollisionTiming = true;
1078 m_nativeCollisionStartTick = Util.EnvironmentTickCount();
1079 }
1080
1081 d.SpaceCollide2(space1, space2, data, nearCallback);
1082
1083 if (CollectStats && m_inCollisionTiming)
1084 {
1085 m_stats[ODENativeSpaceCollisionFrameMsStatName]
1086 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
1087 m_inCollisionTiming = false;
1088 }
1089 }
1090
1091 /// <summary>
1092 /// This is our near callback. A geometry is near a body
1093 /// </summary>
1094 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
1095 /// <param name="g1">a geometry or space</param>
1096 /// <param name="g2">another geometry or space</param>
1097 private void near(IntPtr space, IntPtr g1, IntPtr g2)
1098 {
1099 if (CollectStats && m_inCollisionTiming)
1100 {
1101 m_stats[ODENativeSpaceCollisionFrameMsStatName]
1102 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
1103 m_inCollisionTiming = false;
1104 }
1105
1106// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space);
1107 // no lock here! It's invoked from within Simulate(), which is thread-locked
1108
1109 // Test if we're colliding a geom with a space.
1110 // If so we have to drill down into the space recursively
1111
1112 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
1113 {
1114 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
1115 return;
1116
1117 // Separating static prim geometry spaces.
1118 // We'll be calling near recursivly if one
1119 // of them is a space to find all of the
1120 // contact points in the space
1121 try
1122 {
1123 CollideSpaces(g1, g2, IntPtr.Zero);
1124 }
1125 catch (AccessViolationException)
1126 {
1127 m_log.Error("[ODE SCENE]: Unable to collide test a space");
1128 return;
1129 }
1130 //Colliding a space or a geom with a space or a geom. so drill down
1131
1132 //Collide all geoms in each space..
1133 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
1134 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
1135 return;
1136 }
1137
1138 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
1139 return;
1140
1141 IntPtr b1 = d.GeomGetBody(g1);
1142 IntPtr b2 = d.GeomGetBody(g2);
1143
1144 // d.GeomClassID id = d.GeomGetClass(g1);
1145
1146 String name1 = null;
1147 String name2 = null;
1148
1149 if (!geom_name_map.TryGetValue(g1, out name1))
1150 {
1151 name1 = "null";
1152 }
1153 if (!geom_name_map.TryGetValue(g2, out name2))
1154 {
1155 name2 = "null";
1156 }
1157
1158 //if (id == d.GeomClassId.TriMeshClass)
1159 //{
1160 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
1161 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1162 //}
1163
1164 // Figure out how many contact points we have
1165 int count = 0;
1166
1167 try
1168 {
1169 // Colliding Geom To Geom
1170 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
1171
1172 if (g1 == g2)
1173 return; // Can't collide with yourself
1174
1175 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
1176 return;
1177
1178 count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
1179
1180 // All code after this is only relevant if we have any collisions
1181 if (count <= 0)
1182 return;
1183
1184 if (count > contacts.Length)
1185 m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
1186 }
1187 catch (SEHException)
1188 {
1189 m_log.Error(
1190 "[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.");
1191 base.TriggerPhysicsBasedRestart();
1192 }
1193 catch (Exception e)
1194 {
1195 m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message);
1196 return;
1197 }
1198
1199 PhysicsActor p1;
1200 PhysicsActor p2;
1201
1202 p1ExpectedPoints = 0;
1203 p2ExpectedPoints = 0;
1204
1205 if (!actor_name_map.TryGetValue(g1, out p1))
1206 {
1207 p1 = PANull;
1208 }
1209
1210 if (!actor_name_map.TryGetValue(g2, out p2))
1211 {
1212 p2 = PANull;
1213 }
1214
1215 ContactPoint maxDepthContact = new ContactPoint();
1216 if (p1.CollisionScore + count >= float.MaxValue)
1217 p1.CollisionScore = 0;
1218 p1.CollisionScore += count;
1219
1220 if (p2.CollisionScore + count >= float.MaxValue)
1221 p2.CollisionScore = 0;
1222 p2.CollisionScore += count;
1223
1224 for (int i = 0; i < count; i++)
1225 {
1226 d.ContactGeom curContact = contacts[i];
1227
1228 if (curContact.depth > maxDepthContact.PenetrationDepth)
1229 {
1230 maxDepthContact = new ContactPoint(
1231 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
1232 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
1233 curContact.depth
1234 );
1235 }
1236
1237 //m_log.Warn("[CCOUNT]: " + count);
1238 IntPtr joint;
1239 // If we're colliding with terrain, use 'TerrainContact' instead of contact.
1240 // allows us to have different settings
1241
1242 // We only need to test p2 for 'jump crouch purposes'
1243 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
1244 {
1245 // Testing if the collision is at the feet of the avatar
1246
1247 //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));
1248 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
1249 p2.IsColliding = true;
1250 }
1251 else
1252 {
1253 p2.IsColliding = true;
1254 }
1255
1256 //if ((framecount % m_returncollisions) == 0)
1257
1258 switch (p1.PhysicsActorType)
1259 {
1260 case (int)ActorTypes.Agent:
1261 p1ExpectedPoints = avatarExpectedContacts;
1262 p2.CollidingObj = true;
1263 break;
1264 case (int)ActorTypes.Prim:
1265 if (p1 != null && p1 is OdePrim)
1266 p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts;
1267
1268 if (p2.Velocity.LengthSquared() > 0.0f)
1269 p2.CollidingObj = true;
1270 break;
1271 case (int)ActorTypes.Unknown:
1272 p2.CollidingGround = true;
1273 break;
1274 default:
1275 p2.CollidingGround = true;
1276 break;
1277 }
1278
1279 // we don't want prim or avatar to explode
1280
1281 #region InterPenetration Handling - Unintended physics explosions
1282# region disabled code1
1283
1284 if (curContact.depth >= 0.08f)
1285 {
1286 //This is disabled at the moment only because it needs more tweaking
1287 //It will eventually be uncommented
1288 /*
1289 if (contact.depth >= 1.00f)
1290 {
1291 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
1292 }
1293
1294 //If you interpenetrate a prim with an agent
1295 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
1296 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
1297 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
1298 p2.PhysicsActorType == (int) ActorTypes.Prim))
1299 {
1300
1301 //contact.depth = contact.depth * 4.15f;
1302 /*
1303 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
1304 {
1305 p2.CollidingObj = true;
1306 contact.depth = 0.003f;
1307 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
1308 OdeCharacter character = (OdeCharacter) p2;
1309 character.SetPidStatus(true);
1310 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));
1311
1312 }
1313 else
1314 {
1315
1316 //contact.depth = 0.0000000f;
1317 }
1318 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1319 {
1320
1321 p1.CollidingObj = true;
1322 contact.depth = 0.003f;
1323 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
1324 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));
1325 OdeCharacter character = (OdeCharacter)p1;
1326 character.SetPidStatus(true);
1327 }
1328 else
1329 {
1330
1331 //contact.depth = 0.0000000f;
1332 }
1333
1334
1335
1336 }
1337*/
1338 // If you interpenetrate a prim with another prim
1339 /*
1340 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
1341 {
1342 #region disabledcode2
1343 //OdePrim op1 = (OdePrim)p1;
1344 //OdePrim op2 = (OdePrim)p2;
1345 //op1.m_collisionscore++;
1346 //op2.m_collisionscore++;
1347
1348 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
1349 //{
1350 //op1.m_taintdisable = true;
1351 //AddPhysicsActorTaint(p1);
1352 //op2.m_taintdisable = true;
1353 //AddPhysicsActorTaint(p2);
1354 //}
1355
1356 //if (contact.depth >= 0.25f)
1357 //{
1358 // Don't collide, one or both prim will expld.
1359
1360 //op1.m_interpenetrationcount++;
1361 //op2.m_interpenetrationcount++;
1362 //interpenetrations_before_disable = 200;
1363 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
1364 //{
1365 //op1.m_taintdisable = true;
1366 //AddPhysicsActorTaint(p1);
1367 //}
1368 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
1369 //{
1370 // op2.m_taintdisable = true;
1371 //AddPhysicsActorTaint(p2);
1372 //}
1373
1374 //contact.depth = contact.depth / 8f;
1375 //contact.normal = new d.Vector3(0, 0, 1);
1376 //}
1377 //if (op1.m_disabled || op2.m_disabled)
1378 //{
1379 //Manually disabled objects stay disabled
1380 //contact.depth = 0f;
1381 //}
1382 #endregion
1383 }
1384 */
1385#endregion
1386 if (curContact.depth >= 1.00f)
1387 {
1388 //m_log.Info("[P]: " + contact.depth.ToString());
1389 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
1390 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
1391 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
1392 p2.PhysicsActorType == (int) ActorTypes.Unknown))
1393 {
1394 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
1395 {
1396 if (p2 is OdeCharacter)
1397 {
1398 OdeCharacter character = (OdeCharacter) p2;
1399
1400 //p2.CollidingObj = true;
1401 curContact.depth = 0.00000003f;
1402 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
1403 curContact.pos =
1404 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1405 curContact.pos.Y + (p1.Size.Y/2),
1406 curContact.pos.Z + (p1.Size.Z/2));
1407 character.SetPidStatus(true);
1408 }
1409 }
1410
1411 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1412 {
1413 if (p1 is OdeCharacter)
1414 {
1415 OdeCharacter character = (OdeCharacter) p1;
1416
1417 //p2.CollidingObj = true;
1418 curContact.depth = 0.00000003f;
1419 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1420 curContact.pos =
1421 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1422 curContact.pos.Y + (p1.Size.Y/2),
1423 curContact.pos.Z + (p1.Size.Z/2));
1424 character.SetPidStatus(true);
1425 }
1426 }
1427 }
1428 }
1429 }
1430
1431 #endregion
1432
1433 // Logic for collision handling
1434 // Note, that if *all* contacts are skipped (VolumeDetect)
1435 // The prim still detects (and forwards) collision events but
1436 // appears to be phantom for the world
1437 Boolean skipThisContact = false;
1438
1439 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1440 skipThisContact = true; // No collision on volume detect prims
1441
1442 if (av_av_collisions_off)
1443 if ((p1 is OdeCharacter) && (p2 is OdeCharacter))
1444 skipThisContact = true;
1445
1446 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1447 skipThisContact = true; // No collision on volume detect prims
1448
1449 if (!skipThisContact && curContact.depth < 0f)
1450 skipThisContact = true;
1451
1452 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1453 skipThisContact = true;
1454
1455 const int maxContactsbeforedeath = 4000;
1456 joint = IntPtr.Zero;
1457
1458 if (!skipThisContact)
1459 {
1460 _perloopContact.Add(curContact);
1461
1462 if (name1 == "Terrain" || name2 == "Terrain")
1463 {
1464 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1465 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1466 {
1467 p2ExpectedPoints = avatarExpectedContacts;
1468 // Avatar is moving on terrain, use the movement terrain contact
1469 AvatarMovementTerrainContact.geom = curContact;
1470
1471 if (m_global_contactcount < maxContactsbeforedeath)
1472 {
1473 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1474 m_global_contactcount++;
1475 }
1476 }
1477 else
1478 {
1479 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1480 {
1481 p2ExpectedPoints = avatarExpectedContacts;
1482 // Avatar is standing on terrain, use the non moving terrain contact
1483 TerrainContact.geom = curContact;
1484
1485 if (m_global_contactcount < maxContactsbeforedeath)
1486 {
1487 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1488 m_global_contactcount++;
1489 }
1490 }
1491 else
1492 {
1493 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1494 {
1495 // prim prim contact
1496 // int pj294950 = 0;
1497 int movintYN = 0;
1498 int material = (int) Material.Wood;
1499 // prim terrain contact
1500 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1501 {
1502 movintYN = 1;
1503 }
1504
1505 if (p2 is OdePrim)
1506 {
1507 material = ((OdePrim) p2).m_material;
1508 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1509 }
1510
1511 // Unnessesary because p1 is defined above
1512 //if (p1 is OdePrim)
1513 // {
1514 // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts;
1515 // }
1516 //m_log.DebugFormat("Material: {0}", material);
1517
1518 m_materialContacts[material, movintYN].geom = curContact;
1519
1520 if (m_global_contactcount < maxContactsbeforedeath)
1521 {
1522 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1523 m_global_contactcount++;
1524 }
1525 }
1526 else
1527 {
1528 int movintYN = 0;
1529 // prim terrain contact
1530 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1531 {
1532 movintYN = 1;
1533 }
1534
1535 int material = (int)Material.Wood;
1536
1537 if (p2 is OdePrim)
1538 {
1539 material = ((OdePrim)p2).m_material;
1540 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1541 }
1542
1543 //m_log.DebugFormat("Material: {0}", material);
1544 m_materialContacts[material, movintYN].geom = curContact;
1545
1546 if (m_global_contactcount < maxContactsbeforedeath)
1547 {
1548 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1549 m_global_contactcount++;
1550 }
1551 }
1552 }
1553 }
1554 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1555 //{
1556 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1557 //}
1558 }
1559 else if (name1 == "Water" || name2 == "Water")
1560 {
1561 /*
1562 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1563 {
1564 }
1565 else
1566 {
1567 }
1568 */
1569 //WaterContact.surface.soft_cfm = 0.0000f;
1570 //WaterContact.surface.soft_erp = 0.00000f;
1571 if (curContact.depth > 0.1f)
1572 {
1573 curContact.depth *= 52;
1574 //contact.normal = new d.Vector3(0, 0, 1);
1575 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1576 }
1577
1578 WaterContact.geom = curContact;
1579
1580 if (m_global_contactcount < maxContactsbeforedeath)
1581 {
1582 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1583 m_global_contactcount++;
1584 }
1585 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1586 }
1587 else
1588 {
1589 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1590 {
1591 p2ExpectedPoints = avatarExpectedContacts;
1592 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1593 {
1594 // Avatar is moving on a prim, use the Movement prim contact
1595 AvatarMovementprimContact.geom = curContact;
1596
1597 if (m_global_contactcount < maxContactsbeforedeath)
1598 {
1599 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1600 m_global_contactcount++;
1601 }
1602 }
1603 else
1604 {
1605 // Avatar is standing still on a prim, use the non movement contact
1606 contact.geom = curContact;
1607
1608 if (m_global_contactcount < maxContactsbeforedeath)
1609 {
1610 joint = d.JointCreateContact(world, contactgroup, ref contact);
1611 m_global_contactcount++;
1612 }
1613 }
1614 }
1615 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1616 {
1617 //p1.PhysicsActorType
1618 int material = (int)Material.Wood;
1619
1620 if (p2 is OdePrim)
1621 {
1622 material = ((OdePrim)p2).m_material;
1623 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1624 }
1625
1626 //m_log.DebugFormat("Material: {0}", material);
1627 m_materialContacts[material, 0].geom = curContact;
1628
1629 if (m_global_contactcount < maxContactsbeforedeath)
1630 {
1631 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1632 m_global_contactcount++;
1633 }
1634 }
1635 }
1636
1637 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1638 {
1639 d.JointAttach(joint, b1, b2);
1640 m_global_contactcount++;
1641 }
1642 }
1643
1644 collision_accounting_events(p1, p2, maxDepthContact);
1645
1646 if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle))
1647 {
1648 // If there are more then 3 contact points, it's likely
1649 // that we've got a pile of objects, so ...
1650 // We don't want to send out hundreds of terse updates over and over again
1651 // so lets throttle them and send them again after it's somewhat sorted out.
1652 p2.ThrottleUpdates = true;
1653 }
1654 //m_log.Debug(count.ToString());
1655 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1656 }
1657 }
1658
1659 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1660 {
1661 if (!m_filterCollisions)
1662 return false;
1663
1664 bool result = false;
1665
1666 ActorTypes at = (ActorTypes)atype;
1667
1668 foreach (d.ContactGeom contact in _perloopContact)
1669 {
1670 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1671 //{
1672 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1673 if (at == ActorTypes.Agent)
1674 {
1675 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f)
1676 && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f)
1677 && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
1678 {
1679 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1680 {
1681 //contactGeom.depth *= .00005f;
1682 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1683 // 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));
1684 result = true;
1685 break;
1686 }
1687// else
1688// {
1689// //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1690// }
1691 }
1692// else
1693// {
1694// //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));
1695// //int i = 0;
1696// }
1697 }
1698 else if (at == ActorTypes.Prim)
1699 {
1700 //d.AABB aabb1 = new d.AABB();
1701 //d.AABB aabb2 = new d.AABB();
1702
1703 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1704 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1705 //aabb1.
1706 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)))
1707 {
1708 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1709 {
1710 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1711 {
1712 result = true;
1713 break;
1714 }
1715 }
1716 //m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1717 //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));
1718 }
1719 }
1720 }
1721
1722 return result;
1723 }
1724
1725 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1726 {
1727 // obj1LocalID = 0;
1728 //returncollisions = false;
1729 obj2LocalID = 0;
1730 //ctype = 0;
1731 //cStartStop = 0;
1732 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1733 return;
1734
1735 switch ((ActorTypes)p2.PhysicsActorType)
1736 {
1737 case ActorTypes.Agent:
1738 cc2 = (OdeCharacter)p2;
1739
1740 // obj1LocalID = cc2.m_localID;
1741 switch ((ActorTypes)p1.PhysicsActorType)
1742 {
1743 case ActorTypes.Agent:
1744 cc1 = (OdeCharacter)p1;
1745 obj2LocalID = cc1.LocalID;
1746 cc1.AddCollisionEvent(cc2.LocalID, contact);
1747 //ctype = (int)CollisionCategories.Character;
1748
1749 //if (cc1.CollidingObj)
1750 //cStartStop = (int)StatusIndicators.Generic;
1751 //else
1752 //cStartStop = (int)StatusIndicators.Start;
1753
1754 //returncollisions = true;
1755 break;
1756
1757 case ActorTypes.Prim:
1758 if (p1 is OdePrim)
1759 {
1760 cp1 = (OdePrim) p1;
1761 obj2LocalID = cp1.LocalID;
1762 cp1.AddCollisionEvent(cc2.LocalID, contact);
1763 }
1764 //ctype = (int)CollisionCategories.Geom;
1765
1766 //if (cp1.CollidingObj)
1767 //cStartStop = (int)StatusIndicators.Generic;
1768 //else
1769 //cStartStop = (int)StatusIndicators.Start;
1770
1771 //returncollisions = true;
1772 break;
1773
1774 case ActorTypes.Ground:
1775 case ActorTypes.Unknown:
1776 obj2LocalID = 0;
1777 //ctype = (int)CollisionCategories.Land;
1778 //returncollisions = true;
1779 break;
1780 }
1781
1782 cc2.AddCollisionEvent(obj2LocalID, contact);
1783 break;
1784
1785 case ActorTypes.Prim:
1786
1787 if (p2 is OdePrim)
1788 {
1789 cp2 = (OdePrim) p2;
1790
1791 // obj1LocalID = cp2.m_localID;
1792 switch ((ActorTypes) p1.PhysicsActorType)
1793 {
1794 case ActorTypes.Agent:
1795 if (p1 is OdeCharacter)
1796 {
1797 cc1 = (OdeCharacter) p1;
1798 obj2LocalID = cc1.LocalID;
1799 cc1.AddCollisionEvent(cp2.LocalID, contact);
1800 //ctype = (int)CollisionCategories.Character;
1801
1802 //if (cc1.CollidingObj)
1803 //cStartStop = (int)StatusIndicators.Generic;
1804 //else
1805 //cStartStop = (int)StatusIndicators.Start;
1806 //returncollisions = true;
1807 }
1808 break;
1809 case ActorTypes.Prim:
1810
1811 if (p1 is OdePrim)
1812 {
1813 cp1 = (OdePrim) p1;
1814 obj2LocalID = cp1.LocalID;
1815 cp1.AddCollisionEvent(cp2.LocalID, contact);
1816 //ctype = (int)CollisionCategories.Geom;
1817
1818 //if (cp1.CollidingObj)
1819 //cStartStop = (int)StatusIndicators.Generic;
1820 //else
1821 //cStartStop = (int)StatusIndicators.Start;
1822
1823 //returncollisions = true;
1824 }
1825 break;
1826
1827 case ActorTypes.Ground:
1828 case ActorTypes.Unknown:
1829 obj2LocalID = 0;
1830 //ctype = (int)CollisionCategories.Land;
1831
1832 //returncollisions = true;
1833 break;
1834 }
1835
1836 cp2.AddCollisionEvent(obj2LocalID, contact);
1837 }
1838 break;
1839 }
1840 //if (returncollisions)
1841 //{
1842
1843 //lock (m_storedCollisions)
1844 //{
1845 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1846 //if (m_storedCollisions.ContainsKey(cDictKey))
1847 //{
1848 //sCollisionData objd = m_storedCollisions[cDictKey];
1849 //objd.NumberOfCollisions += 1;
1850 //objd.lastframe = framecount;
1851 //m_storedCollisions[cDictKey] = objd;
1852 //}
1853 //else
1854 //{
1855 //sCollisionData objd = new sCollisionData();
1856 //objd.ColliderLocalId = obj1LocalID;
1857 //objd.CollidedWithLocalId = obj2LocalID;
1858 //objd.CollisionType = ctype;
1859 //objd.NumberOfCollisions = 1;
1860 //objd.lastframe = framecount;
1861 //objd.StatusIndicator = cStartStop;
1862 //m_storedCollisions.Add(cDictKey, objd);
1863 //}
1864 //}
1865 // }
1866 }
1867
1868 private int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1869 {
1870 /* String name1 = null;
1871 String name2 = null;
1872
1873 if (!geom_name_map.TryGetValue(trimesh, out name1))
1874 {
1875 name1 = "null";
1876 }
1877 if (!geom_name_map.TryGetValue(refObject, out name2))
1878 {
1879 name2 = "null";
1880 }
1881
1882 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1883 */
1884 return 1;
1885 }
1886
1887 private int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1888 {
1889// String name1 = null;
1890// String name2 = null;
1891//
1892// if (!geom_name_map.TryGetValue(trimesh, out name1))
1893// {
1894// name1 = "null";
1895// }
1896//
1897// if (!geom_name_map.TryGetValue(refObject, out name2))
1898// {
1899// name2 = "null";
1900// }
1901
1902 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1903
1904 d.Vector3 v0 = new d.Vector3();
1905 d.Vector3 v1 = new d.Vector3();
1906 d.Vector3 v2 = new d.Vector3();
1907
1908 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1909 // 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);
1910
1911 return 1;
1912 }
1913
1914 /// <summary>
1915 /// This is our collision testing routine in ODE
1916 /// </summary>
1917 private void collision_optimized()
1918 {
1919 _perloopContact.Clear();
1920
1921 foreach (OdeCharacter chr in _characters)
1922 {
1923 // Reset the collision values to false
1924 // since we don't know if we're colliding yet
1925 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1926 continue;
1927
1928 chr.IsColliding = false;
1929 chr.CollidingGround = false;
1930 chr.CollidingObj = false;
1931
1932 // Test the avatar's geometry for collision with the space
1933 // This will return near and the space that they are the closest to
1934 // And we'll run this again against the avatar and the space segment
1935 // This will return with a bunch of possible objects in the space segment
1936 // and we'll run it again on all of them.
1937 try
1938 {
1939 CollideSpaces(space, chr.Shell, IntPtr.Zero);
1940 }
1941 catch (AccessViolationException)
1942 {
1943 m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", PhysicsSceneName);
1944 }
1945
1946 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1947 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1948 //{
1949 //chr.Position.Z = terrainheight + 10.0f;
1950 //forcedZ = true;
1951 //}
1952 }
1953
1954 if (CollectStats)
1955 {
1956 m_tempAvatarCollisionsThisFrame = _perloopContact.Count;
1957 m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame;
1958 }
1959
1960 List<OdePrim> removeprims = null;
1961 foreach (OdePrim chr in _activeprims)
1962 {
1963 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1964 {
1965 try
1966 {
1967 lock (chr)
1968 {
1969 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1970 {
1971 CollideSpaces(space, chr.prim_geom, IntPtr.Zero);
1972 }
1973 else
1974 {
1975 if (removeprims == null)
1976 {
1977 removeprims = new List<OdePrim>();
1978 }
1979 removeprims.Add(chr);
1980 m_log.Error(
1981 "[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!");
1982 }
1983 }
1984 }
1985 catch (AccessViolationException)
1986 {
1987 m_log.Error("[ODE SCENE]: Unable to space collide");
1988 }
1989 }
1990 }
1991
1992 if (CollectStats)
1993 m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame;
1994
1995 if (removeprims != null)
1996 {
1997 foreach (OdePrim chr in removeprims)
1998 {
1999 _activeprims.Remove(chr);
2000 }
2001 }
2002 }
2003
2004 #endregion
2005
2006 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
2007 {
2008 if (!m_suportCombine)
2009 return;
2010 m_worldOffset = offset;
2011 WorldExtents = new Vector2(extents.X, extents.Y);
2012 m_parentScene = pScene;
2013 }
2014
2015 // Recovered for use by fly height. Kitto Flora
2016 internal float GetTerrainHeightAtXY(float x, float y)
2017 {
2018 IntPtr heightFieldGeom = IntPtr.Zero;
2019 int offsetX = 0;
2020 int offsetY = 0;
2021
2022 if (m_suportCombine)
2023 {
2024 offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
2025 offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
2026 }
2027
2028 if(RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
2029 {
2030 if (heightFieldGeom != IntPtr.Zero)
2031 {
2032 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
2033 {
2034
2035 int index;
2036
2037
2038 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
2039 (int)x < 0.001f || (int)y < 0.001f)
2040 return 0;
2041
2042 x = x - offsetX + 1f;
2043 y = y - offsetY + 1f;
2044
2045 index = (int)((int)x * ((int)m_regionHeight +3) + (int)y);
2046
2047 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
2048 {
2049 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
2050 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
2051 }
2052
2053 else
2054 return 0f;
2055 }
2056 else
2057 {
2058 return 0f;
2059 }
2060
2061 }
2062 else
2063 {
2064 return 0f;
2065 }
2066
2067 }
2068 else
2069 {
2070 return 0f;
2071 }
2072 }
2073// End recovered. Kitto Flora
2074
2075 /// <summary>
2076 /// Add actor to the list that should receive collision events in the simulate loop.
2077 /// </summary>
2078 /// <param name="obj"></param>
2079 internal void AddCollisionEventReporting(PhysicsActor obj)
2080 {
2081// m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID);
2082
2083 lock (m_collisionEventActorsChanges)
2084 m_collisionEventActorsChanges[obj.LocalID] = obj;
2085 }
2086
2087 /// <summary>
2088 /// Remove actor from the list that should receive collision events in the simulate loop.
2089 /// </summary>
2090 /// <param name="obj"></param>
2091 internal void RemoveCollisionEventReporting(PhysicsActor obj)
2092 {
2093// m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID);
2094
2095 lock (m_collisionEventActorsChanges)
2096 m_collisionEventActorsChanges[obj.LocalID] = null;
2097 }
2098
2099 #region Add/Remove Entities
2100
2101 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
2102 {
2103 OdeCharacter newAv
2104 = new OdeCharacter(
2105 avName, this, position, velocity, size, avPIDD, avPIDP,
2106 avCapRadius, avStandupTensor, avDensity,
2107 avMovementDivisorWalk, avMovementDivisorRun);
2108
2109 newAv.Flying = isFlying;
2110 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
2111 newAv.m_avatarplanted = avplanted;
2112
2113 return newAv;
2114 }
2115
2116 public override void RemoveAvatar(PhysicsActor actor)
2117 {
2118// m_log.DebugFormat(
2119// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}",
2120// actor.Name, actor.LocalID, Name);
2121
2122 ((OdeCharacter) actor).Destroy();
2123 }
2124
2125 internal void AddCharacter(OdeCharacter chr)
2126 {
2127 chr.m_avatarplanted = avplanted;
2128 if (!_characters.Contains(chr))
2129 {
2130 _characters.Add(chr);
2131
2132// m_log.DebugFormat(
2133// "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}",
2134// chr.Name, chr.LocalID, Name, _characters.Count);
2135
2136 if (chr.bad)
2137 m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to characters list", chr.m_uuid);
2138 }
2139 else
2140 {
2141 m_log.ErrorFormat(
2142 "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!",
2143 chr.Name, chr.LocalID);
2144 }
2145 }
2146
2147 internal void RemoveCharacter(OdeCharacter chr)
2148 {
2149 if (_characters.Contains(chr))
2150 {
2151 _characters.Remove(chr);
2152
2153// m_log.DebugFormat(
2154// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}",
2155// chr.Name, chr.LocalID, Name, _characters.Count);
2156 }
2157 else
2158 {
2159 m_log.ErrorFormat(
2160 "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!",
2161 chr.Name, chr.LocalID);
2162 }
2163 }
2164
2165 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
2166 PrimitiveBaseShape pbs, bool isphysical, uint localID)
2167 {
2168 Vector3 pos = position;
2169 Vector3 siz = size;
2170 Quaternion rot = rotation;
2171
2172 OdePrim newPrim;
2173 lock (OdeLock)
2174 {
2175 newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical);
2176
2177 lock (_prims)
2178 _prims.Add(newPrim);
2179 }
2180 newPrim.LocalID = localID;
2181 return newPrim;
2182 }
2183
2184 /// <summary>
2185 /// Make this prim subject to physics.
2186 /// </summary>
2187 /// <param name="prim"></param>
2188 internal void ActivatePrim(OdePrim prim)
2189 {
2190 // adds active prim.. (ones that should be iterated over in collisions_optimized
2191 if (!_activeprims.Contains(prim))
2192 _activeprims.Add(prim);
2193 //else
2194 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
2195 }
2196
2197 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
2198 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
2199 {
2200// m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name);
2201
2202 return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid);
2203 }
2204
2205 public override float TimeDilation
2206 {
2207 get { return m_timeDilation; }
2208 }
2209
2210 public override bool SupportsNINJAJoints
2211 {
2212 get { return m_NINJA_physics_joints_enabled; }
2213 }
2214
2215 // internal utility function: must be called within a lock (OdeLock)
2216 private void InternalAddActiveJoint(PhysicsJoint joint)
2217 {
2218 activeJoints.Add(joint);
2219 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
2220 }
2221
2222 // internal utility function: must be called within a lock (OdeLock)
2223 private void InternalAddPendingJoint(OdePhysicsJoint joint)
2224 {
2225 pendingJoints.Add(joint);
2226 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
2227 }
2228
2229 // internal utility function: must be called within a lock (OdeLock)
2230 private void InternalRemovePendingJoint(PhysicsJoint joint)
2231 {
2232 pendingJoints.Remove(joint);
2233 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
2234 }
2235
2236 // internal utility function: must be called within a lock (OdeLock)
2237 private void InternalRemoveActiveJoint(PhysicsJoint joint)
2238 {
2239 activeJoints.Remove(joint);
2240 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
2241 }
2242
2243 public override void DumpJointInfo()
2244 {
2245 string hdr = "[NINJA] JOINTINFO: ";
2246 foreach (PhysicsJoint j in pendingJoints)
2247 {
2248 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
2249 }
2250 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
2251 foreach (string jointName in SOPName_to_pendingJoint.Keys)
2252 {
2253 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
2254 }
2255 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
2256 foreach (PhysicsJoint j in activeJoints)
2257 {
2258 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
2259 }
2260 m_log.Debug(hdr + activeJoints.Count + " total active joints");
2261 foreach (string jointName in SOPName_to_activeJoint.Keys)
2262 {
2263 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
2264 }
2265 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
2266
2267 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
2268 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
2269 foreach (string actorName in joints_connecting_actor.Keys)
2270 {
2271 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
2272 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
2273 {
2274 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
2275 }
2276 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
2277 }
2278 }
2279
2280 public override void RequestJointDeletion(string ObjectNameInScene)
2281 {
2282 lock (externalJointRequestsLock)
2283 {
2284 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
2285 {
2286 requestedJointsToBeDeleted.Add(ObjectNameInScene);
2287 }
2288 }
2289 }
2290
2291 private void DeleteRequestedJoints()
2292 {
2293 List<string> myRequestedJointsToBeDeleted;
2294 lock (externalJointRequestsLock)
2295 {
2296 // make a local copy of the shared list for processing (threading issues)
2297 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
2298 }
2299
2300 foreach (string jointName in myRequestedJointsToBeDeleted)
2301 {
2302 lock (OdeLock)
2303 {
2304 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
2305 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
2306 {
2307 OdePhysicsJoint joint = null;
2308 if (SOPName_to_activeJoint.ContainsKey(jointName))
2309 {
2310 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
2311 InternalRemoveActiveJoint(joint);
2312 }
2313 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
2314 {
2315 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
2316 InternalRemovePendingJoint(joint);
2317 }
2318
2319 if (joint != null)
2320 {
2321 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
2322 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
2323 {
2324 string bodyName = joint.BodyNames[iBodyName];
2325 if (bodyName != "NULL")
2326 {
2327 joints_connecting_actor[bodyName].Remove(joint);
2328 if (joints_connecting_actor[bodyName].Count == 0)
2329 {
2330 joints_connecting_actor.Remove(bodyName);
2331 }
2332 }
2333 }
2334
2335 DoJointDeactivated(joint);
2336 if (joint.jointID != IntPtr.Zero)
2337 {
2338 d.JointDestroy(joint.jointID);
2339 joint.jointID = IntPtr.Zero;
2340 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
2341 }
2342 else
2343 {
2344 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
2345 }
2346 }
2347 else
2348 {
2349 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
2350 }
2351 }
2352 else
2353 {
2354 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
2355 }
2356 }
2357 }
2358
2359 // remove processed joints from the shared list
2360 lock (externalJointRequestsLock)
2361 {
2362 foreach (string jointName in myRequestedJointsToBeDeleted)
2363 {
2364 requestedJointsToBeDeleted.Remove(jointName);
2365 }
2366 }
2367 }
2368
2369 // for pending joints we don't know if their associated bodies exist yet or not.
2370 // the joint is actually created during processing of the taints
2371 private void CreateRequestedJoints()
2372 {
2373 List<PhysicsJoint> myRequestedJointsToBeCreated;
2374 lock (externalJointRequestsLock)
2375 {
2376 // make a local copy of the shared list for processing (threading issues)
2377 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
2378 }
2379
2380 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2381 {
2382 lock (OdeLock)
2383 {
2384 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
2385 {
2386 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);
2387 continue;
2388 }
2389 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
2390 {
2391 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);
2392 continue;
2393 }
2394
2395 InternalAddPendingJoint(joint as OdePhysicsJoint);
2396
2397 if (joint.BodyNames.Count >= 2)
2398 {
2399 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
2400 {
2401 string bodyName = joint.BodyNames[iBodyName];
2402 if (bodyName != "NULL")
2403 {
2404 if (!joints_connecting_actor.ContainsKey(bodyName))
2405 {
2406 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
2407 }
2408 joints_connecting_actor[bodyName].Add(joint);
2409 }
2410 }
2411 }
2412 }
2413 }
2414
2415 // remove processed joints from shared list
2416 lock (externalJointRequestsLock)
2417 {
2418 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2419 {
2420 requestedJointsToBeCreated.Remove(joint);
2421 }
2422 }
2423 }
2424
2425 /// <summary>
2426 /// Add a request for joint creation.
2427 /// </summary>
2428 /// <remarks>
2429 /// this joint will just be added to a waiting list that is NOT processed during the main
2430 /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
2431 /// </remarks>
2432 /// <param name="objectNameInScene"></param>
2433 /// <param name="jointType"></param>
2434 /// <param name="position"></param>
2435 /// <param name="rotation"></param>
2436 /// <param name="parms"></param>
2437 /// <param name="bodyNames"></param>
2438 /// <param name="trackedBodyName"></param>
2439 /// <param name="localRotation"></param>
2440 /// <returns></returns>
2441 public override PhysicsJoint RequestJointCreation(
2442 string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2443 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2444 {
2445 OdePhysicsJoint joint = new OdePhysicsJoint();
2446 joint.ObjectNameInScene = objectNameInScene;
2447 joint.Type = jointType;
2448 joint.Position = position;
2449 joint.Rotation = rotation;
2450 joint.RawParams = parms;
2451 joint.BodyNames = new List<string>(bodyNames);
2452 joint.TrackedBodyName = trackedBodyName;
2453 joint.LocalRotation = localRotation;
2454 joint.jointID = IntPtr.Zero;
2455 joint.ErrorMessageCount = 0;
2456
2457 lock (externalJointRequestsLock)
2458 {
2459 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2460 {
2461 requestedJointsToBeCreated.Add(joint);
2462 }
2463 }
2464
2465 return joint;
2466 }
2467
2468 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2469 {
2470 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2471 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2472 {
2473 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2474 //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)
2475 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2476 {
2477 jointsToRemove.Add(j);
2478 }
2479 foreach (PhysicsJoint j in jointsToRemove)
2480 {
2481 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2482 RequestJointDeletion(j.ObjectNameInScene);
2483 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2484 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)
2485 }
2486 }
2487 }
2488
2489 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2490 {
2491 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2492 lock (OdeLock)
2493 {
2494 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2495 RemoveAllJointsConnectedToActor(actor);
2496 }
2497 }
2498
2499 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2500 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2501 {
2502 Debug.Assert(joint.IsInPhysicsEngine);
2503 d.Vector3 pos = new d.Vector3();
2504
2505 if (!(joint is OdePhysicsJoint))
2506 {
2507 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2508 }
2509 else
2510 {
2511 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2512 switch (odeJoint.Type)
2513 {
2514 case PhysicsJointType.Ball:
2515 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2516 break;
2517 case PhysicsJointType.Hinge:
2518 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2519 break;
2520 }
2521 }
2522 return new Vector3(pos.X, pos.Y, pos.Z);
2523 }
2524
2525 /// <summary>
2526 /// Get joint axis.
2527 /// </summary>
2528 /// <remarks>
2529 /// normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2530 /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2531 /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2532 /// keeping track of the joint's original orientation relative to one of the involved bodies.
2533 /// </remarks>
2534 /// <param name="joint"></param>
2535 /// <returns></returns>
2536 public override Vector3 GetJointAxis(PhysicsJoint joint)
2537 {
2538 Debug.Assert(joint.IsInPhysicsEngine);
2539 d.Vector3 axis = new d.Vector3();
2540
2541 if (!(joint is OdePhysicsJoint))
2542 {
2543 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2544 }
2545 else
2546 {
2547 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2548 switch (odeJoint.Type)
2549 {
2550 case PhysicsJointType.Ball:
2551 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2552 break;
2553 case PhysicsJointType.Hinge:
2554 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2555 break;
2556 }
2557 }
2558 return new Vector3(axis.X, axis.Y, axis.Z);
2559 }
2560
2561 /// <summary>
2562 /// Stop this prim being subject to physics
2563 /// </summary>
2564 /// <param name="prim"></param>
2565 internal void DeactivatePrim(OdePrim prim)
2566 {
2567 _activeprims.Remove(prim);
2568 }
2569
2570 public override void RemovePrim(PhysicsActor prim)
2571 {
2572 // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be
2573 // removed in the next physics simulate pass.
2574 if (prim is OdePrim)
2575 {
2576 lock (OdeLock)
2577 {
2578 OdePrim p = (OdePrim) prim;
2579
2580 p.setPrimForRemoval();
2581 AddPhysicsActorTaint(prim);
2582 }
2583 }
2584 }
2585
2586 /// <summary>
2587 /// This is called from within simulate but outside the locked portion
2588 /// We need to do our own locking here
2589 /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in
2590 /// Simulate() -- justincc).
2591 ///
2592 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2593 ///
2594 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2595 /// that the space was using.
2596 /// </summary>
2597 /// <param name="prim"></param>
2598 internal void RemovePrimThreadLocked(OdePrim prim)
2599 {
2600// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID);
2601
2602 lock (prim)
2603 {
2604 RemoveCollisionEventReporting(prim);
2605
2606 if (prim.prim_geom != IntPtr.Zero)
2607 {
2608 prim.ResetTaints();
2609
2610 if (prim.IsPhysical)
2611 {
2612 prim.disableBody();
2613 if (prim.childPrim)
2614 {
2615 prim.childPrim = false;
2616 prim.Body = IntPtr.Zero;
2617 prim.m_disabled = true;
2618 prim.IsPhysical = false;
2619 }
2620
2621
2622 }
2623 // we don't want to remove the main space
2624
2625 // If the geometry is in the targetspace, remove it from the target space
2626 //m_log.Warn(prim.m_targetSpace);
2627
2628 //if (prim.m_targetSpace != IntPtr.Zero)
2629 //{
2630 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2631 //{
2632
2633 //if (d.GeomIsSpace(prim.m_targetSpace))
2634 //{
2635 //waitForSpaceUnlock(prim.m_targetSpace);
2636 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2637 prim.m_targetSpace = IntPtr.Zero;
2638 //}
2639 //else
2640 //{
2641 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2642 //((OdePrim)prim).m_targetSpace.ToString());
2643 //}
2644
2645 //}
2646 //}
2647 //m_log.Warn(prim.prim_geom);
2648
2649 if (!prim.RemoveGeom())
2650 m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene");
2651
2652 lock (_prims)
2653 _prims.Remove(prim);
2654
2655 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2656 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2657 //{
2658 //if (prim.m_targetSpace != null)
2659 //{
2660 //if (d.GeomIsSpace(prim.m_targetSpace))
2661 //{
2662 //waitForSpaceUnlock(prim.m_targetSpace);
2663 //d.SpaceRemove(space, prim.m_targetSpace);
2664 // free up memory used by the space.
2665 //d.SpaceDestroy(prim.m_targetSpace);
2666 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2667 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2668 //}
2669 //else
2670 //{
2671 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2672 //((OdePrim) prim).m_targetSpace.ToString());
2673 //}
2674 //}
2675 //}
2676
2677 if (SupportsNINJAJoints)
2678 RemoveAllJointsConnectedToActorThreadLocked(prim);
2679 }
2680 }
2681 }
2682
2683 #endregion
2684
2685 #region Space Separation Calculation
2686
2687 /// <summary>
2688 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2689 /// </summary>
2690 /// <param name="pSpace"></param>
2691 private void resetSpaceArrayItemToZero(IntPtr pSpace)
2692 {
2693 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2694 {
2695 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2696 {
2697 if (staticPrimspace[x, y] == pSpace)
2698 staticPrimspace[x, y] = IntPtr.Zero;
2699 }
2700 }
2701 }
2702
2703// private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2704// {
2705// staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2706// }
2707
2708 /// <summary>
2709 /// Called when a static prim moves. Allocates a space for the prim based on its position
2710 /// </summary>
2711 /// <param name="geom">the pointer to the geom that moved</param>
2712 /// <param name="pos">the position that the geom moved to</param>
2713 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2714 /// <returns>a pointer to the new space it's in</returns>
2715 internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2716 {
2717 // Called from setting the Position and Size of an ODEPrim so
2718 // it's already in locked space.
2719
2720 // we don't want to remove the main space
2721 // we don't need to test physical here because this function should
2722 // never be called if the prim is physical(active)
2723
2724 // All physical prim end up in the root space
2725 //Thread.Sleep(20);
2726 if (currentspace != space)
2727 {
2728 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2729 //if (currentspace == IntPtr.Zero)
2730 //{
2731 //int adfadf = 0;
2732 //}
2733 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2734 {
2735 if (d.GeomIsSpace(currentspace))
2736 {
2737// waitForSpaceUnlock(currentspace);
2738 d.SpaceRemove(currentspace, geom);
2739 }
2740 else
2741 {
2742 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2743 " Geom:" + geom);
2744 }
2745 }
2746 else
2747 {
2748 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2749 if (sGeomIsIn != IntPtr.Zero)
2750 {
2751 if (d.GeomIsSpace(currentspace))
2752 {
2753// waitForSpaceUnlock(sGeomIsIn);
2754 d.SpaceRemove(sGeomIsIn, geom);
2755 }
2756 else
2757 {
2758 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2759 sGeomIsIn + " Geom:" + geom);
2760 }
2761 }
2762 }
2763
2764 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2765 if (d.SpaceGetNumGeoms(currentspace) == 0)
2766 {
2767 if (currentspace != IntPtr.Zero)
2768 {
2769 if (d.GeomIsSpace(currentspace))
2770 {
2771// waitForSpaceUnlock(currentspace);
2772// waitForSpaceUnlock(space);
2773 d.SpaceRemove(space, currentspace);
2774 // free up memory used by the space.
2775
2776 //d.SpaceDestroy(currentspace);
2777 resetSpaceArrayItemToZero(currentspace);
2778 }
2779 else
2780 {
2781 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2782 currentspace + " Geom:" + geom);
2783 }
2784 }
2785 }
2786 }
2787 else
2788 {
2789 // this is a physical object that got disabled. ;.;
2790 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2791 {
2792 if (d.SpaceQuery(currentspace, geom))
2793 {
2794 if (d.GeomIsSpace(currentspace))
2795 {
2796// waitForSpaceUnlock(currentspace);
2797 d.SpaceRemove(currentspace, geom);
2798 }
2799 else
2800 {
2801 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2802 currentspace + " Geom:" + geom);
2803 }
2804 }
2805 else
2806 {
2807 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2808 if (sGeomIsIn != IntPtr.Zero)
2809 {
2810 if (d.GeomIsSpace(sGeomIsIn))
2811 {
2812// waitForSpaceUnlock(sGeomIsIn);
2813 d.SpaceRemove(sGeomIsIn, geom);
2814 }
2815 else
2816 {
2817 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2818 sGeomIsIn + " Geom:" + geom);
2819 }
2820 }
2821 }
2822 }
2823 }
2824
2825 // The routines in the Position and Size sections do the 'inserting' into the space,
2826 // so all we have to do is make sure that the space that we're putting the prim into
2827 // is in the 'main' space.
2828 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2829 IntPtr newspace = calculateSpaceForGeom(pos);
2830
2831 if (newspace == IntPtr.Zero)
2832 {
2833 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2834 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2835 }
2836
2837 return newspace;
2838 }
2839
2840 /// <summary>
2841 /// Creates a new space at X Y
2842 /// </summary>
2843 /// <param name="iprimspaceArrItemX"></param>
2844 /// <param name="iprimspaceArrItemY"></param>
2845 /// <returns>A pointer to the created space</returns>
2846 internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2847 {
2848 // creating a new space for prim and inserting it into main space.
2849 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2850 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2851// waitForSpaceUnlock(space);
2852 d.SpaceSetSublevel(space, 1);
2853 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2854
2855 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2856 }
2857
2858 /// <summary>
2859 /// Calculates the space the prim should be in by its position
2860 /// </summary>
2861 /// <param name="pos"></param>
2862 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2863 internal IntPtr calculateSpaceForGeom(Vector3 pos)
2864 {
2865 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2866 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2867 return staticPrimspace[xyspace[0], xyspace[1]];
2868 }
2869
2870 /// <summary>
2871 /// Holds the space allocation logic
2872 /// </summary>
2873 /// <param name="pos"></param>
2874 /// <returns>an array item based on the position</returns>
2875 internal int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2876 {
2877 int[] returnint = new int[2];
2878
2879 returnint[0] = (int) (pos.X * spacesPerMeterX);
2880
2881 if (returnint[0] > spaceGridMaxX)
2882 returnint[0] = spaceGridMaxX;
2883 if (returnint[0] < 0)
2884 returnint[0] = 0;
2885
2886 returnint[1] = (int)(pos.Y * spacesPerMeterY);
2887 if (returnint[1] > spaceGridMaxY)
2888 returnint[1] = spaceGridMaxY;
2889 if (returnint[1] < 0)
2890 returnint[1] = 0;
2891
2892 return returnint;
2893 }
2894
2895 #endregion
2896
2897 /// <summary>
2898 /// Routine to figure out if we need to mesh this prim with our mesher
2899 /// </summary>
2900 /// <param name="pbs"></param>
2901 /// <returns></returns>
2902 internal bool needsMeshing(PrimitiveBaseShape pbs)
2903 {
2904 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2905 // but we still need to check for sculptie meshing being enabled so this is the most
2906 // convenient place to do it for now...
2907
2908 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2909 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2910 int iPropertiesNotSupportedDefault = 0;
2911
2912 if (pbs.SculptEntry && !meshSculptedPrim)
2913 {
2914#if SPAM
2915 m_log.Warn("NonMesh");
2916#endif
2917 return false;
2918 }
2919
2920 // 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
2921 if (!forceSimplePrimMeshing && !pbs.SculptEntry)
2922 {
2923 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2924 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2925 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2926 {
2927
2928 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2929 && pbs.ProfileHollow == 0
2930 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2931 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2932 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2933 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2934 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2935 {
2936#if SPAM
2937 m_log.Warn("NonMesh");
2938#endif
2939 return false;
2940 }
2941 }
2942 }
2943
2944 if (pbs.ProfileHollow != 0)
2945 iPropertiesNotSupportedDefault++;
2946
2947 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2948 iPropertiesNotSupportedDefault++;
2949
2950 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2951 iPropertiesNotSupportedDefault++;
2952
2953 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2954 iPropertiesNotSupportedDefault++;
2955
2956 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2957 iPropertiesNotSupportedDefault++;
2958
2959 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2960 iPropertiesNotSupportedDefault++;
2961
2962 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2963 iPropertiesNotSupportedDefault++;
2964
2965 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))
2966 iPropertiesNotSupportedDefault++;
2967
2968 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2969 iPropertiesNotSupportedDefault++;
2970
2971 // test for torus
2972 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2973 {
2974 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2975 {
2976 iPropertiesNotSupportedDefault++;
2977 }
2978 }
2979 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2980 {
2981 if (pbs.PathCurve == (byte)Extrusion.Straight)
2982 {
2983 iPropertiesNotSupportedDefault++;
2984 }
2985
2986 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2987 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2988 {
2989 iPropertiesNotSupportedDefault++;
2990 }
2991 }
2992 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2993 {
2994 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2995 {
2996 iPropertiesNotSupportedDefault++;
2997 }
2998 }
2999 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
3000 {
3001 if (pbs.PathCurve == (byte)Extrusion.Straight)
3002 {
3003 iPropertiesNotSupportedDefault++;
3004 }
3005 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
3006 {
3007 iPropertiesNotSupportedDefault++;
3008 }
3009 }
3010
3011 if (pbs.SculptEntry && meshSculptedPrim)
3012 iPropertiesNotSupportedDefault++;
3013
3014 if (iPropertiesNotSupportedDefault == 0)
3015 {
3016#if SPAM
3017 m_log.Warn("NonMesh");
3018#endif
3019 return false;
3020 }
3021#if SPAM
3022 m_log.Debug("Mesh");
3023#endif
3024 return true;
3025 }
3026
3027 /// <summary>
3028 /// Called after our prim properties are set Scale, position etc.
3029 /// </summary>
3030 /// <remarks>
3031 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
3032 /// This assures us that we have no race conditions
3033 /// </remarks>
3034 /// <param name="actor"></param>
3035 public override void AddPhysicsActorTaint(PhysicsActor actor)
3036 {
3037 if (actor is OdePrim)
3038 {
3039 OdePrim taintedprim = ((OdePrim)actor);
3040 lock (_taintedPrims)
3041 _taintedPrims.Add(taintedprim);
3042 }
3043 else if (actor is OdeCharacter)
3044 {
3045 OdeCharacter taintedchar = ((OdeCharacter)actor);
3046 lock (_taintedActors)
3047 {
3048 _taintedActors.Add(taintedchar);
3049 if (taintedchar.bad)
3050 m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
3051 }
3052 }
3053 }
3054
3055 /// <summary>
3056 /// This is our main simulate loop
3057 /// </summary>
3058 /// <remarks>
3059 /// It's thread locked by a Mutex in the scene.
3060 /// It holds Collisions, it instructs ODE to step through the physical reactions
3061 /// It moves the objects around in memory
3062 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
3063 /// </remarks>
3064 /// <param name="timeStep"></param>
3065 /// <returns>The number of frames simulated over that period.</returns>
3066 public override float Simulate(float timeStep)
3067 {
3068 if (!_worldInitialized) return 11f;
3069
3070 int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0;
3071 int tempTick = 0, tempTick2 = 0;
3072
3073 if (framecount >= int.MaxValue)
3074 framecount = 0;
3075
3076 framecount++;
3077
3078 float fps = 0;
3079
3080 float timeLeft = timeStep;
3081
3082 //m_log.Info(timeStep.ToString());
3083// step_time += timeSte
3084//
3085// // If We're loaded down by something else,
3086// // or debugging with the Visual Studio project on pause
3087// // skip a few frames to catch up gracefully.
3088// // without shooting the physicsactors all over the place
3089//
3090// if (step_time >= m_SkipFramesAtms)
3091// {
3092// // Instead of trying to catch up, it'll do 5 physics frames only
3093// step_time = ODE_STEPSIZE;
3094// m_physicsiterations = 5;
3095// }
3096// else
3097// {
3098// m_physicsiterations = 10;
3099// }
3100
3101 // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential
3102 // deadlock if the collision event tries to lock something else later on which is already locked by a
3103 // caller that is adding or removing the collision event.
3104 lock (m_collisionEventActorsChanges)
3105 {
3106 foreach (KeyValuePair<uint, PhysicsActor> kvp in m_collisionEventActorsChanges)
3107 {
3108 if (kvp.Value == null)
3109 m_collisionEventActors.Remove(kvp.Key);
3110 else
3111 m_collisionEventActors[kvp.Key] = kvp.Value;
3112 }
3113
3114 m_collisionEventActorsChanges.Clear();
3115 }
3116
3117 if (SupportsNINJAJoints)
3118 {
3119 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
3120 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
3121 }
3122
3123 lock (OdeLock)
3124 {
3125 // Process 10 frames if the sim is running normal..
3126 // process 5 frames if the sim is running slow
3127 //try
3128 //{
3129 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
3130 //}
3131 //catch (StackOverflowException)
3132 //{
3133 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
3134 // ode.drelease(world);
3135 //base.TriggerPhysicsBasedRestart();
3136 //}
3137
3138 // Figure out the Frames Per Second we're going at.
3139 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
3140
3141 fps = (timeStep / ODE_STEPSIZE) * 1000;
3142 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
3143 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
3144
3145 while (timeLeft > 0.0f)
3146 {
3147 try
3148 {
3149 if (CollectStats)
3150 tempTick = Util.EnvironmentTickCount();
3151
3152 lock (_taintedActors)
3153 {
3154 foreach (OdeCharacter character in _taintedActors)
3155 character.ProcessTaints();
3156
3157 _taintedActors.Clear();
3158 }
3159
3160 if (CollectStats)
3161 {
3162 tempTick2 = Util.EnvironmentTickCount();
3163 m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3164 tempTick = tempTick2;
3165 }
3166
3167 lock (_taintedPrims)
3168 {
3169 foreach (OdePrim prim in _taintedPrims)
3170 {
3171 if (prim.m_taintremove)
3172 {
3173// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name);
3174 RemovePrimThreadLocked(prim);
3175 }
3176 else
3177 {
3178// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name);
3179 prim.ProcessTaints();
3180 }
3181
3182 prim.m_collisionscore = 0;
3183
3184 // This loop can block up the Heartbeat for a very long time on large regions.
3185 // We need to let the Watchdog know that the Heartbeat is not dead
3186 // NOTE: This is currently commented out, but if things like OAR loading are
3187 // timing the heartbeat out we will need to uncomment it
3188 //Watchdog.UpdateThread();
3189 }
3190
3191 if (SupportsNINJAJoints)
3192 SimulatePendingNINJAJoints();
3193
3194 _taintedPrims.Clear();
3195 }
3196
3197 if (CollectStats)
3198 {
3199 tempTick2 = Util.EnvironmentTickCount();
3200 m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3201 tempTick = tempTick2;
3202 }
3203
3204 // Move characters
3205 foreach (OdeCharacter actor in _characters)
3206 actor.Move(defects);
3207
3208 if (defects.Count != 0)
3209 {
3210 foreach (OdeCharacter actor in defects)
3211 {
3212 m_log.ErrorFormat(
3213 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving",
3214 actor.Name, actor.LocalID, PhysicsSceneName);
3215
3216 RemoveCharacter(actor);
3217 actor.DestroyOdeStructures();
3218 }
3219
3220 defects.Clear();
3221 }
3222
3223 if (CollectStats)
3224 {
3225 tempTick2 = Util.EnvironmentTickCount();
3226 m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3227 tempTick = tempTick2;
3228 }
3229
3230 // Move other active objects
3231 foreach (OdePrim prim in _activeprims)
3232 {
3233 prim.m_collisionscore = 0;
3234 prim.Move(timeStep);
3235 }
3236
3237 if (CollectStats)
3238 {
3239 tempTick2 = Util.EnvironmentTickCount();
3240 m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3241 tempTick = tempTick2;
3242 }
3243
3244 //if ((framecount % m_randomizeWater) == 0)
3245 // randomizeWater(waterlevel);
3246
3247 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
3248 m_rayCastManager.ProcessQueuedRequests();
3249
3250 if (CollectStats)
3251 {
3252 tempTick2 = Util.EnvironmentTickCount();
3253 m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3254 tempTick = tempTick2;
3255 }
3256
3257 collision_optimized();
3258
3259 if (CollectStats)
3260 {
3261 tempTick2 = Util.EnvironmentTickCount();
3262 m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3263 tempTick = tempTick2;
3264 }
3265
3266 foreach (PhysicsActor obj in m_collisionEventActors.Values)
3267 {
3268// m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID);
3269
3270 switch ((ActorTypes)obj.PhysicsActorType)
3271 {
3272 case ActorTypes.Agent:
3273 OdeCharacter cobj = (OdeCharacter)obj;
3274 cobj.AddCollisionFrameTime(100);
3275 cobj.SendCollisions();
3276 break;
3277
3278 case ActorTypes.Prim:
3279 OdePrim pobj = (OdePrim)obj;
3280 pobj.SendCollisions();
3281 break;
3282 }
3283 }
3284
3285// if (m_global_contactcount > 0)
3286// m_log.DebugFormat(
3287// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount);
3288
3289 m_global_contactcount = 0;
3290
3291 if (CollectStats)
3292 {
3293 tempTick2 = Util.EnvironmentTickCount();
3294 m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3295 tempTick = tempTick2;
3296 }
3297
3298 d.WorldQuickStep(world, ODE_STEPSIZE);
3299
3300 if (CollectStats)
3301 m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
3302
3303 d.JointGroupEmpty(contactgroup);
3304 }
3305 catch (Exception e)
3306 {
3307 m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3308 }
3309
3310 timeLeft -= ODE_STEPSIZE;
3311 }
3312
3313 if (CollectStats)
3314 tempTick = Util.EnvironmentTickCount();
3315
3316 foreach (OdeCharacter actor in _characters)
3317 {
3318 if (actor.bad)
3319 m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3320
3321 actor.UpdatePositionAndVelocity(defects);
3322 }
3323
3324 if (defects.Count != 0)
3325 {
3326 foreach (OdeCharacter actor in defects)
3327 {
3328 m_log.ErrorFormat(
3329 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity",
3330 actor.Name, actor.LocalID, PhysicsSceneName);
3331
3332 RemoveCharacter(actor);
3333 actor.DestroyOdeStructures();
3334 }
3335
3336 defects.Clear();
3337 }
3338
3339 if (CollectStats)
3340 {
3341 tempTick2 = Util.EnvironmentTickCount();
3342 m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3343 tempTick = tempTick2;
3344 }
3345
3346 //if (timeStep < 0.2f)
3347
3348 foreach (OdePrim prim in _activeprims)
3349 {
3350 if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag))
3351 {
3352 prim.UpdatePositionAndVelocity();
3353
3354 if (SupportsNINJAJoints)
3355 SimulateActorPendingJoints(prim);
3356 }
3357 }
3358
3359 if (CollectStats)
3360 m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
3361
3362 //DumpJointInfo();
3363
3364 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3365 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3366 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3367 if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0))
3368 {
3369 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3370 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3371
3372 if (physics_logging_append_existing_logfile)
3373 {
3374 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3375 TextWriter fwriter = File.AppendText(fname);
3376 fwriter.WriteLine(header);
3377 fwriter.Close();
3378 }
3379
3380 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3381 }
3382
3383 latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun);
3384
3385 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
3386 // has a max of 100 ms to run theoretically.
3387 // If the main loop stalls, it calls Simulate later which makes the tick count ms larger.
3388 // If Physics stalls, it takes longer which makes the tick count ms larger.
3389
3390 if (latertickcount < 100)
3391 {
3392 m_timeDilation = 1.0f;
3393 }
3394 else
3395 {
3396 m_timeDilation = 100f / latertickcount;
3397 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f);
3398 }
3399
3400 tickCountFrameRun = Util.EnvironmentTickCount();
3401
3402 if (CollectStats)
3403 m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick);
3404 }
3405
3406 return fps;
3407 }
3408
3409 /// <summary>
3410 /// Simulate pending NINJA joints.
3411 /// </summary>
3412 /// <remarks>
3413 /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else.
3414 /// </remarks>
3415 private void SimulatePendingNINJAJoints()
3416 {
3417 // Create pending joints, if possible
3418
3419 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
3420 // a joint requires specifying the body id of both involved bodies
3421 if (pendingJoints.Count > 0)
3422 {
3423 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
3424 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
3425 foreach (PhysicsJoint joint in pendingJoints)
3426 {
3427 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
3428 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
3429 List<IntPtr> jointBodies = new List<IntPtr>();
3430 bool allJointBodiesAreReady = true;
3431 foreach (string jointParam in jointParams)
3432 {
3433 if (jointParam == "NULL")
3434 {
3435 //DoJointErrorMessage(joint, "attaching NULL joint to world");
3436 jointBodies.Add(IntPtr.Zero);
3437 }
3438 else
3439 {
3440 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
3441 bool foundPrim = false;
3442 lock (_prims)
3443 {
3444 foreach (OdePrim prim in _prims) // FIXME: inefficient
3445 {
3446 if (prim.SOPName == jointParam)
3447 {
3448 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
3449 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
3450 {
3451 jointBodies.Add(prim.Body);
3452 foundPrim = true;
3453 break;
3454 }
3455 else
3456 {
3457 DoJointErrorMessage(joint, "prim name " + jointParam +
3458 " exists but is not (yet) physical; deferring joint creation. " +
3459 "IsPhysical property is " + prim.IsPhysical +
3460 " and body is " + prim.Body);
3461 foundPrim = false;
3462 break;
3463 }
3464 }
3465 }
3466 }
3467 if (foundPrim)
3468 {
3469 // all is fine
3470 }
3471 else
3472 {
3473 allJointBodiesAreReady = false;
3474 break;
3475 }
3476 }
3477 }
3478
3479 if (allJointBodiesAreReady)
3480 {
3481 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
3482 if (jointBodies[0] == jointBodies[1])
3483 {
3484 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
3485 }
3486 else
3487 {
3488 switch (joint.Type)
3489 {
3490 case PhysicsJointType.Ball:
3491 {
3492 IntPtr odeJoint;
3493 //DoJointErrorMessage(joint, "ODE creating ball joint ");
3494 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
3495 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3496 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3497 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
3498 d.JointSetBallAnchor(odeJoint,
3499 joint.Position.X,
3500 joint.Position.Y,
3501 joint.Position.Z);
3502 //DoJointErrorMessage(joint, "ODE joint setting OK");
3503 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
3504 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
3505 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
3506 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
3507
3508 if (joint is OdePhysicsJoint)
3509 {
3510 ((OdePhysicsJoint)joint).jointID = odeJoint;
3511 }
3512 else
3513 {
3514 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3515 }
3516 }
3517 break;
3518 case PhysicsJointType.Hinge:
3519 {
3520 IntPtr odeJoint;
3521 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
3522 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
3523 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3524 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3525 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
3526 d.JointSetHingeAnchor(odeJoint,
3527 joint.Position.X,
3528 joint.Position.Y,
3529 joint.Position.Z);
3530 // We use the orientation of the x-axis of the joint's coordinate frame
3531 // as the axis for the hinge.
3532
3533 // Therefore, we must get the joint's coordinate frame based on the
3534 // joint.Rotation field, which originates from the orientation of the
3535 // joint's proxy object in the scene.
3536
3537 // The joint's coordinate frame is defined as the transformation matrix
3538 // that converts a vector from joint-local coordinates into world coordinates.
3539 // World coordinates are defined as the XYZ coordinate system of the sim,
3540 // as shown in the top status-bar of the viewer.
3541
3542 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
3543 // and use that as the hinge axis.
3544
3545 //joint.Rotation.Normalize();
3546 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
3547
3548 // Now extract the X axis of the joint's coordinate frame.
3549
3550 // Do not try to use proxyFrame.AtAxis or you will become mired in the
3551 // tar pit of transposed, inverted, and generally messed-up orientations.
3552 // (In other words, Matrix4.AtAxis() is borked.)
3553 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
3554
3555 // Instead, compute the X axis of the coordinate frame by transforming
3556 // the (1,0,0) vector. At least that works.
3557
3558 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
3559 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
3560 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
3561 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
3562 d.JointSetHingeAxis(odeJoint,
3563 jointAxis.X,
3564 jointAxis.Y,
3565 jointAxis.Z);
3566 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
3567 if (joint is OdePhysicsJoint)
3568 {
3569 ((OdePhysicsJoint)joint).jointID = odeJoint;
3570 }
3571 else
3572 {
3573 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3574 }
3575 }
3576 break;
3577 }
3578 successfullyProcessedPendingJoints.Add(joint);
3579 }
3580 }
3581 else
3582 {
3583 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
3584 }
3585 }
3586
3587 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
3588 {
3589 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
3590 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
3591 InternalRemovePendingJoint(successfullyProcessedJoint);
3592 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
3593 InternalAddActiveJoint(successfullyProcessedJoint);
3594 //DoJointErrorMessage(successfullyProcessedJoint, "done");
3595 }
3596 }
3597 }
3598
3599 /// <summary>
3600 /// Simulate the joint proxies of a NINJA actor.
3601 /// </summary>
3602 /// <remarks>
3603 /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there.
3604 /// </remarks>
3605 /// <param name="actor"></param>
3606 private void SimulateActorPendingJoints(OdePrim actor)
3607 {
3608 // If an actor moved, move its joint proxy objects as well.
3609 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3610 // for this purpose but it is never called! So we just do the joint
3611 // movement code here.
3612
3613 if (actor.SOPName != null &&
3614 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3615 joints_connecting_actor[actor.SOPName] != null &&
3616 joints_connecting_actor[actor.SOPName].Count > 0)
3617 {
3618 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3619 {
3620 if (affectedJoint.IsInPhysicsEngine)
3621 {
3622 DoJointMoved(affectedJoint);
3623 }
3624 else
3625 {
3626 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);
3627 }
3628 }
3629 }
3630 }
3631
3632 public override void GetResults()
3633 {
3634 }
3635
3636 public override bool IsThreaded
3637 {
3638 // for now we won't be multithreaded
3639 get { return false; }
3640 }
3641
3642 public override void SetTerrain(float[] heightMap)
3643 {
3644 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3645 {
3646 if (m_parentScene is OdeScene)
3647 {
3648 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3649 }
3650 }
3651 else
3652 {
3653 SetTerrain(heightMap, m_worldOffset);
3654 }
3655 }
3656
3657 private void SetTerrain(float[] heightMap, Vector3 pOffset)
3658 {
3659 int startTime = Util.EnvironmentTickCount();
3660 m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", PhysicsSceneName, pOffset);
3661
3662
3663 float[] _heightmap;
3664
3665 // ok im lasy this are just a aliases
3666 uint regionsizeX = m_regionWidth;
3667 uint regionsizeY = m_regionHeight;
3668
3669 // map is rotated
3670 uint heightmapWidth = regionsizeY + 2;
3671 uint heightmapHeight = regionsizeX + 2;
3672
3673 uint heightmapWidthSamples = heightmapWidth + 1;
3674 uint heightmapHeightSamples = heightmapHeight + 1;
3675
3676 _heightmap = new float[heightmapWidthSamples * heightmapHeightSamples];
3677
3678
3679 const float scale = 1.0f;
3680 const float offset = 0.0f;
3681 const float thickness = 10f;
3682 const int wrap = 0;
3683
3684
3685 float hfmin = float.MaxValue;
3686 float hfmax = float.MinValue;
3687 float val;
3688 uint xx;
3689 uint yy;
3690
3691 uint maxXX = regionsizeX - 1;
3692 uint maxYY = regionsizeY - 1;
3693
3694 // flipping map adding one margin all around so things don't fall in edges
3695
3696 uint xt = 0;
3697 xx = 0;
3698
3699
3700 for (uint x = 0; x < heightmapWidthSamples; x++)
3701 {
3702 if (x > 1 && xx < maxXX)
3703 xx++;
3704 yy = 0;
3705 for (uint y = 0; y < heightmapHeightSamples; y++)
3706 {
3707 if (y > 1 && y < maxYY)
3708 yy += regionsizeX;
3709
3710 val = heightMap[yy + xx];
3711 if (val < 0.0f)
3712 val = 0.0f;
3713 _heightmap[xt + y] = val;
3714
3715 if (hfmin > val)
3716 hfmin = val;
3717 if (hfmax < val)
3718 hfmax = val;
3719 }
3720 xt += heightmapHeightSamples;
3721 }
3722
3723 lock (OdeLock)
3724 {
3725 IntPtr GroundGeom = IntPtr.Zero;
3726 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3727 {
3728 RegionTerrain.Remove(pOffset);
3729 if (GroundGeom != IntPtr.Zero)
3730 {
3731 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3732 {
3733 TerrainHeightFieldHeights.Remove(GroundGeom);
3734 }
3735 d.SpaceRemove(space, GroundGeom);
3736 d.GeomDestroy(GroundGeom);
3737 }
3738
3739 }
3740 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3741 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0,
3742 heightmapWidth, heightmapHeight,
3743 (int)heightmapWidthSamples, (int)heightmapHeightSamples,
3744 scale, offset, thickness, wrap);
3745
3746 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3747 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3748 if (GroundGeom != IntPtr.Zero)
3749 {
3750 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3751 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3752
3753 }
3754 geom_name_map[GroundGeom] = "Terrain";
3755
3756 d.Matrix3 R = new d.Matrix3();
3757
3758 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3759 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3760
3761 q1 = q1 * q2;
3762 Vector3 v3;
3763 float angle;
3764 q1.GetAxisAngle(out v3, out angle);
3765
3766 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3767 d.GeomSetRotation(GroundGeom, ref R);
3768 d.GeomSetPosition(GroundGeom, pOffset.X + regionsizeX * 0.5f, pOffset.Y + regionsizeY * 0.5f, 0f);
3769 IntPtr testGround = IntPtr.Zero;
3770 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3771 {
3772 RegionTerrain.Remove(pOffset);
3773 }
3774 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3775 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3776 }
3777
3778 m_log.DebugFormat(
3779 "[ODE SCENE]: Setting terrain for {0} took {1}ms", PhysicsSceneName, Util.EnvironmentTickCountSubtract(startTime));
3780 }
3781
3782 public override void DeleteTerrain()
3783 {
3784 }
3785
3786 internal float GetWaterLevel()
3787 {
3788 return waterlevel;
3789 }
3790
3791 public override bool SupportsCombining()
3792 {
3793 return m_suportCombine;
3794 }
3795
3796 public override void SetWaterLevel(float baseheight)
3797 {
3798 waterlevel = baseheight;
3799// randomizeWater(waterlevel);
3800 }
3801
3802/*
3803 private void randomizeWater(float baseheight)
3804 {
3805 uint heightmapWidth = m_regionWidth + 2;
3806 uint heightmapHeight = m_regionHeight + 2;
3807 uint heightmapWidthSamples = m_regionWidth + 2;
3808 uint heightmapHeightSamples = m_regionHeight + 2;
3809 float scale = 1.0f;
3810 float offset = 0.0f;
3811 float thickness = 2.9f;
3812 int wrap = 0;
3813
3814 for (int i = 0; i < (258 * 258); i++)
3815 {
3816 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
3817 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
3818 }
3819
3820 lock (OdeLock)
3821 {
3822 if (WaterGeom != IntPtr.Zero)
3823 {
3824 d.SpaceRemove(space, WaterGeom);
3825 }
3826 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3827 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
3828 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
3829 offset, thickness, wrap);
3830 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
3831 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
3832 if (WaterGeom != IntPtr.Zero)
3833 {
3834 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
3835 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
3836 }
3837
3838 geom_name_map[WaterGeom] = "Water";
3839
3840 d.Matrix3 R = new d.Matrix3();
3841
3842 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3843 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3844 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3845
3846 q1 = q1 * q2;
3847 //q1 = q1 * q3;
3848 Vector3 v3;
3849 float angle;
3850 q1.GetAxisAngle(out v3, out angle);
3851
3852 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3853 d.GeomSetRotation(WaterGeom, ref R);
3854 d.GeomSetPosition(WaterGeom, 128, 128, 0);
3855 }
3856 }
3857*/
3858 public override void Dispose()
3859 {
3860 _worldInitialized = false;
3861
3862 m_rayCastManager.Dispose();
3863 m_rayCastManager = null;
3864
3865 lock (OdeLock)
3866 {
3867 lock (_prims)
3868 {
3869 foreach (OdePrim prm in _prims)
3870 {
3871 RemovePrim(prm);
3872 }
3873 }
3874
3875 //foreach (OdeCharacter act in _characters)
3876 //{
3877 //RemoveAvatar(act);
3878 //}
3879 d.WorldDestroy(world);
3880 //d.CloseODE();
3881 }
3882
3883 }
3884
3885 public override Dictionary<uint, float> GetTopColliders()
3886 {
3887 Dictionary<uint, float> topColliders;
3888
3889 lock (_prims)
3890 {
3891 List<OdePrim> orderedPrims = new List<OdePrim>(_prims);
3892 orderedPrims.OrderByDescending(p => p.CollisionScore);
3893 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
3894
3895 foreach (OdePrim p in _prims)
3896 p.CollisionScore = 0;
3897 }
3898
3899 return topColliders;
3900 }
3901
3902 public override bool SupportsRayCast()
3903 {
3904 return true;
3905 }
3906
3907 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
3908 {
3909 if (retMethod != null)
3910 {
3911 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
3912 }
3913 }
3914
3915 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
3916 {
3917 if (retMethod != null)
3918 {
3919 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
3920 }
3921 }
3922
3923 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
3924 {
3925 ContactResult[] ourResults = null;
3926 RayCallback retMethod = delegate(List<ContactResult> results)
3927 {
3928 ourResults = new ContactResult[results.Count];
3929 results.CopyTo(ourResults, 0);
3930 };
3931 int waitTime = 0;
3932 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
3933 while (ourResults == null && waitTime < 1000)
3934 {
3935 Thread.Sleep(1);
3936 waitTime++;
3937 }
3938 if (ourResults == null)
3939 return new List<ContactResult> ();
3940 return new List<ContactResult>(ourResults);
3941 }
3942
3943#if USE_DRAWSTUFF
3944 // Keyboard callback
3945 public void command(int cmd)
3946 {
3947 IntPtr geom;
3948 d.Mass mass;
3949 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
3950
3951
3952
3953 Char ch = Char.ToLower((Char)cmd);
3954 switch ((Char)ch)
3955 {
3956 case 'w':
3957 try
3958 {
3959 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));
3960
3961 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
3962 ds.SetViewpoint(ref xyz, ref hpr);
3963 }
3964 catch (ArgumentException)
3965 { hpr.X = 0; }
3966 break;
3967
3968 case 'a':
3969 hpr.X++;
3970 ds.SetViewpoint(ref xyz, ref hpr);
3971 break;
3972
3973 case 's':
3974 try
3975 {
3976 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));
3977
3978 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
3979 ds.SetViewpoint(ref xyz, ref hpr);
3980 }
3981 catch (ArgumentException)
3982 { hpr.X = 0; }
3983 break;
3984 case 'd':
3985 hpr.X--;
3986 ds.SetViewpoint(ref xyz, ref hpr);
3987 break;
3988 case 'r':
3989 xyz.Z++;
3990 ds.SetViewpoint(ref xyz, ref hpr);
3991 break;
3992 case 'f':
3993 xyz.Z--;
3994 ds.SetViewpoint(ref xyz, ref hpr);
3995 break;
3996 case 'e':
3997 xyz.Y++;
3998 ds.SetViewpoint(ref xyz, ref hpr);
3999 break;
4000 case 'q':
4001 xyz.Y--;
4002 ds.SetViewpoint(ref xyz, ref hpr);
4003 break;
4004 }
4005 }
4006
4007 public void step(int pause)
4008 {
4009
4010 ds.SetColor(1.0f, 1.0f, 0.0f);
4011 ds.SetTexture(ds.Texture.Wood);
4012 lock (_prims)
4013 {
4014 foreach (OdePrim prm in _prims)
4015 {
4016 //IntPtr body = d.GeomGetBody(prm.prim_geom);
4017 if (prm.prim_geom != IntPtr.Zero)
4018 {
4019 d.Vector3 pos;
4020 d.GeomCopyPosition(prm.prim_geom, out pos);
4021 //d.BodyCopyPosition(body, out pos);
4022
4023 d.Matrix3 R;
4024 d.GeomCopyRotation(prm.prim_geom, out R);
4025 //d.BodyCopyRotation(body, out R);
4026
4027
4028 d.Vector3 sides = new d.Vector3();
4029 sides.X = prm.Size.X;
4030 sides.Y = prm.Size.Y;
4031 sides.Z = prm.Size.Z;
4032
4033 ds.DrawBox(ref pos, ref R, ref sides);
4034 }
4035 }
4036 }
4037 ds.SetColor(1.0f, 0.0f, 0.0f);
4038
4039 foreach (OdeCharacter chr in _characters)
4040 {
4041 if (chr.Shell != IntPtr.Zero)
4042 {
4043 IntPtr body = d.GeomGetBody(chr.Shell);
4044
4045 d.Vector3 pos;
4046 d.GeomCopyPosition(chr.Shell, out pos);
4047 //d.BodyCopyPosition(body, out pos);
4048
4049 d.Matrix3 R;
4050 d.GeomCopyRotation(chr.Shell, out R);
4051 //d.BodyCopyRotation(body, out R);
4052
4053 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
4054 d.Vector3 sides = new d.Vector3();
4055 sides.X = 0.5f;
4056 sides.Y = 0.5f;
4057 sides.Z = 0.5f;
4058
4059 ds.DrawBox(ref pos, ref R, ref sides);
4060 }
4061 }
4062 }
4063
4064 public void start(int unused)
4065 {
4066 ds.SetViewpoint(ref xyz, ref hpr);
4067 }
4068#endif
4069
4070 public override Dictionary<string, float> GetStats()
4071 {
4072 if (!CollectStats)
4073 return null;
4074
4075 Dictionary<string, float> returnStats;
4076
4077 lock (OdeLock)
4078 {
4079 returnStats = new Dictionary<string, float>(m_stats);
4080
4081 // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by
4082 // 3 from the SimStatsReporter.
4083 returnStats[ODETotalAvatarsStatName] = _characters.Count * 3;
4084 returnStats[ODETotalPrimsStatName] = _prims.Count * 3;
4085 returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3;
4086
4087 InitializeExtraStats();
4088 }
4089
4090 returnStats[ODEOtherCollisionFrameMsStatName]
4091 = returnStats[ODEOtherCollisionFrameMsStatName]
4092 - returnStats[ODENativeSpaceCollisionFrameMsStatName]
4093 - returnStats[ODENativeGeomCollisionFrameMsStatName];
4094
4095 return returnStats;
4096 }
4097
4098 private void InitializeExtraStats()
4099 {
4100 m_stats[ODETotalFrameMsStatName] = 0;
4101 m_stats[ODEAvatarTaintMsStatName] = 0;
4102 m_stats[ODEPrimTaintMsStatName] = 0;
4103 m_stats[ODEAvatarForcesFrameMsStatName] = 0;
4104 m_stats[ODEPrimForcesFrameMsStatName] = 0;
4105 m_stats[ODERaycastingFrameMsStatName] = 0;
4106 m_stats[ODENativeStepFrameMsStatName] = 0;
4107 m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0;
4108 m_stats[ODENativeGeomCollisionFrameMsStatName] = 0;
4109 m_stats[ODEOtherCollisionFrameMsStatName] = 0;
4110 m_stats[ODECollisionNotificationFrameMsStatName] = 0;
4111 m_stats[ODEAvatarContactsStatsName] = 0;
4112 m_stats[ODEPrimContactsStatName] = 0;
4113 m_stats[ODEAvatarUpdateFrameMsStatName] = 0;
4114 m_stats[ODEPrimUpdateFrameMsStatName] = 0;
4115 }
4116 }
4117}
diff --git a/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs b/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs
new file mode 100644
index 0000000..6dc22bd
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs
@@ -0,0 +1,151 @@
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.PhysicsModules.SharedBase;
34using OpenSim.Region.PhysicsModule.ODE;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Tests.Common;
38using log4net;
39using System.Reflection;
40
41namespace OpenSim.Region.PhysicsModule.ODE.Tests
42{
43 [TestFixture]
44 public class ODETestClass : OpenSimTestCase
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 //private OpenSim.Region.PhysicsModule.ODE.OdePlugin cbt;
49 private PhysicsScene pScene;
50
51 [SetUp]
52 public void Initialize()
53 {
54 IConfigSource openSimINI = new IniConfigSource();
55 IConfig startupConfig = openSimINI.AddConfig("Startup");
56 startupConfig.Set("physics", "OpenDynamicsEngine");
57 startupConfig.Set("DecodedSculptMapPath", "j2kDecodeCache");
58
59 Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
60
61 //PhysicsScene pScene = physicsPluginManager.GetPhysicsScene(
62 // "BulletSim", "Meshmerizer", openSimINI, "BSTestRegion", regionExtent);
63 RegionInfo info = new RegionInfo();
64 info.RegionName = "ODETestRegion";
65 info.RegionSizeX = info.RegionSizeY = info.RegionSizeZ = Constants.RegionSize;
66 OpenSim.Region.Framework.Scenes.Scene scene = new OpenSim.Region.Framework.Scenes.Scene(info);
67
68 //IMesher mesher = new OpenSim.Region.PhysicsModules.Meshing.Meshmerizer();
69 //INonSharedRegionModule mod = mesher as INonSharedRegionModule;
70 //mod.Initialise(openSimINI);
71 //mod.AddRegion(scene);
72 //mod.RegionLoaded(scene);
73
74 pScene = new OdeScene();
75 Console.WriteLine("HERE " + (pScene == null ? "Null" : "Not null"));
76 INonSharedRegionModule mod = (pScene as INonSharedRegionModule);
77 Console.WriteLine("HERE " + (mod == null ? "Null" : "Not null"));
78 mod.Initialise(openSimINI);
79 mod.AddRegion(scene);
80 mod.RegionLoaded(scene);
81
82 // Loading ODEPlugin
83 //cbt = new OdePlugin();
84 // Getting Physics Scene
85 //ps = cbt.GetScene("test");
86 // Initializing Physics Scene.
87 //ps.Initialise(imp.GetMesher(TopConfig), null, Vector3.Zero);
88 float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize];
89 for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++)
90 {
91 _heightmap[i] = 21f;
92 }
93 pScene.SetTerrain(_heightmap);
94 }
95
96 [TearDown]
97 public void Terminate()
98 {
99 pScene.DeleteTerrain();
100 pScene.Dispose();
101
102 }
103
104 [Test]
105 public void CreateAndDropPhysicalCube()
106 {
107 PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox();
108 Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f);
109 Vector3 size = new Vector3(0.5f, 0.5f, 0.5f);
110 Quaternion rot = Quaternion.Identity;
111 PhysicsActor prim = pScene.AddPrimShape("CoolShape", newcube, position, size, rot, true, 0);
112 OdePrim oprim = (OdePrim)prim;
113 OdeScene pscene = (OdeScene)pScene;
114
115 Assert.That(oprim.m_taintadd);
116
117 prim.LocalID = 5;
118
119 for (int i = 0; i < 58; i++)
120 {
121 pScene.Simulate(0.133f);
122
123 Assert.That(oprim.prim_geom != (IntPtr)0);
124
125 Assert.That(oprim.m_targetSpace != (IntPtr)0);
126
127 //Assert.That(oprim.m_targetSpace == pscene.space);
128 m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space);
129
130 Assert.That(!oprim.m_taintadd);
131 m_log.Info("Prim Position (" + oprim.LocalID + "): " + prim.Position);
132
133 // Make sure we're above the ground
134 //Assert.That(prim.Position.Z > 20f);
135 //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore);
136
137 // Make sure we've got a Body
138 Assert.That(oprim.Body != (IntPtr)0);
139 //m_log.Info(
140 }
141
142 // Make sure we're not somewhere above the ground
143 Assert.That(prim.Position.Z < 21.5f);
144
145 pScene.RemovePrim(prim);
146 Assert.That(oprim.m_taintremove);
147 pScene.Simulate(0.133f);
148 Assert.That(oprim.Body == (IntPtr)0);
149 }
150 }
151}
diff --git a/OpenSim/Region/PhysicsModules/Ode/drawstuff.cs b/OpenSim/Region/PhysicsModules/Ode/drawstuff.cs
new file mode 100644
index 0000000..87ca446
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/drawstuff.cs
@@ -0,0 +1,98 @@
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/PhysicsModules/POS/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs
new file mode 100644
index 0000000..e3a3e35
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs
@@ -0,0 +1,62 @@
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;
30using Mono.Addins;
31
32// Information about this assembly is defined by the following
33// attributes.
34//
35// change them to the information which is associated with the assembly
36// you compile.
37
38[assembly : AssemblyTitle("POSPlugin")]
39[assembly : AssemblyDescription("")]
40[assembly : AssemblyConfiguration("")]
41[assembly : AssemblyCompany("http://opensimulator.org")]
42[assembly : AssemblyProduct("POSPlugin")]
43[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
44[assembly : AssemblyTrademark("")]
45[assembly : AssemblyCulture("")]
46
47// This sets the default COM visibility of types in the assembly to invisible.
48// If you need to expose a type to COM, use [ComVisible(true)] on that type.
49
50[assembly : ComVisible(false)]
51
52// The assembly version has following format :
53//
54// Major.Minor.Build.Revision
55//
56// You can specify all values by your own or you can build default build and revision
57// numbers with the '*' character (the default):
58
59[assembly : AssemblyVersion("0.8.2.*")]
60
61[assembly: Addin("OpenSim.Region.PhysicsModule.POS", OpenSim.VersionInfo.VersionNumber)]
62[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/PhysicsModules/POS/POSCharacter.cs b/OpenSim/Region/PhysicsModules/POS/POSCharacter.cs
new file mode 100644
index 0000000..32469d9
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/POS/POSCharacter.cs
@@ -0,0 +1,341 @@
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.PhysicsModules.SharedBase;
34
35namespace OpenSim.Region.PhysicsModule.POS
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 get { return false; }
279 set { return; }
280 }
281
282 public override float PIDTau
283 {
284 set { return; }
285 }
286
287 public override float PIDHoverHeight
288 {
289 set { return; }
290 }
291
292 public override bool PIDHoverActive
293 {
294 set { return; }
295 }
296
297 public override PIDHoverType PIDHoverType
298 {
299 set { return; }
300 }
301
302 public override float PIDHoverTau
303 {
304 set { return; }
305 }
306
307 public override Quaternion APIDTarget
308 {
309 set { return; }
310 }
311
312 public override bool APIDActive
313 {
314 set { return; }
315 }
316
317 public override float APIDStrength
318 {
319 set { return; }
320 }
321
322 public override float APIDDamping
323 {
324 set { return; }
325 }
326
327
328 public override void SubscribeEvents(int ms)
329 {
330 }
331
332 public override void UnSubscribeEvents()
333 {
334 }
335
336 public override bool SubscribedEvents()
337 {
338 return false;
339 }
340 }
341}
diff --git a/OpenSim/Region/PhysicsModules/POS/POSPrim.cs b/OpenSim/Region/PhysicsModules/POS/POSPrim.cs
new file mode 100644
index 0000000..8aae716
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/POS/POSPrim.cs
@@ -0,0 +1,336 @@
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.PhysicsModules.SharedBase;
34
35namespace OpenSim.Region.PhysicsModule.POS
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 get { return false; }
274 set { return; }
275 }
276
277 public override float PIDTau
278 {
279 set { return; }
280 }
281
282 public override float PIDHoverHeight
283 {
284 set { return; }
285 }
286
287 public override bool PIDHoverActive
288 {
289 set { return; }
290 }
291
292 public override PIDHoverType PIDHoverType
293 {
294 set { return; }
295 }
296
297 public override float PIDHoverTau
298 {
299 set { return; }
300 }
301
302 public override Quaternion APIDTarget
303 {
304 set { return; }
305 }
306
307 public override bool APIDActive
308 {
309 set { return; }
310 }
311
312 public override float APIDStrength
313 {
314 set { return; }
315 }
316
317 public override float APIDDamping
318 {
319 set { return; }
320 }
321
322
323 public override void SubscribeEvents(int ms)
324 {
325 }
326
327 public override void UnSubscribeEvents()
328 {
329 }
330
331 public override bool SubscribedEvents()
332 {
333 return false;
334 }
335 }
336}
diff --git a/OpenSim/Region/PhysicsModules/POS/POSScene.cs b/OpenSim/Region/PhysicsModules/POS/POSScene.cs
new file mode 100644
index 0000000..6375f18
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/POS/POSScene.cs
@@ -0,0 +1,323 @@
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 Mono.Addins;
33using OpenSim.Framework;
34using OpenSim.Region.PhysicsModules.SharedBase;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Region.Framework.Interfaces;
37
38namespace OpenSim.Region.PhysicsModule.POS
39{
40 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "POSPhysicsScene")]
41 public class POSScene : PhysicsScene, INonSharedRegionModule
42 {
43 private List<POSCharacter> _characters = new List<POSCharacter>();
44 private List<POSPrim> _prims = new List<POSPrim>();
45 private float[] _heightMap;
46 private const float gravity = -9.8f;
47
48 private bool m_Enabled = false;
49 //protected internal string sceneIdentifier;
50
51 #region INonSharedRegionModule
52 public string Name
53 {
54 get { return "POS"; }
55 }
56
57 public Type ReplaceableInterface
58 {
59 get { return null; }
60 }
61
62 public void Initialise(IConfigSource source)
63 {
64 // TODO: Move this out of Startup
65 IConfig config = source.Configs["Startup"];
66 if (config != null)
67 {
68 string physics = config.GetString("physics", string.Empty);
69 if (physics == Name)
70 m_Enabled = true;
71 }
72
73 }
74
75 public void Close()
76 {
77 }
78
79 public void AddRegion(Scene scene)
80 {
81 if (!m_Enabled)
82 return;
83
84 EngineType = Name;
85 PhysicsSceneName = EngineType + "/" + scene.RegionInfo.RegionName;
86
87 scene.RegisterModuleInterface<PhysicsScene>(this);
88 base.Initialise(scene.PhysicsRequestAsset,
89 (scene.Heightmap != null ? scene.Heightmap.GetFloatsSerialised() : new float[Constants.RegionSize * Constants.RegionSize]),
90 (float)scene.RegionInfo.RegionSettings.WaterHeight);
91
92 }
93
94 public void RemoveRegion(Scene scene)
95 {
96 if (!m_Enabled)
97 return;
98 }
99
100 public void RegionLoaded(Scene scene)
101 {
102 if (!m_Enabled)
103 return;
104 }
105 #endregion
106
107 public override void Dispose()
108 {
109 }
110
111 public override PhysicsActor AddAvatar(
112 string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
113 {
114 POSCharacter act = new POSCharacter();
115 act.Position = position;
116 act.Flying = isFlying;
117 _characters.Add(act);
118 return act;
119 }
120
121 public override void RemovePrim(PhysicsActor prim)
122 {
123 POSPrim p = (POSPrim) prim;
124 if (_prims.Contains(p))
125 {
126 _prims.Remove(p);
127 }
128 }
129
130 public override void RemoveAvatar(PhysicsActor character)
131 {
132 POSCharacter act = (POSCharacter) character;
133 if (_characters.Contains(act))
134 {
135 _characters.Remove(act);
136 }
137 }
138
139/*
140 public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation)
141 {
142 return null;
143 }
144*/
145
146 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
147 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
148 {
149 POSPrim prim = new POSPrim();
150 prim.Position = position;
151 prim.Orientation = rotation;
152 prim.Size = size;
153 _prims.Add(prim);
154 return prim;
155 }
156
157 private bool isColliding(POSCharacter c, POSPrim p)
158 {
159 Vector3 rotatedPos = new Vector3(c.Position.X - p.Position.X, c.Position.Y - p.Position.Y,
160 c.Position.Z - p.Position.Z) * Quaternion.Inverse(p.Orientation);
161 Vector3 avatarSize = new Vector3(c.Size.X, c.Size.Y, c.Size.Z) * Quaternion.Inverse(p.Orientation);
162
163 return (Math.Abs(rotatedPos.X) < (p.Size.X*0.5 + Math.Abs(avatarSize.X)) &&
164 Math.Abs(rotatedPos.Y) < (p.Size.Y*0.5 + Math.Abs(avatarSize.Y)) &&
165 Math.Abs(rotatedPos.Z) < (p.Size.Z*0.5 + Math.Abs(avatarSize.Z)));
166 }
167
168 private bool isCollidingWithPrim(POSCharacter c)
169 {
170 foreach (POSPrim p in _prims)
171 {
172 if (isColliding(c, p))
173 {
174 return true;
175 }
176 }
177
178 return false;
179 }
180
181 public override void AddPhysicsActorTaint(PhysicsActor prim)
182 {
183 }
184
185 public override float Simulate(float timeStep)
186 {
187 float fps = 0;
188 for (int i = 0; i < _characters.Count; ++i)
189 {
190 fps++;
191 POSCharacter character = _characters[i];
192
193 float oldposX = character.Position.X;
194 float oldposY = character.Position.Y;
195 float oldposZ = character.Position.Z;
196
197 if (!character.Flying)
198 {
199 character._target_velocity.Z += gravity * timeStep;
200 }
201
202 Vector3 characterPosition = character.Position;
203
204 characterPosition.X += character._target_velocity.X * timeStep;
205 characterPosition.Y += character._target_velocity.Y * timeStep;
206
207 characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f);
208 characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f);
209
210 bool forcedZ = false;
211
212 float terrainheight = _heightMap[(int)character.Position.Y * Constants.RegionSize + (int)character.Position.X];
213 if (character.Position.Z + (character._target_velocity.Z * timeStep) < terrainheight + 2)
214 {
215 characterPosition.Z = terrainheight + character.Size.Z;
216 forcedZ = true;
217 }
218 else
219 {
220 characterPosition.Z += character._target_velocity.Z*timeStep;
221 }
222
223 /// this is it -- the magic you've all been waiting for! Ladies and gentlemen --
224 /// Completely Bogus Collision Detection!!!
225 /// better known as the CBCD algorithm
226
227 if (isCollidingWithPrim(character))
228 {
229 characterPosition.Z = oldposZ; // first try Z axis
230 if (isCollidingWithPrim(character))
231 {
232 characterPosition.Z = oldposZ + character.Size.Z / 4.4f; // try harder
233 if (isCollidingWithPrim(character))
234 {
235 characterPosition.Z = oldposZ + character.Size.Z / 2.2f; // try very hard
236 if (isCollidingWithPrim(character))
237 {
238 characterPosition.X = oldposX;
239 characterPosition.Y = oldposY;
240 characterPosition.Z = oldposZ;
241
242 characterPosition.X += character._target_velocity.X * timeStep;
243 if (isCollidingWithPrim(character))
244 {
245 characterPosition.X = oldposX;
246 }
247
248 characterPosition.Y += character._target_velocity.Y * timeStep;
249 if (isCollidingWithPrim(character))
250 {
251 characterPosition.Y = oldposY;
252 }
253 }
254 else
255 {
256 forcedZ = true;
257 }
258 }
259 else
260 {
261 forcedZ = true;
262 }
263 }
264 else
265 {
266 forcedZ = true;
267 }
268 }
269
270 characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f);
271 characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f);
272
273 character.Position = characterPosition;
274
275 character._velocity.X = (character.Position.X - oldposX)/timeStep;
276 character._velocity.Y = (character.Position.Y - oldposY)/timeStep;
277
278 if (forcedZ)
279 {
280 character._velocity.Z = 0;
281 character._target_velocity.Z = 0;
282 ((PhysicsActor)character).IsColliding = true;
283 character.RequestPhysicsterseUpdate();
284 }
285 else
286 {
287 ((PhysicsActor)character).IsColliding = false;
288 character._velocity.Z = (character.Position.Z - oldposZ)/timeStep;
289 }
290 }
291 return fps;
292 }
293
294 public override void GetResults()
295 {
296 }
297
298 public override bool IsThreaded
299 {
300 // for now we won't be multithreaded
301 get { return (false); }
302 }
303
304 public override void SetTerrain(float[] heightMap)
305 {
306 _heightMap = heightMap;
307 }
308
309 public override void DeleteTerrain()
310 {
311 }
312
313 public override void SetWaterLevel(float baseheight)
314 {
315 }
316
317 public override Dictionary<uint, float> GetTopColliders()
318 {
319 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
320 return returncolliders;
321 }
322 }
323}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/SharedBase/AssemblyInfo.cs
new file mode 100644
index 0000000..33f60e4
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/AssemblyInfo.cs
@@ -0,0 +1,58 @@
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.8.2.*")]
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/CollisionLocker.cs b/OpenSim/Region/PhysicsModules/SharedBase/CollisionLocker.cs
new file mode 100644
index 0000000..6e658b5
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/CollisionLocker.cs
@@ -0,0 +1,73 @@
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.PhysicsModules.SharedBase
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/PhysicsModules/SharedBase/IMesher.cs b/OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs
new file mode 100644
index 0000000..5c75307
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs
@@ -0,0 +1,71 @@
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.PhysicsModules.SharedBase
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[] getVertexListAsFloat();
63 float[] getVertexListAsFloatLocked();
64 void getIndexListAsPtrToIntArray(out IntPtr indices, out int triStride, out int indexCount);
65 void getVertexListAsPtrToFloatArray(out IntPtr vertexList, out int vertexStride, out int vertexCount);
66 void releaseSourceMeshData();
67 void releasePinned();
68 void Append(IMesh newMesh);
69 void TransformLinear(float[,] matrix, float[] offset);
70 }
71}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/IPhysicsParameters.cs b/OpenSim/Region/PhysicsModules/SharedBase/IPhysicsParameters.cs
new file mode 100755
index 0000000..fb0c9e2
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/IPhysicsParameters.cs
@@ -0,0 +1,73 @@
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.PhysicsModules.SharedBase
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, string value, uint localID);
64
65 // Get parameter.
66 // Return 'false' if not able to get the parameter.
67 bool GetPhysicsParameter(string parm, out string value);
68
69 // Get parameter from a particular object
70 // TODO:
71 // bool GetPhysicsParameter(string parm, out string value, uint localID);
72 }
73}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs b/OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs
new file mode 100644
index 0000000..432708c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs
@@ -0,0 +1,117 @@
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.PhysicsModules.SharedBase
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 PhysicsActor AddAvatar(
44 string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
45 {
46 m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddAvatar({0})", position);
47 return PhysicsActor.Null;
48 }
49
50 public override void RemoveAvatar(PhysicsActor actor)
51 {
52 }
53
54 public override void RemovePrim(PhysicsActor prim)
55 {
56 }
57 public override void SetWaterLevel(float baseheight)
58 {
59
60 }
61
62/*
63 public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation)
64 {
65 m_log.InfoFormat("NullPhysicsScene : AddPrim({0},{1})", position, size);
66 return PhysicsActor.Null;
67 }
68*/
69
70 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
71 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
72 {
73 m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddPrim({0},{1})", position, size);
74 return PhysicsActor.Null;
75 }
76
77 public override void AddPhysicsActorTaint(PhysicsActor prim)
78 {
79 }
80
81 public override float Simulate(float timeStep)
82 {
83 m_workIndicator = (m_workIndicator + 1) % 10;
84
85 return 0f;
86 }
87
88 public override void GetResults()
89 {
90 m_log.Info("[PHYSICS]: NullPhysicsScene : GetResults()");
91 }
92
93 public override void SetTerrain(float[] heightMap)
94 {
95 m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : SetTerrain({0} items)", heightMap.Length);
96 }
97
98 public override void DeleteTerrain()
99 {
100 }
101
102 public override bool IsThreaded
103 {
104 get { return false; }
105 }
106
107 public override void Dispose()
108 {
109 }
110
111 public override Dictionary<uint,float> GetTopColliders()
112 {
113 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
114 return returncolliders;
115 }
116 }
117} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs
new file mode 100644
index 0000000..c04ff58
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs
@@ -0,0 +1,584 @@
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.PhysicsModules.SharedBase
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 virtual byte PhysicsShapeType { get; set; }
151
152 public abstract PrimitiveBaseShape Shape { set; }
153
154 uint m_baseLocalID;
155 public virtual uint LocalID
156 {
157 set { m_baseLocalID = value; }
158 get { return m_baseLocalID; }
159 }
160
161 public abstract bool Grabbed { set; }
162
163 public abstract bool Selected { set; }
164
165 /// <summary>
166 /// Name of this actor.
167 /// </summary>
168 /// <remarks>
169 /// XXX: Bizarrely, this cannot be "Terrain" or "Water" right now unless it really is simulating terrain or
170 /// water. This is not a problem due to the formatting of names given by prims and avatars.
171 /// </remarks>
172 public string Name { get; protected set; }
173
174 /// <summary>
175 /// This is being used by ODE joint code.
176 /// </summary>
177 public string SOPName;
178
179 public abstract void CrossingFailure();
180
181 public abstract void link(PhysicsActor obj);
182
183 public abstract void delink();
184
185 public abstract void LockAngularMotion(Vector3 axis);
186
187 public virtual void RequestPhysicsterseUpdate()
188 {
189 // Make a temporary copy of the event to avoid possibility of
190 // a race condition if the last subscriber unsubscribes
191 // immediately after the null check and before the event is raised.
192 RequestTerseUpdate handler = OnRequestTerseUpdate;
193
194 if (handler != null)
195 {
196 handler();
197 }
198 }
199
200 public virtual void RaiseOutOfBounds(Vector3 pos)
201 {
202 // Make a temporary copy of the event to avoid possibility of
203 // a race condition if the last subscriber unsubscribes
204 // immediately after the null check and before the event is raised.
205 OutOfBounds handler = OnOutOfBounds;
206
207 if (handler != null)
208 {
209 handler(pos);
210 }
211 }
212
213 public virtual void SendCollisionUpdate(EventArgs e)
214 {
215 CollisionUpdate handler = OnCollisionUpdate;
216
217// m_log.DebugFormat("[PHYSICS ACTOR]: Sending collision for {0}", LocalID);
218
219 if (handler != null)
220 handler(e);
221 }
222
223 public virtual void SetMaterial (int material) { }
224 public virtual float Density { get; set; }
225 public virtual float GravModifier { get; set; }
226 public virtual float Friction { get; set; }
227 public virtual float Restitution { get; set; }
228
229 /// <summary>
230 /// Position of this actor.
231 /// </summary>
232 /// <remarks>
233 /// Setting this directly moves the actor to a given position.
234 /// Getting this retrieves the position calculated by physics scene updates, using factors such as velocity and
235 /// collisions.
236 /// </remarks>
237 public abstract Vector3 Position { get; set; }
238
239 public abstract float Mass { get; }
240 public abstract Vector3 Force { get; set; }
241
242 public abstract int VehicleType { get; set; }
243 public abstract void VehicleFloatParam(int param, float value);
244 public abstract void VehicleVectorParam(int param, Vector3 value);
245 public abstract void VehicleRotationParam(int param, Quaternion rotation);
246 public abstract void VehicleFlags(int param, bool remove);
247
248 /// <summary>
249 /// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
250 /// </summary>
251 public abstract void SetVolumeDetect(int param);
252
253 public abstract Vector3 GeometricCenter { get; }
254 public abstract Vector3 CenterOfMass { get; }
255
256 /// <summary>
257 /// The desired velocity of this actor.
258 /// </summary>
259 /// <remarks>
260 /// Setting this provides a target velocity for physics scene updates.
261 /// Getting this returns the last set target. Fetch Velocity to get the current velocity.
262 /// </remarks>
263 protected Vector3 m_targetVelocity;
264 public virtual Vector3 TargetVelocity
265 {
266 get { return m_targetVelocity; }
267 set {
268 m_targetVelocity = value;
269 Velocity = m_targetVelocity;
270 }
271 }
272
273 public abstract Vector3 Velocity { get; set; }
274
275 public abstract Vector3 Torque { get; set; }
276 public abstract float CollisionScore { get; set;}
277 public abstract Vector3 Acceleration { get; set; }
278 public abstract Quaternion Orientation { get; set; }
279 public abstract int PhysicsActorType { get; set; }
280 public abstract bool IsPhysical { get; set; }
281 public abstract bool Flying { get; set; }
282 public abstract bool SetAlwaysRun { get; set; }
283 public abstract bool ThrottleUpdates { get; set; }
284 public abstract bool IsColliding { get; set; }
285 public abstract bool CollidingGround { get; set; }
286 public abstract bool CollidingObj { get; set; }
287 public abstract bool FloatOnWater { set; }
288 public abstract Vector3 RotationalVelocity { get; set; }
289 public abstract bool Kinematic { get; set; }
290 public abstract float Buoyancy { get; set; }
291
292 // Used for MoveTo
293 public abstract Vector3 PIDTarget { set; }
294 public abstract bool PIDActive { get; set; }
295 public abstract float PIDTau { set; }
296
297 // Used for llSetHoverHeight and maybe vehicle height
298 // Hover Height will override MoveTo target's Z
299 public abstract bool PIDHoverActive { set;}
300 public abstract float PIDHoverHeight { set;}
301 public abstract PIDHoverType PIDHoverType { set;}
302 public abstract float PIDHoverTau { set;}
303
304 // For RotLookAt
305 public abstract Quaternion APIDTarget { set;}
306 public abstract bool APIDActive { set;}
307 public abstract float APIDStrength { set;}
308 public abstract float APIDDamping { set;}
309
310 public abstract void AddForce(Vector3 force, bool pushforce);
311 public abstract void AddAngularForce(Vector3 force, bool pushforce);
312 public abstract void SetMomentum(Vector3 momentum);
313 public abstract void SubscribeEvents(int ms);
314 public abstract void UnSubscribeEvents();
315 public abstract bool SubscribedEvents();
316
317 // Extendable interface for new, physics engine specific operations
318 public virtual object Extension(string pFunct, params object[] pParams)
319 {
320 // A NOP of the physics engine does not implement this feature
321 return null;
322 }
323 }
324
325 public class NullPhysicsActor : PhysicsActor
326 {
327 public override bool Stopped
328 {
329 get{ return false; }
330 }
331
332 public override Vector3 Position
333 {
334 get { return Vector3.Zero; }
335 set { return; }
336 }
337
338 public override bool SetAlwaysRun
339 {
340 get { return false; }
341 set { return; }
342 }
343
344 public override uint LocalID
345 {
346 set { return; }
347 }
348
349 public override bool Grabbed
350 {
351 set { return; }
352 }
353
354 public override bool Selected
355 {
356 set { return; }
357 }
358
359 public override float Buoyancy
360 {
361 get { return 0f; }
362 set { return; }
363 }
364
365 public override bool FloatOnWater
366 {
367 set { return; }
368 }
369
370 public override bool CollidingGround
371 {
372 get { return false; }
373 set { return; }
374 }
375
376 public override bool CollidingObj
377 {
378 get { return false; }
379 set { return; }
380 }
381
382 public override Vector3 Size
383 {
384 get { return Vector3.Zero; }
385 set { return; }
386 }
387
388 public override float Mass
389 {
390 get { return 0f; }
391 }
392
393 public override Vector3 Force
394 {
395 get { return Vector3.Zero; }
396 set { return; }
397 }
398
399 public override int VehicleType
400 {
401 get { return 0; }
402 set { return; }
403 }
404
405 public override void VehicleFloatParam(int param, float value)
406 {
407
408 }
409
410 public override void VehicleVectorParam(int param, Vector3 value)
411 {
412
413 }
414
415 public override void VehicleRotationParam(int param, Quaternion rotation)
416 {
417
418 }
419
420 public override void VehicleFlags(int param, bool remove)
421 {
422
423 }
424
425 public override void SetVolumeDetect(int param)
426 {
427
428 }
429
430 public override void SetMaterial(int material)
431 {
432
433 }
434
435 public override Vector3 CenterOfMass
436 {
437 get { return Vector3.Zero; }
438 }
439
440 public override Vector3 GeometricCenter
441 {
442 get { return Vector3.Zero; }
443 }
444
445 public override PrimitiveBaseShape Shape
446 {
447 set { return; }
448 }
449
450 public override Vector3 Velocity
451 {
452 get { return Vector3.Zero; }
453 set { return; }
454 }
455
456 public override Vector3 Torque
457 {
458 get { return Vector3.Zero; }
459 set { return; }
460 }
461
462 public override float CollisionScore
463 {
464 get { return 0f; }
465 set { }
466 }
467
468 public override void CrossingFailure()
469 {
470 }
471
472 public override Quaternion Orientation
473 {
474 get { return Quaternion.Identity; }
475 set { }
476 }
477
478 public override Vector3 Acceleration
479 {
480 get { return Vector3.Zero; }
481 set { }
482 }
483
484 public override bool IsPhysical
485 {
486 get { return false; }
487 set { return; }
488 }
489
490 public override bool Flying
491 {
492 get { return false; }
493 set { return; }
494 }
495
496 public override bool ThrottleUpdates
497 {
498 get { return false; }
499 set { return; }
500 }
501
502 public override bool IsColliding
503 {
504 get { return false; }
505 set { return; }
506 }
507
508 public override int PhysicsActorType
509 {
510 get { return (int) ActorTypes.Unknown; }
511 set { return; }
512 }
513
514 public override bool Kinematic
515 {
516 get { return true; }
517 set { return; }
518 }
519
520 public override void link(PhysicsActor obj)
521 {
522 }
523
524 public override void delink()
525 {
526 }
527
528 public override void LockAngularMotion(Vector3 axis)
529 {
530 }
531
532 public override void AddForce(Vector3 force, bool pushforce)
533 {
534 }
535
536 public override void AddAngularForce(Vector3 force, bool pushforce)
537 {
538
539 }
540
541 public override Vector3 RotationalVelocity
542 {
543 get { return Vector3.Zero; }
544 set { return; }
545 }
546
547 public override Vector3 PIDTarget { set { return; } }
548
549 public override bool PIDActive
550 {
551 get { return false; }
552 set { return; }
553 }
554
555 public override float PIDTau { set { return; } }
556
557 public override float PIDHoverHeight { set { return; } }
558 public override bool PIDHoverActive { set { return; } }
559 public override PIDHoverType PIDHoverType { set { return; } }
560 public override float PIDHoverTau { set { return; } }
561
562 public override Quaternion APIDTarget { set { return; } }
563 public override bool APIDActive { set { return; } }
564 public override float APIDStrength { set { return; } }
565 public override float APIDDamping { set { return; } }
566
567 public override void SetMomentum(Vector3 momentum)
568 {
569 }
570
571 public override void SubscribeEvents(int ms)
572 {
573
574 }
575 public override void UnSubscribeEvents()
576 {
577
578 }
579 public override bool SubscribedEvents()
580 {
581 return false;
582 }
583 }
584}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsJoint.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsJoint.cs
new file mode 100644
index 0000000..ce2bf05
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsJoint.cs
@@ -0,0 +1,55 @@
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.PhysicsModules.SharedBase
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/PhysicsModules/SharedBase/PhysicsScene.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs
new file mode 100644
index 0000000..32691fc
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs
@@ -0,0 +1,358 @@
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;
31
32using log4net;
33using Nini.Config;
34
35using OpenSim.Framework;
36using OpenMetaverse;
37
38namespace OpenSim.Region.PhysicsModules.SharedBase
39{
40 public delegate void physicsCrash();
41
42 public delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal);
43 public delegate void RayCallback(List<ContactResult> list);
44
45 public delegate void JointMoved(PhysicsJoint joint);
46 public delegate void JointDeactivated(PhysicsJoint joint);
47 public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation"
48
49 public enum RayFilterFlags : ushort
50 {
51 // the flags
52 water = 0x01,
53 land = 0x02,
54 agent = 0x04,
55 nonphysical = 0x08,
56 physical = 0x10,
57 phantom = 0x20,
58 volumedtc = 0x40,
59
60 // ray cast colision control (may only work for meshs)
61 ContactsUnImportant = 0x2000,
62 BackFaceCull = 0x4000,
63 ClosestHit = 0x8000,
64
65 // some combinations
66 LSLPhantom = phantom | volumedtc,
67 PrimsNonPhantom = nonphysical | physical,
68 PrimsNonPhantomAgents = nonphysical | physical | agent,
69
70 AllPrims = nonphysical | phantom | volumedtc | physical,
71 AllButLand = agent | nonphysical | physical | phantom | volumedtc,
72
73 ClosestAndBackCull = ClosestHit | BackFaceCull,
74
75 All = 0x3f
76 }
77
78 public delegate void RequestAssetDelegate(UUID assetID, AssetReceivedDelegate callback);
79 public delegate void AssetReceivedDelegate(AssetBase asset);
80
81 /// <summary>
82 /// Contact result from a raycast.
83 /// </summary>
84 public struct ContactResult
85 {
86 public Vector3 Pos;
87 public float Depth;
88 public uint ConsumerID;
89 public Vector3 Normal;
90 }
91
92 public abstract class PhysicsScene
93 {
94// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
95
96 /// <summary>
97 /// A unique identifying string for this instance of the physics engine.
98 /// Useful in debug messages to distinguish one OdeScene instance from another.
99 /// Usually set to include the region name that the physics engine is acting for.
100 /// </summary>
101 public string PhysicsSceneName { get; protected set; }
102
103 /// <summary>
104 /// A string identifying the family of this physics engine. Most common values returned
105 /// are "OpenDynamicsEngine" and "BulletSim" but others are possible.
106 /// </summary>
107 public string EngineType { get; protected set; }
108
109 // The only thing that should register for this event is the SceneGraph
110 // Anything else could cause problems.
111 public event physicsCrash OnPhysicsCrash;
112
113 public static PhysicsScene Null
114 {
115 get { return new NullPhysicsScene(); }
116 }
117
118 public RequestAssetDelegate RequestAssetMethod { get; set; }
119
120 protected void Initialise(RequestAssetDelegate m, float[] terrain, float waterHeight)
121 {
122 RequestAssetMethod = m;
123 SetTerrain(terrain);
124 SetWaterLevel(waterHeight);
125
126 }
127
128 public virtual void TriggerPhysicsBasedRestart()
129 {
130 physicsCrash handler = OnPhysicsCrash;
131 if (handler != null)
132 {
133 OnPhysicsCrash();
134 }
135 }
136
137 /// <summary>
138 /// Add an avatar
139 /// </summary>
140 /// <param name="avName"></param>
141 /// <param name="position"></param>
142 /// <param name="velocity"></param>
143 /// <param name="size"></param>
144 /// <param name="isFlying"></param>
145 /// <returns></returns>
146 public abstract PhysicsActor AddAvatar(
147 string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying);
148
149 /// <summary>
150 /// Add an avatar
151 /// </summary>
152 /// <param name="localID"></param>
153 /// <param name="avName"></param>
154 /// <param name="position"></param>
155 /// <param name="velocity"></param>
156 /// <param name="size"></param>
157 /// <param name="isFlying"></param>
158 /// <returns></returns>
159 public virtual PhysicsActor AddAvatar(
160 uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
161 {
162 PhysicsActor ret = AddAvatar(avName, position, velocity, size, isFlying);
163
164 if (ret != null)
165 ret.LocalID = localID;
166
167 return ret;
168 }
169
170 /// <summary>
171 /// Remove an avatar.
172 /// </summary>
173 /// <param name="actor"></param>
174 public abstract void RemoveAvatar(PhysicsActor actor);
175
176 /// <summary>
177 /// Remove a prim.
178 /// </summary>
179 /// <param name="prim"></param>
180 public abstract void RemovePrim(PhysicsActor prim);
181
182 public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
183 Vector3 size, Quaternion rotation, bool isPhysical, uint localid);
184
185 public virtual PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
186 Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapetype, uint localid)
187 {
188 return AddPrimShape(primName, pbs, position, size, rotation, isPhysical, localid);
189 }
190
191 public virtual float TimeDilation
192 {
193 get { return 1.0f; }
194 }
195
196 public virtual bool SupportsNINJAJoints
197 {
198 get { return false; }
199 }
200
201 public virtual PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
202 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
203 { return null; }
204
205 public virtual void RequestJointDeletion(string objectNameInScene)
206 { return; }
207
208 public virtual void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
209 { return; }
210
211 public virtual void DumpJointInfo()
212 { return; }
213
214 public event JointMoved OnJointMoved;
215
216 protected virtual void DoJointMoved(PhysicsJoint joint)
217 {
218 // We need this to allow subclasses (but not other classes) to invoke the event; C# does
219 // not allow subclasses to invoke the parent class event.
220 if (OnJointMoved != null)
221 {
222 OnJointMoved(joint);
223 }
224 }
225
226 public event JointDeactivated OnJointDeactivated;
227
228 protected virtual void DoJointDeactivated(PhysicsJoint joint)
229 {
230 // We need this to allow subclasses (but not other classes) to invoke the event; C# does
231 // not allow subclasses to invoke the parent class event.
232 if (OnJointDeactivated != null)
233 {
234 OnJointDeactivated(joint);
235 }
236 }
237
238 public event JointErrorMessage OnJointErrorMessage;
239
240 protected virtual void DoJointErrorMessage(PhysicsJoint joint, string message)
241 {
242 // We need this to allow subclasses (but not other classes) to invoke the event; C# does
243 // not allow subclasses to invoke the parent class event.
244 if (OnJointErrorMessage != null)
245 {
246 OnJointErrorMessage(joint, message);
247 }
248 }
249
250 public virtual Vector3 GetJointAnchor(PhysicsJoint joint)
251 { return Vector3.Zero; }
252
253 public virtual Vector3 GetJointAxis(PhysicsJoint joint)
254 { return Vector3.Zero; }
255
256 public abstract void AddPhysicsActorTaint(PhysicsActor prim);
257
258 /// <summary>
259 /// Perform a simulation of the current physics scene over the given timestep.
260 /// </summary>
261 /// <param name="timeStep"></param>
262 /// <returns>The number of frames simulated over that period.</returns>
263 public abstract float Simulate(float timeStep);
264
265 /// <summary>
266 /// Get statistics about this scene.
267 /// </summary>
268 /// <remarks>This facility is currently experimental and subject to change.</remarks>
269 /// <returns>
270 /// A dictionary where the key is the statistic name. If no statistics are supplied then returns null.
271 /// </returns>
272 public virtual Dictionary<string, float> GetStats() { return null; }
273
274 public abstract void GetResults();
275
276 public abstract void SetTerrain(float[] heightMap);
277
278 public abstract void SetWaterLevel(float baseheight);
279
280 public abstract void DeleteTerrain();
281
282 public abstract void Dispose();
283
284 public abstract Dictionary<uint, float> GetTopColliders();
285
286 public abstract bool IsThreaded { get; }
287
288 /// <summary>
289 /// True if the physics plugin supports raycasting against the physics scene
290 /// </summary>
291 public virtual bool SupportsRayCast()
292 {
293 return false;
294 }
295
296 public virtual bool SupportsCombining()
297 {
298 return false;
299 }
300
301 public virtual void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) {}
302
303 public virtual void UnCombine(PhysicsScene pScene) {}
304
305 /// <summary>
306 /// Queue a raycast against the physics scene.
307 /// The provided callback method will be called when the raycast is complete
308 ///
309 /// Many physics engines don't support collision testing at the same time as
310 /// manipulating the physics scene, so we queue the request up and callback
311 /// a custom method when the raycast is complete.
312 /// This allows physics engines that give an immediate result to callback immediately
313 /// and ones that don't, to callback when it gets a result back.
314 ///
315 /// ODE for example will not allow you to change the scene while collision testing or
316 /// it asserts, 'opteration not valid for locked space'. This includes adding a ray to the scene.
317 ///
318 /// This is named RayCastWorld to not conflict with modrex's Raycast method.
319 /// </summary>
320 /// <param name="position">Origin of the ray</param>
321 /// <param name="direction">Direction of the ray</param>
322 /// <param name="length">Length of ray in meters</param>
323 /// <param name="retMethod">Method to call when the raycast is complete</param>
324 public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
325 {
326 if (retMethod != null)
327 retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero);
328 }
329
330 public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
331 {
332 if (retMethod != null)
333 retMethod(new List<ContactResult>());
334 }
335
336 public virtual List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
337 {
338 return new List<ContactResult>();
339 }
340
341 public virtual object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
342 {
343 return null;
344 }
345
346 public virtual bool SupportsRaycastWorldFiltered()
347 {
348 return false;
349 }
350
351 // Extendable interface for new, physics engine specific operations
352 public virtual object Extension(string pFunct, params object[] pParams)
353 {
354 // A NOP if the extension thing is not implemented by the physics engine
355 return null;
356 }
357 }
358}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs
new file mode 100644
index 0000000..da9c96c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs
@@ -0,0 +1,78 @@
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.PhysicsModules.SharedBase
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/PhysicsModules/SharedBase/PhysicsVector.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs
new file mode 100644
index 0000000..76a82fa
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs
@@ -0,0 +1,186 @@
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.PhysicsModules.SharedBase
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/PhysicsModules/SharedBase/VehicleConstants.cs b/OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs
new file mode 100644
index 0000000..63a8cb8
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs
@@ -0,0 +1,121 @@
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.PhysicsModules.SharedBase
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}