aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
authorRobert Adams2011-06-20 17:14:59 -0700
committerDan Lake2011-06-20 17:24:42 -0700
commit302d72701da35b6d481a538c4cb953976d7e9044 (patch)
treefe11403b00e640da659c48dddbc9646860380ccd /OpenSim/Region/Physics/BulletSPlugin
parentMerge branch 'master' of ssh://opensimulator.org/var/git/opensim (diff)
downloadopensim-SC_OLD-302d72701da35b6d481a538c4cb953976d7e9044.zip
opensim-SC_OLD-302d72701da35b6d481a538c4cb953976d7e9044.tar.gz
opensim-SC_OLD-302d72701da35b6d481a538c4cb953976d7e9044.tar.bz2
opensim-SC_OLD-302d72701da35b6d481a538c4cb953976d7e9044.tar.xz
BulletSim initial checkin
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs426
-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.cs1192
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs553
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs186
6 files changed, 3376 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..d9e236f
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -0,0 +1,426 @@
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 public float CAPSULE_RADIUS = 0.37f;
55 public float CAPSULE_LENGTH = 2.140599f;
56 private Vector3 _force;
57 private Vector3 _velocity;
58 private Vector3 _torque;
59 private float _collisionScore;
60 private Vector3 _acceleration;
61 private Quaternion _orientation;
62 private int _physicsActorType;
63 private bool _isPhysical;
64 private bool _flying;
65 private bool _setAlwaysRun;
66 private bool _throttleUpdates;
67 private bool _isColliding;
68 private long _collidingStep;
69 private bool _collidingGround;
70 private long _collidingGroundStep;
71 private bool _collidingObj;
72 private bool _floatOnWater;
73 private Vector3 _rotationalVelocity;
74 private bool _kinematic;
75 private float _buoyancy;
76
77 private int _subscribedEventsMs = 0;
78 private int _lastCollisionTime = 0;
79
80 private Vector3 _PIDTarget;
81 private bool _usePID;
82 private float _PIDTau;
83 private bool _useHoverPID;
84 private float _PIDHoverHeight;
85 private PIDHoverType _PIDHoverType;
86 private float _PIDHoverTao;
87
88 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying)
89 {
90 _localID = localID;
91 _avName = avName;
92 _scene = parent_scene;
93 _position = pos;
94 _size = size;
95 _orientation = Quaternion.Identity;
96 _velocity = Vector3.Zero;
97 _buoyancy = 0f; // characters return a buoyancy of zero
98 _scale = new Vector3(1f, 1f, 1f);
99 float AVvolume = (float) (Math.PI*Math.Pow(CAPSULE_RADIUS, 2)*CAPSULE_LENGTH);
100 _mass = _density*AVvolume;
101
102 ShapeData shapeData = new ShapeData();
103 shapeData.ID = _localID;
104 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
105 shapeData.Position = _position;
106 shapeData.Rotation = _orientation;
107 shapeData.Velocity = _velocity;
108 shapeData.Scale = _scale;
109 shapeData.Mass = _mass;
110 shapeData.Buoyancy = isFlying ? 0f : 1f;
111 shapeData.Static = ShapeData.numericFalse;
112
113 // do actual create at taint time
114 _scene.TaintedObject(delegate()
115 {
116 BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData);
117 });
118
119 return;
120 }
121
122 // called when this character is being destroyed and the resources should be released
123 public void Destroy()
124 {
125 _scene.TaintedObject(delegate()
126 {
127 BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
128 });
129 }
130
131 public override void RequestPhysicsterseUpdate()
132 {
133 base.RequestPhysicsterseUpdate();
134 }
135
136 public override bool Stopped {
137 get { return _stopped; }
138 }
139 public override Vector3 Size {
140 get { return _size; }
141 set { _size = value;
142 }
143 }
144 public override PrimitiveBaseShape Shape {
145 set { _pbs = value;
146 }
147 }
148 public override uint LocalID {
149 set { _localID = value;
150 }
151 get { return _localID; }
152 }
153 public override bool Grabbed {
154 set { _grabbed = value;
155 }
156 }
157 public override bool Selected {
158 set { _selected = value;
159 }
160 }
161 public override void CrossingFailure() { return; }
162 public override void link(PhysicsActor obj) { return; }
163 public override void delink() { return; }
164 public override void LockAngularMotion(Vector3 axis) { return; }
165
166 public override Vector3 Position {
167 get {
168 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
169 return _position;
170 }
171 set {
172 _position = value;
173 _scene.TaintedObject(delegate()
174 {
175 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
176 });
177 }
178 }
179 public override float Mass {
180 get {
181 return _mass;
182 }
183 }
184 public override Vector3 Force {
185 get { return _force; }
186 set {
187 _force = value;
188 m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
189 _scene.TaintedObject(delegate()
190 {
191 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
192 });
193 }
194 }
195
196 public override int VehicleType {
197 get { return 0; }
198 set { return; }
199 }
200 public override void VehicleFloatParam(int param, float value) { }
201 public override void VehicleVectorParam(int param, Vector3 value) {}
202 public override void VehicleRotationParam(int param, Quaternion rotation) { }
203 public override void VehicleFlags(int param, bool remove) { }
204
205 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
206 public override void SetVolumeDetect(int param) { return; }
207
208 public override Vector3 GeometricCenter { get { return Vector3.Zero; } }
209 public override Vector3 CenterOfMass { get { return Vector3.Zero; } }
210 public override Vector3 Velocity {
211 get { return _velocity; }
212 set {
213 _velocity = value;
214 _scene.TaintedObject(delegate()
215 {
216 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity);
217 });
218 }
219 }
220 public override Vector3 Torque {
221 get { return _torque; }
222 set { _torque = value;
223 }
224 }
225 public override float CollisionScore {
226 get { return _collisionScore; }
227 set { _collisionScore = value;
228 }
229 }
230 public override Vector3 Acceleration {
231 get { return _acceleration; }
232 }
233 public override Quaternion Orientation {
234 get { return _orientation; }
235 set {
236 _orientation = value;
237 _scene.TaintedObject(delegate()
238 {
239 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
240 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
241 });
242 }
243 }
244 public override int PhysicsActorType {
245 get { return _physicsActorType; }
246 set { _physicsActorType = value;
247 }
248 }
249 public override bool IsPhysical {
250 get { return _isPhysical; }
251 set { _isPhysical = value;
252 }
253 }
254 public override bool Flying {
255 get { return _flying; }
256 set {
257 _flying = value;
258 _scene.TaintedObject(delegate()
259 {
260 // simulate flying by changing the effect of gravity
261 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _flying ? 0f : 1f);
262 });
263 }
264 }
265 public override bool
266 SetAlwaysRun {
267 get { return _setAlwaysRun; }
268 set { _setAlwaysRun = value; }
269 }
270 public override bool ThrottleUpdates {
271 get { return _throttleUpdates; }
272 set { _throttleUpdates = value; }
273 }
274 public override bool IsColliding {
275 get { return (_collidingStep == _scene.SimulationStep); }
276 set { _isColliding = value; }
277 }
278 public override bool CollidingGround {
279 get { return (_collidingGroundStep == _scene.SimulationStep); }
280 set { _collidingGround = value; }
281 }
282 public override bool CollidingObj {
283 get { return _collidingObj; }
284 set { _collidingObj = value; }
285 }
286 public override bool FloatOnWater {
287 set { _floatOnWater = value; }
288 }
289 public override Vector3 RotationalVelocity {
290 get { return _rotationalVelocity; }
291 set { _rotationalVelocity = value; }
292 }
293 public override bool Kinematic {
294 get { return _kinematic; }
295 set { _kinematic = value; }
296 }
297 public override float Buoyancy {
298 get { return _buoyancy; }
299 set { _buoyancy = value; }
300 }
301
302 // Used for MoveTo
303 public override Vector3 PIDTarget {
304 set { _PIDTarget = value; }
305 }
306 public override bool PIDActive {
307 set { _usePID = value; }
308 }
309 public override float PIDTau {
310 set { _PIDTau = value; }
311 }
312
313 // Used for llSetHoverHeight and maybe vehicle height
314 // Hover Height will override MoveTo target's Z
315 public override bool PIDHoverActive {
316 set { _useHoverPID = value; }
317 }
318 public override float PIDHoverHeight {
319 set { _PIDHoverHeight = value; }
320 }
321 public override PIDHoverType PIDHoverType {
322 set { _PIDHoverType = value; }
323 }
324 public override float PIDHoverTau {
325 set { _PIDHoverTao = value; }
326 }
327
328 // For RotLookAt
329 public override Quaternion APIDTarget { set { return; } }
330 public override bool APIDActive { set { return; } }
331 public override float APIDStrength { set { return; } }
332 public override float APIDDamping { set { return; } }
333
334 public override void AddForce(Vector3 force, bool pushforce) {
335 if (force.IsFinite())
336 {
337 _force.X += force.X;
338 _force.Y += force.Y;
339 _force.Z += force.Z;
340 _scene.TaintedObject(delegate()
341 {
342 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
343 });
344 }
345 else
346 {
347 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
348 }
349 //m_lastUpdateSent = false;
350 }
351 public override void AddAngularForce(Vector3 force, bool pushforce) {
352 }
353 public override void SetMomentum(Vector3 momentum) {
354 }
355 public override void SubscribeEvents(int ms) {
356 _subscribedEventsMs = ms;
357 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
358 }
359 public override void UnSubscribeEvents() {
360 _subscribedEventsMs = 0;
361 }
362 public override bool SubscribedEvents() {
363 return (_subscribedEventsMs > 0);
364 }
365
366 // The physics engine says that properties have updated. Update same and inform
367 // the world that things have changed.
368 public void UpdateProperties(EntityProperties entprop)
369 {
370 bool changed = false;
371 // we assign to the local variables so the normal set action does not happen
372 if (_position != entprop.Position)
373 {
374 _position = entprop.Position;
375 changed = true;
376 }
377 if (_orientation != entprop.Rotation)
378 {
379 _orientation = entprop.Rotation;
380 changed = true;
381 }
382 if (_velocity != entprop.Velocity)
383 {
384 _velocity = entprop.Velocity;
385 changed = true;
386 }
387 if (_acceleration != entprop.Acceleration)
388 {
389 _acceleration = entprop.Acceleration;
390 changed = true;
391 }
392 if (_rotationalVelocity != entprop.AngularVelocity)
393 {
394 _rotationalVelocity = entprop.AngularVelocity;
395 changed = true;
396 }
397 if (changed)
398 {
399 // base.RequestPhysicsterseUpdate();
400 }
401 }
402
403 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
404 {
405 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
406
407 // The following makes IsColliding() and IsCollidingGround() work
408 _collidingStep = _scene.SimulationStep;
409 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
410 {
411 _collidingGroundStep = _scene.SimulationStep;
412 }
413
414 if (_subscribedEventsMs == 0) return; // don't want collisions
415 int nowTime = Util.EnvironmentTickCount();
416 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
417 _lastCollisionTime = nowTime;
418
419 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
420 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
421 CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
422 base.SendCollisionUpdate(args);
423 }
424
425}
426}
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..82a8803
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -0,0 +1,1192 @@
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 bool _setAlwaysRun;
75 private bool _throttleUpdates;
76 private bool _isColliding;
77 private bool _collidingGround;
78 private bool _collidingObj;
79 private bool _floatOnWater;
80 private OMV.Vector3 _rotationalVelocity;
81 private bool _kinematic;
82 private float _buoyancy;
83 private OMV.Vector3 _angularVelocity;
84
85 private List<BSPrim> _childrenPrims;
86 private BSPrim _parentPrim;
87
88 private int _subscribedEventsMs = 0;
89 private int _lastCollisionTime = 0;
90 long _collidingStep;
91 long _collidingGroundStep;
92
93 private BSDynamics _vehicle;
94
95 private OMV.Vector3 _PIDTarget;
96 private bool _usePID;
97 private float _PIDTau;
98 private bool _useHoverPID;
99 private float _PIDHoverHeight;
100 private PIDHoverType _PIDHoverType;
101 private float _PIDHoverTao;
102
103 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
104 OMV.Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical)
105 {
106 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
107 _localID = localID;
108 _avName = primName;
109 _scene = parent_scene;
110 _position = pos;
111 _size = size;
112 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
113 _orientation = rotation;
114 _buoyancy = 1f;
115 _velocity = OMV.Vector3.Zero;
116 _angularVelocity = OMV.Vector3.Zero;
117 _mesh = mesh;
118 _hullKey = 0;
119 _pbs = pbs;
120 _isPhysical = pisPhysical;
121 _isVolumeDetect = false;
122 _subscribedEventsMs = 0;
123 _friction = _scene.DefaultFriction; // TODO: compute based on object material
124 _density = _scene.DefaultDensity; // TODO: compute based on object material
125 _parentPrim = null; // not a child or a parent
126 _vehicle = new BSDynamics(this); // add vehicleness
127 _childrenPrims = new List<BSPrim>();
128 if (_isPhysical)
129 _mass = CalculateMass();
130 else
131 _mass = 0f;
132 // do the actual object creation at taint time
133 _scene.TaintedObject(delegate()
134 {
135 CreateGeom();
136 CreateObject();
137 });
138 }
139
140 // called when this prim is being destroyed and we should free all the resources
141 public void Destroy()
142 {
143 // m_log.DebugFormat("{0}: Destroy", LogHeader);
144 // Undo any vehicle properties
145 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
146 _scene.RemoveVehiclePrim(this); // just to make sure
147 _scene.TaintedObject(delegate()
148 {
149 BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
150 });
151 }
152
153 public override bool Stopped {
154 get { return _stopped; }
155 }
156 public override OMV.Vector3 Size {
157 get { return _size; }
158 set {
159 _size = value;
160 _scene.TaintedObject(delegate()
161 {
162 if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass
163 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical);
164 RecreateGeomAndObject();
165 });
166 }
167 }
168 public override PrimitiveBaseShape Shape {
169 set {
170 _pbs = value;
171 _scene.TaintedObject(delegate()
172 {
173 if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass
174 RecreateGeomAndObject();
175 });
176 }
177 }
178 public override uint LocalID {
179 set { _localID = value; }
180 get { return _localID; }
181 }
182 public override bool Grabbed {
183 set { _grabbed = value;
184 }
185 }
186 public override bool Selected {
187 set {
188 _isSelected = value;
189 _scene.TaintedObject(delegate()
190 {
191 SetObjectDynamic();
192 });
193 }
194 }
195 public override void CrossingFailure() { return; }
196
197 // link me to the specified parent
198 public override void link(PhysicsActor obj) {
199 BSPrim parent = (BSPrim)obj;
200 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
201 // TODO: decide if this parent checking needs to happen at taint time
202 if (_parentPrim == null)
203 {
204 if (parent != null)
205 {
206 // I don't have a parent so I am joining a linkset
207 parent.AddChildToLinkset(this);
208 }
209 }
210 else
211 {
212 // I already have a parent, is parenting changing?
213 if (parent != _parentPrim)
214 {
215 if (parent == null)
216 {
217 // we are being removed from a linkset
218 _parentPrim.RemoveChildFromLinkset(this);
219 }
220 else
221 {
222 // asking to reparent a prim should not happen
223 m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader);
224 }
225 }
226 }
227 return;
228 }
229
230 // delink me from my linkset
231 public override void delink() {
232 // TODO: decide if this parent checking needs to happen at taint time
233 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
234 // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID);
235 if (_parentPrim != null)
236 {
237 _parentPrim.RemoveChildFromLinkset(this);
238 }
239 return;
240 }
241
242 public void AddChildToLinkset(BSPrim pchild)
243 {
244 BSPrim child = pchild;
245 _scene.TaintedObject(delegate()
246 {
247 if (!_childrenPrims.Contains(child))
248 {
249 _childrenPrims.Add(child);
250 child.ParentPrim = this; // the child has gained a parent
251 RecreateGeomAndObject(); // rebuild my shape with the new child added
252 }
253 });
254 return;
255 }
256
257 public void RemoveChildFromLinkset(BSPrim pchild)
258 {
259 BSPrim child = pchild;
260 _scene.TaintedObject(delegate()
261 {
262 if (_childrenPrims.Contains(child))
263 {
264 _childrenPrims.Remove(child);
265 child.ParentPrim = null; // the child has lost its parent
266 RecreateGeomAndObject(); // rebuild my shape with the child removed
267 }
268 else
269 {
270 m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset");
271 }
272 });
273 return;
274 }
275
276 public BSPrim ParentPrim
277 {
278 set { _parentPrim = value; }
279 }
280
281 public ulong HullKey
282 {
283 get { return _hullKey; }
284 }
285
286 // return true if we are the root of a linkset (there are children to manage)
287 public bool IsRootOfLinkset
288 {
289 get { return (_parentPrim == null && _childrenPrims.Count != 0); }
290 }
291
292 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
293
294 public override OMV.Vector3 Position {
295 get {
296 // don't do the following GetObjectPosition because this function is called a zillion times
297 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
298 return _position;
299 }
300 set {
301 _position = value;
302 _scene.TaintedObject(delegate()
303 {
304 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
305 // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
306 });
307 }
308 }
309 public override float Mass {
310 get { return _mass; }
311 }
312 public override OMV.Vector3 Force {
313 get { return _force; }
314 set {
315 _force = value;
316 _scene.TaintedObject(delegate()
317 {
318 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
319 });
320 }
321 }
322
323 public override int VehicleType {
324 get {
325 return (int)_vehicle.Type; // if we are a vehicle, return that type
326 }
327 set {
328 Vehicle type = (Vehicle)value;
329 _vehicle.ProcessTypeChange(type);
330 _scene.TaintedObject(delegate()
331 {
332 if (type == Vehicle.TYPE_NONE)
333 {
334 _scene.RemoveVehiclePrim(this);
335 }
336 else
337 {
338 // make it so the scene will call us each tick to do vehicle things
339 _scene.AddVehiclePrim(this);
340 }
341 return;
342 });
343 }
344 }
345 public override void VehicleFloatParam(int param, float value)
346 {
347 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
348 }
349 public override void VehicleVectorParam(int param, OMV.Vector3 value)
350 {
351 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
352 }
353 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
354 {
355 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
356 }
357 public override void VehicleFlags(int param, bool remove)
358 {
359 _vehicle.ProcessVehicleFlags(param, remove);
360 }
361 // Called each simulation step to advance vehicle characteristics
362 public void StepVehicle(float timeStep)
363 {
364 _vehicle.Step(timeStep, _scene);
365 }
366
367 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
368 public override void SetVolumeDetect(int param) {
369 bool newValue = (param != 0);
370 if (_isVolumeDetect != newValue)
371 {
372 _isVolumeDetect = newValue;
373 _scene.TaintedObject(delegate()
374 {
375 SetObjectDynamic();
376 });
377 }
378 return;
379 }
380
381 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
382 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
383 public override OMV.Vector3 Velocity {
384 get { return _velocity; }
385 set { _velocity = value;
386 _scene.TaintedObject(delegate()
387 {
388 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
389 });
390 }
391 }
392 public OMV.Vector3 AngularVelocity
393 {
394 get { return _angularVelocity; }
395 set
396 {
397 _angularVelocity = value;
398 _scene.TaintedObject(delegate()
399 {
400 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _angularVelocity);
401 });
402 }
403 }
404 public override OMV.Vector3 Torque {
405 get { return _torque; }
406 set { _torque = value;
407 }
408 }
409 public override float CollisionScore {
410 get { return _collisionScore; }
411 set { _collisionScore = value;
412 }
413 }
414 public override OMV.Vector3 Acceleration {
415 get { return _acceleration; }
416 }
417 public override OMV.Quaternion Orientation {
418 get { return _orientation; }
419 set {
420 _orientation = value;
421 _scene.TaintedObject(delegate()
422 {
423 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
424 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
425 // m_log.DebugFormat("{0}: set orientation: {1}", LogHeader, _orientation);
426 });
427 }
428 }
429 public override int PhysicsActorType {
430 get { return _physicsActorType; }
431 set { _physicsActorType = value;
432 }
433 }
434 public override bool IsPhysical {
435 get { return _isPhysical; }
436 set {
437 _isPhysical = value;
438 _scene.TaintedObject(delegate()
439 {
440 SetObjectDynamic();
441 });
442 }
443 }
444
445 // An object is static (does not move) if selected or not physical
446 private bool IsStatic
447 {
448 get { return _isSelected || !IsPhysical; }
449 }
450
451 // An object is solid if it's not phantom and if it's not doing VolumeDetect
452 private bool IsSolid
453 {
454 get { return !IsPhantom && !_isVolumeDetect; }
455 }
456
457 // make gravity work if the object is physical and not selected
458 // no locking here because only called when it is safe
459 private void SetObjectDynamic()
460 {
461 // non-physical things work best with a mass of zero
462 _mass = IsStatic ? 0f : CalculateMass();
463 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass);
464 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}, mass={4}", LogHeader, _localID, IsStatic, IsSolid, _mass);
465 }
466
467 // prims don't fly
468 public override bool Flying {
469 get { return _flying; }
470 set { _flying = value; }
471 }
472 public override bool SetAlwaysRun {
473 get { return _setAlwaysRun; }
474 set { _setAlwaysRun = value; }
475 }
476 public override bool ThrottleUpdates {
477 get { return _throttleUpdates; }
478 set { _throttleUpdates = value; }
479 }
480 public override bool IsColliding {
481 get { return (_collidingStep == _scene.SimulationStep); }
482 set { _isColliding = value; }
483 }
484 public override bool CollidingGround {
485 get { return (_collidingGroundStep == _scene.SimulationStep); }
486 set { _collidingGround = value; }
487 }
488 public override bool CollidingObj {
489 get { return _collidingObj; }
490 set { _collidingObj = value; }
491 }
492 public bool IsPhantom {
493 get {
494 // SceneObjectPart removes phantom objects from the physics scene
495 // so, although we could implement touching and such, we never
496 // are invoked as a phantom object
497 return false;
498 }
499 }
500 public override bool FloatOnWater {
501 set { _floatOnWater = value; }
502 }
503 public override OMV.Vector3 RotationalVelocity {
504 get { return _rotationalVelocity; }
505 set { _rotationalVelocity = value;
506 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
507 }
508 }
509 public override bool Kinematic {
510 get { return _kinematic; }
511 set { _kinematic = value;
512 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
513 }
514 }
515 public override float Buoyancy {
516 get { return _buoyancy; }
517 set { _buoyancy = value;
518 _scene.TaintedObject(delegate()
519 {
520 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
521 });
522 }
523 }
524
525 // Used for MoveTo
526 public override OMV.Vector3 PIDTarget {
527 set { _PIDTarget = value; }
528 }
529 public override bool PIDActive {
530 set { _usePID = value; }
531 }
532 public override float PIDTau {
533 set { _PIDTau = value; }
534 }
535
536 // Used for llSetHoverHeight and maybe vehicle height
537 // Hover Height will override MoveTo target's Z
538 public override bool PIDHoverActive {
539 set { _useHoverPID = value; }
540 }
541 public override float PIDHoverHeight {
542 set { _PIDHoverHeight = value; }
543 }
544 public override PIDHoverType PIDHoverType {
545 set { _PIDHoverType = value; }
546 }
547 public override float PIDHoverTau {
548 set { _PIDHoverTao = value; }
549 }
550
551 // For RotLookAt
552 public override OMV.Quaternion APIDTarget { set { return; } }
553 public override bool APIDActive { set { return; } }
554 public override float APIDStrength { set { return; } }
555 public override float APIDDamping { set { return; } }
556
557 public override void AddForce(OMV.Vector3 force, bool pushforce) {
558 if (force.IsFinite())
559 {
560 _force.X += force.X;
561 _force.Y += force.Y;
562 _force.Z += force.Z;
563 }
564 else
565 {
566 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
567 }
568 _scene.TaintedObject(delegate()
569 {
570 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
571 });
572 }
573
574 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
575 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
576 }
577 public override void SetMomentum(OMV.Vector3 momentum) {
578 }
579 public override void SubscribeEvents(int ms) {
580 _subscribedEventsMs = ms;
581 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
582 }
583 public override void UnSubscribeEvents() {
584 _subscribedEventsMs = 0;
585 }
586 public override bool SubscribedEvents() {
587 return (_subscribedEventsMs > 0);
588 }
589
590 #region Mass Calculation
591
592 private float CalculateMass()
593 {
594 float volume = _size.X * _size.Y * _size.Z; // default
595 float tmp;
596
597 float returnMass = 0;
598 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
599 float hollowVolume = hollowAmount * hollowAmount;
600
601 switch (_pbs.ProfileShape)
602 {
603 case ProfileShape.Square:
604 // default box
605
606 if (_pbs.PathCurve == (byte)Extrusion.Straight)
607 {
608 if (hollowAmount > 0.0)
609 {
610 switch (_pbs.HollowShape)
611 {
612 case HollowShape.Square:
613 case HollowShape.Same:
614 break;
615
616 case HollowShape.Circle:
617
618 hollowVolume *= 0.78539816339f;
619 break;
620
621 case HollowShape.Triangle:
622
623 hollowVolume *= (0.5f * .5f);
624 break;
625
626 default:
627 hollowVolume = 0;
628 break;
629 }
630 volume *= (1.0f - hollowVolume);
631 }
632 }
633
634 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
635 {
636 //a tube
637
638 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
639 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
640 volume -= volume*tmp*tmp;
641
642 if (hollowAmount > 0.0)
643 {
644 hollowVolume *= hollowAmount;
645
646 switch (_pbs.HollowShape)
647 {
648 case HollowShape.Square:
649 case HollowShape.Same:
650 break;
651
652 case HollowShape.Circle:
653 hollowVolume *= 0.78539816339f;;
654 break;
655
656 case HollowShape.Triangle:
657 hollowVolume *= 0.5f * 0.5f;
658 break;
659 default:
660 hollowVolume = 0;
661 break;
662 }
663 volume *= (1.0f - hollowVolume);
664 }
665 }
666
667 break;
668
669 case ProfileShape.Circle:
670
671 if (_pbs.PathCurve == (byte)Extrusion.Straight)
672 {
673 volume *= 0.78539816339f; // elipse base
674
675 if (hollowAmount > 0.0)
676 {
677 switch (_pbs.HollowShape)
678 {
679 case HollowShape.Same:
680 case HollowShape.Circle:
681 break;
682
683 case HollowShape.Square:
684 hollowVolume *= 0.5f * 2.5984480504799f;
685 break;
686
687 case HollowShape.Triangle:
688 hollowVolume *= .5f * 1.27323954473516f;
689 break;
690
691 default:
692 hollowVolume = 0;
693 break;
694 }
695 volume *= (1.0f - hollowVolume);
696 }
697 }
698
699 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
700 {
701 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
702 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
703 volume *= (1.0f - tmp * tmp);
704
705 if (hollowAmount > 0.0)
706 {
707
708 // calculate the hollow volume by it's shape compared to the prim shape
709 hollowVolume *= hollowAmount;
710
711 switch (_pbs.HollowShape)
712 {
713 case HollowShape.Same:
714 case HollowShape.Circle:
715 break;
716
717 case HollowShape.Square:
718 hollowVolume *= 0.5f * 2.5984480504799f;
719 break;
720
721 case HollowShape.Triangle:
722 hollowVolume *= .5f * 1.27323954473516f;
723 break;
724
725 default:
726 hollowVolume = 0;
727 break;
728 }
729 volume *= (1.0f - hollowVolume);
730 }
731 }
732 break;
733
734 case ProfileShape.HalfCircle:
735 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
736 {
737 volume *= 0.52359877559829887307710723054658f;
738 }
739 break;
740
741 case ProfileShape.EquilateralTriangle:
742
743 if (_pbs.PathCurve == (byte)Extrusion.Straight)
744 {
745 volume *= 0.32475953f;
746
747 if (hollowAmount > 0.0)
748 {
749
750 // calculate the hollow volume by it's shape compared to the prim shape
751 switch (_pbs.HollowShape)
752 {
753 case HollowShape.Same:
754 case HollowShape.Triangle:
755 hollowVolume *= .25f;
756 break;
757
758 case HollowShape.Square:
759 hollowVolume *= 0.499849f * 3.07920140172638f;
760 break;
761
762 case HollowShape.Circle:
763 // Hollow shape is a perfect cyllinder in respect to the cube's scale
764 // Cyllinder hollow volume calculation
765
766 hollowVolume *= 0.1963495f * 3.07920140172638f;
767 break;
768
769 default:
770 hollowVolume = 0;
771 break;
772 }
773 volume *= (1.0f - hollowVolume);
774 }
775 }
776 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
777 {
778 volume *= 0.32475953f;
779 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
780 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
781 volume *= (1.0f - tmp * tmp);
782
783 if (hollowAmount > 0.0)
784 {
785
786 hollowVolume *= hollowAmount;
787
788 switch (_pbs.HollowShape)
789 {
790 case HollowShape.Same:
791 case HollowShape.Triangle:
792 hollowVolume *= .25f;
793 break;
794
795 case HollowShape.Square:
796 hollowVolume *= 0.499849f * 3.07920140172638f;
797 break;
798
799 case HollowShape.Circle:
800
801 hollowVolume *= 0.1963495f * 3.07920140172638f;
802 break;
803
804 default:
805 hollowVolume = 0;
806 break;
807 }
808 volume *= (1.0f - hollowVolume);
809 }
810 }
811 break;
812
813 default:
814 break;
815 }
816
817
818
819 float taperX1;
820 float taperY1;
821 float taperX;
822 float taperY;
823 float pathBegin;
824 float pathEnd;
825 float profileBegin;
826 float profileEnd;
827
828 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
829 {
830 taperX1 = _pbs.PathScaleX * 0.01f;
831 if (taperX1 > 1.0f)
832 taperX1 = 2.0f - taperX1;
833 taperX = 1.0f - taperX1;
834
835 taperY1 = _pbs.PathScaleY * 0.01f;
836 if (taperY1 > 1.0f)
837 taperY1 = 2.0f - taperY1;
838 taperY = 1.0f - taperY1;
839 }
840 else
841 {
842 taperX = _pbs.PathTaperX * 0.01f;
843 if (taperX < 0.0f)
844 taperX = -taperX;
845 taperX1 = 1.0f - taperX;
846
847 taperY = _pbs.PathTaperY * 0.01f;
848 if (taperY < 0.0f)
849 taperY = -taperY;
850 taperY1 = 1.0f - taperY;
851
852 }
853
854
855 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
856
857 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
858 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
859 volume *= (pathEnd - pathBegin);
860
861 // this is crude aproximation
862 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
863 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
864 volume *= (profileEnd - profileBegin);
865
866 returnMass = _density * volume;
867
868 if (returnMass <= 0)
869 returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
870
871 if (IsRootOfLinkset)
872 {
873 foreach (BSPrim prim in _childrenPrims)
874 {
875 returnMass += prim.CalculateMass();
876 }
877 }
878
879 if (returnMass > _scene.maximumMassObject)
880 returnMass = _scene.maximumMassObject;
881 return returnMass;
882 }// end CalculateMass
883 #endregion Mass Calculation
884
885 // Create the geometry information in Bullet for later use
886 // No locking here because this is done when we know physics is not simulating
887 private void CreateGeom()
888 {
889 if (_mesh == null)
890 {
891 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
892 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
893 {
894 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
895 {
896 // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to sphere of size {1}", LogHeader, _size);
897 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
898 // Bullet native objects are scaled by the Bullet engine so pass the size in
899 _scale = _size;
900 }
901 }
902 else
903 {
904 // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to box of size {1}", LogHeader, _size);
905 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
906 _scale = _size;
907 }
908 }
909 else
910 {
911 if (_hullKey != 0)
912 {
913 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
914 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
915 _hullKey = 0;
916 _hulls.Clear();
917 }
918
919 int[] indices = _mesh.getIndexListAsInt();
920 List<OMV.Vector3> vertices = _mesh.getVertexList();
921
922 //format conversion from IMesh format to DecompDesc format
923 List<int> convIndices = new List<int>();
924 List<float3> convVertices = new List<float3>();
925 for (int ii = 0; ii < indices.GetLength(0); ii++)
926 {
927 convIndices.Add(indices[ii]);
928 }
929 foreach (OMV.Vector3 vv in vertices)
930 {
931 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
932 }
933
934 // setup and do convex hull conversion
935 _hulls = new List<ConvexResult>();
936 DecompDesc dcomp = new DecompDesc();
937 dcomp.mIndices = convIndices;
938 dcomp.mVertices = convVertices;
939 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
940 // create the hull into the _hulls variable
941 convexBuilder.process(dcomp);
942
943 // Convert the vertices and indices for passing to unmanaged
944 // The hull information is passed as a large floating point array.
945 // The format is:
946 // convHulls[0] = number of hulls
947 // convHulls[1] = number of vertices in first hull
948 // convHulls[2] = hull centroid X coordinate
949 // convHulls[3] = hull centroid Y coordinate
950 // convHulls[4] = hull centroid Z coordinate
951 // convHulls[5] = first hull vertex X
952 // convHulls[6] = first hull vertex Y
953 // convHulls[7] = first hull vertex Z
954 // convHulls[8] = second hull vertex X
955 // ...
956 // convHulls[n] = number of vertices in second hull
957 // convHulls[n+1] = second hull centroid X coordinate
958 // ...
959 //
960 // TODO: is is very inefficient. Someday change the convex hull generator to return
961 // data structures that do not need to be converted in order to pass to Bullet.
962 // And maybe put the values directly into pinned memory rather than marshaling.
963 int hullCount = _hulls.Count;
964 int totalVertices = 1; // include one for the count of the hulls
965 foreach (ConvexResult cr in _hulls)
966 {
967 totalVertices += 4; // add four for the vertex count and centroid
968 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
969 }
970 float[] convHulls = new float[totalVertices];
971
972 convHulls[0] = (float)hullCount;
973 int jj = 1;
974 foreach (ConvexResult cr in _hulls)
975 {
976 // copy vertices for index access
977 float3[] verts = new float3[cr.HullVertices.Count];
978 int kk = 0;
979 foreach (float3 ff in cr.HullVertices)
980 {
981 verts[kk++] = ff;
982 }
983
984 // add to the array one hull's worth of data
985 convHulls[jj++] = cr.HullIndices.Count;
986 convHulls[jj++] = 0f; // centroid x,y,z
987 convHulls[jj++] = 0f;
988 convHulls[jj++] = 0f;
989 foreach (int ind in cr.HullIndices)
990 {
991 convHulls[jj++] = verts[ind].x;
992 convHulls[jj++] = verts[ind].y;
993 convHulls[jj++] = verts[ind].z;
994 }
995 }
996
997 // create the hull definition in Bullet
998 _hullKey = (ulong)_pbs.GetHashCode();
999 // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid= {1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
1000 BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
1001 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1002 // meshes are already scaled by the meshmerizer
1003 _scale = new OMV.Vector3(1f, 1f, 1f);
1004 }
1005 return;
1006 }
1007
1008 private void HullReturn(ConvexResult result)
1009 {
1010 _hulls.Add(result);
1011 return;
1012 }
1013
1014 // Create an object in Bullet
1015 // No locking here because this is done when the physics engine is not simulating
1016 private void CreateObject()
1017 {
1018 if (IsRootOfLinkset)
1019 {
1020 // Create a linkset around this object
1021 /*
1022 * NOTE: the original way of creating a linkset was to create a compound hull in the
1023 * root which consisted of the hulls of all the children. This didn't work well because
1024 * OpenSimulator needs updates and collisions for all the children and the physics
1025 * engine didn't create events for the children when the root hull was moved.
1026 * This code creates the compound hull.
1027 // If I am the root prim of a linkset, replace my physical shape with all the
1028 // pieces of the children.
1029 // All of the children should have called CreateGeom so they have a hull
1030 // in the physics engine already. Here we pull together all of those hulls
1031 // into one shape.
1032 int totalPrimsInLinkset = _childrenPrims.Count + 1;
1033 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset);
1034 ShapeData[] shapes = new ShapeData[totalPrimsInLinkset];
1035 FillShapeInfo(out shapes[0]);
1036 int ii = 1;
1037 foreach (BSPrim prim in _childrenPrims)
1038 {
1039 // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID);
1040 prim.FillShapeInfo(out shapes[ii]);
1041 ii++;
1042 }
1043 BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes);
1044 */
1045 // Create the linkset by putting constraints between the objects of the set so they cannot move
1046 // relative to each other.
1047 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
1048
1049 // remove any constraints that might be in place
1050 foreach (BSPrim prim in _childrenPrims)
1051 {
1052 BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
1053 }
1054 // create constraints between the root prim and each of the children
1055 foreach (BSPrim prim in _childrenPrims)
1056 {
1057 // this is a constraint that allows no freedom of movement between the two objects
1058 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
1059 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, OMV.Vector3.Zero, OMV.Vector3.Zero,
1060 OMV.Vector3.Zero, OMV.Vector3.Zero, OMV.Vector3.Zero, OMV.Vector3.Zero);
1061 }
1062 }
1063 else
1064 {
1065 // simple object
1066 // m_log.DebugFormat("{0}: CreateObject. ID={1}", LogHeader, LocalID);
1067 ShapeData shape;
1068 FillShapeInfo(out shape);
1069 BulletSimAPI.CreateObject(_scene.WorldID, shape);
1070 }
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.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1086 shape.Friction = _friction;
1087 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1088 }
1089
1090 // Rebuild the geometry and object.
1091 // This is called when the shape changes so we need to recreate the mesh/hull.
1092 // No locking here because this is done when the physics engine is not simulating
1093 private void RecreateGeomAndObject()
1094 {
1095 if (_hullKey != 0)
1096 {
1097 // if a hull already exists, delete the old one
1098 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1099 _hullKey = 0;
1100 }
1101 // If this object is complex or we are the root of a linkset, build a mesh.
1102 // The root of a linkset must be a mesh so we can create the linked compound object.
1103 if (_scene.NeedsMeshing(_pbs) || IsRootOfLinkset )
1104 {
1105 // m_log.DebugFormat("{0}: RecreateGeomAndObject: creating mesh", LogHeader);
1106 _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, _scene.meshLOD, _isPhysical);
1107 }
1108 else
1109 {
1110 // it's a BulletSim native shape.
1111 _mesh = null;
1112 }
1113 CreateGeom(); // create the geometry for this prim
1114 CreateObject();
1115 return;
1116 }
1117
1118 // The physics engine says that properties have updated. Update same and inform
1119 // the world that things have changed.
1120 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1121 private int UpPropPosition = 1 << 0;
1122 private int UpPropRotation = 1 << 1;
1123 private int UpPropVelocity = 1 << 2;
1124 private int UpPropAcceleration = 1 << 3;
1125 private int UpPropAngularVel = 1 << 4;
1126
1127 public void UpdateProperties(EntityProperties entprop)
1128 {
1129 int changed = 0;
1130 // assign to the local variables so the normal set action does not happen
1131 if (_position != entprop.Position)
1132 {
1133 _position = entprop.Position;
1134 // m_log.DebugFormat("{0}: UpdateProperties: position = {1}", LogHeader, _position);
1135 changed |= UpPropPosition;
1136 }
1137 if (_orientation != entprop.Rotation)
1138 {
1139 _orientation = entprop.Rotation;
1140 // m_log.DebugFormat("{0}: UpdateProperties: rotation = {1}", LogHeader, _orientation);
1141 changed |= UpPropRotation;
1142 }
1143 if (_velocity != entprop.Velocity)
1144 {
1145 _velocity = entprop.Velocity;
1146 // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity);
1147 changed |= UpPropVelocity;
1148 }
1149 if (_acceleration != entprop.Acceleration)
1150 {
1151 _acceleration = entprop.Acceleration;
1152 // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration);
1153 changed |= UpPropAcceleration;
1154 }
1155 if (_rotationalVelocity != entprop.AngularVelocity)
1156 {
1157 _rotationalVelocity = entprop.AngularVelocity;
1158 // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity);
1159 changed |= UpPropAngularVel;
1160 }
1161 if (changed != 0)
1162 {
1163 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1164 base.RequestPhysicsterseUpdate();
1165 }
1166 }
1167
1168 // I've collided with something
1169 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1170 {
1171 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
1172 // The following makes IsColliding() and IsCollidingGround() work
1173 _collidingStep = _scene.SimulationStep;
1174 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
1175 {
1176 _collidingGroundStep = _scene.SimulationStep;
1177 }
1178
1179 if (_subscribedEventsMs == 0) return; // nothing in the object is waiting for collision events
1180 // throttle the collisions to the number of milliseconds specified in the subscription
1181 int nowTime = Util.EnvironmentTickCount();
1182 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
1183 _lastCollisionTime = nowTime;
1184
1185 // create the event for the collision
1186 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
1187 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1188 CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
1189 base.SendCollisionUpdate(args);
1190 }
1191}
1192}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
new file mode 100644
index 0000000..beffd21
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -0,0 +1,553 @@
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// Fix folding up feet
41// Fix terrain. Only flat terrain works. Terrain with shape is oriented wrong? Origined wrong?
42// Parameterize BulletSim. Pass a structure of parameters to the C++ code. Capsule size, friction, ...
43// Shift drag duplication of objects does not work
44// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
45// Test sculpties
46// Compute physics FPS reasonably
47// Based on material, set density and friction
48// More efficient memory usage in passing hull information from BSPrim to BulletSim
49// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
50// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
51// At the moment, physical and phantom causes object to drop through the terrain
52// Should prim.link() and prim.delink() membership checking happen at taint time?
53// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
54// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
55// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
56// Implement LockAngularMotion
57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
58// Built Galton board (lots of MoveTo's) and some slats were not positioned correctly (mistakes scattered)
59// No mistakes with ODE. Shape creation race condition?
60// Does NeedsMeshing() really need to exclude all the different shapes?
61//
62namespace OpenSim.Region.Physics.BulletSPlugin
63{
64public class BSScene : PhysicsScene
65{
66 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
67 private static readonly string LogHeader = "[BULLETS SCENE]";
68
69 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
70 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>();
71 private List<BSPrim> m_vehicles = new List<BSPrim>();
72 private float[] m_heightMap;
73 private float m_waterLevel;
74 private uint m_worldID;
75 public uint WorldID { get { return m_worldID; } }
76
77 public IMesher mesher;
78 public int meshLOD = 32;
79
80 private int m_maxSubSteps = 10;
81 private float m_fixedTimeStep = 1f / 60f;
82 private long m_simulationStep = 0;
83 public long SimulationStep { get { return m_simulationStep; } }
84
85 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed
86 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes
87 public float maximumMassObject = 10000.01f;
88
89 public const uint TERRAIN_ID = 0;
90 public const uint GROUNDPLANE_ID = 1;
91
92 public float DefaultFriction = 0.70f;
93 public float DefaultDensity = 10.000006836f; // Aluminum g/cm3; TODO: compute based on object material
94 public Vector3 DefaultGravity = new Vector3(0, 0, -9.80665f);
95
96 public delegate void TaintCallback();
97 private List<TaintCallback> _taintedObjects;
98 private Object _taintLock = new Object();
99
100 private BulletSimAPI.DebugLogCallback debugLogCallbackHandle;
101
102 public BSScene(string identifier)
103 {
104 }
105
106 public override void Initialise(IMesher meshmerizer, IConfigSource config)
107 {
108 if (config != null)
109 {
110 IConfig pConfig = config.Configs["BulletSim"];
111 if (pConfig != null)
112 {
113 DefaultFriction = pConfig.GetFloat("Friction", DefaultFriction);
114 DefaultDensity = pConfig.GetFloat("Density", DefaultDensity);
115 // TODO: a lot more parameters that are passed to BulletSim
116 }
117 }
118 // if Debug, enable logging from the unmanaged code
119 if (m_log.IsDebugEnabled)
120 {
121 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
122 debugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
123 BulletSimAPI.SetDebugLogCallback(debugLogCallbackHandle);
124 }
125
126 _meshSculptedPrim = true; // mesh sculpted prims
127 _forceSimplePrimMeshing = false; // use complex meshing if called for
128
129 _taintedObjects = new List<TaintCallback>();
130
131 mesher = meshmerizer;
132 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
133 m_worldID = BulletSimAPI.Initialize(new Vector3(Constants.RegionSize, Constants.RegionSize, 4096f));
134 }
135
136 // Called directly from unmanaged code so don't do much
137 private void BulletLogger(string msg)
138 {
139 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
140 }
141
142 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
143 {
144 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
145 return null;
146 }
147
148 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 size, bool isFlying)
149 {
150 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
151 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
152 lock (m_avatars) m_avatars.Add(localID, actor);
153 return actor;
154 }
155
156 public override void RemoveAvatar(PhysicsActor actor)
157 {
158 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
159 if (actor is BSCharacter)
160 {
161 ((BSCharacter)actor).Destroy();
162 }
163 try
164 {
165 lock (m_avatars) m_avatars.Remove(actor.LocalID);
166 }
167 catch (Exception e)
168 {
169 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
170 }
171 }
172
173 public override void RemovePrim(PhysicsActor prim)
174 {
175 // m_log.DebugFormat("{0}: RemovePrim", LogHeader);
176 if (prim is BSPrim)
177 {
178 ((BSPrim)prim).Destroy();
179 }
180 try
181 {
182 lock (m_prims) m_prims.Remove(prim.LocalID);
183 }
184 catch (Exception e)
185 {
186 m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
187 }
188 }
189
190 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
191 Vector3 size, Quaternion rotation) // deprecated
192 {
193 return null;
194 }
195 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
196 Vector3 size, Quaternion rotation, bool isPhysical)
197 {
198 m_log.ErrorFormat("{0}: CALL TO AddPrimShape in BSScene. NOT IMPLEMENTED", LogHeader);
199 return null;
200 }
201
202 public override PhysicsActor AddPrimShape(uint localID, string primName, PrimitiveBaseShape pbs, Vector3 position,
203 Vector3 size, Quaternion rotation, bool isPhysical)
204 {
205 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
206 IMesh mesh = null;
207 if (NeedsMeshing(pbs))
208 {
209 // if the prim is complex, create the mesh for it.
210 // If simple (box or sphere) leave 'mesh' null and physics will do a native shape.
211 mesh = mesher.CreateMesh(primName, pbs, size, this.meshLOD, isPhysical);
212 }
213 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, mesh, pbs, isPhysical);
214 lock (m_prims) m_prims.Add(localID, prim);
215 return prim;
216 }
217
218 // This is a call from the simulator saying that some physical property has been updated.
219 // The BulletS driver senses the changing of relevant properties so this taint
220 // information call is not needed.
221 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
222
223 // Simulate one timestep
224 public override float Simulate(float timeStep)
225 {
226 int updatedEntityCount;
227 IntPtr updatedEntitiesPtr;
228 IntPtr[] updatedEntities;
229 int collidersCount;
230 IntPtr collidersPtr;
231 int[] colliders; // should be uint but Marshal.Copy does not have that overload
232
233 // update the prim states while we know the physics engine is not busy
234 ProcessTaints();
235
236 // Some of the prims operate with special vehicle properties
237 ProcessVehicles(timeStep);
238 ProcessTaints(); // the vehicles might have added taints
239
240 // step the physical world one interval
241 m_simulationStep++;
242 int numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
243 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
244
245 // if there were collisions, they show up here
246 if (collidersCount > 0)
247 {
248 colliders = new int[collidersCount];
249 Marshal.Copy(collidersPtr, colliders, 0, collidersCount);
250 for (int ii = 0; ii < collidersCount; ii+=2)
251 {
252 uint cA = (uint)colliders[ii];
253 uint cB = (uint)colliders[ii+1];
254 SendCollision(cA, cB);
255 SendCollision(cB, cA);
256 }
257 }
258
259 // if any of the objects had updated properties, they are returned in the updatedEntity structure
260 // TODO: figure out how to pass all of the EntityProperties structures in one marshal call.
261 if (updatedEntityCount > 0)
262 {
263 updatedEntities = new IntPtr[updatedEntityCount];
264 // fetch all the pointers to all the EntityProperties structures for these updates
265 Marshal.Copy(updatedEntitiesPtr, updatedEntities, 0, updatedEntityCount);
266 for (int ii = 0; ii < updatedEntityCount; ii++)
267 {
268 IntPtr updatePointer = updatedEntities[ii];
269 EntityProperties entprop = (EntityProperties)Marshal.PtrToStructure(updatePointer, typeof(EntityProperties));
270 // m_log.DebugFormat("{0}: entprop: id={1}, pos={2}", LogHeader, entprop.ID, entprop.Position);
271 BSCharacter actor;
272 if (m_avatars.TryGetValue(entprop.ID, out actor))
273 {
274 actor.UpdateProperties(entprop);
275 continue;
276 }
277 BSPrim prim;
278 if (m_prims.TryGetValue(entprop.ID, out prim))
279 {
280 prim.UpdateProperties(entprop);
281 }
282 }
283 }
284
285 // fps calculation wrong. This calculation returns about 1 in normal operation.
286 return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f;
287 }
288
289 // Something has collided
290 private void SendCollision(uint localID, uint collidingWith)
291 {
292 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID)
293 {
294 // we never send collisions to the terrain
295 return;
296 }
297
298 ActorTypes type = ActorTypes.Prim;
299 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID)
300 type = ActorTypes.Ground;
301 else if (m_avatars.ContainsKey(collidingWith))
302 type = ActorTypes.Agent;
303
304 BSPrim prim;
305 if (m_prims.TryGetValue(localID, out prim)) {
306 prim.Collide(collidingWith, type, Vector3.Zero, Vector3.UnitZ, 0.01f);
307 return;
308 }
309 BSCharacter actor;
310 if (m_avatars.TryGetValue(localID, out actor)) {
311 actor.Collide(collidingWith, type, Vector3.Zero, Vector3.UnitZ, 0.01f);
312 return;
313 }
314 return;
315 }
316
317 public override void GetResults() { }
318
319 public override void SetTerrain(float[] heightMap) {
320 m_log.DebugFormat("{0}: SetTerrain", LogHeader);
321 m_heightMap = heightMap;
322 this.TaintedObject(delegate()
323 {
324 BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
325 });
326 }
327
328 public float GetTerrainHeightAtXY(float tX, float tY)
329 {
330 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
331 }
332
333 public override void SetWaterLevel(float baseheight)
334 {
335 m_waterLevel = baseheight;
336 }
337 public float GetWaterLevel()
338 {
339 return m_waterLevel;
340 }
341
342 public override void DeleteTerrain()
343 {
344 m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
345 }
346
347 public override void Dispose()
348 {
349 m_log.DebugFormat("{0}: Dispose()", LogHeader);
350 }
351
352 public override Dictionary<uint, float> GetTopColliders()
353 {
354 return new Dictionary<uint, float>();
355 }
356
357 public override bool IsThreaded { get { return false; } }
358
359 /// <summary>
360 /// Routine to figure out if we need to mesh this prim with our mesher
361 /// </summary>
362 /// <param name="pbs"></param>
363 /// <returns>true if the prim needs meshing</returns>
364 public bool NeedsMeshing(PrimitiveBaseShape pbs)
365 {
366 // most of this is redundant now as the mesher will return null if it cant mesh a prim
367 // but we still need to check for sculptie meshing being enabled so this is the most
368 // convenient place to do it for now...
369
370 // int iPropertiesNotSupportedDefault = 0;
371
372 if (pbs.SculptEntry && !_meshSculptedPrim)
373 {
374 // m_log.DebugFormat("{0}: NeedsMeshing: scultpy mesh", LogHeader);
375 return false;
376 }
377
378 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet
379 // can use an internal representation for the prim
380 if (!_forceSimplePrimMeshing)
381 {
382 // m_log.DebugFormat("{0}: NeedsMeshing: simple mesh: profshape={1}, curve={2}", LogHeader, pbs.ProfileShape, pbs.PathCurve);
383 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
384 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1
385 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z))
386 {
387
388 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
389 && pbs.ProfileHollow == 0
390 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
391 && pbs.PathBegin == 0 && pbs.PathEnd == 0
392 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
393 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
394 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
395 {
396 return false;
397 }
398 }
399 }
400
401 /* TODO: verify that the mesher will now do all these shapes
402 if (pbs.ProfileHollow != 0)
403 iPropertiesNotSupportedDefault++;
404
405 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
406 iPropertiesNotSupportedDefault++;
407
408 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
409 iPropertiesNotSupportedDefault++;
410
411 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
412 iPropertiesNotSupportedDefault++;
413
414 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
415 iPropertiesNotSupportedDefault++;
416
417 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
418 iPropertiesNotSupportedDefault++;
419
420 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
421 iPropertiesNotSupportedDefault++;
422
423 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))
424 iPropertiesNotSupportedDefault++;
425
426 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
427 iPropertiesNotSupportedDefault++;
428
429 // test for torus
430 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
431 {
432 if (pbs.PathCurve == (byte)Extrusion.Curve1)
433 {
434 iPropertiesNotSupportedDefault++;
435 }
436 }
437 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
438 {
439 if (pbs.PathCurve == (byte)Extrusion.Straight)
440 {
441 iPropertiesNotSupportedDefault++;
442 }
443 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
444 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
445 {
446 iPropertiesNotSupportedDefault++;
447 }
448 }
449 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
450 {
451 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2)
452 {
453 iPropertiesNotSupportedDefault++;
454 }
455 }
456 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
457 {
458 if (pbs.PathCurve == (byte)Extrusion.Straight)
459 {
460 iPropertiesNotSupportedDefault++;
461 }
462 else if (pbs.PathCurve == (byte)Extrusion.Curve1)
463 {
464 iPropertiesNotSupportedDefault++;
465 }
466 }
467 if (iPropertiesNotSupportedDefault == 0)
468 {
469 return false;
470 }
471 */
472 return true;
473 }
474
475 // The calls to the PhysicsActors can't directly call into the physics engine
476 // because it might be busy. We we delay changes to a known time.
477 // We rely on C#'s closure to save and restore the context for the delegate.
478 public void TaintedObject(TaintCallback callback)
479 {
480 lock (_taintLock)
481 _taintedObjects.Add(callback);
482 return;
483 }
484
485 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
486 // a callback into itself to do the actual property change. That callback is called
487 // here just before the physics engine is called to step the simulation.
488 public void ProcessTaints()
489 {
490 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
491 {
492 // swizzle a new list into the list location so we can process what's there
493 List<TaintCallback> oldList;
494 lock (_taintLock)
495 {
496 oldList = _taintedObjects;
497 _taintedObjects = new List<TaintCallback>();
498 }
499
500 foreach (TaintCallback callback in oldList)
501 {
502 try
503 {
504 callback();
505 }
506 catch (Exception e)
507 {
508 m_log.ErrorFormat("{0}: ProcessTaints: Exception: {1}", LogHeader, e);
509 }
510 }
511 oldList.Clear();
512 }
513 }
514
515 #region Vehicles
516 // Make so the scene will call this prim for vehicle actions each tick.
517 // Safe to call if prim is already in the vehicle list.
518 public void AddVehiclePrim(BSPrim vehicle)
519 {
520 lock (m_vehicles)
521 {
522 if (!m_vehicles.Contains(vehicle))
523 {
524 m_vehicles.Add(vehicle);
525 }
526 }
527 }
528
529 // Remove a prim from our list of vehicles.
530 // Safe to call if the prim is not in the vehicle list.
531 public void RemoveVehiclePrim(BSPrim vehicle)
532 {
533 lock (m_vehicles)
534 {
535 if (m_vehicles.Contains(vehicle))
536 {
537 m_vehicles.Remove(vehicle);
538 }
539 }
540 }
541
542 // Some prims have extra vehicle actions
543 // no locking because only called when physics engine is not busy
544 private void ProcessVehicles(float timeStep)
545 {
546 foreach (BSPrim prim in m_vehicles)
547 {
548 prim.StepVehicle(timeStep);
549 }
550 }
551 #endregion Vehicles
552}
553}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
new file mode 100644
index 0000000..b2bc0d7
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -0,0 +1,186 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above 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
35public struct ConvexHull
36{
37 Vector3 Offset;
38 int VertexCount;
39 Vector3[] Vertices;
40}
41public struct ShapeData
42{
43 public enum PhysicsShapeType
44 {
45 SHAPE_AVATAR = 0,
46 SHAPE_BOX = 1,
47 SHAPE_CONE = 2,
48 SHAPE_CYLINDER = 3,
49 SHAPE_SPHERE = 4,
50 SHAPE_HULL = 5
51 };
52 public const int numericTrue = 1;
53 public const int numericFalse = 0;
54 public uint ID;
55 public PhysicsShapeType Type;
56 public Vector3 Position;
57 public Quaternion Rotation;
58 public Vector3 Velocity;
59 public Vector3 Scale;
60 public float Mass;
61 public float Buoyancy;
62 public System.UInt64 MeshKey;
63 public int Collidable;
64 public float Friction;
65 public int Static; // true if a static object. Otherwise gravity, etc.
66 // note that bools are passed as ints since bool size changes by language
67}
68public struct SweepHit
69{
70 public uint ID;
71 public float Fraction;
72 public Vector3 Normal;
73 public Vector3 Point;
74}
75public struct RaycastHit
76{
77 public uint ID;
78 public float Fraction;
79 public Vector3 Normal;
80}
81
82public struct EntityProperties
83{
84 public uint ID;
85 public Vector3 Position;
86 public Quaternion Rotation;
87 public Vector3 Velocity;
88 public Vector3 Acceleration;
89 public Vector3 AngularVelocity;
90}
91
92static class BulletSimAPI {
93
94[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
95public static extern uint Initialize(Vector3 maxPosition);
96
97[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
98public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
99
100[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
101public static extern void Shutdown(uint worldID);
102
103
104[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
105public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
106 out int updatedEntityCount,
107 out IntPtr updatedEntitiesPtr,
108 out int collidersCount,
109 out IntPtr collidersPtr);
110
111[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
112public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, int hullCount,
113 [MarshalAs(UnmanagedType.LPArray)] float[] hulls
114 );
115
116[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
117public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey);
118
119[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
120public static extern bool CreateObject(uint worldID, ShapeData shapeData);
121
122[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
123public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
124
125[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
126public static extern void AddConstraint(uint worldID, uint id1, uint id2,
127 Vector3 frame1, Vector3 frame2, Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
128
129[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
130public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
131
132[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
133public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
134
135[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
136public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
137
138[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
139public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity);
140
141[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
142public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
143
144[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
145public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
146
147[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
148public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic);
149
150[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
151public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom);
152
153[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
154public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass);
155
156[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
157public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly);
158
159[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
160public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass);
161
162[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
163public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy);
164
165[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
166public static extern bool HasObject(uint worldID, uint id);
167
168[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
169public static extern bool DestroyObject(uint worldID, uint id);
170
171[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
172public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
173
174[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
175public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to);
176
177[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
178public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
179
180// Log a debug message
181[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
182public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
183[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
184public static extern void SetDebugLogCallback(DebugLogCallback callback);
185}
186}