aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules
diff options
context:
space:
mode:
authorDiva Canto2015-08-30 20:06:53 -0700
committerDiva Canto2015-08-30 20:06:53 -0700
commit1d6b33bc2da3b312cff1d1802a73aacdf72b0385 (patch)
tree393736b501aac3b31eb0810bb72d926c7f14fbf8 /OpenSim/Region/PhysicsModules
parentMoved instantiation of SceneCommunicationService object to inside the scene c... (diff)
downloadopensim-SC_OLD-1d6b33bc2da3b312cff1d1802a73aacdf72b0385.zip
opensim-SC_OLD-1d6b33bc2da3b312cff1d1802a73aacdf72b0385.tar.gz
opensim-SC_OLD-1d6b33bc2da3b312cff1d1802a73aacdf72b0385.tar.bz2
opensim-SC_OLD-1d6b33bc2da3b312cff1d1802a73aacdf72b0385.tar.xz
Major renaming of Physics dlls / folders. No functional changes, just renames.
Diffstat (limited to 'OpenSim/Region/PhysicsModules')
-rw-r--r--OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs303
-rw-r--r--OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPlugin.cs64
-rw-r--r--OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs316
-rw-r--r--OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs210
-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.cs854
-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/BSPlugin.cs76
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs1896
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs182
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs350
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSScene.cs1281
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs425
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSShapes.cs1463
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs170
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs585
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs441
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs277
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt379
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs33
-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.cs100
-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/HelperTypes.cs436
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Mesh.cs333
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Meshmerizer.cs971
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/PrimMesher.cs2324
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/SculptMap.cs183
-rw-r--r--OpenSim/Region/PhysicsModules/Meshing/SculptMesh.cs646
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs58
-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.cs3387
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs434
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs48
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/OdePlugin.cs90
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/OdeScene.cs4319
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs128
-rw-r--r--OpenSim/Region/PhysicsModules/Ode/drawstuff.cs98
-rw-r--r--OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs58
-rw-r--r--OpenSim/Region/PhysicsModules/POS/POSCharacter.cs341
-rw-r--r--OpenSim/Region/PhysicsModules/POS/POSPlugin.cs64
-rw-r--r--OpenSim/Region/PhysicsModules/POS/POSPrim.cs336
-rw-r--r--OpenSim/Region/PhysicsModules/POS/POSScene.cs273
-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.cs122
-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/PhysicsPluginManager.cs242
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs361
-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
-rw-r--r--OpenSim/Region/PhysicsModules/SharedBase/ZeroMesher.cs83
107 files changed, 48778 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..7d054dd
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/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("BasicPhysicsPlugin")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("BasicPhysicsPlugin")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.8.2.*")]
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs
new file mode 100644
index 0000000..43fba7b
--- /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.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BasicPhysicsPlugin
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/BasicPhysicsPlugin.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPlugin.cs
new file mode 100644
index 0000000..373c7e0
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPlugin.cs
@@ -0,0 +1,64 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33
34namespace OpenSim.Region.Physics.BasicPhysicsPlugin
35{
36 /// <summary>
37 /// Effectively a physics plugin that simulates no physics at all.
38 /// </summary>
39 public class BasicPhysicsPlugin : IPhysicsPlugin
40 {
41 public BasicPhysicsPlugin()
42 {
43 }
44
45 public bool Init()
46 {
47 return true;
48 }
49
50 public PhysicsScene GetScene(string sceneIdentifier)
51 {
52 return new BasicScene(GetName(), sceneIdentifier);
53 }
54
55 public string GetName()
56 {
57 return ("basicphysics");
58 }
59
60 public void Dispose()
61 {
62 }
63 }
64}
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs
new file mode 100644
index 0000000..dfe4c19
--- /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.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BasicPhysicsPlugin
36{
37 public class BasicPhysicsPrim : PhysicsActor
38 {
39 private Vector3 _size;
40// private PrimitiveBaseShape _shape;
41
42 public BasicPhysicsPrim(
43 string name, uint localId, Vector3 position, Vector3 size, Quaternion orientation, PrimitiveBaseShape shape)
44 {
45 Name = name;
46 LocalID = localId;
47 Position = position;
48 Size = size;
49 Orientation = orientation;
50 Shape = shape;
51 }
52
53 public override int PhysicsActorType
54 {
55 get { return (int) ActorTypes.Agent; }
56 set { return; }
57 }
58
59 public override Vector3 RotationalVelocity { get; set; }
60
61 public override bool SetAlwaysRun
62 {
63 get { return false; }
64 set { return; }
65 }
66
67 public override uint LocalID
68 {
69 set { return; }
70 }
71
72 public override bool Grabbed
73 {
74 set { return; }
75 }
76
77 public override bool Selected
78 {
79 set { return; }
80 }
81
82 public override float Buoyancy
83 {
84 get { return 0f; }
85 set { return; }
86 }
87
88 public override bool FloatOnWater
89 {
90 set { return; }
91 }
92
93 public override bool IsPhysical
94 {
95 get { return false; }
96 set { return; }
97 }
98
99 public override bool ThrottleUpdates
100 {
101 get { return false; }
102 set { return; }
103 }
104
105 public override bool Flying { get; set; }
106
107 public override bool IsColliding { get; set; }
108
109 public override bool CollidingGround
110 {
111 get { return false; }
112 set { return; }
113 }
114
115 public override bool CollidingObj
116 {
117 get { return false; }
118 set { return; }
119 }
120
121 public override bool Stopped
122 {
123 get { return false; }
124 }
125
126 public override Vector3 Position { get; set; }
127
128 public override Vector3 Size
129 {
130 get { return _size; }
131 set {
132 _size = value;
133 _size.Z = _size.Z / 2.0f;
134 }
135 }
136
137 public override PrimitiveBaseShape Shape
138 {
139// set { _shape = value; }
140 set {}
141 }
142
143 public override float Mass
144 {
145 get { return 0f; }
146 }
147
148 public override Vector3 Force
149 {
150 get { return Vector3.Zero; }
151 set { return; }
152 }
153
154 public override int VehicleType
155 {
156 get { return 0; }
157 set { return; }
158 }
159
160 public override void VehicleFloatParam(int param, float value)
161 {
162
163 }
164
165 public override void VehicleVectorParam(int param, Vector3 value)
166 {
167
168 }
169
170 public override void VehicleRotationParam(int param, Quaternion rotation)
171 {
172
173 }
174
175 public override void VehicleFlags(int param, bool remove)
176 {
177
178 }
179
180 public override void SetVolumeDetect(int param)
181 {
182
183 }
184
185 public override Vector3 CenterOfMass
186 {
187 get { return Vector3.Zero; }
188 }
189
190 public override Vector3 GeometricCenter
191 {
192 get { return Vector3.Zero; }
193 }
194
195 public override Vector3 Velocity { get; set; }
196
197 public override Vector3 Torque
198 {
199 get { return Vector3.Zero; }
200 set { return; }
201 }
202
203 public override float CollisionScore
204 {
205 get { return 0f; }
206 set { }
207 }
208
209 public override Quaternion Orientation { get; set; }
210
211 public override Vector3 Acceleration { get; set; }
212
213 public override bool Kinematic
214 {
215 get { return true; }
216 set { }
217 }
218
219 public override void link(PhysicsActor obj)
220 {
221 }
222
223 public override void delink()
224 {
225 }
226
227 public override void LockAngularMotion(Vector3 axis)
228 {
229 }
230
231 public override void AddForce(Vector3 force, bool pushforce)
232 {
233 }
234
235 public override void AddAngularForce(Vector3 force, bool pushforce)
236 {
237 }
238
239 public override void SetMomentum(Vector3 momentum)
240 {
241 }
242
243 public override void CrossingFailure()
244 {
245 }
246
247 public override Vector3 PIDTarget
248 {
249 set { return; }
250 }
251
252 public override bool PIDActive
253 {
254 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..06a205e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs
@@ -0,0 +1,210 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BasicPhysicsPlugin
36{
37 /// <summary>
38 /// This is an incomplete extremely basic physics implementation
39 /// </summary>
40 /// <remarks>
41 /// Not useful for anything at the moment apart from some regression testing in other components where some form
42 /// of physics plugin is needed.
43 /// </remarks>
44 public class BasicScene : PhysicsScene
45 {
46 private List<BasicActor> _actors = new List<BasicActor>();
47 private List<BasicPhysicsPrim> _prims = new List<BasicPhysicsPrim>();
48 private float[] _heightMap;
49 private Vector3 m_regionExtent;
50
51 //protected internal string sceneIdentifier;
52
53 public BasicScene(string engineType, string _sceneIdentifier)
54 {
55 EngineType = engineType;
56 Name = EngineType + "/" + _sceneIdentifier;
57 //sceneIdentifier = _sceneIdentifier;
58 }
59
60 public override void Initialise(IMesher meshmerizer, IConfigSource config)
61 {
62 throw new Exception("Should not be called.");
63 }
64
65 public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
66 {
67 m_regionExtent = regionExtent;
68 }
69
70 public override void Dispose() {}
71
72 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
73 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
74 {
75 BasicPhysicsPrim prim = new BasicPhysicsPrim(primName, localid, position, size, rotation, pbs);
76 prim.IsPhysical = isPhysical;
77
78 _prims.Add(prim);
79
80 return prim;
81 }
82
83 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
84 {
85 BasicActor act = new BasicActor(size);
86 act.Position = position;
87 act.Velocity = velocity;
88 act.Flying = isFlying;
89 _actors.Add(act);
90 return act;
91 }
92
93 public override void RemovePrim(PhysicsActor actor)
94 {
95 BasicPhysicsPrim prim = (BasicPhysicsPrim)actor;
96 if (_prims.Contains(prim))
97 _prims.Remove(prim);
98 }
99
100 public override void RemoveAvatar(PhysicsActor actor)
101 {
102 BasicActor act = (BasicActor)actor;
103 if (_actors.Contains(act))
104 _actors.Remove(act);
105 }
106
107 public override void AddPhysicsActorTaint(PhysicsActor prim)
108 {
109 }
110
111 public override float Simulate(float timeStep)
112 {
113// Console.WriteLine("Simulating");
114
115 float fps = 0;
116 for (int i = 0; i < _actors.Count; ++i)
117 {
118 BasicActor actor = _actors[i];
119 Vector3 actorPosition = actor.Position;
120 Vector3 actorVelocity = actor.Velocity;
121
122// Console.WriteLine(
123// "Processing actor {0}, starting pos {1}, starting vel {2}", i, actorPosition, actorVelocity);
124
125 actorPosition.X += actor.Velocity.X * timeStep;
126 actorPosition.Y += actor.Velocity.Y * timeStep;
127
128 if (actor.Position.Y < 0)
129 {
130 actorPosition.Y = 0.1F;
131 }
132 else if (actor.Position.Y >= m_regionExtent.Y)
133 {
134 actorPosition.Y = (m_regionExtent.Y - 0.1f);
135 }
136
137 if (actor.Position.X < 0)
138 {
139 actorPosition.X = 0.1F;
140 }
141 else if (actor.Position.X >= m_regionExtent.X)
142 {
143 actorPosition.X = (m_regionExtent.X - 0.1f);
144 }
145
146 float terrainHeight = 0;
147 if (_heightMap != null)
148 terrainHeight = _heightMap[(int)actor.Position.Y * (int)m_regionExtent.Y + (int)actor.Position.X];
149
150 float height = terrainHeight + actor.Size.Z;
151// Console.WriteLine("height {0}, actorPosition {1}", height, actorPosition);
152
153 if (actor.Flying)
154 {
155 if (actor.Position.Z + (actor.Velocity.Z * timeStep) < terrainHeight + 2)
156 {
157 actorPosition.Z = height;
158 actorVelocity.Z = 0;
159 actor.IsColliding = true;
160 }
161 else
162 {
163 actorPosition.Z += actor.Velocity.Z * timeStep;
164 actor.IsColliding = false;
165 }
166 }
167 else
168 {
169 actorPosition.Z = height;
170 actorVelocity.Z = 0;
171 actor.IsColliding = true;
172 }
173
174 actor.Position = actorPosition;
175 actor.Velocity = actorVelocity;
176 }
177
178 return fps;
179 }
180
181 public override void GetResults()
182 {
183 }
184
185 public override bool IsThreaded
186 {
187 get { return (false); // for now we won't be multithreaded
188 }
189 }
190
191 public override void SetTerrain(float[] heightMap)
192 {
193 _heightMap = heightMap;
194 }
195
196 public override void DeleteTerrain()
197 {
198 }
199
200 public override void SetWaterLevel(float baseheight)
201 {
202 }
203
204 public override Dictionary<uint, float> GetTopColliders()
205 {
206 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
207 return returncolliders;
208 }
209 }
210}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
new file mode 100755
index 0000000..3bd81d4
--- /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.Physics.BulletSPlugin
39{
40public sealed class BSAPIUnman : BSAPITemplate
41{
42
43private sealed class BulletWorldUnman : BulletWorld
44{
45 public IntPtr ptr;
46 public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx)
47 : base(id, physScene)
48 {
49 ptr = xx;
50 }
51}
52
53private sealed class BulletBodyUnman : BulletBody
54{
55 public IntPtr ptr;
56 public BulletBodyUnman(uint id, IntPtr xx)
57 : base(id)
58 {
59 ptr = xx;
60 }
61 public override bool HasPhysicalBody
62 {
63 get { return ptr != IntPtr.Zero; }
64 }
65 public override void Clear()
66 {
67 ptr = IntPtr.Zero;
68 }
69 public override string AddrString
70 {
71 get { return ptr.ToString("X"); }
72 }
73}
74
75private sealed class BulletShapeUnman : BulletShape
76{
77 public IntPtr ptr;
78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
79 : base()
80 {
81 ptr = xx;
82 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..741f8db
--- /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.Physics.BulletSPlugin
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..bde4557
--- /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.Physics.Manager;
35
36using OMV = OpenMetaverse;
37
38namespace OpenSim.Region.Physics.BulletSPlugin
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..e54c27b
--- /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.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
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..3b3c161
--- /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.Physics.BulletSPlugin
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..1145006
--- /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.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
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..4e81363
--- /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.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
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..79e1d38
--- /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.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
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..7f45e2c
--- /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.Physics.BulletSPlugin
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..8491c0f
--- /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.Physics.BulletSPlugin {
35
36 // Constraint type values as defined by Bullet
37public enum ConstraintType : int
38{
39 POINT2POINT_CONSTRAINT_TYPE = 3,
40 HINGE_CONSTRAINT_TYPE,
41 CONETWIST_CONSTRAINT_TYPE,
42 D6_CONSTRAINT_TYPE,
43 SLIDER_CONSTRAINT_TYPE,
44 CONTACT_CONSTRAINT_TYPE,
45 D6_SPRING_CONSTRAINT_TYPE,
46 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..9c3f160
--- /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.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public sealed class BSCharacter : BSPhysObject
38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]";
41
42 // private bool _stopped;
43 private OMV.Vector3 _size;
44 private bool _grabbed;
45 private bool _selected;
46 private 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..b47e9a8
--- /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.Physics.BulletSPlugin
33{
34
35public abstract class BSConstraint : IDisposable
36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
39 protected BulletWorld m_world;
40 protected BSScene PhysicsScene;
41 protected BulletBody m_body1;
42 protected BulletBody m_body2;
43 protected BulletConstraint m_constraint;
44 protected bool m_enabled = false;
45
46 public BulletBody Body1 { get { return m_body1; } }
47 public BulletBody Body2 { get { return m_body2; } }
48 public BulletConstraint Constraint { get { return m_constraint; } }
49 public abstract ConstraintType Type { get; }
50 public bool IsEnabled { get { return m_enabled; } }
51
52 public BSConstraint(BulletWorld world)
53 {
54 m_world = world;
55 PhysicsScene = m_world.physicsScene;
56 }
57
58 public virtual void Dispose()
59 {
60 if (m_enabled)
61 {
62 m_enabled = false;
63 if (m_constraint.HasPhysicalConstraint)
64 {
65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
67 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..7fcb75c
--- /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.Physics.BulletSPlugin
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..5c8d94e
--- /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.Physics.BulletSPlugin
34{
35
36public sealed class BSConstraintCollection : IDisposable
37{
38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
40
41 delegate bool ConstraintAction(BSConstraint constrain);
42
43 private List<BSConstraint> m_constraints;
44 private BulletWorld m_world;
45
46 public BSConstraintCollection(BulletWorld world)
47 {
48 m_world = world;
49 m_constraints = new List<BSConstraint>();
50 }
51
52 public void Dispose()
53 {
54 this.Clear();
55 }
56
57 public void Clear()
58 {
59 lock (m_constraints)
60 {
61 foreach (BSConstraint cons in m_constraints)
62 {
63 cons.Dispose();
64 }
65 m_constraints.Clear();
66 }
67 }
68
69 public bool AddConstraint(BSConstraint cons)
70 {
71 lock (m_constraints)
72 {
73 // There is only one constraint between any bodies. Remove any old just to make sure.
74 RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
75
76 m_constraints.Add(cons);
77 }
78
79 return true;
80 }
81
82 // Get the constraint between two bodies. There can be only one.
83 // Return 'true' if a constraint was found.
84 public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
85 {
86 bool found = false;
87 BSConstraint foundConstraint = null;
88
89 uint lookingID1 = body1.ID;
90 uint lookingID2 = body2.ID;
91 lock (m_constraints)
92 {
93 foreach (BSConstraint constrain in m_constraints)
94 {
95 if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
96 || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
97 {
98 foundConstraint = constrain;
99 found = true;
100 break;
101 }
102 }
103 }
104 returnConstraint = foundConstraint;
105 return found;
106 }
107
108 // Remove any constraint between the passed bodies.
109 // Presumed there is only one such constraint possible.
110 // Return 'true' if a constraint was found and destroyed.
111 public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
112 {
113 bool ret = false;
114 lock (m_constraints)
115 {
116 BSConstraint constrain;
117 if (this.TryGetConstraint(body1, body2, out constrain))
118 {
119 // remove the constraint from our collection
120 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..7a76a9a
--- /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.Physics.BulletSPlugin
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..ed89f63
--- /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.Physics.BulletSPlugin
33{
34
35public sealed class BSConstraintHinge : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38
39 public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB,
41 Vector3 axisInA, Vector3 axisInB,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 pivotInA, pivotInB, axisInA, axisInB,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52
53}
54
55}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
new file mode 100755
index 0000000..37cfa07
--- /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.Physics.BulletSPlugin
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..8e7ddff
--- /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.Physics.BulletSPlugin
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..c6d6331
--- /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.Physics.Manager;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
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..87eba33
--- /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.Physics.BulletSPlugin
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..cae9efa
--- /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.Physics.BulletSPlugin
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..4384cdc
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs
@@ -0,0 +1,854 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Region.OptionalModules.Scripting;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public sealed class BSLinksetConstraints : BSLinkset
38{
39 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
40
41 public class BSLinkInfoConstraint : BSLinkInfo
42 {
43 public ConstraintType constraintType;
44 public BSConstraint constraint;
45 public OMV.Vector3 linearLimitLow;
46 public OMV.Vector3 linearLimitHigh;
47 public OMV.Vector3 angularLimitLow;
48 public OMV.Vector3 angularLimitHigh;
49 public bool useFrameOffset;
50 public bool enableTransMotor;
51 public float transMotorMaxVel;
52 public float transMotorMaxForce;
53 public float cfm;
54 public float erp;
55 public float solverIterations;
56 //
57 public OMV.Vector3 frameInAloc;
58 public OMV.Quaternion frameInArot;
59 public OMV.Vector3 frameInBloc;
60 public OMV.Quaternion frameInBrot;
61 public bool useLinearReferenceFrameA;
62 // Spring
63 public bool[] springAxisEnable;
64 public float[] springDamping;
65 public float[] springStiffness;
66 public OMV.Vector3 springLinearEquilibriumPoint;
67 public OMV.Vector3 springAngularEquilibriumPoint;
68
69 public BSLinkInfoConstraint(BSPrimLinkable pMember)
70 : base(pMember)
71 {
72 constraint = null;
73 ResetLink();
74 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID);
75 }
76
77 // Set all the parameters for this constraint to a fixed, non-movable constraint.
78 public override void ResetLink()
79 {
80 // constraintType = ConstraintType.D6_CONSTRAINT_TYPE;
81 constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE;
82 linearLimitLow = OMV.Vector3.Zero;
83 linearLimitHigh = OMV.Vector3.Zero;
84 angularLimitLow = OMV.Vector3.Zero;
85 angularLimitHigh = OMV.Vector3.Zero;
86 useFrameOffset = BSParam.LinkConstraintUseFrameOffset;
87 enableTransMotor = BSParam.LinkConstraintEnableTransMotor;
88 transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
89 transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
90 cfm = BSParam.LinkConstraintCFM;
91 erp = BSParam.LinkConstraintERP;
92 solverIterations = BSParam.LinkConstraintSolverIterations;
93 frameInAloc = OMV.Vector3.Zero;
94 frameInArot = OMV.Quaternion.Identity;
95 frameInBloc = OMV.Vector3.Zero;
96 frameInBrot = OMV.Quaternion.Identity;
97 useLinearReferenceFrameA = true;
98 springAxisEnable = new bool[6];
99 springDamping = new float[6];
100 springStiffness = new float[6];
101 for (int ii = 0; ii < springAxisEnable.Length; ii++)
102 {
103 springAxisEnable[ii] = false;
104 springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
105 springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
106 }
107 springLinearEquilibriumPoint = OMV.Vector3.Zero;
108 springAngularEquilibriumPoint = OMV.Vector3.Zero;
109 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID);
110 }
111
112 // Given a constraint, apply the current constraint parameters to same.
113 public override void SetLinkParameters(BSConstraint constrain)
114 {
115 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType);
116 switch (constraintType)
117 {
118 case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
119 case ConstraintType.D6_CONSTRAINT_TYPE:
120 BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof;
121 if (constrain6dof != null)
122 {
123 // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code.
124 // zero linear and angular limits makes the objects unable to move in relation to each other
125 constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh);
126 constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh);
127
128 // tweek the constraint to increase stability
129 constrain6dof.UseFrameOffset(useFrameOffset);
130 constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
131 constrain6dof.SetCFMAndERP(cfm, erp);
132 if (solverIterations != 0f)
133 {
134 constrain6dof.SetSolverIterations(solverIterations);
135 }
136 }
137 break;
138 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
139 BSConstraintSpring constrainSpring = constrain as BSConstraintSpring;
140 if (constrainSpring != null)
141 {
142 // zero linear and angular limits makes the objects unable to move in relation to each other
143 constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh);
144 constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh);
145
146 // tweek the constraint to increase stability
147 constrainSpring.UseFrameOffset(useFrameOffset);
148 constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
149 constrainSpring.SetCFMAndERP(cfm, erp);
150 if (solverIterations != 0f)
151 {
152 constrainSpring.SetSolverIterations(solverIterations);
153 }
154 for (int ii = 0; ii < springAxisEnable.Length; ii++)
155 {
156 constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]);
157 if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
158 constrainSpring.SetDamping(ii, springDamping[ii]);
159 if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
160 constrainSpring.SetStiffness(ii, springStiffness[ii]);
161 }
162 constrainSpring.CalculateTransforms();
163
164 if (springLinearEquilibriumPoint != OMV.Vector3.Zero)
165 constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint);
166 else
167 constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED);
168 }
169 break;
170 default:
171 break;
172 }
173 }
174
175 // Return 'true' if the property updates from the physics engine should be reported
176 // to the simulator.
177 // If the constraint is fixed, we don't need to report as the simulator and viewer will
178 // report the right things.
179 public override bool ShouldUpdateChildProperties()
180 {
181 bool ret = true;
182 if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE)
183 ret = false;
184
185 return ret;
186 }
187 }
188
189 public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
190 {
191 LinksetImpl = LinksetImplementation.Constraint;
192 }
193
194 private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]";
195
196 // When physical properties are changed the linkset needs to recalculate
197 // its internal properties.
198 // This is queued in the 'post taint' queue so the
199 // refresh will happen once after all the other taints are applied.
200 public override void Refresh(BSPrimLinkable requestor)
201 {
202 ScheduleRebuild(requestor);
203 base.Refresh(requestor);
204
205 }
206
207 private void ScheduleRebuild(BSPrimLinkable requestor)
208 {
209 DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
210 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
211
212 // When rebuilding, it is possible to set properties that would normally require a rebuild.
213 // If already rebuilding, don't request another rebuild.
214 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
215 lock (this)
216 {
217 if (!RebuildScheduled)
218 {
219 if (!Rebuilding && HasAnyChildren)
220 {
221 RebuildScheduled = true;
222 // Queue to happen after all the other taint processing
223 m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
224 {
225 if (HasAnyChildren)
226 {
227 // Constraints that have not been changed are not rebuild but make sure
228 // the constraint of the requestor is rebuilt.
229 PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor);
230 // Rebuild the linkset and all its constraints.
231 RecomputeLinksetConstraints();
232 }
233 RebuildScheduled = false;
234 });
235 }
236 }
237 }
238 }
239
240 // The object is going dynamic (physical). Do any setup necessary
241 // for a dynamic linkset.
242 // Only the state of the passed object can be modified. The rest of the linkset
243 // has not yet been fully constructed.
244 // Return 'true' if any properties updated on the passed object.
245 // Called at taint-time!
246 public override bool MakeDynamic(BSPrimLinkable child)
247 {
248 bool ret = false;
249 DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
250 if (IsRoot(child))
251 {
252 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
253 Refresh(LinksetRoot);
254 }
255 return ret;
256 }
257
258 // The object is going static (non-physical). Do any setup necessary for a static linkset.
259 // Return 'true' if any properties updated on the passed object.
260 // This doesn't normally happen -- OpenSim removes the objects from the physical
261 // world if it is a static linkset.
262 // Called at taint-time!
263 public override bool MakeStatic(BSPrimLinkable child)
264 {
265 bool ret = false;
266
267 DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
268 child.ClearDisplacement();
269 if (IsRoot(child))
270 {
271 // Schedule a rebuild to verify that the root shape is set to the real shape.
272 Refresh(LinksetRoot);
273 }
274 return ret;
275 }
276
277 // Called at taint-time!!
278 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj)
279 {
280 // Nothing to do for constraints on property updates
281 }
282
283 // Routine called when rebuilding the body of some member of the linkset.
284 // Destroy all the constraints have have been made to root and set
285 // up to rebuild the constraints before the next simulation step.
286 // Returns 'true' of something was actually removed and would need restoring
287 // Called at taint-time!!
288 public override bool RemoveDependencies(BSPrimLinkable child)
289 {
290 bool ret = false;
291
292 DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
293 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
294
295 lock (m_linksetActivityLock)
296 {
297 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
298 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
299 // Cause the constraints, et al to be rebuilt before the next simulation step.
300 Refresh(LinksetRoot);
301 }
302 return ret;
303 }
304
305 // ================================================================
306
307 // Add a new child to the linkset.
308 // Called while LinkActivity is locked.
309 protected override void AddChildToLinkset(BSPrimLinkable child)
310 {
311 if (!HasChild(child))
312 {
313 m_children.Add(child, new BSLinkInfoConstraint(child));
314
315 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
316
317 // Cause constraints and assorted properties to be recomputed before the next simulation step.
318 Refresh(LinksetRoot);
319 }
320 return;
321 }
322
323 // Remove the specified child from the linkset.
324 // Safe to call even if the child is not really in my linkset.
325 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
326 {
327 if (m_children.Remove(child))
328 {
329 BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now
330 BSPrimLinkable childx = child;
331
332 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
333 childx.LocalID,
334 rootx.LocalID, rootx.PhysBody.AddrString,
335 childx.LocalID, childx.PhysBody.AddrString);
336
337 m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate()
338 {
339 PhysicallyUnlinkAChildFromRoot(rootx, childx);
340 });
341 // See that the linkset parameters are recomputed at the end of the taint time.
342 Refresh(LinksetRoot);
343 }
344 else
345 {
346 // Non-fatal occurance.
347 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
348 }
349 return;
350 }
351
352 // Create a constraint between me (root of linkset) and the passed prim (the child).
353 // Called at taint time!
354 private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
355 {
356 // Don't build the constraint when asked. Put it off until just before the simulation step.
357 Refresh(rootPrim);
358 }
359
360 // Create a static constraint between the two passed objects
361 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li)
362 {
363 BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint;
364 if (linkInfo == null)
365 return null;
366
367 // Zero motion for children so they don't interpolate
368 li.member.ZeroMotion(true);
369
370 BSConstraint constrain = null;
371
372 switch (linkInfo.constraintType)
373 {
374 case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
375 case ConstraintType.D6_CONSTRAINT_TYPE:
376 // Relative position normalized to the root prim
377 // Essentually a vector pointing from center of rootPrim to center of li.member
378 OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position;
379
380 // real world coordinate of midpoint between the two objects
381 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
382
383 DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}",
384 rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody,
385 rootPrim.Position, linkInfo.member.Position, midPoint);
386
387 // create a constraint that allows no freedom of movement between the two objects
388 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
389
390 constrain = new BSConstraint6Dof(
391 m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true );
392
393 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
394 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
395 * of the objects.
396 * Code left for future programmers.
397 // ==================================================================================
398 // relative position normalized to the root prim
399 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
400 OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation;
401
402 // relative rotation of the child to the parent
403 OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation;
404 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
405
406 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID);
407 constrain = new BS6DofConstraint(
408 PhysicsScene.World, rootPrim.Body, liConstraint.member.Body,
409 OMV.Vector3.Zero,
410 OMV.Quaternion.Inverse(rootPrim.Orientation),
411 OMV.Vector3.Zero,
412 OMV.Quaternion.Inverse(liConstraint.member.Orientation),
413 true,
414 true
415 );
416 // ==================================================================================
417 */
418
419 break;
420 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
421 constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody,
422 linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot,
423 linkInfo.useLinearReferenceFrameA,
424 true /*disableCollisionsBetweenLinkedBodies*/);
425 DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}",
426 rootPrim.LocalID,
427 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
428 linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString,
429 rootPrim.Position, linkInfo.member.Position);
430
431 break;
432 default:
433 break;
434 }
435
436 linkInfo.SetLinkParameters(constrain);
437
438 m_physicsScene.Constraints.AddConstraint(constrain);
439
440 return constrain;
441 }
442
443 // Remove linkage between the linkset root and a particular child
444 // The root and child bodies are passed in because we need to remove the constraint between
445 // the bodies that were present at unlink time.
446 // Called at taint time!
447 private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
448 {
449 bool ret = false;
450 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
451 rootPrim.LocalID,
452 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
453 childPrim.LocalID, childPrim.PhysBody.AddrString);
454
455 // If asked to unlink root from root, just remove all the constraints
456 if (rootPrim == childPrim || childPrim == LinksetRoot)
457 {
458 PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
459 ret = true;
460 }
461 else
462 {
463 // Find the constraint for this link and get rid of it from the overall collection and from my list
464 if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
465 {
466 // Make the child refresh its location
467 m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
468 ret = true;
469 }
470 }
471
472 return ret;
473 }
474
475 // Remove linkage between myself and any possible children I might have.
476 // Returns 'true' of any constraints were destroyed.
477 // Called at taint time!
478 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim)
479 {
480 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
481
482 return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
483 }
484
485 // Call each of the constraints that make up this linkset and recompute the
486 // various transforms and variables. Create constraints of not created yet.
487 // Called before the simulation step to make sure the constraint based linkset
488 // is all initialized.
489 // Called at taint time!!
490 private void RecomputeLinksetConstraints()
491 {
492 float linksetMass = LinksetMass;
493 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
494
495 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
496 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
497
498 try
499 {
500 Rebuilding = true;
501
502 // There is no reason to build all this physical stuff for a non-physical linkset.
503 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
504 {
505 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
506 return; // Note the 'finally' clause at the botton which will get executed.
507 }
508
509 ForEachLinkInfo((li) =>
510 {
511 // A child in the linkset physically shows the mass of the whole linkset.
512 // This allows Bullet to apply enough force on the child to move the whole linkset.
513 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
514 li.member.UpdatePhysicalMassProperties(linksetMass, true);
515
516 BSConstraint constrain;
517 if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain))
518 {
519 // If constraint doesn't exist yet, create it.
520 constrain = BuildConstraint(LinksetRoot, li);
521 }
522 li.SetLinkParameters(constrain);
523 constrain.RecomputeConstraintVariables(linksetMass);
524
525 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
526 return false; // 'false' says to keep processing other members
527 });
528 }
529 finally
530 {
531 Rebuilding = false;
532 }
533 }
534
535 #region Extension
536 public override object Extension(string pFunct, params object[] pParams)
537 {
538 object ret = null;
539 switch (pFunct)
540 {
541 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
542 case ExtendedPhysics.PhysFunctChangeLinkType:
543 if (pParams.Length > 2)
544 {
545 int requestedType = (int)pParams[2];
546 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType);
547 if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE
548 || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE
549 || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE
550 || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE
551 || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE
552 || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE)
553 {
554 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
555 if (child != null)
556 {
557 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}",
558 LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType);
559 m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate()
560 {
561 // Pick up all the constraints currently created.
562 RemoveDependencies(child);
563
564 BSLinkInfo linkInfo = null;
565 if (TryGetLinkInfo(child, out linkInfo))
566 {
567 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
568 if (linkInfoC != null)
569 {
570 linkInfoC.constraintType = (ConstraintType)requestedType;
571 ret = (object)true;
572 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}",
573 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
574 }
575 else
576 {
577 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID);
578 }
579 }
580 else
581 {
582 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID);
583 }
584 // Cause the whole linkset to be rebuilt in post-taint time.
585 Refresh(child);
586 });
587 }
588 else
589 {
590 DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID);
591 }
592 }
593 else
594 {
595 DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}",
596 LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE));
597 }
598 }
599 break;
600 // pParams = [ BSPhysObject root, BSPhysObject child ]
601 case ExtendedPhysics.PhysFunctGetLinkType:
602 if (pParams.Length > 0)
603 {
604 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
605 if (child != null)
606 {
607 BSLinkInfo linkInfo = null;
608 if (TryGetLinkInfo(child, out linkInfo))
609 {
610 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
611 if (linkInfoC != null)
612 {
613 ret = (object)(int)linkInfoC.constraintType;
614 DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}",
615 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
616
617 }
618 }
619 }
620 }
621 break;
622 // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ]
623 case ExtendedPhysics.PhysFunctChangeLinkParams:
624 // There should be two parameters: the childActor and a list of parameters to set
625 if (pParams.Length > 2)
626 {
627 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
628 BSLinkInfo baseLinkInfo = null;
629 if (TryGetLinkInfo(child, out baseLinkInfo))
630 {
631 BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint;
632 if (linkInfo != null)
633 {
634 int valueInt;
635 float valueFloat;
636 bool valueBool;
637 OMV.Vector3 valueVector;
638 OMV.Vector3 valueVector2;
639 OMV.Quaternion valueQuaternion;
640 int axisLow, axisHigh;
641
642 int opIndex = 2;
643 while (opIndex < pParams.Length)
644 {
645 int thisOp = 0;
646 string errMsg = "";
647 try
648 {
649 thisOp = (int)pParams[opIndex];
650 DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}",
651 linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]);
652 switch (thisOp)
653 {
654 case ExtendedPhysics.PHYS_PARAM_LINK_TYPE:
655 valueInt = (int)pParams[opIndex + 1];
656 ConstraintType valueType = (ConstraintType)valueInt;
657 if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE
658 || valueType == ConstraintType.D6_CONSTRAINT_TYPE
659 || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE
660 || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE
661 || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE
662 || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE)
663 {
664 linkInfo.constraintType = valueType;
665 }
666 opIndex += 2;
667 break;
668 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC:
669 errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector";
670 valueVector = (OMV.Vector3)pParams[opIndex + 1];
671 linkInfo.frameInAloc = valueVector;
672 opIndex += 2;
673 break;
674 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT:
675 errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation";
676 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
677 linkInfo.frameInArot = valueQuaternion;
678 opIndex += 2;
679 break;
680 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC:
681 errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector";
682 valueVector = (OMV.Vector3)pParams[opIndex + 1];
683 linkInfo.frameInBloc = valueVector;
684 opIndex += 2;
685 break;
686 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT:
687 errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation";
688 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
689 linkInfo.frameInBrot = valueQuaternion;
690 opIndex += 2;
691 break;
692 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW:
693 errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector";
694 valueVector = (OMV.Vector3)pParams[opIndex + 1];
695 linkInfo.linearLimitLow = valueVector;
696 opIndex += 2;
697 break;
698 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH:
699 errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector";
700 valueVector = (OMV.Vector3)pParams[opIndex + 1];
701 linkInfo.linearLimitHigh = valueVector;
702 opIndex += 2;
703 break;
704 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW:
705 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector";
706 valueVector = (OMV.Vector3)pParams[opIndex + 1];
707 linkInfo.angularLimitLow = valueVector;
708 opIndex += 2;
709 break;
710 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH:
711 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector";
712 valueVector = (OMV.Vector3)pParams[opIndex + 1];
713 linkInfo.angularLimitHigh = valueVector;
714 opIndex += 2;
715 break;
716 case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET:
717 errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)";
718 valueBool = ((int)pParams[opIndex + 1]) != 0;
719 linkInfo.useFrameOffset = valueBool;
720 opIndex += 2;
721 break;
722 case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR:
723 errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)";
724 valueBool = ((int)pParams[opIndex + 1]) != 0;
725 linkInfo.enableTransMotor = valueBool;
726 opIndex += 2;
727 break;
728 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL:
729 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float";
730 valueFloat = (float)pParams[opIndex + 1];
731 linkInfo.transMotorMaxVel = valueFloat;
732 opIndex += 2;
733 break;
734 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE:
735 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float";
736 valueFloat = (float)pParams[opIndex + 1];
737 linkInfo.transMotorMaxForce = valueFloat;
738 opIndex += 2;
739 break;
740 case ExtendedPhysics.PHYS_PARAM_CFM:
741 errMsg = "PHYS_PARAM_CFM takes one parameter of type float";
742 valueFloat = (float)pParams[opIndex + 1];
743 linkInfo.cfm = valueFloat;
744 opIndex += 2;
745 break;
746 case ExtendedPhysics.PHYS_PARAM_ERP:
747 errMsg = "PHYS_PARAM_ERP takes one parameter of type float";
748 valueFloat = (float)pParams[opIndex + 1];
749 linkInfo.erp = valueFloat;
750 opIndex += 2;
751 break;
752 case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS:
753 errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float";
754 valueFloat = (float)pParams[opIndex + 1];
755 linkInfo.solverIterations = valueFloat;
756 opIndex += 2;
757 break;
758 case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE:
759 errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)";
760 valueInt = (int)pParams[opIndex + 1];
761 valueBool = ((int)pParams[opIndex + 2]) != 0;
762 GetAxisRange(valueInt, out axisLow, out axisHigh);
763 for (int ii = axisLow; ii <= axisHigh; ii++)
764 linkInfo.springAxisEnable[ii] = valueBool;
765 opIndex += 3;
766 break;
767 case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING:
768 errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float";
769 valueInt = (int)pParams[opIndex + 1];
770 valueFloat = (float)pParams[opIndex + 2];
771 GetAxisRange(valueInt, out axisLow, out axisHigh);
772 for (int ii = axisLow; ii <= axisHigh; ii++)
773 linkInfo.springDamping[ii] = valueFloat;
774 opIndex += 3;
775 break;
776 case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS:
777 errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float";
778 valueInt = (int)pParams[opIndex + 1];
779 valueFloat = (float)pParams[opIndex + 2];
780 GetAxisRange(valueInt, out axisLow, out axisHigh);
781 for (int ii = axisLow; ii <= axisHigh; ii++)
782 linkInfo.springStiffness[ii] = valueFloat;
783 opIndex += 3;
784 break;
785 case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT:
786 errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector";
787 valueVector = (OMV.Vector3)pParams[opIndex + 1];
788 valueVector2 = (OMV.Vector3)pParams[opIndex + 2];
789 linkInfo.springLinearEquilibriumPoint = valueVector;
790 linkInfo.springAngularEquilibriumPoint = valueVector2;
791 opIndex += 3;
792 break;
793 case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA:
794 errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)";
795 valueBool = ((int)pParams[opIndex + 1]) != 0;
796 linkInfo.useLinearReferenceFrameA = valueBool;
797 opIndex += 2;
798 break;
799 default:
800 break;
801 }
802 }
803 catch (InvalidCastException e)
804 {
805 m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}",
806 LogHeader, errMsg, e);
807 }
808 catch (Exception e)
809 {
810 m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e);
811 }
812 }
813 }
814 // Something changed so a rebuild is in order
815 Refresh(child);
816 }
817 }
818 break;
819 default:
820 ret = base.Extension(pFunct, pParams);
821 break;
822 }
823 return ret;
824 }
825
826 // Bullet constraints keep some limit parameters for each linear and angular axis.
827 // Setting same is easier if there is an easy way to see all or types.
828 // This routine returns the array limits for the set of axis.
829 private void GetAxisRange(int rangeSpec, out int low, out int high)
830 {
831 switch (rangeSpec)
832 {
833 case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL:
834 low = 0;
835 high = 2;
836 break;
837 case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL:
838 low = 3;
839 high = 5;
840 break;
841 case ExtendedPhysics.PHYS_AXIS_ALL:
842 low = 0;
843 high = 5;
844 break;
845 default:
846 low = high = rangeSpec;
847 break;
848 }
849 return;
850 }
851 #endregion // Extension
852
853}
854}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
new file mode 100755
index 0000000..ee77d6e
--- /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.Physics.BulletSPlugin
34{
35
36public struct MaterialAttributes
37{
38 // Material type values that correspond with definitions for LSL
39 public enum Material : int
40 {
41 Stone = 0,
42 Metal,
43 Glass,
44 Wood,
45 Flesh,
46 Plastic,
47 Rubber,
48 Light,
49 // Hereafter are BulletSim additions
50 Avatar,
51 NumberOfTypes // the count of types in the enum.
52 }
53
54 // Names must be in the order of the above enum.
55 // These names must coorespond to the lower case field names in the MaterialAttributes
56 // structure as reflection is used to select the field to put the value in.
57 public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
58
59 public MaterialAttributes(string t, float d, float f, float r)
60 {
61 type = t;
62 density = d;
63 friction = f;
64 restitution = r;
65 }
66 public string type;
67 public float density;
68 public float friction;
69 public float restitution;
70}
71
72public static class BSMaterials
73{
74 // Attributes for each material type
75 private static readonly MaterialAttributes[] Attributes;
76
77 // Map of material name to material type code
78 public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap;
79
80 static BSMaterials()
81 {
82 // Attribute sets for both the non-physical and physical instances of materials.
83 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
84
85 // Map of name to type code.
86 MaterialMap = new Dictionary<string, MaterialAttributes.Material>();
87 MaterialMap.Add("Stone", MaterialAttributes.Material.Stone);
88 MaterialMap.Add("Metal", MaterialAttributes.Material.Metal);
89 MaterialMap.Add("Glass", MaterialAttributes.Material.Glass);
90 MaterialMap.Add("Wood", MaterialAttributes.Material.Wood);
91 MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh);
92 MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic);
93 MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber);
94 MaterialMap.Add("Light", MaterialAttributes.Material.Light);
95 MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar);
96 }
97
98 // This is where all the default material attributes are defined.
99 public static void InitializeFromDefaults(ConfigurationParameters parms)
100 {
101 // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
102 float dDensity = parms.defaultDensity;
103 float dFriction = parms.defaultFriction;
104 float dRestitution = parms.defaultRestitution;
105 Attributes[(int)MaterialAttributes.Material.Stone] =
106 new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
107 Attributes[(int)MaterialAttributes.Material.Metal] =
108 new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
109 Attributes[(int)MaterialAttributes.Material.Glass] =
110 new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
111 Attributes[(int)MaterialAttributes.Material.Wood] =
112 new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
113 Attributes[(int)MaterialAttributes.Material.Flesh] =
114 new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
115 Attributes[(int)MaterialAttributes.Material.Plastic] =
116 new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
117 Attributes[(int)MaterialAttributes.Material.Rubber] =
118 new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
119 Attributes[(int)MaterialAttributes.Material.Light] =
120 new MaterialAttributes("light",dDensity, dFriction, dRestitution);
121 Attributes[(int)MaterialAttributes.Material.Avatar] =
122 new MaterialAttributes("avatar",3.5f, 0.2f, 0f);
123
124 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
125 new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
126 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
127 new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f);
128 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
129 new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f);
130 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
131 new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f);
132 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
133 new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f);
134 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
135 new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f);
136 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
137 new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f);
138 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
139 new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
140 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
141 new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f);
142 }
143
144 // Under the [BulletSim] section, one can change the individual material
145 // attribute values. The format of the configuration parameter is:
146 // <materialName><Attribute>["Physical"] = floatValue
147 // For instance:
148 // [BulletSim]
149 // StoneFriction = 0.2
150 // FleshRestitutionPhysical = 0.8
151 // Materials can have different parameters for their static and
152 // physical instantiations. When setting the non-physical value,
153 // both values are changed. Setting the physical value only changes
154 // the physical value.
155 public static void InitializefromParameters(IConfig pConfig)
156 {
157 foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap)
158 {
159 string matName = kvp.Key;
160 foreach (string attribName in MaterialAttributes.MaterialAttribs)
161 {
162 string paramName = matName + attribName;
163 if (pConfig.Contains(paramName))
164 {
165 float paramValue = pConfig.GetFloat(paramName);
166 SetAttributeValue((int)kvp.Value, attribName, paramValue);
167 // set the physical value also
168 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
169 }
170 paramName += "Physical";
171 if (pConfig.Contains(paramName))
172 {
173 float paramValue = pConfig.GetFloat(paramName);
174 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
175 }
176 }
177 }
178 }
179
180 // Use reflection to set the value in the attribute structure.
181 private static void SetAttributeValue(int matType, string attribName, float val)
182 {
183 // 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..7693195
--- /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.Physics.BulletSPlugin
35{
36public abstract class BSMotor
37{
38 // Timescales and other things can be turned off by setting them to 'infinite'.
39 public const float Infinite = 12345.6f;
40 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
41
42 public BSMotor(string useName)
43 {
44 UseName = useName;
45 PhysicsScene = null;
46 Enabled = true;
47 }
48 public virtual bool Enabled { get; set; }
49 public virtual void Reset() { }
50 public virtual void Zero() { }
51 public virtual void GenerateTestOutput(float timeStep) { }
52
53 // A name passed at motor creation for easily identifyable debugging messages.
54 public string UseName { get; private set; }
55
56 // Used only for outputting debug information. Might not be set so check for null.
57 public BSScene PhysicsScene { get; set; }
58 protected void MDetailLog(string msg, params Object[] parms)
59 {
60 if (PhysicsScene != null)
61 {
62 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..6d46fe6
--- /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.Physics.Manager;
33
34using OpenMetaverse;
35using Nini.Config;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
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..90da7a6
--- /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.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37/*
38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant.
41 *
42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last 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/BSPlugin.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs
new file mode 100644
index 0000000..9442854
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs
@@ -0,0 +1,76 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using OpenSim.Framework;
30using OpenSim.Region.Physics.Manager;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
40 /// The unmanaged library is compiled and linked statically with Bullet
41 /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit).
42 /// </summary>
43public class BSPlugin : IPhysicsPlugin
44{
45 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
46
47 private BSScene _mScene;
48
49 public BSPlugin()
50 {
51 }
52
53 public bool Init()
54 {
55 return true;
56 }
57
58 public PhysicsScene GetScene(String sceneIdentifier)
59 {
60 if (_mScene == null)
61 {
62 _mScene = new BSScene(GetName(), sceneIdentifier);
63 }
64 return (_mScene);
65 }
66
67 public string GetName()
68 {
69 return ("BulletSim");
70 }
71
72 public void Dispose()
73 {
74 }
75}
76}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
new file mode 100644
index 0000000..a00991f
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
@@ -0,0 +1,1896 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using System.Collections.Generic;
31using System.Xml;
32using log4net;
33using OMV = OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Physics.Manager;
36using OpenSim.Region.Physics.ConvexDecompositionDotNet;
37using OpenSim.Region.OptionalModules.Scripting; // for ExtendedPhysics
38
39namespace OpenSim.Region.Physics.BulletSPlugin
40{
41
42 [Serializable]
43public class BSPrim : BSPhysObject
44{
45 protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 private static readonly string LogHeader = "[BULLETS PRIM]";
47
48 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
50
51 private bool _grabbed;
52 private bool _isSelected;
53 private bool _isVolumeDetect;
54
55 private float _mass; // the mass of this object
56 private OMV.Vector3 _acceleration;
57 private int _physicsActorType;
58 private bool _isPhysical;
59 private bool _flying;
60 private bool _setAlwaysRun;
61 private bool _throttleUpdates;
62 private bool _floatOnWater;
63 private OMV.Vector3 _rotationalVelocity;
64 private bool _kinematic;
65 private float _buoyancy;
66
67 private int CrossingFailures { get; set; }
68
69 // Keep a handle to the vehicle actor so it is easy to set parameters on same.
70 public const string VehicleActorName = "BasicVehicle";
71
72 // Parameters for the hover actor
73 public const string HoverActorName = "BSPrim.HoverActor";
74 // Parameters for the axis lock actor
75 public const String LockedAxisActorName = "BSPrim.LockedAxis";
76 // Parameters for the move to target actor
77 public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor";
78 // Parameters for the setForce and setTorque actors
79 public const string SetForceActorName = "BSPrim.SetForceActor";
80 public const string SetTorqueActorName = "BSPrim.SetTorqueActor";
81
82 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
83 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
84 : base(parent_scene, localID, primName, "BSPrim")
85 {
86 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
87 _physicsActorType = (int)ActorTypes.Prim;
88 RawPosition = pos;
89 _size = size;
90 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
91 RawOrientation = rotation;
92 _buoyancy = 0f;
93 RawVelocity = OMV.Vector3.Zero;
94 _rotationalVelocity = OMV.Vector3.Zero;
95 BaseShape = pbs;
96 _isPhysical = pisPhysical;
97 _isVolumeDetect = false;
98
99 _mass = CalculateMass();
100
101 DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs));
102 // DetailLog("{0},BSPrim.constructor,call", LocalID);
103 // do the actual object creation at taint time
104 PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate()
105 {
106 // Make sure the object is being created with some sanity.
107 ExtremeSanityCheck(true /* inTaintTime */);
108
109 CreateGeomAndObject(true);
110
111 CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
112
113 IsInitialized = true;
114 });
115 }
116
117 // called when this prim is being destroyed and we should free all the resources
118 public override void Destroy()
119 {
120 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
121 IsInitialized = false;
122
123 base.Destroy();
124
125 // Undo any vehicle properties
126 this.VehicleType = (int)Vehicle.TYPE_NONE;
127
128 PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate()
129 {
130 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
131 // If there are physical body and shape, release my use of same.
132 PhysScene.Shapes.DereferenceBody(PhysBody, null);
133 PhysBody.Clear();
134 PhysShape.Dereference(PhysScene);
135 PhysShape = new BSShapeNull();
136 });
137 }
138
139 // No one uses this property.
140 public override bool Stopped {
141 get { return false; }
142 }
143
144 public override bool IsIncomplete {
145 get {
146 return ShapeRebuildScheduled;
147 }
148 }
149
150 // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued.
151 // The prim is still available but its underlying shape will change soon.
152 // This is protected by a 'lock(this)'.
153 public bool ShapeRebuildScheduled { get; protected set; }
154
155 public override OMV.Vector3 Size {
156 get { return _size; }
157 set {
158 // We presume the scale and size are the same. If scale must be changed for
159 // the physical shape, that is done when the geometry is built.
160 _size = value;
161 Scale = _size;
162 ForceBodyShapeRebuild(false);
163 }
164 }
165
166 public override PrimitiveBaseShape Shape {
167 set {
168 BaseShape = value;
169 DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape));
170 PrimAssetState = PrimAssetCondition.Unknown;
171 ForceBodyShapeRebuild(false);
172 }
173 }
174 // Cause the body and shape of the prim to be rebuilt if necessary.
175 // If there are no changes required, this is quick and does not make changes to the prim.
176 // If rebuilding is necessary (like changing from static to physical), that will happen.
177 // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly.
178 // The return parameter is not used by anyone.
179 public override bool ForceBodyShapeRebuild(bool inTaintTime)
180 {
181 if (inTaintTime)
182 {
183 // If called in taint time, do the operation immediately
184 _mass = CalculateMass(); // changing the shape changes the mass
185 CreateGeomAndObject(true);
186 }
187 else
188 {
189 lock (this)
190 {
191 // If a rebuild is not already in the queue
192 if (!ShapeRebuildScheduled)
193 {
194 // Remember that a rebuild is queued -- this is used to flag an incomplete object
195 ShapeRebuildScheduled = true;
196 PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate()
197 {
198 _mass = CalculateMass(); // changing the shape changes the mass
199 CreateGeomAndObject(true);
200 ShapeRebuildScheduled = false;
201 });
202 }
203 }
204 }
205 return true;
206 }
207 public override bool Grabbed {
208 set { _grabbed = value;
209 }
210 }
211 public override bool Selected {
212 set
213 {
214 if (value != _isSelected)
215 {
216 _isSelected = value;
217 PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate()
218 {
219 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
220 SetObjectDynamic(false);
221 });
222 }
223 }
224 }
225 public override bool IsSelected
226 {
227 get { return _isSelected; }
228 }
229
230 public override void CrossingFailure()
231 {
232 CrossingFailures++;
233 if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds)
234 {
235 base.RaiseOutOfBounds(RawPosition);
236 }
237 else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds)
238 {
239 m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name);
240 }
241 return;
242 }
243
244 // link me to the specified parent
245 public override void link(PhysicsActor obj) {
246 }
247
248 // delink me from my linkset
249 public override void delink() {
250 }
251
252 // Set motion values to zero.
253 // Do it to the properties so the values get set in the physics engine.
254 // Push the setting of the values to the viewer.
255 // Called at taint time!
256 public override void ZeroMotion(bool inTaintTime)
257 {
258 RawVelocity = OMV.Vector3.Zero;
259 _acceleration = OMV.Vector3.Zero;
260 _rotationalVelocity = OMV.Vector3.Zero;
261
262 // Zero some other properties in the physics engine
263 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
264 {
265 if (PhysBody.HasPhysicalBody)
266 PhysScene.PE.ClearAllForces(PhysBody);
267 });
268 }
269 public override void ZeroAngularMotion(bool inTaintTime)
270 {
271 _rotationalVelocity = OMV.Vector3.Zero;
272 // Zero some other properties in the physics engine
273 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
274 {
275 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
276 if (PhysBody.HasPhysicalBody)
277 {
278 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
279 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
280 }
281 });
282 }
283
284 public override void LockAngularMotion(OMV.Vector3 axis)
285 {
286 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
287
288 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
289 if (axis.X != 1)
290 {
291 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f);
292 }
293 if (axis.Y != 1)
294 {
295 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f);
296 }
297 if (axis.Z != 1)
298 {
299 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f);
300 }
301
302 InitializeAxisActor();
303
304 return;
305 }
306
307 public override OMV.Vector3 Position {
308 get {
309 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
310 // RawPosition = ForcePosition;
311 return RawPosition;
312 }
313 set {
314 // If the position must be forced into the physics engine, use ForcePosition.
315 // All positions are given in world positions.
316 if (RawPosition == value)
317 {
318 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
319 return;
320 }
321 RawPosition = value;
322 PositionSanityCheck(false);
323
324 PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate()
325 {
326 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
327 ForcePosition = RawPosition;
328 });
329 }
330 }
331
332 // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity.
333 public override OMV.Vector3 ForcePosition {
334 get {
335 RawPosition = PhysScene.PE.GetPosition(PhysBody);
336 return RawPosition;
337 }
338 set {
339 RawPosition = value;
340 if (PhysBody.HasPhysicalBody)
341 {
342 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
343 ActivateIfPhysical(false);
344 }
345 }
346 }
347
348 // Check that the current position is sane and, if not, modify the position to make it so.
349 // Check for being below terrain and being out of bounds.
350 // Returns 'true' of the position was made sane by some action.
351 private bool PositionSanityCheck(bool inTaintTime)
352 {
353 bool ret = false;
354
355 // We don't care where non-physical items are placed
356 if (!IsPhysicallyActive)
357 return ret;
358
359 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
360 {
361 // The physical object is out of the known/simulated area.
362 // Upper levels of code will handle the transition to other areas so, for
363 // the time, we just ignore the position.
364 return ret;
365 }
366
367 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
368 OMV.Vector3 upForce = OMV.Vector3.Zero;
369 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
370 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
371 {
372 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
373 float targetHeight = terrainHeight + (Size.Z / 2f);
374 // If the object is below ground it just has to be moved up because pushing will
375 // not get it through the terrain
376 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight);
377 if (inTaintTime)
378 {
379 ForcePosition = RawPosition;
380 }
381 // If we are throwing the object around, zero its other forces
382 ZeroMotion(inTaintTime);
383 ret = true;
384 }
385
386 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
387 {
388 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
389 // TODO: a floating motor so object will bob in the water
390 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
391 {
392 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
393 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
394
395 // Apply upforce and overcome gravity.
396 OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
397 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce);
398 AddForce(correctionForce, false, inTaintTime);
399 ret = true;
400 }
401 }
402
403 return ret;
404 }
405
406 // Occasionally things will fly off and really get lost.
407 // Find the wanderers and bring them back.
408 // Return 'true' if some parameter need some sanity.
409 private bool ExtremeSanityCheck(bool inTaintTime)
410 {
411 bool ret = false;
412
413 int wayOverThere = -1000;
414 int wayOutThere = 10000;
415 // There have been instances of objects getting thrown way out of bounds and crashing
416 // the border crossing code.
417 if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere
418 || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere
419 || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere)
420 {
421 RawPosition = new OMV.Vector3(10, 10, 50);
422 ZeroMotion(inTaintTime);
423 ret = true;
424 }
425 if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared)
426 {
427 RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
428 ret = true;
429 }
430 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
431 {
432 _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
433 ret = true;
434 }
435
436 return ret;
437 }
438
439 // Return the effective mass of the object.
440 // The definition of this call is to return the mass of the prim.
441 // If the simulator cares about the mass of the linkset, it will sum it itself.
442 public override float Mass
443 {
444 get { return _mass; }
445 }
446 // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
447 public virtual float TotalMass
448 {
449 get { return _mass; }
450 }
451 // used when we only want this prim's mass and not the linkset thing
452 public override float RawMass {
453 get { return _mass; }
454 }
455 // Set the physical mass to the passed mass.
456 // Note that this does not change _mass!
457 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
458 {
459 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
460 {
461 if (IsStatic)
462 {
463 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
464 Inertia = OMV.Vector3.Zero;
465 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
466 PhysScene.PE.UpdateInertiaTensor(PhysBody);
467 }
468 else
469 {
470 if (inWorld)
471 {
472 // Changing interesting properties doesn't change proxy and collision cache
473 // information. The Bullet solution is to re-add the object to the world
474 // after parameters are changed.
475 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
476 }
477
478 // The computation of mass props requires gravity to be set on the object.
479 Gravity = ComputeGravity(Buoyancy);
480 PhysScene.PE.SetGravity(PhysBody, Gravity);
481
482 // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
483 // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
484
485 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
486 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
487 PhysScene.PE.UpdateInertiaTensor(PhysBody);
488
489 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
490 LocalID, physMass, Inertia, Gravity, inWorld);
491
492 if (inWorld)
493 {
494 AddObjectToPhysicalWorld();
495 }
496 }
497 }
498 }
499
500 // Return what gravity should be set to this very moment
501 public OMV.Vector3 ComputeGravity(float buoyancy)
502 {
503 OMV.Vector3 ret = PhysScene.DefaultGravity;
504
505 if (!IsStatic)
506 {
507 ret *= (1f - buoyancy);
508 ret *= GravModifier;
509 }
510
511 return ret;
512 }
513
514 // Is this used?
515 public override OMV.Vector3 CenterOfMass
516 {
517 get { return RawPosition; }
518 }
519
520 // Is this used?
521 public override OMV.Vector3 GeometricCenter
522 {
523 get { return RawPosition; }
524 }
525
526 public override OMV.Vector3 Force {
527 get { return RawForce; }
528 set {
529 RawForce = value;
530 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
531 {
532 return new BSActorSetForce(PhysScene, this, SetForceActorName);
533 });
534
535 // Call update so actor Refresh() is called to start things off
536 PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate()
537 {
538 UpdatePhysicalParameters();
539 });
540 }
541 }
542
543 // Find and return a handle to the current vehicle actor.
544 // Return 'null' if there is no vehicle actor.
545 public BSDynamics GetVehicleActor(bool createIfNone)
546 {
547 BSDynamics ret = null;
548 BSActor actor;
549 if (PhysicalActors.TryGetActor(VehicleActorName, out actor))
550 {
551 ret = actor as BSDynamics;
552 }
553 else
554 {
555 if (createIfNone)
556 {
557 ret = new BSDynamics(PhysScene, this, VehicleActorName);
558 PhysicalActors.Add(ret.ActorName, ret);
559 }
560 }
561 return ret;
562 }
563
564 public override int VehicleType {
565 get {
566 int ret = (int)Vehicle.TYPE_NONE;
567 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
568 if (vehicleActor != null)
569 ret = (int)vehicleActor.Type;
570 return ret;
571 }
572 set {
573 Vehicle type = (Vehicle)value;
574
575 PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
576 {
577 // Some vehicle scripts change vehicle type on the fly as an easy way to
578 // change all the parameters. Like a plane changing to CAR when on the
579 // ground. In this case, don't want to zero motion.
580 // ZeroMotion(true /* inTaintTime */);
581 if (type == Vehicle.TYPE_NONE)
582 {
583 // Vehicle type is 'none' so get rid of any actor that may have been allocated.
584 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
585 if (vehicleActor != null)
586 {
587 PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
588 }
589 }
590 else
591 {
592 // Vehicle type is not 'none' so create an actor and set it running.
593 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
594 if (vehicleActor != null)
595 {
596 vehicleActor.ProcessTypeChange(type);
597 ActivateIfPhysical(false);
598 }
599 }
600 });
601 }
602 }
603 public override void VehicleFloatParam(int param, float value)
604 {
605 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
606 {
607 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
608 if (vehicleActor != null)
609 {
610 vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
611 ActivateIfPhysical(false);
612 }
613 });
614 }
615 public override void VehicleVectorParam(int param, OMV.Vector3 value)
616 {
617 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
618 {
619 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
620 if (vehicleActor != null)
621 {
622 vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
623 ActivateIfPhysical(false);
624 }
625 });
626 }
627 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
628 {
629 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
630 {
631 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
632 if (vehicleActor != null)
633 {
634 vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
635 ActivateIfPhysical(false);
636 }
637 });
638 }
639 public override void VehicleFlags(int param, bool remove)
640 {
641 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
642 {
643 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
644 if (vehicleActor != null)
645 {
646 vehicleActor.ProcessVehicleFlags(param, remove);
647 }
648 });
649 }
650
651 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
652 public override void SetVolumeDetect(int param) {
653 bool newValue = (param != 0);
654 if (_isVolumeDetect != newValue)
655 {
656 _isVolumeDetect = newValue;
657 PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
658 {
659 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
660 SetObjectDynamic(true);
661 });
662 }
663 return;
664 }
665 public override bool IsVolumeDetect
666 {
667 get { return _isVolumeDetect; }
668 }
669 public override void SetMaterial(int material)
670 {
671 base.SetMaterial(material);
672 PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
673 {
674 UpdatePhysicalParameters();
675 });
676 }
677 public override float Friction
678 {
679 get { return base.Friction; }
680 set
681 {
682 if (base.Friction != value)
683 {
684 base.Friction = value;
685 PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
686 {
687 UpdatePhysicalParameters();
688 });
689 }
690 }
691 }
692 public override float Restitution
693 {
694 get { return base.Restitution; }
695 set
696 {
697 if (base.Restitution != value)
698 {
699 base.Restitution = value;
700 PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
701 {
702 UpdatePhysicalParameters();
703 });
704 }
705 }
706 }
707 // The simulator/viewer keep density as 100kg/m3.
708 // Remember to use BSParam.DensityScaleFactor to create the physical density.
709 public override float Density
710 {
711 get { return base.Density; }
712 set
713 {
714 if (base.Density != value)
715 {
716 base.Density = value;
717 PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
718 {
719 UpdatePhysicalParameters();
720 });
721 }
722 }
723 }
724 public override float GravModifier
725 {
726 get { return base.GravModifier; }
727 set
728 {
729 if (base.GravModifier != value)
730 {
731 base.GravModifier = value;
732 PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
733 {
734 UpdatePhysicalParameters();
735 });
736 }
737 }
738 }
739 public override OMV.Vector3 Velocity {
740 get { return RawVelocity; }
741 set {
742 RawVelocity = value;
743 PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
744 {
745 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
746 ForceVelocity = RawVelocity;
747 });
748 }
749 }
750 public override OMV.Vector3 ForceVelocity {
751 get { return RawVelocity; }
752 set {
753 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
754
755 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
756 if (PhysBody.HasPhysicalBody)
757 {
758 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
759 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
760 ActivateIfPhysical(false);
761 }
762 }
763 }
764 public override OMV.Vector3 Torque {
765 get { return RawTorque; }
766 set {
767 RawTorque = value;
768 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
769 {
770 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
771 });
772 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
773
774 // Call update so actor Refresh() is called to start things off
775 PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate()
776 {
777 UpdatePhysicalParameters();
778 });
779 }
780 }
781 public override OMV.Vector3 Acceleration {
782 get { return _acceleration; }
783 set { _acceleration = value; }
784 }
785
786 public override OMV.Quaternion Orientation {
787 get {
788 return RawOrientation;
789 }
790 set {
791 if (RawOrientation == value)
792 return;
793 RawOrientation = value;
794
795 PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
796 {
797 ForceOrientation = RawOrientation;
798 });
799 }
800 }
801 // Go directly to Bullet to get/set the value.
802 public override OMV.Quaternion ForceOrientation
803 {
804 get
805 {
806 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
807 return RawOrientation;
808 }
809 set
810 {
811 RawOrientation = value;
812 if (PhysBody.HasPhysicalBody)
813 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
814 }
815 }
816 public override int PhysicsActorType {
817 get { return _physicsActorType; }
818 set { _physicsActorType = value; }
819 }
820 public override bool IsPhysical {
821 get { return _isPhysical; }
822 set {
823 if (_isPhysical != value)
824 {
825 _isPhysical = value;
826 PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
827 {
828 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
829 SetObjectDynamic(true);
830 // whether phys-to-static or static-to-phys, the object is not moving.
831 ZeroMotion(true);
832
833 });
834 }
835 }
836 }
837
838 // An object is static (does not move) if selected or not physical
839 public override bool IsStatic
840 {
841 get { return _isSelected || !IsPhysical; }
842 }
843
844 // An object is solid if it's not phantom and if it's not doing VolumeDetect
845 public override bool IsSolid
846 {
847 get { return !IsPhantom && !_isVolumeDetect; }
848 }
849
850 // The object is moving and is actively being dynamic in the physical world
851 public override bool IsPhysicallyActive
852 {
853 get { return !_isSelected && IsPhysical; }
854 }
855
856 // Make gravity work if the object is physical and not selected
857 // Called at taint-time!!
858 private void SetObjectDynamic(bool forceRebuild)
859 {
860 // Recreate the physical object if necessary
861 CreateGeomAndObject(forceRebuild);
862 }
863
864 // Convert the simulator's physical properties into settings on BulletSim objects.
865 // There are four flags we're interested in:
866 // IsStatic: Object does not move, otherwise the object has mass and moves
867 // isSolid: other objects bounce off of this object
868 // isVolumeDetect: other objects pass through but can generate collisions
869 // collisionEvents: whether this object returns collision events
870 // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
871 public virtual void UpdatePhysicalParameters()
872 {
873 if (!PhysBody.HasPhysicalBody)
874 {
875 // This would only happen if updates are called for during initialization when the body is not set up yet.
876 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
877 return;
878 }
879
880 // Mangling all the physical properties requires the object not be in the physical world.
881 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
882 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
883
884 // Set up the object physicalness (does gravity and collisions move this object)
885 MakeDynamic(IsStatic);
886
887 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
888 PhysicalActors.Refresh();
889
890 // Arrange for collision events if the simulator wants them
891 EnableCollisions(SubscribedEvents());
892
893 // Make solid or not (do things bounce off or pass through this object).
894 MakeSolid(IsSolid);
895
896 AddObjectToPhysicalWorld();
897
898 // Rebuild its shape
899 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
900
901 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
902 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
903 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
904 }
905
906 // "Making dynamic" means changing to and from static.
907 // When static, gravity does not effect the object and it is fixed in space.
908 // When dynamic, the object can fall and be pushed by others.
909 // This is independent of its 'solidness' which controls what passes through
910 // this object and what interacts with it.
911 protected virtual void MakeDynamic(bool makeStatic)
912 {
913 if (makeStatic)
914 {
915 // Become a Bullet 'static' object type
916 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
917 // Stop all movement
918 ZeroMotion(true);
919
920 // Set various physical properties so other object interact properly
921 PhysScene.PE.SetFriction(PhysBody, Friction);
922 PhysScene.PE.SetRestitution(PhysBody, Restitution);
923 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
924
925 // Mass is zero which disables a bunch of physics stuff in Bullet
926 UpdatePhysicalMassProperties(0f, false);
927 // Set collision detection parameters
928 if (BSParam.CcdMotionThreshold > 0f)
929 {
930 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
931 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
932 }
933
934 // The activation state is 'disabled' so Bullet will not try to act on it.
935 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
936 // Start it out sleeping and physical actions could wake it up.
937 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
938
939 // This collides like a static object
940 PhysBody.collisionType = CollisionType.Static;
941 }
942 else
943 {
944 // Not a Bullet static object
945 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
946
947 // Set various physical properties so other object interact properly
948 PhysScene.PE.SetFriction(PhysBody, Friction);
949 PhysScene.PE.SetRestitution(PhysBody, Restitution);
950 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
951
952 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
953 // Since this can be called multiple times, only zero forces when becoming physical
954 // PhysicsScene.PE.ClearAllForces(BSBody);
955
956 // For good measure, make sure the transform is set through to the motion state
957 ForcePosition = RawPosition;
958 ForceVelocity = RawVelocity;
959 ForceRotationalVelocity = _rotationalVelocity;
960
961 // A dynamic object has mass
962 UpdatePhysicalMassProperties(RawMass, false);
963
964 // Set collision detection parameters
965 if (BSParam.CcdMotionThreshold > 0f)
966 {
967 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
968 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
969 }
970
971 // Various values for simulation limits
972 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
973 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
974 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
975 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
976
977 // This collides like an object.
978 PhysBody.collisionType = CollisionType.Dynamic;
979
980 // Force activation of the object so Bullet will act on it.
981 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
982 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
983 }
984 }
985
986 // "Making solid" means that other object will not pass through this object.
987 // To make transparent, we create a Bullet ghost object.
988 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
989 // the functions after this one set up the state of a possibly newly created collision body.
990 private void MakeSolid(bool makeSolid)
991 {
992 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
993 if (makeSolid)
994 {
995 // Verify the previous code created the correct shape for this type of thing.
996 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
997 {
998 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
999 }
1000 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1001 }
1002 else
1003 {
1004 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
1005 {
1006 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
1007 }
1008 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1009
1010 // Change collision info from a static object to a ghosty collision object
1011 PhysBody.collisionType = CollisionType.VolumeDetect;
1012 }
1013 }
1014
1015 // Turn on or off the flag controlling whether collision events are returned to the simulator.
1016 private void EnableCollisions(bool wantsCollisionEvents)
1017 {
1018 if (wantsCollisionEvents)
1019 {
1020 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1021 }
1022 else
1023 {
1024 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1025 }
1026 }
1027
1028 // Add me to the physical world.
1029 // Object MUST NOT already be in the world.
1030 // This routine exists because some assorted properties get mangled by adding to the world.
1031 internal void AddObjectToPhysicalWorld()
1032 {
1033 if (PhysBody.HasPhysicalBody)
1034 {
1035 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
1036 }
1037 else
1038 {
1039 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
1040 DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
1041 }
1042 }
1043
1044 // prims don't fly
1045 public override bool Flying {
1046 get { return _flying; }
1047 set {
1048 _flying = value;
1049 }
1050 }
1051 public override bool SetAlwaysRun {
1052 get { return _setAlwaysRun; }
1053 set { _setAlwaysRun = value; }
1054 }
1055 public override bool ThrottleUpdates {
1056 get { return _throttleUpdates; }
1057 set { _throttleUpdates = value; }
1058 }
1059 public bool IsPhantom {
1060 get {
1061 // SceneObjectPart removes phantom objects from the physics scene
1062 // so, although we could implement touching and such, we never
1063 // are invoked as a phantom object
1064 return false;
1065 }
1066 }
1067 public override bool FloatOnWater {
1068 set {
1069 _floatOnWater = value;
1070 PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
1071 {
1072 if (_floatOnWater)
1073 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1074 else
1075 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1076 });
1077 }
1078 }
1079 public override OMV.Vector3 RotationalVelocity {
1080 get {
1081 return _rotationalVelocity;
1082 }
1083 set {
1084 _rotationalVelocity = value;
1085 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1086 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1087 PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
1088 {
1089 ForceRotationalVelocity = _rotationalVelocity;
1090 });
1091 }
1092 }
1093 public override OMV.Vector3 ForceRotationalVelocity {
1094 get {
1095 return _rotationalVelocity;
1096 }
1097 set {
1098 _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
1099 if (PhysBody.HasPhysicalBody)
1100 {
1101 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1102 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1103 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1104 ActivateIfPhysical(false);
1105 }
1106 }
1107 }
1108 public override bool Kinematic {
1109 get { return _kinematic; }
1110 set { _kinematic = value;
1111 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
1112 }
1113 }
1114 public override float Buoyancy {
1115 get { return _buoyancy; }
1116 set {
1117 _buoyancy = value;
1118 PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
1119 {
1120 ForceBuoyancy = _buoyancy;
1121 });
1122 }
1123 }
1124 public override float ForceBuoyancy {
1125 get { return _buoyancy; }
1126 set {
1127 _buoyancy = value;
1128 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
1129 // Force the recalculation of the various inertia,etc variables in the object
1130 UpdatePhysicalMassProperties(RawMass, true);
1131 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
1132 ActivateIfPhysical(false);
1133 }
1134 }
1135
1136 public override bool PIDActive
1137 {
1138 get
1139 {
1140 return MoveToTargetActive;
1141 }
1142
1143 set
1144 {
1145 MoveToTargetActive = value;
1146
1147 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1148 {
1149 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1150 });
1151
1152 // Call update so actor Refresh() is called to start things off
1153 PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate()
1154 {
1155 UpdatePhysicalParameters();
1156 });
1157 }
1158 }
1159
1160 public override OMV.Vector3 PIDTarget
1161 {
1162 set
1163 {
1164 base.PIDTarget = value;
1165 BSActor actor;
1166 if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
1167 {
1168 // if the actor exists, tell it to refresh its values.
1169 actor.Refresh();
1170 }
1171
1172 }
1173 }
1174 // Used for llSetHoverHeight and maybe vehicle height
1175 // Hover Height will override MoveTo target's Z
1176 public override bool PIDHoverActive {
1177 set {
1178 base.HoverActive = value;
1179 EnableActor(HoverActive, HoverActorName, delegate()
1180 {
1181 return new BSActorHover(PhysScene, this, HoverActorName);
1182 });
1183
1184 // Call update so actor Refresh() is called to start things off
1185 PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate()
1186 {
1187 UpdatePhysicalParameters();
1188 });
1189 }
1190 }
1191
1192 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1193 // Per documentation, max force is limited.
1194 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1195
1196 // Since this force is being applied in only one step, make this a force per second.
1197 addForce /= PhysScene.LastTimeStep;
1198 AddForce(addForce, pushforce, false /* inTaintTime */);
1199 }
1200
1201 // Applying a force just adds this to the total force on the object.
1202 // This added force will only last the next simulation tick.
1203 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1204 // for an object, doesn't matter if force is a pushforce or not
1205 if (IsPhysicallyActive)
1206 {
1207 if (force.IsFinite())
1208 {
1209 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1210
1211 OMV.Vector3 addForce = force;
1212 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
1213 {
1214 // Bullet adds this central force to the total force for this tick.
1215 // Deep down in Bullet:
1216 // linearVelocity += totalForce / mass * timeStep;
1217 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1218 if (PhysBody.HasPhysicalBody)
1219 {
1220 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1221 ActivateIfPhysical(false);
1222 }
1223 });
1224 }
1225 else
1226 {
1227 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1228 return;
1229 }
1230 }
1231 }
1232
1233 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
1234 // for an object, doesn't matter if force is a pushforce or not
1235 if (!IsPhysicallyActive)
1236 {
1237 if (impulse.IsFinite())
1238 {
1239 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1240 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1241
1242 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
1243 {
1244 // Bullet adds this impulse immediately to the velocity
1245 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1246 if (PhysBody.HasPhysicalBody)
1247 {
1248 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1249 ActivateIfPhysical(false);
1250 }
1251 });
1252 }
1253 else
1254 {
1255 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1256 return;
1257 }
1258 }
1259 }
1260
1261 // BSPhysObject.AddAngularForce()
1262 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1263 {
1264 if (force.IsFinite())
1265 {
1266 OMV.Vector3 angForce = force;
1267 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
1268 {
1269 if (PhysBody.HasPhysicalBody)
1270 {
1271 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1272 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1273 ActivateIfPhysical(false);
1274 }
1275 });
1276 }
1277 else
1278 {
1279 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1280 return;
1281 }
1282 }
1283
1284 // A torque impulse.
1285 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1286 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1287 // Computed as: angularVelocity += impulse * inertia;
1288 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1289 {
1290 OMV.Vector3 applyImpulse = impulse;
1291 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
1292 {
1293 if (PhysBody.HasPhysicalBody)
1294 {
1295 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1296 ActivateIfPhysical(false);
1297 }
1298 });
1299 }
1300
1301 public override void SetMomentum(OMV.Vector3 momentum) {
1302 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1303 }
1304 #region Mass Calculation
1305
1306 private float CalculateMass()
1307 {
1308 float volume = _size.X * _size.Y * _size.Z; // default
1309 float tmp;
1310
1311 float returnMass = 0;
1312 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1313 float hollowVolume = hollowAmount * hollowAmount;
1314
1315 switch (BaseShape.ProfileShape)
1316 {
1317 case ProfileShape.Square:
1318 // default box
1319
1320 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1321 {
1322 if (hollowAmount > 0.0)
1323 {
1324 switch (BaseShape.HollowShape)
1325 {
1326 case HollowShape.Square:
1327 case HollowShape.Same:
1328 break;
1329
1330 case HollowShape.Circle:
1331
1332 hollowVolume *= 0.78539816339f;
1333 break;
1334
1335 case HollowShape.Triangle:
1336
1337 hollowVolume *= (0.5f * .5f);
1338 break;
1339
1340 default:
1341 hollowVolume = 0;
1342 break;
1343 }
1344 volume *= (1.0f - hollowVolume);
1345 }
1346 }
1347
1348 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1349 {
1350 //a tube
1351
1352 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1353 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1354 volume -= volume*tmp*tmp;
1355
1356 if (hollowAmount > 0.0)
1357 {
1358 hollowVolume *= hollowAmount;
1359
1360 switch (BaseShape.HollowShape)
1361 {
1362 case HollowShape.Square:
1363 case HollowShape.Same:
1364 break;
1365
1366 case HollowShape.Circle:
1367 hollowVolume *= 0.78539816339f;;
1368 break;
1369
1370 case HollowShape.Triangle:
1371 hollowVolume *= 0.5f * 0.5f;
1372 break;
1373 default:
1374 hollowVolume = 0;
1375 break;
1376 }
1377 volume *= (1.0f - hollowVolume);
1378 }
1379 }
1380
1381 break;
1382
1383 case ProfileShape.Circle:
1384
1385 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1386 {
1387 volume *= 0.78539816339f; // elipse base
1388
1389 if (hollowAmount > 0.0)
1390 {
1391 switch (BaseShape.HollowShape)
1392 {
1393 case HollowShape.Same:
1394 case HollowShape.Circle:
1395 break;
1396
1397 case HollowShape.Square:
1398 hollowVolume *= 0.5f * 2.5984480504799f;
1399 break;
1400
1401 case HollowShape.Triangle:
1402 hollowVolume *= .5f * 1.27323954473516f;
1403 break;
1404
1405 default:
1406 hollowVolume = 0;
1407 break;
1408 }
1409 volume *= (1.0f - hollowVolume);
1410 }
1411 }
1412
1413 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1414 {
1415 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1416 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1417 volume *= (1.0f - tmp * tmp);
1418
1419 if (hollowAmount > 0.0)
1420 {
1421
1422 // calculate the hollow volume by it's shape compared to the prim shape
1423 hollowVolume *= hollowAmount;
1424
1425 switch (BaseShape.HollowShape)
1426 {
1427 case HollowShape.Same:
1428 case HollowShape.Circle:
1429 break;
1430
1431 case HollowShape.Square:
1432 hollowVolume *= 0.5f * 2.5984480504799f;
1433 break;
1434
1435 case HollowShape.Triangle:
1436 hollowVolume *= .5f * 1.27323954473516f;
1437 break;
1438
1439 default:
1440 hollowVolume = 0;
1441 break;
1442 }
1443 volume *= (1.0f - hollowVolume);
1444 }
1445 }
1446 break;
1447
1448 case ProfileShape.HalfCircle:
1449 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1450 {
1451 volume *= 0.52359877559829887307710723054658f;
1452 }
1453 break;
1454
1455 case ProfileShape.EquilateralTriangle:
1456
1457 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1458 {
1459 volume *= 0.32475953f;
1460
1461 if (hollowAmount > 0.0)
1462 {
1463
1464 // calculate the hollow volume by it's shape compared to the prim shape
1465 switch (BaseShape.HollowShape)
1466 {
1467 case HollowShape.Same:
1468 case HollowShape.Triangle:
1469 hollowVolume *= .25f;
1470 break;
1471
1472 case HollowShape.Square:
1473 hollowVolume *= 0.499849f * 3.07920140172638f;
1474 break;
1475
1476 case HollowShape.Circle:
1477 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1478 // Cyllinder hollow volume calculation
1479
1480 hollowVolume *= 0.1963495f * 3.07920140172638f;
1481 break;
1482
1483 default:
1484 hollowVolume = 0;
1485 break;
1486 }
1487 volume *= (1.0f - hollowVolume);
1488 }
1489 }
1490 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1491 {
1492 volume *= 0.32475953f;
1493 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1494 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1495 volume *= (1.0f - tmp * tmp);
1496
1497 if (hollowAmount > 0.0)
1498 {
1499
1500 hollowVolume *= hollowAmount;
1501
1502 switch (BaseShape.HollowShape)
1503 {
1504 case HollowShape.Same:
1505 case HollowShape.Triangle:
1506 hollowVolume *= .25f;
1507 break;
1508
1509 case HollowShape.Square:
1510 hollowVolume *= 0.499849f * 3.07920140172638f;
1511 break;
1512
1513 case HollowShape.Circle:
1514
1515 hollowVolume *= 0.1963495f * 3.07920140172638f;
1516 break;
1517
1518 default:
1519 hollowVolume = 0;
1520 break;
1521 }
1522 volume *= (1.0f - hollowVolume);
1523 }
1524 }
1525 break;
1526
1527 default:
1528 break;
1529 }
1530
1531
1532
1533 float taperX1;
1534 float taperY1;
1535 float taperX;
1536 float taperY;
1537 float pathBegin;
1538 float pathEnd;
1539 float profileBegin;
1540 float profileEnd;
1541
1542 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1543 {
1544 taperX1 = BaseShape.PathScaleX * 0.01f;
1545 if (taperX1 > 1.0f)
1546 taperX1 = 2.0f - taperX1;
1547 taperX = 1.0f - taperX1;
1548
1549 taperY1 = BaseShape.PathScaleY * 0.01f;
1550 if (taperY1 > 1.0f)
1551 taperY1 = 2.0f - taperY1;
1552 taperY = 1.0f - taperY1;
1553 }
1554 else
1555 {
1556 taperX = BaseShape.PathTaperX * 0.01f;
1557 if (taperX < 0.0f)
1558 taperX = -taperX;
1559 taperX1 = 1.0f - taperX;
1560
1561 taperY = BaseShape.PathTaperY * 0.01f;
1562 if (taperY < 0.0f)
1563 taperY = -taperY;
1564 taperY1 = 1.0f - taperY;
1565
1566 }
1567
1568
1569 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1570
1571 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1572 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1573 volume *= (pathEnd - pathBegin);
1574
1575 // this is crude aproximation
1576 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1577 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1578 volume *= (profileEnd - profileBegin);
1579
1580 returnMass = Density * BSParam.DensityScaleFactor * volume;
1581
1582 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1583 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1584 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
1585 LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
1586
1587 return returnMass;
1588 }// end CalculateMass
1589 #endregion Mass Calculation
1590
1591 // Rebuild the geometry and object.
1592 // This is called when the shape changes so we need to recreate the mesh/hull.
1593 // Called at taint-time!!!
1594 public void CreateGeomAndObject(bool forceRebuild)
1595 {
1596 // Create the correct physical representation for this type of object.
1597 // Updates base.PhysBody and base.PhysShape with the new information.
1598 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1599 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1600 {
1601 // Called if the current prim body is about to be destroyed.
1602 // Remove all the physical dependencies on the old body.
1603 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1604 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1605 RemoveDependencies();
1606 });
1607
1608 // Make sure the properties are set on the new object
1609 UpdatePhysicalParameters();
1610 return;
1611 }
1612
1613 // Called at taint-time
1614 protected virtual void RemoveDependencies()
1615 {
1616 PhysicalActors.RemoveDependencies();
1617 }
1618
1619 #region Extension
1620 public override object Extension(string pFunct, params object[] pParams)
1621 {
1622 DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
1623 object ret = null;
1624 switch (pFunct)
1625 {
1626 case ExtendedPhysics.PhysFunctAxisLockLimits:
1627 ret = SetAxisLockLimitsExtension(pParams);
1628 break;
1629 default:
1630 ret = base.Extension(pFunct, pParams);
1631 break;
1632 }
1633 return ret;
1634 }
1635
1636 private void InitializeAxisActor()
1637 {
1638 EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree,
1639 LockedAxisActorName, delegate()
1640 {
1641 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
1642 });
1643
1644 // Update parameters so the new actor's Refresh() action is called at the right time.
1645 PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate()
1646 {
1647 UpdatePhysicalParameters();
1648 });
1649 }
1650
1651 // Passed an array of an array of parameters, set the axis locking.
1652 // This expects an int (PHYS_AXIS_*) followed by none or two limit floats
1653 // followed by another int and floats, etc.
1654 private object SetAxisLockLimitsExtension(object[] pParams)
1655 {
1656 DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0));
1657 object ret = null;
1658 try
1659 {
1660 if (pParams.GetLength(0) > 1)
1661 {
1662 int index = 2;
1663 while (index < pParams.GetLength(0))
1664 {
1665 var funct = pParams[index];
1666 DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index);
1667 if (funct is Int32 || funct is Int64)
1668 {
1669 switch ((int)funct)
1670 {
1671 // Those that take no parameters
1672 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1673 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1674 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1675 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1676 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1677 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1678 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1679 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1680 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1681 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1682 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1683 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1684 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1685 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1686 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1687 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1688 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1689 ApplyAxisLimits((int)funct, 0f, 0f);
1690 index += 1;
1691 break;
1692 // Those that take two parameters (the limits)
1693 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1694 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1695 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1696 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1697 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1698 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1699 ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]);
1700 index += 3;
1701 break;
1702 default:
1703 m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct);
1704 index += 1;
1705 break;
1706 }
1707 }
1708 }
1709 InitializeAxisActor();
1710 ret = (object)index;
1711 }
1712 }
1713 catch (Exception e)
1714 {
1715 m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e);
1716 ret = null;
1717 }
1718 return ret; // not implemented yet
1719 }
1720
1721 // Set the locking parameters.
1722 // If an axis is locked, the limits for the axis are set to zero,
1723 // If the axis is being constrained, the high and low value are passed and set.
1724 // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range.
1725 protected void ApplyAxisLimits(int funct, float low, float high)
1726 {
1727 DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high);
1728 float linearMax = 23000f;
1729 float angularMax = (float)Math.PI;
1730
1731 switch (funct)
1732 {
1733 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1734 this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1735 this.LockedLinearAxisLow = OMV.Vector3.Zero;
1736 this.LockedLinearAxisHigh = OMV.Vector3.Zero;
1737 break;
1738 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1739 this.LockedLinearAxis.X = LockedAxis;
1740 this.LockedLinearAxisLow.X = 0f;
1741 this.LockedLinearAxisHigh.X = 0f;
1742 break;
1743 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1744 this.LockedLinearAxis.X = LockedAxis;
1745 this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax);
1746 this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax);
1747 break;
1748 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1749 this.LockedLinearAxis.Y = LockedAxis;
1750 this.LockedLinearAxisLow.Y = 0f;
1751 this.LockedLinearAxisHigh.Y = 0f;
1752 break;
1753 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1754 this.LockedLinearAxis.Y = LockedAxis;
1755 this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax);
1756 this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax);
1757 break;
1758 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1759 this.LockedLinearAxis.Z = LockedAxis;
1760 this.LockedLinearAxisLow.Z = 0f;
1761 this.LockedLinearAxisHigh.Z = 0f;
1762 break;
1763 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1764 this.LockedLinearAxis.Z = LockedAxis;
1765 this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax);
1766 this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax);
1767 break;
1768 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1769 this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1770 this.LockedAngularAxisLow = OMV.Vector3.Zero;
1771 this.LockedAngularAxisHigh = OMV.Vector3.Zero;
1772 break;
1773 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1774 this.LockedAngularAxis.X = LockedAxis;
1775 this.LockedAngularAxisLow.X = 0;
1776 this.LockedAngularAxisHigh.X = 0;
1777 break;
1778 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1779 this.LockedAngularAxis.X = LockedAxis;
1780 this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax);
1781 this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax);
1782 break;
1783 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1784 this.LockedAngularAxis.Y = LockedAxis;
1785 this.LockedAngularAxisLow.Y = 0;
1786 this.LockedAngularAxisHigh.Y = 0;
1787 break;
1788 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1789 this.LockedAngularAxis.Y = LockedAxis;
1790 this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax);
1791 this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax);
1792 break;
1793 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1794 this.LockedAngularAxis.Z = LockedAxis;
1795 this.LockedAngularAxisLow.Z = 0;
1796 this.LockedAngularAxisHigh.Z = 0;
1797 break;
1798 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1799 this.LockedAngularAxis.Z = LockedAxis;
1800 this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax);
1801 this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax);
1802 break;
1803 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1804 this.LockedLinearAxis = LockedAxisFree;
1805 this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax);
1806 this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax);
1807 break;
1808 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1809 this.LockedLinearAxis.X = FreeAxis;
1810 this.LockedLinearAxisLow.X = -linearMax;
1811 this.LockedLinearAxisHigh.X = linearMax;
1812 break;
1813 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1814 this.LockedLinearAxis.Y = FreeAxis;
1815 this.LockedLinearAxisLow.Y = -linearMax;
1816 this.LockedLinearAxisHigh.Y = linearMax;
1817 break;
1818 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1819 this.LockedLinearAxis.Z = FreeAxis;
1820 this.LockedLinearAxisLow.Z = -linearMax;
1821 this.LockedLinearAxisHigh.Z = linearMax;
1822 break;
1823 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1824 this.LockedAngularAxis = LockedAxisFree;
1825 this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax);
1826 this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax);
1827 break;
1828 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1829 this.LockedAngularAxis.X = FreeAxis;
1830 this.LockedAngularAxisLow.X = -angularMax;
1831 this.LockedAngularAxisHigh.X = angularMax;
1832 break;
1833 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1834 this.LockedAngularAxis.Y = FreeAxis;
1835 this.LockedAngularAxisLow.Y = -angularMax;
1836 this.LockedAngularAxisHigh.Y = angularMax;
1837 break;
1838 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1839 this.LockedAngularAxis.Z = FreeAxis;
1840 this.LockedAngularAxisLow.Z = -angularMax;
1841 this.LockedAngularAxisHigh.Z = angularMax;
1842 break;
1843 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1844 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f);
1845 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
1846 break;
1847 default:
1848 break;
1849 }
1850 return;
1851 }
1852 #endregion // Extension
1853
1854 // The physics engine says that properties have updated. Update same and inform
1855 // the world that things have changed.
1856 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
1857 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
1858 public override void UpdateProperties(EntityProperties entprop)
1859 {
1860 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1861 TriggerPreUpdatePropertyAction(ref entprop);
1862
1863 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1864
1865 // Assign directly to the local variables so the normal set actions do not happen
1866 RawPosition = entprop.Position;
1867 RawOrientation = entprop.Rotation;
1868 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1869 // very sensitive to velocity changes.
1870 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1871 RawVelocity = entprop.Velocity;
1872 _acceleration = entprop.Acceleration;
1873 _rotationalVelocity = entprop.RotationalVelocity;
1874
1875 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1876
1877 // The sanity check can change the velocity and/or position.
1878 if (PositionSanityCheck(true /* inTaintTime */ ))
1879 {
1880 entprop.Position = RawPosition;
1881 entprop.Velocity = RawVelocity;
1882 entprop.RotationalVelocity = _rotationalVelocity;
1883 entprop.Acceleration = _acceleration;
1884 }
1885
1886 OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
1887 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1888
1889 // remember the current and last set values
1890 LastEntityProperties = CurrentEntityProperties;
1891 CurrentEntityProperties = entprop;
1892
1893 PhysScene.PostUpdate(this);
1894 }
1895}
1896}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
new file mode 100755
index 0000000..2eb1440
--- /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.Physics.Manager;
35
36using OMV = OpenMetaverse;
37
38namespace OpenSim.Region.Physics.BulletSPlugin
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..430d645
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
@@ -0,0 +1,350 @@
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;
33using OpenSim.Region.OptionalModules.Scripting;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSPrimLinkable : BSPrimDisplaced
40{
41 // The purpose of this subclass is to add linkset functionality to the prim. This overrides
42 // operations necessary for keeping the linkset created and, additionally, this
43 // calls the linkset implementation for its creation and management.
44
45#pragma warning disable 414
46 private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]";
47#pragma warning restore 414
48
49 // This adds the overrides for link() and delink() so the prim is linkable.
50
51 public BSLinkset Linkset { get; set; }
52 // The index of this child prim.
53 public int LinksetChildIndex { get; set; }
54
55 public BSLinkset.LinksetImplementation LinksetType { get; set; }
56
57 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
58 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
59 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
60 {
61 // Default linkset implementation for this prim
62 LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation;
63
64 Linkset = BSLinkset.Factory(PhysScene, this);
65
66 Linkset.Refresh(this);
67 }
68
69 public override void Destroy()
70 {
71 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */);
72 base.Destroy();
73 }
74
75 public override void link(Manager.PhysicsActor obj)
76 {
77 BSPrimLinkable parent = obj as BSPrimLinkable;
78 if (parent != null)
79 {
80 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
81 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
82
83 Linkset = parent.Linkset.AddMeToLinkset(this);
84
85 DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
86 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
87 }
88 return;
89 }
90
91 public override void delink()
92 {
93 // TODO: decide if this parent checking needs to happen at taint time
94 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
95
96 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
97 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
98
99 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/);
100
101 DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
102 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
103 return;
104 }
105
106 // When simulator changes position, this might be moving a child of the linkset.
107 public override OMV.Vector3 Position
108 {
109 get { return base.Position; }
110 set
111 {
112 base.Position = value;
113 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate()
114 {
115 Linkset.UpdateProperties(UpdatedProperties.Position, this);
116 });
117 }
118 }
119
120 // When simulator changes orientation, this might be moving a child of the linkset.
121 public override OMV.Quaternion Orientation
122 {
123 get { return base.Orientation; }
124 set
125 {
126 base.Orientation = value;
127 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate()
128 {
129 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
130 });
131 }
132 }
133
134 public override float TotalMass
135 {
136 get { return Linkset.LinksetMass; }
137 }
138
139 public override OMV.Vector3 CenterOfMass
140 {
141 get { return Linkset.CenterOfMass; }
142 }
143
144 public override OMV.Vector3 GeometricCenter
145 {
146 get { return Linkset.GeometricCenter; }
147 }
148
149 // Refresh the linkset structure and parameters when the prim's physical parameters are changed.
150 public override void UpdatePhysicalParameters()
151 {
152 base.UpdatePhysicalParameters();
153 // Recompute any linkset parameters.
154 // When going from non-physical to physical, this re-enables the constraints that
155 // had been automatically disabled when the mass was set to zero.
156 // For compound based linksets, this enables and disables interactions of the children.
157 if (Linkset != null) // null can happen during initialization
158 Linkset.Refresh(this);
159 }
160
161 // When the prim is made dynamic or static, the linkset needs to change.
162 protected override void MakeDynamic(bool makeStatic)
163 {
164 base.MakeDynamic(makeStatic);
165 if (Linkset != null) // null can happen during initialization
166 {
167 if (makeStatic)
168 Linkset.MakeStatic(this);
169 else
170 Linkset.MakeDynamic(this);
171 }
172 }
173
174 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
175 protected override void RemoveDependencies()
176 {
177 Linkset.RemoveDependencies(this);
178 base.RemoveDependencies();
179 }
180
181 // Called after a simulation step for the changes in physical object properties.
182 // Do any filtering/modification needed for linksets.
183 public override void UpdateProperties(EntityProperties entprop)
184 {
185 if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this))
186 {
187 // Properties are only updated for the roots of a linkset.
188 // TODO: this will have to change when linksets are articulated.
189 base.UpdateProperties(entprop);
190 }
191 /*
192 else
193 {
194 // For debugging, report the movement of children
195 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
196 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
197 entprop.Acceleration, entprop.RotationalVelocity);
198 }
199 */
200 // The linkset might like to know about changing locations
201 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
202 }
203
204 // Called after a simulation step to post a collision with this object.
205 // This returns 'true' if the collision has been queued and the SendCollisions call must
206 // be made at the end of the simulation step.
207 public override bool Collide(uint collidingWith, BSPhysObject collidee,
208 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
209 {
210 bool ret = false;
211 // Ask the linkset if it wants to handle the collision
212 if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth))
213 {
214 // The linkset didn't handle it so pass the collision through normal processing
215 ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
216 }
217 return ret;
218 }
219
220 // A linkset reports any collision on any part of the linkset.
221 public long SomeCollisionSimulationStep = 0;
222 public override bool HasSomeCollision
223 {
224 get
225 {
226 return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding;
227 }
228 set
229 {
230 if (value)
231 SomeCollisionSimulationStep = PhysScene.SimulationStep;
232 else
233 SomeCollisionSimulationStep = 0;
234
235 base.HasSomeCollision = value;
236 }
237 }
238
239 // Convert the existing linkset of this prim into a new type.
240 public bool ConvertLinkset(BSLinkset.LinksetImplementation newType)
241 {
242 bool ret = false;
243 if (LinksetType != newType)
244 {
245 DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType);
246
247 // Set the implementation type first so the call to BSLinkset.Factory gets the new type.
248 this.LinksetType = newType;
249
250 BSLinkset oldLinkset = this.Linkset;
251 BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this);
252
253 this.Linkset = newLinkset;
254
255 // Pick up any physical dependencies this linkset might have in the physics engine.
256 oldLinkset.RemoveDependencies(this);
257
258 // Create a list of the children (mainly because can't interate through a list that's changing)
259 List<BSPrimLinkable> children = new List<BSPrimLinkable>();
260 oldLinkset.ForEachMember((child) =>
261 {
262 if (!oldLinkset.IsRoot(child))
263 children.Add(child);
264 return false; // 'false' says to continue to next member
265 });
266
267 // Remove the children from the old linkset and add to the new (will be a new instance from the factory)
268 foreach (BSPrimLinkable child in children)
269 {
270 oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/);
271 }
272 foreach (BSPrimLinkable child in children)
273 {
274 newLinkset.AddMeToLinkset(child);
275 child.Linkset = newLinkset;
276 }
277
278 // Force the shape and linkset to get reconstructed
279 newLinkset.Refresh(this);
280 this.ForceBodyShapeRebuild(true /* inTaintTime */);
281 }
282 return ret;
283 }
284
285 #region Extension
286 public override object Extension(string pFunct, params object[] pParams)
287 {
288 DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length);
289 object ret = null;
290 switch (pFunct)
291 {
292 // physGetLinksetType();
293 // pParams = [ BSPhysObject root, null ]
294 case ExtendedPhysics.PhysFunctGetLinksetType:
295 {
296 ret = (object)LinksetType;
297 DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret);
298 break;
299 }
300 // physSetLinksetType(type);
301 // pParams = [ BSPhysObject root, null, integer type ]
302 case ExtendedPhysics.PhysFunctSetLinksetType:
303 {
304 if (pParams.Length > 2)
305 {
306 BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2];
307 if (Linkset.IsRoot(this))
308 {
309 PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate()
310 {
311 // Cause the linkset type to change
312 DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}",
313 LocalID, Linkset.LinksetImpl, linksetType);
314 ConvertLinkset(linksetType);
315 });
316 }
317 ret = (object)(int)linksetType;
318 }
319 break;
320 }
321 // physChangeLinkType(linknum, typeCode);
322 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
323 case ExtendedPhysics.PhysFunctChangeLinkType:
324 {
325 ret = Linkset.Extension(pFunct, pParams);
326 break;
327 }
328 // physGetLinkType(linknum);
329 // pParams = [ BSPhysObject root, BSPhysObject child ]
330 case ExtendedPhysics.PhysFunctGetLinkType:
331 {
332 ret = Linkset.Extension(pFunct, pParams);
333 break;
334 }
335 // physChangeLinkParams(linknum, [code, value, code, value, ...]);
336 // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ]
337 case ExtendedPhysics.PhysFunctChangeLinkParams:
338 {
339 ret = Linkset.Extension(pFunct, pParams);
340 break;
341 }
342 default:
343 ret = base.Extension(pFunct, pParams);
344 break;
345 }
346 return ret;
347 }
348 #endregion // Extension
349}
350}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
new file mode 100644
index 0000000..8a19944
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
@@ -0,0 +1,1281 @@
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;
37using OpenSim.Region.CoreModules;
38using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
39using OpenSim.Region.Physics.Manager;
40using Nini.Config;
41using log4net;
42using OpenMetaverse;
43
44namespace OpenSim.Region.Physics.BulletSPlugin
45{
46public sealed class BSScene : PhysicsScene, IPhysicsParameters
47{
48 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
49 internal static readonly string LogHeader = "[BULLETS SCENE]";
50
51 // The name of the region we're working for.
52 public string RegionName { get; private set; }
53
54 public string BulletSimVersion = "?";
55
56 // The handle to the underlying managed or unmanaged version of Bullet being used.
57 public string BulletEngineName { get; private set; }
58 public BSAPITemplate PE;
59
60 // If the physics engine is running on a separate thread
61 public Thread m_physicsThread;
62
63 public Dictionary<uint, BSPhysObject> PhysObjects;
64 public BSShapeCollection Shapes;
65
66 // Keeping track of the objects with collisions so we can report begin and end of a collision
67 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
68 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
69
70 // All the collision processing is protected with this lock object
71 public Object CollisionLock = new Object();
72
73 // Properties are updated here
74 public Object UpdateLock = new Object();
75 public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>();
76
77 // Keep track of all the avatars so we can send them a collision event
78 // every tick so OpenSim will update its animation.
79 private HashSet<BSPhysObject> AvatarsInScene = new HashSet<BSPhysObject>();
80 private Object AvatarsInSceneLock = new Object();
81
82 // let my minuions use my logger
83 public ILog Logger { get { return m_log; } }
84
85 public IMesher mesher;
86 public uint WorldID { get; private set; }
87 public BulletWorld World { get; private set; }
88
89 // All the constraints that have been allocated in this instance.
90 public BSConstraintCollection Constraints { get; private set; }
91
92 // Simulation parameters
93 //internal float m_physicsStepTime; // if running independently, the interval simulated by default
94
95 internal int m_maxSubSteps;
96 internal float m_fixedTimeStep;
97
98 internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc.
99
100 internal long m_simulationStep = 0; // The current simulation step.
101 public long SimulationStep { get { return m_simulationStep; } }
102 // A number to use for SimulationStep that is probably not any step value
103 // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step.
104 public static long NotASimulationStep = -1234;
105
106 internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate()
107
108 internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to
109
110 // Physical objects can register for prestep or poststep events
111 public delegate void PreStepAction(float timeStep);
112 public delegate void PostStepAction(float timeStep);
113 public event PreStepAction BeforeStep;
114 public event PostStepAction AfterStep;
115
116 // A value of the time 'now' so all the collision and update routines do not have to get their own
117 // Set to 'now' just before all the prims and actors are called for collisions and updates
118 public int SimulationNowTime { get; private set; }
119
120 // True if initialized and ready to do simulation steps
121 private bool m_initialized = false;
122
123 // Flag which is true when processing taints.
124 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
125 public bool InTaintTime { get; private set; }
126
127 // Pinned memory used to pass step information between managed and unmanaged
128 internal int m_maxCollisionsPerFrame;
129 internal CollisionDesc[] m_collisionArray;
130
131 internal int m_maxUpdatesPerFrame;
132 internal EntityProperties[] m_updateArray;
133
134 /// <summary>
135 /// Used to control physics simulation timing if Bullet is running on its own thread.
136 /// </summary>
137 private ManualResetEvent m_updateWaitEvent;
138
139 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
140 public const uint GROUNDPLANE_ID = 1;
141 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
142
143 public float SimpleWaterLevel { get; set; }
144 public BSTerrainManager TerrainManager { get; private set; }
145
146 public ConfigurationParameters Params
147 {
148 get { return UnmanagedParams[0]; }
149 }
150 public Vector3 DefaultGravity
151 {
152 get { return new Vector3(0f, 0f, Params.gravity); }
153 }
154 // Just the Z value of the gravity
155 public float DefaultGravityZ
156 {
157 get { return Params.gravity; }
158 }
159
160 // When functions in the unmanaged code must be called, it is only
161 // done at a known time just before the simulation step. The taint
162 // system saves all these function calls and executes them in
163 // order before the simulation.
164 public delegate void TaintCallback();
165 private struct TaintCallbackEntry
166 {
167 public String originator;
168 public String ident;
169 public TaintCallback callback;
170 public TaintCallbackEntry(string pIdent, TaintCallback pCallBack)
171 {
172 originator = BSScene.DetailLogZero;
173 ident = pIdent;
174 callback = pCallBack;
175 }
176 public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack)
177 {
178 originator = pOrigin;
179 ident = pIdent;
180 callback = pCallBack;
181 }
182 }
183 private Object _taintLock = new Object(); // lock for using the next object
184 private List<TaintCallbackEntry> _taintOperations;
185 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
186 private List<TaintCallbackEntry> _postStepOperations;
187
188 // A pointer to an instance if this structure is passed to the C++ code
189 // Used to pass basic configuration values to the unmanaged code.
190 internal ConfigurationParameters[] UnmanagedParams;
191
192 // Sometimes you just have to log everything.
193 public Logging.LogWriter PhysicsLogging;
194 private bool m_physicsLoggingEnabled;
195 private string m_physicsLoggingDir;
196 private string m_physicsLoggingPrefix;
197 private int m_physicsLoggingFileMinutes;
198 private bool m_physicsLoggingDoFlush;
199 private bool m_physicsPhysicalDumpEnabled;
200 public int PhysicsMetricDumpFrames { get; set; }
201 // 'true' of the vehicle code is to log lots of details
202 public bool VehicleLoggingEnabled { get; private set; }
203 public bool VehiclePhysicalLoggingEnabled { get; private set; }
204
205 #region Construction and Initialization
206 public BSScene(string engineType, string identifier)
207 {
208 m_initialized = false;
209
210 // The name of the region we're working for is passed to us. Keep for identification.
211 RegionName = identifier;
212
213 // Set identifying variables in the PhysicsScene interface.
214 EngineType = engineType;
215 Name = EngineType + "/" + RegionName;
216 }
217
218 // Old version of initialization that assumes legacy sized regions (256x256)
219 public override void Initialise(IMesher meshmerizer, IConfigSource config)
220 {
221 m_log.ErrorFormat("{0} WARNING WARNING WARNING! BulletSim initialized without region extent specification. Terrain will be messed up.");
222 Vector3 regionExtent = new Vector3( Constants.RegionSize, Constants.RegionSize, Constants.RegionSize);
223 Initialise(meshmerizer, config, regionExtent);
224
225 }
226
227 public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
228 {
229 mesher = meshmerizer;
230 _taintOperations = new List<TaintCallbackEntry>();
231 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
232 _postStepOperations = new List<TaintCallbackEntry>();
233 PhysObjects = new Dictionary<uint, BSPhysObject>();
234 Shapes = new BSShapeCollection(this);
235
236 m_simulatedTime = 0f;
237 LastTimeStep = 0.1f;
238
239 // Allocate pinned memory to pass parameters.
240 UnmanagedParams = new ConfigurationParameters[1];
241
242 // Set default values for physics parameters plus any overrides from the ini file
243 GetInitialParameterValues(config);
244
245 // Force some parameters to values depending on other configurations
246 // Only use heightmap terrain implementation if terrain larger than legacy size
247 if ((uint)regionExtent.X > Constants.RegionSize || (uint)regionExtent.Y > Constants.RegionSize)
248 {
249 m_log.WarnFormat("{0} Forcing terrain implementation to heightmap for large region", LogHeader);
250 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
251 }
252
253 // Get the connection to the physics engine (could be native or one of many DLLs)
254 PE = SelectUnderlyingBulletEngine(BulletEngineName);
255
256 // Enable very detailed logging.
257 // By creating an empty logger when not logging, the log message invocation code
258 // can be left in and every call doesn't have to check for null.
259 if (m_physicsLoggingEnabled)
260 {
261 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush);
262 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages.
263 }
264 else
265 {
266 PhysicsLogging = new Logging.LogWriter();
267 }
268
269 // Allocate memory for returning of the updates and collisions from the physics engine
270 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
271 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
272
273 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
274 // a child in a mega-region.
275 // Bullet actually doesn't care about the extents of the simulated
276 // area. It tracks active objects no matter where they are.
277 Vector3 worldExtent = regionExtent;
278
279 World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
280
281 Constraints = new BSConstraintCollection(World);
282
283 TerrainManager = new BSTerrainManager(this, worldExtent);
284 TerrainManager.CreateInitialGroundPlaneAndTerrain();
285
286 // Put some informational messages into the log file.
287 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
288
289 InTaintTime = false;
290 m_initialized = true;
291
292 // If the physics engine runs on its own thread, start same.
293 if (BSParam.UseSeparatePhysicsThread)
294 {
295 // The physics simulation should happen independently of the heartbeat loop
296 m_physicsThread
297 = WorkManager.StartThread(
298 BulletSPluginPhysicsThread,
299 string.Format("{0} ({1})", BulletEngineName, RegionName),
300 ThreadPriority.Normal,
301 true,
302 true);
303 }
304 }
305
306 // All default parameter values are set here. There should be no values set in the
307 // variable definitions.
308 private void GetInitialParameterValues(IConfigSource config)
309 {
310 ConfigurationParameters parms = new ConfigurationParameters();
311 UnmanagedParams[0] = parms;
312
313 BSParam.SetParameterDefaultValues(this);
314
315 if (config != null)
316 {
317 // If there are specifications in the ini file, use those values
318 IConfig pConfig = config.Configs["BulletSim"];
319 if (pConfig != null)
320 {
321 BSParam.SetParameterConfigurationValues(this, pConfig);
322
323 // There are two Bullet implementations to choose from
324 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
325
326 // Very detailed logging for physics debugging
327 // TODO: the boolean values can be moved to the normal parameter processing.
328 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
329 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
330 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
331 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
332 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
333 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
334 // Very detailed logging for vehicle debugging
335 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
336 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
337
338 // Do any replacements in the parameters
339 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
340 }
341 else
342 {
343 // Nothing in the configuration INI file so assume unmanaged and other defaults.
344 BulletEngineName = "BulletUnmanaged";
345 m_physicsLoggingEnabled = false;
346 VehicleLoggingEnabled = false;
347 }
348
349 // The material characteristics.
350 BSMaterials.InitializeFromDefaults(Params);
351 if (pConfig != null)
352 {
353 // Let the user add new and interesting material property values.
354 BSMaterials.InitializefromParameters(pConfig);
355 }
356 }
357 }
358
359 // A helper function that handles a true/false parameter and returns the proper float number encoding
360 float ParamBoolean(IConfig config, string parmName, float deflt)
361 {
362 float ret = deflt;
363 if (config.Contains(parmName))
364 {
365 ret = ConfigurationParameters.numericFalse;
366 if (config.GetBoolean(parmName, false))
367 {
368 ret = ConfigurationParameters.numericTrue;
369 }
370 }
371 return ret;
372 }
373
374 // Select the connection to the actual Bullet implementation.
375 // The main engine selection is the engineName up to the first hypen.
376 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
377 // is passed to the engine to do its special selection, etc.
378 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
379 {
380 // For the moment, do a simple switch statement.
381 // Someday do fancyness with looking up the interfaces in the assembly.
382 BSAPITemplate ret = null;
383
384 string selectionName = engineName.ToLower();
385 int hyphenIndex = engineName.IndexOf("-");
386 if (hyphenIndex > 0)
387 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
388
389 switch (selectionName)
390 {
391 case "bullet":
392 case "bulletunmanaged":
393 ret = new BSAPIUnman(engineName, this);
394 break;
395 case "bulletxna":
396 ret = new BSAPIXNA(engineName, this);
397 // Disable some features that are not implemented in BulletXNA
398 m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
399 m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader);
400 BSParam.ShouldUseBulletHACD = false;
401 m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader);
402 BSParam.ShouldUseSingleConvexHullForPrims = false;
403 m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader);
404 BSParam.ShouldUseGImpactShapeForPrims = false;
405 m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader);
406 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
407 break;
408 }
409
410 if (ret == null)
411 {
412 m_log.ErrorFormat("{0} COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
413 }
414 else
415 {
416 m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
417 }
418
419 return ret;
420 }
421
422 public override void Dispose()
423 {
424 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
425
426 // make sure no stepping happens while we're deleting stuff
427 m_initialized = false;
428
429 lock (PhysObjects)
430 {
431 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
432 {
433 kvp.Value.Destroy();
434 }
435 PhysObjects.Clear();
436 }
437
438 // Now that the prims are all cleaned up, there should be no constraints left
439 if (Constraints != null)
440 {
441 Constraints.Dispose();
442 Constraints = null;
443 }
444
445 if (Shapes != null)
446 {
447 Shapes.Dispose();
448 Shapes = null;
449 }
450
451 if (TerrainManager != null)
452 {
453 TerrainManager.ReleaseGroundPlaneAndTerrain();
454 TerrainManager.Dispose();
455 TerrainManager = null;
456 }
457
458 // Anything left in the unmanaged code should be cleaned out
459 PE.Shutdown(World);
460
461 // Not logging any more
462 PhysicsLogging.Close();
463 }
464 #endregion // Construction and Initialization
465
466 #region Prim and Avatar addition and removal
467
468 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
469 {
470 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
471 return null;
472 }
473
474 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
475 {
476 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
477
478 if (!m_initialized) return null;
479
480 BSCharacter actor = new BSCharacter(localID, avName, this, position, velocity, size, isFlying);
481 lock (PhysObjects)
482 PhysObjects.Add(localID, actor);
483
484 // TODO: Remove kludge someday.
485 // We must generate a collision for avatars whether they collide or not.
486 // This is required by OpenSim to update avatar animations, etc.
487 lock (AvatarsInSceneLock)
488 AvatarsInScene.Add(actor);
489
490 return actor;
491 }
492
493 public override void RemoveAvatar(PhysicsActor actor)
494 {
495 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
496
497 if (!m_initialized) return;
498
499 BSCharacter bsactor = actor as BSCharacter;
500 if (bsactor != null)
501 {
502 try
503 {
504 lock (PhysObjects)
505 PhysObjects.Remove(bsactor.LocalID);
506 // Remove kludge someday
507 lock (AvatarsInSceneLock)
508 AvatarsInScene.Remove(bsactor);
509 }
510 catch (Exception e)
511 {
512 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
513 }
514 bsactor.Destroy();
515 // bsactor.dispose();
516 }
517 else
518 {
519 m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}",
520 LogHeader, actor.LocalID, actor.GetType().Name);
521 }
522 }
523
524 public override void RemovePrim(PhysicsActor prim)
525 {
526 if (!m_initialized) return;
527
528 BSPhysObject bsprim = prim as BSPhysObject;
529 if (bsprim != null)
530 {
531 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
532 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
533 try
534 {
535 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
536 }
537 catch (Exception e)
538 {
539 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
540 }
541 bsprim.Destroy();
542 // bsprim.dispose();
543 }
544 else
545 {
546 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
547 }
548 }
549
550 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
551 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
552 {
553 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
554
555 if (!m_initialized) return null;
556
557 // DetailLog("{0},BSScene.AddPrimShape,call", localID);
558
559 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
560 lock (PhysObjects) PhysObjects.Add(localID, prim);
561 return prim;
562 }
563
564 // This is a call from the simulator saying that some physical property has been updated.
565 // The BulletSim driver senses the changing of relevant properties so this taint
566 // information call is not needed.
567 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
568
569 #endregion // Prim and Avatar addition and removal
570
571 #region Simulation
572
573 // Call from the simulator to send physics information to the simulator objects.
574 // This pushes all the collision and property update events into the objects in
575 // the simulator and, since it is on the heartbeat thread, there is an implicit
576 // locking of those data structures from other heartbeat events.
577 // If the physics engine is running on a separate thread, the update information
578 // will be in the ObjectsWithCollions and ObjectsWithUpdates structures.
579 public override float Simulate(float timeStep)
580 {
581 if (!BSParam.UseSeparatePhysicsThread)
582 {
583 DoPhysicsStep(timeStep);
584 }
585 return SendUpdatesToSimulator(timeStep);
586 }
587
588 // Call the physics engine to do one 'timeStep' and collect collisions and updates
589 // into ObjectsWithCollisions and ObjectsWithUpdates data structures.
590 private void DoPhysicsStep(float timeStep)
591 {
592 // prevent simulation until we've been initialized
593 if (!m_initialized) return;
594
595 LastTimeStep = timeStep;
596
597 int updatedEntityCount = 0;
598 int collidersCount = 0;
599
600 int beforeTime = Util.EnvironmentTickCount();
601 int simTime = 0;
602
603 int numTaints = _taintOperations.Count;
604 InTaintTime = true; // Only used for debugging so locking is not necessary.
605
606 // update the prim states while we know the physics engine is not busy
607 ProcessTaints();
608
609 // Some of the physical objects requre individual, pre-step calls
610 // (vehicles and avatar movement, in particular)
611 TriggerPreStepEvent(timeStep);
612
613 // the prestep actions might have added taints
614 numTaints += _taintOperations.Count;
615 ProcessTaints();
616
617 InTaintTime = false; // Only used for debugging so locking is not necessary.
618
619 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
620 // Only enable this in a limited test world with few objects.
621 if (m_physicsPhysicalDumpEnabled)
622 PE.DumpAllInfo(World);
623
624 // step the physical world one interval
625 m_simulationStep++;
626 int numSubSteps = 0;
627 try
628 {
629 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
630
631 }
632 catch (Exception e)
633 {
634 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
635 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
636 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
637 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
638 updatedEntityCount = 0;
639 collidersCount = 0;
640 }
641
642 // Make the physics engine dump useful statistics periodically
643 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
644 PE.DumpPhysicsStatistics(World);
645
646 // Get a value for 'now' so all the collision and update routines don't have to get their own.
647 SimulationNowTime = Util.EnvironmentTickCount();
648
649 // Send collision information to the colliding objects. The objects decide if the collision
650 // is 'real' (like linksets don't collide with themselves) and the individual objects
651 // know if the simulator has subscribed to collisions.
652 lock (CollisionLock)
653 {
654 if (collidersCount > 0)
655 {
656 lock (PhysObjects)
657 {
658 for (int ii = 0; ii < collidersCount; ii++)
659 {
660 uint cA = m_collisionArray[ii].aID;
661 uint cB = m_collisionArray[ii].bID;
662 Vector3 point = m_collisionArray[ii].point;
663 Vector3 normal = m_collisionArray[ii].normal;
664 float penetration = m_collisionArray[ii].penetration;
665 SendCollision(cA, cB, point, normal, penetration);
666 SendCollision(cB, cA, point, -normal, penetration);
667 }
668 }
669 }
670 }
671
672 // If any of the objects had updated properties, tell the managed objects about the update
673 // and remember that there was a change so it will be passed to the simulator.
674 lock (UpdateLock)
675 {
676 if (updatedEntityCount > 0)
677 {
678 lock (PhysObjects)
679 {
680 for (int ii = 0; ii < updatedEntityCount; ii++)
681 {
682 EntityProperties entprop = m_updateArray[ii];
683 BSPhysObject pobj;
684 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
685 {
686 if (pobj.IsInitialized)
687 pobj.UpdateProperties(entprop);
688 }
689 }
690 }
691 }
692 }
693
694 // Some actors want to know when the simulation step is complete.
695 TriggerPostStepEvent(timeStep);
696
697 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
698 if (PhysicsLogging.Enabled)
699 {
700 DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
701 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
702 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
703 }
704
705 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
706 // Only enable this in a limited test world with few objects.
707 if (m_physicsPhysicalDumpEnabled)
708 PE.DumpAllInfo(World);
709
710 // The physics engine returns the number of milliseconds it simulated this call.
711 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
712 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
713 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
714 }
715
716 // Called by a BSPhysObject to note that it has changed properties and this information
717 // should be passed up to the simulator at the proper time.
718 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
719 // this is is under UpdateLock.
720 public void PostUpdate(BSPhysObject updatee)
721 {
722 lock (UpdateLock)
723 {
724 ObjectsWithUpdates.Add(updatee);
725 }
726 }
727
728 // The simulator thinks it is physics time so return all the collisions and position
729 // updates that were collected in actual physics simulation.
730 private float SendUpdatesToSimulator(float timeStep)
731 {
732 if (!m_initialized) return 5.0f;
733
734 DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
735 BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
736 // Push the collisions into the simulator.
737 lock (CollisionLock)
738 {
739 if (ObjectsWithCollisions.Count > 0)
740 {
741 foreach (BSPhysObject bsp in ObjectsWithCollisions)
742 if (!bsp.SendCollisions())
743 {
744 // If the object is done colliding, see that it's removed from the colliding list
745 ObjectsWithNoMoreCollisions.Add(bsp);
746 }
747 }
748
749 // This is a kludge to get avatar movement updates.
750 // The simulator expects collisions for avatars even if there are have been no collisions.
751 // The event updates avatar animations and stuff.
752 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
753 // Note that we get a copy of the list to search because SendCollision() can take a while.
754 HashSet<BSPhysObject> tempAvatarsInScene;
755 lock (AvatarsInSceneLock)
756 {
757 tempAvatarsInScene = new HashSet<BSPhysObject>(AvatarsInScene);
758 }
759 foreach (BSPhysObject actor in tempAvatarsInScene)
760 {
761 if (!ObjectsWithCollisions.Contains(actor)) // don't call avatars twice
762 actor.SendCollisions();
763 }
764 tempAvatarsInScene = null;
765
766 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
767 // Not done above because it is inside an iteration of ObjectWithCollisions.
768 // This complex collision processing is required to create an empty collision
769 // event call after all real collisions have happened on an object. This allows
770 // the simulator to generate the 'collision end' event.
771 if (ObjectsWithNoMoreCollisions.Count > 0)
772 {
773 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
774 ObjectsWithCollisions.Remove(po);
775 ObjectsWithNoMoreCollisions.Clear();
776 }
777 }
778
779 // Call the simulator for each object that has physics property updates.
780 HashSet<BSPhysObject> updatedObjects = null;
781 lock (UpdateLock)
782 {
783 if (ObjectsWithUpdates.Count > 0)
784 {
785 updatedObjects = ObjectsWithUpdates;
786 ObjectsWithUpdates = new HashSet<BSPhysObject>();
787 }
788 }
789 if (updatedObjects != null)
790 {
791 foreach (BSPhysObject obj in updatedObjects)
792 {
793 obj.RequestPhysicsterseUpdate();
794 }
795 updatedObjects.Clear();
796 }
797
798 // Return the framerate simulated to give the above returned results.
799 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
800 float simTime = m_simulatedTime;
801 m_simulatedTime = 0f;
802 return simTime;
803 }
804
805 // Something has collided
806 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
807 {
808 if (localID <= TerrainManager.HighestTerrainID)
809 {
810 return; // don't send collisions to the terrain
811 }
812
813 BSPhysObject collider;
814 // NOTE that PhysObjects was locked before the call to SendCollision().
815 if (!PhysObjects.TryGetValue(localID, out collider))
816 {
817 // If the object that is colliding cannot be found, just ignore the collision.
818 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
819 return;
820 }
821
822 // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
823 BSPhysObject collidee = null;
824 PhysObjects.TryGetValue(collidingWith, out collidee);
825
826 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
827
828 if (collider.IsInitialized)
829 {
830 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
831 {
832 // If a collision was 'good', remember to send it to the simulator
833 lock (CollisionLock)
834 {
835 ObjectsWithCollisions.Add(collider);
836 }
837 }
838 }
839
840 return;
841 }
842
843 public void BulletSPluginPhysicsThread()
844 {
845 Thread.CurrentThread.Priority = ThreadPriority.Highest;
846 m_updateWaitEvent = new ManualResetEvent(false);
847
848 while (m_initialized)
849 {
850 int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
851
852 if (BSParam.Active)
853 DoPhysicsStep(BSParam.PhysicsTimeStep);
854
855 int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
856 int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
857
858 if (simulationTimeVsRealtimeDifferenceMS > 0)
859 {
860 // The simulation of the time interval took less than realtime.
861 // Do a wait for the rest of realtime.
862 m_updateWaitEvent.WaitOne(simulationTimeVsRealtimeDifferenceMS);
863 //Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
864 }
865 else
866 {
867 // The simulation took longer than realtime.
868 // Do some scaling of simulation time.
869 // TODO.
870 DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
871 }
872
873 Watchdog.UpdateThread();
874 }
875
876 Watchdog.RemoveThread();
877 }
878
879 #endregion // Simulation
880
881 public override void GetResults() { }
882
883 #region Terrain
884
885 public override void SetTerrain(float[] heightMap) {
886 TerrainManager.SetTerrain(heightMap);
887 }
888
889 public override void SetWaterLevel(float baseheight)
890 {
891 SimpleWaterLevel = baseheight;
892 }
893
894 public override void DeleteTerrain()
895 {
896 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
897 }
898
899 // Although no one seems to check this, I do support combining.
900 public override bool SupportsCombining()
901 {
902 return TerrainManager.SupportsCombining();
903 }
904 // This call says I am a child to region zero in a mega-region. 'pScene' is that
905 // of region zero, 'offset' is my offset from regions zero's origin, and
906 // 'extents' is the largest XY that is handled in my region.
907 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
908 {
909 TerrainManager.Combine(pScene, offset, extents);
910 }
911
912 // Unhook all the combining that I know about.
913 public override void UnCombine(PhysicsScene pScene)
914 {
915 TerrainManager.UnCombine(pScene);
916 }
917
918 #endregion // Terrain
919
920 public override Dictionary<uint, float> GetTopColliders()
921 {
922 Dictionary<uint, float> topColliders;
923
924 lock (PhysObjects)
925 {
926 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
927 {
928 kvp.Value.ComputeCollisionScore();
929 }
930
931 List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values);
932 orderedPrims.OrderByDescending(p => p.CollisionScore);
933 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
934 }
935
936 return topColliders;
937 }
938
939 public override bool IsThreaded { get { return false; } }
940
941 #region Extensions
942 public override object Extension(string pFunct, params object[] pParams)
943 {
944 DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct);
945 return base.Extension(pFunct, pParams);
946 }
947 #endregion // Extensions
948
949 public static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs)
950 {
951 float pathShearX = pbs.PathShearX < 128 ? (float)pbs.PathShearX * 0.01f : (float)(pbs.PathShearX - 256) * 0.01f;
952 float pathShearY = pbs.PathShearY < 128 ? (float)pbs.PathShearY * 0.01f : (float)(pbs.PathShearY - 256) * 0.01f;
953 float pathBegin = (float)pbs.PathBegin * 2.0e-5f;
954 float pathEnd = 1.0f - (float)pbs.PathEnd * 2.0e-5f;
955 float pathScaleX = (float)(200 - pbs.PathScaleX) * 0.01f;
956 float pathScaleY = (float)(200 - pbs.PathScaleY) * 0.01f;
957 float pathTaperX = pbs.PathTaperX * 0.01f;
958 float pathTaperY = pbs.PathTaperY * 0.01f;
959
960 float profileBegin = (float)pbs.ProfileBegin * 2.0e-5f;
961 float profileEnd = 1.0f - (float)pbs.ProfileEnd * 2.0e-5f;
962 float profileHollow = (float)pbs.ProfileHollow * 2.0e-5f;
963 if (profileHollow > 0.95f)
964 profileHollow = 0.95f;
965
966 StringBuilder buff = new StringBuilder();
967 buff.Append("shape=");
968 buff.Append(((ProfileShape)pbs.ProfileShape).ToString());
969 buff.Append(",");
970 buff.Append("hollow=");
971 buff.Append(((HollowShape)pbs.HollowShape).ToString());
972 buff.Append(",");
973 buff.Append("pathCurve=");
974 buff.Append(((Extrusion)pbs.PathCurve).ToString());
975 buff.Append(",");
976 buff.Append("profCurve=");
977 buff.Append(((Extrusion)pbs.ProfileCurve).ToString());
978 buff.Append(",");
979 buff.Append("profHollow=");
980 buff.Append(profileHollow.ToString());
981 buff.Append(",");
982 buff.Append("pathBegEnd=");
983 buff.Append(pathBegin.ToString());
984 buff.Append("/");
985 buff.Append(pathEnd.ToString());
986 buff.Append(",");
987 buff.Append("profileBegEnd=");
988 buff.Append(profileBegin.ToString());
989 buff.Append("/");
990 buff.Append(profileEnd.ToString());
991 buff.Append(",");
992 buff.Append("scaleXY=");
993 buff.Append(pathScaleX.ToString());
994 buff.Append("/");
995 buff.Append(pathScaleY.ToString());
996 buff.Append(",");
997 buff.Append("shearXY=");
998 buff.Append(pathShearX.ToString());
999 buff.Append("/");
1000 buff.Append(pathShearY.ToString());
1001 buff.Append(",");
1002 buff.Append("taperXY=");
1003 buff.Append(pbs.PathTaperX.ToString());
1004 buff.Append("/");
1005 buff.Append(pbs.PathTaperY.ToString());
1006 buff.Append(",");
1007 buff.Append("skew=");
1008 buff.Append(pbs.PathSkew.ToString());
1009 buff.Append(",");
1010 buff.Append("twist/Beg=");
1011 buff.Append(pbs.PathTwist.ToString());
1012 buff.Append("/");
1013 buff.Append(pbs.PathTwistBegin.ToString());
1014
1015 return buff.ToString();
1016 }
1017
1018 #region Taints
1019 // The simulation execution order is:
1020 // Simulate()
1021 // DoOneTimeTaints
1022 // TriggerPreStepEvent
1023 // DoOneTimeTaints
1024 // Step()
1025 // ProcessAndSendToSimulatorCollisions
1026 // ProcessAndSendToSimulatorPropertyUpdates
1027 // TriggerPostStepEvent
1028
1029 // Calls to the PhysicsActors can't directly call into the physics engine
1030 // because it might be busy. We delay changes to a known time.
1031 // We rely on C#'s closure to save and restore the context for the delegate.
1032 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
1033 {
1034 TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback);
1035 }
1036 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
1037 {
1038 TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1039 }
1040 public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1041 {
1042 TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
1043 }
1044 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1045 {
1046 TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1047 }
1048 // Sometimes a potentially tainted operation can be used in and out of taint time.
1049 // This routine executes the command immediately if in taint-time otherwise it is queued.
1050 public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback)
1051 {
1052 if (!m_initialized) return;
1053
1054 if (inTaintTime)
1055 pCallback();
1056 else
1057 {
1058 lock (_taintLock)
1059 {
1060 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
1061 }
1062 }
1063 }
1064
1065 private void TriggerPreStepEvent(float timeStep)
1066 {
1067 PreStepAction actions = BeforeStep;
1068 if (actions != null)
1069 actions(timeStep);
1070
1071 }
1072
1073 private void TriggerPostStepEvent(float timeStep)
1074 {
1075 PostStepAction actions = AfterStep;
1076 if (actions != null)
1077 actions(timeStep);
1078
1079 }
1080
1081 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
1082 // a callback into itself to do the actual property change. That callback is called
1083 // here just before the physics engine is called to step the simulation.
1084 public void ProcessTaints()
1085 {
1086 ProcessRegularTaints();
1087 ProcessPostTaintTaints();
1088 }
1089
1090 private void ProcessRegularTaints()
1091 {
1092 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
1093 {
1094 // swizzle a new list into the list location so we can process what's there
1095 List<TaintCallbackEntry> oldList;
1096 lock (_taintLock)
1097 {
1098 oldList = _taintOperations;
1099 _taintOperations = new List<TaintCallbackEntry>();
1100 }
1101
1102 foreach (TaintCallbackEntry tcbe in oldList)
1103 {
1104 try
1105 {
1106 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
1107 tcbe.callback();
1108 }
1109 catch (Exception e)
1110 {
1111 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
1112 }
1113 }
1114 oldList.Clear();
1115 }
1116 }
1117
1118 // Schedule an update to happen after all the regular taints are processed.
1119 // Note that new requests for the same operation ("ident") for the same object ("ID")
1120 // will replace any previous operation by the same object.
1121 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
1122 {
1123 string IDAsString = ID.ToString();
1124 string uniqueIdent = ident + "-" + IDAsString;
1125 lock (_taintLock)
1126 {
1127 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback);
1128 }
1129
1130 return;
1131 }
1132
1133 // Taints that happen after the normal taint processing but before the simulation step.
1134 private void ProcessPostTaintTaints()
1135 {
1136 if (m_initialized && _postTaintOperations.Count > 0)
1137 {
1138 Dictionary<string, TaintCallbackEntry> oldList;
1139 lock (_taintLock)
1140 {
1141 oldList = _postTaintOperations;
1142 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
1143 }
1144
1145 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
1146 {
1147 try
1148 {
1149 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
1150 kvp.Value.callback();
1151 }
1152 catch (Exception e)
1153 {
1154 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
1155 }
1156 }
1157 oldList.Clear();
1158 }
1159 }
1160
1161 // Only used for debugging. Does not change state of anything so locking is not necessary.
1162 public bool AssertInTaintTime(string whereFrom)
1163 {
1164 if (!InTaintTime)
1165 {
1166 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
1167 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
1168 // Util.PrintCallStack(DetailLog);
1169 }
1170 return InTaintTime;
1171 }
1172
1173 #endregion // Taints
1174
1175 #region IPhysicsParameters
1176 // Get the list of parameters this physics engine supports
1177 public PhysParameterEntry[] GetParameterList()
1178 {
1179 BSParam.BuildParameterTable();
1180 return BSParam.SettableParameters;
1181 }
1182
1183 // Set parameter on a specific or all instances.
1184 // Return 'false' if not able to set the parameter.
1185 // Setting the value in the m_params block will change the value the physics engine
1186 // will use the next time since it's pinned and shared memory.
1187 // Some of the values require calling into the physics engine to get the new
1188 // value activated ('terrainFriction' for instance).
1189 public bool SetPhysicsParameter(string parm, string val, uint localID)
1190 {
1191 bool ret = false;
1192
1193 BSParam.ParameterDefnBase theParam;
1194 if (BSParam.TryGetParameter(parm, out theParam))
1195 {
1196 // Set the value in the C# code
1197 theParam.SetValue(this, val);
1198
1199 // Optionally set the parameter in the unmanaged code
1200 if (theParam.HasSetOnObject)
1201 {
1202 // update all the localIDs specified
1203 // If the local ID is APPLY_TO_NONE, just change the default value
1204 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1205 // If the localID is a specific object, apply the parameter change to only that object
1206 List<uint> objectIDs = new List<uint>();
1207 switch (localID)
1208 {
1209 case PhysParameterEntry.APPLY_TO_NONE:
1210 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1211 objectIDs.Add(TERRAIN_ID);
1212 TaintedUpdateParameter(parm, objectIDs, val);
1213 break;
1214 case PhysParameterEntry.APPLY_TO_ALL:
1215 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1216 TaintedUpdateParameter(parm, objectIDs, val);
1217 break;
1218 default:
1219 // setting only one localID
1220 objectIDs.Add(localID);
1221 TaintedUpdateParameter(parm, objectIDs, val);
1222 break;
1223 }
1224 }
1225
1226 ret = true;
1227 }
1228 return ret;
1229 }
1230
1231 // schedule the actual updating of the paramter to when the phys engine is not busy
1232 private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val)
1233 {
1234 string xval = val;
1235 List<uint> xlIDs = lIDs;
1236 string xparm = parm;
1237 TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() {
1238 BSParam.ParameterDefnBase thisParam;
1239 if (BSParam.TryGetParameter(xparm, out thisParam))
1240 {
1241 if (thisParam.HasSetOnObject)
1242 {
1243 foreach (uint lID in xlIDs)
1244 {
1245 BSPhysObject theObject = null;
1246 if (PhysObjects.TryGetValue(lID, out theObject))
1247 thisParam.SetOnObject(this, theObject);
1248 }
1249 }
1250 }
1251 });
1252 }
1253
1254 // Get parameter.
1255 // Return 'false' if not able to get the parameter.
1256 public bool GetPhysicsParameter(string parm, out string value)
1257 {
1258 string val = String.Empty;
1259 bool ret = false;
1260 BSParam.ParameterDefnBase theParam;
1261 if (BSParam.TryGetParameter(parm, out theParam))
1262 {
1263 val = theParam.GetValue(this);
1264 ret = true;
1265 }
1266 value = val;
1267 return ret;
1268 }
1269
1270 #endregion IPhysicsParameters
1271
1272 // Invoke the detailed logger and output something if it's enabled.
1273 public void DetailLog(string msg, params Object[] args)
1274 {
1275 PhysicsLogging.Write(msg, args);
1276 }
1277 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1278 public const string DetailLogZero = "0000000000";
1279
1280}
1281}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
new file mode 100755
index 0000000..d1de844
--- /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.Physics.Manager;
33using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
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..86d86cb
--- /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.Physics.Manager;
34using OpenSim.Region.Physics.Meshing;
35using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36
37using OMV = OpenMetaverse;
38
39namespace OpenSim.Region.Physics.BulletSPlugin
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.Name);
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.Name);
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..d70b2fb
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
@@ -0,0 +1,170 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public sealed class BSTerrainHeightmap : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46
47 BulletHMapInfo m_mapInfo = null;
48
49 // Constructor to build a default, flat heightmap terrain.
50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
51 : base(physicsScene, regionBase, id)
52 {
53 Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
54 Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
55 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
56 float[] initialMap = new float[totalHeights];
57 for (int ii = 0; ii < totalHeights; ii++)
58 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 }
61 m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y);
62 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase;
65 // Don't have to free any previous since we just got here.
66 BuildHeightmapTerrain();
67 }
68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id)
74 {
75 m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y);
76 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z;
79 m_mapInfo.maxZ = maxCoords.Z;
80 m_mapInfo.terrainRegionBase = TerrainBase;
81
82 // Don't have to free any previous since we just got here.
83 BuildHeightmapTerrain();
84 }
85
86 public override void Dispose()
87 {
88 ReleaseHeightMapTerrain();
89 }
90
91 // Using the information in m_mapInfo, create the physical representation of the heightmap.
92 private void BuildHeightmapTerrain()
93 {
94 // Create the terrain shape from the mapInfo
95 m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98
99
100 // The terrain object initial position is at the center of the object
101 Vector3 centerPos;
102 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
105
106 m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
107 m_mapInfo.ID, centerPos, Quaternion.Identity);
108
109 // Set current terrain attributes
110 m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
111 m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
112 m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
113 m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
114
115 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
116
117 // Return the new terrain to the world of physical objects
118 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody);
119
120 // redo its bounding box now that it is in the world
121 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody);
122
123 // Make it so the terrain will not move or be considered for movement.
124 m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
125
126 return;
127 }
128
129 // If there is information in m_mapInfo pointing to physical structures, release same.
130 private void ReleaseHeightMapTerrain()
131 {
132 if (m_mapInfo != null)
133 {
134 if (m_mapInfo.terrainBody.HasPhysicalBody)
135 {
136 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody);
137 // Frees both the body and the shape.
138 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody);
139 }
140 }
141 m_mapInfo = null;
142 }
143
144 // The passed position is relative to the base of the region.
145 public override float GetTerrainHeightAtXYZ(Vector3 pos)
146 {
147 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
148
149 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
150 try
151 {
152 ret = m_mapInfo.heightMap[mapIndex];
153 }
154 catch
155 {
156 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
157 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
158 LogHeader, m_mapInfo.terrainRegionBase, pos);
159 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
160 }
161 return ret;
162 }
163
164 // The passed position is relative to the base of the region.
165 public override float GetWaterLevelAtXYZ(Vector3 pos)
166 {
167 return m_physicsScene.SimpleWaterLevel;
168 }
169}
170}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
new file mode 100755
index 0000000..50f917a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
@@ -0,0 +1,585 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43
44// The physical implementation of the terrain is wrapped in this class.
45public abstract class BSTerrainPhys : IDisposable
46{
47 public enum TerrainImplementation
48 {
49 Heightmap = 0,
50 Mesh = 1
51 }
52
53 protected BSScene m_physicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; }
57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 {
60 m_physicsScene = physicsScene;
61 TerrainBase = regionBase;
62 ID = id;
63 }
64 public abstract void Dispose();
65 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
66 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
67}
68
69// ==========================================================================================
70public sealed class BSTerrainManager : IDisposable
71{
72 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
73
74 // These height values are fractional so the odd values will be
75 // noticable when debugging.
76 public const float HEIGHT_INITIALIZATION = 24.987f;
77 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
78 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
79 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
80
81 // If the min and max height are equal, we reduce the min by this
82 // amount to make sure that a bounding box is built for the terrain.
83 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
84
85 // Until the whole simulator is changed to pass us the region size, we rely on constants.
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87
88 // The scene that I am part of
89 private BSScene m_physicsScene { get; set; }
90
91 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane;
93
94 // If doing mega-regions, if we're region zero we will be managing multiple
95 // region terrains since region zero does the physics for the whole mega-region.
96 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
97
98 // Flags used to know when to recalculate the height.
99 private bool m_terrainModified = false;
100
101 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
102 // This is incremented before assigning to new region so it is the last ID allocated.
103 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
104 public uint HighestTerrainID { get {return m_terrainCount; } }
105
106 // If doing mega-regions, this holds our offset from region zero of
107 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
108 private Vector3 m_worldOffset;
109 // If the parent region (region 0), this is the extent of the combined regions
110 // relative to the origin of region zero
111 private Vector3 m_worldMax;
112 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
113
114 public BSTerrainManager(BSScene physicsScene, Vector3 regionSize)
115 {
116 m_physicsScene = physicsScene;
117 DefaultRegionSize = regionSize;
118
119 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
120
121 // Assume one region of default size
122 m_worldOffset = Vector3.Zero;
123 m_worldMax = new Vector3(DefaultRegionSize);
124 MegaRegionParentPhysicsScene = null;
125 }
126
127 public void Dispose()
128 {
129 ReleaseGroundPlaneAndTerrain();
130 }
131
132 // Create the initial instance of terrain and the underlying ground plane.
133 // This is called from the initialization routine so we presume it is
134 // safe to call Bullet in real time. We hope no one is moving prims around yet.
135 public void CreateInitialGroundPlaneAndTerrain()
136 {
137 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
138 // The ground plane is here to catch things that are trying to drop to negative infinity
139 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
140 Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane);
141 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
142 BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity);
143
144 // Everything collides with the ground plane.
145 m_groundPlane.collisionType = CollisionType.Groundplane;
146
147 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
148 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
149
150 // Ground plane does not move
151 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
152
153 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
154 lock (m_terrains)
155 {
156 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
157 m_terrains.Add(Vector3.Zero, initialTerrain);
158 }
159 }
160
161 // Release all the terrain structures we might have allocated
162 public void ReleaseGroundPlaneAndTerrain()
163 {
164 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
165 if (m_groundPlane.HasPhysicalBody)
166 {
167 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
168 {
169 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
170 }
171 m_groundPlane.Clear();
172 }
173
174 ReleaseTerrain();
175 }
176
177 // Release all the terrain we have allocated
178 public void ReleaseTerrain()
179 {
180 lock (m_terrains)
181 {
182 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
183 {
184 kvp.Value.Dispose();
185 }
186 m_terrains.Clear();
187 }
188 }
189
190 // The simulator wants to set a new heightmap for the terrain.
191 public void SetTerrain(float[] heightMap) {
192 float[] localHeightMap = heightMap;
193 // If there are multiple requests for changes to the same terrain between ticks,
194 // only do that last one.
195 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
196 {
197 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
198 {
199 // If a child of a mega-region, we shouldn't have any terrain allocated for us
200 ReleaseGroundPlaneAndTerrain();
201 // If doing the mega-prim stuff and we are the child of the zero region,
202 // the terrain is added to our parent
203 if (MegaRegionParentPhysicsScene is BSScene)
204 {
205 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
206 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
207 BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
208 }
209 }
210 else
211 {
212 // If not doing the mega-prim thing, just change the terrain
213 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
214
215 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
216 }
217 });
218 }
219
220 // Another region is calling this region and passing a terrain.
221 // A region that is not the mega-region root will pass its terrain to the root region so the root region
222 // physics engine will have all the terrains.
223 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
224 {
225 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
226 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
227 {
228 UpdateTerrain(id, heightMap, minCoords, maxCoords);
229 });
230 }
231
232 // If called for terrain has has not been previously allocated, a new terrain will be built
233 // based on the passed information. The 'id' should be either the terrain id or
234 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
235 // The latter feature is for creating child terrains for mega-regions.
236 // If there is an existing terrain body, a new
237 // terrain shape is created and added to the body.
238 // This call is most often used to update the heightMap and parameters of the terrain.
239 // (The above does suggest that some simplification/refactoring is in order.)
240 // Called during taint-time.
241 private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
242 {
243 // Find high and low points of passed heightmap.
244 // The min and max passed in is usually the area objects can be in (maximum
245 // object height, for instance). The terrain wants the bounding box for the
246 // terrain so replace passed min and max Z with the actual terrain min/max Z.
247 float minZ = float.MaxValue;
248 float maxZ = float.MinValue;
249 foreach (float height in heightMap)
250 {
251 if (height < minZ) minZ = height;
252 if (height > maxZ) maxZ = height;
253 }
254 if (minZ == maxZ)
255 {
256 // If min and max are the same, reduce min a little bit so a good bounding box is created.
257 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
258 }
259 minCoords.Z = minZ;
260 maxCoords.Z = maxZ;
261
262 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
263 BSScene.DetailLogZero, id, minCoords, maxCoords);
264
265 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
266
267 lock (m_terrains)
268 {
269 BSTerrainPhys terrainPhys;
270 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
271 {
272 // There is already a terrain in this spot. Free the old and build the new.
273 DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
274 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords);
275
276 // Remove old terrain from the collection
277 m_terrains.Remove(terrainRegionBase);
278 // Release any physical memory it may be using.
279 terrainPhys.Dispose();
280
281 if (MegaRegionParentPhysicsScene == null)
282 {
283 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
284 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
285 m_terrains.Add(terrainRegionBase, newTerrainPhys);
286
287 m_terrainModified = true;
288 }
289 else
290 {
291 // It's possible that Combine() was called after this code was queued.
292 // If we are a child of combined regions, we don't create any terrain for us.
293 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
294
295 // Get rid of any terrain that may have been allocated for us.
296 ReleaseGroundPlaneAndTerrain();
297
298 // I hate doing this, but just bail
299 return;
300 }
301 }
302 else
303 {
304 // We don't know about this terrain so either we are creating a new terrain or
305 // our mega-prim child is giving us a new terrain to add to the phys world
306
307 // if this is a child terrain, calculate a unique terrain id
308 uint newTerrainID = id;
309 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
310 newTerrainID = ++m_terrainCount;
311
312 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
313 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
314 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
315 m_terrains.Add(terrainRegionBase, newTerrainPhys);
316
317 m_terrainModified = true;
318 }
319 }
320 }
321
322 // TODO: redo terrain implementation selection to allow other base types than heightMap.
323 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
324 {
325 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
326 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
327 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
328 BSTerrainPhys newTerrainPhys = null;
329 switch ((int)BSParam.TerrainImplementation)
330 {
331 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
332 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
333 heightMap, minCoords, maxCoords);
334 break;
335 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
336 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
337 heightMap, minCoords, maxCoords);
338 break;
339 default:
340 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
341 LogHeader,
342 (int)BSParam.TerrainImplementation,
343 BSParam.TerrainImplementation,
344 m_physicsScene.RegionName, terrainRegionBase);
345 break;
346 }
347 return newTerrainPhys;
348 }
349
350 // Return 'true' of this position is somewhere in known physical terrain space
351 public bool IsWithinKnownTerrain(Vector3 pos)
352 {
353 Vector3 terrainBaseXYZ;
354 BSTerrainPhys physTerrain;
355 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
356 }
357
358 // Return a new position that is over known terrain if the position is outside our terrain.
359 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
360 {
361 float edgeEpsilon = 0.1f;
362
363 Vector3 ret = pPos;
364
365 // First, base addresses are never negative so correct for that possible problem.
366 if (ret.X < 0f || ret.Y < 0f)
367 {
368 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
369 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
370 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
371 BSScene.DetailLogZero, pPos, ret);
372 }
373
374 // Can't do this function if we don't know about any terrain.
375 if (m_terrains.Count == 0)
376 return ret;
377
378 int loopPrevention = 10;
379 Vector3 terrainBaseXYZ;
380 BSTerrainPhys physTerrain;
381 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
382 {
383 // The passed position is not within a known terrain area.
384 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
385
386 // Must be off the top of a region. Find an adjacent region to move into.
387 // The returned terrain is always 'lower'. That is, closer to <0,0>.
388 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
389
390 if (adjacentTerrainBase.X < terrainBaseXYZ.X)
391 {
392 // moving down into a new region in the X dimension. New position will be the max in the new base.
393 ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon;
394 }
395 if (adjacentTerrainBase.Y < terrainBaseXYZ.Y)
396 {
397 // moving down into a new region in the X dimension. New position will be the max in the new base.
398 ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon;
399 }
400 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
401 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
402
403 if (loopPrevention-- < 0f)
404 {
405 // The 'while' is a little dangerous so this prevents looping forever if the
406 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
407 // the list of terrains is in transition.
408 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
409 break;
410 }
411 }
412
413 return ret;
414 }
415
416 // Given an X and Y, find the height of the terrain.
417 // Since we could be handling multiple terrains for a mega-region,
418 // the base of the region is calcuated assuming all regions are
419 // the same size and that is the default.
420 // Once the heightMapInfo is found, we have all the information to
421 // compute the offset into the array.
422 private float lastHeightTX = 999999f;
423 private float lastHeightTY = 999999f;
424 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
425 public float GetTerrainHeightAtXYZ(Vector3 pos)
426 {
427 float tX = pos.X;
428 float tY = pos.Y;
429 // You'd be surprized at the number of times this routine is called
430 // with the same parameters as last time.
431 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
432 return lastHeight;
433 m_terrainModified = false;
434
435 lastHeightTX = tX;
436 lastHeightTY = tY;
437 float ret = HEIGHT_GETHEIGHT_RET;
438
439 Vector3 terrainBaseXYZ;
440 BSTerrainPhys physTerrain;
441 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
442 {
443 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
444 }
445 else
446 {
447 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
448 LogHeader, m_physicsScene.RegionName, tX, tY);
449 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
450 BSScene.DetailLogZero, pos, terrainBaseXYZ);
451 }
452
453 lastHeight = ret;
454 return ret;
455 }
456
457 public float GetWaterLevelAtXYZ(Vector3 pos)
458 {
459 float ret = WATER_HEIGHT_GETHEIGHT_RET;
460
461 Vector3 terrainBaseXYZ;
462 BSTerrainPhys physTerrain;
463 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
464 {
465 ret = physTerrain.GetWaterLevelAtXYZ(pos);
466 }
467 else
468 {
469 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
470 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
471 }
472 return ret;
473 }
474
475 // Given an address, return 'true' of there is a description of that terrain and output
476 // the descriptor class and the 'base' fo the addresses therein.
477 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
478 {
479 bool ret = false;
480
481 Vector3 terrainBaseXYZ = Vector3.Zero;
482 if (pos.X < 0f || pos.Y < 0f)
483 {
484 // We don't handle negative addresses so just make up a base that will not be found.
485 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
486 }
487 else
488 {
489 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
490 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
491 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
492 }
493
494 BSTerrainPhys physTerrain = null;
495 lock (m_terrains)
496 {
497 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
498 }
499 outTerrainBase = terrainBaseXYZ;
500 outPhysTerrain = physTerrain;
501 return ret;
502 }
503
504 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
505 // this one. Usually used to return an out of bounds object to a known place.
506 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
507 {
508 Vector3 ret = pTerrainBase;
509
510 // Can't do this function if we don't know about any terrain.
511 if (m_terrains.Count == 0)
512 return ret;
513
514 // Just some sanity
515 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
516 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
517 ret.Z = 0f;
518
519 lock (m_terrains)
520 {
521 // Once down to the <0,0> region, we have to be done.
522 while (ret.X > 0f || ret.Y > 0f)
523 {
524 if (ret.X > 0f)
525 {
526 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
527 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
528 if (m_terrains.ContainsKey(ret))
529 break;
530 }
531 if (ret.Y > 0f)
532 {
533 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
534 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
535 if (m_terrains.ContainsKey(ret))
536 break;
537 }
538 }
539 }
540
541 return ret;
542 }
543
544 // Although no one seems to check this, I do support combining.
545 public bool SupportsCombining()
546 {
547 return true;
548 }
549
550 // This routine is called two ways:
551 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
552 // extent of the combined regions. This is to inform the parent of the size
553 // of the combined regions.
554 // and one with 'offset' as the offset of the child region to the base region,
555 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
556 // child of its relative base and new parent.
557 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
558 {
559 m_worldOffset = offset;
560 m_worldMax = extents;
561 MegaRegionParentPhysicsScene = pScene;
562 if (pScene != null)
563 {
564 // We are a child.
565 // We want m_worldMax to be the highest coordinate of our piece of terrain.
566 m_worldMax = offset + DefaultRegionSize;
567 }
568 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
569 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
570 }
571
572 // Unhook all the combining that I know about.
573 public void UnCombine(PhysicsScene pScene)
574 {
575 // Just like ODE, we don't do anything yet.
576 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
577 }
578
579
580 private void DetailLog(string msg, params Object[] args)
581 {
582 m_physicsScene.PhysicsLogging.Write(msg, args);
583 }
584}
585}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
new file mode 100755
index 0000000..e4ca098
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.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 copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public sealed class BSTerrainMesh : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
46
47 private float[] m_savedHeightMap;
48 int m_sizeX;
49 int m_sizeY;
50
51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody;
53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id)
56 {
57 }
58
59 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
60 : base(physicsScene, regionBase, id)
61 {
62 }
63
64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id)
68 {
69 int indicesCount;
70 int[] indices;
71 int verticesCount;
72 float[] vertices;
73
74 m_savedHeightMap = initialMap;
75
76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78
79 bool meshCreationSuccess = false;
80 if (BSParam.TerrainMeshMagnification == 1)
81 {
82 // If a magnification of one, use the old routine that is tried and true.
83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene,
84 initialMap, m_sizeX, m_sizeY, // input size
85 Vector3.Zero, // base for mesh
86 out indicesCount, out indices, out verticesCount, out vertices);
87 }
88 else
89 {
90 // Other magnifications use the newer routine
91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene,
92 initialMap, m_sizeX, m_sizeY, // input size
93 BSParam.TerrainMeshMagnification,
94 physicsScene.TerrainManager.DefaultRegionSize,
95 Vector3.Zero, // base for mesh
96 out indicesCount, out indices, out verticesCount, out vertices);
97 }
98 if (!meshCreationSuccess)
99 {
100 // DISASTER!!
101 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
102 m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
103 // Something is very messed up and a crash is in our future.
104 return;
105 }
106
107 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
109
110 m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices);
111 if (!m_terrainShape.HasPhysicalShape)
112 {
113 // DISASTER!!
114 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
115 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
116 // Something is very messed up and a crash is in our future.
117 return;
118 }
119
120 Vector3 pos = regionBase;
121 Quaternion rot = Quaternion.Identity;
122
123 m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
124 if (!m_terrainBody.HasPhysicalBody)
125 {
126 // DISASTER!!
127 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
128 // Something is very messed up and a crash is in our future.
129 return;
130 }
131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
132
133 // Set current terrain attributes
134 m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
135 m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
136 m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
137 m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
138 m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
139
140 // Static objects are not very massive.
141 m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
142
143 // Put the new terrain to the world of physical objects
144 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody);
145
146 // Redo its bounding box now that it is in the world
147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody);
148
149 m_terrainBody.collisionType = CollisionType.Terrain;
150 m_terrainBody.ApplyCollisionMask(m_physicsScene);
151
152 if (BSParam.UseSingleSidedMeshes)
153 {
154 m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
155 m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
156 }
157
158 // Make it so the terrain will not move or be considered for movement.
159 m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
160 }
161
162 public override void Dispose()
163 {
164 if (m_terrainBody.HasPhysicalBody)
165 {
166 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody);
167 // Frees both the body and the shape.
168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody);
169 m_terrainBody.Clear();
170 m_terrainShape.Clear();
171 }
172 }
173
174 public override float GetTerrainHeightAtXYZ(Vector3 pos)
175 {
176 // For the moment use the saved heightmap to get the terrain height.
177 // TODO: raycast downward to find the true terrain below the position.
178 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
179
180 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
181 try
182 {
183 ret = m_savedHeightMap[mapIndex];
184 }
185 catch
186 {
187 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
188 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
189 LogHeader, TerrainBase, pos);
190 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
191 }
192 return ret;
193 }
194
195 // The passed position is relative to the base of the region.
196 public override float GetWaterLevelAtXYZ(Vector3 pos)
197 {
198 return m_physicsScene.SimpleWaterLevel;
199 }
200
201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
202 // Return 'true' if successfully created.
203 public static bool ConvertHeightmapToMesh( BSScene physicsScene,
204 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
205 Vector3 extentBase, // base to be added to all vertices
206 out int indicesCountO, out int[] indicesO,
207 out int verticesCountO, out float[] verticesO)
208 {
209 bool ret = false;
210
211 int indicesCount = 0;
212 int verticesCount = 0;
213 int[] indices = new int[0];
214 float[] vertices = new float[0];
215
216 // Simple mesh creation which assumes magnification == 1.
217 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
218
219 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
220 // from zero to <= sizeX). The triangle indices are then generated as two triangles
221 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
222 // column of vertices are used to complete the triangles of the last row and column
223 // of the heightmap.
224 try
225 {
226 // One vertice per heightmap value plus the vertices off the side and bottom edge.
227 int totalVertices = (sizeX + 1) * (sizeY + 1);
228 vertices = new float[totalVertices * 3];
229 int totalIndices = sizeX * sizeY * 6;
230 indices = new int[totalIndices];
231
232 if (physicsScene != null)
233 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
234 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
235 float minHeight = float.MaxValue;
236 // Note that sizeX+1 vertices are created since there is land between this and the next region.
237 for (int yy = 0; yy <= sizeY; yy++)
238 {
239 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
240 {
241 int offset = yy * sizeX + xx;
242 // Extend the height with the height from the last row or column
243 if (yy == sizeY) offset -= sizeX;
244 if (xx == sizeX) offset -= 1;
245 float height = heightMap[offset];
246 minHeight = Math.Min(minHeight, height);
247 vertices[verticesCount + 0] = (float)xx + extentBase.X;
248 vertices[verticesCount + 1] = (float)yy + extentBase.Y;
249 vertices[verticesCount + 2] = height + extentBase.Z;
250 verticesCount += 3;
251 }
252 }
253 verticesCount = verticesCount / 3;
254
255 for (int yy = 0; yy < sizeY; yy++)
256 {
257 for (int xx = 0; xx < sizeX; xx++)
258 {
259 int offset = yy * (sizeX + 1) + xx;
260 // Each vertices is presumed to be the upper left corner of a box of two triangles
261 indices[indicesCount + 0] = offset;
262 indices[indicesCount + 1] = offset + 1;
263 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
264 indices[indicesCount + 3] = offset + 1;
265 indices[indicesCount + 4] = offset + sizeX + 2;
266 indices[indicesCount + 5] = offset + sizeX + 1;
267 indicesCount += 6;
268 }
269 }
270
271 ret = true;
272 }
273 catch (Exception e)
274 {
275 if (physicsScene != null)
276 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
277 LogHeader, physicsScene.RegionName, extentBase, e);
278 }
279
280 indicesCountO = indicesCount;
281 indicesO = indices;
282 verticesCountO = verticesCount;
283 verticesO = vertices;
284
285 return ret;
286 }
287
288 private class HeightMapGetter
289 {
290 private float[] m_heightMap;
291 private int m_sizeX;
292 private int m_sizeY;
293 public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
294 {
295 m_heightMap = pHeightMap;
296 m_sizeX = pSizeX;
297 m_sizeY = pSizeY;
298 }
299 // The heightmap is extended as an infinite plane at the last height
300 public float GetHeight(int xx, int yy)
301 {
302 int offset = 0;
303 // Extend the height with the height from the last row or column
304 if (yy >= m_sizeY)
305 if (xx >= m_sizeX)
306 offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
307 else
308 offset = (m_sizeY - 1) * m_sizeX + xx;
309 else
310 if (xx >= m_sizeX)
311 offset = yy * m_sizeX + (m_sizeX - 1);
312 else
313 offset = yy * m_sizeX + xx;
314
315 return m_heightMap[offset];
316 }
317 }
318
319 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
320 // Version that handles magnification.
321 // Return 'true' if successfully created.
322 public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
323 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
324 int magnification, // number of vertices per heighmap step
325 Vector3 extent, // dimensions of the output mesh
326 Vector3 extentBase, // base to be added to all vertices
327 out int indicesCountO, out int[] indicesO,
328 out int verticesCountO, out float[] verticesO)
329 {
330 bool ret = false;
331
332 int indicesCount = 0;
333 int verticesCount = 0;
334 int[] indices = new int[0];
335 float[] vertices = new float[0];
336
337 HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
338
339 // The vertices dimension of the output mesh
340 int meshX = sizeX * magnification;
341 int meshY = sizeY * magnification;
342 // The output size of one mesh step
343 float meshXStep = extent.X / meshX;
344 float meshYStep = extent.Y / meshY;
345
346 // Create an array of vertices that is meshX+1 by meshY+1 (note the loop
347 // from zero to <= meshX). The triangle indices are then generated as two triangles
348 // per heightmap point. There are meshX by meshY of these squares. The extra row and
349 // column of vertices are used to complete the triangles of the last row and column
350 // of the heightmap.
351 try
352 {
353 // Vertices for the output heightmap plus one on the side and bottom to complete triangles
354 int totalVertices = (meshX + 1) * (meshY + 1);
355 vertices = new float[totalVertices * 3];
356 int totalIndices = meshX * meshY * 6;
357 indices = new int[totalIndices];
358
359 if (physicsScene != null)
360 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
361 BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
362 totalVertices, totalIndices, extentBase);
363
364 float minHeight = float.MaxValue;
365 // Note that sizeX+1 vertices are created since there is land between this and the next region.
366 // Loop through the output vertices and compute the mediun height in between the input vertices
367 for (int yy = 0; yy <= meshY; yy++)
368 {
369 for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
370 {
371 float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
372 int stepY = (int)offsetY;
373 float fractionalY = offsetY - (float)stepY;
374 float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
375 int stepX = (int)offsetX;
376 float fractionalX = offsetX - (float)stepX;
377
378 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
379 // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
380
381 // get the four corners of the heightmap square the mesh point is in
382 float heightUL = hmap.GetHeight(stepX , stepY );
383 float heightUR = hmap.GetHeight(stepX + 1, stepY );
384 float heightLL = hmap.GetHeight(stepX , stepY + 1);
385 float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
386
387 // bilinear interplolation
388 float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
389 + heightUR * fractionalX * (1 - fractionalY)
390 + heightLL * (1 - fractionalX) * fractionalY
391 + heightLR * fractionalX * fractionalY;
392
393 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
394 // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
395
396 minHeight = Math.Min(minHeight, height);
397
398 vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
399 vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
400 vertices[verticesCount + 2] = height + extentBase.Z;
401 verticesCount += 3;
402 }
403 }
404 // The number of vertices generated
405 verticesCount /= 3;
406
407 // Loop through all the heightmap squares and create indices for the two triangles for that square
408 for (int yy = 0; yy < meshY; yy++)
409 {
410 for (int xx = 0; xx < meshX; xx++)
411 {
412 int offset = yy * (meshX + 1) + xx;
413 // Each vertices is presumed to be the upper left corner of a box of two triangles
414 indices[indicesCount + 0] = offset;
415 indices[indicesCount + 1] = offset + 1;
416 indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
417 indices[indicesCount + 3] = offset + 1;
418 indices[indicesCount + 4] = offset + meshX + 2;
419 indices[indicesCount + 5] = offset + meshX + 1;
420 indicesCount += 6;
421 }
422 }
423
424 ret = true;
425 }
426 catch (Exception e)
427 {
428 if (physicsScene != null)
429 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
430 LogHeader, physicsScene.RegionName, extentBase, e);
431 }
432
433 indicesCountO = indicesCount;
434 indicesO = indices;
435 verticesCountO = verticesCount;
436 verticesO = vertices;
437
438 return ret;
439 }
440}
441}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
new file mode 100755
index 0000000..5932461
--- /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.Physics.BulletSPlugin
33{
34// Classes to allow some type checking for the API
35// These hold pointers to allocated objects in the unmanaged space.
36// These classes are subclassed by the various physical implementations of
37// objects. In particular, there is a version for physical instances in
38// unmanaged memory ("unman") and one for in managed memory ("XNA").
39
40// Currently, the instances of these classes are a reference to a
41// physical representation and this has no releationship to other
42// instances. Someday, refarb the usage of these classes so each instance
43// refers to a particular physical instance and this class controls reference
44// counts and such. This should be done along with adding BSShapes.
45
46public class BulletWorld
47{
48 public BulletWorld(uint worldId, BSScene bss)
49 {
50 worldID = worldId;
51 physicsScene = bss;
52 }
53 public uint worldID;
54 // The scene is only in here so very low level routines have a handle to print debug/error messages
55 public BSScene physicsScene;
56}
57
58// An allocated Bullet btRigidBody
59public class BulletBody
60{
61 public BulletBody(uint id)
62 {
63 ID = id;
64 collisionType = CollisionType.Static;
65 }
66 public uint ID;
67 public CollisionType collisionType;
68
69 public virtual void Clear() { }
70 public virtual bool HasPhysicalBody { get { return false; } }
71
72 // Apply the specificed collision mask into the physical world
73 public virtual bool ApplyCollisionMask(BSScene physicsScene)
74 {
75 // Should assert the body has been added to the physical world.
76 // (The collision masks are stored in the collision proxy cache which only exists for
77 // a collision body that is in the world.)
78 return physicsScene.PE.SetCollisionGroupMask(this,
79 BulletSimData.CollisionTypeMasks[collisionType].group,
80 BulletSimData.CollisionTypeMasks[collisionType].mask);
81 }
82
83 // Used for log messages for a unique display of the memory/object allocated to this instance
84 public virtual string AddrString
85 {
86 get { return "unknown"; }
87 }
88
89 public override string ToString()
90 {
91 StringBuilder buff = new StringBuilder();
92 buff.Append("<id=");
93 buff.Append(ID.ToString());
94 buff.Append(",p=");
95 buff.Append(AddrString);
96 buff.Append(",c=");
97 buff.Append(collisionType);
98 buff.Append(">");
99 return buff.ToString();
100 }
101}
102
103public class BulletShape
104{
105 public BulletShape()
106 {
107 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/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..4f90eee
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.Physics.BulletSPlugin")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("520ea11b-20cb-449d-ba05-c01015fed841")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.8.2.*")]
33
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs
new file mode 100755
index 0000000..48e74eb
--- /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.Physics.BulletSPlugin;
38using OpenSim.Region.Physics.Manager;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.Physics.BulletSPlugin.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..35cbc1d
--- /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.Physics.BulletSPlugin.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..775bca2
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs
@@ -0,0 +1,100 @@
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.Physics.Manager;
37using OpenSim.Region.Physics.Meshing;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin.Tests
42{
43// Utility functions for building up and tearing down the sample physics environments
44public static class BulletSimTestsUtil
45{
46 // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA"
47 // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults)
48 // May be 'null' if there are no overrides.
49 public static BSScene CreateBasicPhysicsEngine(Dictionary<string,string> paramOverrides)
50 {
51 IConfigSource openSimINI = new IniConfigSource();
52 IConfig startupConfig = openSimINI.AddConfig("Startup");
53 startupConfig.Set("physics", "BulletSim");
54 startupConfig.Set("meshing", "Meshmerizer");
55 startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps
56
57 IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim");
58 // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged".
59 // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged");
60 // bulletSimConfig.Set("BulletEngine", "BulletXNA");
61 bulletSimConfig.Set("MeshSculptedPrim", "false");
62 bulletSimConfig.Set("ForceSimplePrimMeshing", "true");
63 if (paramOverrides != null)
64 {
65 foreach (KeyValuePair<string, string> kvp in paramOverrides)
66 {
67 bulletSimConfig.Set(kvp.Key, kvp.Value);
68 }
69 }
70
71 // If a special directory exists, put detailed logging therein.
72 // This allows local testing/debugging without having to worry that the build engine will output logs.
73 if (Directory.Exists("physlogs"))
74 {
75 bulletSimConfig.Set("PhysicsLoggingDir","./physlogs");
76 bulletSimConfig.Set("PhysicsLoggingEnabled","True");
77 bulletSimConfig.Set("PhysicsLoggingDoFlush","True");
78 bulletSimConfig.Set("VehicleLoggingEnabled","True");
79 }
80
81 PhysicsPluginManager physicsPluginManager;
82 physicsPluginManager = new PhysicsPluginManager();
83 physicsPluginManager.LoadPluginsFromAssemblies("Physics");
84
85 Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
86
87 PhysicsScene pScene = physicsPluginManager.GetPhysicsScene(
88 "BulletSim", "Meshmerizer", openSimINI, "BSTestRegion", regionExtent);
89
90 BSScene bsScene = pScene as BSScene;
91
92 // Since the asset requestor is not initialized, any mesh or sculptie will be a cube.
93 // In the future, add a fake asset fetcher to get meshes and sculpts.
94 // bsScene.RequestAssetMethod = ???;
95
96 return bsScene;
97 }
98
99}
100}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs
new file mode 100644
index 0000000..5a5de11
--- /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.Physics.BulletSPlugin;
38using OpenSim.Region.Physics.Manager;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.Physics.BulletSPlugin.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..4d84c44
--- /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.Physics.ConvexDecompositionDotNet
32{
33 public class Wpoint
34 {
35 public float3 mPoint;
36 public float mWeight;
37
38 public Wpoint(float3 p, float w)
39 {
40 mPoint = p;
41 mWeight = w;
42 }
43 }
44
45 public class CTri
46 {
47 private const int WSCALE = 4;
48
49 public float3 mP1;
50 public float3 mP2;
51 public float3 mP3;
52 public float3 mNear1;
53 public float3 mNear2;
54 public float3 mNear3;
55 public float3 mNormal;
56 public float mPlaneD;
57 public float mConcavity;
58 public float mC1;
59 public float mC2;
60 public float mC3;
61 public int mI1;
62 public int mI2;
63 public int mI3;
64 public int mProcessed; // already been added...
65
66 public CTri(float3 p1, float3 p2, float3 p3, int i1, int i2, int i3)
67 {
68 mProcessed = 0;
69 mI1 = i1;
70 mI2 = i2;
71 mI3 = i3;
72
73 mP1 = new float3(p1);
74 mP2 = new float3(p2);
75 mP3 = new float3(p3);
76
77 mNear1 = new float3();
78 mNear2 = new float3();
79 mNear3 = new float3();
80
81 mNormal = new float3();
82 mPlaneD = mNormal.ComputePlane(mP1, mP2, mP3);
83 }
84
85 public float Facing(CTri t)
86 {
87 return float3.dot(mNormal, t.mNormal);
88 }
89
90 public bool clip(float3 start, ref float3 end)
91 {
92 float3 sect = new float3();
93 bool hit = lineIntersectsTriangle(start, end, mP1, mP2, mP3, ref sect);
94
95 if (hit)
96 end = sect;
97 return hit;
98 }
99
100 public bool Concave(float3 p, ref float distance, ref float3 n)
101 {
102 n.NearestPointInTriangle(p, mP1, mP2, mP3);
103 distance = p.Distance(n);
104 return true;
105 }
106
107 public void addTri(int[] indices, int i1, int i2, int i3, ref int tcount)
108 {
109 indices[tcount * 3 + 0] = i1;
110 indices[tcount * 3 + 1] = i2;
111 indices[tcount * 3 + 2] = i3;
112 tcount++;
113 }
114
115 public float getVolume()
116 {
117 int[] indices = new int[8 * 3];
118
119 int tcount = 0;
120
121 addTri(indices, 0, 1, 2, ref tcount);
122 addTri(indices, 3, 4, 5, ref tcount);
123
124 addTri(indices, 0, 3, 4, ref tcount);
125 addTri(indices, 0, 4, 1, ref tcount);
126
127 addTri(indices, 1, 4, 5, ref tcount);
128 addTri(indices, 1, 5, 2, ref tcount);
129
130 addTri(indices, 0, 3, 5, ref tcount);
131 addTri(indices, 0, 5, 2, ref tcount);
132
133 List<float3> vertices = new List<float3> { mP1, mP2, mP3, mNear1, mNear2, mNear3 };
134 List<int> indexList = new List<int>(indices);
135
136 float v = Concavity.computeMeshVolume(vertices, indexList);
137 return v;
138 }
139
140 public float raySect(float3 p, float3 dir, ref float3 sect)
141 {
142 float4 plane = new float4();
143
144 plane.x = mNormal.x;
145 plane.y = mNormal.y;
146 plane.z = mNormal.z;
147 plane.w = mPlaneD;
148
149 float3 dest = p + dir * 100000f;
150
151 intersect(p, dest, ref sect, plane);
152
153 return sect.Distance(p); // return the intersection distance
154 }
155
156 public float planeDistance(float3 p)
157 {
158 float4 plane = new float4();
159
160 plane.x = mNormal.x;
161 plane.y = mNormal.y;
162 plane.z = mNormal.z;
163 plane.w = mPlaneD;
164
165 return DistToPt(p, plane);
166 }
167
168 public bool samePlane(CTri t)
169 {
170 const float THRESH = 0.001f;
171 float dd = Math.Abs(t.mPlaneD - mPlaneD);
172 if (dd > THRESH)
173 return false;
174 dd = Math.Abs(t.mNormal.x - mNormal.x);
175 if (dd > THRESH)
176 return false;
177 dd = Math.Abs(t.mNormal.y - mNormal.y);
178 if (dd > THRESH)
179 return false;
180 dd = Math.Abs(t.mNormal.z - mNormal.z);
181 if (dd > THRESH)
182 return false;
183 return true;
184 }
185
186 public bool hasIndex(int i)
187 {
188 if (i == mI1 || i == mI2 || i == mI3)
189 return true;
190 return false;
191 }
192
193 public bool sharesEdge(CTri t)
194 {
195 bool ret = false;
196 uint count = 0;
197
198 if (t.hasIndex(mI1))
199 count++;
200 if (t.hasIndex(mI2))
201 count++;
202 if (t.hasIndex(mI3))
203 count++;
204
205 if (count >= 2)
206 ret = true;
207
208 return ret;
209 }
210
211 public float area()
212 {
213 float a = mConcavity * mP1.Area(mP2, mP3);
214 return a;
215 }
216
217 public void addWeighted(List<Wpoint> list)
218 {
219 Wpoint p1 = new Wpoint(mP1, mC1);
220 Wpoint p2 = new Wpoint(mP2, mC2);
221 Wpoint p3 = new Wpoint(mP3, mC3);
222
223 float3 d1 = mNear1 - mP1;
224 float3 d2 = mNear2 - mP2;
225 float3 d3 = mNear3 - mP3;
226
227 d1 *= WSCALE;
228 d2 *= WSCALE;
229 d3 *= WSCALE;
230
231 d1 = d1 + mP1;
232 d2 = d2 + mP2;
233 d3 = d3 + mP3;
234
235 Wpoint p4 = new Wpoint(d1, mC1);
236 Wpoint p5 = new Wpoint(d2, mC2);
237 Wpoint p6 = new Wpoint(d3, mC3);
238
239 list.Add(p1);
240 list.Add(p2);
241 list.Add(p3);
242
243 list.Add(p4);
244 list.Add(p5);
245 list.Add(p6);
246 }
247
248 private static float DistToPt(float3 p, float4 plane)
249 {
250 float x = p.x;
251 float y = p.y;
252 float z = p.z;
253 float d = x*plane.x + y*plane.y + z*plane.z + plane.w;
254 return d;
255 }
256
257 private static void intersect(float3 p1, float3 p2, ref float3 split, float4 plane)
258 {
259 float dp1 = DistToPt(p1, plane);
260
261 float3 dir = new float3();
262 dir.x = p2[0] - p1[0];
263 dir.y = p2[1] - p1[1];
264 dir.z = p2[2] - p1[2];
265
266 float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2];
267 float dot2 = dp1 - plane[3];
268
269 float t = -(plane[3] + dot2) / dot1;
270
271 split.x = (dir[0] * t) + p1[0];
272 split.y = (dir[1] * t) + p1[1];
273 split.z = (dir[2] * t) + p1[2];
274 }
275
276 private static bool rayIntersectsTriangle(float3 p, float3 d, float3 v0, float3 v1, float3 v2, out float t)
277 {
278 t = 0f;
279
280 float3 e1, e2, h, s, q;
281 float a, f, u, v;
282
283 e1 = v1 - v0;
284 e2 = v2 - v0;
285 h = float3.cross(d, e2);
286 a = float3.dot(e1, h);
287
288 if (a > -0.00001f && a < 0.00001f)
289 return false;
290
291 f = 1f / a;
292 s = p - v0;
293 u = f * float3.dot(s, h);
294
295 if (u < 0.0f || u > 1.0f)
296 return false;
297
298 q = float3.cross(s, e1);
299 v = f * float3.dot(d, q);
300 if (v < 0.0f || u + v > 1.0f)
301 return false;
302
303 // at this stage we can compute t to find out where
304 // the intersection point is on the line
305 t = f * float3.dot(e2, q);
306 if (t > 0f) // ray intersection
307 return true;
308 else // this means that there is a line intersection but not a ray intersection
309 return false;
310 }
311
312 private static bool lineIntersectsTriangle(float3 rayStart, float3 rayEnd, float3 p1, float3 p2, float3 p3, ref float3 sect)
313 {
314 float3 dir = rayEnd - rayStart;
315
316 float d = (float)Math.Sqrt(dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2]);
317 float r = 1.0f / d;
318
319 dir *= r;
320
321 float t;
322 bool ret = rayIntersectsTriangle(rayStart, dir, p1, p2, p3, out t);
323
324 if (ret)
325 {
326 if (t > d)
327 {
328 sect.x = rayStart.x + dir.x * t;
329 sect.y = rayStart.y + dir.y * t;
330 sect.z = rayStart.z + dir.z * t;
331 }
332 else
333 {
334 ret = false;
335 }
336 }
337
338 return ret;
339 }
340 }
341}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs
new file mode 100644
index 0000000..cc6383a
--- /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.Physics.ConvexDecompositionDotNet
33{
34 public static class Concavity
35 {
36 // compute's how 'concave' this object is and returns the total volume of the
37 // convex hull as well as the volume of the 'concavity' which was found.
38 public static float computeConcavity(List<float3> vertices, List<int> indices, ref float4 plane, ref float volume)
39 {
40 float cret = 0f;
41 volume = 1f;
42
43 HullResult result = new HullResult();
44 HullDesc desc = new HullDesc();
45
46 desc.MaxFaces = 256;
47 desc.MaxVertices = 256;
48 desc.SetHullFlag(HullFlag.QF_TRIANGLES);
49 desc.Vertices = vertices;
50
51 HullError ret = HullUtils.CreateConvexHull(desc, ref result);
52
53 if (ret == HullError.QE_OK)
54 {
55 volume = computeMeshVolume2(result.OutputVertices, result.Indices);
56
57 // ok..now..for each triangle on the original mesh..
58 // we extrude the points to the nearest point on the hull.
59 List<CTri> tris = new List<CTri>();
60
61 for (int i = 0; i < result.Indices.Count / 3; i++)
62 {
63 int i1 = result.Indices[i * 3 + 0];
64 int i2 = result.Indices[i * 3 + 1];
65 int i3 = result.Indices[i * 3 + 2];
66
67 float3 p1 = result.OutputVertices[i1];
68 float3 p2 = result.OutputVertices[i2];
69 float3 p3 = result.OutputVertices[i3];
70
71 CTri t = new CTri(p1, p2, p3, i1, i2, i3);
72 tris.Add(t);
73 }
74
75 // we have not pre-computed the plane equation for each triangle in the convex hull..
76 float totalVolume = 0;
77
78 List<CTri> ftris = new List<CTri>(); // 'feature' triangles.
79 List<CTri> input_mesh = new List<CTri>();
80
81 for (int i = 0; i < indices.Count / 3; i++)
82 {
83 int i1 = indices[i * 3 + 0];
84 int i2 = indices[i * 3 + 1];
85 int i3 = indices[i * 3 + 2];
86
87 float3 p1 = vertices[i1];
88 float3 p2 = vertices[i2];
89 float3 p3 = vertices[i3];
90
91 CTri t = new CTri(p1, p2, p3, i1, i2, i3);
92 input_mesh.Add(t);
93 }
94
95 for (int i = 0; i < indices.Count / 3; i++)
96 {
97 int i1 = indices[i * 3 + 0];
98 int i2 = indices[i * 3 + 1];
99 int i3 = indices[i * 3 + 2];
100
101 float3 p1 = vertices[i1];
102 float3 p2 = vertices[i2];
103 float3 p3 = vertices[i3];
104
105 CTri t = new CTri(p1, p2, p3, i1, i2, i3);
106
107 featureMatch(t, tris, input_mesh);
108
109 if (t.mConcavity > 0.05f)
110 {
111 float v = t.getVolume();
112 totalVolume += v;
113 ftris.Add(t);
114 }
115 }
116
117 SplitPlane.computeSplitPlane(vertices, indices, ref plane);
118 cret = totalVolume;
119 }
120
121 return cret;
122 }
123
124 public static bool featureMatch(CTri m, List<CTri> tris, List<CTri> input_mesh)
125 {
126 bool ret = false;
127 float neardot = 0.707f;
128 m.mConcavity = 0;
129
130 for (int i = 0; i < tris.Count; i++)
131 {
132 CTri t = tris[i];
133
134 if (t.samePlane(m))
135 {
136 ret = false;
137 break;
138 }
139
140 float dot = float3.dot(t.mNormal, m.mNormal);
141
142 if (dot > neardot)
143 {
144 float d1 = t.planeDistance(m.mP1);
145 float d2 = t.planeDistance(m.mP2);
146 float d3 = t.planeDistance(m.mP3);
147
148 if (d1 > 0.001f || d2 > 0.001f || d3 > 0.001f) // can't be near coplaner!
149 {
150 neardot = dot;
151
152 t.raySect(m.mP1, m.mNormal, ref m.mNear1);
153 t.raySect(m.mP2, m.mNormal, ref m.mNear2);
154 t.raySect(m.mP3, m.mNormal, ref m.mNear3);
155
156 ret = true;
157 }
158 }
159 }
160
161 if (ret)
162 {
163 m.mC1 = m.mP1.Distance(m.mNear1);
164 m.mC2 = m.mP2.Distance(m.mNear2);
165 m.mC3 = m.mP3.Distance(m.mNear3);
166
167 m.mConcavity = m.mC1;
168
169 if (m.mC2 > m.mConcavity)
170 m.mConcavity = m.mC2;
171 if (m.mC3 > m.mConcavity)
172 m.mConcavity = m.mC3;
173 }
174
175 return ret;
176 }
177
178 private static float det(float3 p1, float3 p2, float3 p3)
179 {
180 return p1.x * p2.y * p3.z + p2.x * p3.y * p1.z + p3.x * p1.y * p2.z - p1.x * p3.y * p2.z - p2.x * p1.y * p3.z - p3.x * p2.y * p1.z;
181 }
182
183 public static float computeMeshVolume(List<float3> vertices, List<int> indices)
184 {
185 float volume = 0f;
186
187 for (int i = 0; i < indices.Count / 3; i++)
188 {
189 float3 p1 = vertices[indices[i * 3 + 0]];
190 float3 p2 = vertices[indices[i * 3 + 1]];
191 float3 p3 = vertices[indices[i * 3 + 2]];
192
193 volume += det(p1, p2, p3); // compute the volume of the tetrahedran relative to the origin.
194 }
195
196 volume *= (1.0f / 6.0f);
197 if (volume < 0f)
198 return -volume;
199 return volume;
200 }
201
202 public static float computeMeshVolume2(List<float3> vertices, List<int> indices)
203 {
204 float volume = 0f;
205
206 float3 p0 = vertices[0];
207 for (int i = 0; i < indices.Count / 3; i++)
208 {
209 float3 p1 = vertices[indices[i * 3 + 0]];
210 float3 p2 = vertices[indices[i * 3 + 1]];
211 float3 p3 = vertices[indices[i * 3 + 2]];
212
213 volume += tetVolume(p0, p1, p2, p3); // compute the volume of the tetrahedron relative to the root vertice
214 }
215
216 return volume * (1.0f / 6.0f);
217 }
218
219 private static float tetVolume(float3 p0, float3 p1, float3 p2, float3 p3)
220 {
221 float3 a = p1 - p0;
222 float3 b = p2 - p0;
223 float3 c = p3 - p0;
224
225 float3 cross = float3.cross(b, c);
226 float volume = float3.dot(a, cross);
227
228 if (volume < 0f)
229 return -volume;
230 return volume;
231 }
232 }
233}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs
new file mode 100644
index 0000000..dfaede1
--- /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.Physics.ConvexDecompositionDotNet
33{
34 public class DecompDesc
35 {
36 public List<float3> mVertices;
37 public List<int> mIndices;
38
39 // options
40 public uint mDepth; // depth to split, a maximum of 10, generally not over 7.
41 public float mCpercent; // the concavity threshold percentage. 0=20 is reasonable.
42 public float mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable.
43
44 // hull output limits.
45 public uint mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less.
46 public float mSkinWidth; // a skin width to apply to the output hulls.
47
48 public ConvexDecompositionCallback mCallback; // the interface to receive back the results.
49
50 public DecompDesc()
51 {
52 mDepth = 5;
53 mCpercent = 5;
54 mPpercent = 5;
55 mMaxVertices = 32;
56 }
57 }
58
59 public class CHull
60 {
61 public float[] mMin = new float[3];
62 public float[] mMax = new float[3];
63 public float mVolume;
64 public float mDiagonal;
65 public ConvexResult mResult;
66
67 public CHull(ConvexResult result)
68 {
69 mResult = new ConvexResult(result);
70 mVolume = Concavity.computeMeshVolume(result.HullVertices, result.HullIndices);
71
72 mDiagonal = getBoundingRegion(result.HullVertices, mMin, mMax);
73
74 float dx = mMax[0] - mMin[0];
75 float dy = mMax[1] - mMin[1];
76 float dz = mMax[2] - mMin[2];
77
78 dx *= 0.1f; // inflate 1/10th on each edge
79 dy *= 0.1f; // inflate 1/10th on each edge
80 dz *= 0.1f; // inflate 1/10th on each edge
81
82 mMin[0] -= dx;
83 mMin[1] -= dy;
84 mMin[2] -= dz;
85
86 mMax[0] += dx;
87 mMax[1] += dy;
88 mMax[2] += dz;
89 }
90
91 public void Dispose()
92 {
93 mResult = null;
94 }
95
96 public bool overlap(CHull h)
97 {
98 return overlapAABB(mMin, mMax, h.mMin, h.mMax);
99 }
100
101 // returns the d1Giagonal distance
102 private static float getBoundingRegion(List<float3> points, float[] bmin, float[] bmax)
103 {
104 float3 first = points[0];
105
106 bmin[0] = first.x;
107 bmin[1] = first.y;
108 bmin[2] = first.z;
109
110 bmax[0] = first.x;
111 bmax[1] = first.y;
112 bmax[2] = first.z;
113
114 for (int i = 1; i < points.Count; i++)
115 {
116 float3 p = points[i];
117
118 if (p[0] < bmin[0]) bmin[0] = p[0];
119 if (p[1] < bmin[1]) bmin[1] = p[1];
120 if (p[2] < bmin[2]) bmin[2] = p[2];
121
122 if (p[0] > bmax[0]) bmax[0] = p[0];
123 if (p[1] > bmax[1]) bmax[1] = p[1];
124 if (p[2] > bmax[2]) bmax[2] = p[2];
125 }
126
127 float dx = bmax[0] - bmin[0];
128 float dy = bmax[1] - bmin[1];
129 float dz = bmax[2] - bmin[2];
130
131 return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
132 }
133
134 // return true if the two AABB's overlap.
135 private static bool overlapAABB(float[] bmin1, float[] bmax1, float[] bmin2, float[] bmax2)
136 {
137 if (bmax2[0] < bmin1[0]) return false; // if the maximum is less than our minimum on any axis
138 if (bmax2[1] < bmin1[1]) return false;
139 if (bmax2[2] < bmin1[2]) return false;
140
141 if (bmin2[0] > bmax1[0]) return false; // if the minimum is greater than our maximum on any axis
142 if (bmin2[1] > bmax1[1]) return false; // if the minimum is greater than our maximum on any axis
143 if (bmin2[2] > bmax1[2]) return false; // if the minimum is greater than our maximum on any axis
144
145 return true; // the extents overlap
146 }
147 }
148
149 public class ConvexBuilder
150 {
151 public List<CHull> mChulls = new List<CHull>();
152 private ConvexDecompositionCallback mCallback;
153
154 private int MAXDEPTH = 8;
155 private float CONCAVE_PERCENT = 1f;
156 private float MERGE_PERCENT = 2f;
157
158 public ConvexBuilder(ConvexDecompositionCallback callback)
159 {
160 mCallback = callback;
161 }
162
163 public void Dispose()
164 {
165 int i;
166 for (i = 0; i < mChulls.Count; i++)
167 {
168 CHull cr = mChulls[i];
169 cr.Dispose();
170 }
171 }
172
173 public bool isDuplicate(uint i1, uint i2, uint i3, uint ci1, uint ci2, uint ci3)
174 {
175 uint dcount = 0;
176
177 Debug.Assert(i1 != i2 && i1 != i3 && i2 != i3);
178 Debug.Assert(ci1 != ci2 && ci1 != ci3 && ci2 != ci3);
179
180 if (i1 == ci1 || i1 == ci2 || i1 == ci3)
181 dcount++;
182 if (i2 == ci1 || i2 == ci2 || i2 == ci3)
183 dcount++;
184 if (i3 == ci1 || i3 == ci2 || i3 == ci3)
185 dcount++;
186
187 return dcount == 3;
188 }
189
190 public void getMesh(ConvexResult cr, VertexPool vc, List<int> indices)
191 {
192 List<int> src = cr.HullIndices;
193
194 for (int i = 0; i < src.Count / 3; i++)
195 {
196 int i1 = src[i * 3 + 0];
197 int i2 = src[i * 3 + 1];
198 int i3 = src[i * 3 + 2];
199
200 float3 p1 = cr.HullVertices[i1];
201 float3 p2 = cr.HullVertices[i2];
202 float3 p3 = cr.HullVertices[i3];
203
204 i1 = vc.getIndex(p1);
205 i2 = vc.getIndex(p2);
206 i3 = vc.getIndex(p3);
207 }
208 }
209
210 public CHull canMerge(CHull a, CHull b)
211 {
212 if (!a.overlap(b)) // if their AABB's (with a little slop) don't overlap, then return.
213 return null;
214
215 CHull ret = null;
216
217 // ok..we are going to combine both meshes into a single mesh
218 // and then we are going to compute the concavity...
219
220 VertexPool vc = new VertexPool();
221
222 List<int> indices = new List<int>();
223
224 getMesh(a.mResult, vc, indices);
225 getMesh(b.mResult, vc, indices);
226
227 int vcount = vc.GetSize();
228 List<float3> vertices = vc.GetVertices();
229 int tcount = indices.Count / 3;
230
231 //don't do anything if hull is empty
232 if (tcount == 0)
233 {
234 vc.Clear();
235 return null;
236 }
237
238 HullResult hresult = new HullResult();
239 HullDesc desc = new HullDesc();
240
241 desc.SetHullFlag(HullFlag.QF_TRIANGLES);
242 desc.Vertices = vertices;
243
244 HullError hret = HullUtils.CreateConvexHull(desc, ref hresult);
245
246 if (hret == HullError.QE_OK)
247 {
248 float combineVolume = Concavity.computeMeshVolume(hresult.OutputVertices, hresult.Indices);
249 float sumVolume = a.mVolume + b.mVolume;
250
251 float percent = (sumVolume * 100) / combineVolume;
252 if (percent >= (100.0f - MERGE_PERCENT))
253 {
254 ConvexResult cr = new ConvexResult(hresult.OutputVertices, hresult.Indices);
255 ret = new CHull(cr);
256 }
257 }
258
259 vc.Clear();
260 return ret;
261 }
262
263 public bool combineHulls()
264 {
265 bool combine = false;
266
267 sortChulls(mChulls); // sort the convex hulls, largest volume to least...
268
269 List<CHull> output = new List<CHull>(); // the output hulls...
270
271 int i;
272 for (i = 0; i < mChulls.Count && !combine; ++i)
273 {
274 CHull cr = mChulls[i];
275
276 int j;
277 for (j = 0; j < mChulls.Count; j++)
278 {
279 CHull match = mChulls[j];
280
281 if (cr != match) // don't try to merge a hull with itself, that be stoopid
282 {
283
284 CHull merge = canMerge(cr, match); // if we can merge these two....
285
286 if (merge != null)
287 {
288 output.Add(merge);
289
290 ++i;
291 while (i != mChulls.Count)
292 {
293 CHull cr2 = mChulls[i];
294 if (cr2 != match)
295 {
296 output.Add(cr2);
297 }
298 i++;
299 }
300
301 cr.Dispose();
302 match.Dispose();
303 combine = true;
304 break;
305 }
306 }
307 }
308
309 if (combine)
310 {
311 break;
312 }
313 else
314 {
315 output.Add(cr);
316 }
317 }
318
319 if (combine)
320 {
321 mChulls.Clear();
322 mChulls = output;
323 output.Clear();
324 }
325
326 return combine;
327 }
328
329 public int process(DecompDesc desc)
330 {
331 int ret = 0;
332
333 MAXDEPTH = (int)desc.mDepth;
334 CONCAVE_PERCENT = desc.mCpercent;
335 MERGE_PERCENT = desc.mPpercent;
336
337 ConvexDecomposition.calcConvexDecomposition(desc.mVertices, desc.mIndices, ConvexDecompResult, 0f, 0, MAXDEPTH, CONCAVE_PERCENT, MERGE_PERCENT);
338
339 while (combineHulls()) // keep combinging hulls until I can't combine any more...
340 ;
341
342 int i;
343 for (i = 0; i < mChulls.Count; i++)
344 {
345 CHull cr = mChulls[i];
346
347 // before we hand it back to the application, we need to regenerate the hull based on the
348 // limits given by the user.
349
350 ConvexResult c = cr.mResult; // the high resolution hull...
351
352 HullResult result = new HullResult();
353 HullDesc hdesc = new HullDesc();
354
355 hdesc.SetHullFlag(HullFlag.QF_TRIANGLES);
356
357 hdesc.Vertices = c.HullVertices;
358 hdesc.MaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output
359
360 if (desc.mSkinWidth != 0f)
361 {
362 hdesc.SkinWidth = desc.mSkinWidth;
363 hdesc.SetHullFlag(HullFlag.QF_SKIN_WIDTH); // do skin width computation.
364 }
365
366 HullError ret2 = HullUtils.CreateConvexHull(hdesc, ref result);
367
368 if (ret2 == HullError.QE_OK)
369 {
370 ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices);
371
372 r.mHullVolume = Concavity.computeMeshVolume(result.OutputVertices, result.Indices); // the volume of the hull.
373
374 // compute the best fit OBB
375 //computeBestFitOBB(result.mNumOutputVertices, result.mOutputVertices, sizeof(float) * 3, r.mOBBSides, r.mOBBTransform);
376
377 //r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] * r.mOBBSides[2]; // compute the OBB volume.
378
379 //fm_getTranslation(r.mOBBTransform, r.mOBBCenter); // get the translation component of the 4x4 matrix.
380
381 //fm_matrixToQuat(r.mOBBTransform, r.mOBBOrientation); // extract the orientation as a quaternion.
382
383 //r.mSphereRadius = computeBoundingSphere(result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter);
384 //r.mSphereVolume = fm_sphereVolume(r.mSphereRadius);
385
386 mCallback(r);
387 }
388
389 result = null;
390 cr.Dispose();
391 }
392
393 ret = mChulls.Count;
394
395 mChulls.Clear();
396
397 return ret;
398 }
399
400 public void ConvexDecompResult(ConvexResult result)
401 {
402 CHull ch = new CHull(result);
403 mChulls.Add(ch);
404 }
405
406 public void sortChulls(List<CHull> hulls)
407 {
408 hulls.Sort(delegate(CHull a, CHull b) { return a.mVolume.CompareTo(b.mVolume); });
409 }
410 }
411}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs
new file mode 100644
index 0000000..2e2bb70
--- /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.Physics.ConvexDecompositionDotNet
33{
34 public delegate void ConvexDecompositionCallback(ConvexResult result);
35
36 public class FaceTri
37 {
38 public float3 P1;
39 public float3 P2;
40 public float3 P3;
41
42 public FaceTri() { }
43
44 public FaceTri(List<float3> vertices, int i1, int i2, int i3)
45 {
46 P1 = new float3(vertices[i1]);
47 P2 = new float3(vertices[i2]);
48 P3 = new float3(vertices[i3]);
49 }
50 }
51
52 public static class ConvexDecomposition
53 {
54 private static void addTri(VertexPool vl, List<int> list, float3 p1, float3 p2, float3 p3)
55 {
56 int i1 = vl.getIndex(p1);
57 int i2 = vl.getIndex(p2);
58 int i3 = vl.getIndex(p3);
59
60 // do *not* process degenerate triangles!
61 if ( i1 != i2 && i1 != i3 && i2 != i3 )
62 {
63 list.Add(i1);
64 list.Add(i2);
65 list.Add(i3);
66 }
67 }
68
69 public static void calcConvexDecomposition(List<float3> vertices, List<int> indices, ConvexDecompositionCallback callback, float masterVolume, int depth,
70 int maxDepth, float concavePercent, float mergePercent)
71 {
72 float4 plane = new float4();
73 bool split = false;
74
75 if (depth < maxDepth)
76 {
77 float volume = 0f;
78 float c = Concavity.computeConcavity(vertices, indices, ref plane, ref volume);
79
80 if (depth == 0)
81 {
82 masterVolume = volume;
83 }
84
85 float percent = (c * 100.0f) / masterVolume;
86
87 if (percent > concavePercent) // if great than 5% of the total volume is concave, go ahead and keep splitting.
88 {
89 split = true;
90 }
91 }
92
93 if (depth >= maxDepth || !split)
94 {
95 HullResult result = new HullResult();
96 HullDesc desc = new HullDesc();
97
98 desc.SetHullFlag(HullFlag.QF_TRIANGLES);
99
100 desc.Vertices = vertices;
101
102 HullError ret = HullUtils.CreateConvexHull(desc, ref result);
103
104 if (ret == HullError.QE_OK)
105 {
106 ConvexResult r = new ConvexResult(result.OutputVertices, result.Indices);
107 callback(r);
108 }
109
110 return;
111 }
112
113 List<int> ifront = new List<int>();
114 List<int> iback = new List<int>();
115
116 VertexPool vfront = new VertexPool();
117 VertexPool vback = new VertexPool();
118
119 // ok..now we are going to 'split' all of the input triangles against this plane!
120 for (int i = 0; i < indices.Count / 3; i++)
121 {
122 int i1 = indices[i * 3 + 0];
123 int i2 = indices[i * 3 + 1];
124 int i3 = indices[i * 3 + 2];
125
126 FaceTri t = new FaceTri(vertices, i1, i2, i3);
127
128 float3[] front = new float3[4];
129 float3[] back = new float3[4];
130
131 int fcount = 0;
132 int bcount = 0;
133
134 PlaneTriResult result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount);
135
136 if (fcount > 4 || bcount > 4)
137 {
138 result = PlaneTri.planeTriIntersection(plane, t, 0.00001f, ref front, out fcount, ref back, out bcount);
139 }
140
141 switch (result)
142 {
143 case PlaneTriResult.PTR_FRONT:
144 Debug.Assert(fcount == 3);
145 addTri(vfront, ifront, front[0], front[1], front[2]);
146 break;
147 case PlaneTriResult.PTR_BACK:
148 Debug.Assert(bcount == 3);
149 addTri(vback, iback, back[0], back[1], back[2]);
150 break;
151 case PlaneTriResult.PTR_SPLIT:
152 Debug.Assert(fcount >= 3 && fcount <= 4);
153 Debug.Assert(bcount >= 3 && bcount <= 4);
154
155 addTri(vfront, ifront, front[0], front[1], front[2]);
156 addTri(vback, iback, back[0], back[1], back[2]);
157
158 if (fcount == 4)
159 {
160 addTri(vfront, ifront, front[0], front[2], front[3]);
161 }
162
163 if (bcount == 4)
164 {
165 addTri(vback, iback, back[0], back[2], back[3]);
166 }
167
168 break;
169 }
170 }
171
172 // ok... here we recursively call
173 if (ifront.Count > 0)
174 {
175 int vcount = vfront.GetSize();
176 List<float3> vertices2 = vfront.GetVertices();
177 for (int i = 0; i < vertices2.Count; i++)
178 vertices2[i] = new float3(vertices2[i]);
179 int tcount = ifront.Count / 3;
180
181 calcConvexDecomposition(vertices2, ifront, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent);
182 }
183
184 ifront.Clear();
185 vfront.Clear();
186
187 if (iback.Count > 0)
188 {
189 int vcount = vback.GetSize();
190 List<float3> vertices2 = vback.GetVertices();
191 int tcount = iback.Count / 3;
192
193 calcConvexDecomposition(vertices2, iback, callback, masterVolume, depth + 1, maxDepth, concavePercent, mergePercent);
194 }
195
196 iback.Clear();
197 vback.Clear();
198 }
199 }
200}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs
new file mode 100644
index 0000000..87758b5
--- /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.Physics.ConvexDecompositionDotNet
32{
33 public class ConvexResult
34 {
35 public List<float3> HullVertices;
36 public List<int> HullIndices;
37
38 public float mHullVolume; // the volume of the convex hull.
39
40 //public float[] OBBSides = new float[3]; // the width, height and breadth of the best fit OBB
41 //public float[] OBBCenter = new float[3]; // the center of the OBB
42 //public float[] OBBOrientation = new float[4]; // the quaternion rotation of the OBB.
43 //public float[] OBBTransform = new float[16]; // the 4x4 transform of the OBB.
44 //public float OBBVolume; // the volume of the OBB
45
46 //public float SphereRadius; // radius and center of best fit sphere
47 //public float[] SphereCenter = new float[3];
48 //public float SphereVolume; // volume of the best fit sphere
49
50 public ConvexResult()
51 {
52 HullVertices = new List<float3>();
53 HullIndices = new List<int>();
54 }
55
56 public ConvexResult(List<float3> hvertices, List<int> hindices)
57 {
58 HullVertices = hvertices;
59 HullIndices = hindices;
60 }
61
62 public ConvexResult(ConvexResult r)
63 {
64 HullVertices = new List<float3>(r.HullVertices);
65 HullIndices = new List<int>(r.HullIndices);
66 }
67
68 public void Dispose()
69 {
70 HullVertices = null;
71 HullIndices = null;
72 }
73 }
74}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs
new file mode 100644
index 0000000..d81df26
--- /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.Physics.ConvexDecompositionDotNet
32{
33 public class HullResult
34 {
35 public bool Polygons = true; // true if indices represents polygons, false indices are triangles
36 public List<float3> OutputVertices = new List<float3>();
37 public List<int> Indices;
38
39 // If triangles, then indices are array indexes into the vertex list.
40 // If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc..
41 }
42
43 public class PHullResult
44 {
45 public List<float3> Vertices = new List<float3>();
46 public List<int> Indices = new List<int>();
47 }
48
49 [Flags]
50 public enum HullFlag : int
51 {
52 QF_DEFAULT = 0,
53 QF_TRIANGLES = (1 << 0), // report results as triangles, not polygons.
54 QF_SKIN_WIDTH = (1 << 2) // extrude hull based on this skin width
55 }
56
57 public enum HullError : int
58 {
59 QE_OK, // success!
60 QE_FAIL // failed.
61 }
62
63 public class HullDesc
64 {
65 public HullFlag Flags; // flags to use when generating the convex hull.
66 public List<float3> Vertices;
67 public float NormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on.
68 public float SkinWidth;
69 public uint MaxVertices; // maximum number of vertices to be considered for the hull!
70 public uint MaxFaces;
71
72 public HullDesc()
73 {
74 Flags = HullFlag.QF_DEFAULT;
75 Vertices = new List<float3>();
76 NormalEpsilon = 0.001f;
77 MaxVertices = 4096;
78 MaxFaces = 4096;
79 SkinWidth = 0.01f;
80 }
81
82 public HullDesc(HullFlag flags, List<float3> vertices)
83 {
84 Flags = flags;
85 Vertices = new List<float3>(vertices);
86 NormalEpsilon = 0.001f;
87 MaxVertices = 4096;
88 MaxFaces = 4096;
89 SkinWidth = 0.01f;
90 }
91
92 public bool HasHullFlag(HullFlag flag)
93 {
94 return (Flags & flag) != 0;
95 }
96
97 public void SetHullFlag(HullFlag flag)
98 {
99 Flags |= flag;
100 }
101
102 public void ClearHullFlag(HullFlag flag)
103 {
104 Flags &= ~flag;
105 }
106 }
107
108 public class ConvexH
109 {
110 public struct HalfEdge
111 {
112 public short ea; // the other half of the edge (index into edges list)
113 public byte v; // the vertex at the start of this edge (index into vertices list)
114 public byte p; // the facet on which this edge lies (index into facets list)
115
116 public HalfEdge(short _ea, byte _v, byte _p)
117 {
118 ea = _ea;
119 v = _v;
120 p = _p;
121 }
122
123 public HalfEdge(HalfEdge e)
124 {
125 ea = e.ea;
126 v = e.v;
127 p = e.p;
128 }
129 }
130
131 public List<float3> vertices = new List<float3>();
132 public List<HalfEdge> edges = new List<HalfEdge>();
133 public List<Plane> facets = new List<Plane>();
134
135 public ConvexH(int vertices_size, int edges_size, int facets_size)
136 {
137 vertices = new List<float3>(vertices_size);
138 edges = new List<HalfEdge>(edges_size);
139 facets = new List<Plane>(facets_size);
140 }
141 }
142
143 public class VertFlag
144 {
145 public byte planetest;
146 public byte junk;
147 public byte undermap;
148 public byte overmap;
149 }
150
151 public class EdgeFlag
152 {
153 public byte planetest;
154 public byte fixes;
155 public short undermap;
156 public short overmap;
157 }
158
159 public class PlaneFlag
160 {
161 public byte undermap;
162 public byte overmap;
163 }
164
165 public class Coplanar
166 {
167 public ushort ea;
168 public byte v0;
169 public byte v1;
170 }
171}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs
new file mode 100644
index 0000000..1119a75
--- /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.Physics.ConvexDecompositionDotNet
33{
34 public class HullTriangle : int3
35 {
36 public int3 n = new int3();
37 public int id;
38 public int vmax;
39 public float rise;
40 private List<HullTriangle> tris;
41
42 public HullTriangle(int a, int b, int c, List<HullTriangle> tris)
43 : base(a, b, c)
44 {
45 this.tris = tris;
46
47 n = new int3(-1, -1, -1);
48 id = tris.Count;
49 tris.Add(this);
50 vmax = -1;
51 rise = 0.0f;
52 }
53
54 public void Dispose()
55 {
56 Debug.Assert(tris[id] == this);
57 tris[id] = null;
58 }
59
60 public int neib(int a, int b)
61 {
62 int i;
63
64 for (i = 0; i < 3; i++)
65 {
66 int i1 = (i + 1) % 3;
67 int i2 = (i + 2) % 3;
68 if ((this)[i] == a && (this)[i1] == b)
69 return n[i2];
70 if ((this)[i] == b && (this)[i1] == a)
71 return n[i2];
72 }
73
74 Debug.Assert(false);
75 return -1;
76 }
77
78 public void setneib(int a, int b, int value)
79 {
80 int i;
81
82 for (i = 0; i < 3; i++)
83 {
84 int i1 = (i + 1) % 3;
85 int i2 = (i + 2) % 3;
86 if ((this)[i] == a && (this)[i1] == b)
87 {
88 n[i2] = value;
89 return;
90 }
91 if ((this)[i] == b && (this)[i1] == a)
92 {
93 n[i2] = value;
94 return;
95 }
96 }
97 }
98 }
99}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs
new file mode 100644
index 0000000..c9ccfe2
--- /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.Physics.ConvexDecompositionDotNet
33{
34 public static class HullUtils
35 {
36 public static int argmin(float[] a, int n)
37 {
38 int r = 0;
39 for (int i = 1; i < n; i++)
40 {
41 if (a[i] < a[r])
42 {
43 r = i;
44 }
45 }
46 return r;
47 }
48
49 public static float clampf(float a)
50 {
51 return Math.Min(1.0f, Math.Max(0.0f, a));
52 }
53
54 public static float Round(float a, float precision)
55 {
56 return (float)Math.Floor(0.5f + a / precision) * precision;
57 }
58
59 public static float Interpolate(float f0, float f1, float alpha)
60 {
61 return f0 * (1 - alpha) + f1 * alpha;
62 }
63
64 public static void Swap<T>(ref T a, ref T b)
65 {
66 T tmp = a;
67 a = b;
68 b = tmp;
69 }
70
71 public static bool above(List<float3> vertices, int3 t, float3 p, float epsilon)
72 {
73 float3 vtx = vertices[t.x];
74 float3 n = TriNormal(vtx, vertices[t.y], vertices[t.z]);
75 return (float3.dot(n, p - vtx) > epsilon); // EPSILON???
76 }
77
78 public static int hasedge(int3 t, int a, int b)
79 {
80 for (int i = 0; i < 3; i++)
81 {
82 int i1 = (i + 1) % 3;
83 if (t[i] == a && t[i1] == b)
84 return 1;
85 }
86 return 0;
87 }
88
89 public static bool hasvert(int3 t, int v)
90 {
91 return (t[0] == v || t[1] == v || t[2] == v);
92 }
93
94 public static int shareedge(int3 a, int3 b)
95 {
96 int i;
97 for (i = 0; i < 3; i++)
98 {
99 int i1 = (i + 1) % 3;
100 if (hasedge(a, b[i1], b[i]) != 0)
101 return 1;
102 }
103 return 0;
104 }
105
106 public static void b2bfix(HullTriangle s, HullTriangle t, List<HullTriangle> tris)
107 {
108 int i;
109 for (i = 0; i < 3; i++)
110 {
111 int i1 = (i + 1) % 3;
112 int i2 = (i + 2) % 3;
113 int a = (s)[i1];
114 int b = (s)[i2];
115 Debug.Assert(tris[s.neib(a, b)].neib(b, a) == s.id);
116 Debug.Assert(tris[t.neib(a, b)].neib(b, a) == t.id);
117 tris[s.neib(a, b)].setneib(b, a, t.neib(b, a));
118 tris[t.neib(b, a)].setneib(a, b, s.neib(a, b));
119 }
120 }
121
122 public static void removeb2b(HullTriangle s, HullTriangle t, List<HullTriangle> tris)
123 {
124 b2bfix(s, t, tris);
125 s.Dispose();
126 t.Dispose();
127 }
128
129 public static void checkit(HullTriangle t, List<HullTriangle> tris)
130 {
131 int i;
132 Debug.Assert(tris[t.id] == t);
133 for (i = 0; i < 3; i++)
134 {
135 int i1 = (i + 1) % 3;
136 int i2 = (i + 2) % 3;
137 int a = (t)[i1];
138 int b = (t)[i2];
139 Debug.Assert(a != b);
140 Debug.Assert(tris[t.n[i]].neib(b, a) == t.id);
141 }
142 }
143
144 public static void extrude(HullTriangle t0, int v, List<HullTriangle> tris)
145 {
146 int3 t = t0;
147 int n = tris.Count;
148 HullTriangle ta = new HullTriangle(v, t[1], t[2], tris);
149 ta.n = new int3(t0.n[0], n + 1, n + 2);
150 tris[t0.n[0]].setneib(t[1], t[2], n + 0);
151 HullTriangle tb = new HullTriangle(v, t[2], t[0], tris);
152 tb.n = new int3(t0.n[1], n + 2, n + 0);
153 tris[t0.n[1]].setneib(t[2], t[0], n + 1);
154 HullTriangle tc = new HullTriangle(v, t[0], t[1], tris);
155 tc.n = new int3(t0.n[2], n + 0, n + 1);
156 tris[t0.n[2]].setneib(t[0], t[1], n + 2);
157 checkit(ta, tris);
158 checkit(tb, tris);
159 checkit(tc, tris);
160 if (hasvert(tris[ta.n[0]], v))
161 removeb2b(ta, tris[ta.n[0]], tris);
162 if (hasvert(tris[tb.n[0]], v))
163 removeb2b(tb, tris[tb.n[0]], tris);
164 if (hasvert(tris[tc.n[0]], v))
165 removeb2b(tc, tris[tc.n[0]], tris);
166 t0.Dispose();
167 }
168
169 public static HullTriangle extrudable(float epsilon, List<HullTriangle> tris)
170 {
171 int i;
172 HullTriangle t = null;
173 for (i = 0; i < tris.Count; i++)
174 {
175 if (t == null || (tris.Count > i && (object)tris[i] != null && t.rise < tris[i].rise))
176 {
177 t = tris[i];
178 }
179 }
180 return (t.rise > epsilon) ? t : null;
181 }
182
183 public static Quaternion RotationArc(float3 v0, float3 v1)
184 {
185 Quaternion q = new Quaternion();
186 v0 = float3.normalize(v0); // Comment these two lines out if you know its not needed.
187 v1 = float3.normalize(v1); // If vector is already unit length then why do it again?
188 float3 c = float3.cross(v0, v1);
189 float d = float3.dot(v0, v1);
190 if (d <= -1.0f) // 180 about x axis
191 {
192 return new Quaternion(1f, 0f, 0f, 0f);
193 }
194 float s = (float)Math.Sqrt((1 + d) * 2f);
195 q.x = c.x / s;
196 q.y = c.y / s;
197 q.z = c.z / s;
198 q.w = s / 2.0f;
199 return q;
200 }
201
202 public static float3 PlaneLineIntersection(Plane plane, float3 p0, float3 p1)
203 {
204 // returns the point where the line p0-p1 intersects the plane n&d
205 float3 dif = p1 - p0;
206 float dn = float3.dot(plane.normal, dif);
207 float t = -(plane.dist + float3.dot(plane.normal, p0)) / dn;
208 return p0 + (dif * t);
209 }
210
211 public static float3 LineProject(float3 p0, float3 p1, float3 a)
212 {
213 float3 w = new float3();
214 w = p1 - p0;
215 float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z);
216 return p0 + w * t;
217 }
218
219 public static float3 PlaneProject(Plane plane, float3 point)
220 {
221 return point - plane.normal * (float3.dot(point, plane.normal) + plane.dist);
222 }
223
224 public static float LineProjectTime(float3 p0, float3 p1, float3 a)
225 {
226 float3 w = new float3();
227 w = p1 - p0;
228 float t = float3.dot(w, (a - p0)) / (w.x * w.x + w.y * w.y + w.z * w.z);
229 return t;
230 }
231
232 public static float3 ThreePlaneIntersection(Plane p0, Plane p1, Plane p2)
233 {
234 float3x3 mp = float3x3.Transpose(new float3x3(p0.normal, p1.normal, p2.normal));
235 float3x3 mi = float3x3.Inverse(mp);
236 float3 b = new float3(p0.dist, p1.dist, p2.dist);
237 return -b * mi;
238 }
239
240 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1)
241 {
242 float3 impact = new float3();
243 float3 normal = new float3();
244 return PolyHit(vert, v0, v1, out impact, out normal);
245 }
246
247 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact)
248 {
249 float3 normal = new float3();
250 return PolyHit(vert, v0, v1, out impact, out normal);
251 }
252
253 public static bool PolyHit(List<float3> vert, float3 v0, float3 v1, out float3 impact, out float3 normal)
254 {
255 float3 the_point = new float3();
256
257 impact = null;
258 normal = null;
259
260 int i;
261 float3 nrml = new float3(0, 0, 0);
262 for (i = 0; i < vert.Count; i++)
263 {
264 int i1 = (i + 1) % vert.Count;
265 int i2 = (i + 2) % vert.Count;
266 nrml = nrml + float3.cross(vert[i1] - vert[i], vert[i2] - vert[i1]);
267 }
268
269 float m = float3.magnitude(nrml);
270 if (m == 0.0)
271 {
272 return false;
273 }
274 nrml = nrml * (1.0f / m);
275 float dist = -float3.dot(nrml, vert[0]);
276 float d0;
277 float d1;
278 if ((d0 = float3.dot(v0, nrml) + dist) < 0 || (d1 = float3.dot(v1, nrml) + dist) > 0)
279 {
280 return false;
281 }
282
283 // By using the cached plane distances d0 and d1
284 // we can optimize the following:
285 // the_point = planelineintersection(nrml,dist,v0,v1);
286 float a = d0 / (d0 - d1);
287 the_point = v0 * (1 - a) + v1 * a;
288
289
290 bool inside = true;
291 for (int j = 0; inside && j < vert.Count; j++)
292 {
293 // let inside = 0 if outside
294 float3 pp1 = new float3();
295 float3 pp2 = new float3();
296 float3 side = new float3();
297 pp1 = vert[j];
298 pp2 = vert[(j + 1) % vert.Count];
299 side = float3.cross((pp2 - pp1), (the_point - pp1));
300 inside = (float3.dot(nrml, side) >= 0.0);
301 }
302 if (inside)
303 {
304 if (normal != null)
305 {
306 normal = nrml;
307 }
308 if (impact != null)
309 {
310 impact = the_point;
311 }
312 }
313 return inside;
314 }
315
316 public static bool BoxInside(float3 p, float3 bmin, float3 bmax)
317 {
318 return (p.x >= bmin.x && p.x <= bmax.x && p.y >= bmin.y && p.y <= bmax.y && p.z >= bmin.z && p.z <= bmax.z);
319 }
320
321 public static bool BoxIntersect(float3 v0, float3 v1, float3 bmin, float3 bmax, float3 impact)
322 {
323 if (BoxInside(v0, bmin, bmax))
324 {
325 impact = v0;
326 return true;
327 }
328 if (v0.x <= bmin.x && v1.x >= bmin.x)
329 {
330 float a = (bmin.x - v0.x) / (v1.x - v0.x);
331 //v.x = bmin.x;
332 float vy = (1 - a) * v0.y + a * v1.y;
333 float vz = (1 - a) * v0.z + a * v1.z;
334 if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
335 {
336 impact.x = bmin.x;
337 impact.y = vy;
338 impact.z = vz;
339 return true;
340 }
341 }
342 else if (v0.x >= bmax.x && v1.x <= bmax.x)
343 {
344 float a = (bmax.x - v0.x) / (v1.x - v0.x);
345 //v.x = bmax.x;
346 float vy = (1 - a) * v0.y + a * v1.y;
347 float vz = (1 - a) * v0.z + a * v1.z;
348 if (vy >= bmin.y && vy <= bmax.y && vz >= bmin.z && vz <= bmax.z)
349 {
350 impact.x = bmax.x;
351 impact.y = vy;
352 impact.z = vz;
353 return true;
354 }
355 }
356 if (v0.y <= bmin.y && v1.y >= bmin.y)
357 {
358 float a = (bmin.y - v0.y) / (v1.y - v0.y);
359 float vx = (1 - a) * v0.x + a * v1.x;
360 //v.y = bmin.y;
361 float vz = (1 - a) * v0.z + a * v1.z;
362 if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
363 {
364 impact.x = vx;
365 impact.y = bmin.y;
366 impact.z = vz;
367 return true;
368 }
369 }
370 else if (v0.y >= bmax.y && v1.y <= bmax.y)
371 {
372 float a = (bmax.y - v0.y) / (v1.y - v0.y);
373 float vx = (1 - a) * v0.x + a * v1.x;
374 // vy = bmax.y;
375 float vz = (1 - a) * v0.z + a * v1.z;
376 if (vx >= bmin.x && vx <= bmax.x && vz >= bmin.z && vz <= bmax.z)
377 {
378 impact.x = vx;
379 impact.y = bmax.y;
380 impact.z = vz;
381 return true;
382 }
383 }
384 if (v0.z <= bmin.z && v1.z >= bmin.z)
385 {
386 float a = (bmin.z - v0.z) / (v1.z - v0.z);
387 float vx = (1 - a) * v0.x + a * v1.x;
388 float vy = (1 - a) * v0.y + a * v1.y;
389 // v.z = bmin.z;
390 if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
391 {
392 impact.x = vx;
393 impact.y = vy;
394 impact.z = bmin.z;
395 return true;
396 }
397 }
398 else if (v0.z >= bmax.z && v1.z <= bmax.z)
399 {
400 float a = (bmax.z - v0.z) / (v1.z - v0.z);
401 float vx = (1 - a) * v0.x + a * v1.x;
402 float vy = (1 - a) * v0.y + a * v1.y;
403 // v.z = bmax.z;
404 if (vy >= bmin.y && vy <= bmax.y && vx >= bmin.x && vx <= bmax.x)
405 {
406 impact.x = vx;
407 impact.y = vy;
408 impact.z = bmax.z;
409 return true;
410 }
411 }
412 return false;
413 }
414
415 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint)
416 {
417 return DistanceBetweenLines(ustart, udir, vstart, vdir, upoint, null);
418 }
419
420 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir)
421 {
422 return DistanceBetweenLines(ustart, udir, vstart, vdir, null, null);
423 }
424
425 public static float DistanceBetweenLines(float3 ustart, float3 udir, float3 vstart, float3 vdir, float3 upoint, float3 vpoint)
426 {
427 float3 cp = float3.normalize(float3.cross(udir, vdir));
428
429 float distu = -float3.dot(cp, ustart);
430 float distv = -float3.dot(cp, vstart);
431 float dist = (float)Math.Abs(distu - distv);
432 if (upoint != null)
433 {
434 Plane plane = new Plane();
435 plane.normal = float3.normalize(float3.cross(vdir, cp));
436 plane.dist = -float3.dot(plane.normal, vstart);
437 upoint = PlaneLineIntersection(plane, ustart, ustart + udir);
438 }
439 if (vpoint != null)
440 {
441 Plane plane = new Plane();
442 plane.normal = float3.normalize(float3.cross(udir, cp));
443 plane.dist = -float3.dot(plane.normal, ustart);
444 vpoint = PlaneLineIntersection(plane, vstart, vstart + vdir);
445 }
446 return dist;
447 }
448
449 public static float3 TriNormal(float3 v0, float3 v1, float3 v2)
450 {
451 // return the normal of the triangle
452 // inscribed by v0, v1, and v2
453 float3 cp = float3.cross(v1 - v0, v2 - v1);
454 float m = float3.magnitude(cp);
455 if (m == 0)
456 return new float3(1, 0, 0);
457 return cp * (1.0f / m);
458 }
459
460 public static int PlaneTest(Plane p, float3 v, float planetestepsilon)
461 {
462 float a = float3.dot(v, p.normal) + p.dist;
463 int flag = (a > planetestepsilon) ? (2) : ((a < -planetestepsilon) ? (1) : (0));
464 return flag;
465 }
466
467 public static int SplitTest(ref ConvexH convex, Plane plane, float planetestepsilon)
468 {
469 int flag = 0;
470 for (int i = 0; i < convex.vertices.Count; i++)
471 {
472 flag |= PlaneTest(plane, convex.vertices[i], planetestepsilon);
473 }
474 return flag;
475 }
476
477 public static Quaternion VirtualTrackBall(float3 cop, float3 cor, float3 dir1, float3 dir2)
478 {
479 // routine taken from game programming gems.
480 // Implement track ball functionality to spin stuf on the screen
481 // cop center of projection
482 // cor center of rotation
483 // dir1 old mouse direction
484 // dir2 new mouse direction
485 // pretend there is a sphere around cor. Then find the points
486 // where dir1 and dir2 intersect that sphere. Find the
487 // rotation that takes the first point to the second.
488 float m;
489 // compute plane
490 float3 nrml = cor - cop;
491 float fudgefactor = 1.0f / (float3.magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop
492 nrml = float3.normalize(nrml);
493 float dist = -float3.dot(nrml, cor);
494 float3 u = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir1);
495 u = u - cor;
496 u = u * fudgefactor;
497 m = float3.magnitude(u);
498 if (m > 1)
499 {
500 u /= m;
501 }
502 else
503 {
504 u = u - (nrml * (float)Math.Sqrt(1 - m * m));
505 }
506 float3 v = PlaneLineIntersection(new Plane(nrml, dist), cop, cop + dir2);
507 v = v - cor;
508 v = v * fudgefactor;
509 m = float3.magnitude(v);
510 if (m > 1)
511 {
512 v /= m;
513 }
514 else
515 {
516 v = v - (nrml * (float)Math.Sqrt(1 - m * m));
517 }
518 return RotationArc(u, v);
519 }
520
521 public static bool AssertIntact(ConvexH convex, float planetestepsilon)
522 {
523 int i;
524 int estart = 0;
525 for (i = 0; i < convex.edges.Count; i++)
526 {
527 if (convex.edges[estart].p != convex.edges[i].p)
528 {
529 estart = i;
530 }
531 int inext = i + 1;
532 if (inext >= convex.edges.Count || convex.edges[inext].p != convex.edges[i].p)
533 {
534 inext = estart;
535 }
536 Debug.Assert(convex.edges[inext].p == convex.edges[i].p);
537 int nb = convex.edges[i].ea;
538 Debug.Assert(nb != 255);
539 if (nb == 255 || nb == -1)
540 return false;
541 Debug.Assert(nb != -1);
542 Debug.Assert(i == convex.edges[nb].ea);
543 }
544 for (i = 0; i < convex.edges.Count; i++)
545 {
546 Debug.Assert((0) == PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon));
547 if ((0) != PlaneTest(convex.facets[convex.edges[i].p], convex.vertices[convex.edges[i].v], planetestepsilon))
548 return false;
549 if (convex.edges[estart].p != convex.edges[i].p)
550 {
551 estart = i;
552 }
553 int i1 = i + 1;
554 if (i1 >= convex.edges.Count || convex.edges[i1].p != convex.edges[i].p)
555 {
556 i1 = estart;
557 }
558 int i2 = i1 + 1;
559 if (i2 >= convex.edges.Count || convex.edges[i2].p != convex.edges[i].p)
560 {
561 i2 = estart;
562 }
563 if (i == i2) // i sliced tangent to an edge and created 2 meaningless edges
564 continue;
565 float3 localnormal = TriNormal(convex.vertices[convex.edges[i].v], convex.vertices[convex.edges[i1].v], convex.vertices[convex.edges[i2].v]);
566 Debug.Assert(float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) > 0);
567 if (float3.dot(localnormal, convex.facets[convex.edges[i].p].normal) <= 0)
568 return false;
569 }
570 return true;
571 }
572
573 public static ConvexH test_btbq(float planetestepsilon)
574 {
575 // back to back quads
576 ConvexH convex = new ConvexH(4, 8, 2);
577 convex.vertices[0] = new float3(0, 0, 0);
578 convex.vertices[1] = new float3(1, 0, 0);
579 convex.vertices[2] = new float3(1, 1, 0);
580 convex.vertices[3] = new float3(0, 1, 0);
581 convex.facets[0] = new Plane(new float3(0, 0, 1), 0);
582 convex.facets[1] = new Plane(new float3(0, 0, -1), 0);
583 convex.edges[0] = new ConvexH.HalfEdge(7, 0, 0);
584 convex.edges[1] = new ConvexH.HalfEdge(6, 1, 0);
585 convex.edges[2] = new ConvexH.HalfEdge(5, 2, 0);
586 convex.edges[3] = new ConvexH.HalfEdge(4, 3, 0);
587
588 convex.edges[4] = new ConvexH.HalfEdge(3, 0, 1);
589 convex.edges[5] = new ConvexH.HalfEdge(2, 3, 1);
590 convex.edges[6] = new ConvexH.HalfEdge(1, 2, 1);
591 convex.edges[7] = new ConvexH.HalfEdge(0, 1, 1);
592 AssertIntact(convex, planetestepsilon);
593 return convex;
594 }
595
596 public static ConvexH test_cube()
597 {
598 ConvexH convex = new ConvexH(8, 24, 6);
599 convex.vertices[0] = new float3(0, 0, 0);
600 convex.vertices[1] = new float3(0, 0, 1);
601 convex.vertices[2] = new float3(0, 1, 0);
602 convex.vertices[3] = new float3(0, 1, 1);
603 convex.vertices[4] = new float3(1, 0, 0);
604 convex.vertices[5] = new float3(1, 0, 1);
605 convex.vertices[6] = new float3(1, 1, 0);
606 convex.vertices[7] = new float3(1, 1, 1);
607
608 convex.facets[0] = new Plane(new float3(-1, 0, 0), 0);
609 convex.facets[1] = new Plane(new float3(1, 0, 0), -1);
610 convex.facets[2] = new Plane(new float3(0, -1, 0), 0);
611 convex.facets[3] = new Plane(new float3(0, 1, 0), -1);
612 convex.facets[4] = new Plane(new float3(0, 0, -1), 0);
613 convex.facets[5] = new Plane(new float3(0, 0, 1), -1);
614
615 convex.edges[0] = new ConvexH.HalfEdge(11, 0, 0);
616 convex.edges[1] = new ConvexH.HalfEdge(23, 1, 0);
617 convex.edges[2] = new ConvexH.HalfEdge(15, 3, 0);
618 convex.edges[3] = new ConvexH.HalfEdge(16, 2, 0);
619
620 convex.edges[4] = new ConvexH.HalfEdge(13, 6, 1);
621 convex.edges[5] = new ConvexH.HalfEdge(21, 7, 1);
622 convex.edges[6] = new ConvexH.HalfEdge(9, 5, 1);
623 convex.edges[7] = new ConvexH.HalfEdge(18, 4, 1);
624
625 convex.edges[8] = new ConvexH.HalfEdge(19, 0, 2);
626 convex.edges[9] = new ConvexH.HalfEdge(6, 4, 2);
627 convex.edges[10] = new ConvexH.HalfEdge(20, 5, 2);
628 convex.edges[11] = new ConvexH.HalfEdge(0, 1, 2);
629
630 convex.edges[12] = new ConvexH.HalfEdge(22, 3, 3);
631 convex.edges[13] = new ConvexH.HalfEdge(4, 7, 3);
632 convex.edges[14] = new ConvexH.HalfEdge(17, 6, 3);
633 convex.edges[15] = new ConvexH.HalfEdge(2, 2, 3);
634
635 convex.edges[16] = new ConvexH.HalfEdge(3, 0, 4);
636 convex.edges[17] = new ConvexH.HalfEdge(14, 2, 4);
637 convex.edges[18] = new ConvexH.HalfEdge(7, 6, 4);
638 convex.edges[19] = new ConvexH.HalfEdge(8, 4, 4);
639
640 convex.edges[20] = new ConvexH.HalfEdge(10, 1, 5);
641 convex.edges[21] = new ConvexH.HalfEdge(5, 5, 5);
642 convex.edges[22] = new ConvexH.HalfEdge(12, 7, 5);
643 convex.edges[23] = new ConvexH.HalfEdge(1, 3, 5);
644
645 return convex;
646 }
647
648 public static ConvexH ConvexHMakeCube(float3 bmin, float3 bmax)
649 {
650 ConvexH convex = test_cube();
651 convex.vertices[0] = new float3(bmin.x, bmin.y, bmin.z);
652 convex.vertices[1] = new float3(bmin.x, bmin.y, bmax.z);
653 convex.vertices[2] = new float3(bmin.x, bmax.y, bmin.z);
654 convex.vertices[3] = new float3(bmin.x, bmax.y, bmax.z);
655 convex.vertices[4] = new float3(bmax.x, bmin.y, bmin.z);
656 convex.vertices[5] = new float3(bmax.x, bmin.y, bmax.z);
657 convex.vertices[6] = new float3(bmax.x, bmax.y, bmin.z);
658 convex.vertices[7] = new float3(bmax.x, bmax.y, bmax.z);
659
660 convex.facets[0] = new Plane(new float3(-1, 0, 0), bmin.x);
661 convex.facets[1] = new Plane(new float3(1, 0, 0), -bmax.x);
662 convex.facets[2] = new Plane(new float3(0, -1, 0), bmin.y);
663 convex.facets[3] = new Plane(new float3(0, 1, 0), -bmax.y);
664 convex.facets[4] = new Plane(new float3(0, 0, -1), bmin.z);
665 convex.facets[5] = new Plane(new float3(0, 0, 1), -bmax.z);
666 return convex;
667 }
668
669 public static ConvexH ConvexHCrop(ref ConvexH convex, Plane slice, float planetestepsilon)
670 {
671 int i;
672 int vertcountunder = 0;
673 int vertcountover = 0;
674 List<int> vertscoplanar = new List<int>(); // existing vertex members of convex that are coplanar
675 List<int> edgesplit = new List<int>(); // existing edges that members of convex that cross the splitplane
676
677 Debug.Assert(convex.edges.Count < 480);
678
679 EdgeFlag[] edgeflag = new EdgeFlag[512];
680 VertFlag[] vertflag = new VertFlag[256];
681 PlaneFlag[] planeflag = new PlaneFlag[128];
682 ConvexH.HalfEdge[] tmpunderedges = new ConvexH.HalfEdge[512];
683 Plane[] tmpunderplanes = new Plane[128];
684 Coplanar[] coplanaredges = new Coplanar[512];
685 int coplanaredges_num = 0;
686
687 List<float3> createdverts = new List<float3>();
688
689 // do the side-of-plane tests
690 for (i = 0; i < convex.vertices.Count; i++)
691 {
692 vertflag[i].planetest = (byte)PlaneTest(slice, convex.vertices[i], planetestepsilon);
693 if (vertflag[i].planetest == (0))
694 {
695 // ? vertscoplanar.Add(i);
696 vertflag[i].undermap = (byte)vertcountunder++;
697 vertflag[i].overmap = (byte)vertcountover++;
698 }
699 else if (vertflag[i].planetest == (1))
700 {
701 vertflag[i].undermap = (byte)vertcountunder++;
702 }
703 else
704 {
705 Debug.Assert(vertflag[i].planetest == (2));
706 vertflag[i].overmap = (byte)vertcountover++;
707 vertflag[i].undermap = 255; // for debugging purposes
708 }
709 }
710 int vertcountunderold = vertcountunder; // for debugging only
711
712 int under_edge_count = 0;
713 int underplanescount = 0;
714 int e0 = 0;
715
716 for (int currentplane = 0; currentplane < convex.facets.Count; currentplane++)
717 {
718 int estart = e0;
719 int enextface = 0;
720 int planeside = 0;
721 int e1 = e0 + 1;
722 int vout = -1;
723 int vin = -1;
724 int coplanaredge = -1;
725 do
726 {
727
728 if (e1 >= convex.edges.Count || convex.edges[e1].p != currentplane)
729 {
730 enextface = e1;
731 e1 = estart;
732 }
733 ConvexH.HalfEdge edge0 = convex.edges[e0];
734 ConvexH.HalfEdge edge1 = convex.edges[e1];
735 ConvexH.HalfEdge edgea = convex.edges[edge0.ea];
736
737 planeside |= vertflag[edge0.v].planetest;
738 //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) {
739 // assert(ecop==-1);
740 // ecop=e;
741 //}
742
743 if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (2))
744 {
745 // both endpoints over plane
746 edgeflag[e0].undermap = -1;
747 }
748 else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (1))
749 {
750 // at least one endpoint under, the other coplanar or under
751
752 edgeflag[e0].undermap = (short)under_edge_count;
753 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
754 tmpunderedges[under_edge_count].p = (byte)underplanescount;
755 if (edge0.ea < e0)
756 {
757 // connect the neighbors
758 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
759 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
760 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
761 }
762 under_edge_count++;
763 }
764 else if ((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == (0))
765 {
766 // both endpoints coplanar
767 // must check a 3rd point to see if UNDER
768 int e2 = e1 + 1;
769 if (e2 >= convex.edges.Count || convex.edges[e2].p != currentplane)
770 {
771 e2 = estart;
772 }
773 Debug.Assert(convex.edges[e2].p == currentplane);
774 ConvexH.HalfEdge edge2 = convex.edges[e2];
775 if (vertflag[edge2.v].planetest == (1))
776 {
777
778 edgeflag[e0].undermap = (short)under_edge_count;
779 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
780 tmpunderedges[under_edge_count].p = (byte)underplanescount;
781 tmpunderedges[under_edge_count].ea = -1;
782 // make sure this edge is added to the "coplanar" list
783 coplanaredge = under_edge_count;
784 vout = vertflag[edge0.v].undermap;
785 vin = vertflag[edge1.v].undermap;
786 under_edge_count++;
787 }
788 else
789 {
790 edgeflag[e0].undermap = -1;
791 }
792 }
793 else if (vertflag[edge0.v].planetest == (1) && vertflag[edge1.v].planetest == (2))
794 {
795 // first is under 2nd is over
796
797 edgeflag[e0].undermap = (short)under_edge_count;
798 tmpunderedges[under_edge_count].v = vertflag[edge0.v].undermap;
799 tmpunderedges[under_edge_count].p = (byte)underplanescount;
800 if (edge0.ea < e0)
801 {
802 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
803 // connect the neighbors
804 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
805 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
806 vout = tmpunderedges[edgeflag[edge0.ea].undermap].v;
807 }
808 else
809 {
810 Plane p0 = convex.facets[edge0.p];
811 Plane pa = convex.facets[edgea.p];
812 createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
813 //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])));
814 //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]));
815 vout = vertcountunder++;
816 }
817 under_edge_count++;
818 /// hmmm something to think about: i might be able to output this edge regarless of
819 // wheter or not we know v-in yet. ok i;ll try this now:
820 tmpunderedges[under_edge_count].v = (byte)vout;
821 tmpunderedges[under_edge_count].p = (byte)underplanescount;
822 tmpunderedges[under_edge_count].ea = -1;
823 coplanaredge = under_edge_count;
824 under_edge_count++;
825
826 if (vin != -1)
827 {
828 // we previously processed an edge where we came under
829 // now we know about vout as well
830
831 // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
832 }
833
834 }
835 else if (vertflag[edge0.v].planetest == (0) && vertflag[edge1.v].planetest == (2))
836 {
837 // first is coplanar 2nd is over
838
839 edgeflag[e0].undermap = -1;
840 vout = vertflag[edge0.v].undermap;
841 // I hate this but i have to make sure part of this face is UNDER before ouputting this vert
842 int k = estart;
843 Debug.Assert(edge0.p == currentplane);
844 while (!((planeside & 1) != 0) && k < convex.edges.Count && convex.edges[k].p == edge0.p)
845 {
846 planeside |= vertflag[convex.edges[k].v].planetest;
847 k++;
848 }
849 if ((planeside & 1) != 0)
850 {
851 tmpunderedges[under_edge_count].v = (byte)vout;
852 tmpunderedges[under_edge_count].p = (byte)underplanescount;
853 tmpunderedges[under_edge_count].ea = -1;
854 coplanaredge = under_edge_count; // hmmm should make a note of the edge # for later on
855 under_edge_count++;
856
857 }
858 }
859 else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (1))
860 {
861 // first is over next is under
862 // new vertex!!!
863 Debug.Assert(vin == -1);
864 if (e0 < edge0.ea)
865 {
866 Plane p0 = convex.facets[edge0.p];
867 Plane pa = convex.facets[edgea.p];
868 createdverts.Add(ThreePlaneIntersection(p0, pa, slice));
869 //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]));
870 //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])));
871 vin = vertcountunder++;
872 }
873 else
874 {
875 // find the new vertex that was created by edge[edge0.ea]
876 int nea = edgeflag[edge0.ea].undermap;
877 Debug.Assert(tmpunderedges[nea].p == tmpunderedges[nea + 1].p);
878 vin = tmpunderedges[nea + 1].v;
879 Debug.Assert(vin < vertcountunder);
880 Debug.Assert(vin >= vertcountunderold); // for debugging only
881 }
882 if (vout != -1)
883 {
884 // we previously processed an edge where we went over
885 // now we know vin too
886 // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
887 }
888 // output edge
889 tmpunderedges[under_edge_count].v = (byte)vin;
890 tmpunderedges[under_edge_count].p = (byte)underplanescount;
891 edgeflag[e0].undermap = (short)under_edge_count;
892 if (e0 > edge0.ea)
893 {
894 Debug.Assert(edgeflag[edge0.ea].undermap != -1);
895 // connect the neighbors
896 tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap;
897 tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count;
898 }
899 Debug.Assert(edgeflag[e0].undermap == under_edge_count);
900 under_edge_count++;
901 }
902 else if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (0))
903 {
904 // first is over next is coplanar
905
906 edgeflag[e0].undermap = -1;
907 vin = vertflag[edge1.v].undermap;
908 Debug.Assert(vin != -1);
909 if (vout != -1)
910 {
911 // we previously processed an edge where we came under
912 // now we know both endpoints
913 // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!!
914 }
915
916 }
917 else
918 {
919 Debug.Assert(false);
920 }
921
922
923 e0 = e1;
924 e1++; // do the modulo at the beginning of the loop
925
926 } while (e0 != estart);
927 e0 = enextface;
928 if ((planeside & 1) != 0)
929 {
930 planeflag[currentplane].undermap = (byte)underplanescount;
931 tmpunderplanes[underplanescount] = convex.facets[currentplane];
932 underplanescount++;
933 }
934 else
935 {
936 planeflag[currentplane].undermap = 0;
937 }
938 if (vout >= 0 && (planeside & 1) != 0)
939 {
940 Debug.Assert(vin >= 0);
941 Debug.Assert(coplanaredge >= 0);
942 Debug.Assert(coplanaredge != 511);
943 coplanaredges[coplanaredges_num].ea = (ushort)coplanaredge;
944 coplanaredges[coplanaredges_num].v0 = (byte)vin;
945 coplanaredges[coplanaredges_num].v1 = (byte)vout;
946 coplanaredges_num++;
947 }
948 }
949
950 // add the new plane to the mix:
951 if (coplanaredges_num > 0)
952 {
953 tmpunderplanes[underplanescount++] = slice;
954 }
955 for (i = 0; i < coplanaredges_num - 1; i++)
956 {
957 if (coplanaredges[i].v1 != coplanaredges[i + 1].v0)
958 {
959 int j = 0;
960 for (j = i + 2; j < coplanaredges_num; j++)
961 {
962 if (coplanaredges[i].v1 == coplanaredges[j].v0)
963 {
964 Coplanar tmp = coplanaredges[i + 1];
965 coplanaredges[i + 1] = coplanaredges[j];
966 coplanaredges[j] = tmp;
967 break;
968 }
969 }
970 if (j >= coplanaredges_num)
971 {
972 Debug.Assert(j < coplanaredges_num);
973 return null;
974 }
975 }
976 }
977
978 ConvexH punder = new ConvexH(vertcountunder, under_edge_count + coplanaredges_num, underplanescount);
979 ConvexH under = punder;
980
981 {
982 int k = 0;
983 for (i = 0; i < convex.vertices.Count; i++)
984 {
985 if (vertflag[i].planetest != (2))
986 {
987 under.vertices[k++] = convex.vertices[i];
988 }
989 }
990 i = 0;
991 while (k < vertcountunder)
992 {
993 under.vertices[k++] = createdverts[i++];
994 }
995 Debug.Assert(i == createdverts.Count);
996 }
997
998 for (i = 0; i < coplanaredges_num; i++)
999 {
1000 ConvexH.HalfEdge edge = under.edges[under_edge_count + i];
1001 edge.p = (byte)(underplanescount - 1);
1002 edge.ea = (short)coplanaredges[i].ea;
1003 edge.v = (byte)coplanaredges[i].v0;
1004 under.edges[under_edge_count + i] = edge;
1005
1006 tmpunderedges[coplanaredges[i].ea].ea = (short)(under_edge_count + i);
1007 }
1008
1009 under.edges = new List<ConvexH.HalfEdge>(tmpunderedges);
1010 under.facets = new List<Plane>(tmpunderplanes);
1011 return punder;
1012 }
1013
1014 public static ConvexH ConvexHDup(ConvexH src)
1015 {
1016 ConvexH dst = new ConvexH(src.vertices.Count, src.edges.Count, src.facets.Count);
1017 dst.vertices = new List<float3>(src.vertices.Count);
1018 foreach (float3 f in src.vertices)
1019 dst.vertices.Add(new float3(f));
1020 dst.edges = new List<ConvexH.HalfEdge>(src.edges.Count);
1021 foreach (ConvexH.HalfEdge e in src.edges)
1022 dst.edges.Add(new ConvexH.HalfEdge(e));
1023 dst.facets = new List<Plane>(src.facets.Count);
1024 foreach (Plane p in src.facets)
1025 dst.facets.Add(new Plane(p));
1026 return dst;
1027 }
1028
1029 public static int candidateplane(List<Plane> planes, int planes_count, ConvexH convex, float epsilon)
1030 {
1031 int p = 0;
1032 float md = 0;
1033 int i;
1034 for (i = 0; i < planes_count; i++)
1035 {
1036 float d = 0;
1037 for (int j = 0; j < convex.vertices.Count; j++)
1038 {
1039 d = Math.Max(d, float3.dot(convex.vertices[j], planes[i].normal) + planes[i].dist);
1040 }
1041 if (i == 0 || d > md)
1042 {
1043 p = i;
1044 md = d;
1045 }
1046 }
1047 return (md > epsilon) ? p : -1;
1048 }
1049
1050 public static float3 orth(float3 v)
1051 {
1052 float3 a = float3.cross(v, new float3(0f, 0f, 1f));
1053 float3 b = float3.cross(v, new float3(0f, 1f, 0f));
1054 return float3.normalize((float3.magnitude(a) > float3.magnitude(b)) ? a : b);
1055 }
1056
1057 public static int maxdir(List<float3> p, int count, float3 dir)
1058 {
1059 Debug.Assert(count != 0);
1060 int m = 0;
1061 float currDotm = float3.dot(p[0], dir);
1062 for (int i = 1; i < count; i++)
1063 {
1064 float currDoti = float3.dot(p[i], dir);
1065 if (currDoti > currDotm)
1066 {
1067 currDotm = currDoti;
1068 m = i;
1069 }
1070 }
1071 return m;
1072 }
1073
1074 public static int maxdirfiltered(List<float3> p, int count, float3 dir, byte[] allow)
1075 {
1076 //Debug.Assert(count != 0);
1077 int m = 0;
1078 float currDotm = float3.dot(p[0], dir);
1079 float currDoti;
1080
1081 while (allow[m] == 0)
1082 m++;
1083
1084 for (int i = 1; i < count; i++)
1085 {
1086 if (allow[i] != 0)
1087 {
1088 currDoti = float3.dot(p[i], dir);
1089 if (currDoti > currDotm)
1090 {
1091 currDotm = currDoti;
1092 m = i;
1093 }
1094 }
1095 }
1096 //Debug.Assert(m != -1);
1097 return m;
1098 }
1099
1100 public static int maxdirsterid(List<float3> p, int count, float3 dir, byte[] allow)
1101 {
1102 int m = -1;
1103 while (m == -1)
1104 {
1105 m = maxdirfiltered(p, count, dir, allow);
1106 if (allow[m] == 3)
1107 return m;
1108 float3 u = orth(dir);
1109 float3 v = float3.cross(u, dir);
1110 int ma = -1;
1111 for (float x = 0.0f; x <= 360.0f; x += 45.0f)
1112 {
1113 int mb;
1114 {
1115 float s = (float)Math.Sin((3.14159264f / 180.0f) * (x));
1116 float c = (float)Math.Cos((3.14159264f / 180.0f) * (x));
1117 mb = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
1118 }
1119 if (ma == m && mb == m)
1120 {
1121 allow[m] = 3;
1122 return m;
1123 }
1124 if (ma != -1 && ma != mb) // Yuck - this is really ugly
1125 {
1126 int mc = ma;
1127 for (float xx = x - 40.0f; xx <= x; xx += 5.0f)
1128 {
1129 float s = (float)Math.Sin((3.14159264f / 180.0f) * (xx));
1130 float c = (float)Math.Cos((3.14159264f / 180.0f) * (xx));
1131 int md = maxdirfiltered(p, count, dir + (u * s + v * c) * 0.025f, allow);
1132 if (mc == m && md == m)
1133 {
1134 allow[m] = 3;
1135 return m;
1136 }
1137 mc = md;
1138 }
1139 }
1140 ma = mb;
1141 }
1142 allow[m] = 0;
1143 m = -1;
1144 }
1145
1146 Debug.Assert(false);
1147 return m;
1148 }
1149
1150 public static int4 FindSimplex(List<float3> verts, byte[] allow)
1151 {
1152 float3[] basis = new float3[3];
1153 basis[0] = new float3(0.01f, 0.02f, 1.0f);
1154 int p0 = maxdirsterid(verts, verts.Count, basis[0], allow);
1155 int p1 = maxdirsterid(verts, verts.Count, -basis[0], allow);
1156 basis[0] = verts[p0] - verts[p1];
1157 if (p0 == p1 || basis[0] == new float3(0, 0, 0))
1158 return new int4(-1, -1, -1, -1);
1159 basis[1] = float3.cross(new float3(1, 0.02f, 0), basis[0]);
1160 basis[2] = float3.cross(new float3(-0.02f, 1, 0), basis[0]);
1161 basis[1] = float3.normalize((float3.magnitude(basis[1]) > float3.magnitude(basis[2])) ? basis[1] : basis[2]);
1162 int p2 = maxdirsterid(verts, verts.Count, basis[1], allow);
1163 if (p2 == p0 || p2 == p1)
1164 {
1165 p2 = maxdirsterid(verts, verts.Count, -basis[1], allow);
1166 }
1167 if (p2 == p0 || p2 == p1)
1168 return new int4(-1, -1, -1, -1);
1169 basis[1] = verts[p2] - verts[p0];
1170 basis[2] = float3.normalize(float3.cross(basis[1], basis[0]));
1171 int p3 = maxdirsterid(verts, verts.Count, basis[2], allow);
1172 if (p3 == p0 || p3 == p1 || p3 == p2)
1173 p3 = maxdirsterid(verts, verts.Count, -basis[2], allow);
1174 if (p3 == p0 || p3 == p1 || p3 == p2)
1175 return new int4(-1, -1, -1, -1);
1176 Debug.Assert(!(p0 == p1 || p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3 || p2 == p3));
1177 if (float3.dot(verts[p3] - verts[p0], float3.cross(verts[p1] - verts[p0], verts[p2] - verts[p0])) < 0)
1178 {
1179 Swap(ref p2, ref p3);
1180 }
1181 return new int4(p0, p1, p2, p3);
1182 }
1183
1184 public static float GetDist(float px, float py, float pz, float3 p2)
1185 {
1186 float dx = px - p2.x;
1187 float dy = py - p2.y;
1188 float dz = pz - p2.z;
1189
1190 return dx * dx + dy * dy + dz * dz;
1191 }
1192
1193 public static void ReleaseHull(PHullResult result)
1194 {
1195 if (result.Indices != null)
1196 result.Indices = null;
1197 if (result.Vertices != null)
1198 result.Vertices = null;
1199 }
1200
1201 public static int calchullgen(List<float3> verts, int vlimit, List<HullTriangle> tris)
1202 {
1203 if (verts.Count < 4)
1204 return 0;
1205 if (vlimit == 0)
1206 vlimit = 1000000000;
1207 int j;
1208 float3 bmin = new float3(verts[0]);
1209 float3 bmax = new float3(verts[0]);
1210 List<int> isextreme = new List<int>(verts.Count);
1211 byte[] allow = new byte[verts.Count];
1212 for (j = 0; j < verts.Count; j++)
1213 {
1214 allow[j] = 1;
1215 isextreme.Add(0);
1216 bmin = float3.VectorMin(bmin, verts[j]);
1217 bmax = float3.VectorMax(bmax, verts[j]);
1218 }
1219 float epsilon = float3.magnitude(bmax - bmin) * 0.001f;
1220
1221 int4 p = FindSimplex(verts, allow);
1222 if (p.x == -1) // simplex failed
1223 return 0;
1224
1225 float3 center = (verts[p[0]] + verts[p[1]] + verts[p[2]] + verts[p[3]]) / 4.0f; // a valid interior point
1226 HullTriangle t0 = new HullTriangle(p[2], p[3], p[1], tris);
1227 t0.n = new int3(2, 3, 1);
1228 HullTriangle t1 = new HullTriangle(p[3], p[2], p[0], tris);
1229 t1.n = new int3(3, 2, 0);
1230 HullTriangle t2 = new HullTriangle(p[0], p[1], p[3], tris);
1231 t2.n = new int3(0, 1, 3);
1232 HullTriangle t3 = new HullTriangle(p[1], p[0], p[2], tris);
1233 t3.n = new int3(1, 0, 2);
1234 isextreme[p[0]] = isextreme[p[1]] = isextreme[p[2]] = isextreme[p[3]] = 1;
1235 checkit(t0, tris);
1236 checkit(t1, tris);
1237 checkit(t2, tris);
1238 checkit(t3, tris);
1239
1240 for (j = 0; j < tris.Count; j++)
1241 {
1242 HullTriangle t = tris[j];
1243 Debug.Assert((object)t != null);
1244 Debug.Assert(t.vmax < 0);
1245 float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1246 t.vmax = maxdirsterid(verts, verts.Count, n, allow);
1247 t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]);
1248 }
1249 HullTriangle te;
1250 vlimit -= 4;
1251 while (vlimit > 0 && (te = extrudable(epsilon, tris)) != null)
1252 {
1253 int3 ti = te;
1254 int v = te.vmax;
1255 Debug.Assert(isextreme[v] == 0); // wtf we've already done this vertex
1256 isextreme[v] = 1;
1257 //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already
1258 j = tris.Count;
1259 while (j-- != 0)
1260 {
1261 if (tris.Count <= j || (object)tris[j] == null)
1262 continue;
1263 int3 t = tris[j];
1264 if (above(verts, t, verts[v], 0.01f * epsilon))
1265 {
1266 extrude(tris[j], v, tris);
1267 }
1268 }
1269 // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle
1270 j = tris.Count;
1271 while (j-- != 0)
1272 {
1273 if (tris.Count <= j || (object)tris[j] == null)
1274 continue;
1275 if (!hasvert(tris[j], v))
1276 break;
1277 int3 nt = tris[j];
1278 if (above(verts, nt, center, 0.01f * epsilon) || float3.magnitude(float3.cross(verts[nt[1]] - verts[nt[0]], verts[nt[2]] - verts[nt[1]])) < epsilon * epsilon * 0.1f)
1279 {
1280 HullTriangle nb = tris[tris[j].n[0]];
1281 Debug.Assert(nb != null);
1282 Debug.Assert(!hasvert(nb, v));
1283 Debug.Assert(nb.id < j);
1284 extrude(nb, v, tris);
1285 j = tris.Count;
1286 }
1287 }
1288 j = tris.Count;
1289 while (j-- != 0)
1290 {
1291 HullTriangle t = tris[j];
1292 if (t == null)
1293 continue;
1294 if (t.vmax >= 0)
1295 break;
1296 float3 n = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1297 t.vmax = maxdirsterid(verts, verts.Count, n, allow);
1298 if (isextreme[t.vmax] != 0)
1299 {
1300 t.vmax = -1; // already done that vertex - algorithm needs to be able to terminate.
1301 }
1302 else
1303 {
1304 t.rise = float3.dot(n, verts[t.vmax] - verts[(t)[0]]);
1305 }
1306 }
1307 vlimit--;
1308 }
1309 return 1;
1310 }
1311
1312 public static bool calchull(List<float3> verts, out List<int> tris_out, int vlimit, List<HullTriangle> tris)
1313 {
1314 tris_out = null;
1315
1316 int rc = calchullgen(verts, vlimit, tris);
1317 if (rc == 0)
1318 return false;
1319 List<int> ts = new List<int>();
1320 for (int i = 0; i < tris.Count; i++)
1321 {
1322 if ((object)tris[i] != null)
1323 {
1324 for (int j = 0; j < 3; j++)
1325 ts.Add((tris[i])[j]);
1326 tris[i] = null;
1327 }
1328 }
1329
1330 tris_out = ts;
1331 tris.Clear();
1332 return true;
1333 }
1334
1335 public static int calchullpbev(List<float3> verts, int vlimit, out List<Plane> planes, float bevangle, List<HullTriangle> tris)
1336 {
1337 int i;
1338 int j;
1339 planes = new List<Plane>();
1340 int rc = calchullgen(verts, vlimit, tris);
1341 if (rc == 0)
1342 return 0;
1343 for (i = 0; i < tris.Count; i++)
1344 {
1345 if (tris[i] != null)
1346 {
1347 Plane p = new Plane();
1348 HullTriangle t = tris[i];
1349 p.normal = TriNormal(verts[(t)[0]], verts[(t)[1]], verts[(t)[2]]);
1350 p.dist = -float3.dot(p.normal, verts[(t)[0]]);
1351 planes.Add(p);
1352 for (j = 0; j < 3; j++)
1353 {
1354 if (t.n[j] < t.id)
1355 continue;
1356 HullTriangle s = tris[t.n[j]];
1357 float3 snormal = TriNormal(verts[(s)[0]], verts[(s)[1]], verts[(s)[2]]);
1358 if (float3.dot(snormal, p.normal) >= Math.Cos(bevangle * (3.14159264f / 180.0f)))
1359 continue;
1360 float3 n = float3.normalize(snormal + p.normal);
1361 planes.Add(new Plane(n, -float3.dot(n, verts[maxdir(verts, verts.Count, n)])));
1362 }
1363 }
1364 }
1365
1366 tris.Clear();
1367 return 1;
1368 }
1369
1370 public static int overhull(List<Plane> planes, List<float3> verts, int maxplanes, out List<float3> verts_out, out List<int> faces_out, float inflate)
1371 {
1372 verts_out = null;
1373 faces_out = null;
1374
1375 int i;
1376 int j;
1377 if (verts.Count < 4)
1378 return 0;
1379 maxplanes = Math.Min(maxplanes, planes.Count);
1380 float3 bmin = new float3(verts[0]);
1381 float3 bmax = new float3(verts[0]);
1382 for (i = 0; i < verts.Count; i++)
1383 {
1384 bmin = float3.VectorMin(bmin, verts[i]);
1385 bmax = float3.VectorMax(bmax, verts[i]);
1386 }
1387 // float diameter = magnitude(bmax-bmin);
1388 // inflate *=diameter; // RELATIVE INFLATION
1389 bmin -= new float3(inflate, inflate, inflate);
1390 bmax += new float3(inflate, inflate, inflate);
1391 for (i = 0; i < planes.Count; i++)
1392 {
1393 planes[i].dist -= inflate;
1394 }
1395 float3 emin = new float3(bmin);
1396 float3 emax = new float3(bmax);
1397 float epsilon = float3.magnitude(emax - emin) * 0.025f;
1398 float planetestepsilon = float3.magnitude(emax - emin) * (0.001f);
1399 // todo: add bounding cube planes to force bevel. or try instead not adding the diameter expansion ??? must think.
1400 // ConvexH *convex = ConvexHMakeCube(bmin - float3(diameter,diameter,diameter),bmax+float3(diameter,diameter,diameter));
1401 ConvexH c = ConvexHMakeCube(new float3(bmin), new float3(bmax));
1402 int k;
1403 while (maxplanes-- != 0 && (k = candidateplane(planes, planes.Count, c, epsilon)) >= 0)
1404 {
1405 ConvexH tmp = c;
1406 c = ConvexHCrop(ref tmp, planes[k], planetestepsilon);
1407 if (c == null) // might want to debug this case better!!!
1408 {
1409 c = tmp;
1410 break;
1411 }
1412 if (AssertIntact(c, planetestepsilon) == false) // might want to debug this case better too!!!
1413 {
1414 c = tmp;
1415 break;
1416 }
1417 tmp.edges = null;
1418 tmp.facets = null;
1419 tmp.vertices = null;
1420 }
1421
1422 Debug.Assert(AssertIntact(c, planetestepsilon));
1423 //return c;
1424 //C++ TO C# CONVERTER TODO TASK: The memory management function 'malloc' has no equivalent in C#:
1425 faces_out = new List<int>(); //(int)malloc(sizeof(int) * (1 + c.facets.Count + c.edges.Count)); // new int[1+c->facets.count+c->edges.count];
1426 int faces_count_out = 0;
1427 i = 0;
1428 faces_out[faces_count_out++] = -1;
1429 k = 0;
1430 while (i < c.edges.Count)
1431 {
1432 j = 1;
1433 while (j + i < c.edges.Count && c.edges[i].p == c.edges[i + j].p)
1434 {
1435 j++;
1436 }
1437 faces_out[faces_count_out++] = j;
1438 while (j-- != 0)
1439 {
1440 faces_out[faces_count_out++] = c.edges[i].v;
1441 i++;
1442 }
1443 k++;
1444 }
1445 faces_out[0] = k; // number of faces.
1446 Debug.Assert(k == c.facets.Count);
1447 Debug.Assert(faces_count_out == 1 + c.facets.Count + c.edges.Count);
1448 verts_out = c.vertices; // new float3[c->vertices.count];
1449 int verts_count_out = c.vertices.Count;
1450 for (i = 0; i < c.vertices.Count; i++)
1451 {
1452 verts_out[i] = new float3(c.vertices[i]);
1453 }
1454
1455 c.edges = null;
1456 c.facets = null;
1457 c.vertices = null;
1458 return 1;
1459 }
1460
1461 public static int overhullv(List<float3> verts, int maxplanes, out List<float3> verts_out, out List<int> faces_out, float inflate, float bevangle, int vlimit, List<HullTriangle> tris)
1462 {
1463 verts_out = null;
1464 faces_out = null;
1465
1466 if (verts.Count == 0)
1467 return 0;
1468 List<Plane> planes = new List<Plane>();
1469 int rc = calchullpbev(verts, vlimit, out planes, bevangle, tris);
1470 if (rc == 0)
1471 return 0;
1472 return overhull(planes, verts, maxplanes, out verts_out, out faces_out, inflate);
1473 }
1474
1475 public static void addPoint(ref uint vcount, List<float3> p, float x, float y, float z)
1476 {
1477 p.Add(new float3(x, y, z));
1478 vcount++;
1479 }
1480
1481 public static bool ComputeHull(List<float3> vertices, ref PHullResult result, int vlimit, float inflate)
1482 {
1483 List<HullTriangle> tris = new List<HullTriangle>();
1484 List<int> faces;
1485 List<float3> verts_out;
1486
1487 if (inflate == 0.0f)
1488 {
1489 List<int> tris_out;
1490 bool ret = calchull(vertices, out tris_out, vlimit, tris);
1491 if (ret == false)
1492 return false;
1493
1494 result.Indices = tris_out;
1495 result.Vertices = vertices;
1496 return true;
1497 }
1498 else
1499 {
1500 int ret = overhullv(vertices, 35, out verts_out, out faces, inflate, 120.0f, vlimit, tris);
1501 if (ret == 0)
1502 return false;
1503
1504 List<int3> tris2 = new List<int3>();
1505 int n = faces[0];
1506 int k = 1;
1507 for (int i = 0; i < n; i++)
1508 {
1509 int pn = faces[k++];
1510 for (int j = 2; j < pn; j++)
1511 tris2.Add(new int3(faces[k], faces[k + j - 1], faces[k + j]));
1512 k += pn;
1513 }
1514 Debug.Assert(tris2.Count == faces.Count - 1 - (n * 3));
1515
1516 result.Indices = new List<int>(tris2.Count * 3);
1517 for (int i = 0; i < tris2.Count; i++)
1518 {
1519 result.Indices.Add(tris2[i].x);
1520 result.Indices.Add(tris2[i].y);
1521 result.Indices.Add(tris2[i].z);
1522 }
1523 result.Vertices = verts_out;
1524
1525 return true;
1526 }
1527 }
1528
1529 private static bool CleanupVertices(List<float3> svertices, out List<float3> vertices, float normalepsilon, out float3 scale)
1530 {
1531 const float EPSILON = 0.000001f;
1532
1533 vertices = new List<float3>();
1534 scale = new float3(1f, 1f, 1f);
1535
1536 if (svertices.Count == 0)
1537 return false;
1538
1539 uint vcount = 0;
1540
1541 float[] recip = new float[3];
1542
1543 float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
1544 float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue };
1545
1546 for (int i = 0; i < svertices.Count; i++)
1547 {
1548 float3 p = svertices[i];
1549
1550 for (int j = 0; j < 3; j++)
1551 {
1552 if (p[j] < bmin[j])
1553 bmin[j] = p[j];
1554 if (p[j] > bmax[j])
1555 bmax[j] = p[j];
1556 }
1557 }
1558
1559 float dx = bmax[0] - bmin[0];
1560 float dy = bmax[1] - bmin[1];
1561 float dz = bmax[2] - bmin[2];
1562
1563 float3 center = new float3();
1564
1565 center.x = dx * 0.5f + bmin[0];
1566 center.y = dy * 0.5f + bmin[1];
1567 center.z = dz * 0.5f + bmin[2];
1568
1569 if (dx < EPSILON || dy < EPSILON || dz < EPSILON || svertices.Count < 3)
1570 {
1571 float len = Single.MaxValue;
1572
1573 if (dx > EPSILON && dx < len)
1574 len = dx;
1575 if (dy > EPSILON && dy < len)
1576 len = dy;
1577 if (dz > EPSILON && dz < len)
1578 len = dz;
1579
1580 if (len == Single.MaxValue)
1581 {
1582 dx = dy = dz = 0.01f; // one centimeter
1583 }
1584 else
1585 {
1586 if (dx < EPSILON) // 1/5th the shortest non-zero edge.
1587 dx = len * 0.05f;
1588 if (dy < EPSILON)
1589 dy = len * 0.05f;
1590 if (dz < EPSILON)
1591 dz = len * 0.05f;
1592 }
1593
1594 float x1 = center[0] - dx;
1595 float x2 = center[0] + dx;
1596
1597 float y1 = center[1] - dy;
1598 float y2 = center[1] + dy;
1599
1600 float z1 = center[2] - dz;
1601 float z2 = center[2] + dz;
1602
1603 addPoint(ref vcount, vertices, x1, y1, z1);
1604 addPoint(ref vcount, vertices, x2, y1, z1);
1605 addPoint(ref vcount, vertices, x2, y2, z1);
1606 addPoint(ref vcount, vertices, x1, y2, z1);
1607 addPoint(ref vcount, vertices, x1, y1, z2);
1608 addPoint(ref vcount, vertices, x2, y1, z2);
1609 addPoint(ref vcount, vertices, x2, y2, z2);
1610 addPoint(ref vcount, vertices, x1, y2, z2);
1611
1612 return true; // return cube
1613 }
1614 else
1615 {
1616 scale.x = dx;
1617 scale.y = dy;
1618 scale.z = dz;
1619
1620 recip[0] = 1f / dx;
1621 recip[1] = 1f / dy;
1622 recip[2] = 1f / dz;
1623
1624 center.x *= recip[0];
1625 center.y *= recip[1];
1626 center.z *= recip[2];
1627 }
1628
1629 for (int i = 0; i < svertices.Count; i++)
1630 {
1631 float3 p = svertices[i];
1632
1633 float px = p[0];
1634 float py = p[1];
1635 float pz = p[2];
1636
1637 px = px * recip[0]; // normalize
1638 py = py * recip[1]; // normalize
1639 pz = pz * recip[2]; // normalize
1640
1641 if (true)
1642 {
1643 int j;
1644
1645 for (j = 0; j < vcount; j++)
1646 {
1647 float3 v = vertices[j];
1648
1649 float x = v[0];
1650 float y = v[1];
1651 float z = v[2];
1652
1653 float dx1 = Math.Abs(x - px);
1654 float dy1 = Math.Abs(y - py);
1655 float dz1 = Math.Abs(z - pz);
1656
1657 if (dx1 < normalepsilon && dy1 < normalepsilon && dz1 < normalepsilon)
1658 {
1659 // ok, it is close enough to the old one
1660 // now let us see if it is further from the center of the point cloud than the one we already recorded.
1661 // in which case we keep this one instead.
1662 float dist1 = GetDist(px, py, pz, center);
1663 float dist2 = GetDist(v[0], v[1], v[2], center);
1664
1665 if (dist1 > dist2)
1666 {
1667 v.x = px;
1668 v.y = py;
1669 v.z = pz;
1670 }
1671
1672 break;
1673 }
1674 }
1675
1676 if (j == vcount)
1677 {
1678 float3 dest = new float3(px, py, pz);
1679 vertices.Add(dest);
1680 vcount++;
1681 }
1682 }
1683 }
1684
1685 // ok..now make sure we didn't prune so many vertices it is now invalid.
1686 if (true)
1687 {
1688 float[] bmin2 = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
1689 float[] bmax2 = { Single.MinValue, Single.MinValue, Single.MinValue };
1690
1691 for (int i = 0; i < vcount; i++)
1692 {
1693 float3 p = vertices[i];
1694 for (int j = 0; j < 3; j++)
1695 {
1696 if (p[j] < bmin2[j])
1697 bmin2[j] = p[j];
1698 if (p[j] > bmax2[j])
1699 bmax2[j] = p[j];
1700 }
1701 }
1702
1703 float dx2 = bmax2[0] - bmin2[0];
1704 float dy2 = bmax2[1] - bmin2[1];
1705 float dz2 = bmax2[2] - bmin2[2];
1706
1707 if (dx2 < EPSILON || dy2 < EPSILON || dz2 < EPSILON || vcount < 3)
1708 {
1709 float cx = dx2 * 0.5f + bmin2[0];
1710 float cy = dy2 * 0.5f + bmin2[1];
1711 float cz = dz2 * 0.5f + bmin2[2];
1712
1713 float len = Single.MaxValue;
1714
1715 if (dx2 >= EPSILON && dx2 < len)
1716 len = dx2;
1717 if (dy2 >= EPSILON && dy2 < len)
1718 len = dy2;
1719 if (dz2 >= EPSILON && dz2 < len)
1720 len = dz2;
1721
1722 if (len == Single.MaxValue)
1723 {
1724 dx2 = dy2 = dz2 = 0.01f; // one centimeter
1725 }
1726 else
1727 {
1728 if (dx2 < EPSILON) // 1/5th the shortest non-zero edge.
1729 dx2 = len * 0.05f;
1730 if (dy2 < EPSILON)
1731 dy2 = len * 0.05f;
1732 if (dz2 < EPSILON)
1733 dz2 = len * 0.05f;
1734 }
1735
1736 float x1 = cx - dx2;
1737 float x2 = cx + dx2;
1738
1739 float y1 = cy - dy2;
1740 float y2 = cy + dy2;
1741
1742 float z1 = cz - dz2;
1743 float z2 = cz + dz2;
1744
1745 vcount = 0; // add box
1746
1747 addPoint(ref vcount, vertices, x1, y1, z1);
1748 addPoint(ref vcount, vertices, x2, y1, z1);
1749 addPoint(ref vcount, vertices, x2, y2, z1);
1750 addPoint(ref vcount, vertices, x1, y2, z1);
1751 addPoint(ref vcount, vertices, x1, y1, z2);
1752 addPoint(ref vcount, vertices, x2, y1, z2);
1753 addPoint(ref vcount, vertices, x2, y2, z2);
1754 addPoint(ref vcount, vertices, x1, y2, z2);
1755
1756 return true;
1757 }
1758 }
1759
1760 return true;
1761 }
1762
1763 private static void BringOutYourDead(List<float3> verts, out List<float3> overts, List<int> indices)
1764 {
1765 int[] used = new int[verts.Count];
1766 int ocount = 0;
1767
1768 overts = new List<float3>();
1769
1770 for (int i = 0; i < indices.Count; i++)
1771 {
1772 int v = indices[i]; // original array index
1773
1774 Debug.Assert(v >= 0 && v < verts.Count);
1775
1776 if (used[v] != 0) // if already remapped
1777 {
1778 indices[i] = used[v] - 1; // index to new array
1779 }
1780 else
1781 {
1782 indices[i] = ocount; // new index mapping
1783
1784 overts.Add(verts[v]); // copy old vert to new vert array
1785
1786 ocount++; // increment output vert count
1787
1788 Debug.Assert(ocount >= 0 && ocount <= verts.Count);
1789
1790 used[v] = ocount; // assign new index remapping
1791 }
1792 }
1793 }
1794
1795 public static HullError CreateConvexHull(HullDesc desc, ref HullResult result)
1796 {
1797 HullError ret = HullError.QE_FAIL;
1798
1799 PHullResult hr = new PHullResult();
1800
1801 uint vcount = (uint)desc.Vertices.Count;
1802 if (vcount < 8)
1803 vcount = 8;
1804
1805 List<float3> vsource;
1806 float3 scale = new float3();
1807
1808 bool ok = CleanupVertices(desc.Vertices, out vsource, desc.NormalEpsilon, out scale); // normalize point cloud, remove duplicates!
1809
1810 if (ok)
1811 {
1812 if (true) // scale vertices back to their original size.
1813 {
1814 for (int i = 0; i < vsource.Count; i++)
1815 {
1816 float3 v = vsource[i];
1817 v.x *= scale[0];
1818 v.y *= scale[1];
1819 v.z *= scale[2];
1820 }
1821 }
1822
1823 float skinwidth = 0;
1824 if (desc.HasHullFlag(HullFlag.QF_SKIN_WIDTH))
1825 skinwidth = desc.SkinWidth;
1826
1827 ok = ComputeHull(vsource, ref hr, (int)desc.MaxVertices, skinwidth);
1828
1829 if (ok)
1830 {
1831 List<float3> vscratch;
1832 BringOutYourDead(hr.Vertices, out vscratch, hr.Indices);
1833
1834 ret = HullError.QE_OK;
1835
1836 if (desc.HasHullFlag(HullFlag.QF_TRIANGLES)) // if he wants the results as triangle!
1837 {
1838 result.Polygons = false;
1839 result.Indices = hr.Indices;
1840 result.OutputVertices = vscratch;
1841 }
1842 else
1843 {
1844 result.Polygons = true;
1845 result.OutputVertices = vscratch;
1846
1847 if (true)
1848 {
1849 List<int> source = hr.Indices;
1850 List<int> dest = new List<int>();
1851 for (int i = 0; i < hr.Indices.Count / 3; i++)
1852 {
1853 dest.Add(3);
1854 dest.Add(source[i * 3 + 0]);
1855 dest.Add(source[i * 3 + 1]);
1856 dest.Add(source[i * 3 + 2]);
1857 }
1858
1859 result.Indices = dest;
1860 }
1861 }
1862 }
1863 }
1864
1865 return ret;
1866 }
1867 }
1868}
diff --git a/OpenSim/Region/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..d099676
--- /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.Physics.ConvexDecompositionDotNet
31{
32 public class Plane
33 {
34 public float3 normal = new float3();
35 public float dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0
36
37 public Plane(float3 n, float d)
38 {
39 normal = new float3(n);
40 dist = d;
41 }
42
43 public Plane(Plane p)
44 {
45 normal = new float3(p.normal);
46 dist = p.dist;
47 }
48
49 public Plane()
50 {
51 dist = 0;
52 }
53
54 public void Transform(float3 position, Quaternion orientation)
55 {
56 // Transforms the plane to the space defined by the
57 // given position/orientation
58 float3 newNormal = Quaternion.Inverse(orientation) * normal;
59 float3 origin = Quaternion.Inverse(orientation) * (-normal * dist - position);
60
61 normal = newNormal;
62 dist = -float3.dot(newNormal, origin);
63 }
64
65 public override int GetHashCode()
66 {
67 return normal.GetHashCode() ^ dist.GetHashCode();
68 }
69
70 public override bool Equals(object obj)
71 {
72 Plane p = obj as Plane;
73 if (p == null)
74 return false;
75
76 return this == p;
77 }
78
79 public static bool operator ==(Plane a, Plane b)
80 {
81 return (a.normal == b.normal && a.dist == b.dist);
82 }
83
84 public static bool operator !=(Plane a, Plane b)
85 {
86 return !(a == b);
87 }
88
89 public static Plane PlaneFlip(Plane plane)
90 {
91 return new Plane(-plane.normal, -plane.dist);
92 }
93
94 public static bool coplanar(Plane a, Plane b)
95 {
96 return (a == b || a == PlaneFlip(b));
97 }
98 }
99}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs
new file mode 100644
index 0000000..31f0182
--- /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.Physics.ConvexDecompositionDotNet
33{
34 public enum PlaneTriResult : int
35 {
36 PTR_FRONT,
37 PTR_BACK,
38 PTR_SPLIT
39 }
40
41 public static class PlaneTri
42 {
43 private static float DistToPt(float3 p, float4 plane)
44 {
45 return p.x * plane.x + p.y * plane.y + p.z * plane.z + plane.w;
46 }
47
48 private static PlaneTriResult getSidePlane(float3 p, float4 plane, float epsilon)
49 {
50 float d = DistToPt(p, plane);
51
52 if ((d + epsilon) > 0f)
53 return PlaneTriResult.PTR_FRONT; // it is 'in front' within the provided epsilon value.
54
55 return PlaneTriResult.PTR_BACK;
56 }
57
58 private static void add(float3 p, float3[] dest, ref int pcount)
59 {
60 dest[pcount++] = new float3(p);
61 Debug.Assert(pcount <= 4);
62 }
63
64 // assumes that the points are on opposite sides of the plane!
65 private static void intersect(float3 p1, float3 p2, float3 split, float4 plane)
66 {
67 float dp1 = DistToPt(p1, plane);
68 float[] dir = new float[3];
69
70 dir[0] = p2[0] - p1[0];
71 dir[1] = p2[1] - p1[1];
72 dir[2] = p2[2] - p1[2];
73
74 float dot1 = dir[0] * plane[0] + dir[1] * plane[1] + dir[2] * plane[2];
75 float dot2 = dp1 - plane[3];
76
77 float t = -(plane[3] + dot2) / dot1;
78
79 split.x = (dir[0] * t) + p1[0];
80 split.y = (dir[1] * t) + p1[1];
81 split.z = (dir[2] * t) + p1[2];
82 }
83
84 public static PlaneTriResult planeTriIntersection(float4 plane, FaceTri triangle, float epsilon, ref float3[] front, out int fcount, ref float3[] back, out int bcount)
85 {
86 fcount = 0;
87 bcount = 0;
88
89 // get the three vertices of the triangle.
90 float3 p1 = triangle.P1;
91 float3 p2 = triangle.P2;
92 float3 p3 = triangle.P3;
93
94 PlaneTriResult r1 = getSidePlane(p1, plane, epsilon); // compute the side of the plane each vertex is on
95 PlaneTriResult r2 = getSidePlane(p2, plane, epsilon);
96 PlaneTriResult r3 = getSidePlane(p3, plane, epsilon);
97
98 if (r1 == r2 && r1 == r3) // if all three vertices are on the same side of the plane.
99 {
100 if (r1 == PlaneTriResult.PTR_FRONT) // if all three are in front of the plane, then copy to the 'front' output triangle.
101 {
102 add(p1, front, ref fcount);
103 add(p2, front, ref fcount);
104 add(p3, front, ref fcount);
105 }
106 else
107 {
108 add(p1, back, ref bcount); // if all three are in 'back' then copy to the 'back' output triangle.
109 add(p2, back, ref bcount);
110 add(p3, back, ref bcount);
111 }
112 return r1; // if all three points are on the same side of the plane return result
113 }
114
115 // ok.. we need to split the triangle at the plane.
116
117 // First test ray segment P1 to P2
118 if (r1 == r2) // if these are both on the same side...
119 {
120 if (r1 == PlaneTriResult.PTR_FRONT)
121 {
122 add(p1, front, ref fcount);
123 add(p2, front, ref fcount);
124 }
125 else
126 {
127 add(p1, back, ref bcount);
128 add(p2, back, ref bcount);
129 }
130 }
131 else
132 {
133 float3 split = new float3();
134 intersect(p1, p2, split, plane);
135
136 if (r1 == PlaneTriResult.PTR_FRONT)
137 {
138
139 add(p1, front, ref fcount);
140 add(split, front, ref fcount);
141
142 add(split, back, ref bcount);
143 add(p2, back, ref bcount);
144
145 }
146 else
147 {
148 add(p1, back, ref bcount);
149 add(split, back, ref bcount);
150
151 add(split, front, ref fcount);
152 add(p2, front, ref fcount);
153 }
154
155 }
156
157 // Next test ray segment P2 to P3
158 if (r2 == r3) // if these are both on the same side...
159 {
160 if (r3 == PlaneTriResult.PTR_FRONT)
161 {
162 add(p3, front, ref fcount);
163 }
164 else
165 {
166 add(p3, back, ref bcount);
167 }
168 }
169 else
170 {
171 float3 split = new float3(); // split the point
172 intersect(p2, p3, split, plane);
173
174 if (r3 == PlaneTriResult.PTR_FRONT)
175 {
176 add(split, front, ref fcount);
177 add(split, back, ref bcount);
178
179 add(p3, front, ref fcount);
180 }
181 else
182 {
183 add(split, front, ref fcount);
184 add(split, back, ref bcount);
185
186 add(p3, back, ref bcount);
187 }
188 }
189
190 // Next test ray segment P3 to P1
191 if (r3 != r1) // if these are both on the same side...
192 {
193 float3 split = new float3(); // split the point
194 intersect(p3, p1, split, plane);
195
196 if (r1 == PlaneTriResult.PTR_FRONT)
197 {
198 add(split, front, ref fcount);
199 add(split, back, ref bcount);
200 }
201 else
202 {
203 add(split, front, ref fcount);
204 add(split, back, ref bcount);
205 }
206 }
207
208 return PlaneTriResult.PTR_SPLIT;
209 }
210 }
211}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c5867b2
--- /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.2.*")]
36
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs
new file mode 100644
index 0000000..0ba8f17
--- /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.Physics.ConvexDecompositionDotNet
31{
32 public class Quaternion : float4
33 {
34 public Quaternion()
35 {
36 x = y = z = 0.0f;
37 w = 1.0f;
38 }
39
40 public Quaternion(float3 v, float t)
41 {
42 v = float3.normalize(v);
43 w = (float)Math.Cos(t / 2.0f);
44 v = v * (float)Math.Sin(t / 2.0f);
45 x = v.x;
46 y = v.y;
47 z = v.z;
48 }
49
50 public Quaternion(float _x, float _y, float _z, float _w)
51 {
52 x = _x;
53 y = _y;
54 z = _z;
55 w = _w;
56 }
57
58 public float angle()
59 {
60 return (float)Math.Acos(w) * 2.0f;
61 }
62
63 public float3 axis()
64 {
65 float3 a = new float3(x, y, z);
66 if (Math.Abs(angle()) < 0.0000001f)
67 return new float3(1f, 0f, 0f);
68 return a * (1 / (float)Math.Sin(angle() / 2.0f));
69 }
70
71 public float3 xdir()
72 {
73 return new float3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
74 }
75
76 public float3 ydir()
77 {
78 return new float3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
79 }
80
81 public float3 zdir()
82 {
83 return new float3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
84 }
85
86 public float3x3 getmatrix()
87 {
88 return new float3x3(xdir(), ydir(), zdir());
89 }
90
91 public static implicit operator float3x3(Quaternion q)
92 {
93 return q.getmatrix();
94 }
95
96 public static Quaternion operator *(Quaternion a, Quaternion b)
97 {
98 Quaternion c = new Quaternion();
99 c.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
100 c.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y;
101 c.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
102 c.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
103 return c;
104 }
105
106 public static float3 operator *(Quaternion q, float3 v)
107 {
108 // The following is equivalent to:
109 //return (q.getmatrix() * v);
110 float qx2 = q.x * q.x;
111 float qy2 = q.y * q.y;
112 float qz2 = q.z * q.z;
113
114 float qxqy = q.x * q.y;
115 float qxqz = q.x * q.z;
116 float qxqw = q.x * q.w;
117 float qyqz = q.y * q.z;
118 float qyqw = q.y * q.w;
119 float qzqw = q.z * q.w;
120 return new float3((1 - 2 * (qy2 + qz2)) * v.x + (2 * (qxqy - qzqw)) * v.y + (2 * (qxqz + qyqw)) * v.z, (2 * (qxqy + qzqw)) * v.x + (1 - 2 * (qx2 + qz2)) * v.y + (2 * (qyqz - qxqw)) * v.z, (2 * (qxqz - qyqw)) * v.x + (2 * (qyqz + qxqw)) * v.y + (1 - 2 * (qx2 + qy2)) * v.z);
121 }
122
123 public static Quaternion operator +(Quaternion a, Quaternion b)
124 {
125 return new Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
126 }
127
128 public static Quaternion operator *(Quaternion a, float b)
129 {
130 return new Quaternion(a.x *b, a.y *b, a.z *b, a.w *b);
131 }
132
133 public static Quaternion normalize(Quaternion a)
134 {
135 float m = (float)Math.Sqrt(a.w * a.w + a.x * a.x + a.y * a.y + a.z * a.z);
136 if (m < 0.000000001f)
137 {
138 a.w = 1;
139 a.x = a.y = a.z = 0;
140 return a;
141 }
142 return a * (1f / m);
143 }
144
145 public static float dot(Quaternion a, Quaternion b)
146 {
147 return (a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z);
148 }
149
150 public static Quaternion slerp(Quaternion a, Quaternion b, float interp)
151 {
152 if (dot(a, b) < 0.0)
153 {
154 a.w = -a.w;
155 a.x = -a.x;
156 a.y = -a.y;
157 a.z = -a.z;
158 }
159 float d = dot(a, b);
160 if (d >= 1.0)
161 {
162 return a;
163 }
164 float theta = (float)Math.Acos(d);
165 if (theta == 0.0f)
166 {
167 return (a);
168 }
169 return a * ((float)Math.Sin(theta - interp * theta) / (float)Math.Sin(theta)) + b * ((float)Math.Sin(interp * theta) / (float)Math.Sin(theta));
170 }
171
172 public static Quaternion Interpolate(Quaternion q0, Quaternion q1, float alpha)
173 {
174 return slerp(q0, q1, alpha);
175 }
176
177 public static Quaternion Inverse(Quaternion q)
178 {
179 return new Quaternion(-q.x, -q.y, -q.z, q.w);
180 }
181
182 public static Quaternion YawPitchRoll(float yaw, float pitch, float roll)
183 {
184 roll *= (3.14159264f / 180.0f);
185 yaw *= (3.14159264f / 180.0f);
186 pitch *= (3.14159264f / 180.0f);
187 return new Quaternion(new float3(0.0f, 0.0f, 1.0f), yaw) * new Quaternion(new float3(1.0f, 0.0f, 0.0f), pitch) * new Quaternion(new float3(0.0f, 1.0f, 0.0f), roll);
188 }
189
190 public static float Yaw(Quaternion q)
191 {
192 float3 v = q.ydir();
193 return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f);
194 }
195
196 public static float Pitch(Quaternion q)
197 {
198 float3 v = q.ydir();
199 return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f);
200 }
201
202 public static float Roll(Quaternion q)
203 {
204 q = new Quaternion(new float3(0.0f, 0.0f, 1.0f), -Yaw(q) * (3.14159264f / 180.0f)) * q;
205 q = new Quaternion(new float3(1.0f, 0.0f, 0.0f), -Pitch(q) * (3.14159264f / 180.0f)) * q;
206 return (float)Math.Atan2(-q.xdir().z, q.xdir().x) * (180.0f / 3.14159264f);
207 }
208 }
209}
diff --git a/OpenSim/Region/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..9f06a9a
--- /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.Physics.ConvexDecompositionDotNet
32{
33 public class Rect3d
34 {
35 public float[] mMin = new float[3];
36 public float[] mMax = new float[3];
37
38 public Rect3d()
39 {
40 }
41
42 public Rect3d(float[] bmin, float[] bmax)
43 {
44 mMin[0] = bmin[0];
45 mMin[1] = bmin[1];
46 mMin[2] = bmin[2];
47
48 mMax[0] = bmax[0];
49 mMax[1] = bmax[1];
50 mMax[2] = bmax[2];
51 }
52
53 public void SetMin(float[] bmin)
54 {
55 mMin[0] = bmin[0];
56 mMin[1] = bmin[1];
57 mMin[2] = bmin[2];
58 }
59
60 public void SetMax(float[] bmax)
61 {
62 mMax[0] = bmax[0];
63 mMax[1] = bmax[1];
64 mMax[2] = bmax[2];
65 }
66
67 public void SetMin(float x, float y, float z)
68 {
69 mMin[0] = x;
70 mMin[1] = y;
71 mMin[2] = z;
72 }
73
74 public void SetMax(float x, float y, float z)
75 {
76 mMax[0] = x;
77 mMax[1] = y;
78 mMax[2] = z;
79 }
80 }
81
82 public static class SplitPlane
83 {
84 public static bool computeSplitPlane(List<float3> vertices, List<int> indices, ref float4 plane)
85 {
86 float[] bmin = { Single.MaxValue, Single.MaxValue, Single.MaxValue };
87 float[] bmax = { Single.MinValue, Single.MinValue, Single.MinValue };
88
89 for (int i = 0; i < vertices.Count; i++)
90 {
91 float3 p = vertices[i];
92
93 if (p[0] < bmin[0])
94 bmin[0] = p[0];
95 if (p[1] < bmin[1])
96 bmin[1] = p[1];
97 if (p[2] < bmin[2])
98 bmin[2] = p[2];
99
100 if (p[0] > bmax[0])
101 bmax[0] = p[0];
102 if (p[1] > bmax[1])
103 bmax[1] = p[1];
104 if (p[2] > bmax[2])
105 bmax[2] = p[2];
106 }
107
108 float dx = bmax[0] - bmin[0];
109 float dy = bmax[1] - bmin[1];
110 float dz = bmax[2] - bmin[2];
111
112 float laxis = dx;
113
114 int axis = 0;
115
116 if (dy > dx)
117 {
118 axis = 1;
119 laxis = dy;
120 }
121
122 if (dz > dx && dz > dy)
123 {
124 axis = 2;
125 laxis = dz;
126 }
127
128 float[] p1 = new float[3];
129 float[] p2 = new float[3];
130 float[] p3 = new float[3];
131
132 p3[0] = p2[0] = p1[0] = bmin[0] + dx * 0.5f;
133 p3[1] = p2[1] = p1[1] = bmin[1] + dy * 0.5f;
134 p3[2] = p2[2] = p1[2] = bmin[2] + dz * 0.5f;
135
136 Rect3d b = new Rect3d(bmin, bmax);
137
138 Rect3d b1 = new Rect3d();
139 Rect3d b2 = new Rect3d();
140
141 splitRect(axis, b, b1, b2, p1);
142
143 switch (axis)
144 {
145 case 0:
146 p2[1] = bmin[1];
147 p2[2] = bmin[2];
148
149 if (dz > dy)
150 {
151 p3[1] = bmax[1];
152 p3[2] = bmin[2];
153 }
154 else
155 {
156 p3[1] = bmin[1];
157 p3[2] = bmax[2];
158 }
159
160 break;
161 case 1:
162 p2[0] = bmin[0];
163 p2[2] = bmin[2];
164
165 if (dx > dz)
166 {
167 p3[0] = bmax[0];
168 p3[2] = bmin[2];
169 }
170 else
171 {
172 p3[0] = bmin[0];
173 p3[2] = bmax[2];
174 }
175
176 break;
177 case 2:
178 p2[0] = bmin[0];
179 p2[1] = bmin[1];
180
181 if (dx > dy)
182 {
183 p3[0] = bmax[0];
184 p3[1] = bmin[1];
185 }
186 else
187 {
188 p3[0] = bmin[0];
189 p3[1] = bmax[1];
190 }
191
192 break;
193 }
194
195 computePlane(p1, p2, p3, plane);
196
197 return true;
198 }
199
200 internal static void computePlane(float[] A, float[] B, float[] C, float4 plane)
201 {
202 float vx = (B[0] - C[0]);
203 float vy = (B[1] - C[1]);
204 float vz = (B[2] - C[2]);
205
206 float wx = (A[0] - B[0]);
207 float wy = (A[1] - B[1]);
208 float wz = (A[2] - B[2]);
209
210 float vw_x = vy * wz - vz * wy;
211 float vw_y = vz * wx - vx * wz;
212 float vw_z = vx * wy - vy * wx;
213
214 float mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
215
216 if (mag < 0.000001f)
217 {
218 mag = 0;
219 }
220 else
221 {
222 mag = 1.0f / mag;
223 }
224
225 float x = vw_x * mag;
226 float y = vw_y * mag;
227 float z = vw_z * mag;
228
229 float D = 0.0f - ((x * A[0]) + (y * A[1]) + (z * A[2]));
230
231 plane.x = x;
232 plane.y = y;
233 plane.z = z;
234 plane.w = D;
235 }
236
237 public static void splitRect(int axis, Rect3d source, Rect3d b1, Rect3d b2, float[] midpoint)
238 {
239 switch (axis)
240 {
241 case 0:
242 b1.SetMin(source.mMin);
243 b1.SetMax(midpoint[0], source.mMax[1], source.mMax[2]);
244
245 b2.SetMin(midpoint[0], source.mMin[1], source.mMin[2]);
246 b2.SetMax(source.mMax);
247 break;
248 case 1:
249 b1.SetMin(source.mMin);
250 b1.SetMax(source.mMax[0], midpoint[1], source.mMax[2]);
251
252 b2.SetMin(source.mMin[0], midpoint[1], source.mMin[2]);
253 b2.SetMax(source.mMax);
254 break;
255 case 2:
256 b1.SetMin(source.mMin);
257 b1.SetMax(source.mMax[0], source.mMax[1], midpoint[2]);
258
259 b2.SetMin(source.mMin[0], source.mMin[1], midpoint[2]);
260 b2.SetMax(source.mMax);
261 break;
262 }
263 }
264 }
265}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs
new file mode 100644
index 0000000..6f17c9f
--- /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.Physics.ConvexDecompositionDotNet
32{
33 public class VertexPool
34 {
35 private List<float3> mVertices = new List<float3>();
36 private Dictionary<float3, int> mIndices = new Dictionary<float3, int>();
37
38 public int getIndex(float3 vtx)
39 {
40 int idx;
41 if (mIndices.TryGetValue(vtx, out idx))
42 return idx;
43
44 idx = mVertices.Count;
45 mVertices.Add(vtx);
46 mIndices.Add(vtx, idx);
47 return idx;
48 }
49
50 public float3 Get(int idx)
51 {
52 return mVertices[idx];
53 }
54
55 public int GetSize()
56 {
57 return mVertices.Count;
58 }
59
60 public List<float3> GetVertices()
61 {
62 return mVertices;
63 }
64
65 public void Clear()
66 {
67 mVertices.Clear();
68 }
69 }
70}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs
new file mode 100644
index 0000000..ce88fc8
--- /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.Physics.ConvexDecompositionDotNet
31{
32 public class float2
33 {
34 public float x;
35 public float y;
36
37 public float2()
38 {
39 }
40
41 public float2(float _x, float _y)
42 {
43 x = _x;
44 y = _y;
45 }
46
47 public float this[int i]
48 {
49 get
50 {
51 switch (i)
52 {
53 case 0: return x;
54 case 1: return y;
55 }
56 throw new ArgumentOutOfRangeException();
57 }
58 }
59
60 public static float2 operator -(float2 a, float2 b)
61 {
62 return new float2(a.x - b.x, a.y - b.y);
63 }
64
65 public static float2 operator +(float2 a, float2 b)
66 {
67 return new float2(a.x + b.x, a.y + b.y);
68 }
69 }
70}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs
new file mode 100644
index 0000000..4389114
--- /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.Physics.ConvexDecompositionDotNet
31{
32 public class float3 : IEquatable<float3>
33 {
34 public float x;
35 public float y;
36 public float z;
37
38 public float3()
39 {
40 x = 0;
41 y = 0;
42 z = 0;
43 }
44
45 public float3(float _x, float _y, float _z)
46 {
47 x = _x;
48 y = _y;
49 z = _z;
50 }
51
52 public float3(float3 f)
53 {
54 x = f.x;
55 y = f.y;
56 z = f.z;
57 }
58
59 public float this[int i]
60 {
61 get
62 {
63 switch (i)
64 {
65 case 0: return x;
66 case 1: return y;
67 case 2: return z;
68 }
69 throw new ArgumentOutOfRangeException();
70 }
71 }
72
73 public float Distance(float3 a)
74 {
75 float3 d = new float3(a.x - x, a.y - y, a.z - z);
76 return d.Length();
77 }
78
79 public float Distance2(float3 a)
80 {
81 float dx = a.x - x;
82 float dy = a.y - y;
83 float dz = a.z - z;
84 return dx * dx + dy * dy + dz * dz;
85 }
86
87 public float Length()
88 {
89 return (float)Math.Sqrt(x * x + y * y + z * z);
90 }
91
92 public float Area(float3 p1, float3 p2)
93 {
94 float A = Partial(p1);
95 A += p1.Partial(p2);
96 A += p2.Partial(this);
97 return A * 0.5f;
98 }
99
100 public float Partial(float3 p)
101 {
102 return (x * p.y) - (p.x * y);
103 }
104
105 // Given a point and a line (defined by two points), compute the closest point
106 // in the line. (The line is treated as infinitely long.)
107 public void NearestPointInLine(float3 point, float3 line0, float3 line1)
108 {
109 float3 nearestPoint = new float3();
110 float3 lineDelta = line1 - line0;
111
112 // Handle degenerate lines
113 if (lineDelta == float3.Zero)
114 {
115 nearestPoint = line0;
116 }
117 else
118 {
119 float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta);
120 nearestPoint = line0 + lineDelta * delta;
121 }
122
123 this.x = nearestPoint.x;
124 this.y = nearestPoint.y;
125 this.z = nearestPoint.z;
126 }
127
128 // Given a point and a line segment (defined by two points), compute the closest point
129 // in the line. Cap the point at the endpoints of the line segment.
130 public void NearestPointInLineSegment(float3 point, float3 line0, float3 line1)
131 {
132 float3 nearestPoint = new float3();
133 float3 lineDelta = line1 - line0;
134
135 // Handle degenerate lines
136 if (lineDelta == Zero)
137 {
138 nearestPoint = line0;
139 }
140 else
141 {
142 float delta = float3.dot(point - line0, lineDelta) / float3.dot(lineDelta, lineDelta);
143
144 // Clamp the point to conform to the segment's endpoints
145 if (delta < 0)
146 delta = 0;
147 else if (delta > 1)
148 delta = 1;
149
150 nearestPoint = line0 + lineDelta * delta;
151 }
152
153 this.x = nearestPoint.x;
154 this.y = nearestPoint.y;
155 this.z = nearestPoint.z;
156 }
157
158 // Given a point and a triangle (defined by three points), compute the closest point
159 // in the triangle. Clamp the point so it's confined to the area of the triangle.
160 public void NearestPointInTriangle(float3 point, float3 triangle0, float3 triangle1, float3 triangle2)
161 {
162 float3 nearestPoint = new float3();
163
164 float3 lineDelta0 = triangle1 - triangle0;
165 float3 lineDelta1 = triangle2 - triangle0;
166
167 // Handle degenerate triangles
168 if ((lineDelta0 == Zero) || (lineDelta1 == Zero))
169 {
170 nearestPoint.NearestPointInLineSegment(point, triangle1, triangle2);
171 }
172 else if (lineDelta0 == lineDelta1)
173 {
174 nearestPoint.NearestPointInLineSegment(point, triangle0, triangle1);
175 }
176 else
177 {
178 float3[] axis = new float3[3] { new float3(), new float3(), new float3() };
179 axis[0].NearestPointInLine(triangle0, triangle1, triangle2);
180 axis[1].NearestPointInLine(triangle1, triangle0, triangle2);
181 axis[2].NearestPointInLine(triangle2, triangle0, triangle1);
182
183 float3 axisDot = new float3();
184 axisDot.x = dot(triangle0 - axis[0], point - axis[0]);
185 axisDot.y = dot(triangle1 - axis[1], point - axis[1]);
186 axisDot.z = dot(triangle2 - axis[2], point - axis[2]);
187
188 bool bForce = true;
189 float bestMagnitude2 = 0;
190 float closeMagnitude2;
191 float3 closePoint = new float3();
192
193 if (axisDot.x < 0f)
194 {
195 closePoint.NearestPointInLineSegment(point, triangle1, triangle2);
196 closeMagnitude2 = point.Distance2(closePoint);
197 if (bForce || (bestMagnitude2 > closeMagnitude2))
198 {
199 bForce = false;
200 bestMagnitude2 = closeMagnitude2;
201 nearestPoint = closePoint;
202 }
203 }
204 if (axisDot.y < 0f)
205 {
206 closePoint.NearestPointInLineSegment(point, triangle0, triangle2);
207 closeMagnitude2 = point.Distance2(closePoint);
208 if (bForce || (bestMagnitude2 > closeMagnitude2))
209 {
210 bForce = false;
211 bestMagnitude2 = closeMagnitude2;
212 nearestPoint = closePoint;
213 }
214 }
215 if (axisDot.z < 0f)
216 {
217 closePoint.NearestPointInLineSegment(point, triangle0, triangle1);
218 closeMagnitude2 = point.Distance2(closePoint);
219 if (bForce || (bestMagnitude2 > closeMagnitude2))
220 {
221 bForce = false;
222 bestMagnitude2 = closeMagnitude2;
223 nearestPoint = closePoint;
224 }
225 }
226
227 // If bForce is true at this point, it means the nearest point lies
228 // inside the triangle; use the nearest-point-on-a-plane equation
229 if (bForce)
230 {
231 float3 normal;
232
233 // Get the normal of the polygon (doesn't have to be a unit vector)
234 normal = float3.cross(lineDelta0, lineDelta1);
235
236 float3 pointDelta = point - triangle0;
237 float delta = float3.dot(normal, pointDelta) / float3.dot(normal, normal);
238
239 nearestPoint = point - normal * delta;
240 }
241 }
242
243 this.x = nearestPoint.x;
244 this.y = nearestPoint.y;
245 this.z = nearestPoint.z;
246 }
247
248 public static float3 operator +(float3 a, float3 b)
249 {
250 return new float3(a.x + b.x, a.y + b.y, a.z + b.z);
251 }
252
253 public static float3 operator -(float3 a, float3 b)
254 {
255 return new float3(a.x - b.x, a.y - b.y, a.z - b.z);
256 }
257
258 public static float3 operator -(float3 a, float s)
259 {
260 return new float3(a.x - s, a.y - s, a.z - s);
261 }
262
263 public static float3 operator -(float3 v)
264 {
265 return new float3(-v.x, -v.y, -v.z);
266 }
267
268 public static float3 operator *(float3 v, float s)
269 {
270 return new float3(v.x * s, v.y * s, v.z * s);
271 }
272
273 public static float3 operator *(float s, float3 v)
274 {
275 return new float3(v.x * s, v.y * s, v.z * s);
276 }
277
278 public static float3 operator *(float3 v, float3x3 m)
279 {
280 return new float3((m.x.x * v.x + m.y.x * v.y + m.z.x * v.z), (m.x.y * v.x + m.y.y * v.y + m.z.y * v.z), (m.x.z * v.x + m.y.z * v.y + m.z.z * v.z));
281 }
282
283 public static float3 operator *(float3x3 m, float3 v)
284 {
285 return new float3(dot(m.x, v), dot(m.y, v), dot(m.z, v));
286 }
287
288 public static float3 operator /(float3 v, float s)
289 {
290 float sinv = 1.0f / s;
291 return new float3(v.x * sinv, v.y * sinv, v.z * sinv);
292 }
293
294 public bool Equals(float3 other)
295 {
296 return this == other;
297 }
298
299 public override bool Equals(object obj)
300 {
301 float3 f = obj as float3;
302 if (f == null)
303 return false;
304
305 return this == f;
306 }
307
308 public override int GetHashCode()
309 {
310 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
311 }
312
313 public static bool operator ==(float3 a, float3 b)
314 {
315 // If both are null, or both are same instance, return true.
316 if (System.Object.ReferenceEquals(a, b))
317 return true;
318 // If one is null, but not both, return false.
319 if (((object)a == null) || ((object)b == null))
320 return false;
321
322 return (a.x == b.x && a.y == b.y && a.z == b.z);
323 }
324
325 public static bool operator !=(float3 a, float3 b)
326 {
327 return (a.x != b.x || a.y != b.y || a.z != b.z);
328 }
329
330 public static float dot(float3 a, float3 b)
331 {
332 return a.x * b.x + a.y * b.y + a.z * b.z;
333 }
334
335 public static float3 cmul(float3 v1, float3 v2)
336 {
337 return new float3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
338 }
339
340 public static float3 cross(float3 a, float3 b)
341 {
342 return new float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
343 }
344
345 public static float3 Interpolate(float3 v0, float3 v1, float alpha)
346 {
347 return v0 * (1 - alpha) + v1 * alpha;
348 }
349
350 public static float3 Round(float3 a, int digits)
351 {
352 return new float3((float)Math.Round(a.x, digits), (float)Math.Round(a.y, digits), (float)Math.Round(a.z, digits));
353 }
354
355 public static float3 VectorMax(float3 a, float3 b)
356 {
357 return new float3(Math.Max(a.x, b.x), Math.Max(a.y, b.y), Math.Max(a.z, b.z));
358 }
359
360 public static float3 VectorMin(float3 a, float3 b)
361 {
362 return new float3(Math.Min(a.x, b.x), Math.Min(a.y, b.y), Math.Min(a.z, b.z));
363 }
364
365 public static float3 vabs(float3 v)
366 {
367 return new float3(Math.Abs(v.x), Math.Abs(v.y), Math.Abs(v.z));
368 }
369
370 public static float magnitude(float3 v)
371 {
372 return (float)Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
373 }
374
375 public static float3 normalize(float3 v)
376 {
377 float d = magnitude(v);
378 if (d == 0)
379 d = 0.1f;
380 d = 1 / d;
381 return new float3(v.x * d, v.y * d, v.z * d);
382 }
383
384 public static float3 safenormalize(float3 v)
385 {
386 if (magnitude(v) <= 0.0f)
387 return new float3(1, 0, 0);
388 else
389 return normalize(v);
390 }
391
392 public static float Yaw(float3 v)
393 {
394 return (v.y == 0.0 && v.x == 0.0) ? 0.0f : (float)Math.Atan2(-v.x, v.y) * (180.0f / 3.14159264f);
395 }
396
397 public static float Pitch(float3 v)
398 {
399 return (float)Math.Atan2(v.z, Math.Sqrt(v.x * v.x + v.y * v.y)) * (180.0f / 3.14159264f);
400 }
401
402 public float ComputePlane(float3 A, float3 B, float3 C)
403 {
404 float vx, vy, vz, wx, wy, wz, vw_x, vw_y, vw_z, mag;
405
406 vx = (B.x - C.x);
407 vy = (B.y - C.y);
408 vz = (B.z - C.z);
409
410 wx = (A.x - B.x);
411 wy = (A.y - B.y);
412 wz = (A.z - B.z);
413
414 vw_x = vy * wz - vz * wy;
415 vw_y = vz * wx - vx * wz;
416 vw_z = vx * wy - vy * wx;
417
418 mag = (float)Math.Sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z));
419
420 if (mag < 0.000001f)
421 {
422 mag = 0;
423 }
424 else
425 {
426 mag = 1.0f / mag;
427 }
428
429 x = vw_x * mag;
430 y = vw_y * mag;
431 z = vw_z * mag;
432
433 float D = 0.0f - ((x * A.x) + (y * A.y) + (z * A.z));
434 return D;
435 }
436
437 public override string ToString()
438 {
439 return String.Format("<{0}, {1}, {2}>", x, y, z);
440 }
441
442 public static readonly float3 Zero = new float3();
443 }
444}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs
new file mode 100644
index 0000000..76cf063
--- /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.Physics.ConvexDecompositionDotNet
33{
34 public class float3x3
35 {
36 public float3 x = new float3();
37 public float3 y = new float3();
38 public float3 z = new float3();
39
40 public float3x3()
41 {
42 }
43
44 public float3x3(float xx, float xy, float xz, float yx, float yy, float yz, float zx, float zy, float zz)
45 {
46 x = new float3(xx, xy, xz);
47 y = new float3(yx, yy, yz);
48 z = new float3(zx, zy, zz);
49 }
50
51 public float3x3(float3 _x, float3 _y, float3 _z)
52 {
53 x = new float3(_x);
54 y = new float3(_y);
55 z = new float3(_z);
56 }
57
58 public float3 this[int i]
59 {
60 get
61 {
62 switch (i)
63 {
64 case 0: return x;
65 case 1: return y;
66 case 2: return z;
67 }
68 throw new ArgumentOutOfRangeException();
69 }
70 }
71
72 public float this[int i, int j]
73 {
74 get
75 {
76 switch (i)
77 {
78 case 0:
79 switch (j)
80 {
81 case 0: return x.x;
82 case 1: return x.y;
83 case 2: return x.z;
84 }
85 break;
86 case 1:
87 switch (j)
88 {
89 case 0: return y.x;
90 case 1: return y.y;
91 case 2: return y.z;
92 }
93 break;
94 case 2:
95 switch (j)
96 {
97 case 0: return z.x;
98 case 1: return z.y;
99 case 2: return z.z;
100 }
101 break;
102 }
103 throw new ArgumentOutOfRangeException();
104 }
105 set
106 {
107 switch (i)
108 {
109 case 0:
110 switch (j)
111 {
112 case 0: x.x = value; return;
113 case 1: x.y = value; return;
114 case 2: x.z = value; return;
115 }
116 break;
117 case 1:
118 switch (j)
119 {
120 case 0: y.x = value; return;
121 case 1: y.y = value; return;
122 case 2: y.z = value; return;
123 }
124 break;
125 case 2:
126 switch (j)
127 {
128 case 0: z.x = value; return;
129 case 1: z.y = value; return;
130 case 2: z.z = value; return;
131 }
132 break;
133 }
134 throw new ArgumentOutOfRangeException();
135 }
136 }
137
138 public static float3x3 Transpose(float3x3 m)
139 {
140 return new float3x3(new float3(m.x.x, m.y.x, m.z.x), new float3(m.x.y, m.y.y, m.z.y), new float3(m.x.z, m.y.z, m.z.z));
141 }
142
143 public static float3x3 operator *(float3x3 a, float3x3 b)
144 {
145 return new float3x3(a.x * b, a.y * b, a.z * b);
146 }
147
148 public static float3x3 operator *(float3x3 a, float s)
149 {
150 return new float3x3(a.x * s, a.y * s, a.z * s);
151 }
152
153 public static float3x3 operator /(float3x3 a, float s)
154 {
155 float t = 1f / s;
156 return new float3x3(a.x * t, a.y * t, a.z * t);
157 }
158
159 public static float3x3 operator +(float3x3 a, float3x3 b)
160 {
161 return new float3x3(a.x + b.x, a.y + b.y, a.z + b.z);
162 }
163
164 public static float3x3 operator -(float3x3 a, float3x3 b)
165 {
166 return new float3x3(a.x - b.x, a.y - b.y, a.z - b.z);
167 }
168
169 public static float Determinant(float3x3 m)
170 {
171 return m.x.x * m.y.y * m.z.z + m.y.x * m.z.y * m.x.z + m.z.x * m.x.y * m.y.z - m.x.x * m.z.y * m.y.z - m.y.x * m.x.y * m.z.z - m.z.x * m.y.y * m.x.z;
172 }
173
174 public static float3x3 Inverse(float3x3 a)
175 {
176 float3x3 b = new float3x3();
177 float d = Determinant(a);
178 Debug.Assert(d != 0);
179 for (int i = 0; i < 3; i++)
180 {
181 for (int j = 0; j < 3; j++)
182 {
183 int i1 = (i + 1) % 3;
184 int i2 = (i + 2) % 3;
185 int j1 = (j + 1) % 3;
186 int j2 = (j + 2) % 3;
187
188 // reverse indexs i&j to take transpose
189 b[i, j] = (a[i1][j1] * a[i2][j2] - a[i1][j2] * a[i2][j1]) / d;
190 }
191 }
192 return b;
193 }
194 }
195}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs
new file mode 100644
index 0000000..fa60876
--- /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.Physics.ConvexDecompositionDotNet
31{
32 public class float4
33 {
34 public float x;
35 public float y;
36 public float z;
37 public float w;
38
39 public float4()
40 {
41 x = 0;
42 y = 0;
43 z = 0;
44 w = 0;
45 }
46
47 public float4(float _x, float _y, float _z, float _w)
48 {
49 x = _x;
50 y = _y;
51 z = _z;
52 w = _w;
53 }
54
55 public float4(float3 v, float _w)
56 {
57 x = v.x;
58 y = v.y;
59 z = v.z;
60 w = _w;
61 }
62
63 public float4(float4 f)
64 {
65 x = f.x;
66 y = f.y;
67 z = f.z;
68 w = f.w;
69 }
70
71 public float this[int i]
72 {
73 get
74 {
75 switch (i)
76 {
77 case 0: return x;
78 case 1: return y;
79 case 2: return z;
80 case 3: return w;
81 }
82 throw new ArgumentOutOfRangeException();
83 }
84 }
85
86 public float3 xyz()
87 {
88 return new float3(x, y, z);
89 }
90
91 public void setxyz(float3 xyz)
92 {
93 x = xyz.x;
94 y = xyz.y;
95 z = xyz.z;
96 }
97
98 public override int GetHashCode()
99 {
100 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
101 }
102
103 public override bool Equals(object obj)
104 {
105 float4 f = obj as float4;
106 if (f == null)
107 return false;
108
109 return this == f;
110 }
111
112 public static float4 Homogenize(float3 v3)
113 {
114 return Homogenize(v3, 1.0f);
115 }
116
117 //C++ TO C# CONVERTER NOTE: C# does not allow default values for parameters. Overloaded methods are inserted above.
118 //ORIGINAL LINE: float4 Homogenize(const float3 &v3, const float &w =1.0f)
119 public static float4 Homogenize(float3 v3, float w)
120 {
121 return new float4(v3.x, v3.y, v3.z, w);
122 }
123
124 public static float4 cmul(float4 a, float4 b)
125 {
126 return new float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
127 }
128
129 public static float4 operator +(float4 a, float4 b)
130 {
131 return new float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
132 }
133 public static float4 operator -(float4 a, float4 b)
134 {
135 return new float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
136 }
137
138 public static float4 operator *(float4 v, float4x4 m)
139 {
140 return v.x * m.x + v.y * m.y + v.z * m.z + v.w * m.w; // yes this actually works
141 }
142
143 public static bool operator ==(float4 a, float4 b)
144 {
145 // If both are null, or both are same instance, return true.
146 if (System.Object.ReferenceEquals(a, b))
147 return true;
148 // If one is null, but not both, return false.
149 if (((object)a == null) || ((object)b == null))
150 return false;
151
152 return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
153 }
154
155 public static bool operator !=(float4 a, float4 b)
156 {
157 return !(a == b);
158 }
159
160 public static float4 operator *(float4 v, float s)
161 {
162 return new float4(v.x * s, v.y * s, v.z * s, v.w * s);
163 }
164
165 public static float4 operator *(float s, float4 v)
166 {
167 return new float4(v.x * s, v.y * s, v.z * s, v.w * s);
168 }
169 }
170}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs
new file mode 100644
index 0000000..7d1592f
--- /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.Physics.ConvexDecompositionDotNet
34{
35 public class float4x4
36 {
37 public float4 x = new float4();
38 public float4 y = new float4();
39 public float4 z = new float4();
40 public float4 w = new float4();
41
42 public float4x4()
43 {
44 }
45
46 public float4x4(float4 _x, float4 _y, float4 _z, float4 _w)
47 {
48 x = new float4(_x);
49 y = new float4(_y);
50 z = new float4(_z);
51 w = new float4(_w);
52 }
53
54 public float4x4(
55 float m00, float m01, float m02, float m03,
56 float m10, float m11, float m12, float m13,
57 float m20, float m21, float m22, float m23,
58 float m30, float m31, float m32, float m33)
59 {
60 x = new float4(m00, m01, m02, m03);
61 y = new float4(m10, m11, m12, m13);
62 z = new float4(m20, m21, m22, m23);
63 w = new float4(m30, m31, m32, m33);
64 }
65
66 public float4x4(float4x4 m)
67 {
68 x = new float4(m.x);
69 y = new float4(m.y);
70 z = new float4(m.z);
71 w = new float4(m.w);
72 }
73
74 public float4 this[int i]
75 {
76 get
77 {
78 switch (i)
79 {
80 case 0: return x;
81 case 1: return y;
82 case 2: return z;
83 case 3: return w;
84 }
85 throw new ArgumentOutOfRangeException();
86 }
87 set
88 {
89 switch (i)
90 {
91 case 0: x = value; return;
92 case 1: y = value; return;
93 case 2: z = value; return;
94 case 3: w = value; return;
95 }
96 throw new ArgumentOutOfRangeException();
97 }
98 }
99
100 public override int GetHashCode()
101 {
102 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
103 }
104
105 public override bool Equals(object obj)
106 {
107 float4x4 m = obj as float4x4;
108 if (m == null)
109 return false;
110
111 return this == m;
112 }
113
114 public static float4x4 operator *(float4x4 a, float4x4 b)
115 {
116 return new float4x4(a.x * b, a.y * b, a.z * b, a.w * b);
117 }
118
119 public static bool operator ==(float4x4 a, float4x4 b)
120 {
121 return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
122 }
123
124 public static bool operator !=(float4x4 a, float4x4 b)
125 {
126 return !(a == b);
127 }
128
129 public static float4x4 Inverse(float4x4 m)
130 {
131 float4x4 d = new float4x4();
132 //float dst = d.x.x;
133 float[] tmp = new float[12]; // temp array for pairs
134 float[] src = new float[16]; // array of transpose source matrix
135 float det; // determinant
136 // transpose matrix
137 for (int i = 0; i < 4; i++)
138 {
139 src[i] = m[i].x;
140 src[i + 4] = m[i].y;
141 src[i + 8] = m[i].z;
142 src[i + 12] = m[i].w;
143 }
144 // calculate pairs for first 8 elements (cofactors)
145 tmp[0] = src[10] * src[15];
146 tmp[1] = src[11] * src[14];
147 tmp[2] = src[9] * src[15];
148 tmp[3] = src[11] * src[13];
149 tmp[4] = src[9] * src[14];
150 tmp[5] = src[10] * src[13];
151 tmp[6] = src[8] * src[15];
152 tmp[7] = src[11] * src[12];
153 tmp[8] = src[8] * src[14];
154 tmp[9] = src[10] * src[12];
155 tmp[10] = src[8] * src[13];
156 tmp[11] = src[9] * src[12];
157 // calculate first 8 elements (cofactors)
158 d.x.x = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7];
159 d.x.x -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7];
160 d.x.y = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7];
161 d.x.y -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7];
162 d.x.z = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7];
163 d.x.z -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7];
164 d.x.w = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6];
165 d.x.w -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6];
166 d.y.x = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3];
167 d.y.x -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3];
168 d.y.y = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3];
169 d.y.y -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3];
170 d.y.z = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3];
171 d.y.z -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3];
172 d.y.w = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2];
173 d.y.w -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2];
174 // calculate pairs for second 8 elements (cofactors)
175 tmp[0] = src[2]*src[7];
176 tmp[1] = src[3]*src[6];
177 tmp[2] = src[1]*src[7];
178 tmp[3] = src[3]*src[5];
179 tmp[4] = src[1]*src[6];
180 tmp[5] = src[2]*src[5];
181 tmp[6] = src[0]*src[7];
182 tmp[7] = src[3]*src[4];
183 tmp[8] = src[0]*src[6];
184 tmp[9] = src[2]*src[4];
185 tmp[10] = src[0]*src[5];
186 tmp[11] = src[1]*src[4];
187 // calculate second 8 elements (cofactors)
188 d.z.x = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15];
189 d.z.x -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15];
190 d.z.y = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15];
191 d.z.y -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15];
192 d.z.z = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15];
193 d.z.z -= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15];
194 d.z.w = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14];
195 d.z.w-= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14];
196 d.w.x = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9];
197 d.w.x-= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10];
198 d.w.y = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10];
199 d.w.y-= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8];
200 d.w.z = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8];
201 d.w.z-= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9];
202 d.w.w = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9];
203 d.w.w-= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8];
204 // calculate determinant
205 det = src[0] * d.x.x + src[1] * d.x.y + src[2] * d.x.z + src[3] * d.x.w;
206 // calculate matrix inverse
207 det = 1/det;
208 for (int j = 0; j < 4; j++)
209 d[j] *= det;
210 return d;
211 }
212
213 public static float4x4 MatrixRigidInverse(float4x4 m)
214 {
215 float4x4 trans_inverse = MatrixTranslation(-m.w.xyz());
216 float4x4 rot = new float4x4(m);
217 rot.w = new float4(0f, 0f, 0f, 1f);
218 return trans_inverse * MatrixTranspose(rot);
219 }
220 public static float4x4 MatrixTranspose(float4x4 m)
221 {
222 return new float4x4(m.x.x, m.y.x, m.z.x, m.w.x, m.x.y, m.y.y, m.z.y, m.w.y, m.x.z, m.y.z, m.z.z, m.w.z, m.x.w, m.y.w, m.z.w, m.w.w);
223 }
224 public static float4x4 MatrixPerspectiveFov(float fovy, float aspect, float zn, float zf)
225 {
226 float h = 1.0f / (float)Math.Tan(fovy / 2.0f); // view space height
227 float w = h / aspect; // view space width
228 return new float4x4(w, 0, 0, 0, 0, h, 0, 0, 0, 0, zf / (zn - zf), -1, 0, 0, zn * zf / (zn - zf), 0);
229 }
230 public static float4x4 MatrixTranslation(float3 t)
231 {
232 return new float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, t.x, t.y, t.z, 1);
233 }
234 public static float4x4 MatrixRotationZ(float angle_radians)
235 {
236 float s = (float)Math.Sin(angle_radians);
237 float c = (float)Math.Cos(angle_radians);
238 return new float4x4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
239 }
240 public static float4x4 MatrixLookAt(float3 eye, float3 at, float3 up)
241 {
242 float4x4 m = new float4x4();
243 m.w.w = 1.0f;
244 m.w.setxyz(eye);
245 m.z.setxyz(float3.normalize(eye - at));
246 m.x.setxyz(float3.normalize(float3.cross(up, m.z.xyz())));
247 m.y.setxyz(float3.cross(m.z.xyz(), m.x.xyz()));
248 return MatrixRigidInverse(m);
249 }
250
251 public static float4x4 MatrixFromQuatVec(Quaternion q, float3 v)
252 {
253 // builds a 4x4 transformation matrix based on orientation q and translation v
254 float qx2 = q.x * q.x;
255 float qy2 = q.y * q.y;
256 float qz2 = q.z * q.z;
257
258 float qxqy = q.x * q.y;
259 float qxqz = q.x * q.z;
260 float qxqw = q.x * q.w;
261 float qyqz = q.y * q.z;
262 float qyqw = q.y * q.w;
263 float qzqw = q.z * q.w;
264
265 return new float4x4(
266 1 - 2 * (qy2 + qz2),
267 2 * (qxqy + qzqw),
268 2 * (qxqz - qyqw),
269 0,
270 2 * (qxqy - qzqw),
271 1 - 2 * (qx2 + qz2),
272 2 * (qyqz + qxqw),
273 0,
274 2 * (qxqz + qyqw),
275 2 * (qyqz - qxqw),
276 1 - 2 * (qx2 + qy2),
277 0,
278 v.x,
279 v.y,
280 v.z,
281 1.0f);
282 }
283 }
284}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs
new file mode 100644
index 0000000..9c5760d
--- /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.Physics.ConvexDecompositionDotNet
31{
32 public class int3
33 {
34 public int x;
35 public int y;
36 public int z;
37
38 public int3()
39 {
40 }
41
42 public int3(int _x, int _y, int _z)
43 {
44 x = _x;
45 y = _y;
46 z = _z;
47 }
48
49 public int this[int i]
50 {
51 get
52 {
53 switch (i)
54 {
55 case 0: return x;
56 case 1: return y;
57 case 2: return z;
58 }
59 throw new ArgumentOutOfRangeException();
60 }
61 set
62 {
63 switch (i)
64 {
65 case 0: x = value; return;
66 case 1: y = value; return;
67 case 2: z = value; return;
68 }
69 throw new ArgumentOutOfRangeException();
70 }
71 }
72
73 public override int GetHashCode()
74 {
75 return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
76 }
77
78 public override bool Equals(object obj)
79 {
80 int3 i = obj as int3;
81 if (i == null)
82 return false;
83
84 return this == i;
85 }
86
87 public static bool operator ==(int3 a, int3 b)
88 {
89 // If both are null, or both are same instance, return true.
90 if (System.Object.ReferenceEquals(a, b))
91 return true;
92 // If one is null, but not both, return false.
93 if (((object)a == null) || ((object)b == null))
94 return false;
95
96 for (int i = 0; i < 3; i++)
97 {
98 if (a[i] != b[i])
99 return false;
100 }
101 return true;
102 }
103
104 public static bool operator !=(int3 a, int3 b)
105 {
106 return !(a == b);
107 }
108
109 public static int3 roll3(int3 a)
110 {
111 int tmp = a[0];
112 a[0] = a[1];
113 a[1] = a[2];
114 a[2] = tmp;
115 return a;
116 }
117
118 public static bool isa(int3 a, int3 b)
119 {
120 return (a == b || roll3(a) == b || a == roll3(b));
121 }
122
123 public static bool b2b(int3 a, int3 b)
124 {
125 return isa(a, new int3(b[2], b[1], b[0]));
126 }
127 }
128}
diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs
new file mode 100644
index 0000000..c2b32e5
--- /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.Physics.ConvexDecompositionDotNet
31{
32 public class int4
33 {
34 public int x;
35 public int y;
36 public int z;
37 public int w;
38
39 public int4()
40 {
41 }
42
43 public int4(int _x, int _y, int _z, int _w)
44 {
45 x = _x;
46 y = _y;
47 z = _z;
48 w = _w;
49 }
50
51 public int this[int i]
52 {
53 get
54 {
55 switch (i)
56 {
57 case 0: return x;
58 case 1: return y;
59 case 2: return z;
60 case 3: return w;
61 }
62 throw new ArgumentOutOfRangeException();
63 }
64 }
65 }
66}
diff --git a/OpenSim/Region/PhysicsModules/Meshing/HelperTypes.cs b/OpenSim/Region/PhysicsModules/Meshing/HelperTypes.cs
new file mode 100644
index 0000000..8cd8dcf
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/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.Physics.Manager;
34using OpenSim.Region.Physics.Meshing;
35
36public class Vertex : IComparable<Vertex>
37{
38 Vector3 vector;
39
40 public float X
41 {
42 get { return vector.X; }
43 set { vector.X = value; }
44 }
45
46 public float Y
47 {
48 get { return vector.Y; }
49 set { vector.Y = value; }
50 }
51
52 public float Z
53 {
54 get { return vector.Z; }
55 set { vector.Z = value; }
56 }
57
58 public Vertex(float x, float y, float z)
59 {
60 vector.X = x;
61 vector.Y = y;
62 vector.Z = z;
63 }
64
65 public Vertex normalize()
66 {
67 float tlength = vector.Length();
68 if (tlength != 0f)
69 {
70 float mul = 1.0f / tlength;
71 return new Vertex(vector.X * mul, vector.Y * mul, vector.Z * mul);
72 }
73 else
74 {
75 return new Vertex(0f, 0f, 0f);
76 }
77 }
78
79 public Vertex cross(Vertex v)
80 {
81 return new Vertex(vector.Y * v.Z - vector.Z * v.Y, vector.Z * v.X - vector.X * v.Z, vector.X * v.Y - vector.Y * v.X);
82 }
83
84 // disable warning: mono compiler moans about overloading
85 // operators hiding base operator but should not according to C#
86 // language spec
87#pragma warning disable 0108
88 public static Vertex operator *(Vertex v, Quaternion q)
89 {
90 // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/
91
92 Vertex v2 = new Vertex(0f, 0f, 0f);
93
94 v2.X = q.W * q.W * v.X +
95 2f * q.Y * q.W * v.Z -
96 2f * q.Z * q.W * v.Y +
97 q.X * q.X * v.X +
98 2f * q.Y * q.X * v.Y +
99 2f * q.Z * q.X * v.Z -
100 q.Z * q.Z * v.X -
101 q.Y * q.Y * v.X;
102
103 v2.Y =
104 2f * q.X * q.Y * v.X +
105 q.Y * q.Y * v.Y +
106 2f * q.Z * q.Y * v.Z +
107 2f * q.W * q.Z * v.X -
108 q.Z * q.Z * v.Y +
109 q.W * q.W * v.Y -
110 2f * q.X * q.W * v.Z -
111 q.X * q.X * v.Y;
112
113 v2.Z =
114 2f * q.X * q.Z * v.X +
115 2f * q.Y * q.Z * v.Y +
116 q.Z * q.Z * v.Z -
117 2f * q.W * q.Y * v.X -
118 q.Y * q.Y * v.Z +
119 2f * q.W * q.X * v.Y -
120 q.X * q.X * v.Z +
121 q.W * q.W * v.Z;
122
123 return v2;
124 }
125
126 public static Vertex operator +(Vertex v1, Vertex v2)
127 {
128 return new Vertex(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
129 }
130
131 public static Vertex operator -(Vertex v1, Vertex v2)
132 {
133 return new Vertex(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
134 }
135
136 public static Vertex operator *(Vertex v1, Vertex v2)
137 {
138 return new Vertex(v1.X * v2.X, v1.Y * v2.Y, v1.Z * v2.Z);
139 }
140
141 public static Vertex operator +(Vertex v1, float am)
142 {
143 v1.X += am;
144 v1.Y += am;
145 v1.Z += am;
146 return v1;
147 }
148
149 public static Vertex operator -(Vertex v1, float am)
150 {
151 v1.X -= am;
152 v1.Y -= am;
153 v1.Z -= am;
154 return v1;
155 }
156
157 public static Vertex operator *(Vertex v1, float am)
158 {
159 v1.X *= am;
160 v1.Y *= am;
161 v1.Z *= am;
162 return v1;
163 }
164
165 public static Vertex operator /(Vertex v1, float am)
166 {
167 if (am == 0f)
168 {
169 return new Vertex(0f,0f,0f);
170 }
171 float mul = 1.0f / am;
172 v1.X *= mul;
173 v1.Y *= mul;
174 v1.Z *= mul;
175 return v1;
176 }
177#pragma warning restore 0108
178
179
180 public float dot(Vertex v)
181 {
182 return X * v.X + Y * v.Y + Z * v.Z;
183 }
184
185 public Vertex(Vector3 v)
186 {
187 vector = v;
188 }
189
190 public Vertex Clone()
191 {
192 return new Vertex(X, Y, Z);
193 }
194
195 public static Vertex FromAngle(double angle)
196 {
197 return new Vertex((float) Math.Cos(angle), (float) Math.Sin(angle), 0.0f);
198 }
199
200 public float Length()
201 {
202 return vector.Length();
203 }
204
205 public virtual bool Equals(Vertex v, float tolerance)
206 {
207 Vertex diff = this - v;
208 float d = diff.Length();
209 if (d < tolerance)
210 return true;
211
212 return false;
213 }
214
215
216 public int CompareTo(Vertex other)
217 {
218 if (X < other.X)
219 return -1;
220
221 if (X > other.X)
222 return 1;
223
224 if (Y < other.Y)
225 return -1;
226
227 if (Y > other.Y)
228 return 1;
229
230 if (Z < other.Z)
231 return -1;
232
233 if (Z > other.Z)
234 return 1;
235
236 return 0;
237 }
238
239 public static bool operator >(Vertex me, Vertex other)
240 {
241 return me.CompareTo(other) > 0;
242 }
243
244 public static bool operator <(Vertex me, Vertex other)
245 {
246 return me.CompareTo(other) < 0;
247 }
248
249 public String ToRaw()
250 {
251 // Why this stuff with the number formatter?
252 // Well, the raw format uses the english/US notation of numbers
253 // where the "," separates groups of 1000 while the "." marks the border between 1 and 10E-1.
254 // The german notation uses these characters exactly vice versa!
255 // The Float.ToString() routine is a localized one, giving different results depending on the country
256 // settings your machine works with. Unusable for a machine readable file format :-(
257 NumberFormatInfo nfi = new NumberFormatInfo();
258 nfi.NumberDecimalSeparator = ".";
259 nfi.NumberDecimalDigits = 3;
260
261 String s1 = X.ToString("N2", nfi) + " " + Y.ToString("N2", nfi) + " " + Z.ToString("N2", nfi);
262
263 return s1;
264 }
265}
266
267public class Triangle
268{
269 public Vertex v1;
270 public Vertex v2;
271 public Vertex v3;
272
273 private float radius_square;
274 private float cx;
275 private float cy;
276
277 public Triangle(Vertex _v1, Vertex _v2, Vertex _v3)
278 {
279 v1 = _v1;
280 v2 = _v2;
281 v3 = _v3;
282
283 CalcCircle();
284 }
285
286 public bool isInCircle(float x, float y)
287 {
288 float dx, dy;
289 float dd;
290
291 dx = x - cx;
292 dy = y - cy;
293
294 dd = dx*dx + dy*dy;
295 if (dd < radius_square)
296 return true;
297 else
298 return false;
299 }
300
301 public bool isDegraded()
302 {
303 // This means, the vertices of this triangle are somewhat strange.
304 // They either line up or at least two of them are identical
305 return (radius_square == 0.0);
306 }
307
308 private void CalcCircle()
309 {
310 // Calculate the center and the radius of a circle given by three points p1, p2, p3
311 // It is assumed, that the triangles vertices are already set correctly
312 double p1x, p2x, p1y, p2y, p3x, p3y;
313
314 // Deviation of this routine:
315 // A circle has the general equation (M-p)^2=r^2, where M and p are vectors
316 // this gives us three equations f(p)=r^2, each for one point p1, p2, p3
317 // putting respectively two equations together gives two equations
318 // f(p1)=f(p2) and f(p1)=f(p3)
319 // bringing all constant terms to one side brings them to the form
320 // M*v1=c1 resp.M*v2=c2 where v1=(p1-p2) and v2=(p1-p3) (still vectors)
321 // and c1, c2 are scalars (Naming conventions like the variables below)
322 // Now using the equations that are formed by the components of the vectors
323 // and isolate Mx lets you make one equation that only holds My
324 // The rest is straight forward and eaasy :-)
325 //
326
327 /* helping variables for temporary results */
328 double c1, c2;
329 double v1x, v1y, v2x, v2y;
330
331 double z, n;
332
333 double rx, ry;
334
335 // Readout the three points, the triangle consists of
336 p1x = v1.X;
337 p1y = v1.Y;
338
339 p2x = v2.X;
340 p2y = v2.Y;
341
342 p3x = v3.X;
343 p3y = v3.Y;
344
345 /* calc helping values first */
346 c1 = (p1x*p1x + p1y*p1y - p2x*p2x - p2y*p2y)/2;
347 c2 = (p1x*p1x + p1y*p1y - p3x*p3x - p3y*p3y)/2;
348
349 v1x = p1x - p2x;
350 v1y = p1y - p2y;
351
352 v2x = p1x - p3x;
353 v2y = p1y - p3y;
354
355 z = (c1*v2x - c2*v1x);
356 n = (v1y*v2x - v2y*v1x);
357
358 if (n == 0.0) // This is no triangle, i.e there are (at least) two points at the same location
359 {
360 radius_square = 0.0f;
361 return;
362 }
363
364 cy = (float) (z/n);
365
366 if (v2x != 0.0)
367 {
368 cx = (float) ((c2 - v2y*cy)/v2x);
369 }
370 else if (v1x != 0.0)
371 {
372 cx = (float) ((c1 - v1y*cy)/v1x);
373 }
374 else
375 {
376 Debug.Assert(false, "Malformed triangle"); /* Both terms zero means nothing good */
377 }
378
379 rx = (p1x - cx);
380 ry = (p1y - cy);
381
382 radius_square = (float) (rx*rx + ry*ry);
383 }
384
385 public override String ToString()
386 {
387 NumberFormatInfo nfi = new NumberFormatInfo();
388 nfi.CurrencyDecimalDigits = 2;
389 nfi.CurrencyDecimalSeparator = ".";
390
391 String s1 = "<" + v1.X.ToString(nfi) + "," + v1.Y.ToString(nfi) + "," + v1.Z.ToString(nfi) + ">";
392 String s2 = "<" + v2.X.ToString(nfi) + "," + v2.Y.ToString(nfi) + "," + v2.Z.ToString(nfi) + ">";
393 String s3 = "<" + v3.X.ToString(nfi) + "," + v3.Y.ToString(nfi) + "," + v3.Z.ToString(nfi) + ">";
394
395 return s1 + ";" + s2 + ";" + s3;
396 }
397
398 public Vector3 getNormal()
399 {
400 // Vertices
401
402 // Vectors for edges
403 Vector3 e1;
404 Vector3 e2;
405
406 e1 = new Vector3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
407 e2 = new Vector3(v1.X - v3.X, v1.Y - v3.Y, v1.Z - v3.Z);
408
409 // Cross product for normal
410 Vector3 n = Vector3.Cross(e1, e2);
411
412 // Length
413 float l = n.Length();
414
415 // Normalized "normal"
416 n = n/l;
417
418 return n;
419 }
420
421 public void invertNormal()
422 {
423 Vertex vt;
424 vt = v1;
425 v1 = v2;
426 v2 = vt;
427 }
428
429 // Dumps a triangle in the "raw faces" format, blender can import. This is for visualisation and
430 // debugging purposes
431 public String ToStringRaw()
432 {
433 String output = v1.ToRaw() + " " + v2.ToRaw() + " " + v3.ToRaw();
434 return output;
435 }
436}
diff --git a/OpenSim/Region/PhysicsModules/Meshing/Mesh.cs b/OpenSim/Region/PhysicsModules/Meshing/Mesh.cs
new file mode 100644
index 0000000..bd8e306
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/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.Physics.Manager;
33using PrimMesher;
34using OpenMetaverse;
35
36namespace OpenSim.Region.Physics.Meshing
37{
38 public class Mesh : IMesh
39 {
40 private Dictionary<Vertex, int> m_vertices;
41 private List<Triangle> m_triangles;
42 GCHandle m_pinnedVertexes;
43 GCHandle m_pinnedIndex;
44 IntPtr m_verticesPtr = IntPtr.Zero;
45 int m_vertexCount = 0;
46 IntPtr m_indicesPtr = IntPtr.Zero;
47 int m_indexCount = 0;
48 public float[] m_normals;
49
50 public Mesh()
51 {
52 m_vertices = new Dictionary<Vertex, int>();
53 m_triangles = new List<Triangle>();
54 }
55
56 public Mesh Clone()
57 {
58 Mesh result = new Mesh();
59
60 foreach (Triangle t in m_triangles)
61 {
62 result.Add(new Triangle(t.v1.Clone(), t.v2.Clone(), t.v3.Clone()));
63 }
64
65 return result;
66 }
67
68 public void Add(Triangle triangle)
69 {
70 if (m_pinnedIndex.IsAllocated || m_pinnedVertexes.IsAllocated || m_indicesPtr != IntPtr.Zero || m_verticesPtr != IntPtr.Zero)
71 throw new NotSupportedException("Attempt to Add to a pinned Mesh");
72 // If a vertex of the triangle is not yet in the vertices list,
73 // add it and set its index to the current index count
74 if (!m_vertices.ContainsKey(triangle.v1))
75 m_vertices[triangle.v1] = m_vertices.Count;
76 if (!m_vertices.ContainsKey(triangle.v2))
77 m_vertices[triangle.v2] = m_vertices.Count;
78 if (!m_vertices.ContainsKey(triangle.v3))
79 m_vertices[triangle.v3] = m_vertices.Count;
80 m_triangles.Add(triangle);
81 }
82
83 public void CalcNormals()
84 {
85 int iTriangles = m_triangles.Count;
86
87 this.m_normals = new float[iTriangles * 3];
88
89 int i = 0;
90 foreach (Triangle t in m_triangles)
91 {
92 float ux, uy, uz;
93 float vx, vy, vz;
94 float wx, wy, wz;
95
96 ux = t.v1.X;
97 uy = t.v1.Y;
98 uz = t.v1.Z;
99
100 vx = t.v2.X;
101 vy = t.v2.Y;
102 vz = t.v2.Z;
103
104 wx = t.v3.X;
105 wy = t.v3.Y;
106 wz = t.v3.Z;
107
108
109 // Vectors for edges
110 float e1x, e1y, e1z;
111 float e2x, e2y, e2z;
112
113 e1x = ux - vx;
114 e1y = uy - vy;
115 e1z = uz - vz;
116
117 e2x = ux - wx;
118 e2y = uy - wy;
119 e2z = uz - wz;
120
121
122 // Cross product for normal
123 float nx, ny, nz;
124 nx = e1y * e2z - e1z * e2y;
125 ny = e1z * e2x - e1x * e2z;
126 nz = e1x * e2y - e1y * e2x;
127
128 // Length
129 float l = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz);
130 float lReciprocal = 1.0f / l;
131
132 // Normalized "normal"
133 //nx /= l;
134 //ny /= l;
135 //nz /= l;
136
137 m_normals[i] = nx * lReciprocal;
138 m_normals[i + 1] = ny * lReciprocal;
139 m_normals[i + 2] = nz * lReciprocal;
140
141 i += 3;
142 }
143 }
144
145 public List<Vector3> getVertexList()
146 {
147 List<Vector3> result = new List<Vector3>();
148 foreach (Vertex v in m_vertices.Keys)
149 {
150 result.Add(new Vector3(v.X, v.Y, v.Z));
151 }
152 return result;
153 }
154
155 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.cs b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer.cs
new file mode 100644
index 0000000..42231b5
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/Meshmerizer.cs
@@ -0,0 +1,971 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27//#define SPAM
28
29using System;
30using System.Collections.Generic;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using System.Drawing;
36using System.Drawing.Imaging;
37using System.IO.Compression;
38using PrimMesher;
39using log4net;
40using Nini.Config;
41using System.Reflection;
42using System.IO;
43
44namespace OpenSim.Region.Physics.Meshing
45{
46 public class MeshmerizerPlugin : IMeshingPlugin
47 {
48 public MeshmerizerPlugin()
49 {
50 }
51
52 public string GetName()
53 {
54 return "Meshmerizer";
55 }
56
57 public IMesher GetMesher(IConfigSource config)
58 {
59 return new Meshmerizer(config);
60 }
61 }
62
63 public class Meshmerizer : IMesher
64 {
65 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
66 private static string LogHeader = "[MESH]";
67
68 // Setting baseDir to a path will enable the dumping of raw files
69 // raw files can be imported by blender so a visual inspection of the results can be done
70#if SPAM
71 const string baseDir = "rawFiles";
72#else
73 private const string baseDir = null; //"rawFiles";
74#endif
75 // If 'true', lots of DEBUG logging of asset parsing details
76 private bool debugDetail = false;
77
78 private bool cacheSculptMaps = true;
79 private string decodedSculptMapPath = null;
80 private bool useMeshiesPhysicsMesh = false;
81
82 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
83
84 private List<List<Vector3>> mConvexHulls = null;
85 private List<Vector3> mBoundingHull = null;
86
87 // Mesh cache. Static so it can be shared across instances of this class
88 private static Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
89
90 public Meshmerizer(IConfigSource config)
91 {
92 IConfig start_config = config.Configs["Startup"];
93 IConfig mesh_config = config.Configs["Mesh"];
94
95 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
96 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
97 if (mesh_config != null)
98 {
99 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
100 debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail);
101 }
102
103 try
104 {
105 if (!Directory.Exists(decodedSculptMapPath))
106 Directory.CreateDirectory(decodedSculptMapPath);
107 }
108 catch (Exception e)
109 {
110 m_log.WarnFormat("[SCULPT]: Unable to create {0} directory: ", decodedSculptMapPath, e.Message);
111 }
112 }
113
114 /// <summary>
115 /// creates a simple box mesh of the specified size. This mesh is of very low vertex count and may
116 /// be useful as a backup proxy when level of detail is not needed or when more complex meshes fail
117 /// for some reason
118 /// </summary>
119 /// <param name="minX"></param>
120 /// <param name="maxX"></param>
121 /// <param name="minY"></param>
122 /// <param name="maxY"></param>
123 /// <param name="minZ"></param>
124 /// <param name="maxZ"></param>
125 /// <returns></returns>
126 private static Mesh CreateSimpleBoxMesh(float minX, float maxX, float minY, float maxY, float minZ, float maxZ)
127 {
128 Mesh box = new Mesh();
129 List<Vertex> vertices = new List<Vertex>();
130 // bottom
131
132 vertices.Add(new Vertex(minX, maxY, minZ));
133 vertices.Add(new Vertex(maxX, maxY, minZ));
134 vertices.Add(new Vertex(maxX, minY, minZ));
135 vertices.Add(new Vertex(minX, minY, minZ));
136
137 box.Add(new Triangle(vertices[0], vertices[1], vertices[2]));
138 box.Add(new Triangle(vertices[0], vertices[2], vertices[3]));
139
140 // top
141
142 vertices.Add(new Vertex(maxX, maxY, maxZ));
143 vertices.Add(new Vertex(minX, maxY, maxZ));
144 vertices.Add(new Vertex(minX, minY, maxZ));
145 vertices.Add(new Vertex(maxX, minY, maxZ));
146
147 box.Add(new Triangle(vertices[4], vertices[5], vertices[6]));
148 box.Add(new Triangle(vertices[4], vertices[6], vertices[7]));
149
150 // sides
151
152 box.Add(new Triangle(vertices[5], vertices[0], vertices[3]));
153 box.Add(new Triangle(vertices[5], vertices[3], vertices[6]));
154
155 box.Add(new Triangle(vertices[1], vertices[0], vertices[5]));
156 box.Add(new Triangle(vertices[1], vertices[5], vertices[4]));
157
158 box.Add(new Triangle(vertices[7], vertices[1], vertices[4]));
159 box.Add(new Triangle(vertices[7], vertices[2], vertices[1]));
160
161 box.Add(new Triangle(vertices[3], vertices[2], vertices[7]));
162 box.Add(new Triangle(vertices[3], vertices[7], vertices[6]));
163
164 return box;
165 }
166
167 /// <summary>
168 /// Creates a simple bounding box mesh for a complex input mesh
169 /// </summary>
170 /// <param name="meshIn"></param>
171 /// <returns></returns>
172 private static Mesh CreateBoundingBoxMesh(Mesh meshIn)
173 {
174 float minX = float.MaxValue;
175 float maxX = float.MinValue;
176 float minY = float.MaxValue;
177 float maxY = float.MinValue;
178 float minZ = float.MaxValue;
179 float maxZ = float.MinValue;
180
181 foreach (Vector3 v in meshIn.getVertexList())
182 {
183 if (v.X < minX) minX = v.X;
184 if (v.Y < minY) minY = v.Y;
185 if (v.Z < minZ) minZ = v.Z;
186
187 if (v.X > maxX) maxX = v.X;
188 if (v.Y > maxY) maxY = v.Y;
189 if (v.Z > maxZ) maxZ = v.Z;
190 }
191
192 return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ);
193 }
194
195 private void ReportPrimError(string message, string primName, PrimMesh primMesh)
196 {
197 m_log.Error(message);
198 m_log.Error("\nPrim Name: " + primName);
199 m_log.Error("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString());
200 }
201
202 /// <summary>
203 /// Add a submesh to an existing list of coords and faces.
204 /// </summary>
205 /// <param name="subMeshData"></param>
206 /// <param name="size">Size of entire object</param>
207 /// <param name="coords"></param>
208 /// <param name="faces"></param>
209 private void AddSubMesh(OSDMap subMeshData, Vector3 size, List<Coord> coords, List<Face> faces)
210 {
211 // Console.WriteLine("subMeshMap for {0} - {1}", primName, Util.GetFormattedXml((OSD)subMeshMap));
212
213 // As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some Mesh Level
214 // of Detail Blocks (maps) contain just a NoGeometry key to signal there is no
215 // geometry for this submesh.
216 if (subMeshData.ContainsKey("NoGeometry") && ((OSDBoolean)subMeshData["NoGeometry"]))
217 return;
218
219 OpenMetaverse.Vector3 posMax = ((OSDMap)subMeshData["PositionDomain"])["Max"].AsVector3();
220 OpenMetaverse.Vector3 posMin = ((OSDMap)subMeshData["PositionDomain"])["Min"].AsVector3();
221 ushort faceIndexOffset = (ushort)coords.Count;
222
223 byte[] posBytes = subMeshData["Position"].AsBinary();
224 for (int i = 0; i < posBytes.Length; i += 6)
225 {
226 ushort uX = Utils.BytesToUInt16(posBytes, i);
227 ushort uY = Utils.BytesToUInt16(posBytes, i + 2);
228 ushort uZ = Utils.BytesToUInt16(posBytes, i + 4);
229
230 Coord c = new Coord(
231 Utils.UInt16ToFloat(uX, posMin.X, posMax.X) * size.X,
232 Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y) * size.Y,
233 Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z) * size.Z);
234
235 coords.Add(c);
236 }
237
238 byte[] triangleBytes = subMeshData["TriangleList"].AsBinary();
239 for (int i = 0; i < triangleBytes.Length; i += 6)
240 {
241 ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i) + faceIndexOffset);
242 ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2) + faceIndexOffset);
243 ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4) + faceIndexOffset);
244 Face f = new Face(v1, v2, v3);
245 faces.Add(f);
246 }
247 }
248
249 /// <summary>
250 /// Create a physics mesh from data that comes with the prim. The actual data used depends on the prim type.
251 /// </summary>
252 /// <param name="primName"></param>
253 /// <param name="primShape"></param>
254 /// <param name="size"></param>
255 /// <param name="lod"></param>
256 /// <returns></returns>
257 private Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
258 {
259// m_log.DebugFormat(
260// "[MESH]: Creating physics proxy for {0}, shape {1}",
261// primName, (OpenMetaverse.SculptType)primShape.SculptType);
262
263 List<Coord> coords;
264 List<Face> faces;
265
266 if (primShape.SculptEntry)
267 {
268 if (((OpenMetaverse.SculptType)primShape.SculptType) == SculptType.Mesh)
269 {
270 if (!useMeshiesPhysicsMesh)
271 return null;
272
273 if (!GenerateCoordsAndFacesFromPrimMeshData(primName, primShape, size, out coords, out faces))
274 return null;
275 }
276 else
277 {
278 if (!GenerateCoordsAndFacesFromPrimSculptData(primName, primShape, size, lod, out coords, out faces))
279 return null;
280 }
281 }
282 else
283 {
284 if (!GenerateCoordsAndFacesFromPrimShapeData(primName, primShape, size, lod, out coords, out faces))
285 return null;
286 }
287
288 // Remove the reference to any JPEG2000 sculpt data so it can be GCed
289 primShape.SculptData = Utils.EmptyBytes;
290
291 int numCoords = coords.Count;
292 int numFaces = faces.Count;
293
294 // Create the list of vertices
295 List<Vertex> vertices = new List<Vertex>();
296 for (int i = 0; i < numCoords; i++)
297 {
298 Coord c = coords[i];
299 vertices.Add(new Vertex(c.X, c.Y, c.Z));
300 }
301
302 Mesh mesh = new Mesh();
303 // Add the corresponding triangles to the mesh
304 for (int i = 0; i < numFaces; i++)
305 {
306 Face f = faces[i];
307 mesh.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3]));
308 }
309
310 return mesh;
311 }
312
313 /// <summary>
314 /// Generate the co-ords and faces necessary to construct a mesh from the mesh data the accompanies a prim.
315 /// </summary>
316 /// <param name="primName"></param>
317 /// <param name="primShape"></param>
318 /// <param name="size"></param>
319 /// <param name="coords">Coords are added to this list by the method.</param>
320 /// <param name="faces">Faces are added to this list by the method.</param>
321 /// <returns>true if coords and faces were successfully generated, false if not</returns>
322 private bool GenerateCoordsAndFacesFromPrimMeshData(
323 string primName, PrimitiveBaseShape primShape, Vector3 size, out List<Coord> coords, out List<Face> faces)
324 {
325// m_log.DebugFormat("[MESH]: experimental mesh proxy generation for {0}", primName);
326
327 coords = new List<Coord>();
328 faces = new List<Face>();
329 OSD meshOsd = null;
330
331 mConvexHulls = null;
332 mBoundingHull = null;
333
334 if (primShape.SculptData.Length <= 0)
335 {
336 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
337 // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
338 // The first time will always call with unloaded SculptData if this needs to be uploaded.
339// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
340 return false;
341 }
342
343 long start = 0;
344 using (MemoryStream data = new MemoryStream(primShape.SculptData))
345 {
346 try
347 {
348 OSD osd = OSDParser.DeserializeLLSDBinary(data);
349 if (osd is OSDMap)
350 meshOsd = (OSDMap)osd;
351 else
352 {
353 m_log.Warn("[Mesh}: unable to cast mesh asset to OSDMap");
354 return false;
355 }
356 }
357 catch (Exception e)
358 {
359 m_log.Error("[MESH]: Exception deserializing mesh asset header:" + e.ToString());
360 }
361
362 start = data.Position;
363 }
364
365 if (meshOsd is OSDMap)
366 {
367 OSDMap physicsParms = null;
368 OSDMap map = (OSDMap)meshOsd;
369 if (map.ContainsKey("physics_shape"))
370 {
371 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
372 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName);
373 }
374 else if (map.ContainsKey("physics_mesh"))
375 {
376 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
377 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName);
378 }
379 else if (map.ContainsKey("medium_lod"))
380 {
381 physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh
382 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName);
383 }
384 else if (map.ContainsKey("high_lod"))
385 {
386 physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :)
387 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName);
388 }
389
390 if (map.ContainsKey("physics_convex"))
391 { // pull this out also in case physics engine can use it
392 OSD convexBlockOsd = null;
393 try
394 {
395 OSDMap convexBlock = (OSDMap)map["physics_convex"];
396 {
397 int convexOffset = convexBlock["offset"].AsInteger() + (int)start;
398 int convexSize = convexBlock["size"].AsInteger();
399
400 byte[] convexBytes = new byte[convexSize];
401
402 System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize);
403
404 try
405 {
406 convexBlockOsd = DecompressOsd(convexBytes);
407 }
408 catch (Exception e)
409 {
410 m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e);
411 //return false;
412 }
413 }
414
415 if (convexBlockOsd != null && convexBlockOsd is OSDMap)
416 {
417 convexBlock = convexBlockOsd as OSDMap;
418
419 if (debugDetail)
420 {
421 string keys = LogHeader + " keys found in convexBlock: ";
422 foreach (KeyValuePair<string, OSD> kvp in convexBlock)
423 keys += "'" + kvp.Key + "' ";
424 m_log.Debug(keys);
425 }
426
427 Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f);
428 if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3();
429 Vector3 max = new Vector3(0.5f, 0.5f, 0.5f);
430 if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3();
431
432 List<Vector3> boundingHull = null;
433
434 if (convexBlock.ContainsKey("BoundingVerts"))
435 {
436 byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary();
437 boundingHull = new List<Vector3>();
438 for (int i = 0; i < boundingVertsBytes.Length; )
439 {
440 ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
441 ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
442 ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
443
444 Vector3 pos = new Vector3(
445 Utils.UInt16ToFloat(uX, min.X, max.X),
446 Utils.UInt16ToFloat(uY, min.Y, max.Y),
447 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
448 );
449
450 boundingHull.Add(pos);
451 }
452
453 mBoundingHull = boundingHull;
454 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count);
455 }
456
457 if (convexBlock.ContainsKey("HullList"))
458 {
459 byte[] hullList = convexBlock["HullList"].AsBinary();
460
461 byte[] posBytes = convexBlock["Positions"].AsBinary();
462
463 List<List<Vector3>> hulls = new List<List<Vector3>>();
464 int posNdx = 0;
465
466 foreach (byte cnt in hullList)
467 {
468 int count = cnt == 0 ? 256 : cnt;
469 List<Vector3> hull = new List<Vector3>();
470
471 for (int i = 0; i < count; i++)
472 {
473 ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
474 ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
475 ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
476
477 Vector3 pos = new Vector3(
478 Utils.UInt16ToFloat(uX, min.X, max.X),
479 Utils.UInt16ToFloat(uY, min.Y, max.Y),
480 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
481 );
482
483 hull.Add(pos);
484 }
485
486 hulls.Add(hull);
487 }
488
489 mConvexHulls = hulls;
490 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count);
491 }
492 else
493 {
494 if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName);
495 }
496 }
497 }
498 catch (Exception e)
499 {
500 m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e);
501 }
502 }
503
504 if (physicsParms == null)
505 {
506 m_log.WarnFormat("[MESH]: No recognized physics mesh found in mesh asset for {0}", primName);
507 return false;
508 }
509
510 int physOffset = physicsParms["offset"].AsInteger() + (int)start;
511 int physSize = physicsParms["size"].AsInteger();
512
513 if (physOffset < 0 || physSize == 0)
514 return false; // no mesh data in asset
515
516 OSD decodedMeshOsd = new OSD();
517 byte[] meshBytes = new byte[physSize];
518 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
519 // byte[] decompressed = new byte[physSize * 5];
520 try
521 {
522 decodedMeshOsd = DecompressOsd(meshBytes);
523 }
524 catch (Exception e)
525 {
526 m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e);
527 return false;
528 }
529
530 OSDArray decodedMeshOsdArray = null;
531
532 // physics_shape is an array of OSDMaps, one for each submesh
533 if (decodedMeshOsd is OSDArray)
534 {
535 // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
536
537 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
538 foreach (OSD subMeshOsd in decodedMeshOsdArray)
539 {
540 if (subMeshOsd is OSDMap)
541 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
542 }
543 if (debugDetail)
544 m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}",
545 LogHeader, primName, physOffset, physSize, coords.Count, faces.Count);
546 }
547 }
548
549 return true;
550 }
551
552 /// <summary>
553 /// decompresses a gzipped OSD object
554 /// </summary>
555 /// <param name="decodedOsd"></param> the OSD object
556 /// <param name="meshBytes"></param>
557 /// <returns></returns>
558 private static OSD DecompressOsd(byte[] meshBytes)
559 {
560 OSD decodedOsd = null;
561
562 using (MemoryStream inMs = new MemoryStream(meshBytes))
563 {
564 using (MemoryStream outMs = new MemoryStream())
565 {
566 using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress))
567 {
568 byte[] readBuffer = new byte[2048];
569 inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header
570 int readLen = 0;
571
572 while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
573 outMs.Write(readBuffer, 0, readLen);
574
575 outMs.Flush();
576
577 outMs.Seek(0, SeekOrigin.Begin);
578
579 byte[] decompressedBuf = outMs.GetBuffer();
580
581 decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
582 }
583 }
584 }
585 return decodedOsd;
586 }
587
588 /// <summary>
589 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
590 /// </summary>
591 /// <param name="primName"></param>
592 /// <param name="primShape"></param>
593 /// <param name="size"></param>
594 /// <param name="lod"></param>
595 /// <param name="coords">Coords are added to this list by the method.</param>
596 /// <param name="faces">Faces are added to this list by the method.</param>
597 /// <returns>true if coords and faces were successfully generated, false if not</returns>
598 private bool GenerateCoordsAndFacesFromPrimSculptData(
599 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
600 {
601 coords = new List<Coord>();
602 faces = new List<Face>();
603 PrimMesher.SculptMesh sculptMesh;
604 Image idata = null;
605 string decodedSculptFileName = "";
606
607 if (cacheSculptMaps && primShape.SculptTexture != UUID.Zero)
608 {
609 decodedSculptFileName = System.IO.Path.Combine(decodedSculptMapPath, "smap_" + primShape.SculptTexture.ToString());
610 try
611 {
612 if (File.Exists(decodedSculptFileName))
613 {
614 idata = Image.FromFile(decodedSculptFileName);
615 }
616 }
617 catch (Exception e)
618 {
619 m_log.Error("[SCULPT]: unable to load cached sculpt map " + decodedSculptFileName + " " + e.Message);
620
621 }
622 //if (idata != null)
623 // m_log.Debug("[SCULPT]: loaded cached map asset for map ID: " + primShape.SculptTexture.ToString());
624 }
625
626 if (idata == null)
627 {
628 if (primShape.SculptData == null || primShape.SculptData.Length == 0)
629 return false;
630
631 try
632 {
633 OpenMetaverse.Imaging.ManagedImage managedImage;
634
635 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out managedImage);
636
637 if (managedImage == null)
638 {
639 // In some cases it seems that the decode can return a null bitmap without throwing
640 // an exception
641 m_log.WarnFormat("[PHYSICS]: OpenJPEG decoded sculpt data for {0} to a null bitmap. Ignoring.", primName);
642
643 return false;
644 }
645
646 if ((managedImage.Channels & OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha) != 0)
647 managedImage.ConvertChannels(managedImage.Channels & ~OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha);
648
649 Bitmap imgData = OpenMetaverse.Imaging.LoadTGAClass.LoadTGA(new MemoryStream(managedImage.ExportTGA()));
650 idata = (Image)imgData;
651 managedImage = null;
652
653 if (cacheSculptMaps)
654 {
655 try { idata.Save(decodedSculptFileName, ImageFormat.MemoryBmp); }
656 catch (Exception e) { m_log.Error("[SCULPT]: unable to cache sculpt map " + decodedSculptFileName + " " + e.Message); }
657 }
658 }
659 catch (DllNotFoundException)
660 {
661 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!");
662 return false;
663 }
664 catch (IndexOutOfRangeException)
665 {
666 m_log.Error("[PHYSICS]: OpenJpeg was unable to decode this. Physics Proxy generation failed");
667 return false;
668 }
669 catch (Exception ex)
670 {
671 m_log.Error("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed: " + ex.Message);
672 return false;
673 }
674 }
675
676 PrimMesher.SculptMesh.SculptType sculptType;
677 switch ((OpenMetaverse.SculptType)primShape.SculptType)
678 {
679 case OpenMetaverse.SculptType.Cylinder:
680 sculptType = PrimMesher.SculptMesh.SculptType.cylinder;
681 break;
682 case OpenMetaverse.SculptType.Plane:
683 sculptType = PrimMesher.SculptMesh.SculptType.plane;
684 break;
685 case OpenMetaverse.SculptType.Torus:
686 sculptType = PrimMesher.SculptMesh.SculptType.torus;
687 break;
688 case OpenMetaverse.SculptType.Sphere:
689 sculptType = PrimMesher.SculptMesh.SculptType.sphere;
690 break;
691 default:
692 sculptType = PrimMesher.SculptMesh.SculptType.plane;
693 break;
694 }
695
696 bool mirror = ((primShape.SculptType & 128) != 0);
697 bool invert = ((primShape.SculptType & 64) != 0);
698
699 sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false, mirror, invert);
700
701 idata.Dispose();
702
703 sculptMesh.DumpRaw(baseDir, primName, "primMesh");
704
705 sculptMesh.Scale(size.X, size.Y, size.Z);
706
707 coords = sculptMesh.coords;
708 faces = sculptMesh.faces;
709
710 return true;
711 }
712
713 /// <summary>
714 /// Generate the co-ords and faces necessary to construct a mesh from the shape data the accompanies a prim.
715 /// </summary>
716 /// <param name="primName"></param>
717 /// <param name="primShape"></param>
718 /// <param name="size"></param>
719 /// <param name="coords">Coords are added to this list by the method.</param>
720 /// <param name="faces">Faces are added to this list by the method.</param>
721 /// <returns>true if coords and faces were successfully generated, false if not</returns>
722 private bool GenerateCoordsAndFacesFromPrimShapeData(
723 string primName, PrimitiveBaseShape primShape, Vector3 size, float lod, out List<Coord> coords, out List<Face> faces)
724 {
725 PrimMesh primMesh;
726 coords = new List<Coord>();
727 faces = new List<Face>();
728
729 float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f;
730 float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f;
731 float pathBegin = (float)primShape.PathBegin * 2.0e-5f;
732 float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f;
733 float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f;
734 float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f;
735
736 float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f;
737 float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f;
738 float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f;
739 if (profileHollow > 0.95f)
740 profileHollow = 0.95f;
741
742 int sides = 4;
743 LevelOfDetail iLOD = (LevelOfDetail)lod;
744 if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
745 sides = 3;
746 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
747 {
748 switch (iLOD)
749 {
750 case LevelOfDetail.High: sides = 24; break;
751 case LevelOfDetail.Medium: sides = 12; break;
752 case LevelOfDetail.Low: sides = 6; break;
753 case LevelOfDetail.VeryLow: sides = 3; break;
754 default: sides = 24; break;
755 }
756 }
757 else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
758 { // half circle, prim is a sphere
759 switch (iLOD)
760 {
761 case LevelOfDetail.High: sides = 24; break;
762 case LevelOfDetail.Medium: sides = 12; break;
763 case LevelOfDetail.Low: sides = 6; break;
764 case LevelOfDetail.VeryLow: sides = 3; break;
765 default: sides = 24; break;
766 }
767
768 profileBegin = 0.5f * profileBegin + 0.5f;
769 profileEnd = 0.5f * profileEnd + 0.5f;
770 }
771
772 int hollowSides = sides;
773 if (primShape.HollowShape == HollowShape.Circle)
774 {
775 switch (iLOD)
776 {
777 case LevelOfDetail.High: hollowSides = 24; break;
778 case LevelOfDetail.Medium: hollowSides = 12; break;
779 case LevelOfDetail.Low: hollowSides = 6; break;
780 case LevelOfDetail.VeryLow: hollowSides = 3; break;
781 default: hollowSides = 24; break;
782 }
783 }
784 else if (primShape.HollowShape == HollowShape.Square)
785 hollowSides = 4;
786 else if (primShape.HollowShape == HollowShape.Triangle)
787 hollowSides = 3;
788
789 primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides);
790
791 if (primMesh.errorMessage != null)
792 if (primMesh.errorMessage.Length > 0)
793 m_log.Error("[ERROR] " + primMesh.errorMessage);
794
795 primMesh.topShearX = pathShearX;
796 primMesh.topShearY = pathShearY;
797 primMesh.pathCutBegin = pathBegin;
798 primMesh.pathCutEnd = pathEnd;
799
800 if (primShape.PathCurve == (byte)Extrusion.Straight || primShape.PathCurve == (byte) Extrusion.Flexible)
801 {
802 primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10;
803 primMesh.twistEnd = primShape.PathTwist * 18 / 10;
804 primMesh.taperX = pathScaleX;
805 primMesh.taperY = pathScaleY;
806
807 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
808 {
809 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
810 if (profileBegin < 0.0f) profileBegin = 0.0f;
811 if (profileEnd > 1.0f) profileEnd = 1.0f;
812 }
813#if SPAM
814 m_log.Debug("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString());
815#endif
816 try
817 {
818 primMesh.ExtrudeLinear();
819 }
820 catch (Exception ex)
821 {
822 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
823 return false;
824 }
825 }
826 else
827 {
828 primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f;
829 primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f;
830 primMesh.radius = 0.01f * primShape.PathRadiusOffset;
831 primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions;
832 primMesh.skew = 0.01f * primShape.PathSkew;
833 primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10;
834 primMesh.twistEnd = primShape.PathTwist * 36 / 10;
835 primMesh.taperX = primShape.PathTaperX * 0.01f;
836 primMesh.taperY = primShape.PathTaperY * 0.01f;
837
838 if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f)
839 {
840 ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh);
841 if (profileBegin < 0.0f) profileBegin = 0.0f;
842 if (profileEnd > 1.0f) profileEnd = 1.0f;
843 }
844#if SPAM
845 m_log.Debug("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString());
846#endif
847 try
848 {
849 primMesh.ExtrudeCircular();
850 }
851 catch (Exception ex)
852 {
853 ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh);
854 return false;
855 }
856 }
857
858 primMesh.DumpRaw(baseDir, primName, "primMesh");
859
860 primMesh.Scale(size.X, size.Y, size.Z);
861
862 coords = primMesh.coords;
863 faces = primMesh.faces;
864
865 return true;
866 }
867
868 /// <summary>
869 /// temporary prototype code - please do not use until the interface has been finalized!
870 /// </summary>
871 /// <param name="size">value to scale the hull points by</param>
872 /// <returns>a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null</returns>
873 public List<Vector3> GetBoundingHull(Vector3 size)
874 {
875 if (mBoundingHull == null)
876 return null;
877
878 List<Vector3> verts = new List<Vector3>();
879 foreach (var vert in mBoundingHull)
880 verts.Add(vert * size);
881
882 return verts;
883 }
884
885 /// <summary>
886 /// temporary prototype code - please do not use until the interface has been finalized!
887 /// </summary>
888 /// <param name="size">value to scale the hull points by</param>
889 /// <returns>a list of hulls if they exist and have been successfully decoded, otherwise null</returns>
890 public List<List<Vector3>> GetConvexHulls(Vector3 size)
891 {
892 if (mConvexHulls == null)
893 return null;
894
895 List<List<Vector3>> hulls = new List<List<Vector3>>();
896 foreach (var hull in mConvexHulls)
897 {
898 List<Vector3> verts = new List<Vector3>();
899 foreach (var vert in hull)
900 verts.Add(vert * size);
901 hulls.Add(verts);
902 }
903
904 return hulls;
905 }
906
907 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
908 {
909 return CreateMesh(primName, primShape, size, lod, false, true);
910 }
911
912 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
913 {
914 return CreateMesh(primName, primShape, size, lod, isPhysical, true);
915 }
916
917 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
918 {
919#if SPAM
920 m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName);
921#endif
922
923 Mesh mesh = null;
924 ulong key = 0;
925
926 // If this mesh has been created already, return it instead of creating another copy
927 // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory
928 if (shouldCache)
929 {
930 key = primShape.GetMeshKey(size, lod);
931 lock (m_uniqueMeshes)
932 {
933 if (m_uniqueMeshes.TryGetValue(key, out mesh))
934 return mesh;
935 }
936 }
937
938 if (size.X < 0.01f) size.X = 0.01f;
939 if (size.Y < 0.01f) size.Y = 0.01f;
940 if (size.Z < 0.01f) size.Z = 0.01f;
941
942 mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);
943
944 if (mesh != null)
945 {
946 if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh)
947 {
948#if SPAM
949 m_log.Debug("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " +
950 minSizeForComplexMesh.ToString() + " - creating simple bounding box");
951#endif
952 mesh = CreateBoundingBoxMesh(mesh);
953 mesh.DumpRaw(baseDir, primName, "Z extruded");
954 }
955
956 // trim the vertex and triangle lists to free up memory
957 mesh.TrimExcess();
958
959 if (shouldCache)
960 {
961 lock (m_uniqueMeshes)
962 {
963 m_uniqueMeshes.Add(key, mesh);
964 }
965 }
966 }
967
968 return mesh;
969 }
970 }
971}
diff --git a/OpenSim/Region/PhysicsModules/Meshing/PrimMesher.cs b/OpenSim/Region/PhysicsModules/Meshing/PrimMesher.cs
new file mode 100644
index 0000000..4049ee1
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/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/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..ec968c0
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.Physics.Meshing")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("4b7e35c2-a9dd-4b10-b778-eb417f4f6884")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.8.2.*")]
33
diff --git a/OpenSim/Region/PhysicsModules/Meshing/SculptMap.cs b/OpenSim/Region/PhysicsModules/Meshing/SculptMap.cs
new file mode 100644
index 0000000..740424e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/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/SculptMesh.cs b/OpenSim/Region/PhysicsModules/Meshing/SculptMesh.cs
new file mode 100644
index 0000000..4a7f3ad
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Meshing/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/Ode/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs
new file mode 100644
index 0000000..076da78
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/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("OdePlugin")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("OdePlugin")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.8.2.*")]
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs b/OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs
new file mode 100644
index 0000000..05eaf2a
--- /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.Physics.Manager;
35using log4net;
36
37namespace OpenSim.Region.Physics.OdePlugin
38{
39 /// <summary>
40 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
41 /// </summary>
42 public enum dParam : int
43 {
44 LowStop = 0,
45 HiStop = 1,
46 Vel = 2,
47 FMax = 3,
48 FudgeFactor = 4,
49 Bounce = 5,
50 CFM = 6,
51 StopERP = 7,
52 StopCFM = 8,
53 LoStop2 = 256,
54 HiStop2 = 257,
55 Vel2 = 258,
56 FMax2 = 259,
57 StopERP2 = 7 + 256,
58 StopCFM2 = 8 + 256,
59 LoStop3 = 512,
60 HiStop3 = 513,
61 Vel3 = 514,
62 FMax3 = 515,
63 StopERP3 = 7 + 512,
64 StopCFM3 = 8 + 512
65 }
66
67 public class OdeCharacter : PhysicsActor
68 {
69 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
70
71 private Vector3 _position;
72 private d.Vector3 _zeroPosition;
73 private bool _zeroFlag = false;
74 private bool m_lastUpdateSent = false;
75 private Vector3 _velocity;
76 private Vector3 m_taintTargetVelocity;
77 private Vector3 _target_velocity;
78 private Vector3 _acceleration;
79 private Vector3 m_rotationalVelocity;
80 private float m_mass = 80f;
81 private float m_density = 60f;
82 private bool m_pidControllerActive = true;
83 private float PID_D = 800.0f;
84 private float PID_P = 900.0f;
85 //private static float POSTURE_SERVO = 10000.0f;
86 private float CAPSULE_RADIUS = 0.37f;
87 private float CAPSULE_LENGTH = 2.140599f;
88 private float m_tensor = 3800000f;
89// private float heightFudgeFactor = 0.52f;
90 private float walkDivisor = 1.3f;
91 private float runDivisor = 0.8f;
92 private bool flying = false;
93 private bool m_iscolliding = false;
94 private bool m_iscollidingGround = false;
95 private bool m_wascolliding = false;
96 private bool m_wascollidingGround = false;
97 private bool m_iscollidingObj = false;
98 private bool m_alwaysRun = false;
99 private bool m_hackSentFall = false;
100 private bool m_hackSentFly = false;
101 private int m_requestedUpdateFrequency = 0;
102 private Vector3 m_taintPosition;
103 internal bool m_avatarplanted = false;
104 /// <summary>
105 /// Hold set forces so we can process them outside physics calculations. This prevents race conditions if we set force
106 /// while calculatios are going on
107 /// </summary>
108 private Vector3 m_taintForce;
109
110 // taints and their non-tainted counterparts
111 private bool m_isPhysical = false; // the current physical status
112 private bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing)
113 internal float MinimumGroundFlightOffset = 3f;
114
115 private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes.
116
117 /// <summary>
118 /// Base movement for calculating tilt.
119 /// </summary>
120 private float m_tiltBaseMovement = (float)Math.Sqrt(2);
121
122 /// <summary>
123 /// Used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider
124 /// </summary>
125 private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f;
126
127 private float m_buoyancy = 0f;
128
129 // private CollisionLocker ode;
130 private bool[] m_colliderarr = new bool[11];
131 private bool[] m_colliderGroundarr = new bool[11];
132
133 // Default we're a Character
134 private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
135
136 // Default, Collide with Other Geometries, spaces, bodies and characters.
137 private CollisionCategories m_collisionFlags = (CollisionCategories.Geom
138 | CollisionCategories.Space
139 | CollisionCategories.Body
140 | CollisionCategories.Character
141 | CollisionCategories.Land);
142 /// <summary>
143 /// Body for dynamics simulation
144 /// </summary>
145 internal IntPtr Body { get; private set; }
146
147 private OdeScene _parent_scene;
148
149 /// <summary>
150 /// Collision geometry
151 /// </summary>
152 internal IntPtr Shell { get; private set; }
153
154 private IntPtr Amotor = IntPtr.Zero;
155 private d.Mass ShellMass;
156
157 private int m_eventsubscription = 0;
158 private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
159
160 // unique UUID of this character object
161 internal UUID m_uuid { get; private set; }
162 internal bool bad = false;
163
164 /// <summary>
165 /// ODE Avatar.
166 /// </summary>
167 /// <param name="avName"></param>
168 /// <param name="parent_scene"></param>
169 /// <param name="pos"></param>
170 /// <param name="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.Name);
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..2342bfa
--- /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.Physics.Manager;
50
51namespace OpenSim.Region.Physics.OdePlugin
52{
53 public class ODEDynamics
54 {
55 public Vehicle Type
56 {
57 get { return m_type; }
58 }
59
60 public IntPtr Body
61 {
62 get { return m_body; }
63 }
64
65 private int frcount = 0; // Used to limit dynamics debug output to
66 // every 100th frame
67
68 // private OdeScene m_parentScene = null;
69 private IntPtr m_body = IntPtr.Zero;
70// private IntPtr m_jointGroup = IntPtr.Zero;
71// private IntPtr m_aMotor = IntPtr.Zero;
72
73
74 // Vehicle properties
75 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
76 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
77 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
78 // HOVER_TERRAIN_ONLY
79 // HOVER_GLOBAL_HEIGHT
80 // NO_DEFLECTION_UP
81 // HOVER_WATER_ONLY
82 // HOVER_UP_ONLY
83 // LIMIT_MOTOR_UP
84 // LIMIT_ROLL_ONLY
85 private VehicleFlag m_Hoverflags = (VehicleFlag)0;
86 private Vector3 m_BlockingEndPoint = Vector3.Zero;
87 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
88 // Linear properties
89 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
90 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
91 private Vector3 m_dir = Vector3.Zero; // velocity applied to body
92 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
93 private float m_linearMotorDecayTimescale = 0;
94 private float m_linearMotorTimescale = 0;
95 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
96 private d.Vector3 m_lastPositionVector = new d.Vector3();
97 // private bool m_LinearMotorSetLastFrame = false;
98 // private Vector3 m_linearMotorOffset = Vector3.Zero;
99
100 //Angular properties
101 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
102 private int m_angularMotorApply = 0; // application frame counter
103 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
104 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
105 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
106 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
107 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
108 // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
109
110 //Deflection properties
111 // private float m_angularDeflectionEfficiency = 0;
112 // private float m_angularDeflectionTimescale = 0;
113 // private float m_linearDeflectionEfficiency = 0;
114 // private float m_linearDeflectionTimescale = 0;
115
116 //Banking properties
117 // private float m_bankingEfficiency = 0;
118 // private float m_bankingMix = 0;
119 // private float m_bankingTimescale = 0;
120
121 //Hover and Buoyancy properties
122 private float m_VhoverHeight = 0f;
123// private float m_VhoverEfficiency = 0f;
124 private float m_VhoverTimescale = 0f;
125 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
126 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
127 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
128 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
129 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
130
131 //Attractor properties
132 private float m_verticalAttractionEfficiency = 1.0f; // damped
133 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
134
135 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
136 {
137 switch (pParam)
138 {
139 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
140 if (pValue < 0.01f) pValue = 0.01f;
141 // m_angularDeflectionEfficiency = pValue;
142 break;
143 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
144 if (pValue < 0.01f) pValue = 0.01f;
145 // m_angularDeflectionTimescale = pValue;
146 break;
147 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
148 if (pValue < 0.01f) pValue = 0.01f;
149 m_angularMotorDecayTimescale = pValue;
150 break;
151 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
152 if (pValue < 0.01f) pValue = 0.01f;
153 m_angularMotorTimescale = pValue;
154 break;
155 case Vehicle.BANKING_EFFICIENCY:
156 if (pValue < 0.01f) pValue = 0.01f;
157 // m_bankingEfficiency = pValue;
158 break;
159 case Vehicle.BANKING_MIX:
160 if (pValue < 0.01f) pValue = 0.01f;
161 // m_bankingMix = pValue;
162 break;
163 case Vehicle.BANKING_TIMESCALE:
164 if (pValue < 0.01f) pValue = 0.01f;
165 // m_bankingTimescale = pValue;
166 break;
167 case Vehicle.BUOYANCY:
168 if (pValue < -1f) pValue = -1f;
169 if (pValue > 1f) pValue = 1f;
170 m_VehicleBuoyancy = pValue;
171 break;
172// case Vehicle.HOVER_EFFICIENCY:
173// if (pValue < 0f) pValue = 0f;
174// if (pValue > 1f) pValue = 1f;
175// m_VhoverEfficiency = pValue;
176// break;
177 case Vehicle.HOVER_HEIGHT:
178 m_VhoverHeight = pValue;
179 break;
180 case Vehicle.HOVER_TIMESCALE:
181 if (pValue < 0.01f) pValue = 0.01f;
182 m_VhoverTimescale = pValue;
183 break;
184 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
185 if (pValue < 0.01f) pValue = 0.01f;
186 // m_linearDeflectionEfficiency = pValue;
187 break;
188 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
189 if (pValue < 0.01f) pValue = 0.01f;
190 // m_linearDeflectionTimescale = pValue;
191 break;
192 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
193 if (pValue < 0.01f) pValue = 0.01f;
194 m_linearMotorDecayTimescale = pValue;
195 break;
196 case Vehicle.LINEAR_MOTOR_TIMESCALE:
197 if (pValue < 0.01f) pValue = 0.01f;
198 m_linearMotorTimescale = pValue;
199 break;
200 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
201 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
202 if (pValue > 1.0f) pValue = 1.0f;
203 m_verticalAttractionEfficiency = pValue;
204 break;
205 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
206 if (pValue < 0.01f) pValue = 0.01f;
207 m_verticalAttractionTimescale = pValue;
208 break;
209
210 // These are vector properties but the engine lets you use a single float value to
211 // set all of the components to the same value
212 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
213 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
214 break;
215 case Vehicle.ANGULAR_MOTOR_DIRECTION:
216 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
217 m_angularMotorApply = 10;
218 break;
219 case Vehicle.LINEAR_FRICTION_TIMESCALE:
220 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
221 break;
222 case Vehicle.LINEAR_MOTOR_DIRECTION:
223 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
224 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
225 break;
226 case Vehicle.LINEAR_MOTOR_OFFSET:
227 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
228 break;
229
230 }
231 }//end ProcessFloatVehicleParam
232
233 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
234 {
235 switch (pParam)
236 {
237 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
238 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
239 break;
240 case Vehicle.ANGULAR_MOTOR_DIRECTION:
241 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
242 // Limit requested angular speed to 2 rps= 4 pi rads/sec
243 if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
244 if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
245 if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
246 if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
247 if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
248 if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
249 m_angularMotorApply = 10;
250 break;
251 case Vehicle.LINEAR_FRICTION_TIMESCALE:
252 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
253 break;
254 case Vehicle.LINEAR_MOTOR_DIRECTION:
255 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
256 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
257 break;
258 case Vehicle.LINEAR_MOTOR_OFFSET:
259 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
260 break;
261 case Vehicle.BLOCK_EXIT:
262 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
263 break;
264 }
265 }//end ProcessVectorVehicleParam
266
267 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
268 {
269 switch (pParam)
270 {
271 case Vehicle.REFERENCE_FRAME:
272 // m_referenceFrame = pValue;
273 break;
274 case Vehicle.ROLL_FRAME:
275 m_RollreferenceFrame = pValue;
276 break;
277 }
278 }//end ProcessRotationVehicleParam
279
280 internal void ProcessVehicleFlags(int pParam, bool remove)
281 {
282 if (remove)
283 {
284 if (pParam == -1)
285 {
286 m_flags = (VehicleFlag)0;
287 m_Hoverflags = (VehicleFlag)0;
288 return;
289 }
290 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
291 {
292 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0)
293 m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT);
294 }
295 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
296 {
297 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0)
298 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY);
299 }
300 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
301 {
302 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0)
303 m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY);
304 }
305 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
306 {
307 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0)
308 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY);
309 }
310 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
311 {
312 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0)
313 m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP);
314 }
315 if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY)
316 {
317 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0)
318 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
319 }
320 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
321 {
322 if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0)
323 m_flags &= ~(VehicleFlag.MOUSELOOK_BANK);
324 }
325 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
326 {
327 if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0)
328 m_flags &= ~(VehicleFlag.MOUSELOOK_STEER);
329 }
330 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
331 {
332 if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0)
333 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP);
334 }
335 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
336 {
337 if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0)
338 m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED);
339 }
340 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
341 {
342 if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0)
343 m_flags &= ~(VehicleFlag.NO_X);
344 }
345 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
346 {
347 if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0)
348 m_flags &= ~(VehicleFlag.NO_Y);
349 }
350 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
351 {
352 if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0)
353 m_flags &= ~(VehicleFlag.NO_Z);
354 }
355 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
356 {
357 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0)
358 m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT);
359 }
360 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
361 {
362 if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0)
363 m_flags &= ~(VehicleFlag.NO_DEFLECTION);
364 }
365 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
366 {
367 if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0)
368 m_flags &= ~(VehicleFlag.LOCK_ROTATION);
369 }
370 }
371 else
372 {
373 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
374 {
375 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags);
376 }
377 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
378 {
379 m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags);
380 }
381 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
382 {
383 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags);
384 }
385 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
386 {
387 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags);
388 }
389 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
390 {
391 m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags);
392 }
393 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
394 {
395 m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags);
396 }
397 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
398 {
399 m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags);
400 }
401 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
402 {
403 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags);
404 }
405 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
406 {
407 m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags);
408 }
409 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
410 {
411 m_flags |= (VehicleFlag.NO_X);
412 }
413 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
414 {
415 m_flags |= (VehicleFlag.NO_Y);
416 }
417 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
418 {
419 m_flags |= (VehicleFlag.NO_Z);
420 }
421 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
422 {
423 m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT);
424 }
425 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
426 {
427 m_flags |= (VehicleFlag.NO_DEFLECTION);
428 }
429 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
430 {
431 m_flags |= (VehicleFlag.LOCK_ROTATION);
432 }
433 }
434 }//end ProcessVehicleFlags
435
436 internal void ProcessTypeChange(Vehicle pType)
437 {
438 // Set Defaults For Type
439 m_type = pType;
440 switch (pType)
441 {
442 case Vehicle.TYPE_NONE:
443 m_linearFrictionTimescale = new Vector3(0, 0, 0);
444 m_angularFrictionTimescale = new Vector3(0, 0, 0);
445 m_linearMotorDirection = Vector3.Zero;
446 m_linearMotorTimescale = 0;
447 m_linearMotorDecayTimescale = 0;
448 m_angularMotorDirection = Vector3.Zero;
449 m_angularMotorTimescale = 0;
450 m_angularMotorDecayTimescale = 0;
451 m_VhoverHeight = 0;
452 m_VhoverTimescale = 0;
453 m_VehicleBuoyancy = 0;
454 m_flags = (VehicleFlag)0;
455 break;
456
457 case Vehicle.TYPE_SLED:
458 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
459 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
460 m_linearMotorDirection = Vector3.Zero;
461 m_linearMotorTimescale = 1000;
462 m_linearMotorDecayTimescale = 120;
463 m_angularMotorDirection = Vector3.Zero;
464 m_angularMotorTimescale = 1000;
465 m_angularMotorDecayTimescale = 120;
466 m_VhoverHeight = 0;
467// m_VhoverEfficiency = 1;
468 m_VhoverTimescale = 10;
469 m_VehicleBuoyancy = 0;
470 // m_linearDeflectionEfficiency = 1;
471 // m_linearDeflectionTimescale = 1;
472 // m_angularDeflectionEfficiency = 1;
473 // m_angularDeflectionTimescale = 1000;
474 // m_bankingEfficiency = 0;
475 // m_bankingMix = 1;
476 // m_bankingTimescale = 10;
477 // m_referenceFrame = Quaternion.Identity;
478 m_Hoverflags &=
479 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
480 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
481 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
482 break;
483 case Vehicle.TYPE_CAR:
484 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
485 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
486 m_linearMotorDirection = Vector3.Zero;
487 m_linearMotorTimescale = 1;
488 m_linearMotorDecayTimescale = 60;
489 m_angularMotorDirection = Vector3.Zero;
490 m_angularMotorTimescale = 1;
491 m_angularMotorDecayTimescale = 0.8f;
492 m_VhoverHeight = 0;
493// m_VhoverEfficiency = 0;
494 m_VhoverTimescale = 1000;
495 m_VehicleBuoyancy = 0;
496 // // m_linearDeflectionEfficiency = 1;
497 // // m_linearDeflectionTimescale = 2;
498 // // m_angularDeflectionEfficiency = 0;
499 // m_angularDeflectionTimescale = 10;
500 m_verticalAttractionEfficiency = 1f;
501 m_verticalAttractionTimescale = 10f;
502 // m_bankingEfficiency = -0.2f;
503 // m_bankingMix = 1;
504 // m_bankingTimescale = 1;
505 // m_referenceFrame = Quaternion.Identity;
506 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
507 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY |
508 VehicleFlag.LIMIT_MOTOR_UP);
509 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY);
510 break;
511 case Vehicle.TYPE_BOAT:
512 m_linearFrictionTimescale = new Vector3(10, 3, 2);
513 m_angularFrictionTimescale = new Vector3(10,10,10);
514 m_linearMotorDirection = Vector3.Zero;
515 m_linearMotorTimescale = 5;
516 m_linearMotorDecayTimescale = 60;
517 m_angularMotorDirection = Vector3.Zero;
518 m_angularMotorTimescale = 4;
519 m_angularMotorDecayTimescale = 4;
520 m_VhoverHeight = 0;
521// m_VhoverEfficiency = 0.5f;
522 m_VhoverTimescale = 2;
523 m_VehicleBuoyancy = 1;
524 // m_linearDeflectionEfficiency = 0.5f;
525 // m_linearDeflectionTimescale = 3;
526 // m_angularDeflectionEfficiency = 0.5f;
527 // m_angularDeflectionTimescale = 5;
528 m_verticalAttractionEfficiency = 0.5f;
529 m_verticalAttractionTimescale = 5f;
530 // m_bankingEfficiency = -0.3f;
531 // m_bankingMix = 0.8f;
532 // m_bankingTimescale = 1;
533 // m_referenceFrame = Quaternion.Identity;
534 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
535 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
536 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
537 m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
538 VehicleFlag.LIMIT_MOTOR_UP);
539 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY);
540 break;
541 case Vehicle.TYPE_AIRPLANE:
542 m_linearFrictionTimescale = new Vector3(200, 10, 5);
543 m_angularFrictionTimescale = new Vector3(20, 20, 20);
544 m_linearMotorDirection = Vector3.Zero;
545 m_linearMotorTimescale = 2;
546 m_linearMotorDecayTimescale = 60;
547 m_angularMotorDirection = Vector3.Zero;
548 m_angularMotorTimescale = 4;
549 m_angularMotorDecayTimescale = 4;
550 m_VhoverHeight = 0;
551// m_VhoverEfficiency = 0.5f;
552 m_VhoverTimescale = 1000;
553 m_VehicleBuoyancy = 0;
554 // m_linearDeflectionEfficiency = 0.5f;
555 // m_linearDeflectionTimescale = 3;
556 // m_angularDeflectionEfficiency = 1;
557 // m_angularDeflectionTimescale = 2;
558 m_verticalAttractionEfficiency = 0.9f;
559 m_verticalAttractionTimescale = 2f;
560 // m_bankingEfficiency = 1;
561 // m_bankingMix = 0.7f;
562 // m_bankingTimescale = 2;
563 // m_referenceFrame = Quaternion.Identity;
564 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
565 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
566 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
567 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
568 break;
569 case Vehicle.TYPE_BALLOON:
570 m_linearFrictionTimescale = new Vector3(5, 5, 5);
571 m_angularFrictionTimescale = new Vector3(10, 10, 10);
572 m_linearMotorDirection = Vector3.Zero;
573 m_linearMotorTimescale = 5;
574 m_linearMotorDecayTimescale = 60;
575 m_angularMotorDirection = Vector3.Zero;
576 m_angularMotorTimescale = 6;
577 m_angularMotorDecayTimescale = 10;
578 m_VhoverHeight = 5;
579// m_VhoverEfficiency = 0.8f;
580 m_VhoverTimescale = 10;
581 m_VehicleBuoyancy = 1;
582 // m_linearDeflectionEfficiency = 0;
583 // m_linearDeflectionTimescale = 5;
584 // m_angularDeflectionEfficiency = 0;
585 // m_angularDeflectionTimescale = 5;
586 m_verticalAttractionEfficiency = 1f;
587 m_verticalAttractionTimescale = 100f;
588 // m_bankingEfficiency = 0;
589 // m_bankingMix = 0.7f;
590 // m_bankingTimescale = 5;
591 // m_referenceFrame = Quaternion.Identity;
592 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
593 VehicleFlag.HOVER_UP_ONLY);
594 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
595 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
596 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT);
597 break;
598
599 }
600 }//end SetDefaultsForType
601
602 internal void Enable(IntPtr pBody, OdeScene pParentScene)
603 {
604 if (m_type == Vehicle.TYPE_NONE)
605 return;
606
607 m_body = pBody;
608 }
609
610 internal void Step(float pTimestep, OdeScene pParentScene)
611 {
612 if (m_body == IntPtr.Zero || m_type == Vehicle.TYPE_NONE)
613 return;
614 frcount++; // used to limit debug comment output
615 if (frcount > 100)
616 frcount = 0;
617
618 MoveLinear(pTimestep, pParentScene);
619 MoveAngular(pTimestep);
620 LimitRotation(pTimestep);
621 }// end Step
622
623 private void MoveLinear(float pTimestep, OdeScene _pParentScene)
624 {
625 if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant
626 {
627 if (!d.BodyIsEnabled(Body))
628 d.BodyEnable(Body);
629
630 // add drive to body
631 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
632 m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector?
633
634 // This will work temporarily, but we really need to compare speed on an axis
635 // KF: Limit body velocity to applied velocity?
636 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
637 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
638 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
639 m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y;
640 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
641 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
642
643 // decay applied velocity
644 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
645 //Console.WriteLine("decay: " + decayfraction);
646 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
647 //Console.WriteLine("actual: " + m_linearMotorDirection);
648 }
649 else
650 { // requested is not significant
651 // if what remains of applied is small, zero it.
652 if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
653 m_lastLinearVelocityVector = Vector3.Zero;
654 }
655
656 // convert requested object velocity to world-referenced vector
657 m_dir = m_lastLinearVelocityVector;
658 d.Quaternion rot = d.BodyGetQuaternion(Body);
659 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
660 m_dir *= rotq; // apply obj rotation to velocity vector
661
662 // add Gravity andBuoyancy
663 // KF: So far I have found no good method to combine a script-requested
664 // .Z velocity and gravity. Therefore only 0g will used script-requested
665 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
666 Vector3 grav = Vector3.Zero;
667 // There is some gravity, make a gravity force vector
668 // that is applied after object velocity.
669 d.Mass objMass;
670 d.BodyGetMass(Body, out objMass);
671 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
672 grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy);
673 // Preserve the current Z velocity
674 d.Vector3 vel_now = d.BodyGetLinearVel(Body);
675 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
676
677 d.Vector3 pos = d.BodyGetPosition(Body);
678// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
679 Vector3 posChange = new Vector3();
680 posChange.X = pos.X - m_lastPositionVector.X;
681 posChange.Y = pos.Y - m_lastPositionVector.Y;
682 posChange.Z = pos.Z - m_lastPositionVector.Z;
683 double Zchange = Math.Abs(posChange.Z);
684 if (m_BlockingEndPoint != Vector3.Zero)
685 {
686 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
687 {
688 pos.X -= posChange.X + 1;
689 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
690 }
691 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
692 {
693 pos.Y -= posChange.Y + 1;
694 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
695 }
696 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
697 {
698 pos.Z -= posChange.Z + 1;
699 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
700 }
701 if (pos.X <= 0)
702 {
703 pos.X += posChange.X + 1;
704 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
705 }
706 if (pos.Y <= 0)
707 {
708 pos.Y += posChange.Y + 1;
709 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
710 }
711 }
712 if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y))
713 {
714 pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2;
715 d.BodySetPosition(Body, pos.X, pos.Y, pos.Z);
716 }
717
718 // Check if hovering
719 if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
720 {
721 // We should hover, get the target height
722 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0)
723 {
724 m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight;
725 }
726 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
727 {
728 m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
729 }
730 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
731 {
732 m_VhoverTargetHeight = m_VhoverHeight;
733 }
734
735 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0)
736 {
737 // If body is aready heigher, use its height as target height
738 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
739 }
740 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
741 {
742 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
743 {
744 d.BodySetPosition(Body, pos.X, pos.Y, m_VhoverTargetHeight);
745 }
746 }
747 else
748 {
749 float herr0 = pos.Z - m_VhoverTargetHeight;
750 // Replace Vertical speed with correction figure if significant
751 if (Math.Abs(herr0) > 0.01f)
752 {
753 m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale);
754 //KF: m_VhoverEfficiency is not yet implemented
755 }
756 else
757 {
758 m_dir.Z = 0f;
759 }
760 }
761
762// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
763// m_VhoverTimescale = 0f; // time to acheive height
764// pTimestep is time since last frame,in secs
765 }
766
767 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
768 {
769 //Start Experimental Values
770 if (Zchange > .3)
771 {
772 grav.Z = (float)(grav.Z * 3);
773 }
774 if (Zchange > .15)
775 {
776 grav.Z = (float)(grav.Z * 2);
777 }
778 if (Zchange > .75)
779 {
780 grav.Z = (float)(grav.Z * 1.5);
781 }
782 if (Zchange > .05)
783 {
784 grav.Z = (float)(grav.Z * 1.25);
785 }
786 if (Zchange > .025)
787 {
788 grav.Z = (float)(grav.Z * 1.125);
789 }
790 float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y);
791 float postemp = (pos.Z - terraintemp);
792 if (postemp > 2.5f)
793 {
794 grav.Z = (float)(grav.Z * 1.037125);
795 }
796 //End Experimental Values
797 }
798 if ((m_flags & (VehicleFlag.NO_X)) != 0)
799 {
800 m_dir.X = 0;
801 }
802 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
803 {
804 m_dir.Y = 0;
805 }
806 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
807 {
808 m_dir.Z = 0;
809 }
810
811 m_lastPositionVector = d.BodyGetPosition(Body);
812
813 // Apply velocity
814 d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z);
815 // apply gravity force
816 d.BodyAddForce(Body, grav.X, grav.Y, grav.Z);
817
818
819 // apply friction
820 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
821 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount;
822 } // end MoveLinear()
823
824 private void MoveAngular(float pTimestep)
825 {
826 /*
827 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
828 private int m_angularMotorApply = 0; // application frame counter
829 private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down)
830 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
831 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
832 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
833 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
834 */
835
836 // Get what the body is doing, this includes 'external' influences
837 d.Vector3 angularVelocity = d.BodyGetAngularVel(Body);
838 // Vector3 angularVelocity = Vector3.Zero;
839
840 if (m_angularMotorApply > 0)
841 {
842 // ramp up to new value
843 // current velocity += error / (time to get there / step interval)
844 // requested speed - last motor speed
845 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep);
846 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
847 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
848
849 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected
850 // velocity may still be acheived.
851 }
852 else
853 {
854 // no motor recently applied, keep the body velocity
855 /* m_angularMotorVelocity.X = angularVelocity.X;
856 m_angularMotorVelocity.Y = angularVelocity.Y;
857 m_angularMotorVelocity.Z = angularVelocity.Z; */
858
859 // and decay the velocity
860 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
861 } // end motor section
862
863 // Vertical attractor section
864 Vector3 vertattr = Vector3.Zero;
865
866 if (m_verticalAttractionTimescale < 300)
867 {
868 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep);
869 // get present body rotation
870 d.Quaternion rot = d.BodyGetQuaternion(Body);
871 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W);
872 // make a vector pointing up
873 Vector3 verterr = Vector3.Zero;
874 verterr.Z = 1.0f;
875 // rotate it to Body Angle
876 verterr = verterr * rotq;
877 // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1.
878 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go
879 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
880 if (verterr.Z < 0.0f)
881 {
882 verterr.X = 2.0f - verterr.X;
883 verterr.Y = 2.0f - verterr.Y;
884 }
885 // Error is 0 (no error) to +/- 2 (max error)
886 // scale it by VAservo
887 verterr = verterr * VAservo;
888//if (frcount == 0) Console.WriteLine("VAerr=" + verterr);
889
890 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
891 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
892 vertattr.X = verterr.Y;
893 vertattr.Y = - verterr.X;
894 vertattr.Z = 0f;
895
896 // scaling appears better usingsquare-law
897 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
898 vertattr.X += bounce * angularVelocity.X;
899 vertattr.Y += bounce * angularVelocity.Y;
900
901 } // else vertical attractor is off
902
903 // m_lastVertAttractor = vertattr;
904
905 // Bank section tba
906 // Deflection section tba
907
908 // Sum velocities
909 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
910
911 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
912 {
913 m_lastAngularVelocity.X = 0;
914 m_lastAngularVelocity.Y = 0;
915 }
916
917 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
918 {
919 if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body);
920 }
921 else
922 {
923 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
924 }
925
926 // apply friction
927 Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
928 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
929
930 // Apply to the body
931 d.BodySetAngularVel (Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z);
932
933 } //end MoveAngular
934 internal void LimitRotation(float timestep)
935 {
936 d.Quaternion rot = d.BodyGetQuaternion(Body);
937 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
938 d.Quaternion m_rot = new d.Quaternion();
939 bool changed = false;
940 m_rot.X = rotq.X;
941 m_rot.Y = rotq.Y;
942 m_rot.Z = rotq.Z;
943 m_rot.W = rotq.W;
944 if (m_RollreferenceFrame != Quaternion.Identity)
945 {
946 if (rotq.X >= m_RollreferenceFrame.X)
947 {
948 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
949 }
950 if (rotq.Y >= m_RollreferenceFrame.Y)
951 {
952 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
953 }
954 if (rotq.X <= -m_RollreferenceFrame.X)
955 {
956 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
957 }
958 if (rotq.Y <= -m_RollreferenceFrame.Y)
959 {
960 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
961 }
962 changed = true;
963 }
964 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
965 {
966 m_rot.X = 0;
967 m_rot.Y = 0;
968 changed = true;
969 }
970 if (changed)
971 d.BodySetQuaternion(Body, ref m_rot);
972 }
973 }
974}
diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs b/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs
new file mode 100644
index 0000000..f934b8a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs
@@ -0,0 +1,3387 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * Revised August 26 2009 by Kitto Flora. ODEDynamics.cs replaces
30 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
31 * ODEPrim.cs contains methods dealing with Prim editing, Prim
32 * characteristics and Kinetic motion.
33 * ODEDynamics.cs contains methods dealing with Prim Physical motion
34 * (dynamics) and the associated settings. Old Linear and angular
35 * motors for dynamic motion have been replace with MoveLinear()
36 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
37 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
38 * switch between 'VEHICLE' parameter use and general dynamics
39 * settings use.
40 */
41
42//#define SPAM
43
44using System;
45using System.Collections.Generic;
46using System.Reflection;
47using System.Runtime.InteropServices;
48using System.Threading;
49using log4net;
50using OpenMetaverse;
51using Ode.NET;
52using OpenSim.Framework;
53using OpenSim.Region.Physics.Manager;
54
55namespace OpenSim.Region.Physics.OdePlugin
56{
57 /// <summary>
58 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
59 /// </summary>
60 public class OdePrim : PhysicsActor
61 {
62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63
64 private bool m_isphysical;
65
66 public int ExpectedCollisionContacts { get { return m_expectedCollisionContacts; } }
67 private int m_expectedCollisionContacts = 0;
68
69 /// <summary>
70 /// Gets collide bits so that we can still perform land collisions if a mesh fails to load.
71 /// </summary>
72 private int BadMeshAssetCollideBits
73 {
74 get { return m_isphysical ? (int)CollisionCategories.Land : 0; }
75 }
76
77 /// <summary>
78 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
79 /// </summary>
80 public override bool IsPhysical
81 {
82 get { return m_isphysical; }
83 set
84 {
85 m_isphysical = value;
86 if (!m_isphysical) // Zero the remembered last velocity
87 m_lastVelocity = Vector3.Zero;
88 }
89 }
90
91 private Vector3 _position;
92 private Vector3 _velocity;
93 private Vector3 _torque;
94 private Vector3 m_lastVelocity;
95 private Vector3 m_lastposition;
96 private Quaternion m_lastorientation = new Quaternion();
97 private Vector3 m_rotationalVelocity;
98 private Vector3 _size;
99 private Vector3 _acceleration;
100 // private d.Vector3 _zeroPosition = new d.Vector3(0.0f, 0.0f, 0.0f);
101 private Quaternion _orientation;
102 private Vector3 m_taintposition;
103 private Vector3 m_taintsize;
104 private Vector3 m_taintVelocity;
105 private Vector3 m_taintTorque;
106 private Quaternion m_taintrot;
107 private Vector3 m_angularlock = Vector3.One;
108 private Vector3 m_taintAngularLock = Vector3.One;
109 private IntPtr Amotor = IntPtr.Zero;
110
111 private 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.Zero, 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, prim.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 // The body doesn't already have a finite rotation mode set here
1188 if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null)
1189 {
1190 prm.createAMotor(m_angularlock);
1191 }
1192 prm.Body = Body;
1193 _parent_scene.ActivatePrim(prm);
1194 }
1195
1196 m_collisionCategories |= CollisionCategories.Body;
1197 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1198
1199 if (m_assetFailed)
1200 {
1201 d.GeomSetCategoryBits(prim_geom, 0);
1202 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1203 }
1204 else
1205 {
1206 //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name);
1207 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1208 //Console.WriteLine(" Post GeomSetCategoryBits 2");
1209 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1210 }
1211
1212 d.Quaternion quat2 = new d.Quaternion();
1213 quat2.W = _orientation.W;
1214 quat2.X = _orientation.X;
1215 quat2.Y = _orientation.Y;
1216 quat2.Z = _orientation.Z;
1217
1218 d.Matrix3 mat2 = new d.Matrix3();
1219 d.RfromQ(out mat2, ref quat2);
1220 d.GeomSetBody(prim_geom, Body);
1221 d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z);
1222 //d.GeomSetOffsetPosition(prim.prim_geom,
1223 // (Position.X - prm.Position.X) - pMass.c.X,
1224 // (Position.Y - prm.Position.Y) - pMass.c.Y,
1225 // (Position.Z - prm.Position.Z) - pMass.c.Z);
1226 //d.GeomSetOffsetRotation(prim_geom, ref mat2);
1227 d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z);
1228 d.BodySetMass(Body, ref pMass);
1229
1230 d.BodySetAutoDisableFlag(Body, true);
1231 d.BodySetAutoDisableSteps(Body, body_autodisable_frames);
1232
1233 m_interpenetrationcount = 0;
1234 m_collisionscore = 0;
1235 m_disabled = false;
1236
1237 // The body doesn't already have a finite rotation mode set here
1238 if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null)
1239 {
1240 createAMotor(m_angularlock);
1241 }
1242
1243 d.BodySetPosition(Body, Position.X, Position.Y, Position.Z);
1244
1245 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1246 m_vehicle.Enable(Body, _parent_scene);
1247
1248 _parent_scene.ActivatePrim(this);
1249 }
1250 }
1251
1252 private void ChildSetGeom(OdePrim odePrim)
1253 {
1254// m_log.DebugFormat(
1255// "[ODE PRIM]: ChildSetGeom {0} {1} for {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID);
1256
1257 //if (IsPhysical && Body != IntPtr.Zero)
1258 lock (childrenPrim)
1259 {
1260 foreach (OdePrim prm in childrenPrim)
1261 {
1262 //prm.childPrim = true;
1263 prm.disableBody();
1264 //prm.m_taintparent = null;
1265 //prm._parent = null;
1266 //prm.m_taintPhysics = false;
1267 //prm.m_disabled = true;
1268 //prm.childPrim = false;
1269 }
1270 }
1271
1272 disableBody();
1273
1274 // Spurious - Body == IntPtr.Zero after disableBody()
1275// if (Body != IntPtr.Zero)
1276// {
1277// _parent_scene.DeactivatePrim(this);
1278// }
1279
1280 lock (childrenPrim)
1281 {
1282 foreach (OdePrim prm in childrenPrim)
1283 {
1284//Console.WriteLine("ChildSetGeom calls ParentPrim");
1285 AddChildPrim(prm);
1286 }
1287 }
1288 }
1289
1290 private void ChildDelink(OdePrim odePrim)
1291 {
1292// m_log.DebugFormat(
1293// "[ODE PRIM]: Delinking prim {0} {1} from {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID);
1294
1295 // Okay, we have a delinked child.. need to rebuild the body.
1296 lock (childrenPrim)
1297 {
1298 foreach (OdePrim prm in childrenPrim)
1299 {
1300 prm.childPrim = true;
1301 prm.disableBody();
1302 //prm.m_taintparent = null;
1303 //prm._parent = null;
1304 //prm.m_taintPhysics = false;
1305 //prm.m_disabled = true;
1306 //prm.childPrim = false;
1307 }
1308 }
1309
1310 disableBody();
1311
1312 lock (childrenPrim)
1313 {
1314 //Console.WriteLine("childrenPrim.Remove " + odePrim);
1315 childrenPrim.Remove(odePrim);
1316 }
1317
1318 // Spurious - Body == IntPtr.Zero after disableBody()
1319// if (Body != IntPtr.Zero)
1320// {
1321// _parent_scene.DeactivatePrim(this);
1322// }
1323
1324 lock (childrenPrim)
1325 {
1326 foreach (OdePrim prm in childrenPrim)
1327 {
1328//Console.WriteLine("ChildDelink calls ParentPrim");
1329 AddChildPrim(prm);
1330 }
1331 }
1332 }
1333
1334 /// <summary>
1335 /// Change prim in response to a selection taint.
1336 /// </summary>
1337 private void changeSelectedStatus()
1338 {
1339 if (m_taintselected)
1340 {
1341 m_collisionCategories = CollisionCategories.Selected;
1342 m_collisionFlags = (CollisionCategories.Sensor | CollisionCategories.Space);
1343
1344 // We do the body disable soft twice because 'in theory' a collision could have happened
1345 // in between the disabling and the collision properties setting
1346 // which would wake the physical body up from a soft disabling and potentially cause it to fall
1347 // through the ground.
1348
1349 // NOTE FOR JOINTS: this doesn't always work for jointed assemblies because if you select
1350 // just one part of the assembly, the rest of the assembly is non-selected and still simulating,
1351 // so that causes the selected part to wake up and continue moving.
1352
1353 // even if you select all parts of a jointed assembly, it is not guaranteed that the entire
1354 // assembly will stop simulating during the selection, because of the lack of atomicity
1355 // of select operations (their processing could be interrupted by a thread switch, causing
1356 // simulation to continue before all of the selected object notifications trickle down to
1357 // the physics engine).
1358
1359 // e.g. we select 100 prims that are connected by joints. non-atomically, the first 50 are
1360 // selected and disabled. then, due to a thread switch, the selection processing is
1361 // interrupted and the physics engine continues to simulate, so the last 50 items, whose
1362 // selection was not yet processed, continues to simulate. this wakes up ALL of the
1363 // first 50 again. then the last 50 are disabled. then the first 50, which were just woken
1364 // up, start simulating again, which in turn wakes up the last 50.
1365
1366 if (IsPhysical)
1367 {
1368 disableBodySoft();
1369 }
1370
1371 if (m_assetFailed)
1372 {
1373 d.GeomSetCategoryBits(prim_geom, 0);
1374 d.GeomSetCollideBits(prim_geom, 0);
1375 }
1376 else
1377 {
1378 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1379 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1380 }
1381
1382 if (IsPhysical)
1383 {
1384 disableBodySoft();
1385 }
1386 }
1387 else
1388 {
1389 m_collisionCategories = CollisionCategories.Geom;
1390
1391 if (IsPhysical)
1392 m_collisionCategories |= CollisionCategories.Body;
1393
1394 m_collisionFlags = m_default_collisionFlags;
1395
1396 if (m_collidesLand)
1397 m_collisionFlags |= CollisionCategories.Land;
1398 if (m_collidesWater)
1399 m_collisionFlags |= CollisionCategories.Water;
1400
1401 if (m_assetFailed)
1402 {
1403 d.GeomSetCategoryBits(prim_geom, 0);
1404 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1405 }
1406 else
1407 {
1408 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1409 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1410 }
1411
1412 if (IsPhysical)
1413 {
1414 if (Body != IntPtr.Zero)
1415 {
1416 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1417 d.BodySetForce(Body, 0, 0, 0);
1418 enableBodySoft();
1419 }
1420 }
1421 }
1422
1423 resetCollisionAccounting();
1424 m_isSelected = m_taintselected;
1425 }//end changeSelectedStatus
1426
1427 internal void ResetTaints()
1428 {
1429 m_taintposition = _position;
1430 m_taintrot = _orientation;
1431 m_taintPhysics = IsPhysical;
1432 m_taintselected = m_isSelected;
1433 m_taintsize = _size;
1434 m_taintshape = false;
1435 m_taintforce = false;
1436 m_taintdisable = false;
1437 m_taintVelocity = Vector3.Zero;
1438 }
1439
1440 /// <summary>
1441 /// Create a geometry for the given mesh in the given target space.
1442 /// </summary>
1443 /// <param name="m_targetSpace"></param>
1444 /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param>
1445 private void CreateGeom(IntPtr m_targetSpace, IMesh mesh)
1446 {
1447#if SPAM
1448Console.WriteLine("CreateGeom:");
1449#endif
1450 if (mesh != null)
1451 {
1452 setMesh(_parent_scene, mesh);
1453 }
1454 else
1455 {
1456 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
1457 {
1458 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
1459 {
1460 if (((_size.X / 2f) > 0f))
1461 {
1462// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1463 try
1464 {
1465//Console.WriteLine(" CreateGeom 1");
1466 SetGeom(d.CreateSphere(m_targetSpace, _size.X / 2));
1467 m_expectedCollisionContacts = 3;
1468 }
1469 catch (AccessViolationException)
1470 {
1471 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1472 return;
1473 }
1474 }
1475 else
1476 {
1477// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1478 try
1479 {
1480//Console.WriteLine(" CreateGeom 2");
1481 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1482 m_expectedCollisionContacts = 4;
1483 }
1484 catch (AccessViolationException)
1485 {
1486 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1487 return;
1488 }
1489 }
1490 }
1491 else
1492 {
1493// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1494 try
1495 {
1496//Console.WriteLine(" CreateGeom 3");
1497 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1498 m_expectedCollisionContacts = 4;
1499 }
1500 catch (AccessViolationException)
1501 {
1502 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1503 return;
1504 }
1505 }
1506 }
1507 else
1508 {
1509// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1510 try
1511 {
1512//Console.WriteLine(" CreateGeom 4");
1513 SetGeom(d.CreateBox(m_targetSpace, _size.X, _size.Y, _size.Z));
1514 m_expectedCollisionContacts = 4;
1515 }
1516 catch (AccessViolationException)
1517 {
1518 m_log.WarnFormat("[PHYSICS]: Unable to create physics proxy for object {0}", Name);
1519 return;
1520 }
1521 }
1522 }
1523 }
1524
1525 /// <summary>
1526 /// Remove the existing geom from this prim.
1527 /// </summary>
1528 /// <param name="m_targetSpace"></param>
1529 /// <param name="mesh">If null, then a mesh is used that is based on the profile shape data.</param>
1530 /// <returns>true if the geom was successfully removed, false if it was already gone or the remove failed.</returns>
1531 internal bool RemoveGeom()
1532 {
1533 if (prim_geom != IntPtr.Zero)
1534 {
1535 try
1536 {
1537 _parent_scene.geom_name_map.Remove(prim_geom);
1538 _parent_scene.actor_name_map.Remove(prim_geom);
1539 d.GeomDestroy(prim_geom);
1540 m_expectedCollisionContacts = 0;
1541 prim_geom = IntPtr.Zero;
1542 }
1543 catch (System.AccessViolationException)
1544 {
1545 prim_geom = IntPtr.Zero;
1546 m_expectedCollisionContacts = 0;
1547 m_log.ErrorFormat("[PHYSICS]: PrimGeom dead for {0}", Name);
1548
1549 return false;
1550 }
1551
1552 return true;
1553 }
1554 else
1555 {
1556 m_log.WarnFormat(
1557 "[ODE PRIM]: Called RemoveGeom() on {0} {1} where geometry was already null.", Name, LocalID);
1558
1559 return false;
1560 }
1561 }
1562 /// <summary>
1563 /// Add prim in response to an add taint.
1564 /// </summary>
1565 private void changeadd()
1566 {
1567// m_log.DebugFormat("[ODE PRIM]: Adding prim {0}", Name);
1568
1569 int[] iprimspaceArrItem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1570 IntPtr targetspace = _parent_scene.calculateSpaceForGeom(_position);
1571
1572 if (targetspace == IntPtr.Zero)
1573 targetspace = _parent_scene.createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
1574
1575 m_targetSpace = targetspace;
1576
1577 IMesh mesh = null;
1578
1579 if (_parent_scene.needsMeshing(_pbs))
1580 {
1581 // Don't need to re-enable body.. it's done in SetMesh
1582 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1583 // createmesh returns null when it's a shape that isn't a cube.
1584 // m_log.Debug(m_localID);
1585 if (mesh == null)
1586 CheckMeshAsset();
1587 else
1588 m_assetFailed = false;
1589 }
1590
1591#if SPAM
1592Console.WriteLine("changeadd 1");
1593#endif
1594 CreateGeom(m_targetSpace, mesh);
1595
1596 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1597 d.Quaternion myrot = new d.Quaternion();
1598 myrot.X = _orientation.X;
1599 myrot.Y = _orientation.Y;
1600 myrot.Z = _orientation.Z;
1601 myrot.W = _orientation.W;
1602 d.GeomSetQuaternion(prim_geom, ref myrot);
1603
1604 if (IsPhysical && Body == IntPtr.Zero)
1605 enableBody();
1606
1607 changeSelectedStatus();
1608
1609 m_taintadd = false;
1610 }
1611
1612 /// <summary>
1613 /// Move prim in response to a move taint.
1614 /// </summary>
1615 private void changemove()
1616 {
1617 if (IsPhysical)
1618 {
1619 if (!m_disabled && !m_taintremove && !childPrim)
1620 {
1621 if (Body == IntPtr.Zero)
1622 enableBody();
1623
1624 //Prim auto disable after 20 frames,
1625 //if you move it, re-enable the prim manually.
1626 if (_parent != null)
1627 {
1628 if (m_linkJoint != IntPtr.Zero)
1629 {
1630 d.JointDestroy(m_linkJoint);
1631 m_linkJoint = IntPtr.Zero;
1632 }
1633 }
1634
1635 if (Body != IntPtr.Zero)
1636 {
1637 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1638
1639 if (_parent != null)
1640 {
1641 OdePrim odParent = (OdePrim)_parent;
1642 if (Body != (IntPtr)0 && odParent.Body != (IntPtr)0 && Body != odParent.Body)
1643 {
1644// KF: Fixed Joints were removed? Anyway - this Console.WriteLine does not show up, so routine is not used??
1645Console.WriteLine(" JointCreateFixed");
1646 m_linkJoint = d.JointCreateFixed(_parent_scene.world, _linkJointGroup);
1647 d.JointAttach(m_linkJoint, Body, odParent.Body);
1648 d.JointSetFixed(m_linkJoint);
1649 }
1650 }
1651 d.BodyEnable(Body);
1652 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1653 {
1654 m_vehicle.Enable(Body, _parent_scene);
1655 }
1656 }
1657 else
1658 {
1659 m_log.WarnFormat("[PHYSICS]: Body for {0} still null after enableBody(). This is a crash scenario.", Name);
1660 }
1661 }
1662 //else
1663 // {
1664 //m_log.Debug("[BUG]: race!");
1665 //}
1666 }
1667
1668 // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position);
1669 // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position);
1670// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1671
1672 IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace);
1673 m_targetSpace = tempspace;
1674
1675// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1676
1677 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
1678
1679// _parent_scene.waitForSpaceUnlock(m_targetSpace);
1680 d.SpaceAdd(m_targetSpace, prim_geom);
1681
1682 changeSelectedStatus();
1683
1684 resetCollisionAccounting();
1685 m_taintposition = _position;
1686 }
1687
1688 internal void Move(float timestep)
1689 {
1690 float fx = 0;
1691 float fy = 0;
1692 float fz = 0;
1693
1694 if (IsPhysical && (Body != IntPtr.Zero) && !m_isSelected && !childPrim) // KF: Only move root prims.
1695 {
1696 if (m_vehicle.Type != Vehicle.TYPE_NONE)
1697 {
1698 // 'VEHICLES' are dealt with in ODEDynamics.cs
1699 m_vehicle.Step(timestep, _parent_scene);
1700 }
1701 else
1702 {
1703//Console.WriteLine("Move " + Name);
1704 if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009
1705 // NON-'VEHICLES' are dealt with here
1706// if (d.BodyIsEnabled(Body) && !m_angularlock.ApproxEquals(Vector3.Zero, 0.003f))
1707// {
1708// d.Vector3 avel2 = d.BodyGetAngularVel(Body);
1709// /*
1710// if (m_angularlock.X == 1)
1711// avel2.X = 0;
1712// if (m_angularlock.Y == 1)
1713// avel2.Y = 0;
1714// if (m_angularlock.Z == 1)
1715// avel2.Z = 0;
1716// d.BodySetAngularVel(Body, avel2.X, avel2.Y, avel2.Z);
1717// */
1718// }
1719 //float PID_P = 900.0f;
1720
1721 float m_mass = CalculateMass();
1722
1723// fz = 0f;
1724 //m_log.Info(m_collisionFlags.ToString());
1725
1726
1727 //KF: m_buoyancy should be set by llSetBuoyancy() for non-vehicle.
1728 // would come from SceneObjectPart.cs, public void SetBuoyancy(float fvalue) , PhysActor.Buoyancy = fvalue; ??
1729 // m_buoyancy: (unlimited value) <0=Falls fast; 0=1g; 1=0g; >1 = floats up
1730 // gravityz multiplier = 1 - m_buoyancy
1731 fz = _parent_scene.gravityz * (1.0f - m_buoyancy) * m_mass;
1732
1733 if (PIDActive)
1734 {
1735//Console.WriteLine("PID " + Name);
1736 // KF - this is for object move? eg. llSetPos() ?
1737 //if (!d.BodyIsEnabled(Body))
1738 //d.BodySetForce(Body, 0f, 0f, 0f);
1739 // If we're using the PID controller, then we have no gravity
1740 //fz = (-1 * _parent_scene.gravityz) * m_mass; //KF: ?? Prims have no global gravity,so simply...
1741 fz = 0f;
1742
1743 // no lock; for now it's only called from within Simulate()
1744
1745 // If the PID Controller isn't active then we set our force
1746 // calculating base velocity to the current position
1747
1748 if ((m_PIDTau < 1) && (m_PIDTau != 0))
1749 {
1750 //PID_G = PID_G / m_PIDTau;
1751 m_PIDTau = 1;
1752 }
1753
1754 if ((PID_G - m_PIDTau) <= 0)
1755 {
1756 PID_G = m_PIDTau + 1;
1757 }
1758 //PidStatus = true;
1759
1760 // PhysicsVector vec = new PhysicsVector();
1761 d.Vector3 vel = d.BodyGetLinearVel(Body);
1762
1763 d.Vector3 pos = d.BodyGetPosition(Body);
1764 _target_velocity =
1765 new Vector3(
1766 (m_PIDTarget.X - pos.X) * ((PID_G - m_PIDTau) * timestep),
1767 (m_PIDTarget.Y - pos.Y) * ((PID_G - m_PIDTau) * timestep),
1768 (m_PIDTarget.Z - pos.Z) * ((PID_G - m_PIDTau) * timestep)
1769 );
1770
1771 // if velocity is zero, use position control; otherwise, velocity control
1772
1773 if (_target_velocity.ApproxEquals(Vector3.Zero,0.1f))
1774 {
1775 // keep track of where we stopped. No more slippin' & slidin'
1776
1777 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1778 // react to the physics scene by moving it's position.
1779 // Avatar to Avatar collisions
1780 // Prim to avatar collisions
1781
1782 //fx = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
1783 //fy = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2);
1784 //fz = fz + (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
1785 d.BodySetPosition(Body, m_PIDTarget.X, m_PIDTarget.Y, m_PIDTarget.Z);
1786 d.BodySetLinearVel(Body, 0, 0, 0);
1787 d.BodyAddForce(Body, 0, 0, fz);
1788 return;
1789 }
1790 else
1791 {
1792 _zeroFlag = false;
1793
1794 // We're flying and colliding with something
1795 fx = ((_target_velocity.X) - vel.X) * (PID_D);
1796 fy = ((_target_velocity.Y) - vel.Y) * (PID_D);
1797
1798 // vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P;
1799
1800 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
1801 }
1802 } // end if (PIDActive)
1803
1804 // Hover PID Controller needs to be mutually exlusive to MoveTo PID controller
1805 if (m_useHoverPID && !PIDActive)
1806 {
1807//Console.WriteLine("Hover " + Name);
1808
1809 // If we're using the PID controller, then we have no gravity
1810 fz = (-1 * _parent_scene.gravityz) * m_mass;
1811
1812 // no lock; for now it's only called from within Simulate()
1813
1814 // If the PID Controller isn't active then we set our force
1815 // calculating base velocity to the current position
1816
1817 if ((m_PIDTau < 1))
1818 {
1819 PID_G = PID_G / m_PIDTau;
1820 }
1821
1822 if ((PID_G - m_PIDTau) <= 0)
1823 {
1824 PID_G = m_PIDTau + 1;
1825 }
1826
1827 // Where are we, and where are we headed?
1828 d.Vector3 pos = d.BodyGetPosition(Body);
1829 d.Vector3 vel = d.BodyGetLinearVel(Body);
1830
1831 // Non-Vehicles have a limited set of Hover options.
1832 // determine what our target height really is based on HoverType
1833 switch (m_PIDHoverType)
1834 {
1835 case PIDHoverType.Ground:
1836 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
1837 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
1838 break;
1839 case PIDHoverType.GroundAndWater:
1840 m_groundHeight = _parent_scene.GetTerrainHeightAtXY(pos.X, pos.Y);
1841 m_waterHeight = _parent_scene.GetWaterLevel();
1842 if (m_groundHeight > m_waterHeight)
1843 {
1844 m_targetHoverHeight = m_groundHeight + m_PIDHoverHeight;
1845 }
1846 else
1847 {
1848 m_targetHoverHeight = m_waterHeight + m_PIDHoverHeight;
1849 }
1850 break;
1851
1852 } // end switch (m_PIDHoverType)
1853
1854
1855 _target_velocity =
1856 new Vector3(0.0f, 0.0f,
1857 (m_targetHoverHeight - pos.Z) * ((PID_G - m_PIDHoverTau) * timestep)
1858 );
1859
1860 // if velocity is zero, use position control; otherwise, velocity control
1861
1862 if (_target_velocity.ApproxEquals(Vector3.Zero, 0.1f))
1863 {
1864 // keep track of where we stopped. No more slippin' & slidin'
1865
1866 // We only want to deactivate the PID Controller if we think we want to have our surrogate
1867 // react to the physics scene by moving it's position.
1868 // Avatar to Avatar collisions
1869 // Prim to avatar collisions
1870
1871 d.BodySetPosition(Body, pos.X, pos.Y, m_targetHoverHeight);
1872 d.BodySetLinearVel(Body, vel.X, vel.Y, 0);
1873 d.BodyAddForce(Body, 0, 0, fz);
1874 return;
1875 }
1876 else
1877 {
1878 _zeroFlag = false;
1879
1880 // We're flying and colliding with something
1881 fz = fz + ((_target_velocity.Z - vel.Z) * (PID_D) * m_mass);
1882 }
1883 }
1884
1885 fx *= m_mass;
1886 fy *= m_mass;
1887 //fz *= m_mass;
1888
1889 fx += m_force.X;
1890 fy += m_force.Y;
1891 fz += m_force.Z;
1892
1893 //m_log.Info("[OBJPID]: X:" + fx.ToString() + " Y:" + fy.ToString() + " Z:" + fz.ToString());
1894 if (fx != 0 || fy != 0 || fz != 0)
1895 {
1896 //m_taintdisable = true;
1897 //base.RaiseOutOfBounds(Position);
1898 //d.BodySetLinearVel(Body, fx, fy, 0f);
1899 if (!d.BodyIsEnabled(Body))
1900 {
1901 // A physical body at rest on a surface will auto-disable after a while,
1902 // this appears to re-enable it incase the surface it is upon vanishes,
1903 // and the body should fall again.
1904 d.BodySetLinearVel(Body, 0f, 0f, 0f);
1905 d.BodySetForce(Body, 0, 0, 0);
1906 enableBodySoft();
1907 }
1908
1909 // 35x10 = 350n times the mass per second applied maximum.
1910 float nmax = 35f * m_mass;
1911 float nmin = -35f * m_mass;
1912
1913 if (fx > nmax)
1914 fx = nmax;
1915 if (fx < nmin)
1916 fx = nmin;
1917 if (fy > nmax)
1918 fy = nmax;
1919 if (fy < nmin)
1920 fy = nmin;
1921 d.BodyAddForce(Body, fx, fy, fz);
1922//Console.WriteLine("AddForce " + fx + "," + fy + "," + fz);
1923 }
1924 }
1925 }
1926 else
1927 { // is not physical, or is not a body or is selected
1928 // _zeroPosition = d.BodyGetPosition(Body);
1929 return;
1930//Console.WriteLine("Nothing " + Name);
1931
1932 }
1933 }
1934
1935 private void rotate()
1936 {
1937 d.Quaternion myrot = new d.Quaternion();
1938 myrot.X = _orientation.X;
1939 myrot.Y = _orientation.Y;
1940 myrot.Z = _orientation.Z;
1941 myrot.W = _orientation.W;
1942 if (Body != IntPtr.Zero)
1943 {
1944 // KF: If this is a root prim do BodySet
1945 d.BodySetQuaternion(Body, ref myrot);
1946 if (IsPhysical)
1947 {
1948 if (!m_angularlock.ApproxEquals(Vector3.One, 0f))
1949 createAMotor(m_angularlock);
1950 }
1951 }
1952 else
1953 {
1954 // daughter prim, do Geom set
1955 d.GeomSetQuaternion(prim_geom, ref myrot);
1956 }
1957
1958 resetCollisionAccounting();
1959 m_taintrot = _orientation;
1960 }
1961
1962 private void resetCollisionAccounting()
1963 {
1964 m_collisionscore = 0;
1965 m_interpenetrationcount = 0;
1966 m_disabled = false;
1967 }
1968
1969 /// <summary>
1970 /// Change prim in response to a disable taint.
1971 /// </summary>
1972 private void changedisable()
1973 {
1974 m_disabled = true;
1975 if (Body != IntPtr.Zero)
1976 {
1977 d.BodyDisable(Body);
1978 Body = IntPtr.Zero;
1979 }
1980
1981 m_taintdisable = false;
1982 }
1983
1984 /// <summary>
1985 /// Change prim in response to a physics status taint
1986 /// </summary>
1987 private void changePhysicsStatus()
1988 {
1989 if (IsPhysical)
1990 {
1991 if (Body == IntPtr.Zero)
1992 {
1993 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
1994 {
1995 changeshape();
1996 }
1997 else
1998 {
1999 enableBody();
2000 }
2001 }
2002 }
2003 else
2004 {
2005 if (Body != IntPtr.Zero)
2006 {
2007 if (_pbs.SculptEntry && _parent_scene.meshSculptedPrim)
2008 {
2009 RemoveGeom();
2010
2011//Console.WriteLine("changePhysicsStatus for " + Name);
2012 changeadd();
2013 }
2014
2015 if (childPrim)
2016 {
2017 if (_parent != null)
2018 {
2019 OdePrim parent = (OdePrim)_parent;
2020 parent.ChildDelink(this);
2021 }
2022 }
2023 else
2024 {
2025 disableBody();
2026 }
2027 }
2028 }
2029
2030 changeSelectedStatus();
2031
2032 resetCollisionAccounting();
2033 m_taintPhysics = IsPhysical;
2034 }
2035
2036 /// <summary>
2037 /// Change prim in response to a size taint.
2038 /// </summary>
2039 private void changesize()
2040 {
2041#if SPAM
2042 m_log.DebugFormat("[ODE PRIM]: Called changesize");
2043#endif
2044
2045 if (_size.X <= 0) _size.X = 0.01f;
2046 if (_size.Y <= 0) _size.Y = 0.01f;
2047 if (_size.Z <= 0) _size.Z = 0.01f;
2048
2049 //kill body to rebuild
2050 if (IsPhysical && Body != IntPtr.Zero)
2051 {
2052 if (childPrim)
2053 {
2054 if (_parent != null)
2055 {
2056 OdePrim parent = (OdePrim)_parent;
2057 parent.ChildDelink(this);
2058 }
2059 }
2060 else
2061 {
2062 disableBody();
2063 }
2064 }
2065
2066 if (d.SpaceQuery(m_targetSpace, prim_geom))
2067 {
2068// _parent_scene.waitForSpaceUnlock(m_targetSpace);
2069 d.SpaceRemove(m_targetSpace, prim_geom);
2070 }
2071
2072 RemoveGeom();
2073
2074 // we don't need to do space calculation because the client sends a position update also.
2075
2076 IMesh mesh = null;
2077
2078 // Construction of new prim
2079 if (_parent_scene.needsMeshing(_pbs))
2080 {
2081 float meshlod = _parent_scene.meshSculptLOD;
2082
2083 if (IsPhysical)
2084 meshlod = _parent_scene.MeshSculptphysicalLOD;
2085 // Don't need to re-enable body.. it's done in SetMesh
2086
2087 if (_parent_scene.needsMeshing(_pbs))
2088 {
2089 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
2090 if (mesh == null)
2091 CheckMeshAsset();
2092 else
2093 m_assetFailed = false;
2094 }
2095
2096 }
2097
2098 CreateGeom(m_targetSpace, mesh);
2099 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2100 d.Quaternion myrot = new d.Quaternion();
2101 myrot.X = _orientation.X;
2102 myrot.Y = _orientation.Y;
2103 myrot.Z = _orientation.Z;
2104 myrot.W = _orientation.W;
2105 d.GeomSetQuaternion(prim_geom, ref myrot);
2106
2107 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2108 if (IsPhysical && Body == IntPtr.Zero && !childPrim)
2109 {
2110 // Re creates body on size.
2111 // EnableBody also does setMass()
2112 enableBody();
2113 d.BodyEnable(Body);
2114 }
2115
2116 changeSelectedStatus();
2117
2118 if (childPrim)
2119 {
2120 if (_parent is OdePrim)
2121 {
2122 OdePrim parent = (OdePrim)_parent;
2123 parent.ChildSetGeom(this);
2124 }
2125 }
2126 resetCollisionAccounting();
2127 m_taintsize = _size;
2128 }
2129
2130 /// <summary>
2131 /// Change prim in response to a float on water taint.
2132 /// </summary>
2133 /// <param name="timestep"></param>
2134 private void changefloatonwater()
2135 {
2136 m_collidesWater = m_taintCollidesWater;
2137
2138 if (m_collidesWater)
2139 {
2140 m_collisionFlags |= CollisionCategories.Water;
2141 }
2142 else
2143 {
2144 m_collisionFlags &= ~CollisionCategories.Water;
2145 }
2146
2147 if (m_assetFailed)
2148 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
2149 else
2150
2151 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2152 }
2153 /// <summary>
2154 /// Change prim in response to a shape taint.
2155 /// </summary>
2156 private void changeshape()
2157 {
2158 m_taintshape = false;
2159
2160 // Cleanup of old prim geometry and Bodies
2161 if (IsPhysical && Body != IntPtr.Zero)
2162 {
2163 if (childPrim)
2164 {
2165 if (_parent != null)
2166 {
2167 OdePrim parent = (OdePrim)_parent;
2168 parent.ChildDelink(this);
2169 }
2170 }
2171 else
2172 {
2173 disableBody();
2174 }
2175 }
2176
2177 RemoveGeom();
2178
2179 // we don't need to do space calculation because the client sends a position update also.
2180 if (_size.X <= 0) _size.X = 0.01f;
2181 if (_size.Y <= 0) _size.Y = 0.01f;
2182 if (_size.Z <= 0) _size.Z = 0.01f;
2183 // Construction of new prim
2184
2185 IMesh mesh = null;
2186
2187
2188 if (_parent_scene.needsMeshing(_pbs))
2189 {
2190 // Don't need to re-enable body.. it's done in CreateMesh
2191 float meshlod = _parent_scene.meshSculptLOD;
2192
2193 if (IsPhysical)
2194 meshlod = _parent_scene.MeshSculptphysicalLOD;
2195
2196 // createmesh returns null when it doesn't mesh.
2197 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
2198 if (mesh == null)
2199 CheckMeshAsset();
2200 else
2201 m_assetFailed = false;
2202 }
2203
2204 CreateGeom(m_targetSpace, mesh);
2205 d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z);
2206 d.Quaternion myrot = new d.Quaternion();
2207 //myrot.W = _orientation.w;
2208 myrot.W = _orientation.W;
2209 myrot.X = _orientation.X;
2210 myrot.Y = _orientation.Y;
2211 myrot.Z = _orientation.Z;
2212 d.GeomSetQuaternion(prim_geom, ref myrot);
2213
2214 //d.GeomBoxSetLengths(prim_geom, _size.X, _size.Y, _size.Z);
2215 if (IsPhysical && Body == IntPtr.Zero)
2216 {
2217 // Re creates body on size.
2218 // EnableBody also does setMass()
2219 enableBody();
2220 if (Body != IntPtr.Zero)
2221 {
2222 d.BodyEnable(Body);
2223 }
2224 }
2225
2226 changeSelectedStatus();
2227
2228 if (childPrim)
2229 {
2230 if (_parent is OdePrim)
2231 {
2232 OdePrim parent = (OdePrim)_parent;
2233 parent.ChildSetGeom(this);
2234 }
2235 }
2236
2237 resetCollisionAccounting();
2238// m_taintshape = false;
2239 }
2240
2241 /// <summary>
2242 /// Change prim in response to an add force taint.
2243 /// </summary>
2244 private void changeAddForce()
2245 {
2246 if (!m_isSelected)
2247 {
2248 lock (m_forcelist)
2249 {
2250 //m_log.Info("[PHYSICS]: dequeing forcelist");
2251 if (IsPhysical)
2252 {
2253 Vector3 iforce = Vector3.Zero;
2254 int i = 0;
2255 try
2256 {
2257 for (i = 0; i < m_forcelist.Count; i++)
2258 {
2259
2260 iforce = iforce + (m_forcelist[i] * 100);
2261 }
2262 }
2263 catch (IndexOutOfRangeException)
2264 {
2265 m_forcelist = new List<Vector3>();
2266 m_collisionscore = 0;
2267 m_interpenetrationcount = 0;
2268 m_taintforce = false;
2269 return;
2270 }
2271 catch (ArgumentOutOfRangeException)
2272 {
2273 m_forcelist = new List<Vector3>();
2274 m_collisionscore = 0;
2275 m_interpenetrationcount = 0;
2276 m_taintforce = false;
2277 return;
2278 }
2279 d.BodyEnable(Body);
2280 d.BodyAddForce(Body, iforce.X, iforce.Y, iforce.Z);
2281 }
2282 m_forcelist.Clear();
2283 }
2284
2285 m_collisionscore = 0;
2286 m_interpenetrationcount = 0;
2287 }
2288
2289 m_taintforce = false;
2290 }
2291
2292 /// <summary>
2293 /// Change prim in response to a torque taint.
2294 /// </summary>
2295 private void changeSetTorque()
2296 {
2297 if (!m_isSelected)
2298 {
2299 if (IsPhysical && Body != IntPtr.Zero)
2300 {
2301 d.BodySetTorque(Body, m_taintTorque.X, m_taintTorque.Y, m_taintTorque.Z);
2302 }
2303 }
2304
2305 m_taintTorque = Vector3.Zero;
2306 }
2307
2308 /// <summary>
2309 /// Change prim in response to an angular force taint.
2310 /// </summary>
2311 private void changeAddAngularForce()
2312 {
2313 if (!m_isSelected)
2314 {
2315 lock (m_angularforcelist)
2316 {
2317 //m_log.Info("[PHYSICS]: dequeing forcelist");
2318 if (IsPhysical)
2319 {
2320 Vector3 iforce = Vector3.Zero;
2321 for (int i = 0; i < m_angularforcelist.Count; i++)
2322 {
2323 iforce = iforce + (m_angularforcelist[i] * 100);
2324 }
2325 d.BodyEnable(Body);
2326 d.BodyAddTorque(Body, iforce.X, iforce.Y, iforce.Z);
2327
2328 }
2329 m_angularforcelist.Clear();
2330 }
2331
2332 m_collisionscore = 0;
2333 m_interpenetrationcount = 0;
2334 }
2335
2336 m_taintaddangularforce = false;
2337 }
2338
2339 /// <summary>
2340 /// Change prim in response to a velocity taint.
2341 /// </summary>
2342 private void changevelocity()
2343 {
2344 if (!m_isSelected)
2345 {
2346 // Not sure exactly why this sleep is here, but from experimentation it appears to stop an avatar
2347 // walking through a default rez size prim if it keeps kicking it around - justincc.
2348 Thread.Sleep(20);
2349
2350 if (IsPhysical)
2351 {
2352 if (Body != IntPtr.Zero)
2353 {
2354 d.BodySetLinearVel(Body, m_taintVelocity.X, m_taintVelocity.Y, m_taintVelocity.Z);
2355 }
2356 }
2357
2358 //resetCollisionAccounting();
2359 }
2360
2361 m_taintVelocity = Vector3.Zero;
2362 }
2363
2364 internal void setPrimForRemoval()
2365 {
2366 m_taintremove = true;
2367 }
2368
2369 public override bool Flying
2370 {
2371 // no flying prims for you
2372 get { return false; }
2373 set { }
2374 }
2375
2376 public override bool IsColliding
2377 {
2378 get { return iscolliding; }
2379 set { iscolliding = value; }
2380 }
2381
2382 public override bool CollidingGround
2383 {
2384 get { return false; }
2385 set { return; }
2386 }
2387
2388 public override bool CollidingObj
2389 {
2390 get { return false; }
2391 set { return; }
2392 }
2393
2394 public override bool ThrottleUpdates
2395 {
2396 get { return m_throttleUpdates; }
2397 set { m_throttleUpdates = value; }
2398 }
2399
2400 public override bool Stopped
2401 {
2402 get { return _zeroFlag; }
2403 }
2404
2405 public override Vector3 Position
2406 {
2407 get { return _position; }
2408
2409 set { _position = value;
2410 //m_log.Info("[PHYSICS]: " + _position.ToString());
2411 }
2412 }
2413
2414 public override Vector3 Size
2415 {
2416 get { return _size; }
2417 set
2418 {
2419 if (value.IsFinite())
2420 {
2421 _size = value;
2422// m_log.DebugFormat("[PHYSICS]: Set size on {0} to {1}", Name, value);
2423 }
2424 else
2425 {
2426 m_log.WarnFormat("[PHYSICS]: Got NaN Size on object {0}", Name);
2427 }
2428 }
2429 }
2430
2431 public override float Mass
2432 {
2433 get { return CalculateMass(); }
2434 }
2435
2436 public override Vector3 Force
2437 {
2438 //get { return Vector3.Zero; }
2439 get { return m_force; }
2440 set
2441 {
2442 if (value.IsFinite())
2443 {
2444 m_force = value;
2445 }
2446 else
2447 {
2448 m_log.WarnFormat("[PHYSICS]: NaN in Force Applied to an Object {0}", Name);
2449 }
2450 }
2451 }
2452
2453 public override int VehicleType
2454 {
2455 get { return (int)m_vehicle.Type; }
2456 set { m_vehicle.ProcessTypeChange((Vehicle)value); }
2457 }
2458
2459 public override void VehicleFloatParam(int param, float value)
2460 {
2461 m_vehicle.ProcessFloatVehicleParam((Vehicle) param, value);
2462 }
2463
2464 public override void VehicleVectorParam(int param, Vector3 value)
2465 {
2466 m_vehicle.ProcessVectorVehicleParam((Vehicle) param, value);
2467 }
2468
2469 public override void VehicleRotationParam(int param, Quaternion rotation)
2470 {
2471 m_vehicle.ProcessRotationVehicleParam((Vehicle) param, rotation);
2472 }
2473
2474 public override void VehicleFlags(int param, bool remove)
2475 {
2476 m_vehicle.ProcessVehicleFlags(param, remove);
2477 }
2478
2479 public override void SetVolumeDetect(int param)
2480 {
2481 // We have to lock the scene here so that an entire simulate loop either uses volume detect for all
2482 // possible collisions with this prim or for none of them.
2483 lock (_parent_scene.OdeLock)
2484 {
2485 m_isVolumeDetect = (param != 0);
2486 }
2487 }
2488
2489 public override Vector3 CenterOfMass
2490 {
2491 get { return Vector3.Zero; }
2492 }
2493
2494 public override Vector3 GeometricCenter
2495 {
2496 get { return Vector3.Zero; }
2497 }
2498
2499 public override PrimitiveBaseShape Shape
2500 {
2501 set
2502 {
2503 _pbs = value;
2504 m_assetFailed = false;
2505 m_taintshape = true;
2506 }
2507 }
2508
2509 public override Vector3 Velocity
2510 {
2511 get
2512 {
2513 // Average previous velocity with the new one so
2514 // client object interpolation works a 'little' better
2515 if (_zeroFlag)
2516 return Vector3.Zero;
2517
2518 Vector3 returnVelocity = Vector3.Zero;
2519 returnVelocity.X = (m_lastVelocity.X + _velocity.X) * 0.5f; // 0.5f is mathematically equiv to '/ 2'
2520 returnVelocity.Y = (m_lastVelocity.Y + _velocity.Y) * 0.5f;
2521 returnVelocity.Z = (m_lastVelocity.Z + _velocity.Z) * 0.5f;
2522 return returnVelocity;
2523 }
2524 set
2525 {
2526 if (value.IsFinite())
2527 {
2528 _velocity = value;
2529
2530 m_taintVelocity = value;
2531 _parent_scene.AddPhysicsActorTaint(this);
2532 }
2533 else
2534 {
2535 m_log.WarnFormat("[PHYSICS]: Got NaN Velocity in Object {0}", Name);
2536 }
2537
2538 }
2539 }
2540
2541 public override Vector3 Torque
2542 {
2543 get
2544 {
2545 if (!IsPhysical || Body == IntPtr.Zero)
2546 return Vector3.Zero;
2547
2548 return _torque;
2549 }
2550
2551 set
2552 {
2553 if (value.IsFinite())
2554 {
2555 m_taintTorque = value;
2556 _parent_scene.AddPhysicsActorTaint(this);
2557 }
2558 else
2559 {
2560 m_log.WarnFormat("[PHYSICS]: Got NaN Torque in Object {0}", Name);
2561 }
2562 }
2563 }
2564
2565 public override float CollisionScore
2566 {
2567 get { return m_collisionscore; }
2568 set { m_collisionscore = value; }
2569 }
2570
2571 public override bool Kinematic
2572 {
2573 get { return false; }
2574 set { }
2575 }
2576
2577 public override Quaternion Orientation
2578 {
2579 get { return _orientation; }
2580 set
2581 {
2582 if (QuaternionIsFinite(value))
2583 _orientation = value;
2584 else
2585 m_log.WarnFormat("[PHYSICS]: Got NaN quaternion Orientation from Scene in Object {0}", Name);
2586 }
2587 }
2588
2589 private static bool QuaternionIsFinite(Quaternion q)
2590 {
2591 if (Single.IsNaN(q.X) || Single.IsInfinity(q.X))
2592 return false;
2593 if (Single.IsNaN(q.Y) || Single.IsInfinity(q.Y))
2594 return false;
2595 if (Single.IsNaN(q.Z) || Single.IsInfinity(q.Z))
2596 return false;
2597 if (Single.IsNaN(q.W) || Single.IsInfinity(q.W))
2598 return false;
2599 return true;
2600 }
2601
2602 public override Vector3 Acceleration
2603 {
2604 get { return _acceleration; }
2605 set { _acceleration = value; }
2606 }
2607
2608 public override void AddForce(Vector3 force, bool pushforce)
2609 {
2610 if (force.IsFinite())
2611 {
2612 lock (m_forcelist)
2613 m_forcelist.Add(force);
2614
2615 m_taintforce = true;
2616 }
2617 else
2618 {
2619 m_log.WarnFormat("[PHYSICS]: Got Invalid linear force vector from Scene in Object {0}", Name);
2620 }
2621 //m_log.Info("[PHYSICS]: Added Force:" + force.ToString() + " to prim at " + Position.ToString());
2622 }
2623
2624 public override void AddAngularForce(Vector3 force, bool pushforce)
2625 {
2626 if (force.IsFinite())
2627 {
2628 m_angularforcelist.Add(force);
2629 m_taintaddangularforce = true;
2630 }
2631 else
2632 {
2633 m_log.WarnFormat("[PHYSICS]: Got Invalid Angular force vector from Scene in Object {0}", Name);
2634 }
2635 }
2636
2637 public override Vector3 RotationalVelocity
2638 {
2639 get
2640 {
2641 Vector3 pv = Vector3.Zero;
2642 if (_zeroFlag)
2643 return pv;
2644 m_lastUpdateSent = false;
2645
2646 if (m_rotationalVelocity.ApproxEquals(pv, 0.2f))
2647 return pv;
2648
2649 return m_rotationalVelocity;
2650 }
2651 set
2652 {
2653 if (value.IsFinite())
2654 {
2655 m_rotationalVelocity = value;
2656 setAngularVelocity(value.X, value.Y, value.Z);
2657 }
2658 else
2659 {
2660 m_log.WarnFormat("[PHYSICS]: Got NaN RotationalVelocity in Object {0}", Name);
2661 }
2662 }
2663 }
2664
2665 public override void CrossingFailure()
2666 {
2667 m_crossingfailures++;
2668 if (m_crossingfailures > _parent_scene.geomCrossingFailuresBeforeOutofbounds)
2669 {
2670 base.RaiseOutOfBounds(_position);
2671 return;
2672 }
2673 else if (m_crossingfailures == _parent_scene.geomCrossingFailuresBeforeOutofbounds)
2674 {
2675 m_log.Warn("[PHYSICS]: Too many crossing failures for: " + Name);
2676 }
2677 }
2678
2679 public override float Buoyancy
2680 {
2681 get { return m_buoyancy; }
2682 set { m_buoyancy = value; }
2683 }
2684
2685 public override void link(PhysicsActor obj)
2686 {
2687 m_taintparent = obj;
2688 }
2689
2690 public override void delink()
2691 {
2692 m_taintparent = null;
2693 }
2694
2695 public override void LockAngularMotion(Vector3 axis)
2696 {
2697 // reverse the zero/non zero values for ODE.
2698 if (axis.IsFinite())
2699 {
2700 axis.X = (axis.X > 0) ? 1f : 0f;
2701 axis.Y = (axis.Y > 0) ? 1f : 0f;
2702 axis.Z = (axis.Z > 0) ? 1f : 0f;
2703 m_log.DebugFormat("[axislock]: <{0},{1},{2}>", axis.X, axis.Y, axis.Z);
2704 m_taintAngularLock = axis;
2705 }
2706 else
2707 {
2708 m_log.WarnFormat("[PHYSICS]: Got NaN locking axis from Scene on Object {0}", Name);
2709 }
2710 }
2711
2712 internal void UpdatePositionAndVelocity()
2713 {
2714 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
2715 if (_parent == null)
2716 {
2717 Vector3 pv = Vector3.Zero;
2718 bool lastZeroFlag = _zeroFlag;
2719 float m_minvelocity = 0;
2720 if (Body != (IntPtr)0) // FIXME -> or if it is a joint
2721 {
2722 d.Vector3 vec = d.BodyGetPosition(Body);
2723 d.Quaternion ori = d.BodyGetQuaternion(Body);
2724 d.Vector3 vel = d.BodyGetLinearVel(Body);
2725 d.Vector3 rotvel = d.BodyGetAngularVel(Body);
2726 d.Vector3 torque = d.BodyGetTorque(Body);
2727 _torque = new Vector3(torque.X, torque.Y, torque.Z);
2728 Vector3 l_position = Vector3.Zero;
2729 Quaternion l_orientation = Quaternion.Identity;
2730
2731 // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
2732 //if (vec.X < 0.0f) { vec.X = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2733 //if (vec.Y < 0.0f) { vec.Y = 0.0f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2734 //if (vec.X > 255.95f) { vec.X = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2735 //if (vec.Y > 255.95f) { vec.Y = 255.95f; if (Body != (IntPtr)0) d.BodySetAngularVel(Body, 0, 0, 0); }
2736
2737 m_lastposition = _position;
2738 m_lastorientation = _orientation;
2739
2740 l_position.X = vec.X;
2741 l_position.Y = vec.Y;
2742 l_position.Z = vec.Z;
2743 l_orientation.X = ori.X;
2744 l_orientation.Y = ori.Y;
2745 l_orientation.Z = ori.Z;
2746 l_orientation.W = ori.W;
2747
2748 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)
2749 {
2750 //base.RaiseOutOfBounds(l_position);
2751
2752 if (m_crossingfailures < _parent_scene.geomCrossingFailuresBeforeOutofbounds)
2753 {
2754 _position = l_position;
2755 //_parent_scene.remActivePrim(this);
2756 if (_parent == null)
2757 base.RequestPhysicsterseUpdate();
2758 return;
2759 }
2760 else
2761 {
2762 if (_parent == null)
2763 base.RaiseOutOfBounds(l_position);
2764 return;
2765 }
2766 }
2767
2768 if (l_position.Z < 0)
2769 {
2770 // This is so prim that get lost underground don't fall forever and suck up
2771 //
2772 // Sim resources and memory.
2773 // Disables the prim's movement physics....
2774 // It's a hack and will generate a console message if it fails.
2775
2776 //IsPhysical = false;
2777 if (_parent == null)
2778 base.RaiseOutOfBounds(_position);
2779
2780 _acceleration.X = 0;
2781 _acceleration.Y = 0;
2782 _acceleration.Z = 0;
2783
2784 _velocity.X = 0;
2785 _velocity.Y = 0;
2786 _velocity.Z = 0;
2787 m_rotationalVelocity.X = 0;
2788 m_rotationalVelocity.Y = 0;
2789 m_rotationalVelocity.Z = 0;
2790
2791 if (_parent == null)
2792 base.RequestPhysicsterseUpdate();
2793
2794 m_throttleUpdates = false;
2795 throttleCounter = 0;
2796 _zeroFlag = true;
2797 //outofBounds = true;
2798 }
2799
2800 //float Adiff = 1.0f - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation));
2801//Console.WriteLine("Adiff " + Name + " = " + Adiff);
2802 if ((Math.Abs(m_lastposition.X - l_position.X) < 0.02)
2803 && (Math.Abs(m_lastposition.Y - l_position.Y) < 0.02)
2804 && (Math.Abs(m_lastposition.Z - l_position.Z) < 0.02)
2805// && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.01))
2806 && (1.0 - Math.Abs(Quaternion.Dot(m_lastorientation, l_orientation)) < 0.0001)) // KF 0.01 is far to large
2807 {
2808 _zeroFlag = true;
2809//Console.WriteLine("ZFT 2");
2810 m_throttleUpdates = false;
2811 }
2812 else
2813 {
2814 //m_log.Debug(Math.Abs(m_lastposition.X - l_position.X).ToString());
2815 _zeroFlag = false;
2816 m_lastUpdateSent = false;
2817 //m_throttleUpdates = false;
2818 }
2819
2820 if (_zeroFlag)
2821 {
2822 _velocity.X = 0.0f;
2823 _velocity.Y = 0.0f;
2824 _velocity.Z = 0.0f;
2825
2826 _acceleration.X = 0;
2827 _acceleration.Y = 0;
2828 _acceleration.Z = 0;
2829
2830 //_orientation.w = 0f;
2831 //_orientation.X = 0f;
2832 //_orientation.Y = 0f;
2833 //_orientation.Z = 0f;
2834 m_rotationalVelocity.X = 0;
2835 m_rotationalVelocity.Y = 0;
2836 m_rotationalVelocity.Z = 0;
2837 if (!m_lastUpdateSent)
2838 {
2839 m_throttleUpdates = false;
2840 throttleCounter = 0;
2841 m_rotationalVelocity = pv;
2842
2843 if (_parent == null)
2844 {
2845 base.RequestPhysicsterseUpdate();
2846 }
2847
2848 m_lastUpdateSent = true;
2849 }
2850 }
2851 else
2852 {
2853 if (lastZeroFlag != _zeroFlag)
2854 {
2855 if (_parent == null)
2856 {
2857 base.RequestPhysicsterseUpdate();
2858 }
2859 }
2860
2861 m_lastVelocity = _velocity;
2862
2863 _position = l_position;
2864
2865 _velocity.X = vel.X;
2866 _velocity.Y = vel.Y;
2867 _velocity.Z = vel.Z;
2868
2869 _acceleration = ((_velocity - m_lastVelocity) / 0.1f);
2870 _acceleration = new Vector3(_velocity.X - m_lastVelocity.X / 0.1f, _velocity.Y - m_lastVelocity.Y / 0.1f, _velocity.Z - m_lastVelocity.Z / 0.1f);
2871 //m_log.Info("[PHYSICS]: V1: " + _velocity + " V2: " + m_lastVelocity + " Acceleration: " + _acceleration.ToString());
2872
2873 // Note here that linearvelocity is affecting angular velocity... so I'm guessing this is a vehicle specific thing...
2874 // it does make sense to do this for tiny little instabilities with physical prim, however 0.5m/frame is fairly large.
2875 // 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
2876 // adding these logical exclusion situations to maintain this where I think it was intended to be.
2877 if (m_throttleUpdates || PIDActive || (m_vehicle != null && m_vehicle.Type != Vehicle.TYPE_NONE) || (Amotor != IntPtr.Zero))
2878 {
2879 m_minvelocity = 0.5f;
2880 }
2881 else
2882 {
2883 m_minvelocity = 0.02f;
2884 }
2885
2886 if (_velocity.ApproxEquals(pv, m_minvelocity))
2887 {
2888 m_rotationalVelocity = pv;
2889 }
2890 else
2891 {
2892 m_rotationalVelocity = new Vector3(rotvel.X, rotvel.Y, rotvel.Z);
2893 }
2894
2895 //m_log.Debug("ODE: " + m_rotationalVelocity.ToString());
2896 _orientation.X = ori.X;
2897 _orientation.Y = ori.Y;
2898 _orientation.Z = ori.Z;
2899 _orientation.W = ori.W;
2900 m_lastUpdateSent = false;
2901 if (!m_throttleUpdates || throttleCounter > _parent_scene.geomUpdatesPerThrottledUpdate)
2902 {
2903 if (_parent == null)
2904 {
2905 base.RequestPhysicsterseUpdate();
2906 }
2907 }
2908 else
2909 {
2910 throttleCounter++;
2911 }
2912 }
2913 m_lastposition = l_position;
2914 }
2915 else
2916 {
2917 // Not a body.. so Make sure the client isn't interpolating
2918 _velocity.X = 0;
2919 _velocity.Y = 0;
2920 _velocity.Z = 0;
2921
2922 _acceleration.X = 0;
2923 _acceleration.Y = 0;
2924 _acceleration.Z = 0;
2925
2926 m_rotationalVelocity.X = 0;
2927 m_rotationalVelocity.Y = 0;
2928 m_rotationalVelocity.Z = 0;
2929 _zeroFlag = true;
2930 }
2931 }
2932 }
2933
2934 public override bool FloatOnWater
2935 {
2936 set {
2937 m_taintCollidesWater = value;
2938 _parent_scene.AddPhysicsActorTaint(this);
2939 }
2940 }
2941
2942 public override void SetMomentum(Vector3 momentum)
2943 {
2944 }
2945
2946 public override Vector3 PIDTarget
2947 {
2948 set
2949 {
2950 if (value.IsFinite())
2951 {
2952 m_PIDTarget = value;
2953 }
2954 else
2955 m_log.WarnFormat("[PHYSICS]: Got NaN PIDTarget from Scene on Object {0}", Name);
2956 }
2957 }
2958 public override bool PIDActive { get; set; }
2959 public override float PIDTau { set { m_PIDTau = value; } }
2960
2961 public override float PIDHoverHeight { set { m_PIDHoverHeight = value; ; } }
2962 public override bool PIDHoverActive { set { m_useHoverPID = value; } }
2963 public override PIDHoverType PIDHoverType { set { m_PIDHoverType = value; } }
2964 public override float PIDHoverTau { set { m_PIDHoverTau = value; } }
2965
2966 public override Quaternion APIDTarget{ set { return; } }
2967
2968 public override bool APIDActive{ set { return; } }
2969
2970 public override float APIDStrength{ set { return; } }
2971
2972 public override float APIDDamping{ set { return; } }
2973
2974 private void createAMotor(Vector3 axis)
2975 {
2976 if (Body == IntPtr.Zero)
2977 return;
2978
2979 if (Amotor != IntPtr.Zero)
2980 {
2981 d.JointDestroy(Amotor);
2982 Amotor = IntPtr.Zero;
2983 }
2984
2985 float axisnum = 3;
2986
2987 axisnum = (axisnum - (axis.X + axis.Y + axis.Z));
2988
2989 // PhysicsVector totalSize = new PhysicsVector(_size.X, _size.Y, _size.Z);
2990
2991
2992 // Inverse Inertia Matrix, set the X, Y, and/r Z inertia to 0 then invert it again.
2993 d.Mass objMass;
2994 d.MassSetZero(out objMass);
2995 DMassCopy(ref pMass, ref objMass);
2996
2997 //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);
2998
2999 Matrix4 dMassMat = FromDMass(objMass);
3000
3001 Matrix4 mathmat = Inverse(dMassMat);
3002
3003 /*
3004 //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]);
3005
3006 mathmat = Inverse(mathmat);
3007
3008
3009 objMass = FromMatrix4(mathmat, ref objMass);
3010 //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);
3011
3012 mathmat = Inverse(mathmat);
3013 */
3014 if (axis.X == 0)
3015 {
3016 mathmat.M33 = 50.0000001f;
3017 //objMass.I.M22 = 0;
3018 }
3019 if (axis.Y == 0)
3020 {
3021 mathmat.M22 = 50.0000001f;
3022 //objMass.I.M11 = 0;
3023 }
3024 if (axis.Z == 0)
3025 {
3026 mathmat.M11 = 50.0000001f;
3027 //objMass.I.M00 = 0;
3028 }
3029
3030
3031
3032 mathmat = Inverse(mathmat);
3033 objMass = FromMatrix4(mathmat, ref objMass);
3034 //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);
3035
3036 //return;
3037 if (d.MassCheck(ref objMass))
3038 {
3039 d.BodySetMass(Body, ref objMass);
3040 }
3041 else
3042 {
3043 //m_log.Debug("[PHYSICS]: Mass invalid, ignoring");
3044 }
3045
3046 if (axisnum <= 0)
3047 return;
3048 // int dAMotorEuler = 1;
3049
3050 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
3051 d.JointAttach(Amotor, Body, IntPtr.Zero);
3052 d.JointSetAMotorMode(Amotor, 0);
3053
3054 d.JointSetAMotorNumAxes(Amotor,(int)axisnum);
3055 int i = 0;
3056
3057 if (axis.X == 0)
3058 {
3059 d.JointSetAMotorAxis(Amotor, i, 0, 1, 0, 0);
3060 i++;
3061 }
3062
3063 if (axis.Y == 0)
3064 {
3065 d.JointSetAMotorAxis(Amotor, i, 0, 0, 1, 0);
3066 i++;
3067 }
3068
3069 if (axis.Z == 0)
3070 {
3071 d.JointSetAMotorAxis(Amotor, i, 0, 0, 0, 1);
3072 i++;
3073 }
3074
3075 for (int j = 0; j < (int)axisnum; j++)
3076 {
3077 //d.JointSetAMotorAngle(Amotor, j, 0);
3078 }
3079
3080 //d.JointSetAMotorAngle(Amotor, 1, 0);
3081 //d.JointSetAMotorAngle(Amotor, 2, 0);
3082
3083 // These lowstops and high stops are effectively (no wiggle room)
3084 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0f);
3085 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f);
3086 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0f);
3087 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0f);
3088 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f);
3089 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0f);
3090 //d.JointSetAMotorParam(Amotor, (int) dParam.Vel, 9000f);
3091 d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
3092 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, Mass * 50f);//
3093 }
3094
3095 private Matrix4 FromDMass(d.Mass pMass)
3096 {
3097 Matrix4 obj;
3098 obj.M11 = pMass.I.M00;
3099 obj.M12 = pMass.I.M01;
3100 obj.M13 = pMass.I.M02;
3101 obj.M14 = 0;
3102 obj.M21 = pMass.I.M10;
3103 obj.M22 = pMass.I.M11;
3104 obj.M23 = pMass.I.M12;
3105 obj.M24 = 0;
3106 obj.M31 = pMass.I.M20;
3107 obj.M32 = pMass.I.M21;
3108 obj.M33 = pMass.I.M22;
3109 obj.M34 = 0;
3110 obj.M41 = 0;
3111 obj.M42 = 0;
3112 obj.M43 = 0;
3113 obj.M44 = 1;
3114 return obj;
3115 }
3116
3117 private d.Mass FromMatrix4(Matrix4 pMat, ref d.Mass obj)
3118 {
3119 obj.I.M00 = pMat[0, 0];
3120 obj.I.M01 = pMat[0, 1];
3121 obj.I.M02 = pMat[0, 2];
3122 obj.I.M10 = pMat[1, 0];
3123 obj.I.M11 = pMat[1, 1];
3124 obj.I.M12 = pMat[1, 2];
3125 obj.I.M20 = pMat[2, 0];
3126 obj.I.M21 = pMat[2, 1];
3127 obj.I.M22 = pMat[2, 2];
3128 return obj;
3129 }
3130
3131 public override void SubscribeEvents(int ms)
3132 {
3133 m_eventsubscription = ms;
3134 _parent_scene.AddCollisionEventReporting(this);
3135 }
3136
3137 public override void UnSubscribeEvents()
3138 {
3139 _parent_scene.RemoveCollisionEventReporting(this);
3140 m_eventsubscription = 0;
3141 }
3142
3143 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
3144 {
3145 CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
3146 }
3147
3148 public void SendCollisions()
3149 {
3150 if (m_collisionsOnPreviousFrame || CollisionEventsThisFrame.Count > 0)
3151 {
3152 base.SendCollisionUpdate(CollisionEventsThisFrame);
3153
3154 if (CollisionEventsThisFrame.Count > 0)
3155 {
3156 m_collisionsOnPreviousFrame = true;
3157 CollisionEventsThisFrame.Clear();
3158 }
3159 else
3160 {
3161 m_collisionsOnPreviousFrame = false;
3162 }
3163 }
3164 }
3165
3166 public override bool SubscribedEvents()
3167 {
3168 if (m_eventsubscription > 0)
3169 return true;
3170 return false;
3171 }
3172
3173 public static Matrix4 Inverse(Matrix4 pMat)
3174 {
3175 if (determinant3x3(pMat) == 0)
3176 {
3177 return Matrix4.Identity; // should probably throw an error. singluar matrix inverse not possible
3178 }
3179
3180 return (Adjoint(pMat) / determinant3x3(pMat));
3181 }
3182
3183 public static Matrix4 Adjoint(Matrix4 pMat)
3184 {
3185 Matrix4 adjointMatrix = new Matrix4();
3186 for (int i=0; i<4; i++)
3187 {
3188 for (int j=0; j<4; j++)
3189 {
3190 Matrix4SetValue(ref adjointMatrix, i, j, (float)(Math.Pow(-1, i + j) * (determinant3x3(Minor(pMat, i, j)))));
3191 }
3192 }
3193
3194 adjointMatrix = Transpose(adjointMatrix);
3195 return adjointMatrix;
3196 }
3197
3198 public static Matrix4 Minor(Matrix4 matrix, int iRow, int iCol)
3199 {
3200 Matrix4 minor = new Matrix4();
3201 int m = 0, n = 0;
3202 for (int i = 0; i < 4; i++)
3203 {
3204 if (i == iRow)
3205 continue;
3206 n = 0;
3207 for (int j = 0; j < 4; j++)
3208 {
3209 if (j == iCol)
3210 continue;
3211 Matrix4SetValue(ref minor, m,n, matrix[i, j]);
3212 n++;
3213 }
3214 m++;
3215 }
3216
3217 return minor;
3218 }
3219
3220 public static Matrix4 Transpose(Matrix4 pMat)
3221 {
3222 Matrix4 transposeMatrix = new Matrix4();
3223 for (int i = 0; i < 4; i++)
3224 for (int j = 0; j < 4; j++)
3225 Matrix4SetValue(ref transposeMatrix, i, j, pMat[j, i]);
3226 return transposeMatrix;
3227 }
3228
3229 public static void Matrix4SetValue(ref Matrix4 pMat, int r, int c, float val)
3230 {
3231 switch (r)
3232 {
3233 case 0:
3234 switch (c)
3235 {
3236 case 0:
3237 pMat.M11 = val;
3238 break;
3239 case 1:
3240 pMat.M12 = val;
3241 break;
3242 case 2:
3243 pMat.M13 = val;
3244 break;
3245 case 3:
3246 pMat.M14 = val;
3247 break;
3248 }
3249
3250 break;
3251 case 1:
3252 switch (c)
3253 {
3254 case 0:
3255 pMat.M21 = val;
3256 break;
3257 case 1:
3258 pMat.M22 = val;
3259 break;
3260 case 2:
3261 pMat.M23 = val;
3262 break;
3263 case 3:
3264 pMat.M24 = val;
3265 break;
3266 }
3267
3268 break;
3269 case 2:
3270 switch (c)
3271 {
3272 case 0:
3273 pMat.M31 = val;
3274 break;
3275 case 1:
3276 pMat.M32 = val;
3277 break;
3278 case 2:
3279 pMat.M33 = val;
3280 break;
3281 case 3:
3282 pMat.M34 = val;
3283 break;
3284 }
3285
3286 break;
3287 case 3:
3288 switch (c)
3289 {
3290 case 0:
3291 pMat.M41 = val;
3292 break;
3293 case 1:
3294 pMat.M42 = val;
3295 break;
3296 case 2:
3297 pMat.M43 = val;
3298 break;
3299 case 3:
3300 pMat.M44 = val;
3301 break;
3302 }
3303
3304 break;
3305 }
3306 }
3307
3308 private static float determinant3x3(Matrix4 pMat)
3309 {
3310 float det = 0;
3311 float diag1 = pMat[0, 0]*pMat[1, 1]*pMat[2, 2];
3312 float diag2 = pMat[0, 1]*pMat[2, 1]*pMat[2, 0];
3313 float diag3 = pMat[0, 2]*pMat[1, 0]*pMat[2, 1];
3314 float diag4 = pMat[2, 0]*pMat[1, 1]*pMat[0, 2];
3315 float diag5 = pMat[2, 1]*pMat[1, 2]*pMat[0, 0];
3316 float diag6 = pMat[2, 2]*pMat[1, 0]*pMat[0, 1];
3317
3318 det = diag1 + diag2 + diag3 - (diag4 + diag5 + diag6);
3319 return det;
3320 }
3321
3322 private static void DMassCopy(ref d.Mass src, ref d.Mass dst)
3323 {
3324 dst.c.W = src.c.W;
3325 dst.c.X = src.c.X;
3326 dst.c.Y = src.c.Y;
3327 dst.c.Z = src.c.Z;
3328 dst.mass = src.mass;
3329 dst.I.M00 = src.I.M00;
3330 dst.I.M01 = src.I.M01;
3331 dst.I.M02 = src.I.M02;
3332 dst.I.M10 = src.I.M10;
3333 dst.I.M11 = src.I.M11;
3334 dst.I.M12 = src.I.M12;
3335 dst.I.M20 = src.I.M20;
3336 dst.I.M21 = src.I.M21;
3337 dst.I.M22 = src.I.M22;
3338 }
3339
3340 public override void SetMaterial(int pMaterial)
3341 {
3342 m_material = pMaterial;
3343 }
3344
3345 private void CheckMeshAsset()
3346 {
3347 if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero)
3348 {
3349 m_assetFailed = true;
3350 Util.FireAndForget(delegate
3351 {
3352 RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod;
3353 if (assetProvider != null)
3354 assetProvider(_pbs.SculptTexture, MeshAssetReceived);
3355 }, null, "ODEPrim.CheckMeshAsset");
3356 }
3357 }
3358
3359 private void MeshAssetReceived(AssetBase asset)
3360 {
3361 if (asset != null && asset.Data != null && asset.Data.Length > 0)
3362 {
3363 if (!_pbs.SculptEntry)
3364 return;
3365 if (_pbs.SculptTexture.ToString() != asset.ID)
3366 return;
3367
3368 _pbs.SculptData = new byte[asset.Data.Length];
3369 asset.Data.CopyTo(_pbs.SculptData, 0);
3370// m_assetFailed = false;
3371
3372// m_log.DebugFormat(
3373// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
3374// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
3375
3376 m_taintshape = true;
3377 _parent_scene.AddPhysicsActorTaint(this);
3378 }
3379 else
3380 {
3381 m_log.WarnFormat(
3382 "[ODE PRIM]: Could not get mesh/sculpt asset {0} for {1} at {2} in {3}",
3383 _pbs.SculptTexture, Name, _position, _parent_scene.Name);
3384 }
3385 }
3386 }
3387} \ 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..8d7d3b3
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs
@@ -0,0 +1,434 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using System.Text;
33using OpenMetaverse;
34using OpenSim.Region.Physics.Manager;
35using Ode.NET;
36using log4net;
37
38namespace OpenSim.Region.Physics.OdePlugin
39{
40 /// <summary>
41 /// Processes raycast requests as ODE is in a state to be able to do them.
42 /// This ensures that it's thread safe and there will be no conflicts.
43 /// Requests get returned by a different thread then they were requested by.
44 /// </summary>
45 public class ODERayCastRequestManager
46 {
47 /// <summary>
48 /// Pending raycast requests
49 /// </summary>
50 protected List<ODERayCastRequest> m_PendingRequests = new List<ODERayCastRequest>();
51
52 /// <summary>
53 /// Pending ray requests
54 /// </summary>
55 protected List<ODERayRequest> m_PendingRayRequests = new List<ODERayRequest>();
56
57 /// <summary>
58 /// Scene that created this object.
59 /// </summary>
60 private OdeScene m_scene;
61
62 /// <summary>
63 /// ODE contact array to be filled by the collision testing
64 /// </summary>
65 d.ContactGeom[] contacts = new d.ContactGeom[5];
66
67 /// <summary>
68 /// ODE near callback delegate
69 /// </summary>
70 private d.NearCallback nearCallback;
71 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
72 private List<ContactResult> m_contactResults = new List<ContactResult>();
73
74
75 public ODERayCastRequestManager(OdeScene pScene)
76 {
77 m_scene = pScene;
78 nearCallback = near;
79
80 }
81
82 /// <summary>
83 /// Queues a raycast
84 /// </summary>
85 /// <param name="position">Origin of Ray</param>
86 /// <param name="direction">Ray normal</param>
87 /// <param name="length">Ray length</param>
88 /// <param name="retMethod">Return method to send the results</param>
89 public void QueueRequest(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
90 {
91 lock (m_PendingRequests)
92 {
93 ODERayCastRequest req = new ODERayCastRequest();
94 req.callbackMethod = retMethod;
95 req.length = length;
96 req.Normal = direction;
97 req.Origin = position;
98
99 m_PendingRequests.Add(req);
100 }
101 }
102
103 /// <summary>
104 /// Queues a raycast
105 /// </summary>
106 /// <param name="position">Origin of Ray</param>
107 /// <param name="direction">Ray normal</param>
108 /// <param name="length">Ray length</param>
109 /// <param name="count"></param>
110 /// <param name="retMethod">Return method to send the results</param>
111 public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod)
112 {
113 lock (m_PendingRequests)
114 {
115 ODERayRequest req = new ODERayRequest();
116 req.callbackMethod = retMethod;
117 req.length = length;
118 req.Normal = direction;
119 req.Origin = position;
120 req.Count = count;
121
122 m_PendingRayRequests.Add(req);
123 }
124 }
125
126 /// <summary>
127 /// Process all queued raycast requests
128 /// </summary>
129 /// <returns>Time in MS the raycasts took to process.</returns>
130 public int ProcessQueuedRequests()
131 {
132 int time = System.Environment.TickCount;
133 lock (m_PendingRequests)
134 {
135 if (m_PendingRequests.Count > 0)
136 {
137 ODERayCastRequest[] reqs = m_PendingRequests.ToArray();
138 for (int i = 0; i < reqs.Length; i++)
139 {
140 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
141 RayCast(reqs[i]); // if there isn't anyone to send results
142 }
143
144 m_PendingRequests.Clear();
145 }
146 }
147
148 lock (m_PendingRayRequests)
149 {
150 if (m_PendingRayRequests.Count > 0)
151 {
152 ODERayRequest[] reqs = m_PendingRayRequests.ToArray();
153 for (int i = 0; i < reqs.Length; i++)
154 {
155 if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast
156 RayCast(reqs[i]); // if there isn't anyone to send results
157 }
158
159 m_PendingRayRequests.Clear();
160 }
161 }
162
163 lock (m_contactResults)
164 m_contactResults.Clear();
165
166 return System.Environment.TickCount - time;
167 }
168
169 /// <summary>
170 /// Method that actually initiates the raycast
171 /// </summary>
172 /// <param name="req"></param>
173 private void RayCast(ODERayCastRequest req)
174 {
175 // Create the ray
176 IntPtr ray = d.CreateRay(m_scene.space, req.length);
177 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
178
179 // Collide test
180 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
181
182 // Remove Ray
183 d.GeomDestroy(ray);
184
185 // Define default results
186 bool hitYN = false;
187 uint hitConsumerID = 0;
188 float distance = 999999999999f;
189 Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
190 Vector3 snormal = Vector3.Zero;
191
192 // Find closest contact and object.
193 lock (m_contactResults)
194 {
195 foreach (ContactResult cResult in m_contactResults)
196 {
197 if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
198 {
199 closestcontact = cResult.Pos;
200 hitConsumerID = cResult.ConsumerID;
201 distance = cResult.Depth;
202 hitYN = true;
203 snormal = cResult.Normal;
204 }
205 }
206
207 m_contactResults.Clear();
208 }
209
210 // Return results
211 if (req.callbackMethod != null)
212 req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal);
213 }
214
215 /// <summary>
216 /// Method that actually initiates the raycast
217 /// </summary>
218 /// <param name="req"></param>
219 private void RayCast(ODERayRequest req)
220 {
221 // Create the ray
222 IntPtr ray = d.CreateRay(m_scene.space, req.length);
223 d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
224
225 // Collide test
226 d.SpaceCollide2(m_scene.space, ray, IntPtr.Zero, nearCallback);
227
228 // Remove Ray
229 d.GeomDestroy(ray);
230
231 // Find closest contact and object.
232 lock (m_contactResults)
233 {
234 // Return results
235 if (req.callbackMethod != null)
236 req.callbackMethod(m_contactResults);
237 }
238 }
239
240 // This is the standard Near. Uses space AABBs to speed up detection.
241 private void near(IntPtr space, IntPtr g1, IntPtr g2)
242 {
243
244 //Don't test against heightfield Geom, or you'll be sorry!
245
246 /*
247 terminate called after throwing an instance of 'std::bad_alloc'
248 what(): std::bad_alloc
249 Stacktrace:
250
251 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0x00004>
252 at (wrapper managed-to-native) Ode.NET.d.Collide (intptr,intptr,int,Ode.NET.d/ContactGeom[],int) <0xffffffff>
253 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0x00280>
254 at (wrapper native-to-managed) OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.near (intptr,intptr,intptr) <0xfff
255 fffff>
256 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0x00004>
257 at (wrapper managed-to-native) Ode.NET.d.SpaceCollide2 (intptr,intptr,intptr,Ode.NET.d/NearCallback) <0xffffffff>
258 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.RayCast (OpenSim.Region.Physics.OdePlugin.ODERayCastRequest) <
259 0x00114>
260 at OpenSim.Region.Physics.OdePlugin.ODERayCastRequestManager.ProcessQueuedRequests () <0x000eb>
261 at OpenSim.Region.Physics.OdePlugin.OdeScene.Simulate (single) <0x017e6>
262 at OpenSim.Region.Framework.Scenes.SceneGraph.UpdatePhysics (double) <0x00042>
263 at OpenSim.Region.Framework.Scenes.Scene.Update () <0x0039e>
264 at OpenSim.Region.Framework.Scenes.Scene.Heartbeat (object) <0x00019>
265 at (wrapper runtime-invoke) object.runtime_invoke_void__this___object (object,intptr,intptr,intptr) <0xffffffff>
266
267 Native stacktrace:
268
269 mono [0x80d2a42]
270 [0xb7f5840c]
271 /lib/i686/cmov/libc.so.6(abort+0x188) [0xb7d1a018]
272 /usr/lib/libstdc++.so.6(_ZN9__gnu_cxx27__verbose_terminate_handlerEv+0x158) [0xb45fc988]
273 /usr/lib/libstdc++.so.6 [0xb45fa865]
274 /usr/lib/libstdc++.so.6 [0xb45fa8a2]
275 /usr/lib/libstdc++.so.6 [0xb45fa9da]
276 /usr/lib/libstdc++.so.6(_Znwj+0x83) [0xb45fb033]
277 /usr/lib/libstdc++.so.6(_Znaj+0x1d) [0xb45fb11d]
278 libode.so(_ZN13dxHeightfield23dCollideHeightfieldZoneEiiiiP6dxGeomiiP12dContactGeomi+0xd04) [0xb46678e4]
279 libode.so(_Z19dCollideHeightfieldP6dxGeomS0_iP12dContactGeomi+0x54b) [0xb466832b]
280 libode.so(dCollide+0x102) [0xb46571b2]
281 [0x95cfdec9]
282 [0x8ea07fe1]
283 [0xab260146]
284 libode.so [0xb465a5c4]
285 libode.so(_ZN11dxHashSpace8collide2EPvP6dxGeomPFvS0_S2_S2_E+0x75) [0xb465bcf5]
286 libode.so(dSpaceCollide2+0x177) [0xb465ac67]
287 [0x95cf978e]
288 [0x8ea07945]
289 [0x95cf2bbc]
290 [0xab2787e7]
291 [0xab419fb3]
292 [0xab416657]
293 [0xab415bda]
294 [0xb609b08e]
295 mono(mono_runtime_delegate_invoke+0x34) [0x8192534]
296 mono [0x81a2f0f]
297 mono [0x81d28b6]
298 mono [0x81ea2c6]
299 /lib/i686/cmov/libpthread.so.0 [0xb7e744c0]
300 /lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7dcd6de]
301 */
302
303 // Exclude heightfield geom
304
305 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
306 return;
307 if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass || d.GeomGetClass(g2) == d.GeomClassID.HeightfieldClass)
308 return;
309
310 // Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
311 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
312 {
313 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
314 return;
315
316 // Separating static prim geometry spaces.
317 // We'll be calling near recursivly if one
318 // of them is a space to find all of the
319 // contact points in the space
320 try
321 {
322 d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
323 }
324 catch (AccessViolationException)
325 {
326 m_log.Warn("[PHYSICS]: Unable to collide test a space");
327 return;
328 }
329 //Colliding a space or a geom with a space or a geom. so drill down
330
331 //Collide all geoms in each space..
332 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
333 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
334 return;
335 }
336
337 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
338 return;
339
340 int count = 0;
341 try
342 {
343
344 if (g1 == g2)
345 return; // Can't collide with yourself
346
347 lock (contacts)
348 {
349 count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
350 }
351 }
352 catch (SEHException)
353 {
354 m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
355 }
356 catch (Exception e)
357 {
358 m_log.WarnFormat("[PHYSICS]: Unable to collide test an object: {0}", e.Message);
359 return;
360 }
361
362 PhysicsActor p1 = null;
363 PhysicsActor p2 = null;
364
365 if (g1 != IntPtr.Zero)
366 m_scene.actor_name_map.TryGetValue(g1, out p1);
367
368 if (g2 != IntPtr.Zero)
369 m_scene.actor_name_map.TryGetValue(g1, out p2);
370
371 // Loop over contacts, build results.
372 for (int i = 0; i < count; i++)
373 {
374 if (p1 != null)
375 {
376 if (p1 is OdePrim)
377 {
378 ContactResult collisionresult = new ContactResult();
379
380 collisionresult.ConsumerID = p1.LocalID;
381 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
382 collisionresult.Depth = contacts[i].depth;
383 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
384 contacts[i].normal.Z);
385 lock (m_contactResults)
386 m_contactResults.Add(collisionresult);
387 }
388 }
389
390 if (p2 != null)
391 {
392 if (p2 is OdePrim)
393 {
394 ContactResult collisionresult = new ContactResult();
395
396 collisionresult.ConsumerID = p2.LocalID;
397 collisionresult.Pos = new Vector3(contacts[i].pos.X, contacts[i].pos.Y, contacts[i].pos.Z);
398 collisionresult.Depth = contacts[i].depth;
399 collisionresult.Normal = new Vector3(contacts[i].normal.X, contacts[i].normal.Y,
400 contacts[i].normal.Z);
401
402 lock (m_contactResults)
403 m_contactResults.Add(collisionresult);
404 }
405 }
406 }
407 }
408
409 /// <summary>
410 /// Dereference the creator scene so that it can be garbage collected if needed.
411 /// </summary>
412 internal void Dispose()
413 {
414 m_scene = null;
415 }
416 }
417
418 public struct ODERayCastRequest
419 {
420 public Vector3 Origin;
421 public Vector3 Normal;
422 public float length;
423 public RaycastCallback callbackMethod;
424 }
425
426 public struct ODERayRequest
427 {
428 public Vector3 Origin;
429 public Vector3 Normal;
430 public int Count;
431 public float length;
432 public RayCallback callbackMethod;
433 }
434} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs b/OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs
new file mode 100644
index 0000000..b4a3c48
--- /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.Physics.Manager;
33using OpenSim.Region.Physics.OdePlugin;
34
35namespace OpenSim.Region.Physics.OdePlugin
36{
37 class OdePhysicsJoint : PhysicsJoint
38 {
39 public override bool IsInPhysicsEngine
40 {
41 get
42 {
43 return (jointID != IntPtr.Zero);
44 }
45 }
46 public IntPtr jointID;
47 }
48}
diff --git a/OpenSim/Region/PhysicsModules/Ode/OdePlugin.cs b/OpenSim/Region/PhysicsModules/Ode/OdePlugin.cs
new file mode 100644
index 0000000..7e652fc
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/OdePlugin.cs
@@ -0,0 +1,90 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using System.Threading;
33using System.IO;
34using System.Diagnostics;
35using log4net;
36using Nini.Config;
37using Ode.NET;
38using OpenSim.Framework;
39using OpenSim.Region.Physics.Manager;
40using OpenMetaverse;
41
42namespace OpenSim.Region.Physics.OdePlugin
43{
44 /// <summary>
45 /// ODE plugin
46 /// </summary>
47 public class OdePlugin : IPhysicsPlugin
48 {
49// private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
50
51 private OdeScene m_scene;
52
53 public bool Init()
54 {
55 return true;
56 }
57
58 public PhysicsScene GetScene(String sceneIdentifier)
59 {
60 if (m_scene == null)
61 {
62 // We do this so that OpenSimulator on Windows loads the correct native ODE library depending on whether
63 // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports
64 // will find it already loaded later on.
65 //
66 // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be
67 // controlled in Ode.NET.dll.config
68 if (Util.IsWindows())
69 Util.LoadArchSpecificWindowsDll("ode.dll");
70
71 // Initializing ODE only when a scene is created allows alternative ODE plugins to co-habit (according to
72 // http://opensimulator.org/mantis/view.php?id=2750).
73 d.InitODE();
74
75 m_scene = new OdeScene(GetName(), sceneIdentifier);
76 }
77
78 return m_scene;
79 }
80
81 public string GetName()
82 {
83 return ("OpenDynamicsEngine");
84 }
85
86 public void Dispose()
87 {
88 }
89 }
90} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs
new file mode 100644
index 0000000..5953557
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/OdeScene.cs
@@ -0,0 +1,4319 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28//#define USE_DRAWSTUFF
29//#define SPAM
30
31using System;
32using System.Collections.Generic;
33using System.Diagnostics;
34using System.IO;
35using System.Linq;
36using System.Reflection;
37using System.Runtime.InteropServices;
38using System.Threading;
39using log4net;
40using Nini.Config;
41using Ode.NET;
42using OpenMetaverse;
43#if USE_DRAWSTUFF
44using Drawstuff.NET;
45#endif
46using OpenSim.Framework;
47using OpenSim.Region.Physics.Manager;
48
49namespace OpenSim.Region.Physics.OdePlugin
50{
51 public enum StatusIndicators : int
52 {
53 Generic = 0,
54 Start = 1,
55 End = 2
56 }
57
58// public struct sCollisionData
59// {
60// public uint ColliderLocalId;
61// public uint CollidedWithLocalId;
62// public int NumberOfCollisions;
63// public int CollisionType;
64// public int StatusIndicator;
65// public int lastframe;
66// }
67
68 [Flags]
69 public enum CollisionCategories : int
70 {
71 Disabled = 0,
72 Geom = 0x00000001,
73 Body = 0x00000002,
74 Space = 0x00000004,
75 Character = 0x00000008,
76 Land = 0x00000010,
77 Water = 0x00000020,
78 Wind = 0x00000040,
79 Sensor = 0x00000080,
80 Selected = 0x00000100
81 }
82
83 /// <summary>
84 /// Material type for a primitive
85 /// </summary>
86 public enum Material : int
87 {
88 /// <summary></summary>
89 Stone = 0,
90 /// <summary></summary>
91 Metal = 1,
92 /// <summary></summary>
93 Glass = 2,
94 /// <summary></summary>
95 Wood = 3,
96 /// <summary></summary>
97 Flesh = 4,
98 /// <summary></summary>
99 Plastic = 5,
100 /// <summary></summary>
101 Rubber = 6
102 }
103
104 public class OdeScene : PhysicsScene
105 {
106 private readonly ILog m_log;
107 // private Dictionary<string, sCollisionData> m_storedCollisions = new Dictionary<string, sCollisionData>();
108
109 /// <summary>
110 /// Provide a sync object so that only one thread calls d.Collide() at a time across all OdeScene instances.
111 /// </summary>
112 /// <remarks>
113 /// With ODE as of r1755 (though also tested on r1860), only one thread can call d.Collide() at a
114 /// time, even where physics objects are in entirely different ODE worlds. This is because generating contacts
115 /// uses a static cache at the ODE level.
116 ///
117 /// Without locking, simulators running multiple regions will eventually crash with a native stack trace similar
118 /// to
119 ///
120 /// mono() [0x489171]
121 /// mono() [0x4d154f]
122 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f6ded592c60]
123 /// .../opensim/bin/libode-x86_64.so(_ZN6Opcode11OBBCollider8_CollideEPKNS_14AABBNoLeafNodeE+0xd7a) [0x7f6dd822628a]
124 ///
125 /// ODE provides an experimental option to cache in thread local storage but compiling ODE with this option
126 /// causes OpenSimulator to immediately crash with a native stack trace similar to
127 ///
128 /// mono() [0x489171]
129 /// mono() [0x4d154f]
130 /// /lib/x86_64-linux-gnu/libpthread.so.0(+0xfc60) [0x7f03c9849c60]
131 /// .../opensim/bin/libode-x86_64.so(_Z12dCollideCCTLP6dxGeomS0_iP12dContactGeomi+0x92) [0x7f03b44bcf82]
132 /// </remarks>
133 internal static Object UniversalColliderSyncObject = new Object();
134
135 /// <summary>
136 /// Is stats collecting enabled for this ODE scene?
137 /// </summary>
138 public bool CollectStats { get; set; }
139
140 /// <summary>
141 /// Statistics for this scene.
142 /// </summary>
143 private Dictionary<string, float> m_stats = new Dictionary<string, float>();
144
145 /// <summary>
146 /// Stat name for total number of avatars in this ODE scene.
147 /// </summary>
148 public const string ODETotalAvatarsStatName = "ODETotalAvatars";
149
150 /// <summary>
151 /// Stat name for total number of prims in this ODE scene.
152 /// </summary>
153 public const string ODETotalPrimsStatName = "ODETotalPrims";
154
155 /// <summary>
156 /// Stat name for total number of prims with active physics in this ODE scene.
157 /// </summary>
158 public const string ODEActivePrimsStatName = "ODEActivePrims";
159
160 /// <summary>
161 /// Stat name for the total time spent in ODE frame processing.
162 /// </summary>
163 /// <remarks>
164 /// A sanity check for the main scene loop physics time.
165 /// </remarks>
166 public const string ODETotalFrameMsStatName = "ODETotalFrameMS";
167
168 /// <summary>
169 /// Stat name for time spent processing avatar taints per frame
170 /// </summary>
171 public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS";
172
173 /// <summary>
174 /// Stat name for time spent processing prim taints per frame
175 /// </summary>
176 public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS";
177
178 /// <summary>
179 /// Stat name for time spent calculating avatar forces per frame.
180 /// </summary>
181 public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS";
182
183 /// <summary>
184 /// Stat name for time spent calculating prim forces per frame
185 /// </summary>
186 public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS";
187
188 /// <summary>
189 /// Stat name for time spent fulfilling raycasting requests per frame
190 /// </summary>
191 public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS";
192
193 /// <summary>
194 /// Stat name for time spent in native code that actually steps through the simulation.
195 /// </summary>
196 public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS";
197
198 /// <summary>
199 /// Stat name for the number of milliseconds that ODE spends in native space collision code.
200 /// </summary>
201 public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS";
202
203 /// <summary>
204 /// Stat name for milliseconds that ODE spends in native geom collision code.
205 /// </summary>
206 public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS";
207
208 /// <summary>
209 /// Time spent in collision processing that is not spent in native space or geom collision code.
210 /// </summary>
211 public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS";
212
213 /// <summary>
214 /// Stat name for time spent notifying listeners of collisions
215 /// </summary>
216 public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS";
217
218 /// <summary>
219 /// Stat name for milliseconds spent updating avatar position and velocity
220 /// </summary>
221 public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS";
222
223 /// <summary>
224 /// Stat name for the milliseconds spent updating prim position and velocity
225 /// </summary>
226 public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS";
227
228 /// <summary>
229 /// Stat name for avatar collisions with another entity.
230 /// </summary>
231 public const string ODEAvatarContactsStatsName = "ODEAvatarContacts";
232
233 /// <summary>
234 /// Stat name for prim collisions with another entity.
235 /// </summary>
236 public const string ODEPrimContactsStatName = "ODEPrimContacts";
237
238 /// <summary>
239 /// Used to hold tick numbers for stat collection purposes.
240 /// </summary>
241 private int m_nativeCollisionStartTick;
242
243 /// <summary>
244 /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback.
245 /// </summary>
246 private bool m_inCollisionTiming;
247
248 /// <summary>
249 /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object
250 /// collisions occured using the _perloopcontact if stats collection is enabled.
251 /// </summary>
252 private int m_tempAvatarCollisionsThisFrame;
253
254 /// <summary>
255 /// Used in calculating physics frame time dilation
256 /// </summary>
257 private int tickCountFrameRun;
258
259 /// <summary>
260 /// Used in calculating physics frame time dilation
261 /// </summary>
262 private int latertickcount;
263
264 private Random fluidRandomizer = new Random(Environment.TickCount);
265
266 private const uint m_regionWidth = Constants.RegionSize;
267 private const uint m_regionHeight = Constants.RegionSize;
268
269 private float ODE_STEPSIZE = 0.0178f;
270 private float metersInSpace = 29.9f;
271 private float m_timeDilation = 1.0f;
272
273 public float gravityx = 0f;
274 public float gravityy = 0f;
275 public float gravityz = -9.8f;
276
277 public float AvatarTerminalVelocity { get; set; }
278
279 private float contactsurfacelayer = 0.001f;
280
281 private int worldHashspaceLow = -4;
282 private int worldHashspaceHigh = 128;
283
284 private int smallHashspaceLow = -4;
285 private int smallHashspaceHigh = 66;
286
287 private float waterlevel = 0f;
288 private int framecount = 0;
289 //private int m_returncollisions = 10;
290
291 private readonly IntPtr contactgroup;
292
293 internal IntPtr WaterGeom;
294
295 private float nmTerrainContactFriction = 255.0f;
296 private float nmTerrainContactBounce = 0.1f;
297 private float nmTerrainContactERP = 0.1025f;
298
299 private float mTerrainContactFriction = 75f;
300 private float mTerrainContactBounce = 0.1f;
301 private float mTerrainContactERP = 0.05025f;
302
303 private float nmAvatarObjectContactFriction = 250f;
304 private float nmAvatarObjectContactBounce = 0.1f;
305
306 private float mAvatarObjectContactFriction = 75f;
307 private float mAvatarObjectContactBounce = 0.1f;
308
309 private float avPIDD = 3200f;
310 private float avPIDP = 1400f;
311 private float avCapRadius = 0.37f;
312 private float avStandupTensor = 2000000f;
313
314 /// <summary>
315 /// true = old compatibility mode with leaning capsule; false = new corrected mode
316 /// </summary>
317 /// <remarks>
318 /// Even when set to false, the capsule still tilts but this is done in a different way.
319 /// </remarks>
320 public bool IsAvCapsuleTilted { get; private set; }
321
322 private float avDensity = 80f;
323// private float avHeightFudgeFactor = 0.52f;
324 private float avMovementDivisorWalk = 1.3f;
325 private float avMovementDivisorRun = 0.8f;
326 private float minimumGroundFlightOffset = 3f;
327 public float maximumMassObject = 10000.01f;
328
329 public bool meshSculptedPrim = true;
330 public bool forceSimplePrimMeshing = false;
331
332 public float meshSculptLOD = 32;
333 public float MeshSculptphysicalLOD = 16;
334
335 public float geomDefaultDensity = 10.000006836f;
336
337 public int geomContactPointsStartthrottle = 3;
338 public int geomUpdatesPerThrottledUpdate = 15;
339 private const int avatarExpectedContacts = 3;
340
341 public float bodyPIDD = 35f;
342 public float bodyPIDG = 25;
343
344 public int geomCrossingFailuresBeforeOutofbounds = 5;
345
346 public float bodyMotorJointMaxforceTensor = 2;
347
348 public int bodyFramesAutoDisable = 20;
349
350 private float[] _watermap;
351 private bool m_filterCollisions = true;
352
353 private d.NearCallback nearCallback;
354 public d.TriCallback triCallback;
355 public d.TriArrayCallback triArrayCallback;
356
357 /// <summary>
358 /// Avatars in the physics scene.
359 /// </summary>
360 private readonly HashSet<OdeCharacter> _characters = new HashSet<OdeCharacter>();
361
362 /// <summary>
363 /// Prims in the physics scene.
364 /// </summary>
365 private readonly HashSet<OdePrim> _prims = new HashSet<OdePrim>();
366
367 /// <summary>
368 /// Prims in the physics scene that are subject to physics, not just collisions.
369 /// </summary>
370 private readonly HashSet<OdePrim> _activeprims = new HashSet<OdePrim>();
371
372 /// <summary>
373 /// Prims that the simulator has created/deleted/updated and so need updating in ODE.
374 /// </summary>
375 private readonly HashSet<OdePrim> _taintedPrims = new HashSet<OdePrim>();
376
377 /// <summary>
378 /// Record a character that has taints to be processed.
379 /// </summary>
380 private readonly HashSet<OdeCharacter> _taintedActors = new HashSet<OdeCharacter>();
381
382 /// <summary>
383 /// Keep record of contacts in the physics loop so that we can remove duplicates.
384 /// </summary>
385 private readonly List<d.ContactGeom> _perloopContact = new List<d.ContactGeom>();
386
387 /// <summary>
388 /// A dictionary of actors that should receive collision events.
389 /// </summary>
390 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActors = new Dictionary<uint, PhysicsActor>();
391
392 /// <summary>
393 /// A dictionary of collision event changes that are waiting to be processed.
394 /// </summary>
395 private readonly Dictionary<uint, PhysicsActor> m_collisionEventActorsChanges = new Dictionary<uint, PhysicsActor>();
396
397 /// <summary>
398 /// Maps a unique geometry id (a memory location) to a physics actor name.
399 /// </summary>
400 /// <remarks>
401 /// Only actors participating in collisions have geometries. This has to be maintained separately from
402 /// actor_name_map because terrain and water currently don't conceptually have a physics actor of their own
403 /// apart from the singleton PANull
404 /// </remarks>
405 public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
406
407 /// <summary>
408 /// Maps a unique geometry id (a memory location) to a physics actor.
409 /// </summary>
410 /// <remarks>
411 /// Only actors participating in collisions have geometries.
412 /// </remarks>
413 public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
414
415 /// <summary>
416 /// Defects list to remove characters that no longer have finite positions due to some other bug.
417 /// </summary>
418 /// <remarks>
419 /// Used repeatedly in Simulate() but initialized once here.
420 /// </remarks>
421 private readonly List<OdeCharacter> defects = new List<OdeCharacter>();
422
423 private bool m_NINJA_physics_joints_enabled = false;
424 //private Dictionary<String, IntPtr> jointpart_name_map = new Dictionary<String,IntPtr>();
425 private readonly Dictionary<String, List<PhysicsJoint>> joints_connecting_actor = new Dictionary<String, List<PhysicsJoint>>();
426 private d.ContactGeom[] contacts;
427
428 /// <summary>
429 /// Lock only briefly. accessed by external code (to request new joints) and by OdeScene.Simulate() to move those joints into pending/active
430 /// </summary>
431 private readonly List<PhysicsJoint> requestedJointsToBeCreated = new List<PhysicsJoint>();
432
433 /// <summary>
434 /// can lock for longer. accessed only by OdeScene.
435 /// </summary>
436 private readonly List<PhysicsJoint> pendingJoints = new List<PhysicsJoint>();
437
438 /// <summary>
439 /// can lock for longer. accessed only by OdeScene.
440 /// </summary>
441 private readonly List<PhysicsJoint> activeJoints = new List<PhysicsJoint>();
442
443 /// <summary>
444 /// lock only briefly. accessed by external code (to request deletion of joints) and by OdeScene.Simulate() to move those joints out of pending/active
445 /// </summary>
446 private readonly List<string> requestedJointsToBeDeleted = new List<string>();
447
448 private Object externalJointRequestsLock = new Object();
449 private readonly Dictionary<String, PhysicsJoint> SOPName_to_activeJoint = new Dictionary<String, PhysicsJoint>();
450 private readonly Dictionary<String, PhysicsJoint> SOPName_to_pendingJoint = new Dictionary<String, PhysicsJoint>();
451 private readonly DoubleDictionary<Vector3, IntPtr, IntPtr> RegionTerrain = new DoubleDictionary<Vector3, IntPtr, IntPtr>();
452 private readonly Dictionary<IntPtr,float[]> TerrainHeightFieldHeights = new Dictionary<IntPtr, float[]>();
453
454 private d.Contact contact;
455 private d.Contact TerrainContact;
456 private d.Contact AvatarMovementprimContact;
457 private d.Contact AvatarMovementTerrainContact;
458 private d.Contact WaterContact;
459 private d.Contact[,] m_materialContacts;
460
461//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
462//Ckrinke private int m_randomizeWater = 200;
463 private int m_physicsiterations = 10;
464 private const float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
465 private readonly PhysicsActor PANull = new NullPhysicsActor();
466// private float step_time = 0.0f;
467//Ckrinke: Comment out until used. We declare it, initialize it, but do not use it
468//Ckrinke private int ms = 0;
469 public IntPtr world;
470 //private bool returncollisions = false;
471 // private uint obj1LocalID = 0;
472 private uint obj2LocalID = 0;
473 //private int ctype = 0;
474 private OdeCharacter cc1;
475 private OdePrim cp1;
476 private OdeCharacter cc2;
477 private OdePrim cp2;
478 private int p1ExpectedPoints = 0;
479 private int p2ExpectedPoints = 0;
480 //private int cStartStop = 0;
481 //private string cDictKey = "";
482
483 public IntPtr space;
484
485 //private IntPtr tmpSpace;
486 // split static geometry collision handling into spaces of 30 meters
487 public IntPtr[,] staticPrimspace;
488
489 /// <summary>
490 /// Used to lock the entire physics scene. Locked during the main part of Simulate()
491 /// </summary>
492 internal Object OdeLock = new Object();
493
494 private bool _worldInitialized = false;
495
496 public IMesher mesher;
497
498 private IConfigSource m_config;
499
500 public bool physics_logging = false;
501 public int physics_logging_interval = 0;
502 public bool physics_logging_append_existing_logfile = false;
503
504 private bool avplanted = false;
505 private bool av_av_collisions_off = false;
506
507 public d.Vector3 xyz = new d.Vector3(128.1640f, 128.3079f, 25.7600f);
508 public d.Vector3 hpr = new d.Vector3(125.5000f, -17.0000f, 0.0000f);
509
510 // TODO: unused: private uint heightmapWidth = m_regionWidth + 1;
511 // TODO: unused: private uint heightmapHeight = m_regionHeight + 1;
512 // TODO: unused: private uint heightmapWidthSamples;
513 // TODO: unused: private uint heightmapHeightSamples;
514
515 private volatile int m_global_contactcount = 0;
516
517 private Vector3 m_worldOffset = Vector3.Zero;
518 public Vector2 WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
519 private PhysicsScene m_parentScene = null;
520
521 private ODERayCastRequestManager m_rayCastManager;
522
523 /// <summary>
524 /// Initiailizes the scene
525 /// Sets many properties that ODE requires to be stable
526 /// These settings need to be tweaked 'exactly' right or weird stuff happens.
527 /// </summary>
528 /// <param value="name">Name of the scene. Useful in debug messages.</param>
529 public OdeScene(string engineType, string name)
530 {
531 m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType.ToString() + "." + name);
532
533 Name = name;
534 EngineType = engineType;
535
536 nearCallback = near;
537 triCallback = TriCallback;
538 triArrayCallback = TriArrayCallback;
539 m_rayCastManager = new ODERayCastRequestManager(this);
540
541 // Create the world and the first space
542 world = d.WorldCreate();
543 space = d.HashSpaceCreate(IntPtr.Zero);
544
545 contactgroup = d.JointGroupCreate(0);
546
547 d.WorldSetAutoDisableFlag(world, false);
548
549 #if USE_DRAWSTUFF
550 Thread viewthread = new Thread(new ParameterizedThreadStart(startvisualization));
551 viewthread.Start();
552 #endif
553
554 _watermap = new float[258 * 258];
555
556 // Zero out the prim spaces array (we split our space into smaller spaces so
557 // we can hit test less.
558 }
559
560#if USE_DRAWSTUFF
561 public void startvisualization(object o)
562 {
563 ds.Functions fn;
564 fn.version = ds.VERSION;
565 fn.start = new ds.CallbackFunction(start);
566 fn.step = new ds.CallbackFunction(step);
567 fn.command = new ds.CallbackFunction(command);
568 fn.stop = null;
569 fn.path_to_textures = "./textures";
570 string[] args = new string[0];
571 ds.SimulationLoop(args.Length, args, 352, 288, ref fn);
572 }
573#endif
574
575 // Initialize the mesh plugin
576 public override void Initialise(IMesher meshmerizer, IConfigSource config)
577 {
578 InitializeExtraStats();
579
580 mesher = meshmerizer;
581 m_config = config;
582 // Defaults
583
584 if (Environment.OSVersion.Platform == PlatformID.Unix)
585 {
586 avPIDD = 3200.0f;
587 avPIDP = 1400.0f;
588 avStandupTensor = 2000000f;
589 }
590 else
591 {
592 avPIDD = 2200.0f;
593 avPIDP = 900.0f;
594 avStandupTensor = 550000f;
595 }
596
597 int contactsPerCollision = 80;
598
599 if (m_config != null)
600 {
601 IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"];
602 if (physicsconfig != null)
603 {
604 CollectStats = physicsconfig.GetBoolean("collect_stats", false);
605
606 gravityx = physicsconfig.GetFloat("world_gravityx", 0f);
607 gravityy = physicsconfig.GetFloat("world_gravityy", 0f);
608 gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f);
609
610 float avatarTerminalVelocity = physicsconfig.GetFloat("avatar_terminal_velocity", 54f);
611 AvatarTerminalVelocity = Util.Clamp<float>(avatarTerminalVelocity, 0, 255f);
612 if (AvatarTerminalVelocity != avatarTerminalVelocity)
613 {
614 m_log.WarnFormat(
615 "[ODE SCENE]: avatar_terminal_velocity of {0} is invalid. Clamping to {1}",
616 avatarTerminalVelocity, AvatarTerminalVelocity);
617 }
618
619 worldHashspaceLow = physicsconfig.GetInt("world_hashspace_size_low", -4);
620 worldHashspaceHigh = physicsconfig.GetInt("world_hashspace_size_high", 128);
621
622 metersInSpace = physicsconfig.GetFloat("meters_in_small_space", 29.9f);
623 smallHashspaceLow = physicsconfig.GetInt("small_hashspace_size_low", -4);
624 smallHashspaceHigh = physicsconfig.GetInt("small_hashspace_size_high", 66);
625
626 contactsurfacelayer = physicsconfig.GetFloat("world_contact_surface_layer", 0.001f);
627
628 nmTerrainContactFriction = physicsconfig.GetFloat("nm_terraincontact_friction", 255.0f);
629 nmTerrainContactBounce = physicsconfig.GetFloat("nm_terraincontact_bounce", 0.1f);
630 nmTerrainContactERP = physicsconfig.GetFloat("nm_terraincontact_erp", 0.1025f);
631
632 mTerrainContactFriction = physicsconfig.GetFloat("m_terraincontact_friction", 75f);
633 mTerrainContactBounce = physicsconfig.GetFloat("m_terraincontact_bounce", 0.05f);
634 mTerrainContactERP = physicsconfig.GetFloat("m_terraincontact_erp", 0.05025f);
635
636 nmAvatarObjectContactFriction = physicsconfig.GetFloat("objectcontact_friction", 250f);
637 nmAvatarObjectContactBounce = physicsconfig.GetFloat("objectcontact_bounce", 0.2f);
638
639 mAvatarObjectContactFriction = physicsconfig.GetFloat("m_avatarobjectcontact_friction", 75f);
640 mAvatarObjectContactBounce = physicsconfig.GetFloat("m_avatarobjectcontact_bounce", 0.1f);
641
642 ODE_STEPSIZE = physicsconfig.GetFloat("world_stepsize", ODE_STEPSIZE);
643 m_physicsiterations = physicsconfig.GetInt("world_internal_steps_without_collisions", 10);
644
645 avDensity = physicsconfig.GetFloat("av_density", 80f);
646// avHeightFudgeFactor = physicsconfig.GetFloat("av_height_fudge_factor", 0.52f);
647 avMovementDivisorWalk = physicsconfig.GetFloat("av_movement_divisor_walk", 1.3f);
648 avMovementDivisorRun = physicsconfig.GetFloat("av_movement_divisor_run", 0.8f);
649 avCapRadius = physicsconfig.GetFloat("av_capsule_radius", 0.37f);
650 avplanted = physicsconfig.GetBoolean("av_planted", false);
651 av_av_collisions_off = physicsconfig.GetBoolean("av_av_collisions_off", false);
652
653 IsAvCapsuleTilted = physicsconfig.GetBoolean("av_capsule_tilted", false);
654
655 contactsPerCollision = physicsconfig.GetInt("contacts_per_collision", 80);
656
657 geomContactPointsStartthrottle = physicsconfig.GetInt("geom_contactpoints_start_throttling", 5);
658 geomUpdatesPerThrottledUpdate = physicsconfig.GetInt("geom_updates_before_throttled_update", 15);
659 geomCrossingFailuresBeforeOutofbounds = physicsconfig.GetInt("geom_crossing_failures_before_outofbounds", 5);
660
661 geomDefaultDensity = physicsconfig.GetFloat("geometry_default_density", 10.000006836f);
662 bodyFramesAutoDisable = physicsconfig.GetInt("body_frames_auto_disable", 20);
663
664 bodyPIDD = physicsconfig.GetFloat("body_pid_derivative", 35f);
665 bodyPIDG = physicsconfig.GetFloat("body_pid_gain", 25f);
666
667 forceSimplePrimMeshing = physicsconfig.GetBoolean("force_simple_prim_meshing", forceSimplePrimMeshing);
668 meshSculptedPrim = physicsconfig.GetBoolean("mesh_sculpted_prim", true);
669 meshSculptLOD = physicsconfig.GetFloat("mesh_lod", 32f);
670 MeshSculptphysicalLOD = physicsconfig.GetFloat("mesh_physical_lod", 16f);
671 m_filterCollisions = physicsconfig.GetBoolean("filter_collisions", false);
672
673
674
675 if (Environment.OSVersion.Platform == PlatformID.Unix)
676 {
677 avPIDD = physicsconfig.GetFloat("av_pid_derivative_linux", 2200.0f);
678 avPIDP = physicsconfig.GetFloat("av_pid_proportional_linux", 900.0f);
679 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_linux", 550000f);
680 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_linux", 5f);
681 }
682 else
683 {
684 avPIDD = physicsconfig.GetFloat("av_pid_derivative_win", 2200.0f);
685 avPIDP = physicsconfig.GetFloat("av_pid_proportional_win", 900.0f);
686 avStandupTensor = physicsconfig.GetFloat("av_capsule_standup_tensor_win", 550000f);
687 bodyMotorJointMaxforceTensor = physicsconfig.GetFloat("body_motor_joint_maxforce_tensor_win", 5f);
688 }
689
690 physics_logging = physicsconfig.GetBoolean("physics_logging", false);
691 physics_logging_interval = physicsconfig.GetInt("physics_logging_interval", 0);
692 physics_logging_append_existing_logfile = physicsconfig.GetBoolean("physics_logging_append_existing_logfile", false);
693
694 m_NINJA_physics_joints_enabled = physicsconfig.GetBoolean("use_NINJA_physics_joints", false);
695 minimumGroundFlightOffset = physicsconfig.GetFloat("minimum_ground_flight_offset", 3f);
696 maximumMassObject = physicsconfig.GetFloat("maximum_mass_object", 10000.01f);
697 }
698 }
699
700 contacts = new d.ContactGeom[contactsPerCollision];
701
702 staticPrimspace = new IntPtr[(int)(300 / metersInSpace), (int)(300 / metersInSpace)];
703
704 // Centeral contact friction and bounce
705 // ckrinke 11/10/08 Enabling soft_erp but not soft_cfm until I figure out why
706 // an avatar falls through in Z but not in X or Y when walking on a prim.
707 contact.surface.mode |= d.ContactFlags.SoftERP;
708 contact.surface.mu = nmAvatarObjectContactFriction;
709 contact.surface.bounce = nmAvatarObjectContactBounce;
710 contact.surface.soft_cfm = 0.010f;
711 contact.surface.soft_erp = 0.010f;
712
713 // Terrain contact friction and Bounce
714 // This is the *non* moving version. Use this when an avatar
715 // isn't moving to keep it in place better
716 TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
717 TerrainContact.surface.mu = nmTerrainContactFriction;
718 TerrainContact.surface.bounce = nmTerrainContactBounce;
719 TerrainContact.surface.soft_erp = nmTerrainContactERP;
720
721 WaterContact.surface.mode |= (d.ContactFlags.SoftERP | d.ContactFlags.SoftCFM);
722 WaterContact.surface.mu = 0f; // No friction
723 WaterContact.surface.bounce = 0.0f; // No bounce
724 WaterContact.surface.soft_cfm = 0.010f;
725 WaterContact.surface.soft_erp = 0.010f;
726
727 // Prim contact friction and bounce
728 // THis is the *non* moving version of friction and bounce
729 // Use this when an avatar comes in contact with a prim
730 // and is moving
731 AvatarMovementprimContact.surface.mu = mAvatarObjectContactFriction;
732 AvatarMovementprimContact.surface.bounce = mAvatarObjectContactBounce;
733
734 // Terrain contact friction bounce and various error correcting calculations
735 // Use this when an avatar is in contact with the terrain and moving.
736 AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
737 AvatarMovementTerrainContact.surface.mu = mTerrainContactFriction;
738 AvatarMovementTerrainContact.surface.bounce = mTerrainContactBounce;
739 AvatarMovementTerrainContact.surface.soft_erp = mTerrainContactERP;
740
741 /*
742 <summary></summary>
743 Stone = 0,
744 /// <summary></summary>
745 Metal = 1,
746 /// <summary></summary>
747 Glass = 2,
748 /// <summary></summary>
749 Wood = 3,
750 /// <summary></summary>
751 Flesh = 4,
752 /// <summary></summary>
753 Plastic = 5,
754 /// <summary></summary>
755 Rubber = 6
756 */
757
758 m_materialContacts = new d.Contact[7,2];
759
760 m_materialContacts[(int)Material.Stone, 0] = new d.Contact();
761 m_materialContacts[(int)Material.Stone, 0].surface.mode |= d.ContactFlags.SoftERP;
762 m_materialContacts[(int)Material.Stone, 0].surface.mu = nmAvatarObjectContactFriction;
763 m_materialContacts[(int)Material.Stone, 0].surface.bounce = nmAvatarObjectContactBounce;
764 m_materialContacts[(int)Material.Stone, 0].surface.soft_cfm = 0.010f;
765 m_materialContacts[(int)Material.Stone, 0].surface.soft_erp = 0.010f;
766
767 m_materialContacts[(int)Material.Stone, 1] = new d.Contact();
768 m_materialContacts[(int)Material.Stone, 1].surface.mode |= d.ContactFlags.SoftERP;
769 m_materialContacts[(int)Material.Stone, 1].surface.mu = mAvatarObjectContactFriction;
770 m_materialContacts[(int)Material.Stone, 1].surface.bounce = mAvatarObjectContactBounce;
771 m_materialContacts[(int)Material.Stone, 1].surface.soft_cfm = 0.010f;
772 m_materialContacts[(int)Material.Stone, 1].surface.soft_erp = 0.010f;
773
774 m_materialContacts[(int)Material.Metal, 0] = new d.Contact();
775 m_materialContacts[(int)Material.Metal, 0].surface.mode |= d.ContactFlags.SoftERP;
776 m_materialContacts[(int)Material.Metal, 0].surface.mu = nmAvatarObjectContactFriction;
777 m_materialContacts[(int)Material.Metal, 0].surface.bounce = nmAvatarObjectContactBounce;
778 m_materialContacts[(int)Material.Metal, 0].surface.soft_cfm = 0.010f;
779 m_materialContacts[(int)Material.Metal, 0].surface.soft_erp = 0.010f;
780
781 m_materialContacts[(int)Material.Metal, 1] = new d.Contact();
782 m_materialContacts[(int)Material.Metal, 1].surface.mode |= d.ContactFlags.SoftERP;
783 m_materialContacts[(int)Material.Metal, 1].surface.mu = mAvatarObjectContactFriction;
784 m_materialContacts[(int)Material.Metal, 1].surface.bounce = mAvatarObjectContactBounce;
785 m_materialContacts[(int)Material.Metal, 1].surface.soft_cfm = 0.010f;
786 m_materialContacts[(int)Material.Metal, 1].surface.soft_erp = 0.010f;
787
788 m_materialContacts[(int)Material.Glass, 0] = new d.Contact();
789 m_materialContacts[(int)Material.Glass, 0].surface.mode |= d.ContactFlags.SoftERP;
790 m_materialContacts[(int)Material.Glass, 0].surface.mu = 1f;
791 m_materialContacts[(int)Material.Glass, 0].surface.bounce = 0.5f;
792 m_materialContacts[(int)Material.Glass, 0].surface.soft_cfm = 0.010f;
793 m_materialContacts[(int)Material.Glass, 0].surface.soft_erp = 0.010f;
794
795 /*
796 private float nmAvatarObjectContactFriction = 250f;
797 private float nmAvatarObjectContactBounce = 0.1f;
798
799 private float mAvatarObjectContactFriction = 75f;
800 private float mAvatarObjectContactBounce = 0.1f;
801 */
802 m_materialContacts[(int)Material.Glass, 1] = new d.Contact();
803 m_materialContacts[(int)Material.Glass, 1].surface.mode |= d.ContactFlags.SoftERP;
804 m_materialContacts[(int)Material.Glass, 1].surface.mu = 1f;
805 m_materialContacts[(int)Material.Glass, 1].surface.bounce = 0.5f;
806 m_materialContacts[(int)Material.Glass, 1].surface.soft_cfm = 0.010f;
807 m_materialContacts[(int)Material.Glass, 1].surface.soft_erp = 0.010f;
808
809 m_materialContacts[(int)Material.Wood, 0] = new d.Contact();
810 m_materialContacts[(int)Material.Wood, 0].surface.mode |= d.ContactFlags.SoftERP;
811 m_materialContacts[(int)Material.Wood, 0].surface.mu = nmAvatarObjectContactFriction;
812 m_materialContacts[(int)Material.Wood, 0].surface.bounce = nmAvatarObjectContactBounce;
813 m_materialContacts[(int)Material.Wood, 0].surface.soft_cfm = 0.010f;
814 m_materialContacts[(int)Material.Wood, 0].surface.soft_erp = 0.010f;
815
816 m_materialContacts[(int)Material.Wood, 1] = new d.Contact();
817 m_materialContacts[(int)Material.Wood, 1].surface.mode |= d.ContactFlags.SoftERP;
818 m_materialContacts[(int)Material.Wood, 1].surface.mu = mAvatarObjectContactFriction;
819 m_materialContacts[(int)Material.Wood, 1].surface.bounce = mAvatarObjectContactBounce;
820 m_materialContacts[(int)Material.Wood, 1].surface.soft_cfm = 0.010f;
821 m_materialContacts[(int)Material.Wood, 1].surface.soft_erp = 0.010f;
822
823 m_materialContacts[(int)Material.Flesh, 0] = new d.Contact();
824 m_materialContacts[(int)Material.Flesh, 0].surface.mode |= d.ContactFlags.SoftERP;
825 m_materialContacts[(int)Material.Flesh, 0].surface.mu = nmAvatarObjectContactFriction;
826 m_materialContacts[(int)Material.Flesh, 0].surface.bounce = nmAvatarObjectContactBounce;
827 m_materialContacts[(int)Material.Flesh, 0].surface.soft_cfm = 0.010f;
828 m_materialContacts[(int)Material.Flesh, 0].surface.soft_erp = 0.010f;
829
830 m_materialContacts[(int)Material.Flesh, 1] = new d.Contact();
831 m_materialContacts[(int)Material.Flesh, 1].surface.mode |= d.ContactFlags.SoftERP;
832 m_materialContacts[(int)Material.Flesh, 1].surface.mu = mAvatarObjectContactFriction;
833 m_materialContacts[(int)Material.Flesh, 1].surface.bounce = mAvatarObjectContactBounce;
834 m_materialContacts[(int)Material.Flesh, 1].surface.soft_cfm = 0.010f;
835 m_materialContacts[(int)Material.Flesh, 1].surface.soft_erp = 0.010f;
836
837 m_materialContacts[(int)Material.Plastic, 0] = new d.Contact();
838 m_materialContacts[(int)Material.Plastic, 0].surface.mode |= d.ContactFlags.SoftERP;
839 m_materialContacts[(int)Material.Plastic, 0].surface.mu = nmAvatarObjectContactFriction;
840 m_materialContacts[(int)Material.Plastic, 0].surface.bounce = nmAvatarObjectContactBounce;
841 m_materialContacts[(int)Material.Plastic, 0].surface.soft_cfm = 0.010f;
842 m_materialContacts[(int)Material.Plastic, 0].surface.soft_erp = 0.010f;
843
844 m_materialContacts[(int)Material.Plastic, 1] = new d.Contact();
845 m_materialContacts[(int)Material.Plastic, 1].surface.mode |= d.ContactFlags.SoftERP;
846 m_materialContacts[(int)Material.Plastic, 1].surface.mu = mAvatarObjectContactFriction;
847 m_materialContacts[(int)Material.Plastic, 1].surface.bounce = mAvatarObjectContactBounce;
848 m_materialContacts[(int)Material.Plastic, 1].surface.soft_cfm = 0.010f;
849 m_materialContacts[(int)Material.Plastic, 1].surface.soft_erp = 0.010f;
850
851 m_materialContacts[(int)Material.Rubber, 0] = new d.Contact();
852 m_materialContacts[(int)Material.Rubber, 0].surface.mode |= d.ContactFlags.SoftERP;
853 m_materialContacts[(int)Material.Rubber, 0].surface.mu = nmAvatarObjectContactFriction;
854 m_materialContacts[(int)Material.Rubber, 0].surface.bounce = nmAvatarObjectContactBounce;
855 m_materialContacts[(int)Material.Rubber, 0].surface.soft_cfm = 0.010f;
856 m_materialContacts[(int)Material.Rubber, 0].surface.soft_erp = 0.010f;
857
858 m_materialContacts[(int)Material.Rubber, 1] = new d.Contact();
859 m_materialContacts[(int)Material.Rubber, 1].surface.mode |= d.ContactFlags.SoftERP;
860 m_materialContacts[(int)Material.Rubber, 1].surface.mu = mAvatarObjectContactFriction;
861 m_materialContacts[(int)Material.Rubber, 1].surface.bounce = mAvatarObjectContactBounce;
862 m_materialContacts[(int)Material.Rubber, 1].surface.soft_cfm = 0.010f;
863 m_materialContacts[(int)Material.Rubber, 1].surface.soft_erp = 0.010f;
864
865 d.HashSpaceSetLevels(space, worldHashspaceLow, worldHashspaceHigh);
866
867 // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
868
869 d.WorldSetGravity(world, gravityx, gravityy, gravityz);
870 d.WorldSetContactSurfaceLayer(world, contactsurfacelayer);
871
872 d.WorldSetLinearDamping(world, 256f);
873 d.WorldSetAngularDamping(world, 256f);
874 d.WorldSetAngularDampingThreshold(world, 256f);
875 d.WorldSetLinearDampingThreshold(world, 256f);
876 d.WorldSetMaxAngularSpeed(world, 256f);
877
878 // Set how many steps we go without running collision testing
879 // This is in addition to the step size.
880 // Essentially Steps * m_physicsiterations
881 d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
882 //d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
883
884 for (int i = 0; i < staticPrimspace.GetLength(0); i++)
885 {
886 for (int j = 0; j < staticPrimspace.GetLength(1); j++)
887 {
888 staticPrimspace[i, j] = IntPtr.Zero;
889 }
890 }
891
892 _worldInitialized = true;
893 }
894
895// internal void waitForSpaceUnlock(IntPtr space)
896// {
897// //if (space != IntPtr.Zero)
898// //while (d.SpaceLockQuery(space)) { } // Wait and do nothing
899// }
900
901// /// <summary>
902// /// Debug space message for printing the space that a prim/avatar is in.
903// /// </summary>
904// /// <param name="pos"></param>
905// /// <returns>Returns which split up space the given position is in.</returns>
906// public string whichspaceamIin(Vector3 pos)
907// {
908// return calculateSpaceForGeom(pos).ToString();
909// }
910
911 #region Collision Detection
912
913 /// <summary>
914 /// Collides two geometries.
915 /// </summary>
916 /// <returns></returns>
917 /// <param name='geom1'></param>
918 /// <param name='geom2'>/param>
919 /// <param name='maxContacts'></param>
920 /// <param name='contactsArray'></param>
921 /// <param name='contactGeomSize'></param>
922 private int CollideGeoms(
923 IntPtr geom1, IntPtr geom2, int maxContacts, Ode.NET.d.ContactGeom[] contactsArray, int contactGeomSize)
924 {
925 int count;
926
927 lock (OdeScene.UniversalColliderSyncObject)
928 {
929 // We do this inside the lock so that we don't count any delay in acquiring it
930 if (CollectStats)
931 m_nativeCollisionStartTick = Util.EnvironmentTickCount();
932
933 count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize);
934 }
935
936 // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably
937 // negligable
938 if (CollectStats)
939 m_stats[ODENativeGeomCollisionFrameMsStatName]
940 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
941
942 return count;
943 }
944
945 /// <summary>
946 /// Collide two spaces or a space and a geometry.
947 /// </summary>
948 /// <param name='space1'></param>
949 /// <param name='space2'>/param>
950 /// <param name='data'></param>
951 private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data)
952 {
953 if (CollectStats)
954 {
955 m_inCollisionTiming = true;
956 m_nativeCollisionStartTick = Util.EnvironmentTickCount();
957 }
958
959 d.SpaceCollide2(space1, space2, data, nearCallback);
960
961 if (CollectStats && m_inCollisionTiming)
962 {
963 m_stats[ODENativeSpaceCollisionFrameMsStatName]
964 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
965 m_inCollisionTiming = false;
966 }
967 }
968
969 /// <summary>
970 /// This is our near callback. A geometry is near a body
971 /// </summary>
972 /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
973 /// <param name="g1">a geometry or space</param>
974 /// <param name="g2">another geometry or space</param>
975 private void near(IntPtr space, IntPtr g1, IntPtr g2)
976 {
977 if (CollectStats && m_inCollisionTiming)
978 {
979 m_stats[ODENativeSpaceCollisionFrameMsStatName]
980 += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick);
981 m_inCollisionTiming = false;
982 }
983
984// m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space);
985 // no lock here! It's invoked from within Simulate(), which is thread-locked
986
987 // Test if we're colliding a geom with a space.
988 // If so we have to drill down into the space recursively
989
990 if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
991 {
992 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
993 return;
994
995 // Separating static prim geometry spaces.
996 // We'll be calling near recursivly if one
997 // of them is a space to find all of the
998 // contact points in the space
999 try
1000 {
1001 CollideSpaces(g1, g2, IntPtr.Zero);
1002 }
1003 catch (AccessViolationException)
1004 {
1005 m_log.Error("[ODE SCENE]: Unable to collide test a space");
1006 return;
1007 }
1008 //Colliding a space or a geom with a space or a geom. so drill down
1009
1010 //Collide all geoms in each space..
1011 //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
1012 //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
1013 return;
1014 }
1015
1016 if (g1 == IntPtr.Zero || g2 == IntPtr.Zero)
1017 return;
1018
1019 IntPtr b1 = d.GeomGetBody(g1);
1020 IntPtr b2 = d.GeomGetBody(g2);
1021
1022 // d.GeomClassID id = d.GeomGetClass(g1);
1023
1024 String name1 = null;
1025 String name2 = null;
1026
1027 if (!geom_name_map.TryGetValue(g1, out name1))
1028 {
1029 name1 = "null";
1030 }
1031 if (!geom_name_map.TryGetValue(g2, out name2))
1032 {
1033 name2 = "null";
1034 }
1035
1036 //if (id == d.GeomClassId.TriMeshClass)
1037 //{
1038 // m_log.InfoFormat("near: A collision was detected between {1} and {2}", 0, name1, name2);
1039 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1040 //}
1041
1042 // Figure out how many contact points we have
1043 int count = 0;
1044
1045 try
1046 {
1047 // Colliding Geom To Geom
1048 // This portion of the function 'was' blatantly ripped off from BoxStack.cs
1049
1050 if (g1 == g2)
1051 return; // Can't collide with yourself
1052
1053 if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
1054 return;
1055
1056 count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf);
1057
1058 // All code after this is only relevant if we have any collisions
1059 if (count <= 0)
1060 return;
1061
1062 if (count > contacts.Length)
1063 m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length);
1064 }
1065 catch (SEHException)
1066 {
1067 m_log.Error(
1068 "[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.");
1069 base.TriggerPhysicsBasedRestart();
1070 }
1071 catch (Exception e)
1072 {
1073 m_log.ErrorFormat("[ODE SCENE]: Unable to collide test an object: {0}", e.Message);
1074 return;
1075 }
1076
1077 PhysicsActor p1;
1078 PhysicsActor p2;
1079
1080 p1ExpectedPoints = 0;
1081 p2ExpectedPoints = 0;
1082
1083 if (!actor_name_map.TryGetValue(g1, out p1))
1084 {
1085 p1 = PANull;
1086 }
1087
1088 if (!actor_name_map.TryGetValue(g2, out p2))
1089 {
1090 p2 = PANull;
1091 }
1092
1093 ContactPoint maxDepthContact = new ContactPoint();
1094 if (p1.CollisionScore + count >= float.MaxValue)
1095 p1.CollisionScore = 0;
1096 p1.CollisionScore += count;
1097
1098 if (p2.CollisionScore + count >= float.MaxValue)
1099 p2.CollisionScore = 0;
1100 p2.CollisionScore += count;
1101
1102 for (int i = 0; i < count; i++)
1103 {
1104 d.ContactGeom curContact = contacts[i];
1105
1106 if (curContact.depth > maxDepthContact.PenetrationDepth)
1107 {
1108 maxDepthContact = new ContactPoint(
1109 new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z),
1110 new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z),
1111 curContact.depth
1112 );
1113 }
1114
1115 //m_log.Warn("[CCOUNT]: " + count);
1116 IntPtr joint;
1117 // If we're colliding with terrain, use 'TerrainContact' instead of contact.
1118 // allows us to have different settings
1119
1120 // We only need to test p2 for 'jump crouch purposes'
1121 if (p2 is OdeCharacter && p1.PhysicsActorType == (int)ActorTypes.Prim)
1122 {
1123 // Testing if the collision is at the feet of the avatar
1124
1125 //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));
1126 if ((p2.Position.Z - curContact.pos.Z) > (p2.Size.Z * 0.6f))
1127 p2.IsColliding = true;
1128 }
1129 else
1130 {
1131 p2.IsColliding = true;
1132 }
1133
1134 //if ((framecount % m_returncollisions) == 0)
1135
1136 switch (p1.PhysicsActorType)
1137 {
1138 case (int)ActorTypes.Agent:
1139 p1ExpectedPoints = avatarExpectedContacts;
1140 p2.CollidingObj = true;
1141 break;
1142 case (int)ActorTypes.Prim:
1143 if (p1 != null && p1 is OdePrim)
1144 p1ExpectedPoints = ((OdePrim) p1).ExpectedCollisionContacts;
1145
1146 if (p2.Velocity.LengthSquared() > 0.0f)
1147 p2.CollidingObj = true;
1148 break;
1149 case (int)ActorTypes.Unknown:
1150 p2.CollidingGround = true;
1151 break;
1152 default:
1153 p2.CollidingGround = true;
1154 break;
1155 }
1156
1157 // we don't want prim or avatar to explode
1158
1159 #region InterPenetration Handling - Unintended physics explosions
1160# region disabled code1
1161
1162 if (curContact.depth >= 0.08f)
1163 {
1164 //This is disabled at the moment only because it needs more tweaking
1165 //It will eventually be uncommented
1166 /*
1167 if (contact.depth >= 1.00f)
1168 {
1169 //m_log.Debug("[PHYSICS]: " + contact.depth.ToString());
1170 }
1171
1172 //If you interpenetrate a prim with an agent
1173 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
1174 p1.PhysicsActorType == (int) ActorTypes.Prim) ||
1175 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
1176 p2.PhysicsActorType == (int) ActorTypes.Prim))
1177 {
1178
1179 //contact.depth = contact.depth * 4.15f;
1180 /*
1181 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
1182 {
1183 p2.CollidingObj = true;
1184 contact.depth = 0.003f;
1185 p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
1186 OdeCharacter character = (OdeCharacter) p2;
1187 character.SetPidStatus(true);
1188 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));
1189
1190 }
1191 else
1192 {
1193
1194 //contact.depth = 0.0000000f;
1195 }
1196 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1197 {
1198
1199 p1.CollidingObj = true;
1200 contact.depth = 0.003f;
1201 p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
1202 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));
1203 OdeCharacter character = (OdeCharacter)p1;
1204 character.SetPidStatus(true);
1205 }
1206 else
1207 {
1208
1209 //contact.depth = 0.0000000f;
1210 }
1211
1212
1213
1214 }
1215*/
1216 // If you interpenetrate a prim with another prim
1217 /*
1218 if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
1219 {
1220 #region disabledcode2
1221 //OdePrim op1 = (OdePrim)p1;
1222 //OdePrim op2 = (OdePrim)p2;
1223 //op1.m_collisionscore++;
1224 //op2.m_collisionscore++;
1225
1226 //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
1227 //{
1228 //op1.m_taintdisable = true;
1229 //AddPhysicsActorTaint(p1);
1230 //op2.m_taintdisable = true;
1231 //AddPhysicsActorTaint(p2);
1232 //}
1233
1234 //if (contact.depth >= 0.25f)
1235 //{
1236 // Don't collide, one or both prim will expld.
1237
1238 //op1.m_interpenetrationcount++;
1239 //op2.m_interpenetrationcount++;
1240 //interpenetrations_before_disable = 200;
1241 //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
1242 //{
1243 //op1.m_taintdisable = true;
1244 //AddPhysicsActorTaint(p1);
1245 //}
1246 //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
1247 //{
1248 // op2.m_taintdisable = true;
1249 //AddPhysicsActorTaint(p2);
1250 //}
1251
1252 //contact.depth = contact.depth / 8f;
1253 //contact.normal = new d.Vector3(0, 0, 1);
1254 //}
1255 //if (op1.m_disabled || op2.m_disabled)
1256 //{
1257 //Manually disabled objects stay disabled
1258 //contact.depth = 0f;
1259 //}
1260 #endregion
1261 }
1262 */
1263#endregion
1264 if (curContact.depth >= 1.00f)
1265 {
1266 //m_log.Info("[P]: " + contact.depth.ToString());
1267 if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
1268 p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
1269 (p1.PhysicsActorType == (int) ActorTypes.Agent &&
1270 p2.PhysicsActorType == (int) ActorTypes.Unknown))
1271 {
1272 if (p2.PhysicsActorType == (int) ActorTypes.Agent)
1273 {
1274 if (p2 is OdeCharacter)
1275 {
1276 OdeCharacter character = (OdeCharacter) p2;
1277
1278 //p2.CollidingObj = true;
1279 curContact.depth = 0.00000003f;
1280 p2.Velocity = p2.Velocity + new Vector3(0f, 0f, 0.5f);
1281 curContact.pos =
1282 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1283 curContact.pos.Y + (p1.Size.Y/2),
1284 curContact.pos.Z + (p1.Size.Z/2));
1285 character.SetPidStatus(true);
1286 }
1287 }
1288
1289 if (p1.PhysicsActorType == (int) ActorTypes.Agent)
1290 {
1291 if (p1 is OdeCharacter)
1292 {
1293 OdeCharacter character = (OdeCharacter) p1;
1294
1295 //p2.CollidingObj = true;
1296 curContact.depth = 0.00000003f;
1297 p1.Velocity = p1.Velocity + new Vector3(0f, 0f, 0.5f);
1298 curContact.pos =
1299 new d.Vector3(curContact.pos.X + (p1.Size.X/2),
1300 curContact.pos.Y + (p1.Size.Y/2),
1301 curContact.pos.Z + (p1.Size.Z/2));
1302 character.SetPidStatus(true);
1303 }
1304 }
1305 }
1306 }
1307 }
1308
1309 #endregion
1310
1311 // Logic for collision handling
1312 // Note, that if *all* contacts are skipped (VolumeDetect)
1313 // The prim still detects (and forwards) collision events but
1314 // appears to be phantom for the world
1315 Boolean skipThisContact = false;
1316
1317 if ((p1 is OdePrim) && (((OdePrim)p1).m_isVolumeDetect))
1318 skipThisContact = true; // No collision on volume detect prims
1319
1320 if (av_av_collisions_off)
1321 if ((p1 is OdeCharacter) && (p2 is OdeCharacter))
1322 skipThisContact = true;
1323
1324 if (!skipThisContact && (p2 is OdePrim) && (((OdePrim)p2).m_isVolumeDetect))
1325 skipThisContact = true; // No collision on volume detect prims
1326
1327 if (!skipThisContact && curContact.depth < 0f)
1328 skipThisContact = true;
1329
1330 if (!skipThisContact && checkDupe(curContact, p2.PhysicsActorType))
1331 skipThisContact = true;
1332
1333 const int maxContactsbeforedeath = 4000;
1334 joint = IntPtr.Zero;
1335
1336 if (!skipThisContact)
1337 {
1338 _perloopContact.Add(curContact);
1339
1340 if (name1 == "Terrain" || name2 == "Terrain")
1341 {
1342 if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
1343 (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1344 {
1345 p2ExpectedPoints = avatarExpectedContacts;
1346 // Avatar is moving on terrain, use the movement terrain contact
1347 AvatarMovementTerrainContact.geom = curContact;
1348
1349 if (m_global_contactcount < maxContactsbeforedeath)
1350 {
1351 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
1352 m_global_contactcount++;
1353 }
1354 }
1355 else
1356 {
1357 if (p2.PhysicsActorType == (int)ActorTypes.Agent)
1358 {
1359 p2ExpectedPoints = avatarExpectedContacts;
1360 // Avatar is standing on terrain, use the non moving terrain contact
1361 TerrainContact.geom = curContact;
1362
1363 if (m_global_contactcount < maxContactsbeforedeath)
1364 {
1365 joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
1366 m_global_contactcount++;
1367 }
1368 }
1369 else
1370 {
1371 if (p2.PhysicsActorType == (int)ActorTypes.Prim && p1.PhysicsActorType == (int)ActorTypes.Prim)
1372 {
1373 // prim prim contact
1374 // int pj294950 = 0;
1375 int movintYN = 0;
1376 int material = (int) Material.Wood;
1377 // prim terrain contact
1378 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1379 {
1380 movintYN = 1;
1381 }
1382
1383 if (p2 is OdePrim)
1384 {
1385 material = ((OdePrim) p2).m_material;
1386 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1387 }
1388
1389 // Unnessesary because p1 is defined above
1390 //if (p1 is OdePrim)
1391 // {
1392 // p1ExpectedPoints = ((OdePrim)p1).ExpectedCollisionContacts;
1393 // }
1394 //m_log.DebugFormat("Material: {0}", material);
1395
1396 m_materialContacts[material, movintYN].geom = curContact;
1397
1398 if (m_global_contactcount < maxContactsbeforedeath)
1399 {
1400 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1401 m_global_contactcount++;
1402 }
1403 }
1404 else
1405 {
1406 int movintYN = 0;
1407 // prim terrain contact
1408 if (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)
1409 {
1410 movintYN = 1;
1411 }
1412
1413 int material = (int)Material.Wood;
1414
1415 if (p2 is OdePrim)
1416 {
1417 material = ((OdePrim)p2).m_material;
1418 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1419 }
1420
1421 //m_log.DebugFormat("Material: {0}", material);
1422 m_materialContacts[material, movintYN].geom = curContact;
1423
1424 if (m_global_contactcount < maxContactsbeforedeath)
1425 {
1426 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, movintYN]);
1427 m_global_contactcount++;
1428 }
1429 }
1430 }
1431 }
1432 //if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1433 //{
1434 //m_log.Debug("[PHYSICS]: prim contacting with ground");
1435 //}
1436 }
1437 else if (name1 == "Water" || name2 == "Water")
1438 {
1439 /*
1440 if ((p2.PhysicsActorType == (int) ActorTypes.Prim))
1441 {
1442 }
1443 else
1444 {
1445 }
1446 */
1447 //WaterContact.surface.soft_cfm = 0.0000f;
1448 //WaterContact.surface.soft_erp = 0.00000f;
1449 if (curContact.depth > 0.1f)
1450 {
1451 curContact.depth *= 52;
1452 //contact.normal = new d.Vector3(0, 0, 1);
1453 //contact.pos = new d.Vector3(0, 0, contact.pos.Z - 5f);
1454 }
1455
1456 WaterContact.geom = curContact;
1457
1458 if (m_global_contactcount < maxContactsbeforedeath)
1459 {
1460 joint = d.JointCreateContact(world, contactgroup, ref WaterContact);
1461 m_global_contactcount++;
1462 }
1463 //m_log.Info("[PHYSICS]: Prim Water Contact" + contact.depth);
1464 }
1465 else
1466 {
1467 if ((p2.PhysicsActorType == (int)ActorTypes.Agent))
1468 {
1469 p2ExpectedPoints = avatarExpectedContacts;
1470 if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
1471 {
1472 // Avatar is moving on a prim, use the Movement prim contact
1473 AvatarMovementprimContact.geom = curContact;
1474
1475 if (m_global_contactcount < maxContactsbeforedeath)
1476 {
1477 joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
1478 m_global_contactcount++;
1479 }
1480 }
1481 else
1482 {
1483 // Avatar is standing still on a prim, use the non movement contact
1484 contact.geom = curContact;
1485
1486 if (m_global_contactcount < maxContactsbeforedeath)
1487 {
1488 joint = d.JointCreateContact(world, contactgroup, ref contact);
1489 m_global_contactcount++;
1490 }
1491 }
1492 }
1493 else if (p2.PhysicsActorType == (int)ActorTypes.Prim)
1494 {
1495 //p1.PhysicsActorType
1496 int material = (int)Material.Wood;
1497
1498 if (p2 is OdePrim)
1499 {
1500 material = ((OdePrim)p2).m_material;
1501 p2ExpectedPoints = ((OdePrim)p2).ExpectedCollisionContacts;
1502 }
1503
1504 //m_log.DebugFormat("Material: {0}", material);
1505 m_materialContacts[material, 0].geom = curContact;
1506
1507 if (m_global_contactcount < maxContactsbeforedeath)
1508 {
1509 joint = d.JointCreateContact(world, contactgroup, ref m_materialContacts[material, 0]);
1510 m_global_contactcount++;
1511 }
1512 }
1513 }
1514
1515 if (m_global_contactcount < maxContactsbeforedeath && joint != IntPtr.Zero) // stack collide!
1516 {
1517 d.JointAttach(joint, b1, b2);
1518 m_global_contactcount++;
1519 }
1520 }
1521
1522 collision_accounting_events(p1, p2, maxDepthContact);
1523
1524 if (count > ((p1ExpectedPoints + p2ExpectedPoints) * 0.25) + (geomContactPointsStartthrottle))
1525 {
1526 // If there are more then 3 contact points, it's likely
1527 // that we've got a pile of objects, so ...
1528 // We don't want to send out hundreds of terse updates over and over again
1529 // so lets throttle them and send them again after it's somewhat sorted out.
1530 p2.ThrottleUpdates = true;
1531 }
1532 //m_log.Debug(count.ToString());
1533 //m_log.Debug("near: A collision was detected between {1} and {2}", 0, name1, name2);
1534 }
1535 }
1536
1537 private bool checkDupe(d.ContactGeom contactGeom, int atype)
1538 {
1539 if (!m_filterCollisions)
1540 return false;
1541
1542 bool result = false;
1543
1544 ActorTypes at = (ActorTypes)atype;
1545
1546 foreach (d.ContactGeom contact in _perloopContact)
1547 {
1548 //if ((contact.g1 == contactGeom.g1 && contact.g2 == contactGeom.g2))
1549 //{
1550 // || (contact.g2 == contactGeom.g1 && contact.g1 == contactGeom.g2)
1551 if (at == ActorTypes.Agent)
1552 {
1553 if (((Math.Abs(contactGeom.normal.X - contact.normal.X) < 1.026f)
1554 && (Math.Abs(contactGeom.normal.Y - contact.normal.Y) < 0.303f)
1555 && (Math.Abs(contactGeom.normal.Z - contact.normal.Z) < 0.065f)))
1556 {
1557 if (Math.Abs(contact.depth - contactGeom.depth) < 0.052f)
1558 {
1559 //contactGeom.depth *= .00005f;
1560 //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1561 // 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));
1562 result = true;
1563 break;
1564 }
1565// else
1566// {
1567// //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1568// }
1569 }
1570// else
1571// {
1572// //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));
1573// //int i = 0;
1574// }
1575 }
1576 else if (at == ActorTypes.Prim)
1577 {
1578 //d.AABB aabb1 = new d.AABB();
1579 //d.AABB aabb2 = new d.AABB();
1580
1581 //d.GeomGetAABB(contactGeom.g2, out aabb2);
1582 //d.GeomGetAABB(contactGeom.g1, out aabb1);
1583 //aabb1.
1584 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)))
1585 {
1586 if (contactGeom.normal.X == contact.normal.X && contactGeom.normal.Y == contact.normal.Y && contactGeom.normal.Z == contact.normal.Z)
1587 {
1588 if (Math.Abs(contact.depth - contactGeom.depth) < 0.272f)
1589 {
1590 result = true;
1591 break;
1592 }
1593 }
1594 //m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth));
1595 //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));
1596 }
1597 }
1598 }
1599
1600 return result;
1601 }
1602
1603 private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact)
1604 {
1605 // obj1LocalID = 0;
1606 //returncollisions = false;
1607 obj2LocalID = 0;
1608 //ctype = 0;
1609 //cStartStop = 0;
1610 if (!p2.SubscribedEvents() && !p1.SubscribedEvents())
1611 return;
1612
1613 switch ((ActorTypes)p2.PhysicsActorType)
1614 {
1615 case ActorTypes.Agent:
1616 cc2 = (OdeCharacter)p2;
1617
1618 // obj1LocalID = cc2.m_localID;
1619 switch ((ActorTypes)p1.PhysicsActorType)
1620 {
1621 case ActorTypes.Agent:
1622 cc1 = (OdeCharacter)p1;
1623 obj2LocalID = cc1.LocalID;
1624 cc1.AddCollisionEvent(cc2.LocalID, contact);
1625 //ctype = (int)CollisionCategories.Character;
1626
1627 //if (cc1.CollidingObj)
1628 //cStartStop = (int)StatusIndicators.Generic;
1629 //else
1630 //cStartStop = (int)StatusIndicators.Start;
1631
1632 //returncollisions = true;
1633 break;
1634
1635 case ActorTypes.Prim:
1636 if (p1 is OdePrim)
1637 {
1638 cp1 = (OdePrim) p1;
1639 obj2LocalID = cp1.LocalID;
1640 cp1.AddCollisionEvent(cc2.LocalID, contact);
1641 }
1642 //ctype = (int)CollisionCategories.Geom;
1643
1644 //if (cp1.CollidingObj)
1645 //cStartStop = (int)StatusIndicators.Generic;
1646 //else
1647 //cStartStop = (int)StatusIndicators.Start;
1648
1649 //returncollisions = true;
1650 break;
1651
1652 case ActorTypes.Ground:
1653 case ActorTypes.Unknown:
1654 obj2LocalID = 0;
1655 //ctype = (int)CollisionCategories.Land;
1656 //returncollisions = true;
1657 break;
1658 }
1659
1660 cc2.AddCollisionEvent(obj2LocalID, contact);
1661 break;
1662
1663 case ActorTypes.Prim:
1664
1665 if (p2 is OdePrim)
1666 {
1667 cp2 = (OdePrim) p2;
1668
1669 // obj1LocalID = cp2.m_localID;
1670 switch ((ActorTypes) p1.PhysicsActorType)
1671 {
1672 case ActorTypes.Agent:
1673 if (p1 is OdeCharacter)
1674 {
1675 cc1 = (OdeCharacter) p1;
1676 obj2LocalID = cc1.LocalID;
1677 cc1.AddCollisionEvent(cp2.LocalID, contact);
1678 //ctype = (int)CollisionCategories.Character;
1679
1680 //if (cc1.CollidingObj)
1681 //cStartStop = (int)StatusIndicators.Generic;
1682 //else
1683 //cStartStop = (int)StatusIndicators.Start;
1684 //returncollisions = true;
1685 }
1686 break;
1687 case ActorTypes.Prim:
1688
1689 if (p1 is OdePrim)
1690 {
1691 cp1 = (OdePrim) p1;
1692 obj2LocalID = cp1.LocalID;
1693 cp1.AddCollisionEvent(cp2.LocalID, contact);
1694 //ctype = (int)CollisionCategories.Geom;
1695
1696 //if (cp1.CollidingObj)
1697 //cStartStop = (int)StatusIndicators.Generic;
1698 //else
1699 //cStartStop = (int)StatusIndicators.Start;
1700
1701 //returncollisions = true;
1702 }
1703 break;
1704
1705 case ActorTypes.Ground:
1706 case ActorTypes.Unknown:
1707 obj2LocalID = 0;
1708 //ctype = (int)CollisionCategories.Land;
1709
1710 //returncollisions = true;
1711 break;
1712 }
1713
1714 cp2.AddCollisionEvent(obj2LocalID, contact);
1715 }
1716 break;
1717 }
1718 //if (returncollisions)
1719 //{
1720
1721 //lock (m_storedCollisions)
1722 //{
1723 //cDictKey = obj1LocalID.ToString() + obj2LocalID.ToString() + cStartStop.ToString() + ctype.ToString();
1724 //if (m_storedCollisions.ContainsKey(cDictKey))
1725 //{
1726 //sCollisionData objd = m_storedCollisions[cDictKey];
1727 //objd.NumberOfCollisions += 1;
1728 //objd.lastframe = framecount;
1729 //m_storedCollisions[cDictKey] = objd;
1730 //}
1731 //else
1732 //{
1733 //sCollisionData objd = new sCollisionData();
1734 //objd.ColliderLocalId = obj1LocalID;
1735 //objd.CollidedWithLocalId = obj2LocalID;
1736 //objd.CollisionType = ctype;
1737 //objd.NumberOfCollisions = 1;
1738 //objd.lastframe = framecount;
1739 //objd.StatusIndicator = cStartStop;
1740 //m_storedCollisions.Add(cDictKey, objd);
1741 //}
1742 //}
1743 // }
1744 }
1745
1746 private int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
1747 {
1748 /* String name1 = null;
1749 String name2 = null;
1750
1751 if (!geom_name_map.TryGetValue(trimesh, out name1))
1752 {
1753 name1 = "null";
1754 }
1755 if (!geom_name_map.TryGetValue(refObject, out name2))
1756 {
1757 name2 = "null";
1758 }
1759
1760 m_log.InfoFormat("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
1761 */
1762 return 1;
1763 }
1764
1765 private int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
1766 {
1767// String name1 = null;
1768// String name2 = null;
1769//
1770// if (!geom_name_map.TryGetValue(trimesh, out name1))
1771// {
1772// name1 = "null";
1773// }
1774//
1775// if (!geom_name_map.TryGetValue(refObject, out name2))
1776// {
1777// name2 = "null";
1778// }
1779
1780 // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
1781
1782 d.Vector3 v0 = new d.Vector3();
1783 d.Vector3 v1 = new d.Vector3();
1784 d.Vector3 v2 = new d.Vector3();
1785
1786 d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
1787 // 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);
1788
1789 return 1;
1790 }
1791
1792 /// <summary>
1793 /// This is our collision testing routine in ODE
1794 /// </summary>
1795 private void collision_optimized()
1796 {
1797 _perloopContact.Clear();
1798
1799 foreach (OdeCharacter chr in _characters)
1800 {
1801 // Reset the collision values to false
1802 // since we don't know if we're colliding yet
1803 if (chr.Shell == IntPtr.Zero || chr.Body == IntPtr.Zero)
1804 continue;
1805
1806 chr.IsColliding = false;
1807 chr.CollidingGround = false;
1808 chr.CollidingObj = false;
1809
1810 // Test the avatar's geometry for collision with the space
1811 // This will return near and the space that they are the closest to
1812 // And we'll run this again against the avatar and the space segment
1813 // This will return with a bunch of possible objects in the space segment
1814 // and we'll run it again on all of them.
1815 try
1816 {
1817 CollideSpaces(space, chr.Shell, IntPtr.Zero);
1818 }
1819 catch (AccessViolationException)
1820 {
1821 m_log.ErrorFormat("[ODE SCENE]: Unable to space collide {0}", Name);
1822 }
1823
1824 //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
1825 //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
1826 //{
1827 //chr.Position.Z = terrainheight + 10.0f;
1828 //forcedZ = true;
1829 //}
1830 }
1831
1832 if (CollectStats)
1833 {
1834 m_tempAvatarCollisionsThisFrame = _perloopContact.Count;
1835 m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame;
1836 }
1837
1838 List<OdePrim> removeprims = null;
1839 foreach (OdePrim chr in _activeprims)
1840 {
1841 if (chr.Body != IntPtr.Zero && d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
1842 {
1843 try
1844 {
1845 lock (chr)
1846 {
1847 if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false)
1848 {
1849 CollideSpaces(space, chr.prim_geom, IntPtr.Zero);
1850 }
1851 else
1852 {
1853 if (removeprims == null)
1854 {
1855 removeprims = new List<OdePrim>();
1856 }
1857 removeprims.Add(chr);
1858 m_log.Error(
1859 "[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!");
1860 }
1861 }
1862 }
1863 catch (AccessViolationException)
1864 {
1865 m_log.Error("[ODE SCENE]: Unable to space collide");
1866 }
1867 }
1868 }
1869
1870 if (CollectStats)
1871 m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame;
1872
1873 if (removeprims != null)
1874 {
1875 foreach (OdePrim chr in removeprims)
1876 {
1877 _activeprims.Remove(chr);
1878 }
1879 }
1880 }
1881
1882 #endregion
1883
1884 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
1885 {
1886 m_worldOffset = offset;
1887 WorldExtents = new Vector2(extents.X, extents.Y);
1888 m_parentScene = pScene;
1889 }
1890
1891 // Recovered for use by fly height. Kitto Flora
1892 internal float GetTerrainHeightAtXY(float x, float y)
1893 {
1894 int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1895 int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
1896
1897 IntPtr heightFieldGeom = IntPtr.Zero;
1898
1899 if (RegionTerrain.TryGetValue(new Vector3(offsetX,offsetY,0), out heightFieldGeom))
1900 {
1901 if (heightFieldGeom != IntPtr.Zero)
1902 {
1903 if (TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
1904 {
1905
1906 int index;
1907
1908
1909 if ((int)x > WorldExtents.X || (int)y > WorldExtents.Y ||
1910 (int)x < 0.001f || (int)y < 0.001f)
1911 return 0;
1912
1913 x = x - offsetX;
1914 y = y - offsetY;
1915
1916 index = (int)((int)x * ((int)Constants.RegionSize + 2) + (int)y);
1917
1918 if (index < TerrainHeightFieldHeights[heightFieldGeom].Length)
1919 {
1920 //m_log.DebugFormat("x{0} y{1} = {2}", x, y, (float)TerrainHeightFieldHeights[heightFieldGeom][index]);
1921 return (float)TerrainHeightFieldHeights[heightFieldGeom][index];
1922 }
1923
1924 else
1925 return 0f;
1926 }
1927 else
1928 {
1929 return 0f;
1930 }
1931
1932 }
1933 else
1934 {
1935 return 0f;
1936 }
1937
1938 }
1939 else
1940 {
1941 return 0f;
1942 }
1943 }
1944// End recovered. Kitto Flora
1945
1946 /// <summary>
1947 /// Add actor to the list that should receive collision events in the simulate loop.
1948 /// </summary>
1949 /// <param name="obj"></param>
1950 internal void AddCollisionEventReporting(PhysicsActor obj)
1951 {
1952// m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID);
1953
1954 lock (m_collisionEventActorsChanges)
1955 m_collisionEventActorsChanges[obj.LocalID] = obj;
1956 }
1957
1958 /// <summary>
1959 /// Remove actor from the list that should receive collision events in the simulate loop.
1960 /// </summary>
1961 /// <param name="obj"></param>
1962 internal void RemoveCollisionEventReporting(PhysicsActor obj)
1963 {
1964// m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID);
1965
1966 lock (m_collisionEventActorsChanges)
1967 m_collisionEventActorsChanges[obj.LocalID] = null;
1968 }
1969
1970 #region Add/Remove Entities
1971
1972 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
1973 {
1974 OdeCharacter newAv
1975 = new OdeCharacter(
1976 avName, this, position, velocity, size, avPIDD, avPIDP,
1977 avCapRadius, avStandupTensor, avDensity,
1978 avMovementDivisorWalk, avMovementDivisorRun);
1979
1980 newAv.Flying = isFlying;
1981 newAv.MinimumGroundFlightOffset = minimumGroundFlightOffset;
1982 newAv.m_avatarplanted = avplanted;
1983
1984 return newAv;
1985 }
1986
1987 public override void RemoveAvatar(PhysicsActor actor)
1988 {
1989// m_log.DebugFormat(
1990// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}",
1991// actor.Name, actor.LocalID, Name);
1992
1993 ((OdeCharacter) actor).Destroy();
1994 }
1995
1996 internal void AddCharacter(OdeCharacter chr)
1997 {
1998 chr.m_avatarplanted = avplanted;
1999 if (!_characters.Contains(chr))
2000 {
2001 _characters.Add(chr);
2002
2003// m_log.DebugFormat(
2004// "[ODE SCENE]: Adding physics character {0} {1} to physics scene {2}. Count now {3}",
2005// chr.Name, chr.LocalID, Name, _characters.Count);
2006
2007 if (chr.bad)
2008 m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to characters list", chr.m_uuid);
2009 }
2010 else
2011 {
2012 m_log.ErrorFormat(
2013 "[ODE SCENE]: Tried to add character {0} {1} but they are already in the set!",
2014 chr.Name, chr.LocalID);
2015 }
2016 }
2017
2018 internal void RemoveCharacter(OdeCharacter chr)
2019 {
2020 if (_characters.Contains(chr))
2021 {
2022 _characters.Remove(chr);
2023
2024// m_log.DebugFormat(
2025// "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2}. Count now {3}",
2026// chr.Name, chr.LocalID, Name, _characters.Count);
2027 }
2028 else
2029 {
2030 m_log.ErrorFormat(
2031 "[ODE SCENE]: Tried to remove character {0} {1} but they are not in the list!",
2032 chr.Name, chr.LocalID);
2033 }
2034 }
2035
2036 private PhysicsActor AddPrim(String name, Vector3 position, Vector3 size, Quaternion rotation,
2037 PrimitiveBaseShape pbs, bool isphysical, uint localID)
2038 {
2039 Vector3 pos = position;
2040 Vector3 siz = size;
2041 Quaternion rot = rotation;
2042
2043 OdePrim newPrim;
2044 lock (OdeLock)
2045 {
2046 newPrim = new OdePrim(name, this, pos, siz, rot, pbs, isphysical);
2047
2048 lock (_prims)
2049 _prims.Add(newPrim);
2050 }
2051 newPrim.LocalID = localID;
2052 return newPrim;
2053 }
2054
2055 /// <summary>
2056 /// Make this prim subject to physics.
2057 /// </summary>
2058 /// <param name="prim"></param>
2059 internal void ActivatePrim(OdePrim prim)
2060 {
2061 // adds active prim.. (ones that should be iterated over in collisions_optimized
2062 if (!_activeprims.Contains(prim))
2063 _activeprims.Add(prim);
2064 //else
2065 // m_log.Warn("[PHYSICS]: Double Entry in _activeprims detected, potential crash immenent");
2066 }
2067
2068 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
2069 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
2070 {
2071// m_log.DebugFormat("[ODE SCENE]: Adding physics prim {0} {1} to physics scene {2}", primName, localid, Name);
2072
2073 return AddPrim(primName, position, size, rotation, pbs, isPhysical, localid);
2074 }
2075
2076 public override float TimeDilation
2077 {
2078 get { return m_timeDilation; }
2079 }
2080
2081 public override bool SupportsNINJAJoints
2082 {
2083 get { return m_NINJA_physics_joints_enabled; }
2084 }
2085
2086 // internal utility function: must be called within a lock (OdeLock)
2087 private void InternalAddActiveJoint(PhysicsJoint joint)
2088 {
2089 activeJoints.Add(joint);
2090 SOPName_to_activeJoint.Add(joint.ObjectNameInScene, joint);
2091 }
2092
2093 // internal utility function: must be called within a lock (OdeLock)
2094 private void InternalAddPendingJoint(OdePhysicsJoint joint)
2095 {
2096 pendingJoints.Add(joint);
2097 SOPName_to_pendingJoint.Add(joint.ObjectNameInScene, joint);
2098 }
2099
2100 // internal utility function: must be called within a lock (OdeLock)
2101 private void InternalRemovePendingJoint(PhysicsJoint joint)
2102 {
2103 pendingJoints.Remove(joint);
2104 SOPName_to_pendingJoint.Remove(joint.ObjectNameInScene);
2105 }
2106
2107 // internal utility function: must be called within a lock (OdeLock)
2108 private void InternalRemoveActiveJoint(PhysicsJoint joint)
2109 {
2110 activeJoints.Remove(joint);
2111 SOPName_to_activeJoint.Remove(joint.ObjectNameInScene);
2112 }
2113
2114 public override void DumpJointInfo()
2115 {
2116 string hdr = "[NINJA] JOINTINFO: ";
2117 foreach (PhysicsJoint j in pendingJoints)
2118 {
2119 m_log.Debug(hdr + " pending joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
2120 }
2121 m_log.Debug(hdr + pendingJoints.Count + " total pending joints");
2122 foreach (string jointName in SOPName_to_pendingJoint.Keys)
2123 {
2124 m_log.Debug(hdr + " pending joints dict contains Name: " + jointName);
2125 }
2126 m_log.Debug(hdr + SOPName_to_pendingJoint.Keys.Count + " total pending joints dict entries");
2127 foreach (PhysicsJoint j in activeJoints)
2128 {
2129 m_log.Debug(hdr + " active joint, Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
2130 }
2131 m_log.Debug(hdr + activeJoints.Count + " total active joints");
2132 foreach (string jointName in SOPName_to_activeJoint.Keys)
2133 {
2134 m_log.Debug(hdr + " active joints dict contains Name: " + jointName);
2135 }
2136 m_log.Debug(hdr + SOPName_to_activeJoint.Keys.Count + " total active joints dict entries");
2137
2138 m_log.Debug(hdr + " Per-body joint connectivity information follows.");
2139 m_log.Debug(hdr + joints_connecting_actor.Keys.Count + " bodies are connected by joints.");
2140 foreach (string actorName in joints_connecting_actor.Keys)
2141 {
2142 m_log.Debug(hdr + " Actor " + actorName + " has the following joints connecting it");
2143 foreach (PhysicsJoint j in joints_connecting_actor[actorName])
2144 {
2145 m_log.Debug(hdr + " * joint Name: " + j.ObjectNameInScene + " raw parms:" + j.RawParams);
2146 }
2147 m_log.Debug(hdr + joints_connecting_actor[actorName].Count + " connecting joints total for this actor");
2148 }
2149 }
2150
2151 public override void RequestJointDeletion(string ObjectNameInScene)
2152 {
2153 lock (externalJointRequestsLock)
2154 {
2155 if (!requestedJointsToBeDeleted.Contains(ObjectNameInScene)) // forbid same deletion request from entering twice to prevent spurious deletions processed asynchronously
2156 {
2157 requestedJointsToBeDeleted.Add(ObjectNameInScene);
2158 }
2159 }
2160 }
2161
2162 private void DeleteRequestedJoints()
2163 {
2164 List<string> myRequestedJointsToBeDeleted;
2165 lock (externalJointRequestsLock)
2166 {
2167 // make a local copy of the shared list for processing (threading issues)
2168 myRequestedJointsToBeDeleted = new List<string>(requestedJointsToBeDeleted);
2169 }
2170
2171 foreach (string jointName in myRequestedJointsToBeDeleted)
2172 {
2173 lock (OdeLock)
2174 {
2175 //m_log.Debug("[NINJA] trying to deleting requested joint " + jointName);
2176 if (SOPName_to_activeJoint.ContainsKey(jointName) || SOPName_to_pendingJoint.ContainsKey(jointName))
2177 {
2178 OdePhysicsJoint joint = null;
2179 if (SOPName_to_activeJoint.ContainsKey(jointName))
2180 {
2181 joint = SOPName_to_activeJoint[jointName] as OdePhysicsJoint;
2182 InternalRemoveActiveJoint(joint);
2183 }
2184 else if (SOPName_to_pendingJoint.ContainsKey(jointName))
2185 {
2186 joint = SOPName_to_pendingJoint[jointName] as OdePhysicsJoint;
2187 InternalRemovePendingJoint(joint);
2188 }
2189
2190 if (joint != null)
2191 {
2192 //m_log.Debug("joint.BodyNames.Count is " + joint.BodyNames.Count + " and contents " + joint.BodyNames);
2193 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
2194 {
2195 string bodyName = joint.BodyNames[iBodyName];
2196 if (bodyName != "NULL")
2197 {
2198 joints_connecting_actor[bodyName].Remove(joint);
2199 if (joints_connecting_actor[bodyName].Count == 0)
2200 {
2201 joints_connecting_actor.Remove(bodyName);
2202 }
2203 }
2204 }
2205
2206 DoJointDeactivated(joint);
2207 if (joint.jointID != IntPtr.Zero)
2208 {
2209 d.JointDestroy(joint.jointID);
2210 joint.jointID = IntPtr.Zero;
2211 //DoJointErrorMessage(joint, "successfully destroyed joint " + jointName);
2212 }
2213 else
2214 {
2215 //m_log.Warn("[NINJA] Ignoring re-request to destroy joint " + jointName);
2216 }
2217 }
2218 else
2219 {
2220 // DoJointErrorMessage(joint, "coult not find joint to destroy based on name " + jointName);
2221 }
2222 }
2223 else
2224 {
2225 // DoJointErrorMessage(joint, "WARNING - joint removal failed, joint " + jointName);
2226 }
2227 }
2228 }
2229
2230 // remove processed joints from the shared list
2231 lock (externalJointRequestsLock)
2232 {
2233 foreach (string jointName in myRequestedJointsToBeDeleted)
2234 {
2235 requestedJointsToBeDeleted.Remove(jointName);
2236 }
2237 }
2238 }
2239
2240 // for pending joints we don't know if their associated bodies exist yet or not.
2241 // the joint is actually created during processing of the taints
2242 private void CreateRequestedJoints()
2243 {
2244 List<PhysicsJoint> myRequestedJointsToBeCreated;
2245 lock (externalJointRequestsLock)
2246 {
2247 // make a local copy of the shared list for processing (threading issues)
2248 myRequestedJointsToBeCreated = new List<PhysicsJoint>(requestedJointsToBeCreated);
2249 }
2250
2251 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2252 {
2253 lock (OdeLock)
2254 {
2255 if (SOPName_to_pendingJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_pendingJoint[joint.ObjectNameInScene] != null)
2256 {
2257 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);
2258 continue;
2259 }
2260 if (SOPName_to_activeJoint.ContainsKey(joint.ObjectNameInScene) && SOPName_to_activeJoint[joint.ObjectNameInScene] != null)
2261 {
2262 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);
2263 continue;
2264 }
2265
2266 InternalAddPendingJoint(joint as OdePhysicsJoint);
2267
2268 if (joint.BodyNames.Count >= 2)
2269 {
2270 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
2271 {
2272 string bodyName = joint.BodyNames[iBodyName];
2273 if (bodyName != "NULL")
2274 {
2275 if (!joints_connecting_actor.ContainsKey(bodyName))
2276 {
2277 joints_connecting_actor.Add(bodyName, new List<PhysicsJoint>());
2278 }
2279 joints_connecting_actor[bodyName].Add(joint);
2280 }
2281 }
2282 }
2283 }
2284 }
2285
2286 // remove processed joints from shared list
2287 lock (externalJointRequestsLock)
2288 {
2289 foreach (PhysicsJoint joint in myRequestedJointsToBeCreated)
2290 {
2291 requestedJointsToBeCreated.Remove(joint);
2292 }
2293 }
2294 }
2295
2296 /// <summary>
2297 /// Add a request for joint creation.
2298 /// </summary>
2299 /// <remarks>
2300 /// this joint will just be added to a waiting list that is NOT processed during the main
2301 /// Simulate() loop (to avoid deadlocks). After Simulate() is finished, we handle unprocessed joint requests.
2302 /// </remarks>
2303 /// <param name="objectNameInScene"></param>
2304 /// <param name="jointType"></param>
2305 /// <param name="position"></param>
2306 /// <param name="rotation"></param>
2307 /// <param name="parms"></param>
2308 /// <param name="bodyNames"></param>
2309 /// <param name="trackedBodyName"></param>
2310 /// <param name="localRotation"></param>
2311 /// <returns></returns>
2312 public override PhysicsJoint RequestJointCreation(
2313 string objectNameInScene, PhysicsJointType jointType, Vector3 position,
2314 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
2315 {
2316 OdePhysicsJoint joint = new OdePhysicsJoint();
2317 joint.ObjectNameInScene = objectNameInScene;
2318 joint.Type = jointType;
2319 joint.Position = position;
2320 joint.Rotation = rotation;
2321 joint.RawParams = parms;
2322 joint.BodyNames = new List<string>(bodyNames);
2323 joint.TrackedBodyName = trackedBodyName;
2324 joint.LocalRotation = localRotation;
2325 joint.jointID = IntPtr.Zero;
2326 joint.ErrorMessageCount = 0;
2327
2328 lock (externalJointRequestsLock)
2329 {
2330 if (!requestedJointsToBeCreated.Contains(joint)) // forbid same creation request from entering twice
2331 {
2332 requestedJointsToBeCreated.Add(joint);
2333 }
2334 }
2335
2336 return joint;
2337 }
2338
2339 private void RemoveAllJointsConnectedToActor(PhysicsActor actor)
2340 {
2341 //m_log.Debug("RemoveAllJointsConnectedToActor: start");
2342 if (actor.SOPName != null && joints_connecting_actor.ContainsKey(actor.SOPName) && joints_connecting_actor[actor.SOPName] != null)
2343 {
2344 List<PhysicsJoint> jointsToRemove = new List<PhysicsJoint>();
2345 //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)
2346 foreach (PhysicsJoint j in joints_connecting_actor[actor.SOPName])
2347 {
2348 jointsToRemove.Add(j);
2349 }
2350 foreach (PhysicsJoint j in jointsToRemove)
2351 {
2352 //m_log.Debug("RemoveAllJointsConnectedToActor: about to request deletion of " + j.ObjectNameInScene);
2353 RequestJointDeletion(j.ObjectNameInScene);
2354 //m_log.Debug("RemoveAllJointsConnectedToActor: done request deletion of " + j.ObjectNameInScene);
2355 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)
2356 }
2357 }
2358 }
2359
2360 public override void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
2361 {
2362 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: start");
2363 lock (OdeLock)
2364 {
2365 //m_log.Debug("RemoveAllJointsConnectedToActorThreadLocked: got lock");
2366 RemoveAllJointsConnectedToActor(actor);
2367 }
2368 }
2369
2370 // normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2371 public override Vector3 GetJointAnchor(PhysicsJoint joint)
2372 {
2373 Debug.Assert(joint.IsInPhysicsEngine);
2374 d.Vector3 pos = new d.Vector3();
2375
2376 if (!(joint is OdePhysicsJoint))
2377 {
2378 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2379 }
2380 else
2381 {
2382 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2383 switch (odeJoint.Type)
2384 {
2385 case PhysicsJointType.Ball:
2386 d.JointGetBallAnchor(odeJoint.jointID, out pos);
2387 break;
2388 case PhysicsJointType.Hinge:
2389 d.JointGetHingeAnchor(odeJoint.jointID, out pos);
2390 break;
2391 }
2392 }
2393 return new Vector3(pos.X, pos.Y, pos.Z);
2394 }
2395
2396 /// <summary>
2397 /// Get joint axis.
2398 /// </summary>
2399 /// <remarks>
2400 /// normally called from within OnJointMoved, which is called from within a lock (OdeLock)
2401 /// WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function
2402 /// appears to be unreliable. Fortunately we can compute the joint axis ourselves by
2403 /// keeping track of the joint's original orientation relative to one of the involved bodies.
2404 /// </remarks>
2405 /// <param name="joint"></param>
2406 /// <returns></returns>
2407 public override Vector3 GetJointAxis(PhysicsJoint joint)
2408 {
2409 Debug.Assert(joint.IsInPhysicsEngine);
2410 d.Vector3 axis = new d.Vector3();
2411
2412 if (!(joint is OdePhysicsJoint))
2413 {
2414 DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene);
2415 }
2416 else
2417 {
2418 OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint;
2419 switch (odeJoint.Type)
2420 {
2421 case PhysicsJointType.Ball:
2422 DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene);
2423 break;
2424 case PhysicsJointType.Hinge:
2425 d.JointGetHingeAxis(odeJoint.jointID, out axis);
2426 break;
2427 }
2428 }
2429 return new Vector3(axis.X, axis.Y, axis.Z);
2430 }
2431
2432 /// <summary>
2433 /// Stop this prim being subject to physics
2434 /// </summary>
2435 /// <param name="prim"></param>
2436 internal void DeactivatePrim(OdePrim prim)
2437 {
2438 _activeprims.Remove(prim);
2439 }
2440
2441 public override void RemovePrim(PhysicsActor prim)
2442 {
2443 // As with all ODE physics operations, we don't remove the prim immediately but signal that it should be
2444 // removed in the next physics simulate pass.
2445 if (prim is OdePrim)
2446 {
2447 lock (OdeLock)
2448 {
2449 OdePrim p = (OdePrim) prim;
2450
2451 p.setPrimForRemoval();
2452 AddPhysicsActorTaint(prim);
2453 }
2454 }
2455 }
2456
2457 /// <summary>
2458 /// This is called from within simulate but outside the locked portion
2459 /// We need to do our own locking here
2460 /// (Note: As of 20110801 this no longer appears to be true - this is being called within lock (odeLock) in
2461 /// Simulate() -- justincc).
2462 ///
2463 /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
2464 ///
2465 /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
2466 /// that the space was using.
2467 /// </summary>
2468 /// <param name="prim"></param>
2469 internal void RemovePrimThreadLocked(OdePrim prim)
2470 {
2471// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID);
2472
2473 lock (prim)
2474 {
2475 RemoveCollisionEventReporting(prim);
2476
2477 if (prim.prim_geom != IntPtr.Zero)
2478 {
2479 prim.ResetTaints();
2480
2481 if (prim.IsPhysical)
2482 {
2483 prim.disableBody();
2484 if (prim.childPrim)
2485 {
2486 prim.childPrim = false;
2487 prim.Body = IntPtr.Zero;
2488 prim.m_disabled = true;
2489 prim.IsPhysical = false;
2490 }
2491
2492
2493 }
2494 // we don't want to remove the main space
2495
2496 // If the geometry is in the targetspace, remove it from the target space
2497 //m_log.Warn(prim.m_targetSpace);
2498
2499 //if (prim.m_targetSpace != IntPtr.Zero)
2500 //{
2501 //if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
2502 //{
2503
2504 //if (d.GeomIsSpace(prim.m_targetSpace))
2505 //{
2506 //waitForSpaceUnlock(prim.m_targetSpace);
2507 //d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
2508 prim.m_targetSpace = IntPtr.Zero;
2509 //}
2510 //else
2511 //{
2512 // m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2513 //((OdePrim)prim).m_targetSpace.ToString());
2514 //}
2515
2516 //}
2517 //}
2518 //m_log.Warn(prim.prim_geom);
2519
2520 if (!prim.RemoveGeom())
2521 m_log.Warn("[ODE SCENE]: Unable to remove prim from physics scene");
2522
2523 lock (_prims)
2524 _prims.Remove(prim);
2525
2526 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2527 //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
2528 //{
2529 //if (prim.m_targetSpace != null)
2530 //{
2531 //if (d.GeomIsSpace(prim.m_targetSpace))
2532 //{
2533 //waitForSpaceUnlock(prim.m_targetSpace);
2534 //d.SpaceRemove(space, prim.m_targetSpace);
2535 // free up memory used by the space.
2536 //d.SpaceDestroy(prim.m_targetSpace);
2537 //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
2538 //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
2539 //}
2540 //else
2541 //{
2542 //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
2543 //((OdePrim) prim).m_targetSpace.ToString());
2544 //}
2545 //}
2546 //}
2547
2548 if (SupportsNINJAJoints)
2549 RemoveAllJointsConnectedToActorThreadLocked(prim);
2550 }
2551 }
2552 }
2553
2554 #endregion
2555
2556 #region Space Separation Calculation
2557
2558 /// <summary>
2559 /// Takes a space pointer and zeros out the array we're using to hold the spaces
2560 /// </summary>
2561 /// <param name="pSpace"></param>
2562 private void resetSpaceArrayItemToZero(IntPtr pSpace)
2563 {
2564 for (int x = 0; x < staticPrimspace.GetLength(0); x++)
2565 {
2566 for (int y = 0; y < staticPrimspace.GetLength(1); y++)
2567 {
2568 if (staticPrimspace[x, y] == pSpace)
2569 staticPrimspace[x, y] = IntPtr.Zero;
2570 }
2571 }
2572 }
2573
2574// private void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
2575// {
2576// staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
2577// }
2578
2579 /// <summary>
2580 /// Called when a static prim moves. Allocates a space for the prim based on its position
2581 /// </summary>
2582 /// <param name="geom">the pointer to the geom that moved</param>
2583 /// <param name="pos">the position that the geom moved to</param>
2584 /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
2585 /// <returns>a pointer to the new space it's in</returns>
2586 internal IntPtr recalculateSpaceForGeom(IntPtr geom, Vector3 pos, IntPtr currentspace)
2587 {
2588 // Called from setting the Position and Size of an ODEPrim so
2589 // it's already in locked space.
2590
2591 // we don't want to remove the main space
2592 // we don't need to test physical here because this function should
2593 // never be called if the prim is physical(active)
2594
2595 // All physical prim end up in the root space
2596 //Thread.Sleep(20);
2597 if (currentspace != space)
2598 {
2599 //m_log.Info("[SPACE]: C:" + currentspace.ToString() + " g:" + geom.ToString());
2600 //if (currentspace == IntPtr.Zero)
2601 //{
2602 //int adfadf = 0;
2603 //}
2604 if (d.SpaceQuery(currentspace, geom) && currentspace != IntPtr.Zero)
2605 {
2606 if (d.GeomIsSpace(currentspace))
2607 {
2608// waitForSpaceUnlock(currentspace);
2609 d.SpaceRemove(currentspace, geom);
2610 }
2611 else
2612 {
2613 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" + currentspace +
2614 " Geom:" + geom);
2615 }
2616 }
2617 else
2618 {
2619 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2620 if (sGeomIsIn != IntPtr.Zero)
2621 {
2622 if (d.GeomIsSpace(currentspace))
2623 {
2624// waitForSpaceUnlock(sGeomIsIn);
2625 d.SpaceRemove(sGeomIsIn, geom);
2626 }
2627 else
2628 {
2629 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2630 sGeomIsIn + " Geom:" + geom);
2631 }
2632 }
2633 }
2634
2635 //If there are no more geometries in the sub-space, we don't need it in the main space anymore
2636 if (d.SpaceGetNumGeoms(currentspace) == 0)
2637 {
2638 if (currentspace != IntPtr.Zero)
2639 {
2640 if (d.GeomIsSpace(currentspace))
2641 {
2642// waitForSpaceUnlock(currentspace);
2643// waitForSpaceUnlock(space);
2644 d.SpaceRemove(space, currentspace);
2645 // free up memory used by the space.
2646
2647 //d.SpaceDestroy(currentspace);
2648 resetSpaceArrayItemToZero(currentspace);
2649 }
2650 else
2651 {
2652 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2653 currentspace + " Geom:" + geom);
2654 }
2655 }
2656 }
2657 }
2658 else
2659 {
2660 // this is a physical object that got disabled. ;.;
2661 if (currentspace != IntPtr.Zero && geom != IntPtr.Zero)
2662 {
2663 if (d.SpaceQuery(currentspace, geom))
2664 {
2665 if (d.GeomIsSpace(currentspace))
2666 {
2667// waitForSpaceUnlock(currentspace);
2668 d.SpaceRemove(currentspace, geom);
2669 }
2670 else
2671 {
2672 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2673 currentspace + " Geom:" + geom);
2674 }
2675 }
2676 else
2677 {
2678 IntPtr sGeomIsIn = d.GeomGetSpace(geom);
2679 if (sGeomIsIn != IntPtr.Zero)
2680 {
2681 if (d.GeomIsSpace(sGeomIsIn))
2682 {
2683// waitForSpaceUnlock(sGeomIsIn);
2684 d.SpaceRemove(sGeomIsIn, geom);
2685 }
2686 else
2687 {
2688 m_log.Info("[ODE SCENE]: Invalid Scene passed to 'recalculatespace':" +
2689 sGeomIsIn + " Geom:" + geom);
2690 }
2691 }
2692 }
2693 }
2694 }
2695
2696 // The routines in the Position and Size sections do the 'inserting' into the space,
2697 // so all we have to do is make sure that the space that we're putting the prim into
2698 // is in the 'main' space.
2699 int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
2700 IntPtr newspace = calculateSpaceForGeom(pos);
2701
2702 if (newspace == IntPtr.Zero)
2703 {
2704 newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
2705 d.HashSpaceSetLevels(newspace, smallHashspaceLow, smallHashspaceHigh);
2706 }
2707
2708 return newspace;
2709 }
2710
2711 /// <summary>
2712 /// Creates a new space at X Y
2713 /// </summary>
2714 /// <param name="iprimspaceArrItemX"></param>
2715 /// <param name="iprimspaceArrItemY"></param>
2716 /// <returns>A pointer to the created space</returns>
2717 internal IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
2718 {
2719 // creating a new space for prim and inserting it into main space.
2720 staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
2721 d.GeomSetCategoryBits(staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY], (int)CollisionCategories.Space);
2722// waitForSpaceUnlock(space);
2723 d.SpaceSetSublevel(space, 1);
2724 d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
2725
2726 return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
2727 }
2728
2729 /// <summary>
2730 /// Calculates the space the prim should be in by its position
2731 /// </summary>
2732 /// <param name="pos"></param>
2733 /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
2734 internal IntPtr calculateSpaceForGeom(Vector3 pos)
2735 {
2736 int[] xyspace = calculateSpaceArrayItemFromPos(pos);
2737 //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
2738 return staticPrimspace[xyspace[0], xyspace[1]];
2739 }
2740
2741 /// <summary>
2742 /// Holds the space allocation logic
2743 /// </summary>
2744 /// <param name="pos"></param>
2745 /// <returns>an array item based on the position</returns>
2746 internal int[] calculateSpaceArrayItemFromPos(Vector3 pos)
2747 {
2748 int[] returnint = new int[2];
2749
2750 returnint[0] = (int) (pos.X/metersInSpace);
2751
2752 if (returnint[0] > ((int) (259f/metersInSpace)))
2753 returnint[0] = ((int) (259f/metersInSpace));
2754 if (returnint[0] < 0)
2755 returnint[0] = 0;
2756
2757 returnint[1] = (int) (pos.Y/metersInSpace);
2758 if (returnint[1] > ((int) (259f/metersInSpace)))
2759 returnint[1] = ((int) (259f/metersInSpace));
2760 if (returnint[1] < 0)
2761 returnint[1] = 0;
2762
2763 return returnint;
2764 }
2765
2766 #endregion
2767
2768 /// <summary>
2769 /// Routine to figure out if we need to mesh this prim with our mesher
2770 /// </summary>
2771 /// <param name="pbs"></param>
2772 /// <returns></returns>
2773 internal bool needsMeshing(PrimitiveBaseShape pbs)
2774 {
2775 // most of this is redundant now as the mesher will return null if it cant mesh a prim
2776 // but we still need to check for sculptie meshing being enabled so this is the most
2777 // convenient place to do it for now...
2778
2779 // //if (pbs.PathCurve == (byte)Primitive.PathCurve.Circle && pbs.ProfileCurve == (byte)Primitive.ProfileCurve.Circle && pbs.PathScaleY <= 0.75f)
2780 // //m_log.Debug("needsMeshing: " + " pathCurve: " + pbs.PathCurve.ToString() + " profileCurve: " + pbs.ProfileCurve.ToString() + " pathScaleY: " + Primitive.UnpackPathScale(pbs.PathScaleY).ToString());
2781 int iPropertiesNotSupportedDefault = 0;
2782
2783 if (pbs.SculptEntry && !meshSculptedPrim)
2784 {
2785#if SPAM
2786 m_log.Warn("NonMesh");
2787#endif
2788 return false;
2789 }
2790
2791 // 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
2792 if (!forceSimplePrimMeshing && !pbs.SculptEntry)
2793 {
2794 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
2795 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
2796 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
2797 {
2798
2799 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
2800 && pbs.ProfileHollow == 0
2801 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
2802 && pbs.PathBegin == 0 && pbs.PathEnd == 0
2803 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
2804 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
2805 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
2806 {
2807#if SPAM
2808 m_log.Warn("NonMesh");
2809#endif
2810 return false;
2811 }
2812 }
2813 }
2814
2815 if (pbs.ProfileHollow != 0)
2816 iPropertiesNotSupportedDefault++;
2817
2818 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
2819 iPropertiesNotSupportedDefault++;
2820
2821 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
2822 iPropertiesNotSupportedDefault++;
2823
2824 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
2825 iPropertiesNotSupportedDefault++;
2826
2827 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
2828 iPropertiesNotSupportedDefault++;
2829
2830 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
2831 iPropertiesNotSupportedDefault++;
2832
2833 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
2834 iPropertiesNotSupportedDefault++;
2835
2836 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))
2837 iPropertiesNotSupportedDefault++;
2838
2839 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
2840 iPropertiesNotSupportedDefault++;
2841
2842 // test for torus
2843 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
2844 {
2845 if (pbs.PathCurve == (byte)Extrusion.Curve1)
2846 {
2847 iPropertiesNotSupportedDefault++;
2848 }
2849 }
2850 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
2851 {
2852 if (pbs.PathCurve == (byte)Extrusion.Straight)
2853 {
2854 iPropertiesNotSupportedDefault++;
2855 }
2856
2857 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
2858 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2859 {
2860 iPropertiesNotSupportedDefault++;
2861 }
2862 }
2863 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
2864 {
2865 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
2866 {
2867 iPropertiesNotSupportedDefault++;
2868 }
2869 }
2870 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
2871 {
2872 if (pbs.PathCurve == (byte)Extrusion.Straight)
2873 {
2874 iPropertiesNotSupportedDefault++;
2875 }
2876 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
2877 {
2878 iPropertiesNotSupportedDefault++;
2879 }
2880 }
2881
2882 if (pbs.SculptEntry && meshSculptedPrim)
2883 iPropertiesNotSupportedDefault++;
2884
2885 if (iPropertiesNotSupportedDefault == 0)
2886 {
2887#if SPAM
2888 m_log.Warn("NonMesh");
2889#endif
2890 return false;
2891 }
2892#if SPAM
2893 m_log.Debug("Mesh");
2894#endif
2895 return true;
2896 }
2897
2898 /// <summary>
2899 /// Called after our prim properties are set Scale, position etc.
2900 /// </summary>
2901 /// <remarks>
2902 /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
2903 /// This assures us that we have no race conditions
2904 /// </remarks>
2905 /// <param name="actor"></param>
2906 public override void AddPhysicsActorTaint(PhysicsActor actor)
2907 {
2908 if (actor is OdePrim)
2909 {
2910 OdePrim taintedprim = ((OdePrim)actor);
2911 lock (_taintedPrims)
2912 _taintedPrims.Add(taintedprim);
2913 }
2914 else if (actor is OdeCharacter)
2915 {
2916 OdeCharacter taintedchar = ((OdeCharacter)actor);
2917 lock (_taintedActors)
2918 {
2919 _taintedActors.Add(taintedchar);
2920 if (taintedchar.bad)
2921 m_log.ErrorFormat("[ODE SCENE]: Added BAD actor {0} to tainted actors", taintedchar.m_uuid);
2922 }
2923 }
2924 }
2925
2926 /// <summary>
2927 /// This is our main simulate loop
2928 /// </summary>
2929 /// <remarks>
2930 /// It's thread locked by a Mutex in the scene.
2931 /// It holds Collisions, it instructs ODE to step through the physical reactions
2932 /// It moves the objects around in memory
2933 /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
2934 /// </remarks>
2935 /// <param name="timeStep"></param>
2936 /// <returns>The number of frames simulated over that period.</returns>
2937 public override float Simulate(float timeStep)
2938 {
2939 if (!_worldInitialized) return 11f;
2940
2941 int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0;
2942 int tempTick = 0, tempTick2 = 0;
2943
2944 if (framecount >= int.MaxValue)
2945 framecount = 0;
2946
2947 framecount++;
2948
2949 float fps = 0;
2950
2951 float timeLeft = timeStep;
2952
2953 //m_log.Info(timeStep.ToString());
2954// step_time += timeSte
2955//
2956// // If We're loaded down by something else,
2957// // or debugging with the Visual Studio project on pause
2958// // skip a few frames to catch up gracefully.
2959// // without shooting the physicsactors all over the place
2960//
2961// if (step_time >= m_SkipFramesAtms)
2962// {
2963// // Instead of trying to catch up, it'll do 5 physics frames only
2964// step_time = ODE_STEPSIZE;
2965// m_physicsiterations = 5;
2966// }
2967// else
2968// {
2969// m_physicsiterations = 10;
2970// }
2971
2972 // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential
2973 // deadlock if the collision event tries to lock something else later on which is already locked by a
2974 // caller that is adding or removing the collision event.
2975 lock (m_collisionEventActorsChanges)
2976 {
2977 foreach (KeyValuePair<uint, PhysicsActor> kvp in m_collisionEventActorsChanges)
2978 {
2979 if (kvp.Value == null)
2980 m_collisionEventActors.Remove(kvp.Key);
2981 else
2982 m_collisionEventActors[kvp.Key] = kvp.Value;
2983 }
2984
2985 m_collisionEventActorsChanges.Clear();
2986 }
2987
2988 if (SupportsNINJAJoints)
2989 {
2990 DeleteRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2991 CreateRequestedJoints(); // this must be outside of the lock (OdeLock) to avoid deadlocks
2992 }
2993
2994 lock (OdeLock)
2995 {
2996 // Process 10 frames if the sim is running normal..
2997 // process 5 frames if the sim is running slow
2998 //try
2999 //{
3000 //d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
3001 //}
3002 //catch (StackOverflowException)
3003 //{
3004 // m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
3005 // ode.drelease(world);
3006 //base.TriggerPhysicsBasedRestart();
3007 //}
3008
3009 // Figure out the Frames Per Second we're going at.
3010 //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
3011
3012 fps = (timeStep / ODE_STEPSIZE) * 1000;
3013 // HACK: Using a time dilation of 1.0 to debug rubberbanding issues
3014 //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f);
3015
3016 while (timeLeft > 0.0f)
3017 {
3018 try
3019 {
3020 if (CollectStats)
3021 tempTick = Util.EnvironmentTickCount();
3022
3023 lock (_taintedActors)
3024 {
3025 foreach (OdeCharacter character in _taintedActors)
3026 character.ProcessTaints();
3027
3028 _taintedActors.Clear();
3029 }
3030
3031 if (CollectStats)
3032 {
3033 tempTick2 = Util.EnvironmentTickCount();
3034 m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3035 tempTick = tempTick2;
3036 }
3037
3038 lock (_taintedPrims)
3039 {
3040 foreach (OdePrim prim in _taintedPrims)
3041 {
3042 if (prim.m_taintremove)
3043 {
3044// Console.WriteLine("Simulate calls RemovePrimThreadLocked for {0}", prim.Name);
3045 RemovePrimThreadLocked(prim);
3046 }
3047 else
3048 {
3049// Console.WriteLine("Simulate calls ProcessTaints for {0}", prim.Name);
3050 prim.ProcessTaints();
3051 }
3052
3053 prim.m_collisionscore = 0;
3054
3055 // This loop can block up the Heartbeat for a very long time on large regions.
3056 // We need to let the Watchdog know that the Heartbeat is not dead
3057 // NOTE: This is currently commented out, but if things like OAR loading are
3058 // timing the heartbeat out we will need to uncomment it
3059 //Watchdog.UpdateThread();
3060 }
3061
3062 if (SupportsNINJAJoints)
3063 SimulatePendingNINJAJoints();
3064
3065 _taintedPrims.Clear();
3066 }
3067
3068 if (CollectStats)
3069 {
3070 tempTick2 = Util.EnvironmentTickCount();
3071 m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3072 tempTick = tempTick2;
3073 }
3074
3075 // Move characters
3076 foreach (OdeCharacter actor in _characters)
3077 actor.Move(defects);
3078
3079 if (defects.Count != 0)
3080 {
3081 foreach (OdeCharacter actor in defects)
3082 {
3083 m_log.ErrorFormat(
3084 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when moving",
3085 actor.Name, actor.LocalID, Name);
3086
3087 RemoveCharacter(actor);
3088 actor.DestroyOdeStructures();
3089 }
3090
3091 defects.Clear();
3092 }
3093
3094 if (CollectStats)
3095 {
3096 tempTick2 = Util.EnvironmentTickCount();
3097 m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3098 tempTick = tempTick2;
3099 }
3100
3101 // Move other active objects
3102 foreach (OdePrim prim in _activeprims)
3103 {
3104 prim.m_collisionscore = 0;
3105 prim.Move(timeStep);
3106 }
3107
3108 if (CollectStats)
3109 {
3110 tempTick2 = Util.EnvironmentTickCount();
3111 m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3112 tempTick = tempTick2;
3113 }
3114
3115 //if ((framecount % m_randomizeWater) == 0)
3116 // randomizeWater(waterlevel);
3117
3118 //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests();
3119 m_rayCastManager.ProcessQueuedRequests();
3120
3121 if (CollectStats)
3122 {
3123 tempTick2 = Util.EnvironmentTickCount();
3124 m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3125 tempTick = tempTick2;
3126 }
3127
3128 collision_optimized();
3129
3130 if (CollectStats)
3131 {
3132 tempTick2 = Util.EnvironmentTickCount();
3133 m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3134 tempTick = tempTick2;
3135 }
3136
3137 foreach (PhysicsActor obj in m_collisionEventActors.Values)
3138 {
3139// m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID);
3140
3141 switch ((ActorTypes)obj.PhysicsActorType)
3142 {
3143 case ActorTypes.Agent:
3144 OdeCharacter cobj = (OdeCharacter)obj;
3145 cobj.AddCollisionFrameTime(100);
3146 cobj.SendCollisions();
3147 break;
3148
3149 case ActorTypes.Prim:
3150 OdePrim pobj = (OdePrim)obj;
3151 pobj.SendCollisions();
3152 break;
3153 }
3154 }
3155
3156// if (m_global_contactcount > 0)
3157// m_log.DebugFormat(
3158// "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount);
3159
3160 m_global_contactcount = 0;
3161
3162 if (CollectStats)
3163 {
3164 tempTick2 = Util.EnvironmentTickCount();
3165 m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3166 tempTick = tempTick2;
3167 }
3168
3169 d.WorldQuickStep(world, ODE_STEPSIZE);
3170
3171 if (CollectStats)
3172 m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
3173
3174 d.JointGroupEmpty(contactgroup);
3175 }
3176 catch (Exception e)
3177 {
3178 m_log.ErrorFormat("[ODE SCENE]: {0}, {1}, {2}", e.Message, e.TargetSite, e);
3179 }
3180
3181 timeLeft -= ODE_STEPSIZE;
3182 }
3183
3184 if (CollectStats)
3185 tempTick = Util.EnvironmentTickCount();
3186
3187 foreach (OdeCharacter actor in _characters)
3188 {
3189 if (actor.bad)
3190 m_log.ErrorFormat("[ODE SCENE]: BAD Actor {0} in _characters list was not removed?", actor.m_uuid);
3191
3192 actor.UpdatePositionAndVelocity(defects);
3193 }
3194
3195 if (defects.Count != 0)
3196 {
3197 foreach (OdeCharacter actor in defects)
3198 {
3199 m_log.ErrorFormat(
3200 "[ODE SCENE]: Removing physics character {0} {1} from physics scene {2} due to defect found when updating position and velocity",
3201 actor.Name, actor.LocalID, Name);
3202
3203 RemoveCharacter(actor);
3204 actor.DestroyOdeStructures();
3205 }
3206
3207 defects.Clear();
3208 }
3209
3210 if (CollectStats)
3211 {
3212 tempTick2 = Util.EnvironmentTickCount();
3213 m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick);
3214 tempTick = tempTick2;
3215 }
3216
3217 //if (timeStep < 0.2f)
3218
3219 foreach (OdePrim prim in _activeprims)
3220 {
3221 if (prim.IsPhysical && (d.BodyIsEnabled(prim.Body) || !prim._zeroFlag))
3222 {
3223 prim.UpdatePositionAndVelocity();
3224
3225 if (SupportsNINJAJoints)
3226 SimulateActorPendingJoints(prim);
3227 }
3228 }
3229
3230 if (CollectStats)
3231 m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick);
3232
3233 //DumpJointInfo();
3234
3235 // Finished with all sim stepping. If requested, dump world state to file for debugging.
3236 // TODO: This call to the export function is already inside lock (OdeLock) - but is an extra lock needed?
3237 // TODO: This overwrites all dump files in-place. Should this be a growing logfile, or separate snapshots?
3238 if (physics_logging && (physics_logging_interval > 0) && (framecount % physics_logging_interval == 0))
3239 {
3240 string fname = "state-" + world.ToString() + ".DIF"; // give each physics world a separate filename
3241 string prefix = "world" + world.ToString(); // prefix for variable names in exported .DIF file
3242
3243 if (physics_logging_append_existing_logfile)
3244 {
3245 string header = "-------------- START OF PHYSICS FRAME " + framecount.ToString() + " --------------";
3246 TextWriter fwriter = File.AppendText(fname);
3247 fwriter.WriteLine(header);
3248 fwriter.Close();
3249 }
3250
3251 d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix);
3252 }
3253
3254 latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun);
3255
3256 // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics
3257 // has a max of 100 ms to run theoretically.
3258 // If the main loop stalls, it calls Simulate later which makes the tick count ms larger.
3259 // If Physics stalls, it takes longer which makes the tick count ms larger.
3260
3261 if (latertickcount < 100)
3262 {
3263 m_timeDilation = 1.0f;
3264 }
3265 else
3266 {
3267 m_timeDilation = 100f / latertickcount;
3268 //m_timeDilation = Math.Min((Math.Max(100 - (Util.EnvironmentTickCount() - tickCountFrameRun), 1) / 100f), 1.0f);
3269 }
3270
3271 tickCountFrameRun = Util.EnvironmentTickCount();
3272
3273 if (CollectStats)
3274 m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick);
3275 }
3276
3277 return fps;
3278 }
3279
3280 /// <summary>
3281 /// Simulate pending NINJA joints.
3282 /// </summary>
3283 /// <remarks>
3284 /// Called by the main Simulate() loop if NINJA joints are active. Should not be called from anywhere else.
3285 /// </remarks>
3286 private void SimulatePendingNINJAJoints()
3287 {
3288 // Create pending joints, if possible
3289
3290 // joints can only be processed after ALL bodies are processed (and exist in ODE), since creating
3291 // a joint requires specifying the body id of both involved bodies
3292 if (pendingJoints.Count > 0)
3293 {
3294 List<PhysicsJoint> successfullyProcessedPendingJoints = new List<PhysicsJoint>();
3295 //DoJointErrorMessage(joints_connecting_actor, "taint: " + pendingJoints.Count + " pending joints");
3296 foreach (PhysicsJoint joint in pendingJoints)
3297 {
3298 //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams);
3299 string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
3300 List<IntPtr> jointBodies = new List<IntPtr>();
3301 bool allJointBodiesAreReady = true;
3302 foreach (string jointParam in jointParams)
3303 {
3304 if (jointParam == "NULL")
3305 {
3306 //DoJointErrorMessage(joint, "attaching NULL joint to world");
3307 jointBodies.Add(IntPtr.Zero);
3308 }
3309 else
3310 {
3311 //DoJointErrorMessage(joint, "looking for prim name: " + jointParam);
3312 bool foundPrim = false;
3313 lock (_prims)
3314 {
3315 foreach (OdePrim prim in _prims) // FIXME: inefficient
3316 {
3317 if (prim.SOPName == jointParam)
3318 {
3319 //DoJointErrorMessage(joint, "found for prim name: " + jointParam);
3320 if (prim.IsPhysical && prim.Body != IntPtr.Zero)
3321 {
3322 jointBodies.Add(prim.Body);
3323 foundPrim = true;
3324 break;
3325 }
3326 else
3327 {
3328 DoJointErrorMessage(joint, "prim name " + jointParam +
3329 " exists but is not (yet) physical; deferring joint creation. " +
3330 "IsPhysical property is " + prim.IsPhysical +
3331 " and body is " + prim.Body);
3332 foundPrim = false;
3333 break;
3334 }
3335 }
3336 }
3337 }
3338 if (foundPrim)
3339 {
3340 // all is fine
3341 }
3342 else
3343 {
3344 allJointBodiesAreReady = false;
3345 break;
3346 }
3347 }
3348 }
3349
3350 if (allJointBodiesAreReady)
3351 {
3352 //DoJointErrorMessage(joint, "allJointBodiesAreReady for " + joint.ObjectNameInScene + " with parms " + joint.RawParams);
3353 if (jointBodies[0] == jointBodies[1])
3354 {
3355 DoJointErrorMessage(joint, "ERROR: joint cannot be created; the joint bodies are the same, body1==body2. Raw body is " + jointBodies[0] + ". raw parms: " + joint.RawParams);
3356 }
3357 else
3358 {
3359 switch (joint.Type)
3360 {
3361 case PhysicsJointType.Ball:
3362 {
3363 IntPtr odeJoint;
3364 //DoJointErrorMessage(joint, "ODE creating ball joint ");
3365 odeJoint = d.JointCreateBall(world, IntPtr.Zero);
3366 //DoJointErrorMessage(joint, "ODE attaching ball joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3367 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3368 //DoJointErrorMessage(joint, "ODE setting ball anchor: " + odeJoint + " to vec:" + joint.Position);
3369 d.JointSetBallAnchor(odeJoint,
3370 joint.Position.X,
3371 joint.Position.Y,
3372 joint.Position.Z);
3373 //DoJointErrorMessage(joint, "ODE joint setting OK");
3374 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b0: ");
3375 //DoJointErrorMessage(joint, "" + (jointBodies[0] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[0]) : "fixed environment"));
3376 //DoJointErrorMessage(joint, "The ball joint's bodies are here: b1: ");
3377 //DoJointErrorMessage(joint, "" + (jointBodies[1] != IntPtr.Zero ? "" + d.BodyGetPosition(jointBodies[1]) : "fixed environment"));
3378
3379 if (joint is OdePhysicsJoint)
3380 {
3381 ((OdePhysicsJoint)joint).jointID = odeJoint;
3382 }
3383 else
3384 {
3385 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3386 }
3387 }
3388 break;
3389 case PhysicsJointType.Hinge:
3390 {
3391 IntPtr odeJoint;
3392 //DoJointErrorMessage(joint, "ODE creating hinge joint ");
3393 odeJoint = d.JointCreateHinge(world, IntPtr.Zero);
3394 //DoJointErrorMessage(joint, "ODE attaching hinge joint: " + odeJoint + " with b1:" + jointBodies[0] + " b2:" + jointBodies[1]);
3395 d.JointAttach(odeJoint, jointBodies[0], jointBodies[1]);
3396 //DoJointErrorMessage(joint, "ODE setting hinge anchor: " + odeJoint + " to vec:" + joint.Position);
3397 d.JointSetHingeAnchor(odeJoint,
3398 joint.Position.X,
3399 joint.Position.Y,
3400 joint.Position.Z);
3401 // We use the orientation of the x-axis of the joint's coordinate frame
3402 // as the axis for the hinge.
3403
3404 // Therefore, we must get the joint's coordinate frame based on the
3405 // joint.Rotation field, which originates from the orientation of the
3406 // joint's proxy object in the scene.
3407
3408 // The joint's coordinate frame is defined as the transformation matrix
3409 // that converts a vector from joint-local coordinates into world coordinates.
3410 // World coordinates are defined as the XYZ coordinate system of the sim,
3411 // as shown in the top status-bar of the viewer.
3412
3413 // Once we have the joint's coordinate frame, we extract its X axis (AtAxis)
3414 // and use that as the hinge axis.
3415
3416 //joint.Rotation.Normalize();
3417 Matrix4 proxyFrame = Matrix4.CreateFromQuaternion(joint.Rotation);
3418
3419 // Now extract the X axis of the joint's coordinate frame.
3420
3421 // Do not try to use proxyFrame.AtAxis or you will become mired in the
3422 // tar pit of transposed, inverted, and generally messed-up orientations.
3423 // (In other words, Matrix4.AtAxis() is borked.)
3424 // Vector3 jointAxis = proxyFrame.AtAxis; <--- this path leadeth to madness
3425
3426 // Instead, compute the X axis of the coordinate frame by transforming
3427 // the (1,0,0) vector. At least that works.
3428
3429 //m_log.Debug("PHY: making axis: complete matrix is " + proxyFrame);
3430 Vector3 jointAxis = Vector3.Transform(Vector3.UnitX, proxyFrame);
3431 //m_log.Debug("PHY: making axis: hinge joint axis is " + jointAxis);
3432 //DoJointErrorMessage(joint, "ODE setting hinge axis: " + odeJoint + " to vec:" + jointAxis);
3433 d.JointSetHingeAxis(odeJoint,
3434 jointAxis.X,
3435 jointAxis.Y,
3436 jointAxis.Z);
3437 //d.JointSetHingeParam(odeJoint, (int)dParam.CFM, 0.1f);
3438 if (joint is OdePhysicsJoint)
3439 {
3440 ((OdePhysicsJoint)joint).jointID = odeJoint;
3441 }
3442 else
3443 {
3444 DoJointErrorMessage(joint, "WARNING: non-ode joint in ODE!");
3445 }
3446 }
3447 break;
3448 }
3449 successfullyProcessedPendingJoints.Add(joint);
3450 }
3451 }
3452 else
3453 {
3454 DoJointErrorMessage(joint, "joint could not yet be created; still pending");
3455 }
3456 }
3457
3458 foreach (PhysicsJoint successfullyProcessedJoint in successfullyProcessedPendingJoints)
3459 {
3460 //DoJointErrorMessage(successfullyProcessedJoint, "finalizing succesfully procsssed joint " + successfullyProcessedJoint.ObjectNameInScene + " parms " + successfullyProcessedJoint.RawParams);
3461 //DoJointErrorMessage(successfullyProcessedJoint, "removing from pending");
3462 InternalRemovePendingJoint(successfullyProcessedJoint);
3463 //DoJointErrorMessage(successfullyProcessedJoint, "adding to active");
3464 InternalAddActiveJoint(successfullyProcessedJoint);
3465 //DoJointErrorMessage(successfullyProcessedJoint, "done");
3466 }
3467 }
3468 }
3469
3470 /// <summary>
3471 /// Simulate the joint proxies of a NINJA actor.
3472 /// </summary>
3473 /// <remarks>
3474 /// Called as part of the Simulate() loop if NINJA physics is active. Must only be called from there.
3475 /// </remarks>
3476 /// <param name="actor"></param>
3477 private void SimulateActorPendingJoints(OdePrim actor)
3478 {
3479 // If an actor moved, move its joint proxy objects as well.
3480 // There seems to be an event PhysicsActor.OnPositionUpdate that could be used
3481 // for this purpose but it is never called! So we just do the joint
3482 // movement code here.
3483
3484 if (actor.SOPName != null &&
3485 joints_connecting_actor.ContainsKey(actor.SOPName) &&
3486 joints_connecting_actor[actor.SOPName] != null &&
3487 joints_connecting_actor[actor.SOPName].Count > 0)
3488 {
3489 foreach (PhysicsJoint affectedJoint in joints_connecting_actor[actor.SOPName])
3490 {
3491 if (affectedJoint.IsInPhysicsEngine)
3492 {
3493 DoJointMoved(affectedJoint);
3494 }
3495 else
3496 {
3497 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);
3498 }
3499 }
3500 }
3501 }
3502
3503 public override void GetResults()
3504 {
3505 }
3506
3507 public override bool IsThreaded
3508 {
3509 // for now we won't be multithreaded
3510 get { return false; }
3511 }
3512
3513 #region ODE Specific Terrain Fixes
3514 private float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
3515 {
3516 float[] returnarr = new float[262144];
3517 float[,] resultarr = new float[(int)WorldExtents.X, (int)WorldExtents.Y];
3518
3519 // Filling out the array into its multi-dimensional components
3520 for (int y = 0; y < WorldExtents.Y; y++)
3521 {
3522 for (int x = 0; x < WorldExtents.X; x++)
3523 {
3524 resultarr[y, x] = heightMap[y * (int)WorldExtents.Y + x];
3525 }
3526 }
3527
3528 // Resize using Nearest Neighbour
3529
3530 // This particular way is quick but it only works on a multiple of the original
3531
3532 // The idea behind this method can be described with the following diagrams
3533 // second pass and third pass happen in the same loop really.. just separated
3534 // them to show what this does.
3535
3536 // First Pass
3537 // ResultArr:
3538 // 1,1,1,1,1,1
3539 // 1,1,1,1,1,1
3540 // 1,1,1,1,1,1
3541 // 1,1,1,1,1,1
3542 // 1,1,1,1,1,1
3543 // 1,1,1,1,1,1
3544
3545 // Second Pass
3546 // ResultArr2:
3547 // 1,,1,,1,,1,,1,,1,
3548 // ,,,,,,,,,,
3549 // 1,,1,,1,,1,,1,,1,
3550 // ,,,,,,,,,,
3551 // 1,,1,,1,,1,,1,,1,
3552 // ,,,,,,,,,,
3553 // 1,,1,,1,,1,,1,,1,
3554 // ,,,,,,,,,,
3555 // 1,,1,,1,,1,,1,,1,
3556 // ,,,,,,,,,,
3557 // 1,,1,,1,,1,,1,,1,
3558
3559 // Third pass fills in the blanks
3560 // ResultArr2:
3561 // 1,1,1,1,1,1,1,1,1,1,1,1
3562 // 1,1,1,1,1,1,1,1,1,1,1,1
3563 // 1,1,1,1,1,1,1,1,1,1,1,1
3564 // 1,1,1,1,1,1,1,1,1,1,1,1
3565 // 1,1,1,1,1,1,1,1,1,1,1,1
3566 // 1,1,1,1,1,1,1,1,1,1,1,1
3567 // 1,1,1,1,1,1,1,1,1,1,1,1
3568 // 1,1,1,1,1,1,1,1,1,1,1,1
3569 // 1,1,1,1,1,1,1,1,1,1,1,1
3570 // 1,1,1,1,1,1,1,1,1,1,1,1
3571 // 1,1,1,1,1,1,1,1,1,1,1,1
3572
3573 // X,Y = .
3574 // X+1,y = ^
3575 // X,Y+1 = *
3576 // X+1,Y+1 = #
3577
3578 // Filling in like this;
3579 // .*
3580 // ^#
3581 // 1st .
3582 // 2nd *
3583 // 3rd ^
3584 // 4th #
3585 // on single loop.
3586
3587 float[,] resultarr2 = new float[512, 512];
3588 for (int y = 0; y < WorldExtents.Y; y++)
3589 {
3590 for (int x = 0; x < WorldExtents.X; x++)
3591 {
3592 resultarr2[y * 2, x * 2] = resultarr[y, x];
3593
3594 if (y < WorldExtents.Y)
3595 {
3596 resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
3597 }
3598 if (x < WorldExtents.X)
3599 {
3600 resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
3601 }
3602 if (x < WorldExtents.X && y < WorldExtents.Y)
3603 {
3604 resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
3605 }
3606 }
3607 }
3608
3609 //Flatten out the array
3610 int i = 0;
3611 for (int y = 0; y < 512; y++)
3612 {
3613 for (int x = 0; x < 512; x++)
3614 {
3615 if (resultarr2[y, x] <= 0)
3616 returnarr[i] = 0.0000001f;
3617 else
3618 returnarr[i] = resultarr2[y, x];
3619
3620 i++;
3621 }
3622 }
3623
3624 return returnarr;
3625 }
3626
3627 private float[] ResizeTerrain512Interpolation(float[] heightMap)
3628 {
3629 float[] returnarr = new float[262144];
3630 float[,] resultarr = new float[512,512];
3631
3632 // Filling out the array into its multi-dimensional components
3633 for (int y = 0; y < 256; y++)
3634 {
3635 for (int x = 0; x < 256; x++)
3636 {
3637 resultarr[y, x] = heightMap[y * 256 + x];
3638 }
3639 }
3640
3641 // Resize using interpolation
3642
3643 // This particular way is quick but it only works on a multiple of the original
3644
3645 // The idea behind this method can be described with the following diagrams
3646 // second pass and third pass happen in the same loop really.. just separated
3647 // them to show what this does.
3648
3649 // First Pass
3650 // ResultArr:
3651 // 1,1,1,1,1,1
3652 // 1,1,1,1,1,1
3653 // 1,1,1,1,1,1
3654 // 1,1,1,1,1,1
3655 // 1,1,1,1,1,1
3656 // 1,1,1,1,1,1
3657
3658 // Second Pass
3659 // ResultArr2:
3660 // 1,,1,,1,,1,,1,,1,
3661 // ,,,,,,,,,,
3662 // 1,,1,,1,,1,,1,,1,
3663 // ,,,,,,,,,,
3664 // 1,,1,,1,,1,,1,,1,
3665 // ,,,,,,,,,,
3666 // 1,,1,,1,,1,,1,,1,
3667 // ,,,,,,,,,,
3668 // 1,,1,,1,,1,,1,,1,
3669 // ,,,,,,,,,,
3670 // 1,,1,,1,,1,,1,,1,
3671
3672 // Third pass fills in the blanks
3673 // ResultArr2:
3674 // 1,1,1,1,1,1,1,1,1,1,1,1
3675 // 1,1,1,1,1,1,1,1,1,1,1,1
3676 // 1,1,1,1,1,1,1,1,1,1,1,1
3677 // 1,1,1,1,1,1,1,1,1,1,1,1
3678 // 1,1,1,1,1,1,1,1,1,1,1,1
3679 // 1,1,1,1,1,1,1,1,1,1,1,1
3680 // 1,1,1,1,1,1,1,1,1,1,1,1
3681 // 1,1,1,1,1,1,1,1,1,1,1,1
3682 // 1,1,1,1,1,1,1,1,1,1,1,1
3683 // 1,1,1,1,1,1,1,1,1,1,1,1
3684 // 1,1,1,1,1,1,1,1,1,1,1,1
3685
3686 // X,Y = .
3687 // X+1,y = ^
3688 // X,Y+1 = *
3689 // X+1,Y+1 = #
3690
3691 // Filling in like this;
3692 // .*
3693 // ^#
3694 // 1st .
3695 // 2nd *
3696 // 3rd ^
3697 // 4th #
3698 // on single loop.
3699
3700 float[,] resultarr2 = new float[512,512];
3701 for (int y = 0; y < (int)Constants.RegionSize; y++)
3702 {
3703 for (int x = 0; x < (int)Constants.RegionSize; x++)
3704 {
3705 resultarr2[y*2, x*2] = resultarr[y, x];
3706
3707 if (y < (int)Constants.RegionSize)
3708 {
3709 if (y + 1 < (int)Constants.RegionSize)
3710 {
3711 if (x + 1 < (int)Constants.RegionSize)
3712 {
3713 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
3714 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3715 }
3716 else
3717 {
3718 resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
3719 }
3720 }
3721 else
3722 {
3723 resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
3724 }
3725 }
3726 if (x < (int)Constants.RegionSize)
3727 {
3728 if (x + 1 < (int)Constants.RegionSize)
3729 {
3730 if (y + 1 < (int)Constants.RegionSize)
3731 {
3732 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3733 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3734 }
3735 else
3736 {
3737 resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
3738 }
3739 }
3740 else
3741 {
3742 resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
3743 }
3744 }
3745 if (x < (int)Constants.RegionSize && y < (int)Constants.RegionSize)
3746 {
3747 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize))
3748 {
3749 resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
3750 resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
3751 }
3752 else
3753 {
3754 resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
3755 }
3756 }
3757 }
3758 }
3759 //Flatten out the array
3760 int i = 0;
3761 for (int y = 0; y < 512; y++)
3762 {
3763 for (int x = 0; x < 512; x++)
3764 {
3765 if (Single.IsNaN(resultarr2[y, x]) || Single.IsInfinity(resultarr2[y, x]))
3766 {
3767 m_log.Warn("[ODE SCENE]: Non finite heightfield element detected. Setting it to 0");
3768 resultarr2[y, x] = 0;
3769 }
3770 returnarr[i] = resultarr2[y, x];
3771 i++;
3772 }
3773 }
3774
3775 return returnarr;
3776 }
3777
3778 #endregion
3779
3780 public override void SetTerrain(float[] heightMap)
3781 {
3782 if (m_worldOffset != Vector3.Zero && m_parentScene != null)
3783 {
3784 if (m_parentScene is OdeScene)
3785 {
3786 ((OdeScene)m_parentScene).SetTerrain(heightMap, m_worldOffset);
3787 }
3788 }
3789 else
3790 {
3791 SetTerrain(heightMap, m_worldOffset);
3792 }
3793 }
3794
3795 private void SetTerrain(float[] heightMap, Vector3 pOffset)
3796 {
3797 int startTime = Util.EnvironmentTickCount();
3798 m_log.DebugFormat("[ODE SCENE]: Setting terrain for {0} with offset {1}", Name, pOffset);
3799
3800 // this._heightmap[i] = (double)heightMap[i];
3801 // dbm (danx0r) -- creating a buffer zone of one extra sample all around
3802 //_origheightmap = heightMap;
3803
3804 float[] _heightmap;
3805
3806 // zero out a heightmap array float array (single dimension [flattened]))
3807 //if ((int)Constants.RegionSize == 256)
3808 // _heightmap = new float[514 * 514];
3809 //else
3810
3811 _heightmap = new float[(((int)Constants.RegionSize + 2) * ((int)Constants.RegionSize + 2))];
3812
3813 uint heightmapWidth = Constants.RegionSize + 1;
3814 uint heightmapHeight = Constants.RegionSize + 1;
3815
3816 uint heightmapWidthSamples;
3817
3818 uint heightmapHeightSamples;
3819
3820 //if (((int)Constants.RegionSize) == 256)
3821 //{
3822 // heightmapWidthSamples = 2 * (uint)Constants.RegionSize + 2;
3823 // heightmapHeightSamples = 2 * (uint)Constants.RegionSize + 2;
3824 // heightmapWidth++;
3825 // heightmapHeight++;
3826 //}
3827 //else
3828 //{
3829
3830 heightmapWidthSamples = (uint)Constants.RegionSize + 1;
3831 heightmapHeightSamples = (uint)Constants.RegionSize + 1;
3832 //}
3833
3834 const float scale = 1.0f;
3835 const float offset = 0.0f;
3836 const float thickness = 0.2f;
3837 const int wrap = 0;
3838
3839 int regionsize = (int) Constants.RegionSize + 2;
3840 //Double resolution
3841 //if (((int)Constants.RegionSize) == 256)
3842 // heightMap = ResizeTerrain512Interpolation(heightMap);
3843
3844
3845 // if (((int)Constants.RegionSize) == 256 && (int)Constants.RegionSize == 256)
3846 // regionsize = 512;
3847
3848 float hfmin = 2000;
3849 float hfmax = -2000;
3850
3851 for (int x = 0; x < heightmapWidthSamples; x++)
3852 {
3853 for (int y = 0; y < heightmapHeightSamples; y++)
3854 {
3855 int xx = Util.Clip(x - 1, 0, regionsize - 1);
3856 int yy = Util.Clip(y - 1, 0, regionsize - 1);
3857
3858
3859 float val= heightMap[yy * (int)Constants.RegionSize + xx];
3860 _heightmap[x * ((int)Constants.RegionSize + 2) + y] = val;
3861
3862 hfmin = (val < hfmin) ? val : hfmin;
3863 hfmax = (val > hfmax) ? val : hfmax;
3864 }
3865 }
3866
3867 lock (OdeLock)
3868 {
3869 IntPtr GroundGeom = IntPtr.Zero;
3870 if (RegionTerrain.TryGetValue(pOffset, out GroundGeom))
3871 {
3872 RegionTerrain.Remove(pOffset);
3873 if (GroundGeom != IntPtr.Zero)
3874 {
3875 if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
3876 {
3877 TerrainHeightFieldHeights.Remove(GroundGeom);
3878 }
3879 d.SpaceRemove(space, GroundGeom);
3880 d.GeomDestroy(GroundGeom);
3881 }
3882
3883 }
3884 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
3885 d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth + 1, heightmapHeight + 1,
3886 (int)heightmapWidthSamples + 1, (int)heightmapHeightSamples + 1, scale,
3887 offset, thickness, wrap);
3888 d.GeomHeightfieldDataSetBounds(HeightmapData, hfmin - 1, hfmax + 1);
3889 GroundGeom = d.CreateHeightfield(space, HeightmapData, 1);
3890 if (GroundGeom != IntPtr.Zero)
3891 {
3892 d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
3893 d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
3894
3895 }
3896 geom_name_map[GroundGeom] = "Terrain";
3897
3898 d.Matrix3 R = new d.Matrix3();
3899
3900 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
3901 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
3902 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
3903
3904 q1 = q1 * q2;
3905 //q1 = q1 * q3;
3906 Vector3 v3;
3907 float angle;
3908 q1.GetAxisAngle(out v3, out angle);
3909
3910 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
3911 d.GeomSetRotation(GroundGeom, ref R);
3912 d.GeomSetPosition(GroundGeom, (pOffset.X + ((int)Constants.RegionSize * 0.5f)), (pOffset.Y + ((int)Constants.RegionSize * 0.5f)), 0);
3913 IntPtr testGround = IntPtr.Zero;
3914 if (RegionTerrain.TryGetValue(pOffset, out testGround))
3915 {
3916 RegionTerrain.Remove(pOffset);
3917 }
3918 RegionTerrain.Add(pOffset, GroundGeom, GroundGeom);
3919 TerrainHeightFieldHeights.Add(GroundGeom,_heightmap);
3920 }
3921
3922 m_log.DebugFormat(
3923 "[ODE SCENE]: Setting terrain for {0} took {1}ms", Name, Util.EnvironmentTickCountSubtract(startTime));
3924 }
3925
3926 public override void DeleteTerrain()
3927 {
3928 }
3929
3930 internal float GetWaterLevel()
3931 {
3932 return waterlevel;
3933 }
3934
3935 public override bool SupportsCombining()
3936 {
3937 return true;
3938 }
3939
3940// public override void UnCombine(PhysicsScene pScene)
3941// {
3942// IntPtr localGround = IntPtr.Zero;
3943//// float[] localHeightfield;
3944// bool proceed = false;
3945// List<IntPtr> geomDestroyList = new List<IntPtr>();
3946//
3947// lock (OdeLock)
3948// {
3949// if (RegionTerrain.TryGetValue(Vector3.Zero, out localGround))
3950// {
3951// foreach (IntPtr geom in TerrainHeightFieldHeights.Keys)
3952// {
3953// if (geom == localGround)
3954// {
3955//// localHeightfield = TerrainHeightFieldHeights[geom];
3956// proceed = true;
3957// }
3958// else
3959// {
3960// geomDestroyList.Add(geom);
3961// }
3962// }
3963//
3964// if (proceed)
3965// {
3966// m_worldOffset = Vector3.Zero;
3967// WorldExtents = new Vector2((int)Constants.RegionSize, (int)Constants.RegionSize);
3968// m_parentScene = null;
3969//
3970// foreach (IntPtr g in geomDestroyList)
3971// {
3972// // removingHeightField needs to be done or the garbage collector will
3973// // collect the terrain data before we tell ODE to destroy it causing
3974// // memory corruption
3975// if (TerrainHeightFieldHeights.ContainsKey(g))
3976// {
3977//// float[] removingHeightField = TerrainHeightFieldHeights[g];
3978// TerrainHeightFieldHeights.Remove(g);
3979//
3980// if (RegionTerrain.ContainsKey(g))
3981// {
3982// RegionTerrain.Remove(g);
3983// }
3984//
3985// d.GeomDestroy(g);
3986// //removingHeightField = new float[0];
3987// }
3988// }
3989//
3990// }
3991// else
3992// {
3993// m_log.Warn("[PHYSICS]: Couldn't proceed with UnCombine. Region has inconsistant data.");
3994// }
3995// }
3996// }
3997// }
3998
3999 public override void SetWaterLevel(float baseheight)
4000 {
4001 waterlevel = baseheight;
4002 randomizeWater(waterlevel);
4003 }
4004
4005 private void randomizeWater(float baseheight)
4006 {
4007 const uint heightmapWidth = m_regionWidth + 2;
4008 const uint heightmapHeight = m_regionHeight + 2;
4009 const uint heightmapWidthSamples = m_regionWidth + 2;
4010 const uint heightmapHeightSamples = m_regionHeight + 2;
4011 const float scale = 1.0f;
4012 const float offset = 0.0f;
4013 const float thickness = 2.9f;
4014 const int wrap = 0;
4015
4016 for (int i = 0; i < (258 * 258); i++)
4017 {
4018 _watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
4019 // m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
4020 }
4021
4022 lock (OdeLock)
4023 {
4024 if (WaterGeom != IntPtr.Zero)
4025 {
4026 d.SpaceRemove(space, WaterGeom);
4027 }
4028 IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
4029 d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
4030 (int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
4031 offset, thickness, wrap);
4032 d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
4033 WaterGeom = d.CreateHeightfield(space, HeightmapData, 1);
4034 if (WaterGeom != IntPtr.Zero)
4035 {
4036 d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
4037 d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
4038 }
4039
4040 geom_name_map[WaterGeom] = "Water";
4041
4042 d.Matrix3 R = new d.Matrix3();
4043
4044 Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
4045 Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
4046 //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
4047
4048 q1 = q1 * q2;
4049 //q1 = q1 * q3;
4050 Vector3 v3;
4051 float angle;
4052 q1.GetAxisAngle(out v3, out angle);
4053
4054 d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
4055 d.GeomSetRotation(WaterGeom, ref R);
4056 d.GeomSetPosition(WaterGeom, 128, 128, 0);
4057 }
4058 }
4059
4060 public override void Dispose()
4061 {
4062 _worldInitialized = false;
4063
4064 m_rayCastManager.Dispose();
4065 m_rayCastManager = null;
4066
4067 lock (OdeLock)
4068 {
4069 lock (_prims)
4070 {
4071 foreach (OdePrim prm in _prims)
4072 {
4073 RemovePrim(prm);
4074 }
4075 }
4076
4077 //foreach (OdeCharacter act in _characters)
4078 //{
4079 //RemoveAvatar(act);
4080 //}
4081 d.WorldDestroy(world);
4082 //d.CloseODE();
4083 }
4084
4085 }
4086
4087 public override Dictionary<uint, float> GetTopColliders()
4088 {
4089 Dictionary<uint, float> topColliders;
4090
4091 lock (_prims)
4092 {
4093 List<OdePrim> orderedPrims = new List<OdePrim>(_prims);
4094 orderedPrims.OrderByDescending(p => p.CollisionScore);
4095 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
4096
4097 foreach (OdePrim p in _prims)
4098 p.CollisionScore = 0;
4099 }
4100
4101 return topColliders;
4102 }
4103
4104 public override bool SupportsRayCast()
4105 {
4106 return true;
4107 }
4108
4109 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
4110 {
4111 if (retMethod != null)
4112 {
4113 m_rayCastManager.QueueRequest(position, direction, length, retMethod);
4114 }
4115 }
4116
4117 public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
4118 {
4119 if (retMethod != null)
4120 {
4121 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
4122 }
4123 }
4124
4125 public override List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
4126 {
4127 ContactResult[] ourResults = null;
4128 RayCallback retMethod = delegate(List<ContactResult> results)
4129 {
4130 ourResults = new ContactResult[results.Count];
4131 results.CopyTo(ourResults, 0);
4132 };
4133 int waitTime = 0;
4134 m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod);
4135 while (ourResults == null && waitTime < 1000)
4136 {
4137 Thread.Sleep(1);
4138 waitTime++;
4139 }
4140 if (ourResults == null)
4141 return new List<ContactResult> ();
4142 return new List<ContactResult>(ourResults);
4143 }
4144
4145#if USE_DRAWSTUFF
4146 // Keyboard callback
4147 public void command(int cmd)
4148 {
4149 IntPtr geom;
4150 d.Mass mass;
4151 d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f);
4152
4153
4154
4155 Char ch = Char.ToLower((Char)cmd);
4156 switch ((Char)ch)
4157 {
4158 case 'w':
4159 try
4160 {
4161 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));
4162
4163 xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z;
4164 ds.SetViewpoint(ref xyz, ref hpr);
4165 }
4166 catch (ArgumentException)
4167 { hpr.X = 0; }
4168 break;
4169
4170 case 'a':
4171 hpr.X++;
4172 ds.SetViewpoint(ref xyz, ref hpr);
4173 break;
4174
4175 case 's':
4176 try
4177 {
4178 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));
4179
4180 xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z;
4181 ds.SetViewpoint(ref xyz, ref hpr);
4182 }
4183 catch (ArgumentException)
4184 { hpr.X = 0; }
4185 break;
4186 case 'd':
4187 hpr.X--;
4188 ds.SetViewpoint(ref xyz, ref hpr);
4189 break;
4190 case 'r':
4191 xyz.Z++;
4192 ds.SetViewpoint(ref xyz, ref hpr);
4193 break;
4194 case 'f':
4195 xyz.Z--;
4196 ds.SetViewpoint(ref xyz, ref hpr);
4197 break;
4198 case 'e':
4199 xyz.Y++;
4200 ds.SetViewpoint(ref xyz, ref hpr);
4201 break;
4202 case 'q':
4203 xyz.Y--;
4204 ds.SetViewpoint(ref xyz, ref hpr);
4205 break;
4206 }
4207 }
4208
4209 public void step(int pause)
4210 {
4211
4212 ds.SetColor(1.0f, 1.0f, 0.0f);
4213 ds.SetTexture(ds.Texture.Wood);
4214 lock (_prims)
4215 {
4216 foreach (OdePrim prm in _prims)
4217 {
4218 //IntPtr body = d.GeomGetBody(prm.prim_geom);
4219 if (prm.prim_geom != IntPtr.Zero)
4220 {
4221 d.Vector3 pos;
4222 d.GeomCopyPosition(prm.prim_geom, out pos);
4223 //d.BodyCopyPosition(body, out pos);
4224
4225 d.Matrix3 R;
4226 d.GeomCopyRotation(prm.prim_geom, out R);
4227 //d.BodyCopyRotation(body, out R);
4228
4229
4230 d.Vector3 sides = new d.Vector3();
4231 sides.X = prm.Size.X;
4232 sides.Y = prm.Size.Y;
4233 sides.Z = prm.Size.Z;
4234
4235 ds.DrawBox(ref pos, ref R, ref sides);
4236 }
4237 }
4238 }
4239 ds.SetColor(1.0f, 0.0f, 0.0f);
4240
4241 foreach (OdeCharacter chr in _characters)
4242 {
4243 if (chr.Shell != IntPtr.Zero)
4244 {
4245 IntPtr body = d.GeomGetBody(chr.Shell);
4246
4247 d.Vector3 pos;
4248 d.GeomCopyPosition(chr.Shell, out pos);
4249 //d.BodyCopyPosition(body, out pos);
4250
4251 d.Matrix3 R;
4252 d.GeomCopyRotation(chr.Shell, out R);
4253 //d.BodyCopyRotation(body, out R);
4254
4255 ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f);
4256 d.Vector3 sides = new d.Vector3();
4257 sides.X = 0.5f;
4258 sides.Y = 0.5f;
4259 sides.Z = 0.5f;
4260
4261 ds.DrawBox(ref pos, ref R, ref sides);
4262 }
4263 }
4264 }
4265
4266 public void start(int unused)
4267 {
4268 ds.SetViewpoint(ref xyz, ref hpr);
4269 }
4270#endif
4271
4272 public override Dictionary<string, float> GetStats()
4273 {
4274 if (!CollectStats)
4275 return null;
4276
4277 Dictionary<string, float> returnStats;
4278
4279 lock (OdeLock)
4280 {
4281 returnStats = new Dictionary<string, float>(m_stats);
4282
4283 // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by
4284 // 3 from the SimStatsReporter.
4285 returnStats[ODETotalAvatarsStatName] = _characters.Count * 3;
4286 returnStats[ODETotalPrimsStatName] = _prims.Count * 3;
4287 returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3;
4288
4289 InitializeExtraStats();
4290 }
4291
4292 returnStats[ODEOtherCollisionFrameMsStatName]
4293 = returnStats[ODEOtherCollisionFrameMsStatName]
4294 - returnStats[ODENativeSpaceCollisionFrameMsStatName]
4295 - returnStats[ODENativeGeomCollisionFrameMsStatName];
4296
4297 return returnStats;
4298 }
4299
4300 private void InitializeExtraStats()
4301 {
4302 m_stats[ODETotalFrameMsStatName] = 0;
4303 m_stats[ODEAvatarTaintMsStatName] = 0;
4304 m_stats[ODEPrimTaintMsStatName] = 0;
4305 m_stats[ODEAvatarForcesFrameMsStatName] = 0;
4306 m_stats[ODEPrimForcesFrameMsStatName] = 0;
4307 m_stats[ODERaycastingFrameMsStatName] = 0;
4308 m_stats[ODENativeStepFrameMsStatName] = 0;
4309 m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0;
4310 m_stats[ODENativeGeomCollisionFrameMsStatName] = 0;
4311 m_stats[ODEOtherCollisionFrameMsStatName] = 0;
4312 m_stats[ODECollisionNotificationFrameMsStatName] = 0;
4313 m_stats[ODEAvatarContactsStatsName] = 0;
4314 m_stats[ODEPrimContactsStatName] = 0;
4315 m_stats[ODEAvatarUpdateFrameMsStatName] = 0;
4316 m_stats[ODEPrimUpdateFrameMsStatName] = 0;
4317 }
4318 }
4319}
diff --git a/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs b/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs
new file mode 100644
index 0000000..16404c6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs
@@ -0,0 +1,128 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using Nini.Config;
30using NUnit.Framework;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.OdePlugin;
35using OpenSim.Tests.Common;
36using log4net;
37using System.Reflection;
38
39namespace OpenSim.Region.Physics.OdePlugin.Tests
40{
41 [TestFixture]
42 public class ODETestClass : OpenSimTestCase
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 private OpenSim.Region.Physics.OdePlugin.OdePlugin cbt;
47 private PhysicsScene ps;
48 private IMeshingPlugin imp;
49
50 [SetUp]
51 public void Initialize()
52 {
53 IConfigSource TopConfig = new IniConfigSource();
54 IConfig config = TopConfig.AddConfig("Startup");
55 config.Set("DecodedSculptMapPath","j2kDecodeCache");
56
57 // Loading ODEPlugin
58 cbt = new OdePlugin();
59 // Loading Zero Mesher
60 imp = new ZeroMesherPlugin();
61 // Getting Physics Scene
62 ps = cbt.GetScene("test");
63 // Initializing Physics Scene.
64 ps.Initialise(imp.GetMesher(TopConfig),null);
65 float[] _heightmap = new float[(int)Constants.RegionSize * (int)Constants.RegionSize];
66 for (int i = 0; i < ((int)Constants.RegionSize * (int)Constants.RegionSize); i++)
67 {
68 _heightmap[i] = 21f;
69 }
70 ps.SetTerrain(_heightmap);
71 }
72
73 [TearDown]
74 public void Terminate()
75 {
76 ps.DeleteTerrain();
77 ps.Dispose();
78
79 }
80
81 [Test]
82 public void CreateAndDropPhysicalCube()
83 {
84 PrimitiveBaseShape newcube = PrimitiveBaseShape.CreateBox();
85 Vector3 position = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 128f);
86 Vector3 size = new Vector3(0.5f, 0.5f, 0.5f);
87 Quaternion rot = Quaternion.Identity;
88 PhysicsActor prim = ps.AddPrimShape("CoolShape", newcube, position, size, rot, true, 0);
89 OdePrim oprim = (OdePrim)prim;
90 OdeScene pscene = (OdeScene) ps;
91
92 Assert.That(oprim.m_taintadd);
93
94 prim.LocalID = 5;
95
96 for (int i = 0; i < 58; i++)
97 {
98 ps.Simulate(0.133f);
99
100 Assert.That(oprim.prim_geom != (IntPtr)0);
101
102 Assert.That(oprim.m_targetSpace != (IntPtr)0);
103
104 //Assert.That(oprim.m_targetSpace == pscene.space);
105 m_log.Info("TargetSpace: " + oprim.m_targetSpace + " - SceneMainSpace: " + pscene.space);
106
107 Assert.That(!oprim.m_taintadd);
108 m_log.Info("Prim Position (" + oprim.LocalID + "): " + prim.Position);
109
110 // Make sure we're above the ground
111 //Assert.That(prim.Position.Z > 20f);
112 //m_log.Info("PrimCollisionScore (" + oprim.m_localID + "): " + oprim.m_collisionscore);
113
114 // Make sure we've got a Body
115 Assert.That(oprim.Body != (IntPtr)0);
116 //m_log.Info(
117 }
118
119 // Make sure we're not somewhere above the ground
120 Assert.That(prim.Position.Z < 21.5f);
121
122 ps.RemovePrim(prim);
123 Assert.That(oprim.m_taintremove);
124 ps.Simulate(0.133f);
125 Assert.That(oprim.Body == (IntPtr)0);
126 }
127 }
128}
diff --git a/OpenSim/Region/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..fc1ffba
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/POS/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("POSPlugin")]
38[assembly : AssemblyDescription("")]
39[assembly : AssemblyConfiguration("")]
40[assembly : AssemblyCompany("http://opensimulator.org")]
41[assembly : AssemblyProduct("POSPlugin")]
42[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
43[assembly : AssemblyTrademark("")]
44[assembly : AssemblyCulture("")]
45
46// This sets the default COM visibility of types in the assembly to invisible.
47// If you need to expose a type to COM, use [ComVisible(true)] on that type.
48
49[assembly : ComVisible(false)]
50
51// The assembly version has following format :
52//
53// Major.Minor.Build.Revision
54//
55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default):
57
58[assembly : AssemblyVersion("0.8.2.*")]
diff --git a/OpenSim/Region/PhysicsModules/POS/POSCharacter.cs b/OpenSim/Region/PhysicsModules/POS/POSCharacter.cs
new file mode 100644
index 0000000..40ab984
--- /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.Physics.Manager;
34
35namespace OpenSim.Region.Physics.POSPlugin
36{
37 public class POSCharacter : PhysicsActor
38 {
39 private Vector3 _position;
40 public Vector3 _velocity;
41 public Vector3 _target_velocity = Vector3.Zero;
42 public Vector3 _size = Vector3.Zero;
43 private Vector3 _acceleration;
44 private Vector3 m_rotationalVelocity = Vector3.Zero;
45 private bool flying;
46 private bool isColliding;
47
48 public POSCharacter()
49 {
50 }
51
52 public override int PhysicsActorType
53 {
54 get { return (int) ActorTypes.Agent; }
55 set { return; }
56 }
57
58 public override Vector3 RotationalVelocity
59 {
60 get { return m_rotationalVelocity; }
61 set { m_rotationalVelocity = value; }
62 }
63
64 public override bool SetAlwaysRun
65 {
66 get { return false; }
67 set { return; }
68 }
69
70 public override uint LocalID
71 {
72 set { return; }
73 }
74
75 public override bool Grabbed
76 {
77 set { return; }
78 }
79
80 public override bool Selected
81 {
82 set { return; }
83 }
84
85 public override float Buoyancy
86 {
87 get { return 0f; }
88 set { return; }
89 }
90
91 public override bool FloatOnWater
92 {
93 set { return; }
94 }
95
96 public override bool IsPhysical
97 {
98 get { return false; }
99 set { return; }
100 }
101
102 public override bool ThrottleUpdates
103 {
104 get { return false; }
105 set { return; }
106 }
107
108 public override bool Flying
109 {
110 get { return flying; }
111 set { flying = value; }
112 }
113
114 public override bool IsColliding
115 {
116 get { return isColliding; }
117 set { isColliding = value; }
118 }
119
120 public override bool CollidingGround
121 {
122 get { return false; }
123 set { return; }
124 }
125
126 public override bool CollidingObj
127 {
128 get { return false; }
129 set { return; }
130 }
131
132 public override bool Stopped
133 {
134 get { return false; }
135 }
136
137 public override Vector3 Position
138 {
139 get { return _position; }
140 set { _position = value; }
141 }
142
143 public override Vector3 Size
144 {
145 get { return _size; }
146 set
147 {
148 _size = value;
149 _size.Z = _size.Z / 2.0f;
150 }
151 }
152
153 public override float Mass
154 {
155 get { return 0f; }
156 }
157
158 public override Vector3 Force
159 {
160 get { return Vector3.Zero; }
161 set { return; }
162 }
163
164 public override int VehicleType
165 {
166 get { return 0; }
167 set { return; }
168 }
169
170 public override void VehicleFloatParam(int param, float value)
171 {
172
173 }
174
175 public override void VehicleVectorParam(int param, Vector3 value)
176 {
177
178 }
179
180 public override void VehicleRotationParam(int param, Quaternion rotation)
181 {
182
183 }
184
185 public override void VehicleFlags(int param, bool remove) { }
186
187 public override void SetVolumeDetect(int param)
188 {
189
190 }
191
192 public override Vector3 CenterOfMass
193 {
194 get { return Vector3.Zero; }
195 }
196
197 public override Vector3 GeometricCenter
198 {
199 get { return Vector3.Zero; }
200 }
201
202 public override PrimitiveBaseShape Shape
203 {
204 set { return; }
205 }
206
207 public override Vector3 Velocity
208 {
209 get { return _velocity; }
210 set { _target_velocity = value; }
211 }
212
213 public override Vector3 Torque
214 {
215 get { return Vector3.Zero; }
216 set { return; }
217 }
218
219 public override float CollisionScore
220 {
221 get { return 0f; }
222 set { }
223 }
224
225 public override Quaternion Orientation
226 {
227 get { return Quaternion.Identity; }
228 set { }
229 }
230
231 public override Vector3 Acceleration
232 {
233 get { return _acceleration; }
234 set { _acceleration = value; }
235 }
236
237 public override bool Kinematic
238 {
239 get { return true; }
240 set { }
241 }
242
243 public override void link(PhysicsActor obj)
244 {
245 }
246
247 public override void delink()
248 {
249 }
250
251 public override void LockAngularMotion(Vector3 axis)
252 {
253 }
254
255 public override void AddForce(Vector3 force, bool pushforce)
256 {
257 }
258
259 public override void AddAngularForce(Vector3 force, bool pushforce)
260 {
261 }
262
263 public override void SetMomentum(Vector3 momentum)
264 {
265 }
266
267 public override void CrossingFailure()
268 {
269 }
270
271 public override Vector3 PIDTarget
272 {
273 set { return; }
274 }
275
276 public override bool PIDActive
277 {
278 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/POSPlugin.cs b/OpenSim/Region/PhysicsModules/POS/POSPlugin.cs
new file mode 100644
index 0000000..ed086dd
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/POS/POSPlugin.cs
@@ -0,0 +1,64 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using Nini.Config;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33
34namespace OpenSim.Region.Physics.POSPlugin
35{
36 /// <summary>
37 /// for now will be a very POS physics engine
38 /// </summary>
39 public class POSPlugin : IPhysicsPlugin
40 {
41 public POSPlugin()
42 {
43 }
44
45 public bool Init()
46 {
47 return true;
48 }
49
50 public PhysicsScene GetScene(string sceneIdentifier)
51 {
52 return new POSScene(GetName(), sceneIdentifier);
53 }
54
55 public string GetName()
56 {
57 return ("POS");
58 }
59
60 public void Dispose()
61 {
62 }
63 }
64}
diff --git a/OpenSim/Region/PhysicsModules/POS/POSPrim.cs b/OpenSim/Region/PhysicsModules/POS/POSPrim.cs
new file mode 100644
index 0000000..7c1e915
--- /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.Physics.Manager;
34
35namespace OpenSim.Region.Physics.POSPlugin
36{
37 public class POSPrim : PhysicsActor
38 {
39 private Vector3 _position;
40 private Vector3 _velocity;
41 private Vector3 _acceleration;
42 private Vector3 _size;
43 private Vector3 m_rotationalVelocity = Vector3.Zero;
44 private Quaternion _orientation;
45 private bool iscolliding;
46
47 public POSPrim()
48 {
49 }
50
51 public override int PhysicsActorType
52 {
53 get { return (int) ActorTypes.Prim; }
54 set { return; }
55 }
56
57 public override Vector3 RotationalVelocity
58 {
59 get { return m_rotationalVelocity; }
60 set { m_rotationalVelocity = value; }
61 }
62
63 public override bool IsPhysical
64 {
65 get { return false; }
66 set { return; }
67 }
68
69 public override bool ThrottleUpdates
70 {
71 get { return false; }
72 set { return; }
73 }
74
75 public override bool IsColliding
76 {
77 get { return iscolliding; }
78 set { iscolliding = value; }
79 }
80
81 public override bool CollidingGround
82 {
83 get { return false; }
84 set { return; }
85 }
86
87 public override bool CollidingObj
88 {
89 get { return false; }
90 set { return; }
91 }
92
93 public override bool Stopped
94 {
95 get { return false; }
96 }
97
98 public override Vector3 Position
99 {
100 get { return _position; }
101 set { _position = value; }
102 }
103
104 public override Vector3 Size
105 {
106 get { return _size; }
107 set { _size = value; }
108 }
109
110 public override float Mass
111 {
112 get { return 0f; }
113 }
114
115 public override Vector3 Force
116 {
117 get { return Vector3.Zero; }
118 set { return; }
119 }
120
121 public override int VehicleType
122 {
123 get { return 0; }
124 set { return; }
125 }
126
127 public override void VehicleFloatParam(int param, float value)
128 {
129
130 }
131
132 public override void VehicleVectorParam(int param, Vector3 value)
133 {
134
135 }
136
137 public override void VehicleRotationParam(int param, Quaternion rotation)
138 {
139
140 }
141
142 public override void VehicleFlags(int param, bool remove) { }
143
144 public override void SetVolumeDetect(int param)
145 {
146
147 }
148
149 public override Vector3 CenterOfMass
150 {
151 get { return Vector3.Zero; }
152 }
153
154 public override Vector3 GeometricCenter
155 {
156 get { return Vector3.Zero; }
157 }
158
159 public override PrimitiveBaseShape Shape
160 {
161 set { return; }
162 }
163
164 public override float Buoyancy
165 {
166 get { return 0f; }
167 set { return; }
168 }
169
170 public override bool FloatOnWater
171 {
172 set { return; }
173 }
174
175 public override Vector3 Velocity
176 {
177 get { return _velocity; }
178 set { _velocity = value; }
179 }
180
181 public override float CollisionScore
182 {
183 get { return 0f; }
184 set { }
185 }
186
187 public override Quaternion Orientation
188 {
189 get { return _orientation; }
190 set { _orientation = value; }
191 }
192
193 public override Vector3 Acceleration
194 {
195 get { return _acceleration; }
196 set { _acceleration = value; }
197 }
198
199 public override bool Kinematic
200 {
201 get { return true; }
202 set { }
203 }
204
205 public override void AddForce(Vector3 force, bool pushforce)
206 {
207 }
208
209 public override void AddAngularForce(Vector3 force, bool pushforce)
210 {
211 }
212
213 public override Vector3 Torque
214 {
215 get { return Vector3.Zero; }
216 set { return; }
217 }
218
219 public override void SetMomentum(Vector3 momentum)
220 {
221 }
222
223 public override bool Flying
224 {
225 get { return false; }
226 set { }
227 }
228
229 public override bool SetAlwaysRun
230 {
231 get { return false; }
232 set { return; }
233 }
234
235 public override uint LocalID
236 {
237 set { return; }
238 }
239
240 public override bool Grabbed
241 {
242 set { return; }
243 }
244
245 public override void link(PhysicsActor obj)
246 {
247 }
248
249 public override void delink()
250 {
251 }
252
253 public override void LockAngularMotion(Vector3 axis)
254 {
255 }
256
257 public override bool Selected
258 {
259 set { return; }
260 }
261
262 public override void CrossingFailure()
263 {
264 }
265
266 public override Vector3 PIDTarget
267 {
268 set { return; }
269 }
270
271 public override bool PIDActive
272 {
273 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..080c6ab
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/POS/POSScene.cs
@@ -0,0 +1,273 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using Nini.Config;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.POSPlugin
36{
37 public class POSScene : PhysicsScene
38 {
39 private List<POSCharacter> _characters = new List<POSCharacter>();
40 private List<POSPrim> _prims = new List<POSPrim>();
41 private float[] _heightMap;
42 private const float gravity = -9.8f;
43
44 //protected internal string sceneIdentifier;
45
46 public POSScene(string engineType, String _sceneIdentifier)
47 {
48 EngineType = engineType;
49 Name = EngineType + "/" + _sceneIdentifier;
50 //sceneIdentifier = _sceneIdentifier;
51 }
52
53 public override void Initialise(IMesher meshmerizer, IConfigSource config)
54 {
55 }
56
57 public override void Dispose()
58 {
59 }
60
61 public override PhysicsActor AddAvatar(
62 string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
63 {
64 POSCharacter act = new POSCharacter();
65 act.Position = position;
66 act.Flying = isFlying;
67 _characters.Add(act);
68 return act;
69 }
70
71 public override void RemovePrim(PhysicsActor prim)
72 {
73 POSPrim p = (POSPrim) prim;
74 if (_prims.Contains(p))
75 {
76 _prims.Remove(p);
77 }
78 }
79
80 public override void RemoveAvatar(PhysicsActor character)
81 {
82 POSCharacter act = (POSCharacter) character;
83 if (_characters.Contains(act))
84 {
85 _characters.Remove(act);
86 }
87 }
88
89/*
90 public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation)
91 {
92 return null;
93 }
94*/
95
96 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
97 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
98 {
99 POSPrim prim = new POSPrim();
100 prim.Position = position;
101 prim.Orientation = rotation;
102 prim.Size = size;
103 _prims.Add(prim);
104 return prim;
105 }
106
107 private bool isColliding(POSCharacter c, POSPrim p)
108 {
109 Vector3 rotatedPos = new Vector3(c.Position.X - p.Position.X, c.Position.Y - p.Position.Y,
110 c.Position.Z - p.Position.Z) * Quaternion.Inverse(p.Orientation);
111 Vector3 avatarSize = new Vector3(c.Size.X, c.Size.Y, c.Size.Z) * Quaternion.Inverse(p.Orientation);
112
113 return (Math.Abs(rotatedPos.X) < (p.Size.X*0.5 + Math.Abs(avatarSize.X)) &&
114 Math.Abs(rotatedPos.Y) < (p.Size.Y*0.5 + Math.Abs(avatarSize.Y)) &&
115 Math.Abs(rotatedPos.Z) < (p.Size.Z*0.5 + Math.Abs(avatarSize.Z)));
116 }
117
118 private bool isCollidingWithPrim(POSCharacter c)
119 {
120 foreach (POSPrim p in _prims)
121 {
122 if (isColliding(c, p))
123 {
124 return true;
125 }
126 }
127
128 return false;
129 }
130
131 public override void AddPhysicsActorTaint(PhysicsActor prim)
132 {
133 }
134
135 public override float Simulate(float timeStep)
136 {
137 float fps = 0;
138 for (int i = 0; i < _characters.Count; ++i)
139 {
140 fps++;
141 POSCharacter character = _characters[i];
142
143 float oldposX = character.Position.X;
144 float oldposY = character.Position.Y;
145 float oldposZ = character.Position.Z;
146
147 if (!character.Flying)
148 {
149 character._target_velocity.Z += gravity * timeStep;
150 }
151
152 Vector3 characterPosition = character.Position;
153
154 characterPosition.X += character._target_velocity.X * timeStep;
155 characterPosition.Y += character._target_velocity.Y * timeStep;
156
157 characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f);
158 characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f);
159
160 bool forcedZ = false;
161
162 float terrainheight = _heightMap[(int)character.Position.Y * Constants.RegionSize + (int)character.Position.X];
163 if (character.Position.Z + (character._target_velocity.Z * timeStep) < terrainheight + 2)
164 {
165 characterPosition.Z = terrainheight + character.Size.Z;
166 forcedZ = true;
167 }
168 else
169 {
170 characterPosition.Z += character._target_velocity.Z*timeStep;
171 }
172
173 /// this is it -- the magic you've all been waiting for! Ladies and gentlemen --
174 /// Completely Bogus Collision Detection!!!
175 /// better known as the CBCD algorithm
176
177 if (isCollidingWithPrim(character))
178 {
179 characterPosition.Z = oldposZ; // first try Z axis
180 if (isCollidingWithPrim(character))
181 {
182 characterPosition.Z = oldposZ + character.Size.Z / 4.4f; // try harder
183 if (isCollidingWithPrim(character))
184 {
185 characterPosition.Z = oldposZ + character.Size.Z / 2.2f; // try very hard
186 if (isCollidingWithPrim(character))
187 {
188 characterPosition.X = oldposX;
189 characterPosition.Y = oldposY;
190 characterPosition.Z = oldposZ;
191
192 characterPosition.X += character._target_velocity.X * timeStep;
193 if (isCollidingWithPrim(character))
194 {
195 characterPosition.X = oldposX;
196 }
197
198 characterPosition.Y += character._target_velocity.Y * timeStep;
199 if (isCollidingWithPrim(character))
200 {
201 characterPosition.Y = oldposY;
202 }
203 }
204 else
205 {
206 forcedZ = true;
207 }
208 }
209 else
210 {
211 forcedZ = true;
212 }
213 }
214 else
215 {
216 forcedZ = true;
217 }
218 }
219
220 characterPosition.X = Util.Clamp(character.Position.X, 0.01f, Constants.RegionSize - 0.01f);
221 characterPosition.Y = Util.Clamp(character.Position.Y, 0.01f, Constants.RegionSize - 0.01f);
222
223 character.Position = characterPosition;
224
225 character._velocity.X = (character.Position.X - oldposX)/timeStep;
226 character._velocity.Y = (character.Position.Y - oldposY)/timeStep;
227
228 if (forcedZ)
229 {
230 character._velocity.Z = 0;
231 character._target_velocity.Z = 0;
232 ((PhysicsActor)character).IsColliding = true;
233 character.RequestPhysicsterseUpdate();
234 }
235 else
236 {
237 ((PhysicsActor)character).IsColliding = false;
238 character._velocity.Z = (character.Position.Z - oldposZ)/timeStep;
239 }
240 }
241 return fps;
242 }
243
244 public override void GetResults()
245 {
246 }
247
248 public override bool IsThreaded
249 {
250 // for now we won't be multithreaded
251 get { return (false); }
252 }
253
254 public override void SetTerrain(float[] heightMap)
255 {
256 _heightMap = heightMap;
257 }
258
259 public override void DeleteTerrain()
260 {
261 }
262
263 public override void SetWaterLevel(float baseheight)
264 {
265 }
266
267 public override Dictionary<uint, float> GetTopColliders()
268 {
269 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
270 return returncolliders;
271 }
272 }
273}
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..cace4e4
--- /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.Physics.Manager
32{
33 public class CollisionLocker
34 {
35 private List<IntPtr> worldlock = new List<IntPtr>();
36
37 public CollisionLocker()
38 {
39
40 }
41
42 public void dlock(IntPtr world)
43 {
44 lock (worldlock)
45 {
46 worldlock.Add(world);
47 }
48
49 }
50
51 public void dunlock(IntPtr world)
52 {
53 lock (worldlock)
54 {
55 worldlock.Remove(world);
56 }
57 }
58
59 public bool lockquery()
60 {
61 return (worldlock.Count > 0);
62 }
63
64 public void drelease(IntPtr world)
65 {
66 lock (worldlock)
67 {
68 if (worldlock.Contains(world))
69 worldlock.Remove(world);
70 }
71 }
72 }
73}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs b/OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs
new file mode 100644
index 0000000..2e7bb5d
--- /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.Physics.Manager
34{
35 public interface IMesher
36 {
37 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod);
38 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical);
39 IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache);
40 }
41
42 // Values for level of detail to be passed to the mesher.
43 // Values origionally chosen for the LOD of sculpties (the sqrt(width*heigth) of sculpt texture)
44 // Lower level of detail reduces the number of vertices used to represent the meshed shape.
45 public enum LevelOfDetail
46 {
47 High = 32,
48 Medium = 16,
49 Low = 8,
50 VeryLow = 4
51 }
52
53 public interface IVertex
54 {
55 }
56
57 public interface IMesh
58 {
59 List<Vector3> getVertexList();
60 int[] getIndexListAsInt();
61 int[] getIndexListAsIntLocked();
62 float[] 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..31a397c
--- /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.Physics.Manager
34{
35 public struct PhysParameterEntry
36 {
37 // flags to say to apply to all or no instances (I wish one could put consts into interfaces)
38 public const uint APPLY_TO_ALL = 0xfffffff3;
39 public const uint APPLY_TO_NONE = 0xfffffff4;
40
41 // values that denote true and false values
42 public const float NUMERIC_TRUE = 1f;
43 public const float NUMERIC_FALSE = 0f;
44
45 public string name;
46 public string desc;
47
48 public PhysParameterEntry(string n, string d)
49 {
50 name = n;
51 desc = d;
52 }
53 }
54
55 // Interface for a physics scene that implements the runtime setting and getting of physics parameters
56 public interface IPhysicsParameters
57 {
58 // Get the list of parameters this physics engine supports
59 PhysParameterEntry[] GetParameterList();
60
61 // Set parameter on a specific or all instances.
62 // Return 'false' if not able to set the parameter.
63 bool SetPhysicsParameter(string parm, 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..b52f1f6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs
@@ -0,0 +1,122 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using System.Reflection;
30using log4net;
31using Nini.Config;
32using OpenSim.Framework;
33using OpenMetaverse;
34
35namespace OpenSim.Region.Physics.Manager
36{
37 class NullPhysicsScene : PhysicsScene
38 {
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40
41 private static int m_workIndicator;
42
43 public override void Initialise(IMesher meshmerizer, IConfigSource config)
44 {
45 // Does nothing right now
46 }
47
48 public override PhysicsActor AddAvatar(
49 string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
50 {
51 m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddAvatar({0})", position);
52 return PhysicsActor.Null;
53 }
54
55 public override void RemoveAvatar(PhysicsActor actor)
56 {
57 }
58
59 public override void RemovePrim(PhysicsActor prim)
60 {
61 }
62 public override void SetWaterLevel(float baseheight)
63 {
64
65 }
66
67/*
68 public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation)
69 {
70 m_log.InfoFormat("NullPhysicsScene : AddPrim({0},{1})", position, size);
71 return PhysicsActor.Null;
72 }
73*/
74
75 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
76 Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
77 {
78 m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : AddPrim({0},{1})", position, size);
79 return PhysicsActor.Null;
80 }
81
82 public override void AddPhysicsActorTaint(PhysicsActor prim)
83 {
84 }
85
86 public override float Simulate(float timeStep)
87 {
88 m_workIndicator = (m_workIndicator + 1) % 10;
89
90 return 0f;
91 }
92
93 public override void GetResults()
94 {
95 m_log.Info("[PHYSICS]: NullPhysicsScene : GetResults()");
96 }
97
98 public override void SetTerrain(float[] heightMap)
99 {
100 m_log.InfoFormat("[PHYSICS]: NullPhysicsScene : SetTerrain({0} items)", heightMap.Length);
101 }
102
103 public override void DeleteTerrain()
104 {
105 }
106
107 public override bool IsThreaded
108 {
109 get { return false; }
110 }
111
112 public override void Dispose()
113 {
114 }
115
116 public override Dictionary<uint,float> GetTopColliders()
117 {
118 Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
119 return returncolliders;
120 }
121 }
122} \ 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..6bc6e23
--- /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.Physics.Manager
36{
37 public delegate void PositionUpdate(Vector3 position);
38 public delegate void VelocityUpdate(Vector3 velocity);
39 public delegate void OrientationUpdate(Quaternion orientation);
40
41 public enum ActorTypes : int
42 {
43 Unknown = 0,
44 Agent = 1,
45 Prim = 2,
46 Ground = 3
47 }
48
49 public enum PIDHoverType
50 {
51 Ground,
52 GroundAndWater,
53 Water,
54 Absolute
55 }
56
57 public struct ContactPoint
58 {
59 public Vector3 Position;
60 public Vector3 SurfaceNormal;
61 public float PenetrationDepth;
62
63 public ContactPoint(Vector3 position, Vector3 surfaceNormal, float penetrationDepth)
64 {
65 Position = position;
66 SurfaceNormal = surfaceNormal;
67 PenetrationDepth = penetrationDepth;
68 }
69 }
70
71 /// <summary>
72 /// Used to pass collision information to OnCollisionUpdate listeners.
73 /// </summary>
74 public class CollisionEventUpdate : EventArgs
75 {
76 /// <summary>
77 /// Number of collision events in this update.
78 /// </summary>
79 public int Count { get { return m_objCollisionList.Count; } }
80
81 public bool CollisionsOnPreviousFrame { get; private set; }
82
83 public Dictionary<uint, ContactPoint> m_objCollisionList;
84
85 public CollisionEventUpdate(Dictionary<uint, ContactPoint> objCollisionList)
86 {
87 m_objCollisionList = objCollisionList;
88 }
89
90 public CollisionEventUpdate()
91 {
92 m_objCollisionList = new Dictionary<uint, ContactPoint>();
93 }
94
95 public void AddCollider(uint localID, ContactPoint contact)
96 {
97 if (!m_objCollisionList.ContainsKey(localID))
98 {
99 m_objCollisionList.Add(localID, contact);
100 }
101 else
102 {
103 if (m_objCollisionList[localID].PenetrationDepth < contact.PenetrationDepth)
104 m_objCollisionList[localID] = contact;
105 }
106 }
107
108 /// <summary>
109 /// Clear added collision events.
110 /// </summary>
111 public void Clear()
112 {
113 m_objCollisionList.Clear();
114 }
115 }
116
117 public abstract class PhysicsActor
118 {
119// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
120
121 public delegate void RequestTerseUpdate();
122 public delegate void CollisionUpdate(EventArgs e);
123 public delegate void OutOfBounds(Vector3 pos);
124
125// disable warning: public events
126#pragma warning disable 67
127 public event PositionUpdate OnPositionUpdate;
128 public event VelocityUpdate OnVelocityUpdate;
129 public event OrientationUpdate OnOrientationUpdate;
130 public event RequestTerseUpdate OnRequestTerseUpdate;
131
132 /// <summary>
133 /// Subscribers to this event must synchronously handle the dictionary of collisions received, since the event
134 /// object is reused in subsequent physics frames.
135 /// </summary>
136 public event CollisionUpdate OnCollisionUpdate;
137
138 public event OutOfBounds OnOutOfBounds;
139#pragma warning restore 67
140
141 public static PhysicsActor Null
142 {
143 get { return new NullPhysicsActor(); }
144 }
145
146 public abstract bool Stopped { get; }
147
148 public abstract Vector3 Size { get; set; }
149
150 public 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..b685d04
--- /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.Physics.Manager
34{
35 public enum PhysicsJointType : int
36 {
37 Ball = 0,
38 Hinge = 1
39 }
40
41 public class PhysicsJoint
42 {
43 public virtual bool IsInPhysicsEngine { get { return false; } } // set internally to indicate if this joint has already been passed to the physics engine or is still pending
44 public PhysicsJointType Type;
45 public string RawParams;
46 public List<string> BodyNames = new List<string>();
47 public Vector3 Position; // global coords
48 public Quaternion Rotation; // global coords
49 public string ObjectNameInScene; // proxy object in scene that represents the joint position/orientation
50 public string TrackedBodyName; // body name that this joint is attached to (ObjectNameInScene will follow TrackedBodyName)
51 public Quaternion LocalRotation; // joint orientation relative to one of the involved bodies, the tracked body
52 public int ErrorMessageCount; // total # of error messages printed for this joint since its creation. if too many, further error messages are suppressed to prevent flooding.
53 public const int maxErrorMessages = 100; // no more than this # of error messages will be printed for each joint
54 }
55}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsPluginManager.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsPluginManager.cs
new file mode 100644
index 0000000..d8279b7
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsPluginManager.cs
@@ -0,0 +1,242 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using Nini.Config;
33using log4net;
34using OpenSim.Framework;
35using OpenMetaverse;
36
37namespace OpenSim.Region.Physics.Manager
38{
39 /// <summary>
40 /// Description of MyClass.
41 /// </summary>
42 public class PhysicsPluginManager
43 {
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45
46 private Dictionary<string, IPhysicsPlugin> _PhysPlugins = new Dictionary<string, IPhysicsPlugin>();
47 private Dictionary<string, IMeshingPlugin> _MeshPlugins = new Dictionary<string, IMeshingPlugin>();
48
49 /// <summary>
50 /// Constructor.
51 /// </summary>
52 public PhysicsPluginManager()
53 {
54 // Load "plugins", that are hard coded and not existing in form of an external lib, and hence always
55 // available
56 IMeshingPlugin plugHard;
57 plugHard = new ZeroMesherPlugin();
58 _MeshPlugins.Add(plugHard.GetName(), plugHard);
59
60 m_log.Info("[PHYSICS]: Added meshing engine: " + plugHard.GetName());
61 }
62
63 /// <summary>
64 /// Get a physics scene for the given physics engine and mesher.
65 /// </summary>
66 /// <param name="physEngineName"></param>
67 /// <param name="meshEngineName"></param>
68 /// <param name="config"></param>
69 /// <returns></returns>
70 public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName,
71 IConfigSource config, string regionName, Vector3 regionExtent)
72 {
73 if (String.IsNullOrEmpty(physEngineName))
74 {
75 return PhysicsScene.Null;
76 }
77
78 if (String.IsNullOrEmpty(meshEngineName))
79 {
80 return PhysicsScene.Null;
81 }
82
83 IMesher meshEngine = null;
84 if (_MeshPlugins.ContainsKey(meshEngineName))
85 {
86 m_log.Info("[PHYSICS]: creating meshing engine " + meshEngineName);
87 meshEngine = _MeshPlugins[meshEngineName].GetMesher(config);
88 }
89 else
90 {
91 m_log.WarnFormat("[PHYSICS]: couldn't find meshingEngine: {0}", meshEngineName);
92 throw new ArgumentException(String.Format("couldn't find meshingEngine: {0}", meshEngineName));
93 }
94
95 if (_PhysPlugins.ContainsKey(physEngineName))
96 {
97 m_log.Info("[PHYSICS]: creating " + physEngineName);
98 PhysicsScene result = _PhysPlugins[physEngineName].GetScene(regionName);
99 result.Initialise(meshEngine, config, regionExtent);
100 return result;
101 }
102 else
103 {
104 m_log.WarnFormat("[PHYSICS]: couldn't find physicsEngine: {0}", physEngineName);
105 throw new ArgumentException(String.Format("couldn't find physicsEngine: {0}", physEngineName));
106 }
107 }
108
109 /// <summary>
110 /// Load all plugins in assemblies at the given path
111 /// </summary>
112 /// <param name="pluginsPath"></param>
113 public void LoadPluginsFromAssemblies(string assembliesPath)
114 {
115 // Walk all assemblies (DLLs effectively) and see if they are home
116 // of a plugin that is of interest for us
117 string[] pluginFiles = Directory.GetFiles(assembliesPath, "*.dll");
118
119 for (int i = 0; i < pluginFiles.Length; i++)
120 {
121 LoadPluginsFromAssembly(pluginFiles[i]);
122 }
123 }
124
125 /// <summary>
126 /// Load plugins from an assembly at the given path
127 /// </summary>
128 /// <param name="assemblyPath"></param>
129 public void LoadPluginsFromAssembly(string assemblyPath)
130 {
131 // TODO / NOTE
132 // The assembly named 'OpenSim.Region.Physics.BasicPhysicsPlugin' was loaded from
133 // 'file:///C:/OpenSim/trunk2/bin/Physics/OpenSim.Region.Physics.BasicPhysicsPlugin.dll'
134 // using the LoadFrom context. The use of this context can result in unexpected behavior
135 // for serialization, casting and dependency resolution. In almost all cases, it is recommended
136 // that the LoadFrom context be avoided. This can be done by installing assemblies in the
137 // Global Assembly Cache or in the ApplicationBase directory and using Assembly.
138 // Load when explicitly loading assemblies.
139 Assembly pluginAssembly = null;
140 Type[] types = null;
141
142 try
143 {
144 pluginAssembly = Assembly.LoadFrom(assemblyPath);
145 }
146 catch (Exception ex)
147 {
148 m_log.Error("[PHYSICS]: Failed to load plugin from " + assemblyPath, ex);
149 }
150
151 if (pluginAssembly != null)
152 {
153 try
154 {
155 types = pluginAssembly.GetTypes();
156 }
157 catch (ReflectionTypeLoadException ex)
158 {
159 m_log.Error("[PHYSICS]: Failed to enumerate types in plugin from " + assemblyPath + ": " +
160 ex.LoaderExceptions[0].Message, ex);
161 }
162 catch (Exception ex)
163 {
164 m_log.Error("[PHYSICS]: Failed to enumerate types in plugin from " + assemblyPath, ex);
165 }
166
167 if (types != null)
168 {
169 foreach (Type pluginType in types)
170 {
171 if (pluginType.IsPublic)
172 {
173 if (!pluginType.IsAbstract)
174 {
175 Type physTypeInterface = pluginType.GetInterface("IPhysicsPlugin");
176
177 if (physTypeInterface != null)
178 {
179 IPhysicsPlugin plug =
180 (IPhysicsPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
181 plug.Init();
182 if (!_PhysPlugins.ContainsKey(plug.GetName()))
183 {
184 _PhysPlugins.Add(plug.GetName(), plug);
185 m_log.Info("[PHYSICS]: Added physics engine: " + plug.GetName());
186 }
187 }
188
189 Type meshTypeInterface = pluginType.GetInterface("IMeshingPlugin");
190
191 if (meshTypeInterface != null)
192 {
193 IMeshingPlugin plug =
194 (IMeshingPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
195 if (!_MeshPlugins.ContainsKey(plug.GetName()))
196 {
197 _MeshPlugins.Add(plug.GetName(), plug);
198 m_log.Info("[PHYSICS]: Added meshing engine: " + plug.GetName());
199 }
200 }
201
202 physTypeInterface = null;
203 meshTypeInterface = null;
204 }
205 }
206 }
207 }
208 }
209
210 pluginAssembly = null;
211 }
212
213 //---
214 public static void PhysicsPluginMessage(string message, bool isWarning)
215 {
216 if (isWarning)
217 {
218 m_log.Warn("[PHYSICS]: " + message);
219 }
220 else
221 {
222 m_log.Info("[PHYSICS]: " + message);
223 }
224 }
225
226 //---
227 }
228
229 public interface IPhysicsPlugin
230 {
231 bool Init();
232 PhysicsScene GetScene(String sceneIdentifier);
233 string GetName();
234 void Dispose();
235 }
236
237 public interface IMeshingPlugin
238 {
239 string GetName();
240 IMesher GetMesher(IConfigSource config);
241 }
242}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs
new file mode 100644
index 0000000..9cdedbf
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs
@@ -0,0 +1,361 @@
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.Physics.Manager
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 Name { 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 public virtual void TriggerPhysicsBasedRestart()
121 {
122 physicsCrash handler = OnPhysicsCrash;
123 if (handler != null)
124 {
125 OnPhysicsCrash();
126 }
127 }
128
129 // Deprecated. Do not use this for new physics engines.
130 public abstract void Initialise(IMesher meshmerizer, IConfigSource config);
131
132 // For older physics engines that do not implement non-legacy region sizes.
133 // If the physics engine handles the region extent feature, it overrides this function.
134 public virtual void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
135 {
136 // If not overridden, call the old initialization entry.
137 Initialise(meshmerizer, config);
138 }
139
140 /// <summary>
141 /// Add an avatar
142 /// </summary>
143 /// <param name="avName"></param>
144 /// <param name="position"></param>
145 /// <param name="velocity"></param>
146 /// <param name="size"></param>
147 /// <param name="isFlying"></param>
148 /// <returns></returns>
149 public abstract PhysicsActor AddAvatar(
150 string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying);
151
152 /// <summary>
153 /// Add an avatar
154 /// </summary>
155 /// <param name="localID"></param>
156 /// <param name="avName"></param>
157 /// <param name="position"></param>
158 /// <param name="velocity"></param>
159 /// <param name="size"></param>
160 /// <param name="isFlying"></param>
161 /// <returns></returns>
162 public virtual PhysicsActor AddAvatar(
163 uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
164 {
165 PhysicsActor ret = AddAvatar(avName, position, velocity, size, isFlying);
166
167 if (ret != null)
168 ret.LocalID = localID;
169
170 return ret;
171 }
172
173 /// <summary>
174 /// Remove an avatar.
175 /// </summary>
176 /// <param name="actor"></param>
177 public abstract void RemoveAvatar(PhysicsActor actor);
178
179 /// <summary>
180 /// Remove a prim.
181 /// </summary>
182 /// <param name="prim"></param>
183 public abstract void RemovePrim(PhysicsActor prim);
184
185 public abstract PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
186 Vector3 size, Quaternion rotation, bool isPhysical, uint localid);
187
188 public virtual PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
189 Vector3 size, Quaternion rotation, bool isPhysical, bool isPhantom, byte shapetype, uint localid)
190 {
191 return AddPrimShape(primName, pbs, position, size, rotation, isPhysical, localid);
192 }
193
194 public virtual float TimeDilation
195 {
196 get { return 1.0f; }
197 }
198
199 public virtual bool SupportsNINJAJoints
200 {
201 get { return false; }
202 }
203
204 public virtual PhysicsJoint RequestJointCreation(string objectNameInScene, PhysicsJointType jointType, Vector3 position,
205 Quaternion rotation, string parms, List<string> bodyNames, string trackedBodyName, Quaternion localRotation)
206 { return null; }
207
208 public virtual void RequestJointDeletion(string objectNameInScene)
209 { return; }
210
211 public virtual void RemoveAllJointsConnectedToActorThreadLocked(PhysicsActor actor)
212 { return; }
213
214 public virtual void DumpJointInfo()
215 { return; }
216
217 public event JointMoved OnJointMoved;
218
219 protected virtual void DoJointMoved(PhysicsJoint joint)
220 {
221 // We need this to allow subclasses (but not other classes) to invoke the event; C# does
222 // not allow subclasses to invoke the parent class event.
223 if (OnJointMoved != null)
224 {
225 OnJointMoved(joint);
226 }
227 }
228
229 public event JointDeactivated OnJointDeactivated;
230
231 protected virtual void DoJointDeactivated(PhysicsJoint joint)
232 {
233 // We need this to allow subclasses (but not other classes) to invoke the event; C# does
234 // not allow subclasses to invoke the parent class event.
235 if (OnJointDeactivated != null)
236 {
237 OnJointDeactivated(joint);
238 }
239 }
240
241 public event JointErrorMessage OnJointErrorMessage;
242
243 protected virtual void DoJointErrorMessage(PhysicsJoint joint, string message)
244 {
245 // We need this to allow subclasses (but not other classes) to invoke the event; C# does
246 // not allow subclasses to invoke the parent class event.
247 if (OnJointErrorMessage != null)
248 {
249 OnJointErrorMessage(joint, message);
250 }
251 }
252
253 public virtual Vector3 GetJointAnchor(PhysicsJoint joint)
254 { return Vector3.Zero; }
255
256 public virtual Vector3 GetJointAxis(PhysicsJoint joint)
257 { return Vector3.Zero; }
258
259 public abstract void AddPhysicsActorTaint(PhysicsActor prim);
260
261 /// <summary>
262 /// Perform a simulation of the current physics scene over the given timestep.
263 /// </summary>
264 /// <param name="timeStep"></param>
265 /// <returns>The number of frames simulated over that period.</returns>
266 public abstract float Simulate(float timeStep);
267
268 /// <summary>
269 /// Get statistics about this scene.
270 /// </summary>
271 /// <remarks>This facility is currently experimental and subject to change.</remarks>
272 /// <returns>
273 /// A dictionary where the key is the statistic name. If no statistics are supplied then returns null.
274 /// </returns>
275 public virtual Dictionary<string, float> GetStats() { return null; }
276
277 public abstract void GetResults();
278
279 public abstract void SetTerrain(float[] heightMap);
280
281 public abstract void SetWaterLevel(float baseheight);
282
283 public abstract void DeleteTerrain();
284
285 public abstract void Dispose();
286
287 public abstract Dictionary<uint, float> GetTopColliders();
288
289 public abstract bool IsThreaded { get; }
290
291 /// <summary>
292 /// True if the physics plugin supports raycasting against the physics scene
293 /// </summary>
294 public virtual bool SupportsRayCast()
295 {
296 return false;
297 }
298
299 public virtual bool SupportsCombining()
300 {
301 return false;
302 }
303
304 public virtual void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) {}
305
306 public virtual void UnCombine(PhysicsScene pScene) {}
307
308 /// <summary>
309 /// Queue a raycast against the physics scene.
310 /// The provided callback method will be called when the raycast is complete
311 ///
312 /// Many physics engines don't support collision testing at the same time as
313 /// manipulating the physics scene, so we queue the request up and callback
314 /// a custom method when the raycast is complete.
315 /// This allows physics engines that give an immediate result to callback immediately
316 /// and ones that don't, to callback when it gets a result back.
317 ///
318 /// ODE for example will not allow you to change the scene while collision testing or
319 /// it asserts, 'opteration not valid for locked space'. This includes adding a ray to the scene.
320 ///
321 /// This is named RayCastWorld to not conflict with modrex's Raycast method.
322 /// </summary>
323 /// <param name="position">Origin of the ray</param>
324 /// <param name="direction">Direction of the ray</param>
325 /// <param name="length">Length of ray in meters</param>
326 /// <param name="retMethod">Method to call when the raycast is complete</param>
327 public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
328 {
329 if (retMethod != null)
330 retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero);
331 }
332
333 public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod)
334 {
335 if (retMethod != null)
336 retMethod(new List<ContactResult>());
337 }
338
339 public virtual List<ContactResult> RaycastWorld(Vector3 position, Vector3 direction, float length, int Count)
340 {
341 return new List<ContactResult>();
342 }
343
344 public virtual object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
345 {
346 return null;
347 }
348
349 public virtual bool SupportsRaycastWorldFiltered()
350 {
351 return false;
352 }
353
354 // Extendable interface for new, physics engine specific operations
355 public virtual object Extension(string pFunct, params object[] pParams)
356 {
357 // A NOP if the extension thing is not implemented by the physics engine
358 return null;
359 }
360 }
361}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs
new file mode 100644
index 0000000..f480d71
--- /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.Physics.Manager
33{
34 [Flags]
35 public enum SenseType : uint
36 {
37 NONE = 0,
38 AGENT = 1,
39 ACTIVE = 2,
40 PASSIVE = 3,
41 SCRIPTED = 4
42 }
43
44 public abstract class PhysicsSensor
45 {
46 public static PhysicsSensor Null
47 {
48 get { return new NullPhysicsSensor(); }
49 }
50 public abstract Vector3 Position { get; set; }
51 public abstract void TimerCallback (object obj, ElapsedEventArgs eea);
52 public abstract float radianarc {get; set;}
53 public abstract string targetname {get; set;}
54 public abstract Guid targetKey{get;set;}
55 public abstract SenseType sensetype { get;set;}
56 public abstract float range { get;set;}
57 public abstract float rateSeconds { get;set;}
58 }
59
60 public class NullPhysicsSensor : PhysicsSensor
61 {
62 public override Vector3 Position
63 {
64 get { return Vector3.Zero; }
65 set { return; }
66 }
67 public override void TimerCallback(object obj, ElapsedEventArgs eea)
68 {
69 // don't do squat
70 }
71 public override float radianarc { get { return 0f; } set { } }
72 public override string targetname { get { return ""; } set { } }
73 public override Guid targetKey { get { return Guid.Empty; } set { } }
74 public override SenseType sensetype { get { return SenseType.NONE; } set { } }
75 public override float range { get { return 0; } set { } }
76 public override float rateSeconds { get { return 0; } set { } }
77 }
78}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs b/OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs
new file mode 100644
index 0000000..f60a636
--- /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.Physics.Manager
31{
32 /*public class PhysicsVector
33 {
34 public float X;
35 public float Y;
36 public float Z;
37
38 public Vector3()
39 {
40 }
41
42 public Vector3(float x, float y, float z)
43 {
44 X = x;
45 Y = y;
46 Z = z;
47 }
48
49 public Vector3(Vector3 pv) : this(pv.X, pv.Y, pv.Z)
50 {
51 }
52
53 public void setValues(float x, float y, float z)
54 {
55 X = x;
56 Y = y;
57 Z = z;
58 }
59
60 public static readonly PhysicsVector Zero = new PhysicsVector(0f, 0f, 0f);
61
62 public override string ToString()
63 {
64 return "<" + X + "," + Y + "," + Z + ">";
65 }
66
67 /// <summary>
68 /// These routines are the easiest way to store XYZ values in an Vector3 without requiring 3 calls.
69 /// </summary>
70 /// <returns></returns>
71 public byte[] GetBytes()
72 {
73 byte[] byteArray = new byte[12];
74
75 Buffer.BlockCopy(BitConverter.GetBytes(X), 0, byteArray, 0, 4);
76 Buffer.BlockCopy(BitConverter.GetBytes(Y), 0, byteArray, 4, 4);
77 Buffer.BlockCopy(BitConverter.GetBytes(Z), 0, byteArray, 8, 4);
78
79 if (!BitConverter.IsLittleEndian)
80 {
81 Array.Reverse(byteArray, 0, 4);
82 Array.Reverse(byteArray, 4, 4);
83 Array.Reverse(byteArray, 8, 4);
84 }
85
86 return byteArray;
87 }
88
89 public void FromBytes(byte[] byteArray, int pos)
90 {
91 byte[] conversionBuffer = null;
92 if (!BitConverter.IsLittleEndian)
93 {
94 // Big endian architecture
95 if (conversionBuffer == null)
96 conversionBuffer = new byte[12];
97
98 Buffer.BlockCopy(byteArray, pos, conversionBuffer, 0, 12);
99
100 Array.Reverse(conversionBuffer, 0, 4);
101 Array.Reverse(conversionBuffer, 4, 4);
102 Array.Reverse(conversionBuffer, 8, 4);
103
104 X = BitConverter.ToSingle(conversionBuffer, 0);
105 Y = BitConverter.ToSingle(conversionBuffer, 4);
106 Z = BitConverter.ToSingle(conversionBuffer, 8);
107 }
108 else
109 {
110 // Little endian architecture
111 X = BitConverter.ToSingle(byteArray, pos);
112 Y = BitConverter.ToSingle(byteArray, pos + 4);
113 Z = BitConverter.ToSingle(byteArray, pos + 8);
114 }
115 }
116
117 // Operations
118 public static PhysicsVector operator +(Vector3 a, Vector3 b)
119 {
120 return new PhysicsVector(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
121 }
122
123 public static PhysicsVector operator -(Vector3 a, Vector3 b)
124 {
125 return new PhysicsVector(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
126 }
127
128 public static PhysicsVector cross(Vector3 a, Vector3 b)
129 {
130 return new PhysicsVector(a.Y*b.Z - a.Z*b.Y, a.Z*b.X - a.X*b.Z, a.X*b.Y - a.Y*b.X);
131 }
132
133 public float length()
134 {
135 return (float) Math.Sqrt(X*X + Y*Y + Z*Z);
136 }
137
138 public static float GetDistanceTo(Vector3 a, Vector3 b)
139 {
140 float dx = a.X - b.X;
141 float dy = a.Y - b.Y;
142 float dz = a.Z - b.Z;
143 return (float) Math.Sqrt(dx * dx + dy * dy + dz * dz);
144 }
145
146 public static PhysicsVector operator /(Vector3 v, float f)
147 {
148 return new PhysicsVector(v.X/f, v.Y/f, v.Z/f);
149 }
150
151 public static PhysicsVector operator *(Vector3 v, float f)
152 {
153 return new PhysicsVector(v.X*f, v.Y*f, v.Z*f);
154 }
155
156 public static PhysicsVector operator *(float f, Vector3 v)
157 {
158 return v*f;
159 }
160
161 public static bool isFinite(Vector3 v)
162 {
163 if (v == null)
164 return false;
165 if (Single.IsInfinity(v.X) || Single.IsNaN(v.X))
166 return false;
167 if (Single.IsInfinity(v.Y) || Single.IsNaN(v.Y))
168 return false;
169 if (Single.IsInfinity(v.Z) || Single.IsNaN(v.Z))
170 return false;
171
172 return true;
173 }
174
175 public virtual bool IsIdentical(Vector3 v, float tolerance)
176 {
177 PhysicsVector diff = this - v;
178 float d = diff.length();
179 if (d <= tolerance)
180 return true;
181
182 return false;
183 }
184
185 }*/
186}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs b/OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs
new file mode 100644
index 0000000..f0775c1
--- /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.Physics.Manager
31{
32 public enum Vehicle : int
33 {
34 /// <summary>
35 /// Turns off Vehicle Support
36 /// </summary>
37 TYPE_NONE = 0,
38
39 /// <summary>
40 /// No Angular motor, High Left right friction, No Hover, Linear Deflection 1, no angular deflection
41 /// no vertical attractor, No banking, Identity rotation frame
42 /// </summary>
43 TYPE_SLED = 1,
44
45 /// <summary>
46 /// Needs Motors to be driven by timer or control events High left/right friction, No angular friction
47 /// Linear Motor wins in a second, decays in 60 seconds. Angular motor wins in a second, decays in 8/10ths of a second
48 /// linear deflection 2 seconds
49 /// Vertical Attractor locked UP
50 /// </summary>
51 TYPE_CAR = 2,
52 TYPE_BOAT = 3,
53 TYPE_AIRPLANE = 4,
54 TYPE_BALLOON = 5,
55 LINEAR_FRICTION_TIMESCALE = 16,
56 /// <summary>
57 /// vector of timescales for exponential decay of angular velocity about three axis
58 /// </summary>
59 ANGULAR_FRICTION_TIMESCALE = 17,
60 /// <summary>
61 /// linear velocity vehicle will try for
62 /// </summary>
63 LINEAR_MOTOR_DIRECTION = 18,
64
65 /// <summary>
66 /// Offset from center of mass where linear motor forces are added
67 /// </summary>
68 LINEAR_MOTOR_OFFSET = 20,
69 /// <summary>
70 /// angular velocity that vehicle will try for
71 /// </summary>
72 ANGULAR_MOTOR_DIRECTION = 19,
73 HOVER_HEIGHT = 24,
74 HOVER_EFFICIENCY = 25,
75 HOVER_TIMESCALE = 26,
76 BUOYANCY = 27,
77 LINEAR_DEFLECTION_EFFICIENCY = 28,
78 LINEAR_DEFLECTION_TIMESCALE = 29,
79 LINEAR_MOTOR_TIMESCALE = 30,
80 LINEAR_MOTOR_DECAY_TIMESCALE = 31,
81
82 /// <summary>
83 /// slide between 0 and 1
84 /// </summary>
85 ANGULAR_DEFLECTION_EFFICIENCY = 32,
86 ANGULAR_DEFLECTION_TIMESCALE = 33,
87 ANGULAR_MOTOR_TIMESCALE = 34,
88 ANGULAR_MOTOR_DECAY_TIMESCALE = 35,
89 VERTICAL_ATTRACTION_EFFICIENCY = 36,
90 VERTICAL_ATTRACTION_TIMESCALE = 37,
91 BANKING_EFFICIENCY = 38,
92 BANKING_MIX = 39,
93 BANKING_TIMESCALE = 40,
94 REFERENCE_FRAME = 44,
95 BLOCK_EXIT = 45,
96 ROLL_FRAME = 46
97
98 }
99
100 [Flags]
101 public enum VehicleFlag
102 {
103 NO_DEFLECTION_UP = 1,
104 LIMIT_ROLL_ONLY = 2,
105 HOVER_WATER_ONLY = 4,
106 HOVER_TERRAIN_ONLY = 8,
107 HOVER_GLOBAL_HEIGHT = 16,
108 HOVER_UP_ONLY = 32,
109 LIMIT_MOTOR_UP = 64,
110 MOUSELOOK_STEER = 128,
111 MOUSELOOK_BANK = 256,
112 CAMERA_DECOUPLED = 512,
113 NO_X = 1024,
114 NO_Y = 2048,
115 NO_Z = 4096,
116 LOCK_HOVER_HEIGHT = 8192,
117 NO_DEFLECTION = 16392,
118 LOCK_ROTATION = 32784
119 }
120
121}
diff --git a/OpenSim/Region/PhysicsModules/SharedBase/ZeroMesher.cs b/OpenSim/Region/PhysicsModules/SharedBase/ZeroMesher.cs
new file mode 100644
index 0000000..270d2ec
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/SharedBase/ZeroMesher.cs
@@ -0,0 +1,83 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Framework;
30using OpenMetaverse;
31using Nini.Config;
32
33/*
34 * This is the zero mesher.
35 * Whatever you want him to mesh, he can't, telling you that by responding with a null pointer.
36 * Effectivly this is for switching off meshing and for testing as each physics machine should deal
37 * with the null pointer situation.
38 * But it's also a convenience thing, as physics machines can rely on having a mesher in any situation, even
39 * if it's a dump one like this.
40 * Note, that this mesher is *not* living in a module but in the manager itself, so
41 * it's always availabe and thus the default in case of configuration errors
42*/
43
44namespace OpenSim.Region.Physics.Manager
45{
46 public class ZeroMesherPlugin : IMeshingPlugin
47 {
48 public ZeroMesherPlugin()
49 {
50 }
51
52 public string GetName()
53 {
54 return "ZeroMesher";
55 }
56
57 public IMesher GetMesher(IConfigSource config)
58 {
59 return new ZeroMesher();
60 }
61 }
62
63 public class ZeroMesher : IMesher
64 {
65 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
66 {
67 return CreateMesh(primName, primShape, size, lod, false, false);
68 }
69
70 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical)
71 {
72 return CreateMesh(primName, primShape, size, lod, false, false);
73 }
74
75 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache)
76 {
77 // Remove the reference to the encoded JPEG2000 data so it can be GCed
78 primShape.SculptData = OpenMetaverse.Utils.EmptyBytes;
79
80 return null;
81 }
82 }
83}