Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
commit
de869028cb
|
@ -41,8 +41,6 @@ public class BSCharacter : BSPhysObject
|
|||
|
||||
// private bool _stopped;
|
||||
private OMV.Vector3 _size;
|
||||
private OMV.Vector3 _scale;
|
||||
private PrimitiveBaseShape _pbs;
|
||||
private bool _grabbed;
|
||||
private bool _selected;
|
||||
private OMV.Vector3 _position;
|
||||
|
@ -67,6 +65,10 @@ public class BSCharacter : BSPhysObject
|
|||
private bool _kinematic;
|
||||
private float _buoyancy;
|
||||
|
||||
// The friction and velocity of the avatar is modified depending on whether walking or not.
|
||||
private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
|
||||
private float _currentFriction; // the friction currently being used (changed by setVelocity).
|
||||
|
||||
private OMV.Vector3 _PIDTarget;
|
||||
private bool _usePID;
|
||||
private float _PIDTau;
|
||||
|
@ -84,14 +86,18 @@ public class BSCharacter : BSPhysObject
|
|||
_flying = isFlying;
|
||||
_orientation = OMV.Quaternion.Identity;
|
||||
_velocity = OMV.Vector3.Zero;
|
||||
_appliedVelocity = OMV.Vector3.Zero;
|
||||
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
||||
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
|
||||
_avatarDensity = PhysicsScene.Params.avatarDensity;
|
||||
|
||||
// The dimensions of the avatar capsule are kept in the scale.
|
||||
// Physics creates a unit capsule which is scaled by the physics engine.
|
||||
ComputeAvatarScale(_size);
|
||||
_avatarDensity = PhysicsScene.Params.avatarDensity;
|
||||
// set _avatarVolume and _mass based on capsule size, _density and _scale
|
||||
// set _avatarVolume and _mass based on capsule size, _density and Scale
|
||||
ComputeAvatarVolumeAndMass();
|
||||
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
|
||||
LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw);
|
||||
|
||||
ShapeData shapeData = new ShapeData();
|
||||
shapeData.ID = LocalID;
|
||||
|
@ -99,28 +105,22 @@ public class BSCharacter : BSPhysObject
|
|||
shapeData.Position = _position;
|
||||
shapeData.Rotation = _orientation;
|
||||
shapeData.Velocity = _velocity;
|
||||
shapeData.Scale = _scale;
|
||||
shapeData.Size = Scale;
|
||||
shapeData.Scale = Scale;
|
||||
shapeData.Mass = _mass;
|
||||
shapeData.Buoyancy = _buoyancy;
|
||||
shapeData.Static = ShapeData.numericFalse;
|
||||
shapeData.Friction = PhysicsScene.Params.avatarFriction;
|
||||
shapeData.Friction = PhysicsScene.Params.avatarStandingFriction;
|
||||
shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
|
||||
|
||||
// do actual create at taint time
|
||||
PhysicsScene.TaintedObject("BSCharacter.create", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.create,taint", LocalID);
|
||||
BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData);
|
||||
// New body and shape into BSBody and BSShape
|
||||
PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null);
|
||||
|
||||
// Set the buoyancy for flying. This will be refactored when all the settings happen in C#.
|
||||
// If not set at creation, the avatar will stop flying when created after crossing a region boundry.
|
||||
BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
|
||||
|
||||
BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID));
|
||||
|
||||
// This works here because CreateObject has already put the character into the physical world.
|
||||
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
|
||||
(uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
|
||||
SetPhysicalProperties();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -131,53 +131,85 @@ public class BSCharacter : BSPhysObject
|
|||
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
||||
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
|
||||
{
|
||||
BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
|
||||
PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
|
||||
PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
|
||||
});
|
||||
}
|
||||
|
||||
private void SetPhysicalProperties()
|
||||
{
|
||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||
|
||||
ZeroMotion();
|
||||
ForcePosition = _position;
|
||||
// Set the velocity and compute the proper friction
|
||||
ForceVelocity = _velocity;
|
||||
BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
|
||||
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
|
||||
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||
{
|
||||
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||
}
|
||||
|
||||
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
|
||||
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
|
||||
|
||||
BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
|
||||
|
||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||
|
||||
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
|
||||
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
|
||||
|
||||
// Do this after the object has been added to the world
|
||||
BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
|
||||
(uint)CollisionFilterGroups.AvatarFilter,
|
||||
(uint)CollisionFilterGroups.AvatarMask);
|
||||
}
|
||||
|
||||
public override void RequestPhysicsterseUpdate()
|
||||
{
|
||||
base.RequestPhysicsterseUpdate();
|
||||
}
|
||||
// No one calls this method so I don't know what it could possibly mean
|
||||
public override bool Stopped {
|
||||
get { return false; }
|
||||
}
|
||||
public override bool Stopped { get { return false; } }
|
||||
public override OMV.Vector3 Size {
|
||||
get
|
||||
{
|
||||
// Avatar capsule size is kept in the scale parameter.
|
||||
return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
|
||||
return _size;
|
||||
}
|
||||
|
||||
set {
|
||||
// When an avatar's size is set, only the height is changed
|
||||
// and that really only depends on the radius.
|
||||
// When an avatar's size is set, only the height is changed.
|
||||
_size = value;
|
||||
ComputeAvatarScale(_size);
|
||||
|
||||
// TODO: something has to be done with the avatar's vertical position
|
||||
|
||||
ComputeAvatarVolumeAndMass();
|
||||
DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
|
||||
LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw);
|
||||
|
||||
PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
|
||||
{
|
||||
BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true);
|
||||
BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
|
||||
OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
|
||||
BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
public override PrimitiveBaseShape Shape {
|
||||
set { _pbs = value;
|
||||
}
|
||||
public override OMV.Vector3 Scale { get; set; }
|
||||
public override PrimitiveBaseShape Shape
|
||||
{
|
||||
set { BaseShape = value; }
|
||||
}
|
||||
|
||||
public override bool Grabbed {
|
||||
set { _grabbed = value;
|
||||
}
|
||||
set { _grabbed = value; }
|
||||
}
|
||||
public override bool Selected {
|
||||
set { _selected = value;
|
||||
}
|
||||
set { _selected = value; }
|
||||
}
|
||||
public override void CrossingFailure() { return; }
|
||||
public override void link(PhysicsActor obj) { return; }
|
||||
|
@ -204,7 +236,7 @@ public class BSCharacter : BSPhysObject
|
|||
|
||||
public override OMV.Vector3 Position {
|
||||
get {
|
||||
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
||||
// _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
|
||||
return _position;
|
||||
}
|
||||
set {
|
||||
|
@ -214,7 +246,7 @@ public class BSCharacter : BSPhysObject
|
|||
PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -263,7 +295,7 @@ public class BSCharacter : BSPhysObject
|
|||
// A version of the sanity check that also makes sure a new position value is
|
||||
// pushed back to the physics engine. This routine would be used by anyone
|
||||
// who is not already pushing the value.
|
||||
private bool PositionSanityCheck2(bool inTaintTime)
|
||||
private bool PositionSanityCheck(bool inTaintTime)
|
||||
{
|
||||
bool ret = false;
|
||||
if (PositionSanityCheck())
|
||||
|
@ -273,7 +305,7 @@ public class BSCharacter : BSPhysObject
|
|||
BSScene.TaintCallback sanityOperation = delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
||||
};
|
||||
if (inTaintTime)
|
||||
sanityOperation();
|
||||
|
@ -284,11 +316,7 @@ public class BSCharacter : BSPhysObject
|
|||
return ret;
|
||||
}
|
||||
|
||||
public override float Mass {
|
||||
get {
|
||||
return _mass;
|
||||
}
|
||||
}
|
||||
public override float Mass { get { return _mass; } }
|
||||
|
||||
// used when we only want this prim's mass and not the linkset thing
|
||||
public override float MassRaw { get {return _mass; } }
|
||||
|
@ -301,15 +329,13 @@ public class BSCharacter : BSPhysObject
|
|||
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
|
||||
BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force);
|
||||
BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override int VehicleType {
|
||||
get { return 0; }
|
||||
set { return; }
|
||||
}
|
||||
// Avatars don't do vehicles
|
||||
public override int VehicleType { get { return 0; } set { return; } }
|
||||
public override void VehicleFloatParam(int param, float value) { }
|
||||
public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
|
||||
public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
|
||||
|
@ -328,15 +354,37 @@ public class BSCharacter : BSPhysObject
|
|||
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
|
||||
BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
|
||||
ForceVelocity = _velocity;
|
||||
});
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 ForceVelocity {
|
||||
get { return _velocity; }
|
||||
set {
|
||||
// Depending on whether the avatar is moving or not, change the friction
|
||||
// to keep the avatar from slipping around
|
||||
if (_velocity.Length() == 0)
|
||||
{
|
||||
if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
|
||||
{
|
||||
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
|
||||
BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentFriction != PhysicsScene.Params.avatarFriction)
|
||||
{
|
||||
_currentFriction = PhysicsScene.Params.avatarFriction;
|
||||
BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
|
||||
}
|
||||
}
|
||||
_velocity = value;
|
||||
BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
|
||||
// Remember the set velocity so we can suppress the reduction by friction, ...
|
||||
_appliedVelocity = value;
|
||||
|
||||
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
|
||||
BulletSimAPI.Activate2(BSBody.ptr, true);
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 Torque {
|
||||
|
@ -360,8 +408,8 @@ public class BSCharacter : BSPhysObject
|
|||
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
|
||||
PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
|
||||
{
|
||||
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
|
||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||
// _position = BulletSimAPI.GetPosition2(BSBody.ptr);
|
||||
BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -389,12 +437,18 @@ public class BSCharacter : BSPhysObject
|
|||
set { _isPhysical = value;
|
||||
}
|
||||
}
|
||||
public override bool IsSolid {
|
||||
get { return true; }
|
||||
}
|
||||
public override bool IsStatic {
|
||||
get { return false; }
|
||||
}
|
||||
public override bool Flying {
|
||||
get { return _flying; }
|
||||
set {
|
||||
_flying = value;
|
||||
// simulate flying by changing the effect of gravity
|
||||
this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
|
||||
Buoyancy = ComputeBuoyancyFromFlying(_flying);
|
||||
}
|
||||
}
|
||||
// Flying is implimented by changing the avatar's buoyancy.
|
||||
|
@ -454,10 +508,19 @@ public class BSCharacter : BSPhysObject
|
|||
PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||
BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
|
||||
ForceBuoyancy = _buoyancy;
|
||||
});
|
||||
}
|
||||
}
|
||||
public override float ForceBuoyancy {
|
||||
get { return _buoyancy; }
|
||||
set { _buoyancy = value;
|
||||
DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||
// Buoyancy is faked by changing the gravity applied to the object
|
||||
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
|
||||
BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
|
||||
}
|
||||
}
|
||||
|
||||
// Used for MoveTo
|
||||
public override OMV.Vector3 PIDTarget {
|
||||
|
@ -518,27 +581,32 @@ public class BSCharacter : BSPhysObject
|
|||
|
||||
private void ComputeAvatarScale(OMV.Vector3 size)
|
||||
{
|
||||
_scale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
||||
_scale.Y = PhysicsScene.Params.avatarCapsuleRadius;
|
||||
// The 'size' given by the simulator is the mid-point of the avatar
|
||||
// and X and Y are unspecified.
|
||||
|
||||
// The 1.15 came from ODE but it seems to cause the avatar to float off the ground
|
||||
// _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
|
||||
_scale.Z = (_size.Z) - (_scale.X + _scale.Y);
|
||||
OMV.Vector3 newScale = OMV.Vector3.Zero;
|
||||
newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
|
||||
newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
|
||||
|
||||
// From the total height, remote the capsule half spheres that are at each end
|
||||
newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y);
|
||||
// newScale.Z = (size.Z * 2f);
|
||||
Scale = newScale;
|
||||
}
|
||||
|
||||
// set _avatarVolume and _mass based on capsule size, _density and _scale
|
||||
// set _avatarVolume and _mass based on capsule size, _density and Scale
|
||||
private void ComputeAvatarVolumeAndMass()
|
||||
{
|
||||
_avatarVolume = (float)(
|
||||
Math.PI
|
||||
* _scale.X
|
||||
* _scale.Y // the area of capsule cylinder
|
||||
* _scale.Z // times height of capsule cylinder
|
||||
* Scale.X
|
||||
* Scale.Y // the area of capsule cylinder
|
||||
* Scale.Z // times height of capsule cylinder
|
||||
+ 1.33333333f
|
||||
* Math.PI
|
||||
* _scale.X
|
||||
* Math.Min(_scale.X, _scale.Y)
|
||||
* _scale.Y // plus the volume of the capsule end caps
|
||||
* Scale.X
|
||||
* Math.Min(Scale.X, Scale.Y)
|
||||
* Scale.Y // plus the volume of the capsule end caps
|
||||
);
|
||||
_mass = _avatarDensity * _avatarVolume;
|
||||
}
|
||||
|
@ -553,7 +621,23 @@ public class BSCharacter : BSPhysObject
|
|||
_acceleration = entprop.Acceleration;
|
||||
_rotationalVelocity = entprop.RotationalVelocity;
|
||||
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
||||
PositionSanityCheck2(true);
|
||||
PositionSanityCheck(true);
|
||||
|
||||
// remember the current and last set values
|
||||
LastEntityProperties = CurrentEntityProperties;
|
||||
CurrentEntityProperties = entprop;
|
||||
|
||||
if (entprop.Velocity != LastEntityProperties.Velocity)
|
||||
{
|
||||
// Changes in the velocity are suppressed in avatars.
|
||||
// That's just the way they are defined.
|
||||
OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
|
||||
_velocity = avVel;
|
||||
BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
|
||||
}
|
||||
|
||||
// Tell the linkset about this
|
||||
Linkset.UpdateProperties(this);
|
||||
|
||||
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
|
||||
// base.RequestPhysicsterseUpdate();
|
||||
|
|
|
@ -47,6 +47,7 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
TypeName = typeName;
|
||||
|
||||
Linkset = new BSLinkset(PhysicsScene, this);
|
||||
LastAssetBuildFailed = false;
|
||||
|
||||
CollisionCollection = new CollisionEventUpdate();
|
||||
SubscribedEventsMs = 0;
|
||||
|
@ -69,6 +70,23 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
// Reference to the physical shape (btCollisionShape) of this object
|
||||
public BulletShape BSShape;
|
||||
|
||||
// 'true' if the mesh's underlying asset failed to build.
|
||||
// This will keep us from looping after the first time the build failed.
|
||||
public bool LastAssetBuildFailed { get; set; }
|
||||
|
||||
// The objects base shape information. Null if not a prim type shape.
|
||||
public PrimitiveBaseShape BaseShape { get; protected set; }
|
||||
|
||||
// When the physical properties are updated, an EntityProperty holds the update values.
|
||||
// Keep the current and last EntityProperties to enable computation of differences
|
||||
// between the current update and the previous values.
|
||||
public EntityProperties CurrentEntityProperties { get; set; }
|
||||
public EntityProperties LastEntityProperties { get; set; }
|
||||
|
||||
public abstract OMV.Vector3 Scale { get; set; }
|
||||
public abstract bool IsSolid { get; }
|
||||
public abstract bool IsStatic { get; }
|
||||
|
||||
// Stop all physical motion.
|
||||
public abstract void ZeroMotion();
|
||||
|
||||
|
@ -89,6 +107,10 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
|
||||
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
|
||||
|
||||
public abstract float ForceBuoyancy { get; set; }
|
||||
|
||||
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
|
||||
|
||||
#region Collisions
|
||||
|
||||
// Requested number of milliseconds between collision events. Zero means disabled.
|
||||
|
@ -129,30 +151,28 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
// if someone has subscribed for collision events....
|
||||
if (SubscribedEvents()) {
|
||||
CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
|
||||
// DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
|
||||
// LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
||||
DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
|
||||
LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
|
||||
|
||||
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.
|
||||
// Send the collected collisions into the simulator.
|
||||
// Called at taint time from within the Step() function thus no locking problems
|
||||
// with CollisionCollection and ObjectsWithNoMoreCollisions.
|
||||
// Return 'true' if there were some actual collisions passed up
|
||||
public virtual bool SendCollisions()
|
||||
{
|
||||
bool ret = true;
|
||||
// If the 'no collision' call, force it to happen right now so quick collision_end
|
||||
bool force = CollisionCollection.Count == 0;
|
||||
|
||||
// throttle the collisions to the number of milliseconds specified in the subscription
|
||||
int nowTime = PhysicsScene.SimulationNowTime;
|
||||
if (nowTime >= NextCollisionOkTime)
|
||||
if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
|
||||
{
|
||||
NextCollisionOkTime = nowTime + SubscribedEventsMs;
|
||||
NextCollisionOkTime = PhysicsScene.SimulationNowTime + 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.
|
||||
|
|
|
@ -46,12 +46,10 @@ public sealed class BSPrim : BSPhysObject
|
|||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly string LogHeader = "[BULLETS PRIM]";
|
||||
|
||||
private PrimitiveBaseShape _pbs;
|
||||
|
||||
// _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
|
||||
// Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
|
||||
// _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
|
||||
// Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
|
||||
private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
|
||||
private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
|
||||
// private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
|
||||
|
||||
private bool _grabbed;
|
||||
private bool _isSelected;
|
||||
|
@ -98,12 +96,12 @@ public sealed class BSPrim : BSPhysObject
|
|||
_physicsActorType = (int)ActorTypes.Prim;
|
||||
_position = pos;
|
||||
_size = size;
|
||||
_scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
|
||||
Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
|
||||
_orientation = rotation;
|
||||
_buoyancy = 1f;
|
||||
_velocity = OMV.Vector3.Zero;
|
||||
_rotationalVelocity = OMV.Vector3.Zero;
|
||||
_pbs = pbs;
|
||||
BaseShape = pbs;
|
||||
_isPhysical = pisPhysical;
|
||||
_isVolumeDetect = false;
|
||||
_friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
|
||||
|
@ -160,33 +158,32 @@ public sealed class BSPrim : BSPhysObject
|
|||
get { return _size; }
|
||||
set {
|
||||
_size = value;
|
||||
PhysicsScene.TaintedObject("BSPrim.setSize", delegate()
|
||||
{
|
||||
_mass = CalculateMass(); // changing size changes the mass
|
||||
// Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
|
||||
// scale and margins are set.
|
||||
CreateGeomAndObject(true);
|
||||
// DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical);
|
||||
});
|
||||
ForceBodyShapeRebuild(false);
|
||||
}
|
||||
}
|
||||
// Scale is what we set in the physics engine. It is different than 'size' in that
|
||||
// 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
|
||||
public OMV.Vector3 Scale
|
||||
{
|
||||
get { return _scale; }
|
||||
set { _scale = value; }
|
||||
}
|
||||
public override OMV.Vector3 Scale { get; set; }
|
||||
|
||||
public override PrimitiveBaseShape Shape {
|
||||
set {
|
||||
_pbs = value;
|
||||
PhysicsScene.TaintedObject("BSPrim.setShape", delegate()
|
||||
{
|
||||
_mass = CalculateMass(); // changing the shape changes the mass
|
||||
CreateGeomAndObject(true);
|
||||
});
|
||||
BaseShape = value;
|
||||
ForceBodyShapeRebuild(false);
|
||||
}
|
||||
}
|
||||
public override bool ForceBodyShapeRebuild(bool inTaintTime)
|
||||
{
|
||||
BSScene.TaintCallback rebuildOperation = delegate()
|
||||
{
|
||||
_mass = CalculateMass(); // changing the shape changes the mass
|
||||
CreateGeomAndObject(true);
|
||||
};
|
||||
if (inTaintTime)
|
||||
rebuildOperation();
|
||||
else
|
||||
PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
|
||||
return true;
|
||||
}
|
||||
public override bool Grabbed {
|
||||
set { _grabbed = value;
|
||||
}
|
||||
|
@ -325,9 +322,9 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
|
||||
// A version of the sanity check that also makes sure a new position value is
|
||||
// pushed back to the physics engine. This routine would be used by anyone
|
||||
// pushed to the physics engine. This routine would be used by anyone
|
||||
// who is not already pushing the value.
|
||||
private bool PositionSanityCheck2(bool inTaintTime)
|
||||
private bool PositionSanityCheck(bool inTaintTime)
|
||||
{
|
||||
bool ret = false;
|
||||
if (PositionSanityCheck())
|
||||
|
@ -337,7 +334,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
BSScene.TaintCallback sanityOperation = delegate()
|
||||
{
|
||||
DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
|
||||
BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
|
||||
ForcePosition = _position;
|
||||
};
|
||||
if (inTaintTime)
|
||||
sanityOperation();
|
||||
|
@ -547,13 +544,13 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
|
||||
// An object is static (does not move) if selected or not physical
|
||||
private bool IsStatic
|
||||
public override bool IsStatic
|
||||
{
|
||||
get { return _isSelected || !IsPhysical; }
|
||||
}
|
||||
|
||||
// An object is solid if it's not phantom and if it's not doing VolumeDetect
|
||||
public bool IsSolid
|
||||
public override bool IsSolid
|
||||
{
|
||||
get { return !IsPhantom && !_isVolumeDetect; }
|
||||
}
|
||||
|
@ -631,6 +628,12 @@ public sealed class BSPrim : BSPhysObject
|
|||
BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
|
||||
// There is no inertia in a static object
|
||||
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
|
||||
// Set collision detection parameters
|
||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||
{
|
||||
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||
}
|
||||
// There can be special things needed for implementing linksets
|
||||
Linkset.MakeStatic(this);
|
||||
// The activation state is 'disabled' so Bullet will not try to act on it.
|
||||
|
@ -662,6 +665,13 @@ public sealed class BSPrim : BSPhysObject
|
|||
BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
|
||||
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
|
||||
|
||||
// Set collision detection parameters
|
||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||
{
|
||||
BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||
}
|
||||
|
||||
// Various values for simulation limits
|
||||
BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
|
||||
BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
|
||||
|
@ -813,13 +823,20 @@ public sealed class BSPrim : BSPhysObject
|
|||
_buoyancy = value;
|
||||
PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
|
||||
{
|
||||
// DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||
// Buoyancy is faked by changing the gravity applied to the object
|
||||
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
|
||||
BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
|
||||
ForceBuoyancy = _buoyancy;
|
||||
});
|
||||
}
|
||||
}
|
||||
public override float ForceBuoyancy {
|
||||
get { return _buoyancy; }
|
||||
set {
|
||||
_buoyancy = value;
|
||||
// DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
|
||||
// Buoyancy is faked by changing the gravity applied to the object
|
||||
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
|
||||
BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
|
||||
}
|
||||
}
|
||||
|
||||
// Used for MoveTo
|
||||
public override OMV.Vector3 PIDTarget {
|
||||
|
@ -907,19 +924,19 @@ public sealed class BSPrim : BSPhysObject
|
|||
float tmp;
|
||||
|
||||
float returnMass = 0;
|
||||
float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
|
||||
float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
|
||||
float hollowVolume = hollowAmount * hollowAmount;
|
||||
|
||||
switch (_pbs.ProfileShape)
|
||||
switch (BaseShape.ProfileShape)
|
||||
{
|
||||
case ProfileShape.Square:
|
||||
// default box
|
||||
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Straight)
|
||||
{
|
||||
if (hollowAmount > 0.0)
|
||||
{
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Square:
|
||||
case HollowShape.Same:
|
||||
|
@ -943,19 +960,19 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
}
|
||||
|
||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||
else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||
{
|
||||
//a tube
|
||||
|
||||
volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
|
||||
tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
|
||||
volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
|
||||
tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
|
||||
volume -= volume*tmp*tmp;
|
||||
|
||||
if (hollowAmount > 0.0)
|
||||
{
|
||||
hollowVolume *= hollowAmount;
|
||||
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Square:
|
||||
case HollowShape.Same:
|
||||
|
@ -980,13 +997,13 @@ public sealed class BSPrim : BSPhysObject
|
|||
|
||||
case ProfileShape.Circle:
|
||||
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Straight)
|
||||
{
|
||||
volume *= 0.78539816339f; // elipse base
|
||||
|
||||
if (hollowAmount > 0.0)
|
||||
{
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Same:
|
||||
case HollowShape.Circle:
|
||||
|
@ -1008,10 +1025,10 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
}
|
||||
|
||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||
else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||
{
|
||||
volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
|
||||
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
||||
volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
|
||||
tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
|
||||
volume *= (1.0f - tmp * tmp);
|
||||
|
||||
if (hollowAmount > 0.0)
|
||||
|
@ -1020,7 +1037,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
// calculate the hollow volume by it's shape compared to the prim shape
|
||||
hollowVolume *= hollowAmount;
|
||||
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Same:
|
||||
case HollowShape.Circle:
|
||||
|
@ -1044,7 +1061,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
break;
|
||||
|
||||
case ProfileShape.HalfCircle:
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||
{
|
||||
volume *= 0.52359877559829887307710723054658f;
|
||||
}
|
||||
|
@ -1052,7 +1069,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
|
||||
case ProfileShape.EquilateralTriangle:
|
||||
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Straight)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Straight)
|
||||
{
|
||||
volume *= 0.32475953f;
|
||||
|
||||
|
@ -1060,7 +1077,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
{
|
||||
|
||||
// calculate the hollow volume by it's shape compared to the prim shape
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Same:
|
||||
case HollowShape.Triangle:
|
||||
|
@ -1085,11 +1102,11 @@ public sealed class BSPrim : BSPhysObject
|
|||
volume *= (1.0f - hollowVolume);
|
||||
}
|
||||
}
|
||||
else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
|
||||
else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
|
||||
{
|
||||
volume *= 0.32475953f;
|
||||
volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
|
||||
tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
|
||||
volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
|
||||
tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
|
||||
volume *= (1.0f - tmp * tmp);
|
||||
|
||||
if (hollowAmount > 0.0)
|
||||
|
@ -1097,7 +1114,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
|
||||
hollowVolume *= hollowAmount;
|
||||
|
||||
switch (_pbs.HollowShape)
|
||||
switch (BaseShape.HollowShape)
|
||||
{
|
||||
case HollowShape.Same:
|
||||
case HollowShape.Triangle:
|
||||
|
@ -1137,26 +1154,26 @@ public sealed class BSPrim : BSPhysObject
|
|||
float profileBegin;
|
||||
float profileEnd;
|
||||
|
||||
if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
|
||||
if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
|
||||
{
|
||||
taperX1 = _pbs.PathScaleX * 0.01f;
|
||||
taperX1 = BaseShape.PathScaleX * 0.01f;
|
||||
if (taperX1 > 1.0f)
|
||||
taperX1 = 2.0f - taperX1;
|
||||
taperX = 1.0f - taperX1;
|
||||
|
||||
taperY1 = _pbs.PathScaleY * 0.01f;
|
||||
taperY1 = BaseShape.PathScaleY * 0.01f;
|
||||
if (taperY1 > 1.0f)
|
||||
taperY1 = 2.0f - taperY1;
|
||||
taperY = 1.0f - taperY1;
|
||||
}
|
||||
else
|
||||
{
|
||||
taperX = _pbs.PathTaperX * 0.01f;
|
||||
taperX = BaseShape.PathTaperX * 0.01f;
|
||||
if (taperX < 0.0f)
|
||||
taperX = -taperX;
|
||||
taperX1 = 1.0f - taperX;
|
||||
|
||||
taperY = _pbs.PathTaperY * 0.01f;
|
||||
taperY = BaseShape.PathTaperY * 0.01f;
|
||||
if (taperY < 0.0f)
|
||||
taperY = -taperY;
|
||||
taperY1 = 1.0f - taperY;
|
||||
|
@ -1166,13 +1183,13 @@ public sealed class BSPrim : BSPhysObject
|
|||
|
||||
volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
|
||||
|
||||
pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
|
||||
pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
|
||||
pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
|
||||
pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
|
||||
volume *= (pathEnd - pathBegin);
|
||||
|
||||
// this is crude aproximation
|
||||
profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
|
||||
profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
|
||||
profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
|
||||
profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
|
||||
volume *= (profileEnd - profileBegin);
|
||||
|
||||
returnMass = _density * volume;
|
||||
|
@ -1207,7 +1224,8 @@ public sealed class BSPrim : BSPhysObject
|
|||
shape.Position = _position;
|
||||
shape.Rotation = _orientation;
|
||||
shape.Velocity = _velocity;
|
||||
shape.Scale = _scale;
|
||||
shape.Size = _size;
|
||||
shape.Scale = Scale;
|
||||
shape.Mass = _isPhysical ? _mass : 0f;
|
||||
shape.Buoyancy = _buoyancy;
|
||||
shape.HullKey = 0;
|
||||
|
@ -1217,7 +1235,6 @@ public sealed class BSPrim : BSPhysObject
|
|||
shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
|
||||
shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
|
||||
shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
|
||||
shape.Size = _size;
|
||||
}
|
||||
// Rebuild the geometry and object.
|
||||
// This is called when the shape changes so we need to recreate the mesh/hull.
|
||||
|
@ -1234,7 +1251,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
// Create the correct physical representation for this type of object.
|
||||
// Updates BSBody and BSShape with the new information.
|
||||
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
|
||||
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, _pbs,
|
||||
PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
|
||||
null, delegate(BulletBody dBody)
|
||||
{
|
||||
// Called if the current prim body is about to be destroyed.
|
||||
|
@ -1328,9 +1345,11 @@ public sealed class BSPrim : BSPhysObject
|
|||
_acceleration = entprop.Acceleration;
|
||||
_rotationalVelocity = entprop.RotationalVelocity;
|
||||
|
||||
PositionSanityCheck2(true);
|
||||
// remember the current and last set values
|
||||
LastEntityProperties = CurrentEntityProperties;
|
||||
CurrentEntityProperties = entprop;
|
||||
|
||||
Linkset.UpdateProperties(this);
|
||||
PositionSanityCheck(true);
|
||||
|
||||
DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
||||
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
|
||||
|
@ -1348,6 +1367,9 @@ public sealed class BSPrim : BSPhysObject
|
|||
entprop.Acceleration, entprop.RotationalVelocity);
|
||||
}
|
||||
*/
|
||||
// The linkset implimentation might want to know about this.
|
||||
|
||||
Linkset.UpdateProperties(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -256,14 +256,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
||||
|
||||
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
|
||||
WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
|
||||
World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
|
||||
m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
|
||||
m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
|
||||
m_DebugLogCallbackHandle);
|
||||
|
||||
// Initialization to support the transition to a new API which puts most of the logic
|
||||
// into the C# code so it is easier to modify and add to.
|
||||
World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
|
||||
m_DebugLogCallbackHandle));
|
||||
|
||||
Constraints = new BSConstraintCollection(World);
|
||||
|
||||
|
@ -360,7 +356,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
}
|
||||
|
||||
// Anything left in the unmanaged code should be cleaned out
|
||||
BulletSimAPI.Shutdown(WorldID);
|
||||
BulletSimAPI.Shutdown2(World.ptr);
|
||||
|
||||
// Not logging any more
|
||||
PhysicsLogging.Close();
|
||||
|
@ -498,7 +494,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
{
|
||||
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
|
||||
|
||||
numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
|
||||
numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
|
||||
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
|
||||
|
||||
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
|
||||
|
@ -536,26 +532,26 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
}
|
||||
}
|
||||
|
||||
// This is a kludge to get avatar movement updates.
|
||||
// the simulator expects collisions for avatars even if there are have been no collisions. This updates
|
||||
// avatar animations and stuff.
|
||||
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
|
||||
foreach (BSPhysObject bsp in m_avatars)
|
||||
bsp.SendCollisions();
|
||||
|
||||
// The above SendCollision's batch up the collisions on the objects.
|
||||
// Now push the collisions into the simulator.
|
||||
if (ObjectsWithCollisions.Count > 0)
|
||||
{
|
||||
foreach (BSPhysObject bsp in ObjectsWithCollisions)
|
||||
if (!m_avatars.Contains(bsp)) // don't call avatars twice
|
||||
if (!bsp.SendCollisions())
|
||||
{
|
||||
// If the object is done colliding, see that it's removed from the colliding list
|
||||
ObjectsWithNoMoreCollisions.Add(bsp);
|
||||
}
|
||||
if (!bsp.SendCollisions())
|
||||
{
|
||||
// If the object is done colliding, see that it's removed from the colliding list
|
||||
ObjectsWithNoMoreCollisions.Add(bsp);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a kludge to get avatar movement updates.
|
||||
// The simulator expects collisions for avatars even if there are have been no collisions.
|
||||
// The event updates avatar animations and stuff.
|
||||
// If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
|
||||
foreach (BSPhysObject bsp in m_avatars)
|
||||
if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
|
||||
bsp.SendCollisions();
|
||||
|
||||
// Objects that are done colliding are removed from the ObjectsWithCollisions list.
|
||||
// Not done above because it is inside an iteration of ObjectWithCollisions.
|
||||
if (ObjectsWithNoMoreCollisions.Count > 0)
|
||||
|
@ -579,11 +575,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
}
|
||||
}
|
||||
|
||||
// This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
|
||||
// Only enable this in a limited test world with few objects.
|
||||
// BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
|
||||
|
||||
// The physics engine returns the number of milliseconds it simulated this call.
|
||||
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
|
||||
// We multiply by 45 to give a recognizable running rate (45 or less).
|
||||
return numSubSteps * m_fixedTimeStep * 1000 * 45;
|
||||
// return timeStep * 1000 * 45;
|
||||
// We multiply by 55 to give a recognizable running rate (55 or less).
|
||||
return numSubSteps * m_fixedTimeStep * 1000 * 55;
|
||||
// return timeStep * 1000 * 55;
|
||||
}
|
||||
|
||||
// Something has collided
|
||||
|
@ -800,6 +800,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
|
||||
delegate float ParamGet(BSScene scene);
|
||||
delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
|
||||
delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
|
||||
|
||||
private struct ParameterDefn
|
||||
{
|
||||
|
@ -809,6 +810,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
public ParamUser userParam; // get the value from the configuration file
|
||||
public ParamGet getter; // return the current value stored for this parameter
|
||||
public ParamSet setter; // set the current value for this parameter
|
||||
public SetOnObject onObject; // set the value on an object in the physical domain
|
||||
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
|
||||
{
|
||||
name = n;
|
||||
|
@ -817,6 +819,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
userParam = u;
|
||||
getter = g;
|
||||
setter = s;
|
||||
onObject = null;
|
||||
}
|
||||
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
|
||||
{
|
||||
name = n;
|
||||
desc = d;
|
||||
defaultValue = v;
|
||||
userParam = u;
|
||||
getter = g;
|
||||
setter = s;
|
||||
onObject = o;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -838,6 +851,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
//
|
||||
// The single letter parameters for the delegates are:
|
||||
// s = BSScene
|
||||
// o = BSPhysObject
|
||||
// p = string parameter name
|
||||
// l = localID of referenced object
|
||||
// v = float value
|
||||
|
@ -947,70 +961,84 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
-9.80665f,
|
||||
(s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].gravity; },
|
||||
(s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
|
||||
|
||||
|
||||
new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linearDamping; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
|
||||
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].angularDamping; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ),
|
||||
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
|
||||
0.2f,
|
||||
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].deactivationTime; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.BSBody.ptr, v); } ),
|
||||
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
|
||||
0.8f,
|
||||
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linearSleepingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
|
||||
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
|
||||
1.0f,
|
||||
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].angularSleepingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ),
|
||||
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
|
||||
0f, // set to zero to disable
|
||||
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].ccdMotionThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.BSBody.ptr, v); } ),
|
||||
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetCcdSweepSphereRadius2(o.BSBody.ptr, v); } ),
|
||||
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
|
||||
0.1f,
|
||||
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].contactProcessingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.BSBody.ptr, v); } ),
|
||||
|
||||
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
|
||||
0.5f,
|
||||
(s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].terrainFriction; },
|
||||
(s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ),
|
||||
(s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
|
||||
new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
|
||||
0.8f,
|
||||
(s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].terrainHitFraction; },
|
||||
(s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ),
|
||||
(s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
|
||||
new ParameterDefn("TerrainRestitution", "Bouncyness" ,
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].terrainRestitution; },
|
||||
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
|
||||
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
|
||||
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
|
||||
0.2f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].avatarFriction; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
|
||||
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
|
||||
10f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].avatarStandingFriction; },
|
||||
(s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
|
||||
new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
|
||||
60f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
|
||||
|
@ -1227,52 +1255,54 @@ public class BSScene : PhysicsScene, IPhysicsParameters
|
|||
return ret;
|
||||
}
|
||||
|
||||
// check to see if we are updating a parameter for a particular or all of the prims
|
||||
protected void UpdateParameterObject(ref float loc, string parm, uint localID, float val)
|
||||
{
|
||||
List<uint> operateOn;
|
||||
lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
|
||||
UpdateParameterSet(operateOn, ref loc, parm, localID, val);
|
||||
}
|
||||
|
||||
// update all the localIDs specified
|
||||
// If the local ID is APPLY_TO_NONE, just change the default value
|
||||
// If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
|
||||
// If the localID is a specific object, apply the parameter change to only that object
|
||||
protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val)
|
||||
protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
|
||||
{
|
||||
List<uint> objectIDs = new List<uint>();
|
||||
switch (localID)
|
||||
{
|
||||
case PhysParameterEntry.APPLY_TO_NONE:
|
||||
defaultLoc = val; // setting only the default value
|
||||
// This will cause a call into the physical world if some operation is specified (SetOnObject).
|
||||
objectIDs.Add(TERRAIN_ID);
|
||||
TaintedUpdateParameter(parm, objectIDs, val);
|
||||
break;
|
||||
case PhysParameterEntry.APPLY_TO_ALL:
|
||||
defaultLoc = val; // setting ALL also sets the default value
|
||||
List<uint> objectIDs = lIDs;
|
||||
string xparm = parm.ToLower();
|
||||
float xval = val;
|
||||
TaintedObject("BSScene.UpdateParameterSet", delegate() {
|
||||
foreach (uint lID in objectIDs)
|
||||
{
|
||||
BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
|
||||
}
|
||||
});
|
||||
lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
|
||||
TaintedUpdateParameter(parm, objectIDs, val);
|
||||
break;
|
||||
default:
|
||||
// setting only one localID
|
||||
TaintedUpdateParameter(parm, localID, val);
|
||||
objectIDs.Add(localID);
|
||||
TaintedUpdateParameter(parm, objectIDs, val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// schedule the actual updating of the paramter to when the phys engine is not busy
|
||||
protected void TaintedUpdateParameter(string parm, uint localID, float val)
|
||||
protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
|
||||
{
|
||||
uint xlocalID = localID;
|
||||
string xparm = parm.ToLower();
|
||||
float xval = val;
|
||||
TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
|
||||
BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
|
||||
List<uint> xlIDs = lIDs;
|
||||
string xparm = parm;
|
||||
TaintedObject("BSScene.UpdateParameterSet", delegate() {
|
||||
ParameterDefn thisParam;
|
||||
if (TryGetParameter(xparm, out thisParam))
|
||||
{
|
||||
if (thisParam.onObject != null)
|
||||
{
|
||||
foreach (uint lID in xlIDs)
|
||||
{
|
||||
BSPhysObject theObject = null;
|
||||
PhysObjects.TryGetValue(lID, out theObject);
|
||||
thisParam.onObject(this, theObject, xval);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public class BSShapeCollection : IDisposable
|
|||
}
|
||||
|
||||
// Description of a hull.
|
||||
// Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects
|
||||
// Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
|
||||
private struct HullDesc
|
||||
{
|
||||
public IntPtr ptr;
|
||||
|
@ -59,17 +59,9 @@ public class BSShapeCollection : IDisposable
|
|||
public DateTime lastReferenced;
|
||||
}
|
||||
|
||||
private struct BodyDesc
|
||||
{
|
||||
public IntPtr ptr;
|
||||
// Bodies are only used once so reference count is always either one or zero
|
||||
public int referenceCount;
|
||||
public DateTime lastReferenced;
|
||||
}
|
||||
|
||||
// The sharable set of meshes and hulls. Indexed by their shape hash.
|
||||
private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
|
||||
private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
|
||||
private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
|
||||
|
||||
public BSShapeCollection(BSScene physScene)
|
||||
{
|
||||
|
@ -92,8 +84,12 @@ public class BSShapeCollection : IDisposable
|
|||
// First checks the shape and updates that if necessary then makes
|
||||
// sure the body is of the right type.
|
||||
// Return 'true' if either the body or the shape changed.
|
||||
// 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
|
||||
// the current shape or body is destroyed. This allows the caller to remove any
|
||||
// higher level dependencies on the shape or body. Mostly used for LinkSets to
|
||||
// remove the physical constraints before the body is destroyed.
|
||||
// Called at taint-time!!
|
||||
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim,
|
||||
public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
|
||||
ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
|
||||
{
|
||||
|
@ -103,7 +99,8 @@ public class BSShapeCollection : IDisposable
|
|||
lock (m_collectionActivityLock)
|
||||
{
|
||||
// Do we have the correct geometry for this type of object?
|
||||
// Updates prim.BSShape with information/pointers to requested shape
|
||||
// Updates prim.BSShape with information/pointers to shape.
|
||||
// CreateGeom returns 'true' of BSShape as changed to a new shape.
|
||||
bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
|
||||
// If we had to select a new shape geometry for the object,
|
||||
// rebuild the body around it.
|
||||
|
@ -120,40 +117,24 @@ public class BSShapeCollection : IDisposable
|
|||
|
||||
// Track another user of a body
|
||||
// We presume the caller has allocated the body.
|
||||
// Bodies only have one user so the reference count is either 1 or 0.
|
||||
// Bodies only have one user so the body is just put into the world if not already there.
|
||||
public void ReferenceBody(BulletBody body, bool inTaintTime)
|
||||
{
|
||||
lock (m_collectionActivityLock)
|
||||
{
|
||||
BodyDesc bodyDesc;
|
||||
if (Bodies.TryGetValue(body.ID, out bodyDesc))
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
|
||||
BSScene.TaintCallback createOperation = delegate()
|
||||
{
|
||||
bodyDesc.referenceCount++;
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
// New entry
|
||||
bodyDesc.ptr = body.ptr;
|
||||
bodyDesc.referenceCount = 1;
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={2}",
|
||||
body.ID, body, bodyDesc.referenceCount);
|
||||
BSScene.TaintCallback createOperation = delegate()
|
||||
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
||||
{
|
||||
if (!BulletSimAPI.IsInWorld2(body.ptr))
|
||||
{
|
||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}",
|
||||
body.ID, body);
|
||||
}
|
||||
};
|
||||
if (inTaintTime)
|
||||
createOperation();
|
||||
else
|
||||
PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
|
||||
}
|
||||
bodyDesc.lastReferenced = System.DateTime.Now;
|
||||
Bodies[body.ID] = bodyDesc;
|
||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||
DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
|
||||
}
|
||||
};
|
||||
if (inTaintTime)
|
||||
createOperation();
|
||||
else
|
||||
PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,43 +147,25 @@ public class BSShapeCollection : IDisposable
|
|||
|
||||
lock (m_collectionActivityLock)
|
||||
{
|
||||
BodyDesc bodyDesc;
|
||||
if (Bodies.TryGetValue(body.ID, out bodyDesc))
|
||||
BSScene.TaintCallback removeOperation = delegate()
|
||||
{
|
||||
bodyDesc.referenceCount--;
|
||||
bodyDesc.lastReferenced = System.DateTime.Now;
|
||||
Bodies[body.ID] = bodyDesc;
|
||||
DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
|
||||
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
|
||||
body.ID, body.ptr.ToString("X"), inTaintTime);
|
||||
// If the caller needs to know the old body is going away, pass the event up.
|
||||
if (bodyCallback != null) bodyCallback(body);
|
||||
|
||||
// If body is no longer being used, free it -- bodies can never be shared.
|
||||
if (bodyDesc.referenceCount == 0)
|
||||
{
|
||||
Bodies.Remove(body.ID);
|
||||
BSScene.TaintCallback removeOperation = delegate()
|
||||
{
|
||||
DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
|
||||
body.ID, body.ptr.ToString("X"), inTaintTime);
|
||||
// If the caller needs to know the old body is going away, pass the event up.
|
||||
if (bodyCallback != null) bodyCallback(body);
|
||||
// It may have already been removed from the world in which case the next is a NOOP.
|
||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||
|
||||
// It may have already been removed from the world in which case the next is a NOOP.
|
||||
BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
|
||||
|
||||
// Zero any reference to the shape so it is not freed when the body is deleted.
|
||||
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
|
||||
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
|
||||
};
|
||||
// If already in taint-time, do the operations now. Otherwise queue for later.
|
||||
if (inTaintTime)
|
||||
removeOperation();
|
||||
else
|
||||
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
|
||||
}
|
||||
}
|
||||
// Zero any reference to the shape so it is not freed when the body is deleted.
|
||||
BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
|
||||
BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
|
||||
};
|
||||
// If already in taint-time, do the operations now. Otherwise queue for later.
|
||||
if (inTaintTime)
|
||||
removeOperation();
|
||||
else
|
||||
{
|
||||
DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
|
||||
}
|
||||
PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,7 +234,6 @@ public class BSShapeCollection : IDisposable
|
|||
}
|
||||
|
||||
// Release the usage of a shape.
|
||||
// The collisionObject is released since it is a copy of the real collision shape.
|
||||
public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
if (shape.ptr == IntPtr.Zero)
|
||||
|
@ -279,26 +241,32 @@ public class BSShapeCollection : IDisposable
|
|||
|
||||
BSScene.TaintCallback dereferenceOperation = delegate()
|
||||
{
|
||||
switch (shape.type)
|
||||
if (shape.ptr != IntPtr.Zero)
|
||||
{
|
||||
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
||||
DereferenceHull(shape, shapeCallback);
|
||||
break;
|
||||
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||
DereferenceMesh(shape, shapeCallback);
|
||||
break;
|
||||
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
||||
break;
|
||||
default:
|
||||
if (shape.isNativeShape)
|
||||
{
|
||||
// Native shapes are not tracked and are released immediately
|
||||
if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
|
||||
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
||||
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
|
||||
if (shapeCallback != null) shapeCallback(shape);
|
||||
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (shape.type)
|
||||
{
|
||||
DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
|
||||
BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
|
||||
if (shapeCallback != null) shapeCallback(shape);
|
||||
BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
|
||||
case ShapeData.PhysicsShapeType.SHAPE_HULL:
|
||||
DereferenceHull(shape, shapeCallback);
|
||||
break;
|
||||
case ShapeData.PhysicsShapeType.SHAPE_MESH:
|
||||
DereferenceMesh(shape, shapeCallback);
|
||||
break;
|
||||
case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (inTaintTime)
|
||||
|
@ -351,19 +319,31 @@ public class BSShapeCollection : IDisposable
|
|||
|
||||
// Create the geometry information in Bullet for later use.
|
||||
// The objects needs a hull if it's physical otherwise a mesh is enough.
|
||||
// No locking here because this is done when we know physics is not simulating.
|
||||
// if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used.
|
||||
// if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
|
||||
// shared geometries will be used. If the parameters of the existing shape are the same
|
||||
// as this request, the shape is not rebuilt.
|
||||
// Info in prim.BSShape is updated to the new shape.
|
||||
// Returns 'true' if the geometry was rebuilt.
|
||||
// Called at taint-time!
|
||||
private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData,
|
||||
private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
|
||||
PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
bool ret = false;
|
||||
bool haveShape = false;
|
||||
bool nativeShapePossible = true;
|
||||
|
||||
if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
||||
{
|
||||
// an avatar capsule is close to a native shape (it is not shared)
|
||||
ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
|
||||
ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
|
||||
DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
|
||||
haveShape = true;
|
||||
}
|
||||
// If the prim attributes are simple, this could be a simple Bullet native shape
|
||||
if (nativeShapePossible
|
||||
if (!haveShape
|
||||
&& pbs != null
|
||||
&& nativeShapePossible
|
||||
&& ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
|
||||
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
|
||||
&& pbs.ProfileHollow == 0
|
||||
|
@ -406,7 +386,7 @@ public class BSShapeCollection : IDisposable
|
|||
// If a simple shape is not happening, create a mesh and possibly a hull.
|
||||
// Note that if it's a native shape, the check for physical/non-physical is not
|
||||
// made. Native shapes are best used in either case.
|
||||
if (!haveShape)
|
||||
if (!haveShape && pbs != null)
|
||||
{
|
||||
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
|
||||
{
|
||||
|
@ -425,12 +405,12 @@ public class BSShapeCollection : IDisposable
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Creates a native shape and assignes it to prim.BSShape
|
||||
private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData,
|
||||
// Creates a native shape and assignes it to prim.BSShape.
|
||||
// "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
|
||||
private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData,
|
||||
ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
|
||||
ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
BulletShape newShape;
|
||||
|
||||
shapeData.Type = shapeType;
|
||||
// Bullet native objects are scaled by the Bullet engine so pass the size in
|
||||
|
@ -440,23 +420,42 @@ public class BSShapeCollection : IDisposable
|
|||
// release any previous shape
|
||||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||
|
||||
// Native shapes are always built independently.
|
||||
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
|
||||
newShape.shapeKey = (System.UInt64)shapeKey;
|
||||
newShape.isNativeShape = true;
|
||||
BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
|
||||
|
||||
// Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
|
||||
// DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape);
|
||||
// Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
|
||||
DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
|
||||
shapeData.ID, newShape, shapeData.Scale);
|
||||
|
||||
prim.BSShape = newShape;
|
||||
return true;
|
||||
}
|
||||
|
||||
private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
|
||||
ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
|
||||
{
|
||||
BulletShape newShape;
|
||||
|
||||
if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
|
||||
{
|
||||
newShape = new BulletShape(
|
||||
BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale),
|
||||
shapeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
|
||||
}
|
||||
newShape.shapeKey = (System.UInt64)shapeKey;
|
||||
newShape.isNativeShape = true;
|
||||
|
||||
return newShape;
|
||||
}
|
||||
|
||||
// Builds a mesh shape in the physical world and updates prim.BSShape.
|
||||
// Dereferences previous shape in BSShape and adds a reference for this new shape.
|
||||
// Returns 'true' of a mesh was actually built. Otherwise .
|
||||
// Called at taint-time!
|
||||
private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
BulletShape newShape = new BulletShape(IntPtr.Zero);
|
||||
|
@ -475,6 +474,8 @@ public class BSShapeCollection : IDisposable
|
|||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||
|
||||
newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
|
||||
// Take evasive action if the mesh was not constructed.
|
||||
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
|
||||
|
||||
ReferenceShape(newShape);
|
||||
|
||||
|
@ -488,7 +489,7 @@ public class BSShapeCollection : IDisposable
|
|||
private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||
{
|
||||
IMesh meshData = null;
|
||||
IntPtr meshPtr;
|
||||
IntPtr meshPtr = IntPtr.Zero;
|
||||
MeshDesc meshDesc;
|
||||
if (Meshes.TryGetValue(newMeshKey, out meshDesc))
|
||||
{
|
||||
|
@ -500,23 +501,26 @@ public class BSShapeCollection : IDisposable
|
|||
// Pass false for physicalness as this creates some sort of bounding box which we don't need
|
||||
meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
|
||||
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||
|
||||
float[] verticesAsFloats = new float[vertices.Count * 3];
|
||||
int vi = 0;
|
||||
foreach (OMV.Vector3 vv in vertices)
|
||||
if (meshData != null)
|
||||
{
|
||||
verticesAsFloats[vi++] = vv.X;
|
||||
verticesAsFloats[vi++] = vv.Y;
|
||||
verticesAsFloats[vi++] = vv.Z;
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||
|
||||
float[] verticesAsFloats = new float[vertices.Count * 3];
|
||||
int vi = 0;
|
||||
foreach (OMV.Vector3 vv in vertices)
|
||||
{
|
||||
verticesAsFloats[vi++] = vv.X;
|
||||
verticesAsFloats[vi++] = vv.Y;
|
||||
verticesAsFloats[vi++] = vv.Z;
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
|
||||
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
|
||||
|
||||
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
||||
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
|
||||
// LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
|
||||
|
||||
meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
|
||||
indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
|
||||
}
|
||||
BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
|
||||
newShape.shapeKey = newMeshKey;
|
||||
|
@ -526,7 +530,7 @@ public class BSShapeCollection : IDisposable
|
|||
|
||||
// See that hull shape exists in the physical world and update prim.BSShape.
|
||||
// We could be creating the hull because scale changed or whatever.
|
||||
private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
|
||||
ShapeDestructionCallback shapeCallback)
|
||||
{
|
||||
BulletShape newShape;
|
||||
|
@ -545,6 +549,7 @@ public class BSShapeCollection : IDisposable
|
|||
DereferenceShape(prim.BSShape, true, shapeCallback);
|
||||
|
||||
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
|
||||
newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
|
||||
|
||||
ReferenceShape(newShape);
|
||||
|
||||
|
@ -558,7 +563,7 @@ public class BSShapeCollection : IDisposable
|
|||
private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
|
||||
{
|
||||
|
||||
IntPtr hullPtr;
|
||||
IntPtr hullPtr = IntPtr.Zero;
|
||||
HullDesc hullDesc;
|
||||
if (Hulls.TryGetValue(newHullKey, out hullDesc))
|
||||
{
|
||||
|
@ -570,86 +575,89 @@ public class BSShapeCollection : IDisposable
|
|||
// Build a new hull in the physical world
|
||||
// Pass false for physicalness as this creates some sort of bounding box which we don't need
|
||||
IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
|
||||
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||
|
||||
//format conversion from IMesh format to DecompDesc format
|
||||
List<int> convIndices = new List<int>();
|
||||
List<float3> convVertices = new List<float3>();
|
||||
for (int ii = 0; ii < indices.GetLength(0); ii++)
|
||||
if (meshData != null)
|
||||
{
|
||||
convIndices.Add(indices[ii]);
|
||||
}
|
||||
foreach (OMV.Vector3 vv in vertices)
|
||||
{
|
||||
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
|
||||
}
|
||||
|
||||
// setup and do convex hull conversion
|
||||
m_hulls = new List<ConvexResult>();
|
||||
DecompDesc dcomp = new DecompDesc();
|
||||
dcomp.mIndices = convIndices;
|
||||
dcomp.mVertices = convVertices;
|
||||
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
|
||||
// create the hull into the _hulls variable
|
||||
convexBuilder.process(dcomp);
|
||||
int[] indices = meshData.getIndexListAsInt();
|
||||
List<OMV.Vector3> vertices = meshData.getVertexList();
|
||||
|
||||
// Convert the vertices and indices for passing to unmanaged.
|
||||
// The hull information is passed as a large floating point array.
|
||||
// The format is:
|
||||
// convHulls[0] = number of hulls
|
||||
// convHulls[1] = number of vertices in first hull
|
||||
// convHulls[2] = hull centroid X coordinate
|
||||
// convHulls[3] = hull centroid Y coordinate
|
||||
// convHulls[4] = hull centroid Z coordinate
|
||||
// convHulls[5] = first hull vertex X
|
||||
// convHulls[6] = first hull vertex Y
|
||||
// convHulls[7] = first hull vertex Z
|
||||
// convHulls[8] = second hull vertex X
|
||||
// ...
|
||||
// convHulls[n] = number of vertices in second hull
|
||||
// convHulls[n+1] = second hull centroid X coordinate
|
||||
// ...
|
||||
//
|
||||
// TODO: is is very inefficient. Someday change the convex hull generator to return
|
||||
// data structures that do not need to be converted in order to pass to Bullet.
|
||||
// And maybe put the values directly into pinned memory rather than marshaling.
|
||||
int hullCount = m_hulls.Count;
|
||||
int totalVertices = 1; // include one for the count of the hulls
|
||||
foreach (ConvexResult cr in m_hulls)
|
||||
{
|
||||
totalVertices += 4; // add four for the vertex count and centroid
|
||||
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
|
||||
}
|
||||
float[] convHulls = new float[totalVertices];
|
||||
|
||||
convHulls[0] = (float)hullCount;
|
||||
int jj = 1;
|
||||
foreach (ConvexResult cr in m_hulls)
|
||||
{
|
||||
// copy vertices for index access
|
||||
float3[] verts = new float3[cr.HullVertices.Count];
|
||||
int kk = 0;
|
||||
foreach (float3 ff in cr.HullVertices)
|
||||
//format conversion from IMesh format to DecompDesc format
|
||||
List<int> convIndices = new List<int>();
|
||||
List<float3> convVertices = new List<float3>();
|
||||
for (int ii = 0; ii < indices.GetLength(0); ii++)
|
||||
{
|
||||
verts[kk++] = ff;
|
||||
convIndices.Add(indices[ii]);
|
||||
}
|
||||
foreach (OMV.Vector3 vv in vertices)
|
||||
{
|
||||
convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
|
||||
}
|
||||
|
||||
// add to the array one hull's worth of data
|
||||
convHulls[jj++] = cr.HullIndices.Count;
|
||||
convHulls[jj++] = 0f; // centroid x,y,z
|
||||
convHulls[jj++] = 0f;
|
||||
convHulls[jj++] = 0f;
|
||||
foreach (int ind in cr.HullIndices)
|
||||
// setup and do convex hull conversion
|
||||
m_hulls = new List<ConvexResult>();
|
||||
DecompDesc dcomp = new DecompDesc();
|
||||
dcomp.mIndices = convIndices;
|
||||
dcomp.mVertices = convVertices;
|
||||
ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
|
||||
// create the hull into the _hulls variable
|
||||
convexBuilder.process(dcomp);
|
||||
|
||||
// Convert the vertices and indices for passing to unmanaged.
|
||||
// The hull information is passed as a large floating point array.
|
||||
// The format is:
|
||||
// convHulls[0] = number of hulls
|
||||
// convHulls[1] = number of vertices in first hull
|
||||
// convHulls[2] = hull centroid X coordinate
|
||||
// convHulls[3] = hull centroid Y coordinate
|
||||
// convHulls[4] = hull centroid Z coordinate
|
||||
// convHulls[5] = first hull vertex X
|
||||
// convHulls[6] = first hull vertex Y
|
||||
// convHulls[7] = first hull vertex Z
|
||||
// convHulls[8] = second hull vertex X
|
||||
// ...
|
||||
// convHulls[n] = number of vertices in second hull
|
||||
// convHulls[n+1] = second hull centroid X coordinate
|
||||
// ...
|
||||
//
|
||||
// TODO: is is very inefficient. Someday change the convex hull generator to return
|
||||
// data structures that do not need to be converted in order to pass to Bullet.
|
||||
// And maybe put the values directly into pinned memory rather than marshaling.
|
||||
int hullCount = m_hulls.Count;
|
||||
int totalVertices = 1; // include one for the count of the hulls
|
||||
foreach (ConvexResult cr in m_hulls)
|
||||
{
|
||||
convHulls[jj++] = verts[ind].x;
|
||||
convHulls[jj++] = verts[ind].y;
|
||||
convHulls[jj++] = verts[ind].z;
|
||||
totalVertices += 4; // add four for the vertex count and centroid
|
||||
totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
|
||||
}
|
||||
float[] convHulls = new float[totalVertices];
|
||||
|
||||
convHulls[0] = (float)hullCount;
|
||||
int jj = 1;
|
||||
foreach (ConvexResult cr in m_hulls)
|
||||
{
|
||||
// copy vertices for index access
|
||||
float3[] verts = new float3[cr.HullVertices.Count];
|
||||
int kk = 0;
|
||||
foreach (float3 ff in cr.HullVertices)
|
||||
{
|
||||
verts[kk++] = ff;
|
||||
}
|
||||
|
||||
// add to the array one hull's worth of data
|
||||
convHulls[jj++] = cr.HullIndices.Count;
|
||||
convHulls[jj++] = 0f; // centroid x,y,z
|
||||
convHulls[jj++] = 0f;
|
||||
convHulls[jj++] = 0f;
|
||||
foreach (int ind in cr.HullIndices)
|
||||
{
|
||||
convHulls[jj++] = verts[ind].x;
|
||||
convHulls[jj++] = verts[ind].y;
|
||||
convHulls[jj++] = verts[ind].z;
|
||||
}
|
||||
}
|
||||
// create the hull data structure in Bullet
|
||||
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
|
||||
}
|
||||
// create the hull data structure in Bullet
|
||||
hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
|
||||
}
|
||||
|
||||
BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
|
||||
|
@ -690,11 +698,55 @@ public class BSShapeCollection : IDisposable
|
|||
return ComputeShapeKey(shapeData, pbs, out lod);
|
||||
}
|
||||
|
||||
private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
|
||||
{
|
||||
// If the shape was successfully created, nothing more to do
|
||||
if (newShape.ptr != IntPtr.Zero)
|
||||
return newShape;
|
||||
|
||||
// The most common reason for failure is that an underlying asset is not available
|
||||
|
||||
// If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
|
||||
if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
|
||||
{
|
||||
prim.LastAssetBuildFailed = true;
|
||||
BSPhysObject xprim = prim;
|
||||
Util.FireAndForget(delegate
|
||||
{
|
||||
RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
|
||||
if (assetProvider != null)
|
||||
{
|
||||
BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
|
||||
assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
|
||||
{
|
||||
if (!yprim.BaseShape.SculptEntry)
|
||||
return;
|
||||
if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
|
||||
return;
|
||||
|
||||
yprim.BaseShape.SculptData = new byte[asset.Data.Length];
|
||||
asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
|
||||
// This will cause the prim to see that the filler shape is not the right
|
||||
// one and try again to build the object.
|
||||
yprim.ForceBodyShapeRebuild(false);
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// While we figure out the real problem, stick a simple native shape on the object.
|
||||
BulletShape fillinShape =
|
||||
BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE);
|
||||
|
||||
return fillinShape;
|
||||
}
|
||||
|
||||
// Create a body object in Bullet.
|
||||
// Updates prim.BSBody with the information about the new body if one is created.
|
||||
// Returns 'true' if an object was actually created.
|
||||
// Called at taint-time.
|
||||
private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape,
|
||||
private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
|
||||
ShapeData shapeData, BodyDestructionCallback bodyCallback)
|
||||
{
|
||||
bool ret = false;
|
||||
|
|
|
@ -114,6 +114,7 @@ public class BSTerrainManager
|
|||
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
|
||||
Vector3.Zero, Quaternion.Identity));
|
||||
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
|
||||
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
|
||||
// Ground plane does not move
|
||||
BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
|
||||
// Everything collides with the ground plane.
|
||||
|
@ -334,7 +335,8 @@ public class BSTerrainManager
|
|||
|
||||
// Make sure the new shape is processed.
|
||||
// BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
|
||||
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
||||
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
|
||||
// BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
|
||||
|
||||
m_terrainModified = true;
|
||||
};
|
||||
|
|
|
@ -223,6 +223,7 @@ public struct ShapeData
|
|||
KEY_SPHERE = 2,
|
||||
KEY_CONE = 3,
|
||||
KEY_CYLINDER = 4,
|
||||
KEY_CAPSULE = 5,
|
||||
}
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
@ -282,6 +283,7 @@ public struct ConfigurationParameters
|
|||
public float terrainHitFraction;
|
||||
public float terrainRestitution;
|
||||
public float avatarFriction;
|
||||
public float avatarStandingFriction;
|
||||
public float avatarDensity;
|
||||
public float avatarRestitution;
|
||||
public float avatarCapsuleRadius;
|
||||
|
@ -388,7 +390,7 @@ public enum CollisionFilterGroups : uint
|
|||
VolumeDetectMask = ~BSensorTrigger,
|
||||
TerrainFilter = BTerrainFilter,
|
||||
TerrainMask = BAllFilter & ~BStaticFilter,
|
||||
GroundPlaneFilter = BAllFilter,
|
||||
GroundPlaneFilter = BGroundPlaneFilter,
|
||||
GroundPlaneMask = BAllFilter
|
||||
|
||||
};
|
||||
|
@ -428,6 +430,7 @@ public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg
|
|||
[return: MarshalAs(UnmanagedType.LPStr)]
|
||||
public static extern string GetVersion();
|
||||
|
||||
/* Remove the linkage to the old api methods
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
|
||||
int maxCollisions, IntPtr collisionArray,
|
||||
|
@ -531,7 +534,7 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
|
|||
// ===============================================================================
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern void DumpBulletStatistics();
|
||||
|
||||
*/
|
||||
// Log a debug message
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern void SetDebugLogCallback(DebugLogCallback callback);
|
||||
|
@ -562,7 +565,8 @@ public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
|
|||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
|
||||
int maxCollisions, IntPtr collisionArray,
|
||||
int maxUpdates, IntPtr updateArray);
|
||||
int maxUpdates, IntPtr updateArray,
|
||||
DebugLogCallback logRoutine);
|
||||
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
|
||||
|
@ -603,6 +607,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
|
|||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern bool IsNativeShape2(IntPtr shape);
|
||||
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
|
||||
|
||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
|
||||
public static extern IntPtr CreateCompoundShape2(IntPtr sim);
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue