Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

0.7.5-pf-bulletsim
Justin Clark-Casey (justincc) 2012-12-14 23:29:33 +00:00
commit 2816551215
13 changed files with 442 additions and 304 deletions

View File

@ -167,9 +167,8 @@ public sealed class BSCharacter : BSPhysObject
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
// Do this after the object has been added to the world
BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr,
(uint)CollisionFilterGroups.AvatarGroup,
(uint)CollisionFilterGroups.AvatarMask);
PhysBody.collisionType = CollisionType.Avatar;
PhysBody.ApplyCollisionMask();
}
public override void RequestPhysicsterseUpdate()

View File

@ -124,7 +124,7 @@ public abstract class BSLinkset
get { return ComputeLinksetGeometricCenter(); }
}
protected void Initialize(BSScene scene, BSPhysObject parent)
protected BSLinkset(BSScene scene, BSPhysObject parent)
{
// A simple linkset of one (no children)
LinksetID = m_nextLinksetID++;
@ -135,6 +135,7 @@ public abstract class BSLinkset
LinksetRoot = parent;
m_children = new HashSet<BSPhysObject>();
m_mass = parent.RawMass;
Rebuilding = false;
}
// Link to a linkset where the child knows the parent.
@ -227,7 +228,7 @@ public abstract class BSLinkset
// I am the root of a linkset and a new child is being added
// Called while LinkActivity is locked.
protected abstract void AddChildToLinkset(BSPhysObject child);
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
protected abstract void RemoveChildFromLinkset(BSPhysObject child);
@ -237,6 +238,10 @@ public abstract class BSLinkset
// May be called at runtime or taint-time.
public abstract void Refresh(BSPhysObject requestor);
// Flag denoting the linkset is in the process of being rebuilt.
// Used to know not the schedule a rebuild in the middle of a rebuild.
protected bool Rebuilding { get; set; }
// The object is going dynamic (physical). Do any setup necessary
// for a dynamic linkset.
// Only the state of the passed object can be modified. The rest of the linkset

View File

@ -61,9 +61,8 @@ public sealed class BSLinksetCompound : BSLinkset
{
private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
public BSLinksetCompound(BSScene scene, BSPhysObject parent)
public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
{
base.Initialize(scene, parent);
}
// For compound implimented linksets, if there are children, use compound shape for the root.
@ -81,8 +80,6 @@ public sealed class BSLinksetCompound : BSLinkset
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
// This is queued in the 'post taint' queue so the
// refresh will happen once after all the other taints are applied.
public override void Refresh(BSPhysObject requestor)
{
// External request for Refresh (from BSPrim) doesn't need to do anything
@ -92,12 +89,18 @@ public sealed class BSLinksetCompound : BSLinkset
// Schedule a refresh to happen after all the other taint processing.
private void InternalRefresh(BSPhysObject requestor)
{
DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID);
PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1},rebuilding={2}",
LinksetRoot.LocalID, requestor.LocalID, Rebuilding);
// When rebuilding, it is possible to set properties that would normally require a rebuild.
// If already rebuilding, don't request another rebuild.
if (!Rebuilding)
{
if (IsRoot(requestor) && HasAnyChildren)
RecomputeLinksetCompound();
});
PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
{
if (IsRoot(requestor) && HasAnyChildren)
RecomputeLinksetCompound();
});
}
}
// The object is going dynamic (physical). Do any setup necessary
@ -114,6 +117,8 @@ public sealed class BSLinksetCompound : BSLinkset
{
// The root is going dynamic. Make sure mass is properly set.
m_mass = ComputeLinksetMass();
if (HasAnyChildren)
InternalRefresh(LinksetRoot);
}
else
{
@ -123,6 +128,9 @@ public sealed class BSLinksetCompound : BSLinkset
BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
// We don't want collisions from the old linkset children.
BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
child.PhysBody.collisionType = CollisionType.LinksetChild;
ret = true;
}
return ret;
@ -137,10 +145,18 @@ public sealed class BSLinksetCompound : BSLinkset
{
bool ret = false;
DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
if (!IsRoot(child))
if (IsRoot(child))
{
if (HasAnyChildren)
InternalRefresh(LinksetRoot);
}
else
{
// The non-physical children can come back to life.
BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
child.PhysBody.collisionType = CollisionType.LinksetChild;
// Don't force activation so setting of DISABLE_SIMULATION can stay if used.
BulletSimAPI.Activate2(child.PhysBody.ptr, false);
ret = true;
@ -182,19 +198,25 @@ public sealed class BSLinksetCompound : BSLinkset
// Because it is a convenient time, recompute child world position and rotation based on
// its position in the linkset.
RecomputeChildWorldPosition(child, true);
// Cause the current shape to be freed and the new one to be built.
InternalRefresh(LinksetRoot);
ret = true;
}
// Cannot schedule a refresh/rebuild here because this routine is called when
// the linkset is being rebuilt.
// InternalRefresh(LinksetRoot);
return ret;
}
// When the linkset is built, the child shape is added
// to the compound shape relative to the root shape. The linkset then moves around but
// this does not move the actual child prim. The child prim's location must be recomputed
// based on the location of the root shape.
// Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
// this routine will restore the removed constraints.
// Called at taint-time!!
public override void RestoreBodyDependencies(BSPrim child)
{
}
// When the linkset is built, the child shape is added to the compound shape relative to the
// root shape. The linkset then moves around but this does not move the actual child
// prim. The child prim's location must be recomputed based on the location of the root shape.
private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
{
BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
@ -227,14 +249,6 @@ public sealed class BSLinksetCompound : BSLinkset
}
}
// Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
// this routine will restore the removed constraints.
// Called at taint-time!!
public override void RestoreBodyDependencies(BSPrim child)
{
// The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
}
// ================================================================
// Add a new child to the linkset.
@ -254,7 +268,7 @@ public sealed class BSLinksetCompound : BSLinkset
}
// Remove the specified child from the linkset.
// Safe to call even if the child is not really in my linkset.
// Safe to call even if the child is not really in the linkset.
protected override void RemoveChildFromLinkset(BSPhysObject child)
{
if (m_children.Remove(child))
@ -289,74 +303,83 @@ public sealed class BSLinksetCompound : BSLinkset
// Called at taint time!!
private void RecomputeLinksetCompound()
{
// Cause the root shape to be rebuilt as a compound object with just the root in it
LinksetRoot.ForceBodyShapeRebuild(true);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
// Add a shape for each of the other children in the linkset
ForEachMember(delegate(BSPhysObject cPrim)
try
{
if (!IsRoot(cPrim))
// Suppress rebuilding while rebuilding
Rebuilding = true;
// Cause the root shape to be rebuilt as a compound object with just the root in it
LinksetRoot.ForceBodyShapeRebuild(true);
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
// Add a shape for each of the other children in the linkset
ForEachMember(delegate(BSPhysObject cPrim)
{
// Compute the displacement of the child from the root of the linkset.
// This info is saved in the child prim so the relationship does not
// change over time and the new child position can be computed
// when the linkset is being disassembled (the linkset may have moved).
BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
if (lci == null)
if (!IsRoot(cPrim))
{
// Each child position and rotation is given relative to the root.
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
// Save relative position for recomputing child's world position after moving linkset.
lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
cPrim.LinksetInfo = lci;
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
}
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
if (cPrim.PhysShape.isNativeShape)
{
// A native shape is turning into a hull collision shape because native
// shapes are not shared so we have to hullify it so it will be tracked
// and freed at the correct time. This also solves the scaling problem
// (native shapes scaled but hull/meshes are assumed to not be).
// TODO: decide of the native shape can just be used in the compound shape.
// Use call to CreateGeomNonSpecial().
BulletShape saveShape = cPrim.PhysShape;
cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
// PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
BulletShape newShape = cPrim.PhysShape;
cPrim.PhysShape = saveShape;
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos , lci.OffsetRot);
}
else
{
// For the shared shapes (meshes and hulls), just use the shape in the child.
// The reference count added here will be decremented when the compound shape
// is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
// Compute the displacement of the child from the root of the linkset.
// This info is saved in the child prim so the relationship does not
// change over time and the new child position can be computed
// when the linkset is being disassembled (the linkset may have moved).
BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
if (lci == null)
{
PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
// Each child position and rotation is given relative to the root.
OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
// Save relative position for recomputing child's world position after moving linkset.
lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
cPrim.LinksetInfo = lci;
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
}
DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
if (cPrim.PhysShape.isNativeShape)
{
// A native shape is turning into a hull collision shape because native
// shapes are not shared so we have to hullify it so it will be tracked
// and freed at the correct time. This also solves the scaling problem
// (native shapes scaled but hull/meshes are assumed to not be).
// TODO: decide of the native shape can just be used in the compound shape.
// Use call to CreateGeomNonSpecial().
BulletShape saveShape = cPrim.PhysShape;
cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
// PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
BulletShape newShape = cPrim.PhysShape;
cPrim.PhysShape = saveShape;
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot);
}
else
{
// For the shared shapes (meshes and hulls), just use the shape in the child.
// The reference count added here will be decremented when the compound shape
// is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
{
PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
}
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot);
}
BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos , lci.OffsetRot);
}
}
return false; // 'false' says to move onto the next child in the list
});
return false; // 'false' says to move onto the next child in the list
});
// With all of the linkset packed into the root prim, it has the mass of everyone.
float linksetMass = LinksetMass;
LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
// With all of the linkset packed into the root prim, it has the mass of everyone.
float linksetMass = LinksetMass;
LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
}
finally
{
Rebuilding = false;
}
BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);

View File

@ -36,9 +36,8 @@ public sealed class BSLinksetConstraints : BSLinkset
{
// private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
{
base.Initialize(scene, parent);
}
// When physical properties are changed the linkset needs to recalculate

View File

@ -661,14 +661,7 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
// Collision filter can be set only when the object is in the world
if (PhysBody.collisionGroup != 0 || PhysBody.collisionMask != 0)
{
if (!BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, (uint)PhysBody.collisionGroup, (uint)PhysBody.collisionMask))
{
PhysicsScene.Logger.ErrorFormat("{0} Failure setting prim collision mask. localID={1}, grp={2:X}, mask={3:X}",
LogHeader, LocalID, PhysBody.collisionGroup, PhysBody.collisionMask);
}
}
PhysBody.ApplyCollisionMask();
// Recompute any linkset parameters.
// When going from non-physical to physical, this re-enables the constraints that
@ -713,11 +706,11 @@ public sealed class BSPrim : BSPhysObject
// Start it out sleeping and physical actions could wake it up.
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING);
// This collides like a static object
PhysBody.collisionType = CollisionType.Static;
// There can be special things needed for implementing linksets
Linkset.MakeStatic(this);
PhysBody.collisionGroup = CollisionFilterGroups.StaticObjectGroup;
PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
}
else
{
@ -755,16 +748,15 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
// There might be special things needed for implementing linksets.
Linkset.MakeDynamic(this);
// This collides like an object.
PhysBody.collisionType = CollisionType.Dynamic;
// Force activation of the object so Bullet will act on it.
// Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
// BulletSimAPI.Activate2(BSBody.ptr, true);
PhysBody.collisionGroup = CollisionFilterGroups.ObjectGroup;
PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
// There might be special things needed for implementing linksets.
Linkset.MakeDynamic(this);
}
}
@ -791,8 +783,9 @@ public sealed class BSPrim : BSPhysObject
m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
}
CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
PhysBody.collisionGroup = CollisionFilterGroups.VolumeDetectGroup;
PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
// Change collision info from a static object to a ghosty collision object
PhysBody.collisionType = CollisionType.VolumeDetect;
}
}

View File

@ -121,9 +121,8 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
// redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
BulletSimAPI.SetCollisionGroupMask2(m_mapInfo.terrainBody.ptr,
(uint)CollisionFilterGroups.TerrainGroup,
(uint)CollisionFilterGroups.TerrainMask);
m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
m_mapInfo.terrainBody.ApplyCollisionMask();
// Make it so the terrain will not move or be considered for movement.
BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);

View File

@ -140,8 +140,8 @@ public sealed class BSTerrainManager
// Ground plane does not move
BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
// Everything collides with the ground plane.
BulletSimAPI.SetCollisionGroupMask2(m_groundPlane.ptr,
(uint)CollisionFilterGroups.GroundPlaneGroup, (uint)CollisionFilterGroups.GroundPlaneMask);
m_groundPlane.collisionType = CollisionType.Groundplane;
m_groundPlane.ApplyCollisionMask();
// Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);

View File

@ -130,9 +130,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
BulletSimAPI.SetCollisionGroupMask2(m_terrainBody.ptr,
(uint)CollisionFilterGroups.TerrainGroup,
(uint)CollisionFilterGroups.TerrainMask);
m_terrainBody.collisionType = CollisionType.Terrain;
m_terrainBody.ApplyCollisionMask();
// Make it so the terrain will not move or be considered for movement.
BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);

View File

@ -25,6 +25,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
@ -32,110 +33,6 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin {
// Classes to allow some type checking for the API
// These hold pointers to allocated objects in the unmanaged space.
// The physics engine controller class created at initialization
public struct BulletSim
{
public BulletSim(uint worldId, BSScene bss, IntPtr xx)
{
ptr = xx;
worldID = worldId;
physicsScene = bss;
}
public IntPtr ptr;
public uint worldID;
// The scene is only in here so very low level routines have a handle to print debug/error messages
public BSScene physicsScene;
}
// An allocated Bullet btRigidBody
public struct BulletBody
{
public BulletBody(uint id) : this(id, IntPtr.Zero)
{
}
public BulletBody(uint id, IntPtr xx)
{
ID = id;
ptr = xx;
collisionGroup = 0;
collisionMask = 0;
}
public IntPtr ptr;
public uint ID;
public CollisionFilterGroups collisionGroup;
public CollisionFilterGroups collisionMask;
public void Clear()
{
ptr = IntPtr.Zero;
}
public bool HasPhysicalBody { get { return ptr != IntPtr.Zero; } }
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<id=");
buff.Append(ID.ToString());
buff.Append(",p=");
buff.Append(ptr.ToString("X"));
if (collisionGroup != 0 || collisionMask != 0)
{
buff.Append(",g=");
buff.Append(collisionGroup.ToString("X"));
buff.Append(",m=");
buff.Append(collisionMask.ToString("X"));
}
buff.Append(">");
return buff.ToString();
}
}
public struct BulletShape
{
public BulletShape(IntPtr xx)
{
ptr = xx;
type=BSPhysicsShapeType.SHAPE_UNKNOWN;
shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
isNativeShape = false;
}
public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
{
ptr = xx;
type = typ;
shapeKey = 0;
isNativeShape = false;
}
public IntPtr ptr;
public BSPhysicsShapeType type;
public System.UInt64 shapeKey;
public bool isNativeShape;
public void Clear()
{
ptr = IntPtr.Zero;
}
public bool HasPhysicalShape { get { return ptr != IntPtr.Zero; } }
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<p=");
buff.Append(ptr.ToString("X"));
buff.Append(",s=");
buff.Append(type.ToString());
buff.Append(",k=");
buff.Append(shapeKey.ToString("X"));
buff.Append(",n=");
buff.Append(isNativeShape.ToString());
buff.Append(">");
return buff.ToString();
}
}
// Constraint type values as defined by Bullet
public enum ConstraintType : int
{
@ -149,50 +46,6 @@ public enum ConstraintType : int
MAX_CONSTRAINT_TYPE
}
// An allocated Bullet btConstraint
public struct BulletConstraint
{
public BulletConstraint(IntPtr xx)
{
ptr = xx;
}
public IntPtr ptr;
public void Clear()
{
ptr = IntPtr.Zero;
}
public bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } }
}
// An allocated HeightMapThing which holds various heightmap info.
// Made a class rather than a struct so there would be only one
// instance of this and C# will pass around pointers rather
// than making copies.
public class BulletHeightMapInfo
{
public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
ID = id;
Ptr = xx;
heightMap = hm;
terrainRegionBase = Vector3.Zero;
minCoords = new Vector3(100f, 100f, 25f);
maxCoords = new Vector3(101f, 101f, 26f);
minZ = maxZ = 0f;
sizeX = sizeY = 256f;
}
public uint ID;
public IntPtr Ptr;
public float[] heightMap;
public Vector3 terrainRegionBase;
public Vector3 minCoords;
public Vector3 maxCoords;
public float sizeX, sizeY;
public float minZ, maxZ;
public BulletShape terrainShape;
public BulletBody terrainBody;
}
// ===============================================================================
[StructLayout(LayoutKind.Sequential)]
public struct ConvexHull
@ -385,21 +238,15 @@ public enum CollisionFlags : uint
BS_FLOATS_ON_WATER = 1 << 11,
BS_VEHICLE_COLLISIONS = 1 << 12,
BS_NONE = 0,
BS_ALL = 0xFFFFFFFF,
// These are the collision flags switched depending on physical state.
// The other flags are used for other things and should not be fooled with.
BS_ACTIVE = CF_STATIC_OBJECT
| CF_KINEMATIC_OBJECT
| CF_NO_CONTACT_RESPONSE
BS_ALL = 0xFFFFFFFF
};
// Values for collisions groups and masks
// Values f collisions groups and masks
public enum CollisionFilterGroups : uint
{
// Don't use the bit definitions!! Define the use in a
// filter/mask definition below. This way collision interactions
// are more easily debugged.
// are more easily found and debugged.
BNoneGroup = 0,
BDefaultGroup = 1 << 0,
BStaticGroup = 1 << 1,
@ -413,24 +260,8 @@ public enum CollisionFilterGroups : uint
BTerrainGroup = 1 << 11,
BRaycastGroup = 1 << 12,
BSolidGroup = 1 << 13,
BLinksetGroup = 1 << 14,
// The collsion filters and masked are defined in one place -- don't want them scattered
AvatarGroup = BCharacterGroup,
AvatarMask = BAllGroup,
ObjectGroup = BSolidGroup,
ObjectMask = BAllGroup,
StaticObjectGroup = BStaticGroup,
StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
LinksetGroup = BLinksetGroup,
LinksetMask = BAllGroup & ~BLinksetGroup, // linkset objects don't collide with each other
VolumeDetectGroup = BSensorTrigger,
VolumeDetectMask = ~BSensorTrigger,
TerrainGroup = BTerrainGroup,
TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
GroundPlaneGroup = BGroundPlaneGroup,
GroundPlaneMask = BAllGroup
// BLinksetGroup = xx // a linkset proper is either static or dynamic
BLinksetChildGroup = 1 << 14,
};
// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
@ -457,7 +288,7 @@ public enum ConstraintParamAxis : int
// ===============================================================================
static class BulletSimAPI {
// ===============================================================================
// Link back to the managed code for outputting log messages
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);

View File

@ -0,0 +1,278 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
// Classes to allow some type checking for the API
// These hold pointers to allocated objects in the unmanaged space.
// The physics engine controller class created at initialization
public struct BulletSim
{
public BulletSim(uint worldId, BSScene bss, IntPtr xx)
{
ptr = xx;
worldID = worldId;
physicsScene = bss;
}
public IntPtr ptr;
public uint worldID;
// The scene is only in here so very low level routines have a handle to print debug/error messages
public BSScene physicsScene;
}
// An allocated Bullet btRigidBody
public struct BulletBody
{
public BulletBody(uint id) : this(id, IntPtr.Zero)
{
}
public BulletBody(uint id, IntPtr xx)
{
ID = id;
ptr = xx;
collisionType = CollisionType.Static;
}
public IntPtr ptr;
public uint ID;
public CollisionType collisionType;
public void Clear()
{
ptr = IntPtr.Zero;
}
public bool HasPhysicalBody { get { return ptr != IntPtr.Zero; } }
// Apply the specificed collision mask into the physical world
public void ApplyCollisionMask()
{
// Should assert the body has been added to the physical world.
// (The collision masks are stored in the collision proxy cache which only exists for
// a collision body that is in the world.)
BulletSimAPI.SetCollisionGroupMask2(ptr,
BulletSimData.CollisionTypeMasks[collisionType].group,
BulletSimData.CollisionTypeMasks[collisionType].mask);
}
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<id=");
buff.Append(ID.ToString());
buff.Append(",p=");
buff.Append(ptr.ToString("X"));
buff.Append(",c=");
buff.Append(collisionType);
buff.Append(">");
return buff.ToString();
}
}
public struct BulletShape
{
public BulletShape(IntPtr xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN)
{
}
public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
{
ptr = xx;
type = typ;
shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
isNativeShape = false;
}
public IntPtr ptr;
public BSPhysicsShapeType type;
public System.UInt64 shapeKey;
public bool isNativeShape;
public void Clear()
{
ptr = IntPtr.Zero;
}
public bool HasPhysicalShape { get { return ptr != IntPtr.Zero; } }
public override string ToString()
{
StringBuilder buff = new StringBuilder();
buff.Append("<p=");
buff.Append(ptr.ToString("X"));
buff.Append(",s=");
buff.Append(type.ToString());
buff.Append(",k=");
buff.Append(shapeKey.ToString("X"));
buff.Append(",n=");
buff.Append(isNativeShape.ToString());
buff.Append(">");
return buff.ToString();
}
}
// An allocated Bullet btConstraint
public struct BulletConstraint
{
public BulletConstraint(IntPtr xx)
{
ptr = xx;
}
public IntPtr ptr;
public void Clear()
{
ptr = IntPtr.Zero;
}
public bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } }
}
// An allocated HeightMapThing which holds various heightmap info.
// Made a class rather than a struct so there would be only one
// instance of this and C# will pass around pointers rather
// than making copies.
public class BulletHeightMapInfo
{
public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
ID = id;
Ptr = xx;
heightMap = hm;
terrainRegionBase = OMV.Vector3.Zero;
minCoords = new OMV.Vector3(100f, 100f, 25f);
maxCoords = new OMV.Vector3(101f, 101f, 26f);
minZ = maxZ = 0f;
sizeX = sizeY = 256f;
}
public uint ID;
public IntPtr Ptr;
public float[] heightMap;
public OMV.Vector3 terrainRegionBase;
public OMV.Vector3 minCoords;
public OMV.Vector3 maxCoords;
public float sizeX, sizeY;
public float minZ, maxZ;
public BulletShape terrainShape;
public BulletBody terrainBody;
}
// The general class of collsion object.
public enum CollisionType
{
Avatar,
Groundplane,
Terrain,
Static,
Dynamic,
VolumeDetect,
// Linkset, // A linkset should be either Static or Dynamic
LinksetChild,
Unknown
};
// Hold specification of group and mask collision flags for a CollisionType
public struct CollisionTypeFilterGroup
{
public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
{
type = t;
group = g;
mask = m;
}
public CollisionType type;
public uint group;
public uint mask;
};
/* NOTE: old definitions kept for reference. Delete when things are working.
// The collsion filters and masked are defined in one place -- don't want them scattered
AvatarGroup = BCharacterGroup,
AvatarMask = BAllGroup,
ObjectGroup = BSolidGroup,
ObjectMask = BAllGroup,
StaticObjectGroup = BStaticGroup,
StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much
LinksetGroup = BLinksetGroup,
LinksetMask = BAllGroup,
LinksetChildGroup = BLinksetChildGroup,
LinksetChildMask = BNoneGroup, // Linkset children disappear from the world
VolumeDetectGroup = BSensorTrigger,
VolumeDetectMask = ~BSensorTrigger,
TerrainGroup = BTerrainGroup,
TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide
GroundPlaneGroup = BGroundPlaneGroup,
GroundPlaneMask = BAllGroup
*/
public static class BulletSimData
{
// Map of collisionTypes to flags for collision groups and masks.
// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
// but, instead, use references to this dictionary. Finding and debugging
// collision flag problems will be made easier.
public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
= new Dictionary<CollisionType, CollisionTypeFilterGroup>()
{
{ CollisionType.Avatar,
new CollisionTypeFilterGroup(CollisionType.Avatar,
(uint)CollisionFilterGroups.BCharacterGroup,
(uint)CollisionFilterGroups.BAllGroup)
},
{ CollisionType.Groundplane,
new CollisionTypeFilterGroup(CollisionType.Groundplane,
(uint)CollisionFilterGroups.BGroundPlaneGroup,
(uint)CollisionFilterGroups.BAllGroup)
},
{ CollisionType.Terrain,
new CollisionTypeFilterGroup(CollisionType.Terrain,
(uint)CollisionFilterGroups.BTerrainGroup,
(uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
},
{ CollisionType.Static,
new CollisionTypeFilterGroup(CollisionType.Static,
(uint)CollisionFilterGroups.BStaticGroup,
(uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
},
{ CollisionType.Dynamic,
new CollisionTypeFilterGroup(CollisionType.Dynamic,
(uint)CollisionFilterGroups.BSolidGroup,
(uint)(CollisionFilterGroups.BAllGroup))
},
{ CollisionType.VolumeDetect,
new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
(uint)CollisionFilterGroups.BSensorTrigger,
(uint)(~CollisionFilterGroups.BSensorTrigger))
},
{ CollisionType.LinksetChild,
new CollisionTypeFilterGroup(CollisionType.LinksetChild,
(uint)CollisionFilterGroups.BTerrainGroup,
(uint)(CollisionFilterGroups.BNoneGroup))
},
};
}
}

View File

@ -19,6 +19,7 @@ Some vehicles should not be able to turn if no speed or off ground.
Neb car jiggling left and right
Happens on terrain and any other mesh object. Flat cubes are much smoother.
This has been reduced but not eliminated.
Light cycle falling over when driving
For limitMotorUp, use raycast down to find if vehicle is in the air.
Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
Verify that angular motion specified around Z moves in the vehicle coordinates.
@ -121,6 +122,9 @@ Remove unused fields from ShapeData (not used in API2)
Breakout code for mesh/hull/compound/native into separate BSShape* classes
Standardize access to building and reference code.
The skeleton classes are in the sources but are not complete or linked in.
Make BSBody and BSShape real classes to centralize creation/changin/destruction
Convert state and parameter calls from BulletSimAPI direct calls to
calls on BSBody and BSShape
Generalize Dynamics and PID with standardized motors.
Generalize Linkset and vehicles into PropertyManagers
Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
@ -132,7 +136,7 @@ Implement linkset by setting position of children when root updated. (LinksetMan
Linkset implementation using manual prim movement.
LinkablePrim class? Would that simplify/centralize the linkset logic?
BSScene.UpdateParameterSet() is broken. How to set params on objects?
Remove HeightmapInfo from terrain specification.
Remove HeightmapInfo from terrain specification
Since C++ code does not need terrain height, this structure et al are not needed.
Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
bob at the water level. BSPrim.PositionSanityCheck().
@ -164,7 +168,6 @@ Do prim hash codes work for sculpties and meshes? (Resolution: yes)
Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
Compound shapes will need the LocalID in the shapes and collision
processing to get it from there.
Light cycle falling over when driving (Resolution: implemented VerticalAttractor)
Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
Package Bullet source mods for Bullet internal stats output
(Resolution: move code into WorldData.h rather than relying on patches)

View File

@ -250,17 +250,20 @@ namespace OpenSim.Region.Physics.Manager
public abstract Vector3 CenterOfMass { get; }
/// <summary>
/// Velocity of this actor.
/// The desired velocity of this actor.
/// </summary>
/// <remarks>
/// Setting this provides a target velocity for physics scene updates.
/// Getting this returns the velocity calculated by physics scene updates, using factors such as target velocity,
/// time to accelerate and collisions.
/// Getting this returns the last set target. Fetch Velocity to get the current velocity.
/// </remarks>
protected Vector3 m_targetVelocity;
public virtual Vector3 TargetVelocity
{
get { return Velocity; }
set { Velocity = value; }
get { return m_targetVelocity; }
set {
m_targetVelocity = value;
Velocity = m_targetVelocity;
}
}
public abstract Vector3 Velocity { get; set; }

View File

@ -32,9 +32,15 @@
<appender-ref ref="LogFileAppender" />
</root>
<!-- Independently control logging level for XEngine -->
<logger name="OpenSim.Region.ScriptEngine.XEngine">
<level value="INFO"/>
</logger>
<!-- Independently control logging level for per region module loading -->
<logger name="OpenSim.ApplicationPlugins.RegionModulesController.RegionModulesControllerPlugin">
<level value="INFO"/>
</logger>
</log4net>
</configuration>