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.cs434
-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.cs1265
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs655
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs234
6 files changed, 3607 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..9f9ebcc
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -0,0 +1,434 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above 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 = 80f;
53 public float _density = 60f;
54 private Vector3 _force;
55 private Vector3 _velocity;
56 private Vector3 _torque;
57 private float _collisionScore;
58 private Vector3 _acceleration;
59 private Quaternion _orientation;
60 private int _physicsActorType;
61 private bool _isPhysical;
62 private bool _flying;
63 private bool _setAlwaysRun;
64 private bool _throttleUpdates;
65 private bool _isColliding;
66 private long _collidingStep;
67 private bool _collidingGround;
68 private long _collidingGroundStep;
69 private bool _collidingObj;
70 private bool _floatOnWater;
71 private Vector3 _rotationalVelocity;
72 private bool _kinematic;
73 private float _buoyancy;
74
75 private int _subscribedEventsMs = 0;
76 private int _lastCollisionTime = 0;
77
78 private Vector3 _PIDTarget;
79 private bool _usePID;
80 private float _PIDTau;
81 private bool _useHoverPID;
82 private float _PIDHoverHeight;
83 private PIDHoverType _PIDHoverType;
84 private float _PIDHoverTao;
85
86 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying)
87 {
88 _localID = localID;
89 _avName = avName;
90 _scene = parent_scene;
91 _position = pos;
92 _size = size;
93 _orientation = Quaternion.Identity;
94 _velocity = Vector3.Zero;
95 _buoyancy = 0f; // characters return a buoyancy of zero
96 _scale = new Vector3(1f, 1f, 1f);
97 float AVvolume = (float) (Math.PI*Math.Pow(_scene.Params.avatarCapsuleRadius, 2)*_scene.Params.avatarCapsuleHeight);
98 _density = _scene.Params.avatarDensity;
99 _mass = _density*AVvolume;
100
101 ShapeData shapeData = new ShapeData();
102 shapeData.ID = _localID;
103 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
104 shapeData.Position = _position;
105 shapeData.Rotation = _orientation;
106 shapeData.Velocity = _velocity;
107 shapeData.Scale = _scale;
108 shapeData.Mass = _mass;
109 shapeData.Buoyancy = isFlying ? 1f : 0f;
110 shapeData.Static = ShapeData.numericFalse;
111 shapeData.Friction = _scene.Params.avatarFriction;
112 shapeData.Restitution = _scene.Params.defaultRestitution;
113
114 // do actual create at taint time
115 _scene.TaintedObject(delegate()
116 {
117 BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData);
118 });
119
120 return;
121 }
122
123 // called when this character is being destroyed and the resources should be released
124 public void Destroy()
125 {
126 _scene.TaintedObject(delegate()
127 {
128 BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
129 });
130 }
131
132 public override void RequestPhysicsterseUpdate()
133 {
134 base.RequestPhysicsterseUpdate();
135 }
136
137 public override bool Stopped {
138 get { return _stopped; }
139 }
140 public override Vector3 Size {
141 get { return _size; }
142 set { _size = value;
143 }
144 }
145 public override PrimitiveBaseShape Shape {
146 set { _pbs = value;
147 }
148 }
149 public override uint LocalID {
150 set { _localID = value;
151 }
152 get { return _localID; }
153 }
154 public override bool Grabbed {
155 set { _grabbed = value;
156 }
157 }
158 public override bool Selected {
159 set { _selected = value;
160 }
161 }
162 public override void CrossingFailure() { return; }
163 public override void link(PhysicsActor obj) { return; }
164 public override void delink() { return; }
165 public override void LockAngularMotion(Vector3 axis) { return; }
166
167 public override Vector3 Position {
168 get {
169 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
170 return _position;
171 }
172 set {
173 _position = value;
174 _scene.TaintedObject(delegate()
175 {
176 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
177 });
178 }
179 }
180 public override float Mass {
181 get {
182 return _mass;
183 }
184 }
185 public override Vector3 Force {
186 get { return _force; }
187 set {
188 _force = value;
189 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
190 _scene.TaintedObject(delegate()
191 {
192 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
193 });
194 }
195 }
196
197 public override int VehicleType {
198 get { return 0; }
199 set { return; }
200 }
201 public override void VehicleFloatParam(int param, float value) { }
202 public override void VehicleVectorParam(int param, Vector3 value) {}
203 public override void VehicleRotationParam(int param, Quaternion rotation) { }
204 public override void VehicleFlags(int param, bool remove) { }
205
206 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
207 public override void SetVolumeDetect(int param) { return; }
208
209 public override Vector3 GeometricCenter { get { return Vector3.Zero; } }
210 public override Vector3 CenterOfMass { get { return Vector3.Zero; } }
211 public override Vector3 Velocity {
212 get { return _velocity; }
213 set {
214 _velocity = value;
215 _scene.TaintedObject(delegate()
216 {
217 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity);
218 });
219 }
220 }
221 public override Vector3 Torque {
222 get { return _torque; }
223 set { _torque = value;
224 }
225 }
226 public override float CollisionScore {
227 get { return _collisionScore; }
228 set { _collisionScore = value;
229 }
230 }
231 public override Vector3 Acceleration {
232 get { return _acceleration; }
233 }
234 public override Quaternion Orientation {
235 get { return _orientation; }
236 set {
237 _orientation = value;
238 _scene.TaintedObject(delegate()
239 {
240 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
241 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
242 });
243 }
244 }
245 public override int PhysicsActorType {
246 get { return _physicsActorType; }
247 set { _physicsActorType = value;
248 }
249 }
250 public override bool IsPhysical {
251 get { return _isPhysical; }
252 set { _isPhysical = value;
253 }
254 }
255 public override bool Flying {
256 get { return _flying; }
257 set {
258 _flying = value;
259 _scene.TaintedObject(delegate()
260 {
261 // simulate flying by changing the effect of gravity
262 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _flying ? 1f : 0f);
263 });
264 }
265 }
266 public override bool
267 SetAlwaysRun {
268 get { return _setAlwaysRun; }
269 set { _setAlwaysRun = value; }
270 }
271 public override bool ThrottleUpdates {
272 get { return _throttleUpdates; }
273 set { _throttleUpdates = value; }
274 }
275 public override bool IsColliding {
276 get { return (_collidingStep == _scene.SimulationStep); }
277 set { _isColliding = value; }
278 }
279 public override bool CollidingGround {
280 get { return (_collidingGroundStep == _scene.SimulationStep); }
281 set { _collidingGround = value; }
282 }
283 public override bool CollidingObj {
284 get { return _collidingObj; }
285 set { _collidingObj = value; }
286 }
287 public override bool FloatOnWater {
288 set { _floatOnWater = value; }
289 }
290 public override Vector3 RotationalVelocity {
291 get { return _rotationalVelocity; }
292 set { _rotationalVelocity = value; }
293 }
294 public override bool Kinematic {
295 get { return _kinematic; }
296 set { _kinematic = value; }
297 }
298 public override float Buoyancy {
299 get { return _buoyancy; }
300 set { _buoyancy = value;
301 _scene.TaintedObject(delegate()
302 {
303 // simulate flying by changing the effect of gravity
304 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy);
305 });
306 }
307 }
308
309 // Used for MoveTo
310 public override Vector3 PIDTarget {
311 set { _PIDTarget = value; }
312 }
313 public override bool PIDActive {
314 set { _usePID = value; }
315 }
316 public override float PIDTau {
317 set { _PIDTau = value; }
318 }
319
320 // Used for llSetHoverHeight and maybe vehicle height
321 // Hover Height will override MoveTo target's Z
322 public override bool PIDHoverActive {
323 set { _useHoverPID = value; }
324 }
325 public override float PIDHoverHeight {
326 set { _PIDHoverHeight = value; }
327 }
328 public override PIDHoverType PIDHoverType {
329 set { _PIDHoverType = value; }
330 }
331 public override float PIDHoverTau {
332 set { _PIDHoverTao = value; }
333 }
334
335 // For RotLookAt
336 public override Quaternion APIDTarget { set { return; } }
337 public override bool APIDActive { set { return; } }
338 public override float APIDStrength { set { return; } }
339 public override float APIDDamping { set { return; } }
340
341 public override void AddForce(Vector3 force, bool pushforce) {
342 if (force.IsFinite())
343 {
344 _force.X += force.X;
345 _force.Y += force.Y;
346 _force.Z += force.Z;
347 _scene.TaintedObject(delegate()
348 {
349 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
350 });
351 }
352 else
353 {
354 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
355 }
356 //m_lastUpdateSent = false;
357 }
358 public override void AddAngularForce(Vector3 force, bool pushforce) {
359 }
360 public override void SetMomentum(Vector3 momentum) {
361 }
362 public override void SubscribeEvents(int ms) {
363 _subscribedEventsMs = ms;
364 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
365 }
366 public override void UnSubscribeEvents() {
367 _subscribedEventsMs = 0;
368 }
369 public override bool SubscribedEvents() {
370 return (_subscribedEventsMs > 0);
371 }
372
373 // The physics engine says that properties have updated. Update same and inform
374 // the world that things have changed.
375 public void UpdateProperties(EntityProperties entprop)
376 {
377 bool changed = false;
378 // we assign to the local variables so the normal set action does not happen
379 if (_position != entprop.Position)
380 {
381 _position = entprop.Position;
382 changed = true;
383 }
384 if (_orientation != entprop.Rotation)
385 {
386 _orientation = entprop.Rotation;
387 changed = true;
388 }
389 if (_velocity != entprop.Velocity)
390 {
391 _velocity = entprop.Velocity;
392 changed = true;
393 }
394 if (_acceleration != entprop.Acceleration)
395 {
396 _acceleration = entprop.Acceleration;
397 changed = true;
398 }
399 if (_rotationalVelocity != entprop.RotationalVelocity)
400 {
401 _rotationalVelocity = entprop.RotationalVelocity;
402 changed = true;
403 }
404 if (changed)
405 {
406 // base.RequestPhysicsterseUpdate();
407 }
408 }
409
410 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
411 {
412 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
413
414 // The following makes IsColliding() and IsCollidingGround() work
415 _collidingStep = _scene.SimulationStep;
416 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
417 {
418 _collidingGroundStep = _scene.SimulationStep;
419 }
420
421 // throttle collisions to the rate specified in the subscription
422 if (_subscribedEventsMs == 0) return; // don't want collisions
423 int nowTime = _scene.SimulationNowTime;
424 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
425 _lastCollisionTime = nowTime;
426
427 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
428 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
429 CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
430 base.SendCollisionUpdate(args);
431 }
432
433}
434}
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..04cb452
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -0,0 +1,1265 @@
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 if (this._parentPrim == null)
1227 {
1228 // Assign to the local variables so the normal set action does not happen
1229 _position = entprop.Position;
1230 _orientation = entprop.Rotation;
1231 _velocity = entprop.Velocity;
1232 _acceleration = entprop.Acceleration;
1233 _rotationalVelocity = entprop.RotationalVelocity;
1234 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1235 base.RequestPhysicsterseUpdate();
1236 }
1237 }
1238 }
1239
1240 // I've collided with something
1241 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1242 {
1243 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
1244
1245 // The following lines make IsColliding() and IsCollidingGround() work
1246 _collidingStep = _scene.SimulationStep;
1247 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
1248 {
1249 _collidingGroundStep = _scene.SimulationStep;
1250 }
1251
1252 if (_subscribedEventsMs == 0) return; // nothing in the object is waiting for collision events
1253 // throttle the collisions to the number of milliseconds specified in the subscription
1254 int nowTime = _scene.SimulationNowTime;
1255 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
1256 _lastCollisionTime = nowTime;
1257
1258 // create the event for the collision
1259 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
1260 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1261 CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
1262 base.SendCollisionUpdate(args);
1263 }
1264}
1265}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
new file mode 100644
index 0000000..de86d59
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -0,0 +1,655 @@
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
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 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
67 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>();
68 private List<BSPrim> m_vehicles = new List<BSPrim>();
69 private float[] m_heightMap;
70 private float m_waterLevel;
71 private uint m_worldID;
72 public uint WorldID { get { return m_worldID; } }
73
74 private bool m_initialized = false;
75
76 public IMesher mesher;
77 private int m_meshLOD;
78 public int MeshLOD
79 {
80 get { return m_meshLOD; }
81 }
82
83 private int m_maxSubSteps;
84 private float m_fixedTimeStep;
85 private long m_simulationStep = 0;
86 public long SimulationStep { get { return m_simulationStep; } }
87
88 // A value of the time now so all the collision and update routines do not have to get their own
89 // Set to 'now' just before all the prims and actors are called for collisions and updates
90 private int m_simulationNowTime;
91 public int SimulationNowTime { get { return m_simulationNowTime; } }
92
93 private int m_maxCollisionsPerFrame;
94 private CollisionDesc[] m_collisionArray;
95 private GCHandle m_collisionArrayPinnedHandle;
96
97 private int m_maxUpdatesPerFrame;
98 private EntityProperties[] m_updateArray;
99 private GCHandle m_updateArrayPinnedHandle;
100
101 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed
102 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes
103
104 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
105 public const uint GROUNDPLANE_ID = 1;
106
107 public ConfigurationParameters Params
108 {
109 get { return m_params[0]; }
110 }
111 public Vector3 DefaultGravity
112 {
113 get { return new Vector3(0f, 0f, Params.gravity); }
114 }
115
116 private float m_maximumObjectMass;
117 public float MaximumObjectMass
118 {
119 get { return m_maximumObjectMass; }
120 }
121
122 public delegate void TaintCallback();
123 private List<TaintCallback> _taintedObjects;
124 private Object _taintLock = new Object();
125
126 // A pointer to an instance if this structure is passed to the C++ code
127 ConfigurationParameters[] m_params;
128 GCHandle m_paramsHandle;
129
130 private BulletSimAPI.DebugLogCallback debugLogCallbackHandle;
131
132 public BSScene(string identifier)
133 {
134 m_initialized = false;
135 }
136
137 public override void Initialise(IMesher meshmerizer, IConfigSource config)
138 {
139 // Allocate pinned memory to pass parameters.
140 m_params = new ConfigurationParameters[1];
141 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
142
143 // Set default values for physics parameters plus any overrides from the ini file
144 GetInitialParameterValues(config);
145
146 // allocate more pinned memory close to the above in an attempt to get the memory all together
147 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
148 m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned);
149 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
150 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
151
152 // if Debug, enable logging from the unmanaged code
153 if (m_log.IsDebugEnabled)
154 {
155 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
156 debugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
157 BulletSimAPI.SetDebugLogCallback(debugLogCallbackHandle);
158 }
159
160 _taintedObjects = new List<TaintCallback>();
161
162 mesher = meshmerizer;
163 // The bounding box for the simulated world
164 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 4096f);
165
166 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
167 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
168 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
169 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
170
171 m_initialized = true;
172 }
173
174 // All default parameter values are set here. There should be no values set in the
175 // variable definitions.
176 private void GetInitialParameterValues(IConfigSource config)
177 {
178 ConfigurationParameters parms = new ConfigurationParameters();
179
180 _meshSculptedPrim = true; // mesh sculpted prims
181 _forceSimplePrimMeshing = false; // use complex meshing if called for
182
183 m_meshLOD = 32;
184
185 m_maxSubSteps = 10;
186 m_fixedTimeStep = 1f / 60f;
187 m_maxCollisionsPerFrame = 2048;
188 m_maxUpdatesPerFrame = 2048;
189 m_maximumObjectMass = 10000.01f;
190
191 parms.defaultFriction = 0.70f;
192 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
193 parms.defaultRestitution = 0f;
194 parms.collisionMargin = 0.0f;
195 parms.gravity = -9.80665f;
196
197 parms.linearDamping = 0.0f;
198 parms.angularDamping = 0.0f;
199 parms.deactivationTime = 0.2f;
200 parms.linearSleepingThreshold = 0.8f;
201 parms.angularSleepingThreshold = 1.0f;
202 parms.ccdMotionThreshold = 0.5f; // set to zero to disable
203 parms.ccdSweptSphereRadius = 0.2f;
204
205 parms.terrainFriction = 0.85f;
206 parms.terrainHitFriction = 0.8f;
207 parms.terrainRestitution = 0.2f;
208 parms.avatarFriction = 0.85f;
209 parms.avatarDensity = 60f;
210 parms.avatarCapsuleRadius = 0.37f;
211 parms.avatarCapsuleHeight = 1.5f; // 2.140599f
212
213 if (config != null)
214 {
215 // If there are specifications in the ini file, use those values
216 // WHEN ADDING OR UPDATING THIS SECTION, BE SURE TO ALSO UPDATE OpenSimDefaults.ini
217 IConfig pConfig = config.Configs["BulletSim"];
218 if (pConfig != null)
219 {
220 _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim);
221 _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing);
222
223 m_meshLOD = pConfig.GetInt("MeshLevelOfDetail", m_meshLOD);
224
225 m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps);
226 m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep);
227 m_maxCollisionsPerFrame = pConfig.GetInt("MaxCollisionsPerFrame", m_maxCollisionsPerFrame);
228 m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame);
229 m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass);
230
231 parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction);
232 parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity);
233 parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution);
234 parms.collisionMargin = pConfig.GetFloat("CollisionMargin", parms.collisionMargin);
235 parms.gravity = pConfig.GetFloat("Gravity", parms.gravity);
236
237 parms.linearDamping = pConfig.GetFloat("LinearDamping", parms.linearDamping);
238 parms.angularDamping = pConfig.GetFloat("AngularDamping", parms.angularDamping);
239 parms.deactivationTime = pConfig.GetFloat("DeactivationTime", parms.deactivationTime);
240 parms.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", parms.linearSleepingThreshold);
241 parms.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", parms.angularSleepingThreshold);
242 parms.ccdMotionThreshold = pConfig.GetFloat("CcdMotionThreshold", parms.ccdMotionThreshold);
243 parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius);
244
245 parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction);
246 parms.terrainHitFriction = pConfig.GetFloat("TerrainHitFriction", parms.terrainHitFriction);
247 parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution);
248 parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction);
249 parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity);
250 parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius);
251 parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight);
252 }
253 }
254 m_params[0] = parms;
255 }
256
257 // Called directly from unmanaged code so don't do much
258 private void BulletLogger(string msg)
259 {
260 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
261 }
262
263 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
264 {
265 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
266 return null;
267 }
268
269 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
270 {
271 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
272 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
273 lock (m_avatars) m_avatars.Add(localID, actor);
274 return actor;
275 }
276
277 public override void RemoveAvatar(PhysicsActor actor)
278 {
279 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
280 if (actor is BSCharacter)
281 {
282 ((BSCharacter)actor).Destroy();
283 }
284 try
285 {
286 lock (m_avatars) m_avatars.Remove(actor.LocalID);
287 }
288 catch (Exception e)
289 {
290 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
291 }
292 }
293
294 public override void RemovePrim(PhysicsActor prim)
295 {
296 // m_log.DebugFormat("{0}: RemovePrim", LogHeader);
297 if (prim is BSPrim)
298 {
299 ((BSPrim)prim).Destroy();
300 }
301 try
302 {
303 lock (m_prims) m_prims.Remove(prim.LocalID);
304 }
305 catch (Exception e)
306 {
307 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
308 }
309 }
310
311 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
312 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
313 {
314 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
315 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
316 lock (m_prims) m_prims.Add(localID, prim);
317 return prim;
318 }
319
320 // This is a call from the simulator saying that some physical property has been updated.
321 // The BulletSim driver senses the changing of relevant properties so this taint
322 // information call is not needed.
323 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
324
325 // Simulate one timestep
326 public override float Simulate(float timeStep)
327 {
328 int updatedEntityCount;
329 IntPtr updatedEntitiesPtr;
330 int collidersCount;
331 IntPtr collidersPtr;
332
333 // prevent simulation until we've been initialized
334 if (!m_initialized) return 10.0f;
335
336 // update the prim states while we know the physics engine is not busy
337 ProcessTaints();
338
339 // Some of the prims operate with special vehicle properties
340 ProcessVehicles(timeStep);
341 ProcessTaints(); // the vehicles might have added taints
342
343 // step the physical world one interval
344 m_simulationStep++;
345 int numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
346 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
347
348 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
349
350 // Get a value for 'now' so all the collision and update routines don't have to get their own
351 m_simulationNowTime = Util.EnvironmentTickCount();
352
353 // If there were collisions, process them by sending the event to the prim.
354 // Collisions must be processed before updates.
355 if (collidersCount > 0)
356 {
357 for (int ii = 0; ii < collidersCount; ii++)
358 {
359 uint cA = m_collisionArray[ii].aID;
360 uint cB = m_collisionArray[ii].bID;
361 Vector3 point = m_collisionArray[ii].point;
362 Vector3 normal = m_collisionArray[ii].normal;
363 SendCollision(cA, cB, point, normal, 0.01f);
364 SendCollision(cB, cA, point, -normal, 0.01f);
365 }
366 }
367
368 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
369 if (updatedEntityCount > 0)
370 {
371 for (int ii = 0; ii < updatedEntityCount; ii++)
372 {
373 EntityProperties entprop = m_updateArray[ii];
374 // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position);
375 BSCharacter actor;
376 if (m_avatars.TryGetValue(entprop.ID, out actor))
377 {
378 actor.UpdateProperties(entprop);
379 continue;
380 }
381 BSPrim prim;
382 if (m_prims.TryGetValue(entprop.ID, out prim))
383 {
384 prim.UpdateProperties(entprop);
385 }
386 }
387 }
388
389 // FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation.
390 return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f;
391 }
392
393 // Something has collided
394 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration)
395 {
396 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID)
397 {
398 return; // don't send collisions to the terrain
399 }
400
401 ActorTypes type = ActorTypes.Prim;
402 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID)
403 type = ActorTypes.Ground;
404 else if (m_avatars.ContainsKey(collidingWith))
405 type = ActorTypes.Agent;
406
407 BSPrim prim;
408 if (m_prims.TryGetValue(localID, out prim)) {
409 prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
410 return;
411 }
412 BSCharacter actor;
413 if (m_avatars.TryGetValue(localID, out actor)) {
414 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
415 return;
416 }
417 return;
418 }
419
420 public override void GetResults() { }
421
422 public override void SetTerrain(float[] heightMap) {
423 m_heightMap = heightMap;
424 this.TaintedObject(delegate()
425 {
426 BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
427 });
428 }
429
430 public float GetTerrainHeightAtXY(float tX, float tY)
431 {
432 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
433 }
434
435 public override void SetWaterLevel(float baseheight)
436 {
437 m_waterLevel = baseheight;
438 }
439 public float GetWaterLevel()
440 {
441 return m_waterLevel;
442 }
443
444 public override void DeleteTerrain()
445 {
446 m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
447 }
448
449 public override void Dispose()
450 {
451 m_log.DebugFormat("{0}: Dispose()", LogHeader);
452 }
453
454 public override Dictionary<uint, float> GetTopColliders()
455 {
456 return new Dictionary<uint, float>();
457 }
458
459 public override bool IsThreaded { get { return false; } }
460
461 /// <summary>
462 /// Routine to figure out if we need to mesh this prim with our mesher
463 /// </summary>
464 /// <param name="pbs"></param>
465 /// <returns>true if the prim needs meshing</returns>
466 public bool NeedsMeshing(PrimitiveBaseShape pbs)
467 {
468 // most of this is redundant now as the mesher will return null if it cant mesh a prim
469 // but we still need to check for sculptie meshing being enabled so this is the most
470 // convenient place to do it for now...
471
472 // int iPropertiesNotSupportedDefault = 0;
473
474 if (pbs.SculptEntry && !_meshSculptedPrim)
475 {
476 // Render sculpties as boxes
477 return false;
478 }
479
480 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet
481 // can use an internal representation for the prim
482 if (!_forceSimplePrimMeshing)
483 {
484 // m_log.DebugFormat("{0}: NeedsMeshing: simple mesh: profshape={1}, curve={2}", LogHeader, pbs.ProfileShape, pbs.PathCurve);
485 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
486 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
487 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
488 {
489
490 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
491 && pbs.ProfileHollow == 0
492 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
493 && pbs.PathBegin == 0 && pbs.PathEnd == 0
494 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
495 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
496 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
497 {
498 return false;
499 }
500 }
501 }
502
503 /* TODO: verify that the mesher will now do all these shapes
504 if (pbs.ProfileHollow != 0)
505 iPropertiesNotSupportedDefault++;
506
507 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
508 iPropertiesNotSupportedDefault++;
509
510 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
511 iPropertiesNotSupportedDefault++;
512
513 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
514 iPropertiesNotSupportedDefault++;
515
516 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
517 iPropertiesNotSupportedDefault++;
518
519 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
520 iPropertiesNotSupportedDefault++;
521
522 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
523 iPropertiesNotSupportedDefault++;
524
525 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))
526 iPropertiesNotSupportedDefault++;
527
528 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
529 iPropertiesNotSupportedDefault++;
530
531 // test for torus
532 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
533 {
534 if (pbs.PathCurve == (byte)Extrusion.Curve1)
535 {
536 iPropertiesNotSupportedDefault++;
537 }
538 }
539 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
540 {
541 if (pbs.PathCurve == (byte)Extrusion.Straight)
542 {
543 iPropertiesNotSupportedDefault++;
544 }
545 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
546 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
547 {
548 iPropertiesNotSupportedDefault++;
549 }
550 }
551 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
552 {
553 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
554 {
555 iPropertiesNotSupportedDefault++;
556 }
557 }
558 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
559 {
560 if (pbs.PathCurve == (byte)Extrusion.Straight)
561 {
562 iPropertiesNotSupportedDefault++;
563 }
564 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
565 {
566 iPropertiesNotSupportedDefault++;
567 }
568 }
569 if (iPropertiesNotSupportedDefault == 0)
570 {
571 return false;
572 }
573 */
574 return true;
575 }
576
577 // The calls to the PhysicsActors can't directly call into the physics engine
578 // because it might be busy. We we delay changes to a known time.
579 // We rely on C#'s closure to save and restore the context for the delegate.
580 public void TaintedObject(TaintCallback callback)
581 {
582 lock (_taintLock)
583 _taintedObjects.Add(callback);
584 return;
585 }
586
587 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
588 // a callback into itself to do the actual property change. That callback is called
589 // here just before the physics engine is called to step the simulation.
590 public void ProcessTaints()
591 {
592 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
593 {
594 // swizzle a new list into the list location so we can process what's there
595 List<TaintCallback> oldList;
596 lock (_taintLock)
597 {
598 oldList = _taintedObjects;
599 _taintedObjects = new List<TaintCallback>();
600 }
601
602 foreach (TaintCallback callback in oldList)
603 {
604 try
605 {
606 callback();
607 }
608 catch (Exception e)
609 {
610 m_log.ErrorFormat("{0}: ProcessTaints: Exception: {1}", LogHeader, e);
611 }
612 }
613 oldList.Clear();
614 }
615 }
616
617 #region Vehicles
618 // Make so the scene will call this prim for vehicle actions each tick.
619 // Safe to call if prim is already in the vehicle list.
620 public void AddVehiclePrim(BSPrim vehicle)
621 {
622 lock (m_vehicles)
623 {
624 if (!m_vehicles.Contains(vehicle))
625 {
626 m_vehicles.Add(vehicle);
627 }
628 }
629 }
630
631 // Remove a prim from our list of vehicles.
632 // Safe to call if the prim is not in the vehicle list.
633 public void RemoveVehiclePrim(BSPrim vehicle)
634 {
635 lock (m_vehicles)
636 {
637 if (m_vehicles.Contains(vehicle))
638 {
639 m_vehicles.Remove(vehicle);
640 }
641 }
642 }
643
644 // Some prims have extra vehicle actions
645 // no locking because only called when physics engine is not busy
646 private void ProcessVehicles(float timeStep)
647 {
648 foreach (BSPrim prim in m_vehicles)
649 {
650 prim.StepVehicle(timeStep);
651 }
652 }
653 #endregion Vehicles
654}
655}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
new file mode 100644
index 0000000..819fce1
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -0,0 +1,234 @@
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 // note that bools are passed as ints since bool size changes by language
55 public const int numericTrue = 1;
56 public const int numericFalse = 0;
57 public uint ID;
58 public PhysicsShapeType Type;
59 public Vector3 Position;
60 public Quaternion Rotation;
61 public Vector3 Velocity;
62 public Vector3 Scale;
63 public float Mass;
64 public float Buoyancy;
65 public System.UInt64 MeshKey;
66 public float Friction;
67 public float Restitution;
68 public int Collidable;
69 public int Static; // true if a static object. Otherwise gravity, etc.
70}
71[StructLayout(LayoutKind.Sequential)]
72public struct SweepHit
73{
74 public uint ID;
75 public float Fraction;
76 public Vector3 Normal;
77 public Vector3 Point;
78}
79[StructLayout(LayoutKind.Sequential)]
80public struct RaycastHit
81{
82 public uint ID;
83 public float Fraction;
84 public Vector3 Normal;
85}
86[StructLayout(LayoutKind.Sequential)]
87public struct CollisionDesc
88{
89 public uint aID;
90 public uint bID;
91 public Vector3 point;
92 public Vector3 normal;
93}
94[StructLayout(LayoutKind.Sequential)]
95public struct EntityProperties
96{
97 public uint ID;
98 public Vector3 Position;
99 public Quaternion Rotation;
100 public Vector3 Velocity;
101 public Vector3 Acceleration;
102 public Vector3 RotationalVelocity;
103}
104
105// Format of this structure must match the definition in the C++ code
106[StructLayout(LayoutKind.Sequential)]
107public struct ConfigurationParameters
108{
109 public float defaultFriction;
110 public float defaultDensity;
111 public float defaultRestitution;
112 public float collisionMargin;
113 public float gravity;
114
115 public float linearDamping;
116 public float angularDamping;
117 public float deactivationTime;
118 public float linearSleepingThreshold;
119 public float angularSleepingThreshold;
120 public float ccdMotionThreshold;
121 public float ccdSweptSphereRadius;
122
123 public float terrainFriction;
124 public float terrainHitFriction;
125 public float terrainRestitution;
126 public float avatarFriction;
127 public float avatarDensity;
128 public float avatarRestitution;
129 public float avatarCapsuleRadius;
130 public float avatarCapsuleHeight;
131}
132
133static class BulletSimAPI {
134
135[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
136public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
137 int maxCollisions, IntPtr collisionArray,
138 int maxUpdates, IntPtr updateArray);
139
140[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
141public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
142
143[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
144public static extern void Shutdown(uint worldID);
145
146
147[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
148public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
149 out int updatedEntityCount,
150 out IntPtr updatedEntitiesPtr,
151 out int collidersCount,
152 out IntPtr collidersPtr);
153
154[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
155public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, int hullCount,
156 [MarshalAs(UnmanagedType.LPArray)] float[] hulls
157 );
158
159[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
160public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey);
161
162[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
163public static extern bool CreateObject(uint worldID, ShapeData shapeData);
164
165[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
166public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
167
168[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
169public static extern void AddConstraint(uint worldID, uint id1, uint id2,
170 Vector3 frame1, Quaternion frame1rot,
171 Vector3 frame2, Quaternion frame2rot,
172 Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
173
174[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
175public static extern bool RemoveConstraintByID(uint worldID, uint id1);
176
177[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
178public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
179
180[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
181public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
182
183[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
184public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
185
186[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
187public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity);
188
189[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
190public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
191
192[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
193public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
194
195[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
196public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic);
197
198[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
199public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom);
200
201[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
202public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass);
203
204[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
205public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly);
206
207[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
208public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass);
209
210[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
211public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy);
212
213[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
214public static extern bool HasObject(uint worldID, uint id);
215
216[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
217public static extern bool DestroyObject(uint worldID, uint id);
218
219[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
220public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
221
222[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
223public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to);
224
225[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
226public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
227
228// Log a debug message
229[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
230public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
231[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
232public static extern void SetDebugLogCallback(DebugLogCallback callback);
233}
234}