aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs
diff options
context:
space:
mode:
authorteravus2012-12-23 15:21:25 -0500
committerteravus2012-12-23 15:21:25 -0500
commit92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf (patch)
treeeabcbb758a7512222e84cb51b51b6822cdbf561b /OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs
parentRevert "Whitespace change to trigger bot" (diff)
downloadopensim-SC_OLD-92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf.zip
opensim-SC_OLD-92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf.tar.gz
opensim-SC_OLD-92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf.tar.bz2
opensim-SC_OLD-92e4f9f412046f8f7926c99c9e56c3a8b6b2edbf.tar.xz
* Initial commit of BulletSimN (BulletSNPlugin). Purely C# implementation of BulletSim. This is designed to be /as close as possible/ to the BulletSim plugin while still being entirely in the managed space to make keeping it up to date easy as possible (no thinking work). This implementation is /slower/ then the c++ version just because it's fully managed, so it's not appropriate for huge sims, but it will run small ones OK. At the moment, it supports all known features of BulletSim. Think of it like.. POS but everything works. To use this plugin, set the physics plugin to BulletSimN.
Diffstat (limited to 'OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs345
1 files changed, 345 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs
new file mode 100644
index 0000000..4096ef8
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSPhysObject.cs
@@ -0,0 +1,345 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSNPlugin
36{
37/*
38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant.
41 *
42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time.
47 */
48
49/*
50 * As of 20121221, the following are the call sequences (going down) for different script physical functions:
51 * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque
56 */
57
58public abstract class BSPhysObject : PhysicsActor
59{
60 protected BSPhysObject()
61 {
62 }
63 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
64 {
65 PhysicsScene = parentScene;
66 LocalID = localID;
67 PhysObjectName = name;
68 TypeName = typeName;
69
70 Linkset = BSLinkset.Factory(PhysicsScene, this);
71 LastAssetBuildFailed = false;
72
73 // Default material type
74 Material = MaterialAttributes.Material.Wood;
75
76 CollisionCollection = new CollisionEventUpdate();
77 SubscribedEventsMs = 0;
78 CollidingStep = 0;
79 CollidingGroundStep = 0;
80 }
81
82 // Tell the object to clean up.
83 public virtual void Destroy()
84 {
85 UnRegisterAllPreStepActions();
86 }
87
88 public BSScene PhysicsScene { get; protected set; }
89 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
90 public string PhysObjectName { get; protected set; }
91 public string TypeName { get; protected set; }
92
93 public BSLinkset Linkset { get; set; }
94 public BSLinksetInfo LinksetInfo { get; set; }
95
96 // Return the object mass without calculating it or having side effects
97 public abstract float RawMass { get; }
98 // Set the raw mass but also update physical mass properties (inertia, ...)
99 public abstract void UpdatePhysicalMassProperties(float mass);
100
101 // The last value calculated for the prim's inertia
102 public OMV.Vector3 Inertia { get; set; }
103
104 // Reference to the physical body (btCollisionObject) of this object
105 public BulletBody PhysBody;
106 // Reference to the physical shape (btCollisionShape) of this object
107 public BulletShape PhysShape;
108
109 // 'true' if the mesh's underlying asset failed to build.
110 // This will keep us from looping after the first time the build failed.
111 public bool LastAssetBuildFailed { get; set; }
112
113 // The objects base shape information. Null if not a prim type shape.
114 public PrimitiveBaseShape BaseShape { get; protected set; }
115 // Some types of objects have preferred physical representations.
116 // Returns SHAPE_UNKNOWN if there is no preference.
117 public virtual BSPhysicsShapeType PreferredPhysicalShape
118 {
119 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
120 }
121
122 // When the physical properties are updated, an EntityProperty holds the update values.
123 // Keep the current and last EntityProperties to enable computation of differences
124 // between the current update and the previous values.
125 public EntityProperties CurrentEntityProperties { get; set; }
126 public EntityProperties LastEntityProperties { get; set; }
127
128 public virtual OMV.Vector3 Scale { get; set; }
129 public abstract bool IsSolid { get; }
130 public abstract bool IsStatic { get; }
131
132 // Materialness
133 public MaterialAttributes.Material Material { get; private set; }
134 public override void SetMaterial(int material)
135 {
136 Material = (MaterialAttributes.Material)material;
137 }
138
139 // Stop all physical motion.
140 public abstract void ZeroMotion(bool inTaintTime);
141 public abstract void ZeroAngularMotion(bool inTaintTime);
142
143 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
144 public virtual void StepVehicle(float timeStep) { }
145
146 // Update the physical location and motion of the object. Called with data from Bullet.
147 public abstract void UpdateProperties(EntityProperties entprop);
148
149 public abstract OMV.Vector3 RawPosition { get; set; }
150 public abstract OMV.Vector3 ForcePosition { get; set; }
151
152 public abstract OMV.Quaternion RawOrientation { get; set; }
153 public abstract OMV.Quaternion ForceOrientation { get; set; }
154
155 // The system is telling us the velocity it wants to move at.
156 // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
157 public override OMV.Vector3 TargetVelocity
158 {
159 get { return m_targetVelocity; }
160 set
161 {
162 m_targetVelocity = value;
163 Velocity = value;
164 }
165 }
166 public abstract OMV.Vector3 ForceVelocity { get; set; }
167
168 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
169
170 public abstract float ForceBuoyancy { get; set; }
171
172 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
173
174 #region Collisions
175
176 // Requested number of milliseconds between collision events. Zero means disabled.
177 protected int SubscribedEventsMs { get; set; }
178 // Given subscription, the time that a collision may be passed up
179 protected int NextCollisionOkTime { get; set; }
180 // The simulation step that last had a collision
181 protected long CollidingStep { get; set; }
182 // The simulation step that last had a collision with the ground
183 protected long CollidingGroundStep { get; set; }
184 // The collision flags we think are set in Bullet
185 protected CollisionFlags CurrentCollisionFlags { get; set; }
186
187 // The collisions that have been collected this tick
188 protected CollisionEventUpdate CollisionCollection;
189
190 // The simulation step is telling this object about a collision.
191 // Return 'true' if a collision was processed and should be sent up.
192 // Called at taint time from within the Step() function
193 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
194 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
195 {
196 bool ret = false;
197
198 // The following lines make IsColliding() and IsCollidingGround() work
199 CollidingStep = PhysicsScene.SimulationStep;
200 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
201 {
202 CollidingGroundStep = PhysicsScene.SimulationStep;
203 }
204
205 // prims in the same linkset cannot collide with each other
206 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
207 {
208 return ret;
209 }
210
211 // if someone has subscribed for collision events....
212 if (SubscribedEvents()) {
213 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
214 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
215 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
216
217 ret = true;
218 }
219 return ret;
220 }
221
222 // Send the collected collisions into the simulator.
223 // Called at taint time from within the Step() function thus no locking problems
224 // with CollisionCollection and ObjectsWithNoMoreCollisions.
225 // Return 'true' if there were some actual collisions passed up
226 public virtual bool SendCollisions()
227 {
228 bool ret = true;
229 // If the 'no collision' call, force it to happen right now so quick collision_end
230 bool force = (CollisionCollection.Count == 0);
231
232 // throttle the collisions to the number of milliseconds specified in the subscription
233 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
234 {
235 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
236
237 // We are called if we previously had collisions. If there are no collisions
238 // this time, send up one last empty event so OpenSim can sense collision end.
239 if (CollisionCollection.Count == 0)
240 {
241 // If I have no collisions this time, remove me from the list of objects with collisions.
242 ret = false;
243 }
244
245 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
246 base.SendCollisionUpdate(CollisionCollection);
247
248 // The CollisionCollection instance is passed around in the simulator.
249 // Make sure we don't have a handle to that one and that a new one is used for next time.
250 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
251 // a race condition is created for the other users of this instance.
252 CollisionCollection = new CollisionEventUpdate();
253 }
254 return ret;
255 }
256
257 // Subscribe for collision events.
258 // Parameter is the millisecond rate the caller wishes collision events to occur.
259 public override void SubscribeEvents(int ms) {
260 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
261 SubscribedEventsMs = ms;
262 if (ms > 0)
263 {
264 // make sure first collision happens
265 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
266
267 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
268 {
269 if (PhysBody.HasPhysicalBody)
270 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
271 });
272 }
273 else
274 {
275 // Subscribing for zero or less is the same as unsubscribing
276 UnSubscribeEvents();
277 }
278 }
279 public override void UnSubscribeEvents() {
280 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
281 SubscribedEventsMs = 0;
282 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
283 {
284 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
285 if (PhysBody.HasPhysicalBody)
286 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
287 });
288 }
289 // Return 'true' if the simulator wants collision events
290 public override bool SubscribedEvents() {
291 return (SubscribedEventsMs > 0);
292 }
293
294 #endregion // Collisions
295
296 #region Per Simulation Step actions
297 // There are some actions that must be performed for a physical object before each simulation step.
298 // These actions are optional so, rather than scanning all the physical objects and asking them
299 // if they have anything to do, a physical object registers for an event call before the step is performed.
300 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
301 private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
302 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
303 {
304 string identifier = op + "-" + id.ToString();
305 RegisteredActions[identifier] = actn;
306 PhysicsScene.BeforeStep += actn;
307 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
308 }
309
310 // Unregister a pre step action. Safe to call if the action has not been registered.
311 protected void UnRegisterPreStepAction(string op, uint id)
312 {
313 string identifier = op + "-" + id.ToString();
314 bool removed = false;
315 if (RegisteredActions.ContainsKey(identifier))
316 {
317 PhysicsScene.BeforeStep -= RegisteredActions[identifier];
318 RegisteredActions.Remove(identifier);
319 removed = true;
320 }
321 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
322 }
323
324 protected void UnRegisterAllPreStepActions()
325 {
326 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
327 {
328 PhysicsScene.BeforeStep -= kvp.Value;
329 }
330 RegisteredActions.Clear();
331 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
332 }
333
334
335 #endregion // Per Simulation Step actions
336
337 // High performance detailed logging routine used by the physical objects.
338 protected void DetailLog(string msg, params Object[] args)
339 {
340 if (PhysicsScene.PhysicsLogging.Enabled)
341 PhysicsScene.DetailLog(msg, args);
342 }
343
344}
345}