aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs451
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs951
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs68
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1357
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs860
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs257
6 files changed, 3944 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
new file mode 100644
index 0000000..682eb80
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.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 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 OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public class BSCharacter : PhysicsActor
38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]";
41
42 private BSScene _scene;
43 private String _avName;
44 private bool _stopped;
45 private Vector3 _size;
46 private Vector3 _scale;
47 private PrimitiveBaseShape _pbs;
48 private uint _localID = 0;
49 private bool _grabbed;
50 private bool _selected;
51 private Vector3 _position;
52 private float _mass;
53 public float _density;
54 public float _avatarVolume;
55 private Vector3 _force;
56 private Vector3 _velocity;
57 private Vector3 _torque;
58 private float _collisionScore;
59 private Vector3 _acceleration;
60 private Quaternion _orientation;
61 private int _physicsActorType;
62 private bool _isPhysical;
63 private bool _flying;
64 private bool _setAlwaysRun;
65 private bool _throttleUpdates;
66 private bool _isColliding;
67 private long _collidingStep;
68 private bool _collidingGround;
69 private long _collidingGroundStep;
70 private bool _collidingObj;
71 private bool _floatOnWater;
72 private Vector3 _rotationalVelocity;
73 private bool _kinematic;
74 private float _buoyancy;
75
76 private int _subscribedEventsMs = 0;
77 private int _lastCollisionTime = 0;
78
79 private Vector3 _PIDTarget;
80 private bool _usePID;
81 private float _PIDTau;
82 private bool _useHoverPID;
83 private float _PIDHoverHeight;
84 private PIDHoverType _PIDHoverType;
85 private float _PIDHoverTao;
86
87 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying)
88 {
89 _localID = localID;
90 _avName = avName;
91 _scene = parent_scene;
92 _position = pos;
93 _size = size;
94 _flying = isFlying;
95 _orientation = Quaternion.Identity;
96 _velocity = Vector3.Zero;
97 _buoyancy = isFlying ? 1f : 0f;
98 _scale = new Vector3(1f, 1f, 1f);
99 _density = _scene.Params.avatarDensity;
100 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale
101
102 ShapeData shapeData = new ShapeData();
103 shapeData.ID = _localID;
104 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
105 shapeData.Position = _position;
106 shapeData.Rotation = _orientation;
107 shapeData.Velocity = _velocity;
108 shapeData.Scale = _scale;
109 shapeData.Mass = _mass;
110 shapeData.Buoyancy = _buoyancy;
111 shapeData.Static = ShapeData.numericFalse;
112 shapeData.Friction = _scene.Params.avatarFriction;
113 shapeData.Restitution = _scene.Params.defaultRestitution;
114
115 // do actual create at taint time
116 _scene.TaintedObject(delegate()
117 {
118 BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData);
119 });
120
121 return;
122 }
123
124 // called when this character is being destroyed and the resources should be released
125 public void Destroy()
126 {
127 _scene.TaintedObject(delegate()
128 {
129 BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
130 });
131 }
132
133 public override void RequestPhysicsterseUpdate()
134 {
135 base.RequestPhysicsterseUpdate();
136 }
137
138 public override bool Stopped {
139 get { return _stopped; }
140 }
141 public override Vector3 Size {
142 get { return _size; }
143 set { _size = value;
144 }
145 }
146 public override PrimitiveBaseShape Shape {
147 set { _pbs = value;
148 }
149 }
150 public override uint LocalID {
151 set { _localID = value;
152 }
153 get { return _localID; }
154 }
155 public override bool Grabbed {
156 set { _grabbed = value;
157 }
158 }
159 public override bool Selected {
160 set { _selected = value;
161 }
162 }
163 public override void CrossingFailure() { return; }
164 public override void link(PhysicsActor obj) { return; }
165 public override void delink() { return; }
166 public override void LockAngularMotion(Vector3 axis) { return; }
167
168 public override Vector3 Position {
169 get {
170 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
171 return _position;
172 }
173 set {
174 _position = value;
175 _scene.TaintedObject(delegate()
176 {
177 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
178 });
179 }
180 }
181 public override float Mass {
182 get {
183 return _mass;
184 }
185 }
186 public override Vector3 Force {
187 get { return _force; }
188 set {
189 _force = value;
190 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
191 _scene.TaintedObject(delegate()
192 {
193 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
194 });
195 }
196 }
197
198 public override int VehicleType {
199 get { return 0; }
200 set { return; }
201 }
202 public override void VehicleFloatParam(int param, float value) { }
203 public override void VehicleVectorParam(int param, Vector3 value) {}
204 public override void VehicleRotationParam(int param, Quaternion rotation) { }
205 public override void VehicleFlags(int param, bool remove) { }
206
207 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
208 public override void SetVolumeDetect(int param) { return; }
209
210 public override Vector3 GeometricCenter { get { return Vector3.Zero; } }
211 public override Vector3 CenterOfMass { get { return Vector3.Zero; } }
212 public override Vector3 Velocity {
213 get { return _velocity; }
214 set {
215 _velocity = value;
216 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
217 _scene.TaintedObject(delegate()
218 {
219 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity);
220 });
221 }
222 }
223 public override Vector3 Torque {
224 get { return _torque; }
225 set { _torque = value;
226 }
227 }
228 public override float CollisionScore {
229 get { return _collisionScore; }
230 set { _collisionScore = value;
231 }
232 }
233 public override Vector3 Acceleration {
234 get { return _acceleration; }
235 }
236 public override Quaternion Orientation {
237 get { return _orientation; }
238 set {
239 _orientation = value;
240 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
241 _scene.TaintedObject(delegate()
242 {
243 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
244 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
245 });
246 }
247 }
248 public override int PhysicsActorType {
249 get { return _physicsActorType; }
250 set { _physicsActorType = value;
251 }
252 }
253 public override bool IsPhysical {
254 get { return _isPhysical; }
255 set { _isPhysical = value;
256 }
257 }
258 public override bool Flying {
259 get { return _flying; }
260 set {
261 _flying = value;
262 _scene.TaintedObject(delegate()
263 {
264 // simulate flying by changing the effect of gravity
265 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _flying ? 1f : 0f);
266 });
267 }
268 }
269 public override bool
270 SetAlwaysRun {
271 get { return _setAlwaysRun; }
272 set { _setAlwaysRun = value; }
273 }
274 public override bool ThrottleUpdates {
275 get { return _throttleUpdates; }
276 set { _throttleUpdates = value; }
277 }
278 public override bool IsColliding {
279 get { return (_collidingStep == _scene.SimulationStep); }
280 set { _isColliding = value; }
281 }
282 public override bool CollidingGround {
283 get { return (_collidingGroundStep == _scene.SimulationStep); }
284 set { _collidingGround = value; }
285 }
286 public override bool CollidingObj {
287 get { return _collidingObj; }
288 set { _collidingObj = value; }
289 }
290 public override bool FloatOnWater {
291 set { _floatOnWater = value; }
292 }
293 public override Vector3 RotationalVelocity {
294 get { return _rotationalVelocity; }
295 set { _rotationalVelocity = value; }
296 }
297 public override bool Kinematic {
298 get { return _kinematic; }
299 set { _kinematic = value; }
300 }
301 public override float Buoyancy {
302 get { return _buoyancy; }
303 set { _buoyancy = value;
304 _scene.TaintedObject(delegate()
305 {
306 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy);
307 });
308 }
309 }
310
311 // Used for MoveTo
312 public override Vector3 PIDTarget {
313 set { _PIDTarget = value; }
314 }
315 public override bool PIDActive {
316 set { _usePID = value; }
317 }
318 public override float PIDTau {
319 set { _PIDTau = value; }
320 }
321
322 // Used for llSetHoverHeight and maybe vehicle height
323 // Hover Height will override MoveTo target's Z
324 public override bool PIDHoverActive {
325 set { _useHoverPID = value; }
326 }
327 public override float PIDHoverHeight {
328 set { _PIDHoverHeight = value; }
329 }
330 public override PIDHoverType PIDHoverType {
331 set { _PIDHoverType = value; }
332 }
333 public override float PIDHoverTau {
334 set { _PIDHoverTao = value; }
335 }
336
337 // For RotLookAt
338 public override Quaternion APIDTarget { set { return; } }
339 public override bool APIDActive { set { return; } }
340 public override float APIDStrength { set { return; } }
341 public override float APIDDamping { set { return; } }
342
343 public override void AddForce(Vector3 force, bool pushforce) {
344 if (force.IsFinite())
345 {
346 _force.X += force.X;
347 _force.Y += force.Y;
348 _force.Z += force.Z;
349 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
350 _scene.TaintedObject(delegate()
351 {
352 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
353 });
354 }
355 else
356 {
357 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
358 }
359 //m_lastUpdateSent = false;
360 }
361 public override void AddAngularForce(Vector3 force, bool pushforce) {
362 }
363 public override void SetMomentum(Vector3 momentum) {
364 }
365 public override void SubscribeEvents(int ms) {
366 _subscribedEventsMs = ms;
367 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
368 }
369 public override void UnSubscribeEvents() {
370 _subscribedEventsMs = 0;
371 }
372 public override bool SubscribedEvents() {
373 return (_subscribedEventsMs > 0);
374 }
375
376 // set _avatarVolume and _mass based on capsule size, _density and _scale
377 private void ComputeAvatarVolumeAndMass()
378 {
379 _avatarVolume = (float)(
380 Math.PI
381 * _scene.Params.avatarCapsuleRadius * _scale.X
382 * _scene.Params.avatarCapsuleRadius * _scale.Y
383 * _scene.Params.avatarCapsuleHeight * _scale.Z);
384 _mass = _density * _avatarVolume;
385 }
386
387 // The physics engine says that properties have updated. Update same and inform
388 // the world that things have changed.
389 public void UpdateProperties(EntityProperties entprop)
390 {
391 bool changed = false;
392 // we assign to the local variables so the normal set action does not happen
393 if (_position != entprop.Position)
394 {
395 _position = entprop.Position;
396 changed = true;
397 }
398 if (_orientation != entprop.Rotation)
399 {
400 _orientation = entprop.Rotation;
401 changed = true;
402 }
403 if (_velocity != entprop.Velocity)
404 {
405 _velocity = entprop.Velocity;
406 changed = true;
407 }
408 if (_acceleration != entprop.Acceleration)
409 {
410 _acceleration = entprop.Acceleration;
411 changed = true;
412 }
413 if (_rotationalVelocity != entprop.RotationalVelocity)
414 {
415 _rotationalVelocity = entprop.RotationalVelocity;
416 changed = true;
417 }
418 if (changed)
419 {
420 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
421 // Avatar movement is not done by generating this event. There is a system that
422 // checks for avatar updates each heartbeat loop.
423 // base.RequestPhysicsterseUpdate();
424 }
425 }
426
427 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
428 {
429 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
430
431 // The following makes IsColliding() and IsCollidingGround() work
432 _collidingStep = _scene.SimulationStep;
433 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
434 {
435 _collidingGroundStep = _scene.SimulationStep;
436 }
437
438 // throttle collisions to the rate specified in the subscription
439 if (_subscribedEventsMs == 0) return; // don't want collisions
440 int nowTime = _scene.SimulationNowTime;
441 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
442 _lastCollisionTime = nowTime;
443
444 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
445 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
446 CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
447 base.SendCollisionUpdate(args);
448 }
449
450}
451}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
new file mode 100644
index 0000000..046726d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -0,0 +1,951 @@
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/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
29 * call the BulletSim system.
30 */
31/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces
32 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
33 * ODEPrim.cs contains methods dealing with Prim editing, Prim
34 * characteristics and Kinetic motion.
35 * ODEDynamics.cs contains methods dealing with Prim Physical motion
36 * (dynamics) and the associated settings. Old Linear and angular
37 * motors for dynamic motion have been replace with MoveLinear()
38 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
39 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
40 * switch between 'VEHICLE' parameter use and general dynamics
41 * settings use.
42 */
43
44using System;
45using System.Collections.Generic;
46using System.Reflection;
47using System.Runtime.InteropServices;
48using log4net;
49using OpenMetaverse;
50using OpenSim.Framework;
51using OpenSim.Region.Physics.Manager;
52
53namespace OpenSim.Region.Physics.BulletSPlugin
54{
55 public class BSDynamics
56 {
57 private int frcount = 0; // Used to limit dynamics debug output to
58 // every 100th frame
59
60 // private BSScene m_parentScene = null;
61 private BSPrim m_prim; // the prim this dynamic controller belongs to
62
63 // Vehicle properties
64 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind
65 public Vehicle Type
66 {
67 get { return m_type; }
68 }
69 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
70 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
71 // HOVER_TERRAIN_ONLY
72 // HOVER_GLOBAL_HEIGHT
73 // NO_DEFLECTION_UP
74 // HOVER_WATER_ONLY
75 // HOVER_UP_ONLY
76 // LIMIT_MOTOR_UP
77 // LIMIT_ROLL_ONLY
78 private VehicleFlag m_Hoverflags = (VehicleFlag)0;
79 private Vector3 m_BlockingEndPoint = Vector3.Zero;
80 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
81 // Linear properties
82 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
83 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
84 private Vector3 m_dir = Vector3.Zero; // velocity applied to body
85 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
86 private float m_linearMotorDecayTimescale = 0;
87 private float m_linearMotorTimescale = 0;
88 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
89 private Vector3 m_lastPositionVector = Vector3.Zero;
90 // private bool m_LinearMotorSetLastFrame = false;
91 // private Vector3 m_linearMotorOffset = Vector3.Zero;
92
93 //Angular properties
94 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
95 private int m_angularMotorApply = 0; // application frame counter
96 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
97 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
98 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
99 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
100 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
101 // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
102
103 //Deflection properties
104 // private float m_angularDeflectionEfficiency = 0;
105 // private float m_angularDeflectionTimescale = 0;
106 // private float m_linearDeflectionEfficiency = 0;
107 // private float m_linearDeflectionTimescale = 0;
108
109 //Banking properties
110 // private float m_bankingEfficiency = 0;
111 // private float m_bankingMix = 0;
112 // private float m_bankingTimescale = 0;
113
114 //Hover and Buoyancy properties
115 private float m_VhoverHeight = 0f;
116// private float m_VhoverEfficiency = 0f;
117 private float m_VhoverTimescale = 0f;
118 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
119 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
120 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
121 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity.
122 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
123
124 //Attractor properties
125 private float m_verticalAttractionEfficiency = 1.0f; // damped
126 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
127
128 public BSDynamics(BSPrim myPrim)
129 {
130 m_prim = myPrim;
131 m_type = Vehicle.TYPE_NONE;
132 }
133
134 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
135 {
136 switch (pParam)
137 {
138 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
139 if (pValue < 0.01f) pValue = 0.01f;
140 // m_angularDeflectionEfficiency = pValue;
141 break;
142 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
143 if (pValue < 0.01f) pValue = 0.01f;
144 // m_angularDeflectionTimescale = pValue;
145 break;
146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
147 if (pValue < 0.01f) pValue = 0.01f;
148 m_angularMotorDecayTimescale = pValue;
149 break;
150 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
151 if (pValue < 0.01f) pValue = 0.01f;
152 m_angularMotorTimescale = pValue;
153 break;
154 case Vehicle.BANKING_EFFICIENCY:
155 if (pValue < 0.01f) pValue = 0.01f;
156 // m_bankingEfficiency = pValue;
157 break;
158 case Vehicle.BANKING_MIX:
159 if (pValue < 0.01f) pValue = 0.01f;
160 // m_bankingMix = pValue;
161 break;
162 case Vehicle.BANKING_TIMESCALE:
163 if (pValue < 0.01f) pValue = 0.01f;
164 // m_bankingTimescale = pValue;
165 break;
166 case Vehicle.BUOYANCY:
167 if (pValue < -1f) pValue = -1f;
168 if (pValue > 1f) pValue = 1f;
169 m_VehicleBuoyancy = pValue;
170 break;
171// case Vehicle.HOVER_EFFICIENCY:
172// if (pValue < 0f) pValue = 0f;
173// if (pValue > 1f) pValue = 1f;
174// m_VhoverEfficiency = pValue;
175// break;
176 case Vehicle.HOVER_HEIGHT:
177 m_VhoverHeight = pValue;
178 break;
179 case Vehicle.HOVER_TIMESCALE:
180 if (pValue < 0.01f) pValue = 0.01f;
181 m_VhoverTimescale = pValue;
182 break;
183 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
184 if (pValue < 0.01f) pValue = 0.01f;
185 // m_linearDeflectionEfficiency = pValue;
186 break;
187 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
188 if (pValue < 0.01f) pValue = 0.01f;
189 // m_linearDeflectionTimescale = pValue;
190 break;
191 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
192 if (pValue < 0.01f) pValue = 0.01f;
193 m_linearMotorDecayTimescale = pValue;
194 break;
195 case Vehicle.LINEAR_MOTOR_TIMESCALE:
196 if (pValue < 0.01f) pValue = 0.01f;
197 m_linearMotorTimescale = pValue;
198 break;
199 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
200 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable
201 if (pValue > 1.0f) pValue = 1.0f;
202 m_verticalAttractionEfficiency = pValue;
203 break;
204 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
205 if (pValue < 0.01f) pValue = 0.01f;
206 m_verticalAttractionTimescale = pValue;
207 break;
208
209 // These are vector properties but the engine lets you use a single float value to
210 // set all of the components to the same value
211 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
212 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
213 break;
214 case Vehicle.ANGULAR_MOTOR_DIRECTION:
215 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
216 m_angularMotorApply = 10;
217 break;
218 case Vehicle.LINEAR_FRICTION_TIMESCALE:
219 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
220 break;
221 case Vehicle.LINEAR_MOTOR_DIRECTION:
222 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
223 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
224 break;
225 case Vehicle.LINEAR_MOTOR_OFFSET:
226 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
227 break;
228
229 }
230 }//end ProcessFloatVehicleParam
231
232 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 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 // Limit requested angular speed to 2 rps= 4 pi rads/sec
242 if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f;
243 if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f;
244 if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f;
245 if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f;
246 if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f;
247 if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
248 m_angularMotorApply = 10;
249 break;
250 case Vehicle.LINEAR_FRICTION_TIMESCALE:
251 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
252 break;
253 case Vehicle.LINEAR_MOTOR_DIRECTION:
254 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
255 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
256 break;
257 case Vehicle.LINEAR_MOTOR_OFFSET:
258 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
259 break;
260 case Vehicle.BLOCK_EXIT:
261 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
262 break;
263 }
264 }//end ProcessVectorVehicleParam
265
266 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
267 {
268 switch (pParam)
269 {
270 case Vehicle.REFERENCE_FRAME:
271 // m_referenceFrame = pValue;
272 break;
273 case Vehicle.ROLL_FRAME:
274 m_RollreferenceFrame = pValue;
275 break;
276 }
277 }//end ProcessRotationVehicleParam
278
279 internal void ProcessVehicleFlags(int pParam, bool remove)
280 {
281 if (remove)
282 {
283 if (pParam == -1)
284 {
285 m_flags = (VehicleFlag)0;
286 m_Hoverflags = (VehicleFlag)0;
287 return;
288 }
289 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
290 {
291 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0)
292 m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT);
293 }
294 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
295 {
296 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0)
297 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY);
298 }
299 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
300 {
301 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0)
302 m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY);
303 }
304 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
305 {
306 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0)
307 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY);
308 }
309 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
310 {
311 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0)
312 m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP);
313 }
314 if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY)
315 {
316 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0)
317 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
318 }
319 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
320 {
321 if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0)
322 m_flags &= ~(VehicleFlag.MOUSELOOK_BANK);
323 }
324 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
325 {
326 if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0)
327 m_flags &= ~(VehicleFlag.MOUSELOOK_STEER);
328 }
329 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
330 {
331 if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0)
332 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP);
333 }
334 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
335 {
336 if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0)
337 m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED);
338 }
339 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
340 {
341 if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0)
342 m_flags &= ~(VehicleFlag.NO_X);
343 }
344 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
345 {
346 if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0)
347 m_flags &= ~(VehicleFlag.NO_Y);
348 }
349 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
350 {
351 if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0)
352 m_flags &= ~(VehicleFlag.NO_Z);
353 }
354 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
355 {
356 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0)
357 m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT);
358 }
359 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
360 {
361 if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0)
362 m_flags &= ~(VehicleFlag.NO_DEFLECTION);
363 }
364 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
365 {
366 if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0)
367 m_flags &= ~(VehicleFlag.LOCK_ROTATION);
368 }
369 }
370 else
371 {
372 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
373 {
374 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags);
375 }
376 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
377 {
378 m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags);
379 }
380 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
381 {
382 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags);
383 }
384 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
385 {
386 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags);
387 }
388 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
389 {
390 m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags);
391 }
392 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
393 {
394 m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags);
395 }
396 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
397 {
398 m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags);
399 }
400 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
401 {
402 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags);
403 }
404 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
405 {
406 m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags);
407 }
408 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
409 {
410 m_flags |= (VehicleFlag.NO_X);
411 }
412 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
413 {
414 m_flags |= (VehicleFlag.NO_Y);
415 }
416 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
417 {
418 m_flags |= (VehicleFlag.NO_Z);
419 }
420 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
421 {
422 m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT);
423 }
424 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
425 {
426 m_flags |= (VehicleFlag.NO_DEFLECTION);
427 }
428 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
429 {
430 m_flags |= (VehicleFlag.LOCK_ROTATION);
431 }
432 }
433 }//end ProcessVehicleFlags
434
435 internal void ProcessTypeChange(Vehicle pType)
436 {
437 // Set Defaults For Type
438 m_type = pType;
439 switch (pType)
440 {
441 case Vehicle.TYPE_NONE:
442 m_linearFrictionTimescale = new Vector3(0, 0, 0);
443 m_angularFrictionTimescale = new Vector3(0, 0, 0);
444 m_linearMotorDirection = Vector3.Zero;
445 m_linearMotorTimescale = 0;
446 m_linearMotorDecayTimescale = 0;
447 m_angularMotorDirection = Vector3.Zero;
448 m_angularMotorTimescale = 0;
449 m_angularMotorDecayTimescale = 0;
450 m_VhoverHeight = 0;
451 m_VhoverTimescale = 0;
452 m_VehicleBuoyancy = 0;
453 m_flags = (VehicleFlag)0;
454 break;
455
456 case Vehicle.TYPE_SLED:
457 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
458 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
459 m_linearMotorDirection = Vector3.Zero;
460 m_linearMotorTimescale = 1000;
461 m_linearMotorDecayTimescale = 120;
462 m_angularMotorDirection = Vector3.Zero;
463 m_angularMotorTimescale = 1000;
464 m_angularMotorDecayTimescale = 120;
465 m_VhoverHeight = 0;
466// m_VhoverEfficiency = 1;
467 m_VhoverTimescale = 10;
468 m_VehicleBuoyancy = 0;
469 // m_linearDeflectionEfficiency = 1;
470 // m_linearDeflectionTimescale = 1;
471 // m_angularDeflectionEfficiency = 1;
472 // m_angularDeflectionTimescale = 1000;
473 // m_bankingEfficiency = 0;
474 // m_bankingMix = 1;
475 // m_bankingTimescale = 10;
476 // m_referenceFrame = Quaternion.Identity;
477 m_Hoverflags &=
478 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
479 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
480 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
481 break;
482 case Vehicle.TYPE_CAR:
483 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
484 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
485 m_linearMotorDirection = Vector3.Zero;
486 m_linearMotorTimescale = 1;
487 m_linearMotorDecayTimescale = 60;
488 m_angularMotorDirection = Vector3.Zero;
489 m_angularMotorTimescale = 1;
490 m_angularMotorDecayTimescale = 0.8f;
491 m_VhoverHeight = 0;
492// m_VhoverEfficiency = 0;
493 m_VhoverTimescale = 1000;
494 m_VehicleBuoyancy = 0;
495 // // m_linearDeflectionEfficiency = 1;
496 // // m_linearDeflectionTimescale = 2;
497 // // m_angularDeflectionEfficiency = 0;
498 // m_angularDeflectionTimescale = 10;
499 m_verticalAttractionEfficiency = 1f;
500 m_verticalAttractionTimescale = 10f;
501 // m_bankingEfficiency = -0.2f;
502 // m_bankingMix = 1;
503 // m_bankingTimescale = 1;
504 // m_referenceFrame = Quaternion.Identity;
505 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT);
506 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY |
507 VehicleFlag.LIMIT_MOTOR_UP);
508 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY);
509 break;
510 case Vehicle.TYPE_BOAT:
511 m_linearFrictionTimescale = new Vector3(10, 3, 2);
512 m_angularFrictionTimescale = new Vector3(10,10,10);
513 m_linearMotorDirection = Vector3.Zero;
514 m_linearMotorTimescale = 5;
515 m_linearMotorDecayTimescale = 60;
516 m_angularMotorDirection = Vector3.Zero;
517 m_angularMotorTimescale = 4;
518 m_angularMotorDecayTimescale = 4;
519 m_VhoverHeight = 0;
520// m_VhoverEfficiency = 0.5f;
521 m_VhoverTimescale = 2;
522 m_VehicleBuoyancy = 1;
523 // m_linearDeflectionEfficiency = 0.5f;
524 // m_linearDeflectionTimescale = 3;
525 // m_angularDeflectionEfficiency = 0.5f;
526 // m_angularDeflectionTimescale = 5;
527 m_verticalAttractionEfficiency = 0.5f;
528 m_verticalAttractionTimescale = 5f;
529 // m_bankingEfficiency = -0.3f;
530 // m_bankingMix = 0.8f;
531 // m_bankingTimescale = 1;
532 // m_referenceFrame = Quaternion.Identity;
533 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
534 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
535 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
536 m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
537 VehicleFlag.LIMIT_MOTOR_UP);
538 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY);
539 break;
540 case Vehicle.TYPE_AIRPLANE:
541 m_linearFrictionTimescale = new Vector3(200, 10, 5);
542 m_angularFrictionTimescale = new Vector3(20, 20, 20);
543 m_linearMotorDirection = Vector3.Zero;
544 m_linearMotorTimescale = 2;
545 m_linearMotorDecayTimescale = 60;
546 m_angularMotorDirection = Vector3.Zero;
547 m_angularMotorTimescale = 4;
548 m_angularMotorDecayTimescale = 4;
549 m_VhoverHeight = 0;
550// m_VhoverEfficiency = 0.5f;
551 m_VhoverTimescale = 1000;
552 m_VehicleBuoyancy = 0;
553 // m_linearDeflectionEfficiency = 0.5f;
554 // m_linearDeflectionTimescale = 3;
555 // m_angularDeflectionEfficiency = 1;
556 // m_angularDeflectionTimescale = 2;
557 m_verticalAttractionEfficiency = 0.9f;
558 m_verticalAttractionTimescale = 2f;
559 // m_bankingEfficiency = 1;
560 // m_bankingMix = 0.7f;
561 // m_bankingTimescale = 2;
562 // m_referenceFrame = Quaternion.Identity;
563 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
564 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
565 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
566 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
567 break;
568 case Vehicle.TYPE_BALLOON:
569 m_linearFrictionTimescale = new Vector3(5, 5, 5);
570 m_angularFrictionTimescale = new Vector3(10, 10, 10);
571 m_linearMotorDirection = Vector3.Zero;
572 m_linearMotorTimescale = 5;
573 m_linearMotorDecayTimescale = 60;
574 m_angularMotorDirection = Vector3.Zero;
575 m_angularMotorTimescale = 6;
576 m_angularMotorDecayTimescale = 10;
577 m_VhoverHeight = 5;
578// m_VhoverEfficiency = 0.8f;
579 m_VhoverTimescale = 10;
580 m_VehicleBuoyancy = 1;
581 // m_linearDeflectionEfficiency = 0;
582 // m_linearDeflectionTimescale = 5;
583 // m_angularDeflectionEfficiency = 0;
584 // m_angularDeflectionTimescale = 5;
585 m_verticalAttractionEfficiency = 1f;
586 m_verticalAttractionTimescale = 100f;
587 // m_bankingEfficiency = 0;
588 // m_bankingMix = 0.7f;
589 // m_bankingTimescale = 5;
590 // m_referenceFrame = Quaternion.Identity;
591 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
592 VehicleFlag.HOVER_UP_ONLY);
593 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP);
594 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
595 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT);
596 break;
597
598 }
599 }//end SetDefaultsForType
600
601 internal void Step(float pTimestep, BSScene pParentScene)
602 {
603 if (m_type == Vehicle.TYPE_NONE) return;
604
605 frcount++; // used to limit debug comment output
606 if (frcount > 100)
607 frcount = 0;
608
609 MoveLinear(pTimestep, pParentScene);
610 MoveAngular(pTimestep);
611 LimitRotation(pTimestep);
612 }// end Step
613
614 private void MoveLinear(float pTimestep, BSScene _pParentScene)
615 {
616 if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant
617 {
618 // add drive to body
619 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep);
620 m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector?
621
622 // This will work temporarily, but we really need to compare speed on an axis
623 // KF: Limit body velocity to applied velocity?
624 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
625 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
626 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
627 m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y;
628 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
629 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
630
631 // decay applied velocity
632 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
633 //Console.WriteLine("decay: " + decayfraction);
634 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
635 //Console.WriteLine("actual: " + m_linearMotorDirection);
636 }
637 else
638 { // requested is not significant
639 // if what remains of applied is small, zero it.
640 if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
641 m_lastLinearVelocityVector = Vector3.Zero;
642 }
643
644 // convert requested object velocity to world-referenced vector
645 m_dir = m_lastLinearVelocityVector;
646 Quaternion rot = m_prim.Orientation;
647 Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object
648 m_dir *= rotq; // apply obj rotation to velocity vector
649
650 // add Gravity andBuoyancy
651 // KF: So far I have found no good method to combine a script-requested
652 // .Z velocity and gravity. Therefore only 0g will used script-requested
653 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
654 Vector3 grav = Vector3.Zero;
655 // There is some gravity, make a gravity force vector
656 // that is applied after object velocity.
657 float objMass = m_prim.Mass;
658 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
659 grav.Z = _pParentScene.DefaultGravity.Z * objMass * (1f - m_VehicleBuoyancy);
660 // Preserve the current Z velocity
661 Vector3 vel_now = m_prim.Velocity;
662 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
663
664 Vector3 pos = m_prim.Position;
665// 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);
666 Vector3 posChange = new Vector3();
667 posChange.X = pos.X - m_lastPositionVector.X;
668 posChange.Y = pos.Y - m_lastPositionVector.Y;
669 posChange.Z = pos.Z - m_lastPositionVector.Z;
670 double Zchange = Math.Abs(posChange.Z);
671 if (m_BlockingEndPoint != Vector3.Zero)
672 {
673 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
674 {
675 pos.X -= posChange.X + 1;
676 m_prim.Position = pos;
677 }
678 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
679 {
680 pos.Y -= posChange.Y + 1;
681 m_prim.Position = pos;
682 }
683 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
684 {
685 pos.Z -= posChange.Z + 1;
686 m_prim.Position = pos;
687 }
688 if (pos.X <= 0)
689 {
690 pos.X += posChange.X + 1;
691 m_prim.Position = pos;
692 }
693 if (pos.Y <= 0)
694 {
695 pos.Y += posChange.Y + 1;
696 m_prim.Position = pos;
697 }
698 }
699 if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y))
700 {
701 pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2;
702 m_prim.Position = pos;
703 }
704
705 // Check if hovering
706 if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
707 {
708 // We should hover, get the target height
709 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0)
710 {
711 m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight;
712 }
713 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
714 {
715 m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
716 }
717 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
718 {
719 m_VhoverTargetHeight = m_VhoverHeight;
720 }
721
722 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0)
723 {
724 // If body is aready heigher, use its height as target height
725 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z;
726 }
727 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
728 {
729 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
730 {
731 m_prim.Position = pos;
732 }
733 }
734 else
735 {
736 float herr0 = pos.Z - m_VhoverTargetHeight;
737 // Replace Vertical speed with correction figure if significant
738 if (Math.Abs(herr0) > 0.01f)
739 {
740 m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale);
741 //KF: m_VhoverEfficiency is not yet implemented
742 }
743 else
744 {
745 m_dir.Z = 0f;
746 }
747 }
748
749// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
750// m_VhoverTimescale = 0f; // time to acheive height
751// pTimestep is time since last frame,in secs
752 }
753
754 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
755 {
756 //Start Experimental Values
757 if (Zchange > .3)
758 {
759 grav.Z = (float)(grav.Z * 3);
760 }
761 if (Zchange > .15)
762 {
763 grav.Z = (float)(grav.Z * 2);
764 }
765 if (Zchange > .75)
766 {
767 grav.Z = (float)(grav.Z * 1.5);
768 }
769 if (Zchange > .05)
770 {
771 grav.Z = (float)(grav.Z * 1.25);
772 }
773 if (Zchange > .025)
774 {
775 grav.Z = (float)(grav.Z * 1.125);
776 }
777 float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y);
778 float postemp = (pos.Z - terraintemp);
779 if (postemp > 2.5f)
780 {
781 grav.Z = (float)(grav.Z * 1.037125);
782 }
783 //End Experimental Values
784 }
785 if ((m_flags & (VehicleFlag.NO_X)) != 0)
786 {
787 m_dir.X = 0;
788 }
789 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
790 {
791 m_dir.Y = 0;
792 }
793 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
794 {
795 m_dir.Z = 0;
796 }
797
798 m_lastPositionVector = m_prim.Position;
799
800 // Apply velocity
801 m_prim.Velocity = m_dir;
802 // apply gravity force
803 m_prim.Force = grav;
804
805
806 // apply friction
807 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
808 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount;
809 } // end MoveLinear()
810
811 private void MoveAngular(float pTimestep)
812 {
813 /*
814 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
815 private int m_angularMotorApply = 0; // application frame counter
816 private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down)
817 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
818 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
819 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
820 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
821 */
822
823 // Get what the body is doing, this includes 'external' influences
824 Vector3 angularVelocity = m_prim.AngularVelocity;
825 // Vector3 angularVelocity = Vector3.Zero;
826
827 if (m_angularMotorApply > 0)
828 {
829 // ramp up to new value
830 // current velocity += error / (time to get there / step interval)
831 // requested speed - last motor speed
832 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep);
833 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
834 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
835
836 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected
837 // velocity may still be acheived.
838 }
839 else
840 {
841 // no motor recently applied, keep the body velocity
842 /* m_angularMotorVelocity.X = angularVelocity.X;
843 m_angularMotorVelocity.Y = angularVelocity.Y;
844 m_angularMotorVelocity.Z = angularVelocity.Z; */
845
846 // and decay the velocity
847 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep);
848 } // end motor section
849
850 // Vertical attractor section
851 Vector3 vertattr = Vector3.Zero;
852
853 if (m_verticalAttractionTimescale < 300)
854 {
855 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep);
856 // get present body rotation
857 Quaternion rotq = m_prim.Orientation;
858 // make a vector pointing up
859 Vector3 verterr = Vector3.Zero;
860 verterr.Z = 1.0f;
861 // rotate it to Body Angle
862 verterr = verterr * rotq;
863 // 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.
864 // 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
865 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body.
866 if (verterr.Z < 0.0f)
867 {
868 verterr.X = 2.0f - verterr.X;
869 verterr.Y = 2.0f - verterr.Y;
870 }
871 // Error is 0 (no error) to +/- 2 (max error)
872 // scale it by VAservo
873 verterr = verterr * VAservo;
874//if (frcount == 0) Console.WriteLine("VAerr=" + verterr);
875
876 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so
877 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed.
878 vertattr.X = verterr.Y;
879 vertattr.Y = - verterr.X;
880 vertattr.Z = 0f;
881
882 // scaling appears better usingsquare-law
883 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
884 vertattr.X += bounce * angularVelocity.X;
885 vertattr.Y += bounce * angularVelocity.Y;
886
887 } // else vertical attractor is off
888
889 // m_lastVertAttractor = vertattr;
890
891 // Bank section tba
892 // Deflection section tba
893
894 // Sum velocities
895 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
896
897 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
898 {
899 m_lastAngularVelocity.X = 0;
900 m_lastAngularVelocity.Y = 0;
901 }
902
903 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
904 {
905 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
906 }
907
908 // apply friction
909 Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
910 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
911
912 // Apply to the body
913 m_prim.AngularVelocity = m_lastAngularVelocity;
914
915 } //end MoveAngular
916 internal void LimitRotation(float timestep)
917 {
918 Quaternion rotq = m_prim.Orientation; // rotq = rotation of object
919 Quaternion m_rot = rotq;
920 bool changed = false;
921 if (m_RollreferenceFrame != Quaternion.Identity)
922 {
923 if (rotq.X >= m_RollreferenceFrame.X)
924 {
925 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
926 }
927 if (rotq.Y >= m_RollreferenceFrame.Y)
928 {
929 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
930 }
931 if (rotq.X <= -m_RollreferenceFrame.X)
932 {
933 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
934 }
935 if (rotq.Y <= -m_RollreferenceFrame.Y)
936 {
937 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
938 }
939 changed = true;
940 }
941 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
942 {
943 m_rot.X = 0;
944 m_rot.Y = 0;
945 changed = true;
946 }
947 if (changed)
948 m_prim.Orientation = m_rot;
949 }
950 }
951}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
new file mode 100644
index 0000000..61be56d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -0,0 +1,68 @@
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{
35public class BSPlugin : IPhysicsPlugin
36{
37 //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
38
39 private BSScene _mScene;
40
41 public BSPlugin()
42 {
43 }
44
45 public bool Init()
46 {
47 return true;
48 }
49
50 public PhysicsScene GetScene(String sceneIdentifier)
51 {
52 if (_mScene == null)
53 {
54 _mScene = new BSScene(sceneIdentifier);
55 }
56 return (_mScene);
57 }
58
59 public string GetName()
60 {
61 return ("BulletSim");
62 }
63
64 public void Dispose()
65 {
66 }
67}
68}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
new file mode 100644
index 0000000..bb8d601
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -0,0 +1,1357 @@
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.Reflection;
29using System.Collections.Generic;
30using System.Xml;
31using log4net;
32using OMV = OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Physics.Manager;
35using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39 [Serializable]
40public sealed class BSPrim : PhysicsActor
41{
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 private static readonly string LogHeader = "[BULLETS PRIM]";
44
45 private IMesh _mesh;
46 private PrimitiveBaseShape _pbs;
47 private ShapeData.PhysicsShapeType _shapeType;
48 private ulong _meshKey;
49 private ulong _hullKey;
50 private List<ConvexResult> _hulls;
51
52 private BSScene _scene;
53 private String _avName;
54 private uint _localID = 0;
55
56 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
57 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
58 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
59 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
60
61 private bool _stopped;
62 private bool _grabbed;
63 private bool _isSelected;
64 private bool _isVolumeDetect;
65 private OMV.Vector3 _position;
66 private float _mass;
67 private float _density;
68 private OMV.Vector3 _force;
69 private OMV.Vector3 _velocity;
70 private OMV.Vector3 _torque;
71 private float _collisionScore;
72 private OMV.Vector3 _acceleration;
73 private OMV.Quaternion _orientation;
74 private int _physicsActorType;
75 private bool _isPhysical;
76 private bool _flying;
77 private float _friction;
78 private float _restitution;
79 private bool _setAlwaysRun;
80 private bool _throttleUpdates;
81 private bool _isColliding;
82 private bool _collidingGround;
83 private bool _collidingObj;
84 private bool _floatOnWater;
85 private OMV.Vector3 _rotationalVelocity;
86 private bool _kinematic;
87 private float _buoyancy;
88 private OMV.Vector3 _angularVelocity;
89
90 private List<BSPrim> _childrenPrims;
91 private BSPrim _parentPrim;
92
93 private int _subscribedEventsMs = 0;
94 private int _lastCollisionTime = 0;
95 long _collidingStep;
96 long _collidingGroundStep;
97
98 private BSDynamics _vehicle;
99
100 private OMV.Vector3 _PIDTarget;
101 private bool _usePID;
102 private float _PIDTau;
103 private bool _useHoverPID;
104 private float _PIDHoverHeight;
105 private PIDHoverType _PIDHoverType;
106 private float _PIDHoverTao;
107
108 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
109 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
110 {
111 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
112 _localID = localID;
113 _avName = primName;
114 _scene = parent_scene;
115 _position = pos;
116 _size = size;
117 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
118 _orientation = rotation;
119 _buoyancy = 1f;
120 _velocity = OMV.Vector3.Zero;
121 _rotationalVelocity = OMV.Vector3.Zero;
122 _angularVelocity = OMV.Vector3.Zero;
123 _hullKey = 0;
124 _meshKey = 0;
125 _pbs = pbs;
126 _isPhysical = pisPhysical;
127 _isVolumeDetect = false;
128 _subscribedEventsMs = 0;
129 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material
130 _density = _scene.Params.defaultDensity; // TODO: compute based on object material
131 _restitution = _scene.Params.defaultRestitution;
132 _parentPrim = null; // not a child or a parent
133 _vehicle = new BSDynamics(this); // add vehicleness
134 _childrenPrims = new List<BSPrim>();
135 if (_isPhysical)
136 _mass = CalculateMass();
137 else
138 _mass = 0f;
139 // do the actual object creation at taint time
140 _scene.TaintedObject(delegate()
141 {
142 RecreateGeomAndObject();
143 });
144 }
145
146 // called when this prim is being destroyed and we should free all the resources
147 public void Destroy()
148 {
149 // m_log.DebugFormat("{0}: Destroy", LogHeader);
150 // Undo any vehicle properties
151 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
152 _scene.RemoveVehiclePrim(this); // just to make sure
153 _scene.TaintedObject(delegate()
154 {
155 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
156 BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
157 });
158 }
159
160 public override bool Stopped {
161 get { return _stopped; }
162 }
163 public override OMV.Vector3 Size {
164 get { return _size; }
165 set {
166 _size = value;
167 _scene.TaintedObject(delegate()
168 {
169 if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass
170 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical);
171 RecreateGeomAndObject();
172 });
173 }
174 }
175 public override PrimitiveBaseShape Shape {
176 set {
177 _pbs = value;
178 _scene.TaintedObject(delegate()
179 {
180 if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass
181 RecreateGeomAndObject();
182 });
183 }
184 }
185 public override uint LocalID {
186 set { _localID = value; }
187 get { return _localID; }
188 }
189 public override bool Grabbed {
190 set { _grabbed = value;
191 }
192 }
193 public override bool Selected {
194 set {
195 _isSelected = value;
196 _scene.TaintedObject(delegate()
197 {
198 SetObjectDynamic();
199 });
200 }
201 }
202 public override void CrossingFailure() { return; }
203
204 // link me to the specified parent
205 public override void link(PhysicsActor obj) {
206 BSPrim parent = (BSPrim)obj;
207 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
208 // TODO: decide if this parent checking needs to happen at taint time
209 if (_parentPrim == null)
210 {
211 if (parent != null)
212 {
213 // I don't have a parent so I am joining a linkset
214 parent.AddChildToLinkset(this);
215 }
216 }
217 else
218 {
219 // I already have a parent, is parenting changing?
220 if (parent != _parentPrim)
221 {
222 if (parent == null)
223 {
224 // we are being removed from a linkset
225 _parentPrim.RemoveChildFromLinkset(this);
226 }
227 else
228 {
229 // asking to reparent a prim should not happen
230 m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader);
231 }
232 }
233 }
234 return;
235 }
236
237 // delink me from my linkset
238 public override void delink() {
239 // TODO: decide if this parent checking needs to happen at taint time
240 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
241 // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID);
242 if (_parentPrim != null)
243 {
244 _parentPrim.RemoveChildFromLinkset(this);
245 }
246 return;
247 }
248
249 // I am the root of a linkset and a new child is being added
250 public void AddChildToLinkset(BSPrim pchild)
251 {
252 BSPrim child = pchild;
253 _scene.TaintedObject(delegate()
254 {
255 if (!_childrenPrims.Contains(child))
256 {
257 _childrenPrims.Add(child);
258 child.ParentPrim = this; // the child has gained a parent
259 RecreateGeomAndObject(); // rebuild my shape with the new child added
260 }
261 });
262 return;
263 }
264
265 // I am the root of a linkset and one of my children is being removed.
266 // Safe to call even if the child is not really in my linkset.
267 public void RemoveChildFromLinkset(BSPrim pchild)
268 {
269 BSPrim child = pchild;
270 _scene.TaintedObject(delegate()
271 {
272 if (_childrenPrims.Contains(child))
273 {
274 BulletSimAPI.RemoveConstraint(_scene.WorldID, child.LocalID, this.LocalID);
275 _childrenPrims.Remove(child);
276 child.ParentPrim = null; // the child has lost its parent
277 RecreateGeomAndObject(); // rebuild my shape with the child removed
278 }
279 else
280 {
281 m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset");
282 }
283 });
284 return;
285 }
286
287 public BSPrim ParentPrim
288 {
289 set { _parentPrim = value; }
290 }
291
292 // return true if we are the root of a linkset (there are children to manage)
293 public bool IsRootOfLinkset
294 {
295 get { return (_parentPrim == null && _childrenPrims.Count != 0); }
296 }
297
298 // Set motion values to zero.
299 // Do it to the properties so the values get set in the physics engine.
300 // Push the setting of the values to the viewer.
301 private void ZeroMotion()
302 {
303 Velocity = OMV.Vector3.Zero;
304 _acceleration = OMV.Vector3.Zero;
305 RotationalVelocity = OMV.Vector3.Zero;
306 base.RequestPhysicsterseUpdate();
307 }
308
309 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
310
311 public override OMV.Vector3 Position {
312 get {
313 // don't do the following GetObjectPosition because this function is called a zillion times
314 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
315 return _position;
316 }
317 set {
318 _position = value;
319 _scene.TaintedObject(delegate()
320 {
321 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
322 // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
323 });
324 }
325 }
326 public override float Mass {
327 get { return _mass; }
328 }
329 public override OMV.Vector3 Force {
330 get { return _force; }
331 set {
332 _force = value;
333 _scene.TaintedObject(delegate()
334 {
335 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
336 });
337 }
338 }
339
340 public override int VehicleType {
341 get {
342 return (int)_vehicle.Type; // if we are a vehicle, return that type
343 }
344 set {
345 Vehicle type = (Vehicle)value;
346 _vehicle.ProcessTypeChange(type);
347 _scene.TaintedObject(delegate()
348 {
349 if (type == Vehicle.TYPE_NONE)
350 {
351 _scene.RemoveVehiclePrim(this);
352 }
353 else
354 {
355 // make it so the scene will call us each tick to do vehicle things
356 _scene.AddVehiclePrim(this);
357 }
358 return;
359 });
360 }
361 }
362 public override void VehicleFloatParam(int param, float value)
363 {
364 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
365 }
366 public override void VehicleVectorParam(int param, OMV.Vector3 value)
367 {
368 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
369 }
370 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
371 {
372 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
373 }
374 public override void VehicleFlags(int param, bool remove)
375 {
376 _vehicle.ProcessVehicleFlags(param, remove);
377 }
378 // Called each simulation step to advance vehicle characteristics
379 public void StepVehicle(float timeStep)
380 {
381 _vehicle.Step(timeStep, _scene);
382 }
383
384 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
385 public override void SetVolumeDetect(int param) {
386 bool newValue = (param != 0);
387 if (_isVolumeDetect != newValue)
388 {
389 _isVolumeDetect = newValue;
390 _scene.TaintedObject(delegate()
391 {
392 SetObjectDynamic();
393 });
394 }
395 return;
396 }
397
398 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
399 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
400 public override OMV.Vector3 Velocity {
401 get { return _velocity; }
402 set { _velocity = value;
403 _scene.TaintedObject(delegate()
404 {
405 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
406 });
407 }
408 }
409 public override OMV.Vector3 Torque {
410 get { return _torque; }
411 set { _torque = value;
412 }
413 }
414 public override float CollisionScore {
415 get { return _collisionScore; }
416 set { _collisionScore = value;
417 }
418 }
419 public override OMV.Vector3 Acceleration {
420 get { return _acceleration; }
421 }
422 public override OMV.Quaternion Orientation {
423 get { return _orientation; }
424 set {
425 _orientation = value;
426 // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation);
427 _scene.TaintedObject(delegate()
428 {
429 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
430 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
431 });
432 }
433 }
434 public override int PhysicsActorType {
435 get { return _physicsActorType; }
436 set { _physicsActorType = value;
437 }
438 }
439 public override bool IsPhysical {
440 get { return _isPhysical; }
441 set {
442 _isPhysical = value;
443 _scene.TaintedObject(delegate()
444 {
445 SetObjectDynamic();
446 });
447 }
448 }
449
450 // An object is static (does not move) if selected or not physical
451 private bool IsStatic
452 {
453 get { return _isSelected || !IsPhysical; }
454 }
455
456 // An object is solid if it's not phantom and if it's not doing VolumeDetect
457 private bool IsSolid
458 {
459 get { return !IsPhantom && !_isVolumeDetect; }
460 }
461
462 // make gravity work if the object is physical and not selected
463 // no locking here because only called when it is safe
464 private void SetObjectDynamic()
465 {
466 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid);
467 // non-physical things work best with a mass of zero
468 if (IsStatic)
469 {
470 _mass = 0f;
471 }
472 else
473 {
474 _mass = CalculateMass();
475 // If it's dynamic, make sure the hull has been created for it
476 // This shouldn't do much work if the object had previously been built
477 RecreateGeomAndObject();
478
479 }
480 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass);
481 }
482
483 // prims don't fly
484 public override bool Flying {
485 get { return _flying; }
486 set { _flying = value; }
487 }
488 public override bool SetAlwaysRun {
489 get { return _setAlwaysRun; }
490 set { _setAlwaysRun = value; }
491 }
492 public override bool ThrottleUpdates {
493 get { return _throttleUpdates; }
494 set { _throttleUpdates = value; }
495 }
496 public override bool IsColliding {
497 get { return (_collidingStep == _scene.SimulationStep); }
498 set { _isColliding = value; }
499 }
500 public override bool CollidingGround {
501 get { return (_collidingGroundStep == _scene.SimulationStep); }
502 set { _collidingGround = value; }
503 }
504 public override bool CollidingObj {
505 get { return _collidingObj; }
506 set { _collidingObj = value; }
507 }
508 public bool IsPhantom {
509 get {
510 // SceneObjectPart removes phantom objects from the physics scene
511 // so, although we could implement touching and such, we never
512 // are invoked as a phantom object
513 return false;
514 }
515 }
516 public override bool FloatOnWater {
517 set { _floatOnWater = value; }
518 }
519 public override OMV.Vector3 RotationalVelocity {
520 get { return _rotationalVelocity; }
521 set { _rotationalVelocity = value;
522 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
523 _scene.TaintedObject(delegate()
524 {
525 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
526 });
527 }
528 }
529 public OMV.Vector3 AngularVelocity {
530 get { return _angularVelocity; }
531 set { _angularVelocity = value; }
532 }
533 public override bool Kinematic {
534 get { return _kinematic; }
535 set { _kinematic = value;
536 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
537 }
538 }
539 public override float Buoyancy {
540 get { return _buoyancy; }
541 set { _buoyancy = value;
542 _scene.TaintedObject(delegate()
543 {
544 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
545 });
546 }
547 }
548
549 // Used for MoveTo
550 public override OMV.Vector3 PIDTarget {
551 set { _PIDTarget = value; }
552 }
553 public override bool PIDActive {
554 set { _usePID = value; }
555 }
556 public override float PIDTau {
557 set { _PIDTau = value; }
558 }
559
560 // Used for llSetHoverHeight and maybe vehicle height
561 // Hover Height will override MoveTo target's Z
562 public override bool PIDHoverActive {
563 set { _useHoverPID = value; }
564 }
565 public override float PIDHoverHeight {
566 set { _PIDHoverHeight = value; }
567 }
568 public override PIDHoverType PIDHoverType {
569 set { _PIDHoverType = value; }
570 }
571 public override float PIDHoverTau {
572 set { _PIDHoverTao = value; }
573 }
574
575 // For RotLookAt
576 public override OMV.Quaternion APIDTarget { set { return; } }
577 public override bool APIDActive { set { return; } }
578 public override float APIDStrength { set { return; } }
579 public override float APIDDamping { set { return; } }
580
581 public override void AddForce(OMV.Vector3 force, bool pushforce) {
582 if (force.IsFinite())
583 {
584 _force.X += force.X;
585 _force.Y += force.Y;
586 _force.Z += force.Z;
587 }
588 else
589 {
590 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
591 }
592 _scene.TaintedObject(delegate()
593 {
594 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
595 });
596 }
597
598 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
599 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
600 }
601 public override void SetMomentum(OMV.Vector3 momentum) {
602 }
603 public override void SubscribeEvents(int ms) {
604 _subscribedEventsMs = ms;
605 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
606 }
607 public override void UnSubscribeEvents() {
608 _subscribedEventsMs = 0;
609 }
610 public override bool SubscribedEvents() {
611 return (_subscribedEventsMs > 0);
612 }
613
614 #region Mass Calculation
615
616 private float CalculateMass()
617 {
618 float volume = _size.X * _size.Y * _size.Z; // default
619 float tmp;
620
621 float returnMass = 0;
622 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
623 float hollowVolume = hollowAmount * hollowAmount;
624
625 switch (_pbs.ProfileShape)
626 {
627 case ProfileShape.Square:
628 // default box
629
630 if (_pbs.PathCurve == (byte)Extrusion.Straight)
631 {
632 if (hollowAmount > 0.0)
633 {
634 switch (_pbs.HollowShape)
635 {
636 case HollowShape.Square:
637 case HollowShape.Same:
638 break;
639
640 case HollowShape.Circle:
641
642 hollowVolume *= 0.78539816339f;
643 break;
644
645 case HollowShape.Triangle:
646
647 hollowVolume *= (0.5f * .5f);
648 break;
649
650 default:
651 hollowVolume = 0;
652 break;
653 }
654 volume *= (1.0f - hollowVolume);
655 }
656 }
657
658 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
659 {
660 //a tube
661
662 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
663 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
664 volume -= volume*tmp*tmp;
665
666 if (hollowAmount > 0.0)
667 {
668 hollowVolume *= hollowAmount;
669
670 switch (_pbs.HollowShape)
671 {
672 case HollowShape.Square:
673 case HollowShape.Same:
674 break;
675
676 case HollowShape.Circle:
677 hollowVolume *= 0.78539816339f;;
678 break;
679
680 case HollowShape.Triangle:
681 hollowVolume *= 0.5f * 0.5f;
682 break;
683 default:
684 hollowVolume = 0;
685 break;
686 }
687 volume *= (1.0f - hollowVolume);
688 }
689 }
690
691 break;
692
693 case ProfileShape.Circle:
694
695 if (_pbs.PathCurve == (byte)Extrusion.Straight)
696 {
697 volume *= 0.78539816339f; // elipse base
698
699 if (hollowAmount > 0.0)
700 {
701 switch (_pbs.HollowShape)
702 {
703 case HollowShape.Same:
704 case HollowShape.Circle:
705 break;
706
707 case HollowShape.Square:
708 hollowVolume *= 0.5f * 2.5984480504799f;
709 break;
710
711 case HollowShape.Triangle:
712 hollowVolume *= .5f * 1.27323954473516f;
713 break;
714
715 default:
716 hollowVolume = 0;
717 break;
718 }
719 volume *= (1.0f - hollowVolume);
720 }
721 }
722
723 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
724 {
725 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
726 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
727 volume *= (1.0f - tmp * tmp);
728
729 if (hollowAmount > 0.0)
730 {
731
732 // calculate the hollow volume by it's shape compared to the prim shape
733 hollowVolume *= hollowAmount;
734
735 switch (_pbs.HollowShape)
736 {
737 case HollowShape.Same:
738 case HollowShape.Circle:
739 break;
740
741 case HollowShape.Square:
742 hollowVolume *= 0.5f * 2.5984480504799f;
743 break;
744
745 case HollowShape.Triangle:
746 hollowVolume *= .5f * 1.27323954473516f;
747 break;
748
749 default:
750 hollowVolume = 0;
751 break;
752 }
753 volume *= (1.0f - hollowVolume);
754 }
755 }
756 break;
757
758 case ProfileShape.HalfCircle:
759 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
760 {
761 volume *= 0.52359877559829887307710723054658f;
762 }
763 break;
764
765 case ProfileShape.EquilateralTriangle:
766
767 if (_pbs.PathCurve == (byte)Extrusion.Straight)
768 {
769 volume *= 0.32475953f;
770
771 if (hollowAmount > 0.0)
772 {
773
774 // calculate the hollow volume by it's shape compared to the prim shape
775 switch (_pbs.HollowShape)
776 {
777 case HollowShape.Same:
778 case HollowShape.Triangle:
779 hollowVolume *= .25f;
780 break;
781
782 case HollowShape.Square:
783 hollowVolume *= 0.499849f * 3.07920140172638f;
784 break;
785
786 case HollowShape.Circle:
787 // Hollow shape is a perfect cyllinder in respect to the cube's scale
788 // Cyllinder hollow volume calculation
789
790 hollowVolume *= 0.1963495f * 3.07920140172638f;
791 break;
792
793 default:
794 hollowVolume = 0;
795 break;
796 }
797 volume *= (1.0f - hollowVolume);
798 }
799 }
800 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
801 {
802 volume *= 0.32475953f;
803 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
804 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
805 volume *= (1.0f - tmp * tmp);
806
807 if (hollowAmount > 0.0)
808 {
809
810 hollowVolume *= hollowAmount;
811
812 switch (_pbs.HollowShape)
813 {
814 case HollowShape.Same:
815 case HollowShape.Triangle:
816 hollowVolume *= .25f;
817 break;
818
819 case HollowShape.Square:
820 hollowVolume *= 0.499849f * 3.07920140172638f;
821 break;
822
823 case HollowShape.Circle:
824
825 hollowVolume *= 0.1963495f * 3.07920140172638f;
826 break;
827
828 default:
829 hollowVolume = 0;
830 break;
831 }
832 volume *= (1.0f - hollowVolume);
833 }
834 }
835 break;
836
837 default:
838 break;
839 }
840
841
842
843 float taperX1;
844 float taperY1;
845 float taperX;
846 float taperY;
847 float pathBegin;
848 float pathEnd;
849 float profileBegin;
850 float profileEnd;
851
852 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
853 {
854 taperX1 = _pbs.PathScaleX * 0.01f;
855 if (taperX1 > 1.0f)
856 taperX1 = 2.0f - taperX1;
857 taperX = 1.0f - taperX1;
858
859 taperY1 = _pbs.PathScaleY * 0.01f;
860 if (taperY1 > 1.0f)
861 taperY1 = 2.0f - taperY1;
862 taperY = 1.0f - taperY1;
863 }
864 else
865 {
866 taperX = _pbs.PathTaperX * 0.01f;
867 if (taperX < 0.0f)
868 taperX = -taperX;
869 taperX1 = 1.0f - taperX;
870
871 taperY = _pbs.PathTaperY * 0.01f;
872 if (taperY < 0.0f)
873 taperY = -taperY;
874 taperY1 = 1.0f - taperY;
875
876 }
877
878
879 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
880
881 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
882 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
883 volume *= (pathEnd - pathBegin);
884
885 // this is crude aproximation
886 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
887 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
888 volume *= (profileEnd - profileBegin);
889
890 returnMass = _density * volume;
891
892 if (IsRootOfLinkset)
893 {
894 foreach (BSPrim prim in _childrenPrims)
895 {
896 returnMass += prim.CalculateMass();
897 }
898 }
899
900 if (returnMass <= 0)
901 returnMass = 0.0001f;
902
903 if (returnMass > _scene.MaximumObjectMass)
904 returnMass = _scene.MaximumObjectMass;
905
906 return returnMass;
907 }// end CalculateMass
908 #endregion Mass Calculation
909
910 // Create the geometry information in Bullet for later use
911 // The objects needs a hull if it's physical otherwise a mesh is enough
912 // No locking here because this is done when we know physics is not simulating
913 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used
914 private void CreateGeom(bool forceRebuild)
915 {
916 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
917 if (!_scene.NeedsMeshing(_pbs))
918 {
919 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
920 {
921 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
922 {
923 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
924 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
925 // Bullet native objects are scaled by the Bullet engine so pass the size in
926 _scale = _size;
927 }
928 }
929 else
930 {
931 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size);
932 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
933 _scale = _size;
934 }
935 }
936 else
937 {
938 if (IsPhysical)
939 {
940 if (forceRebuild || _hullKey == 0)
941 {
942 // physical objects require a hull for interaction.
943 // This will create the mesh if it doesn't already exist
944 CreateGeomHull();
945 }
946 }
947 else
948 {
949 if (forceRebuild || _meshKey == 0)
950 {
951 // Static (non-physical) objects only need a mesh for bumping into
952 CreateGeomMesh();
953 }
954 }
955 }
956 }
957
958 // No locking here because this is done when we know physics is not simulating
959 private void CreateGeomMesh()
960 {
961 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
962 ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod);
963 // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey);
964
965 // if this new shape is the same as last time, don't recreate the mesh
966 if (_meshKey == newMeshKey) return;
967
968 // Since we're recreating new, get rid of any previously generated shape
969 if (_meshKey != 0)
970 {
971 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
972 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
973 _mesh = null;
974 _meshKey = 0;
975 }
976
977 _meshKey = newMeshKey;
978 // always pass false for physicalness as this creates some sort of bounding box which we don't need
979 _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false);
980
981 int[] indices = _mesh.getIndexListAsInt();
982 List<OMV.Vector3> vertices = _mesh.getVertexList();
983
984 float[] verticesAsFloats = new float[vertices.Count * 3];
985 int vi = 0;
986 foreach (OMV.Vector3 vv in vertices)
987 {
988 // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z);
989 verticesAsFloats[vi++] = vv.X;
990 verticesAsFloats[vi++] = vv.Y;
991 verticesAsFloats[vi++] = vv.Z;
992 }
993
994 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
995 // LogHeader, _localID, _meshKey, indices.Length, vertices.Count);
996 BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices,
997 vertices.Count, verticesAsFloats);
998
999 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
1000 // meshes are already scaled by the meshmerizer
1001 _scale = new OMV.Vector3(1f, 1f, 1f);
1002 return;
1003 }
1004
1005 // No locking here because this is done when we know physics is not simulating
1006 private void CreateGeomHull()
1007 {
1008 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
1009 ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod);
1010 // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey);
1011
1012 // if the hull hasn't changed, don't rebuild it
1013 if (newHullKey == _hullKey) return;
1014
1015 // Since we're recreating new, get rid of any previously generated shape
1016 if (_hullKey != 0)
1017 {
1018 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1019 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1020 _hullKey = 0;
1021 _hulls.Clear();
1022 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1023 _mesh = null; // the mesh cannot match either
1024 _meshKey = 0;
1025 }
1026
1027 _hullKey = newHullKey;
1028 if (_meshKey != _hullKey)
1029 {
1030 // if the underlying mesh has changed, rebuild it
1031 CreateGeomMesh();
1032 }
1033
1034 int[] indices = _mesh.getIndexListAsInt();
1035 List<OMV.Vector3> vertices = _mesh.getVertexList();
1036
1037 //format conversion from IMesh format to DecompDesc format
1038 List<int> convIndices = new List<int>();
1039 List<float3> convVertices = new List<float3>();
1040 for (int ii = 0; ii < indices.GetLength(0); ii++)
1041 {
1042 convIndices.Add(indices[ii]);
1043 }
1044 foreach (OMV.Vector3 vv in vertices)
1045 {
1046 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
1047 }
1048
1049 // setup and do convex hull conversion
1050 _hulls = new List<ConvexResult>();
1051 DecompDesc dcomp = new DecompDesc();
1052 dcomp.mIndices = convIndices;
1053 dcomp.mVertices = convVertices;
1054 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
1055 // create the hull into the _hulls variable
1056 convexBuilder.process(dcomp);
1057
1058 // Convert the vertices and indices for passing to unmanaged
1059 // The hull information is passed as a large floating point array.
1060 // The format is:
1061 // convHulls[0] = number of hulls
1062 // convHulls[1] = number of vertices in first hull
1063 // convHulls[2] = hull centroid X coordinate
1064 // convHulls[3] = hull centroid Y coordinate
1065 // convHulls[4] = hull centroid Z coordinate
1066 // convHulls[5] = first hull vertex X
1067 // convHulls[6] = first hull vertex Y
1068 // convHulls[7] = first hull vertex Z
1069 // convHulls[8] = second hull vertex X
1070 // ...
1071 // convHulls[n] = number of vertices in second hull
1072 // convHulls[n+1] = second hull centroid X coordinate
1073 // ...
1074 //
1075 // TODO: is is very inefficient. Someday change the convex hull generator to return
1076 // data structures that do not need to be converted in order to pass to Bullet.
1077 // And maybe put the values directly into pinned memory rather than marshaling.
1078 int hullCount = _hulls.Count;
1079 int totalVertices = 1; // include one for the count of the hulls
1080 foreach (ConvexResult cr in _hulls)
1081 {
1082 totalVertices += 4; // add four for the vertex count and centroid
1083 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
1084 }
1085 float[] convHulls = new float[totalVertices];
1086
1087 convHulls[0] = (float)hullCount;
1088 int jj = 1;
1089 foreach (ConvexResult cr in _hulls)
1090 {
1091 // copy vertices for index access
1092 float3[] verts = new float3[cr.HullVertices.Count];
1093 int kk = 0;
1094 foreach (float3 ff in cr.HullVertices)
1095 {
1096 verts[kk++] = ff;
1097 }
1098
1099 // add to the array one hull's worth of data
1100 convHulls[jj++] = cr.HullIndices.Count;
1101 convHulls[jj++] = 0f; // centroid x,y,z
1102 convHulls[jj++] = 0f;
1103 convHulls[jj++] = 0f;
1104 foreach (int ind in cr.HullIndices)
1105 {
1106 convHulls[jj++] = verts[ind].x;
1107 convHulls[jj++] = verts[ind].y;
1108 convHulls[jj++] = verts[ind].z;
1109 }
1110 }
1111
1112 // create the hull definition in Bullet
1113 // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
1114 BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
1115 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1116 // meshes are already scaled by the meshmerizer
1117 _scale = new OMV.Vector3(1f, 1f, 1f);
1118 return;
1119 }
1120
1121 // Callback from convex hull creater with a newly created hull.
1122 // Just add it to the collection of hulls for this shape.
1123 private void HullReturn(ConvexResult result)
1124 {
1125 _hulls.Add(result);
1126 return;
1127 }
1128
1129 // Create an object in Bullet
1130 // No locking here because this is done when the physics engine is not simulating
1131 private void CreateObject()
1132 {
1133 if (IsRootOfLinkset)
1134 {
1135 // Create a linkset around this object
1136 // CreateLinksetWithCompoundHull();
1137 CreateLinksetWithConstraints();
1138 }
1139 else
1140 {
1141 // simple object
1142 // the mesh or hull must have already been created in Bullet
1143 ShapeData shape;
1144 FillShapeInfo(out shape);
1145 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1146 BulletSimAPI.CreateObject(_scene.WorldID, shape);
1147 }
1148 }
1149
1150 // Create a linkset by creating a compound hull at the root prim that consists of all
1151 // the children.
1152 // NOTE: This does not allow proper collisions with the children prims so it is not a workable solution
1153 void CreateLinksetWithCompoundHull()
1154 {
1155 // If I am the root prim of a linkset, replace my physical shape with all the
1156 // pieces of the children.
1157 // All of the children should have called CreateGeom so they have a hull
1158 // in the physics engine already. Here we pull together all of those hulls
1159 // into one shape.
1160 int totalPrimsInLinkset = _childrenPrims.Count + 1;
1161 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset);
1162 ShapeData[] shapes = new ShapeData[totalPrimsInLinkset];
1163 FillShapeInfo(out shapes[0]);
1164 int ii = 1;
1165 foreach (BSPrim prim in _childrenPrims)
1166 {
1167 // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID);
1168 prim.FillShapeInfo(out shapes[ii]);
1169 ii++;
1170 }
1171 BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes);
1172 }
1173
1174 // Copy prim's info into the BulletSim shape description structure
1175 public void FillShapeInfo(out ShapeData shape)
1176 {
1177 shape.ID = _localID;
1178 shape.Type = _shapeType;
1179 shape.Position = _position;
1180 shape.Rotation = _orientation;
1181 shape.Velocity = _velocity;
1182 shape.Scale = _scale;
1183 shape.Mass = _isPhysical ? _mass : 0f;
1184 shape.Buoyancy = _buoyancy;
1185 shape.HullKey = _hullKey;
1186 shape.MeshKey = _meshKey;
1187 shape.Friction = _friction;
1188 shape.Restitution = _restitution;
1189 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1190 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1191 }
1192
1193 // Create the linkset by putting constraints between the objects of the set so they cannot move
1194 // relative to each other.
1195 // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added
1196 void CreateLinksetWithConstraints()
1197 {
1198 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
1199
1200 // remove any constraints that might be in place
1201 foreach (BSPrim prim in _childrenPrims)
1202 {
1203 // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1204 BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
1205 }
1206 // create constraints between the root prim and each of the children
1207 foreach (BSPrim prim in _childrenPrims)
1208 {
1209 // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID);
1210
1211 // Zero motion for children so they don't interpolate
1212 prim.ZeroMotion();
1213
1214 // relative position normalized to the root prim
1215 OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation);
1216
1217 // relative rotation of the child to the parent
1218 OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation;
1219
1220 // this is a constraint that allows no freedom of movement between the two objects
1221 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
1222 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID,
1223 childRelativePosition,
1224 relativeRotation,
1225 OMV.Vector3.Zero,
1226 OMV.Quaternion.Identity,
1227 OMV.Vector3.Zero, OMV.Vector3.Zero,
1228 OMV.Vector3.Zero, OMV.Vector3.Zero);
1229 }
1230 }
1231
1232 // Rebuild the geometry and object.
1233 // This is called when the shape changes so we need to recreate the mesh/hull.
1234 // No locking here because this is done when the physics engine is not simulating
1235 private void RecreateGeomAndObject()
1236 {
1237 // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID);
1238 CreateGeom(true);
1239 CreateObject();
1240 return;
1241 }
1242
1243 // The physics engine says that properties have updated. Update same and inform
1244 // the world that things have changed.
1245 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1246 enum UpdatedProperties {
1247 Position = 1 << 0,
1248 Rotation = 1 << 1,
1249 Velocity = 1 << 2,
1250 Acceleration = 1 << 3,
1251 RotationalVel = 1 << 4
1252 }
1253
1254 const float ROTATION_TOLERANCE = 0.01f;
1255 const float VELOCITY_TOLERANCE = 0.001f;
1256 const float POSITION_TOLERANCE = 0.05f;
1257 const float ACCELERATION_TOLERANCE = 0.01f;
1258 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1259 const bool SHOULD_DAMP_UPDATES = false;
1260
1261 public void UpdateProperties(EntityProperties entprop)
1262 {
1263 UpdatedProperties changed = 0;
1264 if (SHOULD_DAMP_UPDATES)
1265 {
1266 // assign to the local variables so the normal set action does not happen
1267 // if (_position != entprop.Position)
1268 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1269 {
1270 _position = entprop.Position;
1271 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position);
1272 changed |= UpdatedProperties.Position;
1273 }
1274 // if (_orientation != entprop.Rotation)
1275 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1276 {
1277 _orientation = entprop.Rotation;
1278 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation);
1279 changed |= UpdatedProperties.Rotation;
1280 }
1281 // if (_velocity != entprop.Velocity)
1282 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1283 {
1284 _velocity = entprop.Velocity;
1285 // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity);
1286 changed |= UpdatedProperties.Velocity;
1287 }
1288 // if (_acceleration != entprop.Acceleration)
1289 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1290 {
1291 _acceleration = entprop.Acceleration;
1292 // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration);
1293 changed |= UpdatedProperties.Acceleration;
1294 }
1295 // if (_rotationalVelocity != entprop.RotationalVelocity)
1296 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1297 {
1298 _rotationalVelocity = entprop.RotationalVelocity;
1299 // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity);
1300 changed |= UpdatedProperties.RotationalVel;
1301 }
1302 if (changed != 0)
1303 {
1304 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1305 // Only update the position of single objects and linkset roots
1306 if (this._parentPrim == null)
1307 {
1308 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1309 base.RequestPhysicsterseUpdate();
1310 }
1311 }
1312 }
1313 else
1314 {
1315 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1316
1317 // Only updates only for individual prims and for the root object of a linkset.
1318 if (this._parentPrim == null)
1319 {
1320 // Assign to the local variables so the normal set action does not happen
1321 _position = entprop.Position;
1322 _orientation = entprop.Rotation;
1323 _velocity = entprop.Velocity;
1324 _acceleration = entprop.Acceleration;
1325 _rotationalVelocity = entprop.RotationalVelocity;
1326 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1327 base.RequestPhysicsterseUpdate();
1328 }
1329 }
1330 }
1331
1332 // I've collided with something
1333 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1334 {
1335 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
1336
1337 // The following lines make IsColliding() and IsCollidingGround() work
1338 _collidingStep = _scene.SimulationStep;
1339 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
1340 {
1341 _collidingGroundStep = _scene.SimulationStep;
1342 }
1343
1344 if (_subscribedEventsMs == 0) return; // nothing in the object is waiting for collision events
1345 // throttle the collisions to the number of milliseconds specified in the subscription
1346 int nowTime = _scene.SimulationNowTime;
1347 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
1348 _lastCollisionTime = nowTime;
1349
1350 // create the event for the collision
1351 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
1352 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1353 CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
1354 base.SendCollisionUpdate(args);
1355 }
1356}
1357}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
new file mode 100644
index 0000000..7704002
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -0,0 +1,860 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Runtime.InteropServices;
30using System.Text;
31using System.Threading;
32using Nini.Config;
33using log4net;
34using OpenSim.Framework;
35using OpenSim.Region.Physics.Manager;
36using OpenMetaverse;
37using OpenSim.Region.Framework;
38
39// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
40// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
41// Test sculpties
42// Compute physics FPS reasonably
43// Based on material, set density and friction
44// More efficient memory usage in passing hull information from BSPrim to BulletSim
45// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
46// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
47// At the moment, physical and phantom causes object to drop through the terrain
48// Should prim.link() and prim.delink() membership checking happen at taint time?
49// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
50// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
51// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
52// Implement LockAngularMotion
53// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
54// Does NeedsMeshing() really need to exclude all the different shapes?
55//
56namespace OpenSim.Region.Physics.BulletSPlugin
57{
58public class BSScene : PhysicsScene, IPhysicsParameters
59{
60 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
61 private static readonly string LogHeader = "[BULLETS SCENE]";
62
63 public string BulletSimVersion = "?";
64
65 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
66 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>();
67 private List<BSPrim> m_vehicles = new List<BSPrim>();
68 private float[] m_heightMap;
69 private float m_waterLevel;
70 private uint m_worldID;
71 public uint WorldID { get { return m_worldID; } }
72
73 private bool m_initialized = false;
74
75 public IMesher mesher;
76 private float m_meshLOD;
77 public float MeshLOD
78 {
79 get { return m_meshLOD; }
80 }
81 private float m_sculptLOD;
82 public float SculptLOD
83 {
84 get { return m_sculptLOD; }
85 }
86
87 private int m_maxSubSteps;
88 private float m_fixedTimeStep;
89 private long m_simulationStep = 0;
90 public long SimulationStep { get { return m_simulationStep; } }
91
92 // A value of the time now so all the collision and update routines do not have to get their own
93 // Set to 'now' just before all the prims and actors are called for collisions and updates
94 private int m_simulationNowTime;
95 public int SimulationNowTime { get { return m_simulationNowTime; } }
96
97 private int m_maxCollisionsPerFrame;
98 private CollisionDesc[] m_collisionArray;
99 private GCHandle m_collisionArrayPinnedHandle;
100
101 private int m_maxUpdatesPerFrame;
102 private EntityProperties[] m_updateArray;
103 private GCHandle m_updateArrayPinnedHandle;
104
105 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed
106 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes
107
108 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
109 public const uint GROUNDPLANE_ID = 1;
110
111 public ConfigurationParameters Params
112 {
113 get { return m_params[0]; }
114 }
115 public Vector3 DefaultGravity
116 {
117 get { return new Vector3(0f, 0f, Params.gravity); }
118 }
119
120 private float m_maximumObjectMass;
121 public float MaximumObjectMass
122 {
123 get { return m_maximumObjectMass; }
124 }
125
126 public delegate void TaintCallback();
127 private List<TaintCallback> _taintedObjects;
128 private Object _taintLock = new Object();
129
130 // A pointer to an instance if this structure is passed to the C++ code
131 ConfigurationParameters[] m_params;
132 GCHandle m_paramsHandle;
133
134 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
135
136 public BSScene(string identifier)
137 {
138 m_initialized = false;
139 }
140
141 public override void Initialise(IMesher meshmerizer, IConfigSource config)
142 {
143 // Allocate pinned memory to pass parameters.
144 m_params = new ConfigurationParameters[1];
145 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
146
147 // Set default values for physics parameters plus any overrides from the ini file
148 GetInitialParameterValues(config);
149
150 // allocate more pinned memory close to the above in an attempt to get the memory all together
151 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
152 m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned);
153 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
154 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
155
156 // Get the version of the DLL
157 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
158 // BulletSimVersion = BulletSimAPI.GetVersion();
159 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
160
161 // if Debug, enable logging from the unmanaged code
162 if (m_log.IsDebugEnabled)
163 {
164 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
165 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
166 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
167 }
168
169 _taintedObjects = new List<TaintCallback>();
170
171 mesher = meshmerizer;
172 // The bounding box for the simulated world
173 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 4096f);
174
175 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
176 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
177 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
178 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
179
180 m_initialized = true;
181 }
182
183 // All default parameter values are set here. There should be no values set in the
184 // variable definitions.
185 private void GetInitialParameterValues(IConfigSource config)
186 {
187 ConfigurationParameters parms = new ConfigurationParameters();
188
189 _meshSculptedPrim = true; // mesh sculpted prims
190 _forceSimplePrimMeshing = false; // use complex meshing if called for
191
192 m_meshLOD = 8f;
193 m_sculptLOD = 32f;
194
195 m_maxSubSteps = 10;
196 m_fixedTimeStep = 1f / 60f;
197 m_maxCollisionsPerFrame = 2048;
198 m_maxUpdatesPerFrame = 2048;
199 m_maximumObjectMass = 10000.01f;
200
201 parms.defaultFriction = 0.5f;
202 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
203 parms.defaultRestitution = 0f;
204 parms.collisionMargin = 0.0f;
205 parms.gravity = -9.80665f;
206
207 parms.linearDamping = 0.0f;
208 parms.angularDamping = 0.0f;
209 parms.deactivationTime = 0.2f;
210 parms.linearSleepingThreshold = 0.8f;
211 parms.angularSleepingThreshold = 1.0f;
212 parms.ccdMotionThreshold = 0.5f; // set to zero to disable
213 parms.ccdSweptSphereRadius = 0.2f;
214
215 parms.terrainFriction = 0.5f;
216 parms.terrainHitFraction = 0.8f;
217 parms.terrainRestitution = 0f;
218 parms.avatarFriction = 0.0f;
219 parms.avatarDensity = 60f;
220 parms.avatarCapsuleRadius = 0.37f;
221 parms.avatarCapsuleHeight = 1.5f; // 2.140599f
222
223 if (config != null)
224 {
225 // If there are specifications in the ini file, use those values
226 // WHEN ADDING OR UPDATING THIS SECTION, BE SURE TO UPDATE OpenSimDefaults.ini
227 // ALSO REMEMBER TO UPDATE THE RUNTIME SETTING OF THE PARAMETERS.
228 IConfig pConfig = config.Configs["BulletSim"];
229 if (pConfig != null)
230 {
231 _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim);
232 _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing);
233
234 m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD);
235 m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD);
236
237 m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps);
238 m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep);
239 m_maxCollisionsPerFrame = pConfig.GetInt("MaxCollisionsPerFrame", m_maxCollisionsPerFrame);
240 m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame);
241 m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass);
242
243 parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction);
244 parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity);
245 parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution);
246 parms.collisionMargin = pConfig.GetFloat("CollisionMargin", parms.collisionMargin);
247 parms.gravity = pConfig.GetFloat("Gravity", parms.gravity);
248
249 parms.linearDamping = pConfig.GetFloat("LinearDamping", parms.linearDamping);
250 parms.angularDamping = pConfig.GetFloat("AngularDamping", parms.angularDamping);
251 parms.deactivationTime = pConfig.GetFloat("DeactivationTime", parms.deactivationTime);
252 parms.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", parms.linearSleepingThreshold);
253 parms.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", parms.angularSleepingThreshold);
254 parms.ccdMotionThreshold = pConfig.GetFloat("CcdMotionThreshold", parms.ccdMotionThreshold);
255 parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius);
256
257 parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction);
258 parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction);
259 parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution);
260 parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction);
261 parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity);
262 parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius);
263 parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight);
264 }
265 }
266 m_params[0] = parms;
267 }
268
269 // Called directly from unmanaged code so don't do much
270 private void BulletLogger(string msg)
271 {
272 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
273 }
274
275 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
276 {
277 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
278 return null;
279 }
280
281 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
282 {
283 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
284 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
285 lock (m_avatars) m_avatars.Add(localID, actor);
286 return actor;
287 }
288
289 public override void RemoveAvatar(PhysicsActor actor)
290 {
291 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
292 if (actor is BSCharacter)
293 {
294 ((BSCharacter)actor).Destroy();
295 }
296 try
297 {
298 lock (m_avatars) m_avatars.Remove(actor.LocalID);
299 }
300 catch (Exception e)
301 {
302 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
303 }
304 }
305
306 public override void RemovePrim(PhysicsActor prim)
307 {
308 // m_log.DebugFormat("{0}: RemovePrim", LogHeader);
309 if (prim is BSPrim)
310 {
311 ((BSPrim)prim).Destroy();
312 }
313 try
314 {
315 lock (m_prims) m_prims.Remove(prim.LocalID);
316 }
317 catch (Exception e)
318 {
319 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
320 }
321 }
322
323 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
324 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
325 {
326 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
327 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
328 lock (m_prims) m_prims.Add(localID, prim);
329 return prim;
330 }
331
332 // This is a call from the simulator saying that some physical property has been updated.
333 // The BulletSim driver senses the changing of relevant properties so this taint
334 // information call is not needed.
335 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
336
337 // Simulate one timestep
338 public override float Simulate(float timeStep)
339 {
340 int updatedEntityCount;
341 IntPtr updatedEntitiesPtr;
342 int collidersCount;
343 IntPtr collidersPtr;
344
345 // prevent simulation until we've been initialized
346 if (!m_initialized) return 10.0f;
347
348 // update the prim states while we know the physics engine is not busy
349 ProcessTaints();
350
351 // Some of the prims operate with special vehicle properties
352 ProcessVehicles(timeStep);
353 ProcessTaints(); // the vehicles might have added taints
354
355 // step the physical world one interval
356 m_simulationStep++;
357 int numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
358 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
359
360 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
361
362 // Get a value for 'now' so all the collision and update routines don't have to get their own
363 m_simulationNowTime = Util.EnvironmentTickCount();
364
365 // If there were collisions, process them by sending the event to the prim.
366 // Collisions must be processed before updates.
367 if (collidersCount > 0)
368 {
369 for (int ii = 0; ii < collidersCount; ii++)
370 {
371 uint cA = m_collisionArray[ii].aID;
372 uint cB = m_collisionArray[ii].bID;
373 Vector3 point = m_collisionArray[ii].point;
374 Vector3 normal = m_collisionArray[ii].normal;
375 SendCollision(cA, cB, point, normal, 0.01f);
376 SendCollision(cB, cA, point, -normal, 0.01f);
377 }
378 }
379
380 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
381 if (updatedEntityCount > 0)
382 {
383 for (int ii = 0; ii < updatedEntityCount; ii++)
384 {
385 EntityProperties entprop = m_updateArray[ii];
386 // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position);
387 BSCharacter actor;
388 if (m_avatars.TryGetValue(entprop.ID, out actor))
389 {
390 actor.UpdateProperties(entprop);
391 continue;
392 }
393 BSPrim prim;
394 if (m_prims.TryGetValue(entprop.ID, out prim))
395 {
396 prim.UpdateProperties(entprop);
397 }
398 }
399 }
400
401 // TODO: FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation.
402 return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f;
403 }
404
405 // Something has collided
406 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration)
407 {
408 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID)
409 {
410 return; // don't send collisions to the terrain
411 }
412
413 ActorTypes type = ActorTypes.Prim;
414 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID)
415 type = ActorTypes.Ground;
416 else if (m_avatars.ContainsKey(collidingWith))
417 type = ActorTypes.Agent;
418
419 BSPrim prim;
420 if (m_prims.TryGetValue(localID, out prim)) {
421 prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
422 return;
423 }
424 BSCharacter actor;
425 if (m_avatars.TryGetValue(localID, out actor)) {
426 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
427 return;
428 }
429 return;
430 }
431
432 public override void GetResults() { }
433
434 public override void SetTerrain(float[] heightMap) {
435 m_heightMap = heightMap;
436 this.TaintedObject(delegate()
437 {
438 BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
439 });
440 }
441
442 public float GetTerrainHeightAtXY(float tX, float tY)
443 {
444 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
445 }
446
447 public override void SetWaterLevel(float baseheight)
448 {
449 m_waterLevel = baseheight;
450 }
451 public float GetWaterLevel()
452 {
453 return m_waterLevel;
454 }
455
456 public override void DeleteTerrain()
457 {
458 m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
459 }
460
461 public override void Dispose()
462 {
463 m_log.DebugFormat("{0}: Dispose()", LogHeader);
464 }
465
466 public override Dictionary<uint, float> GetTopColliders()
467 {
468 return new Dictionary<uint, float>();
469 }
470
471 public override bool IsThreaded { get { return false; } }
472
473 /// <summary>
474 /// Routine to figure out if we need to mesh this prim with our mesher
475 /// </summary>
476 /// <param name="pbs"></param>
477 /// <returns>true if the prim needs meshing</returns>
478 public bool NeedsMeshing(PrimitiveBaseShape pbs)
479 {
480 // most of this is redundant now as the mesher will return null if it cant mesh a prim
481 // but we still need to check for sculptie meshing being enabled so this is the most
482 // convenient place to do it for now...
483
484 // int iPropertiesNotSupportedDefault = 0;
485
486 if (pbs.SculptEntry && !_meshSculptedPrim)
487 {
488 // Render sculpties as boxes
489 return false;
490 }
491
492 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet
493 // can use an internal representation for the prim
494 if (!_forceSimplePrimMeshing)
495 {
496 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
497 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
498 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
499 {
500
501 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
502 && pbs.ProfileHollow == 0
503 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
504 && pbs.PathBegin == 0 && pbs.PathEnd == 0
505 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
506 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
507 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
508 {
509 return false;
510 }
511 }
512 }
513
514 /* TODO: verify that the mesher will now do all these shapes
515 if (pbs.ProfileHollow != 0)
516 iPropertiesNotSupportedDefault++;
517
518 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
519 iPropertiesNotSupportedDefault++;
520
521 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
522 iPropertiesNotSupportedDefault++;
523
524 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
525 iPropertiesNotSupportedDefault++;
526
527 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
528 iPropertiesNotSupportedDefault++;
529
530 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
531 iPropertiesNotSupportedDefault++;
532
533 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
534 iPropertiesNotSupportedDefault++;
535
536 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))
537 iPropertiesNotSupportedDefault++;
538
539 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
540 iPropertiesNotSupportedDefault++;
541
542 // test for torus
543 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
544 {
545 if (pbs.PathCurve == (byte)Extrusion.Curve1)
546 {
547 iPropertiesNotSupportedDefault++;
548 }
549 }
550 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
551 {
552 if (pbs.PathCurve == (byte)Extrusion.Straight)
553 {
554 iPropertiesNotSupportedDefault++;
555 }
556 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
557 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
558 {
559 iPropertiesNotSupportedDefault++;
560 }
561 }
562 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
563 {
564 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
565 {
566 iPropertiesNotSupportedDefault++;
567 }
568 }
569 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
570 {
571 if (pbs.PathCurve == (byte)Extrusion.Straight)
572 {
573 iPropertiesNotSupportedDefault++;
574 }
575 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
576 {
577 iPropertiesNotSupportedDefault++;
578 }
579 }
580 if (iPropertiesNotSupportedDefault == 0)
581 {
582 return false;
583 }
584 */
585 return true;
586 }
587
588 // The calls to the PhysicsActors can't directly call into the physics engine
589 // because it might be busy. We we delay changes to a known time.
590 // We rely on C#'s closure to save and restore the context for the delegate.
591 public void TaintedObject(TaintCallback callback)
592 {
593 lock (_taintLock)
594 _taintedObjects.Add(callback);
595 return;
596 }
597
598 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
599 // a callback into itself to do the actual property change. That callback is called
600 // here just before the physics engine is called to step the simulation.
601 public void ProcessTaints()
602 {
603 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
604 {
605 // swizzle a new list into the list location so we can process what's there
606 List<TaintCallback> oldList;
607 lock (_taintLock)
608 {
609 oldList = _taintedObjects;
610 _taintedObjects = new List<TaintCallback>();
611 }
612
613 foreach (TaintCallback callback in oldList)
614 {
615 try
616 {
617 callback();
618 }
619 catch (Exception e)
620 {
621 m_log.ErrorFormat("{0}: ProcessTaints: Exception: {1}", LogHeader, e);
622 }
623 }
624 oldList.Clear();
625 }
626 }
627
628 #region Vehicles
629 // Make so the scene will call this prim for vehicle actions each tick.
630 // Safe to call if prim is already in the vehicle list.
631 public void AddVehiclePrim(BSPrim vehicle)
632 {
633 lock (m_vehicles)
634 {
635 if (!m_vehicles.Contains(vehicle))
636 {
637 m_vehicles.Add(vehicle);
638 }
639 }
640 }
641
642 // Remove a prim from our list of vehicles.
643 // Safe to call if the prim is not in the vehicle list.
644 public void RemoveVehiclePrim(BSPrim vehicle)
645 {
646 lock (m_vehicles)
647 {
648 if (m_vehicles.Contains(vehicle))
649 {
650 m_vehicles.Remove(vehicle);
651 }
652 }
653 }
654
655 // Some prims have extra vehicle actions
656 // no locking because only called when physics engine is not busy
657 private void ProcessVehicles(float timeStep)
658 {
659 foreach (BSPrim prim in m_vehicles)
660 {
661 prim.StepVehicle(timeStep);
662 }
663 }
664 #endregion Vehicles
665
666 #region Runtime settable parameters
667 public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[]
668 {
669 new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)"),
670 new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"),
671 new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"),
672 new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"),
673 new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"),
674
675 new PhysParameterEntry("DefaultFriction", "Friction factor used on new objects"),
676 new PhysParameterEntry("DefaultDensity", "Density for new objects" ),
677 new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ),
678 // new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ),
679 new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ),
680
681 new PhysParameterEntry("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)" ),
682 new PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ),
683 new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ),
684 new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ),
685 new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ),
686 // new PhysParameterEntry("CcdMotionThreshold", "" ),
687 // new PhysParameterEntry("CcdSweptSphereRadius", "" ),
688
689 new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ),
690 new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ),
691 new PhysParameterEntry("TerrainRestitution", "Bouncyness" ),
692 new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ),
693 new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ),
694 new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ),
695 new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ),
696 new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" )
697 };
698
699 #region IPhysicsParameters
700 // Get the list of parameters this physics engine supports
701 public PhysParameterEntry[] GetParameterList()
702 {
703 return SettableParameters;
704 }
705
706 // Set parameter on a specific or all instances.
707 // Return 'false' if not able to set the parameter.
708 // Setting the value in the m_params block will change the value the physics engine
709 // will use the next time since it's pinned and shared memory.
710 // Some of the values require calling into the physics engine to get the new
711 // value activated ('terrainFriction' for instance).
712 public bool SetPhysicsParameter(string parm, float val, uint localID)
713 {
714 bool ret = true;
715 string lparm = parm.ToLower();
716 switch (lparm)
717 {
718 case "meshlod": m_meshLOD = (int)val; break;
719 case "sculptlod": m_sculptLOD = (int)val; break;
720 case "maxsubstep": m_maxSubSteps = (int)val; break;
721 case "fixedtimestep": m_fixedTimeStep = val; break;
722 case "maxobjectmass": m_maximumObjectMass = val; break;
723
724 case "defaultfriction": m_params[0].defaultFriction = val; break;
725 case "defaultdensity": m_params[0].defaultDensity = val; break;
726 case "defaultrestitution": m_params[0].defaultRestitution = val; break;
727 case "collisionmargin": m_params[0].collisionMargin = val; break;
728 case "gravity": m_params[0].gravity = val; TaintedUpdateParameter(lparm, PhysParameterEntry.APPLY_TO_NONE, val); break;
729
730 case "lineardamping": UpdateParameterPrims(ref m_params[0].linearDamping, lparm, localID, val); break;
731 case "angulardamping": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
732 case "deactivationtime": UpdateParameterPrims(ref m_params[0].deactivationTime, lparm, localID, val); break;
733 case "linearsleepingthreshold": UpdateParameterPrims(ref m_params[0].linearSleepingThreshold, lparm, localID, val); break;
734 case "angularsleepingthreshold": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
735 case "ccdmotionthreshold": UpdateParameterPrims(ref m_params[0].ccdMotionThreshold, lparm, localID, val); break;
736 case "ccdsweptsphereradius": UpdateParameterPrims(ref m_params[0].ccdSweptSphereRadius, lparm, localID, val); break;
737
738 // set a terrain physical feature and cause terrain to be recalculated
739 case "terrainfriction": m_params[0].terrainFriction = val; TaintedUpdateParameter("terrain", 0, val); break;
740 case "terrainhitfraction": m_params[0].terrainHitFraction = val; TaintedUpdateParameter("terrain", 0, val); break;
741 case "terrainrestitution": m_params[0].terrainRestitution = val; TaintedUpdateParameter("terrain", 0, val); break;
742 // set an avatar physical feature and cause avatar(s) to be recalculated
743 case "avatarfriction": UpdateParameterAvatars(ref m_params[0].avatarFriction, "avatar", localID, val); break;
744 case "avatardensity": UpdateParameterAvatars(ref m_params[0].avatarDensity, "avatar", localID, val); break;
745 case "avatarrestitution": UpdateParameterAvatars(ref m_params[0].avatarRestitution, "avatar", localID, val); break;
746 case "avatarcapsuleradius": UpdateParameterAvatars(ref m_params[0].avatarCapsuleRadius, "avatar", localID, val); break;
747 case "avatarcapsuleheight": UpdateParameterAvatars(ref m_params[0].avatarCapsuleHeight, "avatar", localID, val); break;
748
749 default: ret = false; break;
750 }
751 return ret;
752 }
753
754 // check to see if we are updating a parameter for a particular or all of the prims
755 private void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
756 {
757 List<uint> operateOn;
758 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
759 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
760 }
761
762 // check to see if we are updating a parameter for a particular or all of the avatars
763 private void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
764 {
765 List<uint> operateOn;
766 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
767 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
768 }
769
770 // update all the localIDs specified
771 // If the local ID is APPLY_TO_NONE, just change the default value
772 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
773 // If the localID is a specific object, apply the parameter change to only that object
774 private void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val)
775 {
776 switch (localID)
777 {
778 case PhysParameterEntry.APPLY_TO_NONE:
779 defaultLoc = val; // setting only the default value
780 break;
781 case PhysParameterEntry.APPLY_TO_ALL:
782 defaultLoc = val; // setting ALL also sets the default value
783 List<uint> objectIDs = lIDs;
784 string xparm = parm.ToLower();
785 float xval = val;
786 TaintedObject(delegate() {
787 foreach (uint lID in objectIDs)
788 {
789 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval);
790 }
791 });
792 break;
793 default:
794 // setting only one localID
795 TaintedUpdateParameter(parm, localID, val);
796 break;
797 }
798 }
799
800 // schedule the actual updating of the paramter to when the phys engine is not busy
801 private void TaintedUpdateParameter(string parm, uint localID, float val)
802 {
803 uint xlocalID = localID;
804 string xparm = parm.ToLower();
805 float xval = val;
806 TaintedObject(delegate() {
807 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval);
808 });
809 }
810
811 // Get parameter.
812 // Return 'false' if not able to get the parameter.
813 public bool GetPhysicsParameter(string parm, out float value)
814 {
815 float val = 0f;
816 bool ret = true;
817 switch (parm.ToLower())
818 {
819 case "meshlod": val = (float)m_meshLOD; break;
820 case "sculptlod": val = (float)m_sculptLOD; break;
821 case "maxsubstep": val = (float)m_maxSubSteps; break;
822 case "fixedtimestep": val = m_fixedTimeStep; break;
823 case "maxobjectmass": val = m_maximumObjectMass; break;
824
825 case "defaultfriction": val = m_params[0].defaultFriction; break;
826 case "defaultdensity": val = m_params[0].defaultDensity; break;
827 case "defaultrestitution": val = m_params[0].defaultRestitution; break;
828 case "collisionmargin": val = m_params[0].collisionMargin; break;
829 case "gravity": val = m_params[0].gravity; break;
830
831 case "lineardamping": val = m_params[0].linearDamping; break;
832 case "angulardamping": val = m_params[0].angularDamping; break;
833 case "deactivationtime": val = m_params[0].deactivationTime; break;
834 case "linearsleepingthreshold": val = m_params[0].linearSleepingThreshold; break;
835 case "angularsleepingthreshold": val = m_params[0].angularDamping; break;
836 case "ccdmotionthreshold": val = m_params[0].ccdMotionThreshold; break;
837 case "ccdsweptsphereradius": val = m_params[0].ccdSweptSphereRadius; break;
838
839 case "terrainfriction": val = m_params[0].terrainFriction; break;
840 case "terrainhitfraction": val = m_params[0].terrainHitFraction; break;
841 case "terrainrestitution": val = m_params[0].terrainRestitution; break;
842
843 case "avatarfriction": val = m_params[0].avatarFriction; break;
844 case "avatardensity": val = m_params[0].avatarDensity; break;
845 case "avatarrestitution": val = m_params[0].avatarRestitution; break;
846 case "avatarcapsuleradius": val = m_params[0].avatarCapsuleRadius; break;
847 case "avatarcapsuleheight": val = m_params[0].avatarCapsuleHeight; break;
848 default: ret = false; break;
849
850 }
851 value = val;
852 return ret;
853 }
854
855 #endregion IPhysicsParameters
856
857 #endregion Runtime settable parameters
858
859}
860}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
new file mode 100644
index 0000000..a610c8d
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -0,0 +1,257 @@
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.Runtime.InteropServices;
29using System.Security;
30using System.Text;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin {
34
35[StructLayout(LayoutKind.Sequential)]
36public struct ConvexHull
37{
38 Vector3 Offset;
39 int VertexCount;
40 Vector3[] Vertices;
41}
42[StructLayout(LayoutKind.Sequential)]
43public struct ShapeData
44{
45 public enum PhysicsShapeType
46 {
47 SHAPE_AVATAR = 0,
48 SHAPE_BOX = 1,
49 SHAPE_CONE = 2,
50 SHAPE_CYLINDER = 3,
51 SHAPE_SPHERE = 4,
52 SHAPE_MESH = 5,
53 SHAPE_HULL = 6
54 };
55 public uint ID;
56 public PhysicsShapeType Type;
57 public Vector3 Position;
58 public Quaternion Rotation;
59 public Vector3 Velocity;
60 public Vector3 Scale;
61 public float Mass;
62 public float Buoyancy;
63 public System.UInt64 HullKey;
64 public System.UInt64 MeshKey;
65 public float Friction;
66 public float Restitution;
67 public int Collidable;
68 public int Static; // true if a static object. Otherwise gravity, etc.
69
70 // note that bools are passed as ints since bool size changes by language and architecture
71 public const int numericTrue = 1;
72 public const int numericFalse = 0;
73}
74[StructLayout(LayoutKind.Sequential)]
75public struct SweepHit
76{
77 public uint ID;
78 public float Fraction;
79 public Vector3 Normal;
80 public Vector3 Point;
81}
82[StructLayout(LayoutKind.Sequential)]
83public struct RaycastHit
84{
85 public uint ID;
86 public float Fraction;
87 public Vector3 Normal;
88}
89[StructLayout(LayoutKind.Sequential)]
90public struct CollisionDesc
91{
92 public uint aID;
93 public uint bID;
94 public Vector3 point;
95 public Vector3 normal;
96}
97[StructLayout(LayoutKind.Sequential)]
98public struct EntityProperties
99{
100 public uint ID;
101 public Vector3 Position;
102 public Quaternion Rotation;
103 public Vector3 Velocity;
104 public Vector3 Acceleration;
105 public Vector3 RotationalVelocity;
106}
107
108// Format of this structure must match the definition in the C++ code
109[StructLayout(LayoutKind.Sequential)]
110public struct ConfigurationParameters
111{
112 public float defaultFriction;
113 public float defaultDensity;
114 public float defaultRestitution;
115 public float collisionMargin;
116 public float gravity;
117
118 public float linearDamping;
119 public float angularDamping;
120 public float deactivationTime;
121 public float linearSleepingThreshold;
122 public float angularSleepingThreshold;
123 public float ccdMotionThreshold;
124 public float ccdSweptSphereRadius;
125
126 public float terrainFriction;
127 public float terrainHitFraction;
128 public float terrainRestitution;
129 public float avatarFriction;
130 public float avatarDensity;
131 public float avatarRestitution;
132 public float avatarCapsuleRadius;
133 public float avatarCapsuleHeight;
134
135 public const float numericTrue = 1f;
136 public const float numericFalse = 0f;
137}
138
139static class BulletSimAPI {
140
141[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
142[return: MarshalAs(UnmanagedType.LPStr)]
143public static extern string GetVersion();
144
145[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
146public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
147 int maxCollisions, IntPtr collisionArray,
148 int maxUpdates, IntPtr updateArray);
149
150[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
151public static extern bool UpdateParameter(uint worldID, uint localID,
152 [MarshalAs(UnmanagedType.LPStr)]string paramCode, float value);
153
154[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
155public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
156
157[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
158public static extern void Shutdown(uint worldID);
159
160
161[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
162public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
163 out int updatedEntityCount,
164 out IntPtr updatedEntitiesPtr,
165 out int collidersCount,
166 out IntPtr collidersPtr);
167
168[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
169public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
170 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
171 );
172
173[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
174public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
175 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
176 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
177 );
178
179[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
180public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey);
181
182[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
183public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
184
185[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
186public static extern bool CreateObject(uint worldID, ShapeData shapeData);
187
188[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
189public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
190
191[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
192public static extern void AddConstraint(uint worldID, uint id1, uint id2,
193 Vector3 frame1, Quaternion frame1rot,
194 Vector3 frame2, Quaternion frame2rot,
195 Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
196
197[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
198public static extern bool RemoveConstraintByID(uint worldID, uint id1);
199
200[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
201public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
202
203[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
204public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
205
206[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
207public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
208
209[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
210public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity);
211
212[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
213public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
214
215[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
216public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
217
218[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
219public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic);
220
221[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
222public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom);
223
224[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
225public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass);
226
227[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
228public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly);
229
230[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
231public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass);
232
233[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
234public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy);
235
236[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
237public static extern bool HasObject(uint worldID, uint id);
238
239[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
240public static extern bool DestroyObject(uint worldID, uint id);
241
242[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
243public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
244
245[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
246public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to);
247
248[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
249public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
250
251// Log a debug message
252[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
253public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
254[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
255public static extern void SetDebugLogCallback(DebugLogCallback callback);
256}
257}