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