diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 426 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 951 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs | 68 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 1192 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 553 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | 186 |
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 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public 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 | |||
44 | using System; | ||
45 | using System.Collections.Generic; | ||
46 | using System.Reflection; | ||
47 | using System.Runtime.InteropServices; | ||
48 | using log4net; | ||
49 | using OpenMetaverse; | ||
50 | using OpenSim.Framework; | ||
51 | using OpenSim.Region.Physics.Manager; | ||
52 | |||
53 | namespace 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 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using OpenSim.Framework; | ||
30 | using OpenSim.Region.Physics.Manager; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | public 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 | */ | ||
27 | using System; | ||
28 | using System.Reflection; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Xml; | ||
31 | using log4net; | ||
32 | using OMV = OpenMetaverse; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Physics.Manager; | ||
35 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | [Serializable] | ||
40 | public 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 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Runtime.InteropServices; | ||
30 | using System.Text; | ||
31 | using System.Threading; | ||
32 | using Nini.Config; | ||
33 | using log4net; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.Physics.Manager; | ||
36 | using OpenMetaverse; | ||
37 | using 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 | // | ||
62 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
63 | { | ||
64 | public 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 | */ | ||
27 | using System; | ||
28 | using System.Runtime.InteropServices; | ||
29 | using System.Security; | ||
30 | using System.Text; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin { | ||
34 | |||
35 | public struct ConvexHull | ||
36 | { | ||
37 | Vector3 Offset; | ||
38 | int VertexCount; | ||
39 | Vector3[] Vertices; | ||
40 | } | ||
41 | public 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 | } | ||
68 | public struct SweepHit | ||
69 | { | ||
70 | public uint ID; | ||
71 | public float Fraction; | ||
72 | public Vector3 Normal; | ||
73 | public Vector3 Point; | ||
74 | } | ||
75 | public struct RaycastHit | ||
76 | { | ||
77 | public uint ID; | ||
78 | public float Fraction; | ||
79 | public Vector3 Normal; | ||
80 | } | ||
81 | |||
82 | public 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 | |||
92 | static class BulletSimAPI { | ||
93 | |||
94 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
95 | public static extern uint Initialize(Vector3 maxPosition); | ||
96 | |||
97 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
98 | public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); | ||
99 | |||
100 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
101 | public static extern void Shutdown(uint worldID); | ||
102 | |||
103 | |||
104 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
105 | public 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] | ||
112 | public 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] | ||
117 | public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey); | ||
118 | |||
119 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
120 | public static extern bool CreateObject(uint worldID, ShapeData shapeData); | ||
121 | |||
122 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
123 | public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas); | ||
124 | |||
125 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
126 | public 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] | ||
130 | public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2); | ||
131 | |||
132 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
133 | public static extern Vector3 GetObjectPosition(uint WorldID, uint id); | ||
134 | |||
135 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
136 | public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); | ||
137 | |||
138 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
139 | public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity); | ||
140 | |||
141 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
142 | public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); | ||
143 | |||
144 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
145 | public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); | ||
146 | |||
147 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
148 | public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic); | ||
149 | |||
150 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
151 | public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom); | ||
152 | |||
153 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
154 | public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass); | ||
155 | |||
156 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
157 | public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly); | ||
158 | |||
159 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
160 | public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass); | ||
161 | |||
162 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
163 | public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy); | ||
164 | |||
165 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
166 | public static extern bool HasObject(uint worldID, uint id); | ||
167 | |||
168 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
169 | public static extern bool DestroyObject(uint worldID, uint id); | ||
170 | |||
171 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
172 | public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin); | ||
173 | |||
174 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
175 | public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to); | ||
176 | |||
177 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
178 | public static extern Vector3 RecoverFromPenetration(uint worldID, uint id); | ||
179 | |||
180 | // Log a debug message | ||
181 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | ||
182 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | ||
183 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
184 | public static extern void SetDebugLogCallback(DebugLogCallback callback); | ||
185 | } | ||
186 | } | ||