From ee7cda261cbbc9dcd558c35eabc070cc0bf45644 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Tue, 18 Sep 2012 08:39:52 -0700 Subject: BulletSim: move a bunch of common logic out of BSPrim and BSCharacter and into the parent class BSPhysObject. Rework collision logic to enable extra collision after done colliding. Rename 'Scene' to 'PhysicsScene' to differentiate it from the simulator 'Scene'. --- .../Region/Physics/BulletSPlugin/BSPhysObject.cs | 138 +++++++++++++++++++-- 1 file changed, 131 insertions(+), 7 deletions(-) (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 3fe71e1..242aa80 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -39,26 +39,150 @@ namespace OpenSim.Region.Physics.BulletSPlugin // unless the difference is significant. public abstract class BSPhysObject : PhysicsActor { - public abstract BSLinkset Linkset { get; set; } + protected void BaseInitialize(BSScene parentScene) + { + PhysicsScene = parentScene; + Linkset = new BSLinkset(PhysicsScene, this); - public abstract bool Collide(uint collidingWith, BSPhysObject collidee, - OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); - public abstract void SendCollisions(); + CollisionCollection = new CollisionEventUpdate(); + SubscribedEventsMs = 0; + CollidingStep = 0; + CollidingGroundStep = 0; + } - // Return the object mass without calculating it or side effects + public BSScene PhysicsScene { get; protected set; } + + public BSLinkset Linkset { get; set; } + + // Return the object mass without calculating it or having side effects public abstract float MassRaw { get; } // Reference to the physical body (btCollisionObject) of this object - public abstract BulletBody BSBody { get; set; } + public BulletBody BSBody { get; protected set; } // Reference to the physical shape (btCollisionShape) of this object - public abstract BulletShape BSShape { get; set; } + public BulletShape BSShape { get; protected set; } + // Stop all physical motion. public abstract void ZeroMotion(); + // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. public virtual void StepVehicle(float timeStep) { } + // Update the physical location and motion of the object. Called with data from Bullet. public abstract void UpdateProperties(EntityProperties entprop); + // Tell the object to clean up. public abstract void Destroy(); + + #region Collisions + + // Requested number of milliseconds between collision events. Zero means disabled. + protected int SubscribedEventsMs { get; set; } + // Given subscription, the time that a collision may be passed up + protected int NextCollisionOkTime { get; set; } + // The simulation step that last had a collision + protected long CollidingStep { get; set; } + // The simulation step that last had a collision with the ground + protected long CollidingGroundStep { get; set; } + // The collision flags we think are set in Bullet + protected CollisionFlags CurrentCollisionFlags { get; set; } + + // The collisions that have been collected this tick + protected CollisionEventUpdate CollisionCollection; + + // The simulation step is telling this object about a collision. + // Return 'true' if a collision was processed and should be sent up. + // Called at taint time from within the Step() function + public virtual bool Collide(uint collidingWith, BSPhysObject collidee, + OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) + { + bool ret = false; + + // The following lines make IsColliding() and IsCollidingGround() work + CollidingStep = PhysicsScene.SimulationStep; + if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) + { + CollidingGroundStep = PhysicsScene.SimulationStep; + } + + // prims in the same linkset cannot collide with each other + if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) + { + return ret; + } + + PhysicsScene.PhysicsLogging.Write("{0},BSPhysObject.Collison,call,with={1}", LocalID, collidingWith); + + // if someone has subscribed for collision events.... + if (SubscribedEvents()) { + CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); + PhysicsScene.PhysicsLogging.Write("{0},BSPhysObject.Collison.AddCollider,call,with={1},point={2},normal={3},depth={4},next={5}", + LocalID, collidingWith, contactPoint, contactNormal, pentrationDepth, NextCollisionOkTime.ToString("yyyyMMddHHmmssfff")); + ret = true; + } + return ret; + } + + // Routine to send the collected collisions into the simulator. + // Also handles removal of this from the collection of objects with collisions if + // there are no collisions from this object. Mechanism is create one last + // collision event to make collision_end work. + public virtual void SendCollisions() + { + // throttle the collisions to the number of milliseconds specified in the subscription + int nowTime = PhysicsScene.SimulationNowTime; + if (nowTime >= NextCollisionOkTime) + { + NextCollisionOkTime = nowTime + SubscribedEventsMs; + + // We are called if we previously had collisions. If there are no collisions + // this time, send up one last empty event so OpenSim can sense collision end. + if (CollisionCollection.Count == 0) + PhysicsScene.ObjectsWithNoMoreCollisions.Add(this); + + base.SendCollisionUpdate(CollisionCollection); + + // The collisionCollection structure is passed around in the simulator. + // Make sure we don't have a handle to that one and that a new one is used next time. + CollisionCollection = new CollisionEventUpdate(); + } + } + + // Subscribe for collision events. + // Parameter is the millisecond rate the caller wishes collision events to occur. + public override void SubscribeEvents(int ms) { + SubscribedEventsMs = ms; + if (ms > 0) + { + // make sure first collision happens + NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); + PhysicsScene.PhysicsLogging.Write("{0},SubscribeEvents,call,ms={1},nextOKTime={2}", + LocalID, SubscribedEventsMs, NextCollisionOkTime.ToString("yyyyMMddHHmmssfff")); + + PhysicsScene.TaintedObject("BSPhysObject.SubscribeEvents", delegate() + { + CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + }); + } + else + { + // Subscribing for zero or less is the same as unsubscribing + UnSubscribeEvents(); + } + } + public override void UnSubscribeEvents() { + SubscribedEventsMs = 0; + PhysicsScene.PhysicsLogging.Write("{0},UnSubscribeEvents,call", LocalID); + PhysicsScene.TaintedObject("BSPhysObject.UnSubscribeEvents", delegate() + { + CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + }); + } + // Return 'true' if the simulator wants collision events + public override bool SubscribedEvents() { + return (SubscribedEventsMs > 0); + } + + #endregion // Collisions } } -- cgit v1.1