ubitODE + physmanager: - Revised use of ODE collisions categories and bits(flags) for better use as filters together with top spaces (for example physical prims are on topactivespace and not physical are on topstaticspace) - Added new world raycast with filters. This blocks calling thread with a timeout of 500ms waiting for heartbeat ode thread signal job done. - Don't let ode bodies being disabled for 2 long except for vehicles. This is necessary to detect when the object is at rest at top of other and that is removed. Assume that vehicles can be enabled by used action.

avinationmerge
UbitUmarov 2012-04-16 16:16:55 +01:00
parent 3999822e13
commit 86a2169d73
7 changed files with 1030 additions and 776 deletions

View File

@ -172,6 +172,12 @@ namespace OpenSim.Region.Physics.Manager
public virtual bool Phantom { get; set; }
public virtual bool IsVolumeDtc
{
get { return false; }
set { return; }
}
public virtual byte PhysicsShapeType { get; set; }
public abstract PrimitiveBaseShape Shape { set; }

View File

@ -43,6 +43,34 @@ namespace OpenSim.Region.Physics.Manager
public delegate void JointDeactivated(PhysicsJoint joint);
public delegate void JointErrorMessage(PhysicsJoint joint, string message); // this refers to an "error message due to a problem", not "amount of joint constraint violation"
public enum RayFilterFlags:ushort
{
// the flags
water = 0x01,
land = 0x02,
agent = 0x04,
nonphysical = 0x08,
physical = 0x10,
phantom = 0x20,
volumedtc = 0x40,
// ray cast colision control (may only work for meshs)
BackFaceCull = 0x4000,
ClosestHit = 0x8000,
// some combinations
LSLPhanton = phantom | volumedtc,
PrimsNonPhantom = nonphysical | physical,
PrimsNonPhantomAgents = nonphysical | physical | agent,
AllPrims = nonphysical | phantom | volumedtc | physical,
AllButLand = agent | nonphysical | physical | phantom | volumedtc,
ClosestAndBackCull = ClosestHit | BackFaceCull,
All = 0x3f
}
/// <summary>
/// Contact result from a raycast.
/// </summary>
@ -54,6 +82,8 @@ namespace OpenSim.Region.Physics.Manager
public Vector3 Normal;
}
public abstract class PhysicsScene
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@ -280,6 +310,16 @@ namespace OpenSim.Region.Physics.Manager
return new List<ContactResult>();
}
public virtual object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
{
return null;
}
public virtual bool SuportsRaycastWorldFiltered()
{
return false;
}
public virtual void RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, RaycastCallback retMethod){}
public virtual void RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) { }
public virtual List<ContactResult> RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, int Count)

View File

@ -115,12 +115,10 @@ namespace OpenSim.Region.Physics.OdePlugin
private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
// Default, Collide with Other Geometries, spaces, bodies and characters.
private CollisionCategories m_collisionFlags = (CollisionCategories.Geom
| CollisionCategories.Space
| CollisionCategories.Body
| CollisionCategories.Character
private CollisionCategories m_collisionFlags = (CollisionCategories.Character
| CollisionCategories.Geom
);
// we do land collisions not ode | CollisionCategories.Land);
// we do land collisions not ode | CollisionCategories.Land);
public IntPtr Body = IntPtr.Zero;
private OdeScene _parent_scene;
public IntPtr Shell = IntPtr.Zero;
@ -639,6 +637,8 @@ namespace OpenSim.Region.Physics.OdePlugin
public override void SetMomentum(Vector3 momentum)
{
if (momentum.IsFinite())
AddChange(changes.Momentum, momentum);
}
@ -663,8 +663,8 @@ namespace OpenSim.Region.Physics.OdePlugin
}
Shell = d.CreateCapsule(_parent_scene.ActiveSpace, CAPSULE_RADIUS, CAPSULE_LENGTH);
d.GeomSetCategoryBits(Shell, (int)m_collisionCategories);
d.GeomSetCollideBits(Shell, (int)m_collisionFlags);
d.GeomSetCategoryBits(Shell, (uint)m_collisionCategories);
d.GeomSetCollideBits(Shell, (uint)m_collisionFlags);
d.MassSetCapsule(out ShellMass, m_density, 3, CAPSULE_RADIUS, CAPSULE_LENGTH);
@ -759,7 +759,6 @@ namespace OpenSim.Region.Physics.OdePlugin
_parent_scene.geom_name_map.Remove(Shell);
_parent_scene.waitForSpaceUnlock(_parent_scene.ActiveSpace);
d.GeomDestroy(Shell);
_parent_scene.geom_name_map.Remove(Shell);
Shell = IntPtr.Zero;
}
}
@ -1324,6 +1323,16 @@ namespace OpenSim.Region.Physics.OdePlugin
}
}
// for now momentum is actually velocity
private void changeMomentum(Vector3 newmomentum)
{
_velocity = newmomentum;
_target_velocity = newmomentum;
m_pidControllerActive = true;
if (Body != IntPtr.Zero)
d.BodySetLinearVel(Body, newmomentum.X, newmomentum.Y, newmomentum.Z);
}
private void donullchange()
{
}
@ -1395,6 +1404,10 @@ namespace OpenSim.Region.Physics.OdePlugin
case changes.Size:
changeSize((Vector3)arg);
break;
case changes.Momentum:
changeMomentum((Vector3)arg);
break;
/* not in use for now
case changes.Shape:
changeShape((PrimitiveBaseShape)arg);

File diff suppressed because it is too large Load Diff

View File

@ -30,10 +30,11 @@ using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
using OdeAPI;
using log4net;
using OpenMetaverse;
namespace OpenSim.Region.Physics.OdePlugin
{
@ -54,9 +55,11 @@ namespace OpenSim.Region.Physics.OdePlugin
/// </summary>
private OdeScene m_scene;
IntPtr ray;
IntPtr ray; // the ray. we only need one for our lifetime
private const int ColisionContactGeomsPerTest = 5;
private const int DefaultMaxCount = 25;
private const int MaxTimePerCallMS = 30;
/// <summary>
/// ODE near callback delegate
@ -64,19 +67,22 @@ namespace OpenSim.Region.Physics.OdePlugin
private d.NearCallback nearCallback;
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private List<ContactResult> m_contactResults = new List<ContactResult>();
private RayFilterFlags CurrentRayFilter;
private int CurrentMaxCount;
public ODERayCastRequestManager(OdeScene pScene)
{
m_scene = pScene;
nearCallback = near;
ray = d.CreateRay(IntPtr.Zero, 1.0f);
d.GeomSetCategoryBits(ray,0);
}
/// <summary>
/// Queues a raycast
/// Queues request for a raycast to all world
/// </summary>
/// <param name="position">Origin of Ray</param>
/// <param name="direction">Ray normal</param>
/// <param name="direction">Ray direction</param>
/// <param name="length">Ray length</param>
/// <param name="retMethod">Return method to send the results</param>
public void QueueRequest(Vector3 position, Vector3 direction, float length, RayCallback retMethod)
@ -84,14 +90,22 @@ namespace OpenSim.Region.Physics.OdePlugin
ODERayRequest req = new ODERayRequest();
req.geom = IntPtr.Zero;
req.callbackMethod = retMethod;
req.Count = 0;
req.Count = DefaultMaxCount;
req.length = length;
req.Normal = direction;
req.Origin = position;
req.filter = RayFilterFlags.AllButLand;
m_PendingRequests.Enqueue(req);
}
/// <summary>
/// Queues request for a raycast to particular part
/// </summary>
/// <param name="position">Origin of Ray</param>
/// <param name="direction">Ray direction</param>
/// <param name="length">Ray length</param>
/// <param name="retMethod">Return method to send the results</param>
public void QueueRequest(IntPtr geom, Vector3 position, Vector3 direction, float length, RayCallback retMethod)
{
ODERayRequest req = new ODERayRequest();
@ -100,7 +114,8 @@ namespace OpenSim.Region.Physics.OdePlugin
req.length = length;
req.Normal = direction;
req.Origin = position;
req.Count = 0;
req.Count = DefaultMaxCount;
req.filter = RayFilterFlags.AllButLand;
m_PendingRequests.Enqueue(req);
}
@ -110,10 +125,11 @@ namespace OpenSim.Region.Physics.OdePlugin
ODERayRequest req = new ODERayRequest();
req.geom = IntPtr.Zero;
req.callbackMethod = retMethod;
req.Count = 0;
req.Count = DefaultMaxCount;
req.length = length;
req.Normal = direction;
req.Origin = position;
req.filter = RayFilterFlags.AllButLand;
m_PendingRequests.Enqueue(req);
}
@ -126,7 +142,8 @@ namespace OpenSim.Region.Physics.OdePlugin
req.length = length;
req.Normal = direction;
req.Origin = position;
req.Count = 0;
req.Count = DefaultMaxCount;
req.filter = RayFilterFlags.AllButLand;
m_PendingRequests.Enqueue(req);
}
@ -148,6 +165,22 @@ namespace OpenSim.Region.Physics.OdePlugin
req.Normal = direction;
req.Origin = position;
req.Count = count;
req.filter = RayFilterFlags.AllButLand;
m_PendingRequests.Enqueue(req);
}
public void QueueRequest(Vector3 position, Vector3 direction, float length, int count,RayFilterFlags filter , RayCallback retMethod)
{
ODERayRequest req = new ODERayRequest();
req.geom = IntPtr.Zero;
req.callbackMethod = retMethod;
req.length = length;
req.Normal = direction;
req.Origin = position;
req.Count = count;
req.filter = filter;
m_PendingRequests.Enqueue(req);
}
@ -161,6 +194,7 @@ namespace OpenSim.Region.Physics.OdePlugin
req.Normal = direction;
req.Origin = position;
req.Count = count;
req.filter = RayFilterFlags.AllButLand;
m_PendingRequests.Enqueue(req);
}
@ -174,6 +208,7 @@ namespace OpenSim.Region.Physics.OdePlugin
req.Normal = direction;
req.Origin = position;
req.Count = count;
req.filter = RayFilterFlags.AllButLand;
m_PendingRequests.Enqueue(req);
}
@ -187,6 +222,7 @@ namespace OpenSim.Region.Physics.OdePlugin
req.Normal = direction;
req.Origin = position;
req.Count = count;
req.filter = RayFilterFlags.AllButLand;
m_PendingRequests.Enqueue(req);
}
@ -197,63 +233,104 @@ namespace OpenSim.Region.Physics.OdePlugin
/// <returns>Time in MS the raycasts took to process.</returns>
public int ProcessQueuedRequests()
{
int time = System.Environment.TickCount;
if (m_PendingRequests.Count <= 0)
return 0;
if (m_scene.ContactgeomsArray == IntPtr.Zero) // oops something got wrong or scene isn't ready still
if (m_scene.ContactgeomsArray == IntPtr.Zero || ray == IntPtr.Zero)
// oops something got wrong or scene isn't ready still
{
m_PendingRequests.Clear();
return 0;
}
int time = Util.EnvironmentTickCount();
ODERayRequest req;
int closestHit;
int backfacecull;
CollisionCategories catflags;
int i = 50; // arbitary limit of processed tests per frame
while(m_PendingRequests.Dequeue(out req))
while (m_PendingRequests.Dequeue(out req))
{
if (req.geom == IntPtr.Zero)
doSpaceRay(req);
else
doGeomRay(req);
if(--i < 0)
break;
if (req.callbackMethod != null)
{
CurrentRayFilter = req.filter;
CurrentMaxCount = req.Count;
closestHit = ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0 ? 0 : 1);
backfacecull = ((CurrentRayFilter & RayFilterFlags.BackFaceCull) == 0 ? 0 : 1);
d.GeomRaySetLength(ray, req.length);
d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
d.GeomRaySetParams(ray, 0, backfacecull);
d.GeomRaySetClosestHit(ray, closestHit);
if (req.callbackMethod is RaycastCallback)
// if we only want one get only one per colision pair saving memory
CurrentRayFilter |= RayFilterFlags.ClosestHit;
if (req.geom == IntPtr.Zero)
{
// translate ray filter to colision flags
catflags = 0;
if ((CurrentRayFilter & RayFilterFlags.volumedtc) != 0)
catflags |= CollisionCategories.VolumeDtc;
if ((CurrentRayFilter & RayFilterFlags.phantom) != 0)
catflags |= CollisionCategories.Phantom;
if ((CurrentRayFilter & RayFilterFlags.agent) != 0)
catflags |= CollisionCategories.Character;
if ((CurrentRayFilter & RayFilterFlags.PrimsNonPhantom) != 0)
catflags |= CollisionCategories.Geom;
if ((CurrentRayFilter & RayFilterFlags.land) != 0)
catflags |= CollisionCategories.Land;
if ((CurrentRayFilter & RayFilterFlags.water) != 0)
catflags |= CollisionCategories.Water;
if (catflags != 0)
doSpaceRay(req);
}
else
{
// if we select a geom don't use filters
d.GeomSetCollideBits(ray, (uint)CollisionCategories.All);
doGeomRay(req);
}
}
if (Util.EnvironmentTickCountSubtract(time) > MaxTimePerCallMS)
break;
}
lock (m_contactResults)
m_contactResults.Clear();
return System.Environment.TickCount - time;
return Util.EnvironmentTickCountSubtract(time);
}
/// <summary>
/// Method that actually initiates the raycast with full top space
/// Method that actually initiates the raycast with spaces
/// </summary>
/// <param name="req"></param>
///
private const RayFilterFlags FilterActiveSpace = RayFilterFlags.agent | RayFilterFlags.physical | RayFilterFlags.LSLPhanton;
private const RayFilterFlags FilterStaticSpace = RayFilterFlags.water | RayFilterFlags.land | RayFilterFlags.nonphysical | RayFilterFlags.LSLPhanton;
private void doSpaceRay(ODERayRequest req)
{
// Create the ray
// IntPtr ray = d.CreateRay(m_scene.TopSpace, req.length);
d.GeomRaySetLength(ray, req.length);
d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
// Collide test
d.SpaceCollide2(m_scene.TopSpace, ray, IntPtr.Zero, nearCallback);
// Remove Ray
// d.GeomDestroy(ray);
if (req.callbackMethod == null)
return;
// Collide tests
if ((CurrentRayFilter & FilterActiveSpace) != 0)
d.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
d.SpaceCollide2(ray, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
if (req.callbackMethod is RaycastCallback)
{
// Define default results
bool hitYN = false;
uint hitConsumerID = 0;
float distance = 999999999999f;
Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
float distance = float.MaxValue;
Vector3 closestcontact = Vector3.Zero;
Vector3 snormal = Vector3.Zero;
// Find closest contact and object.
@ -261,25 +338,30 @@ namespace OpenSim.Region.Physics.OdePlugin
{
foreach (ContactResult cResult in m_contactResults)
{
if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
if(cResult.Depth < distance)
{
closestcontact = cResult.Pos;
hitConsumerID = cResult.ConsumerID;
distance = cResult.Depth;
hitYN = true;
snormal = cResult.Normal;
}
}
m_contactResults.Clear();
}
if (distance > 0 && distance < float.MaxValue)
hitYN = true;
((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
}
else
{
((RayCallback)req.callbackMethod)(m_contactResults);
List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
lock (m_PendingRequests)
{
cresult.AddRange(m_contactResults);
m_contactResults.Clear();
}
((RayCallback)req.callbackMethod)(cresult);
}
}
@ -289,27 +371,16 @@ namespace OpenSim.Region.Physics.OdePlugin
/// <param name="req"></param>
private void doGeomRay(ODERayRequest req)
{
// Create the ray
// IntPtr ray = d.CreateRay(m_scene.TopSpace, req.length);
d.GeomRaySetLength(ray, req.length);
d.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
// Collide test
d.SpaceCollide2(req.geom, ray, IntPtr.Zero, nearCallback); // still do this to have full AABB pre test
// Remove Ray
// d.GeomDestroy(ray);
if (req.callbackMethod == null)
return;
d.SpaceCollide2(ray, req.geom, IntPtr.Zero, nearCallback); // still do this to have full AABB pre test
if (req.callbackMethod is RaycastCallback)
{
// Define default results
bool hitYN = false;
uint hitConsumerID = 0;
float distance = 999999999999f;
Vector3 closestcontact = new Vector3(99999f, 99999f, 99999f);
float distance = float.MaxValue;
Vector3 closestcontact = Vector3.Zero;
Vector3 snormal = Vector3.Zero;
// Find closest contact and object.
@ -317,25 +388,31 @@ namespace OpenSim.Region.Physics.OdePlugin
{
foreach (ContactResult cResult in m_contactResults)
{
if (Vector3.Distance(req.Origin, cResult.Pos) < Vector3.Distance(req.Origin, closestcontact))
if(cResult.Depth < distance )
{
closestcontact = cResult.Pos;
hitConsumerID = cResult.ConsumerID;
distance = cResult.Depth;
hitYN = true;
snormal = cResult.Normal;
}
}
m_contactResults.Clear();
}
if (distance > 0 && distance < float.MaxValue)
hitYN = true;
((RaycastCallback)req.callbackMethod)(hitYN, closestcontact, hitConsumerID, distance, snormal);
}
else
{
((RayCallback)req.callbackMethod)(m_contactResults);
List<ContactResult> cresult = new List<ContactResult>(m_contactResults.Count);
lock (m_PendingRequests)
{
cresult.AddRange(m_contactResults);
m_contactResults.Clear();
}
((RayCallback)req.callbackMethod)(cresult);
}
}
@ -350,20 +427,16 @@ namespace OpenSim.Region.Physics.OdePlugin
return true;
}
// This is the standard Near. g2 is the ray
// This is the standard Near. g1 is the ray
private void near(IntPtr space, IntPtr g1, IntPtr g2)
{
//Don't test against heightfield Geom, or you'll be sorry!
// Exclude heightfield geom
if (g1 == IntPtr.Zero || g1 == g2)
if (g2 == IntPtr.Zero || g1 == g2)
return;
if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass)
if (m_contactResults.Count >= CurrentMaxCount)
return;
// Raytest against AABBs of spaces first, then dig into the spaces it hits for actual geoms.
if (d.GeomIsSpace(g1))
if (d.GeomIsSpace(g2))
{
try
{
@ -381,10 +454,6 @@ namespace OpenSim.Region.Physics.OdePlugin
{
count = d.CollidePtr(g1, g2, ColisionContactGeomsPerTest, m_scene.ContactgeomsArray, d.ContactGeom.unmanagedSizeOf);
}
catch (SEHException)
{
m_log.Error("[PHYSICS Ray]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
}
catch (Exception e)
{
m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
@ -394,31 +463,116 @@ namespace OpenSim.Region.Physics.OdePlugin
if (count == 0)
return;
PhysicsActor p1 = null;
uint ID = 0;
PhysicsActor p2 = null;
if (g1 != IntPtr.Zero)
m_scene.actor_name_map.TryGetValue(g1, out p1);
m_scene.actor_name_map.TryGetValue(g2, out p2);
if (p2 == null)
{
string name;
if (!m_scene.geom_name_map.TryGetValue(g2, out name))
return;
if (name == "Terrain")
{
// land colision
if ((CurrentRayFilter & RayFilterFlags.land) == 0)
return;
}
else if (name == "Water")
{
if ((CurrentRayFilter & RayFilterFlags.water) == 0)
return;
}
else
return;
}
else
{
if (p2 is OdePrim)
{
RayFilterFlags thisFlags;
if (p2.IsPhysical)
thisFlags = RayFilterFlags.physical;
else
thisFlags = RayFilterFlags.nonphysical;
if (p2.Phantom)
thisFlags |= RayFilterFlags.phantom;
if (p2.IsVolumeDtc)
thisFlags |= RayFilterFlags.volumedtc;
if ((thisFlags & CurrentRayFilter) == 0)
return;
ID = ((OdePrim)p2).m_localID;
}
else if (p2 is OdeCharacter)
{
if ((CurrentRayFilter & RayFilterFlags.agent) == 0)
return;
else
ID = ((OdeCharacter)p2).m_localID;
}
else //??
return;
}
d.ContactGeom curcontact = new d.ContactGeom();
// Loop over contacts, build results.
for (int i = 0; i < count; i++)
// closestHit for now only works for meshs, so must do it for others
if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0)
{
if (!GetCurContactGeom(i, ref curcontact))
break;
if (p1 != null) {
if (p1 is OdePrim)
// Loop all contacts, build results.
for (int i = 0; i < count; i++)
{
if (!GetCurContactGeom(i, ref curcontact))
break;
ContactResult collisionresult = new ContactResult();
collisionresult.ConsumerID = ID;
collisionresult.Pos = new Vector3(curcontact.pos.X, curcontact.pos.Y, curcontact.pos.Z);
collisionresult.Depth = curcontact.depth;
collisionresult.Normal = new Vector3(curcontact.normal.X, curcontact.normal.Y,
curcontact.normal.Z);
lock (m_contactResults)
{
m_contactResults.Add(collisionresult);
if (m_contactResults.Count >= CurrentMaxCount)
return;
}
}
}
else
{
// keep only closest contact
ContactResult collisionresult = new ContactResult();
collisionresult.ConsumerID = ID;
collisionresult.Depth = float.MaxValue;
for (int i = 0; i < count; i++)
{
if (!GetCurContactGeom(i, ref curcontact))
break;
if (curcontact.depth < collisionresult.Depth)
{
ContactResult collisionresult = new ContactResult();
collisionresult.ConsumerID = ((OdePrim)p1).m_localID;
collisionresult.Pos = new Vector3(curcontact.pos.X, curcontact.pos.Y, curcontact.pos.Z);
collisionresult.Depth = curcontact.depth;
collisionresult.Normal = new Vector3(curcontact.normal.X, curcontact.normal.Y,
curcontact.normal.Z);
lock (m_contactResults)
m_contactResults.Add(collisionresult);
}
}
if (collisionresult.Depth != float.MaxValue)
{
lock (m_contactResults)
m_contactResults.Add(collisionresult);
}
}
}
@ -428,6 +582,11 @@ namespace OpenSim.Region.Physics.OdePlugin
internal void Dispose()
{
m_scene = null;
if (ray != IntPtr.Zero)
{
d.GeomDestroy(ray);
ray = IntPtr.Zero;
}
}
}
@ -439,5 +598,6 @@ namespace OpenSim.Region.Physics.OdePlugin
public int Count;
public float length;
public object callbackMethod;
public RayFilterFlags filter;
}
}

View File

@ -889,13 +889,13 @@ namespace OdeAPI
public static extern IntPtr GeomGetBody(IntPtr geom);
[DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetCategoryBits"), SuppressUnmanagedCodeSecurity]
public static extern int GeomGetCategoryBits(IntPtr geom);
public static extern uint GeomGetCategoryBits(IntPtr geom);
[DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetClassData"), SuppressUnmanagedCodeSecurity]
public static extern IntPtr GeomGetClassData(IntPtr geom);
[DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetCollideBits"), SuppressUnmanagedCodeSecurity]
public static extern int GeomGetCollideBits(IntPtr geom);
public static extern uint GeomGetCollideBits(IntPtr geom);
[DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomGetClass"), SuppressUnmanagedCodeSecurity]
public static extern GeomClassID GeomGetClass(IntPtr geom);
@ -1086,10 +1086,10 @@ namespace OdeAPI
public static extern void GeomSetBody(IntPtr geom, IntPtr body);
[DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetCategoryBits"), SuppressUnmanagedCodeSecurity]
public static extern void GeomSetCategoryBits(IntPtr geom, int bits);
public static extern void GeomSetCategoryBits(IntPtr geom, uint bits);
[DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetCollideBits"), SuppressUnmanagedCodeSecurity]
public static extern void GeomSetCollideBits(IntPtr geom, int bits);
public static extern void GeomSetCollideBits(IntPtr geom, uint bits);
[DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomSetConvex"), SuppressUnmanagedCodeSecurity]
public static extern IntPtr GeomSetConvex(IntPtr geom, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons);

View File

@ -60,19 +60,31 @@ namespace OpenSim.Region.Physics.OdePlugin
public int lastframe;
}
// colision flags of things others can colide with
// rays, sensors, probes removed since can't be colided with
// The top space where things are placed provided further selection
// ie physical are in active space nonphysical in static
// this should be exclusive as possible
[Flags]
public enum CollisionCategories : int
public enum CollisionCategories : uint
{
Disabled = 0,
Geom = 0x00000001,
Body = 0x00000002,
Space = 0x00000004,
Character = 0x00000008,
Land = 0x00000010,
Water = 0x00000020,
Wind = 0x00000040,
Sensor = 0x00000080,
Selected = 0x00000100
//by 'things' types
Space = 0x01,
Geom = 0x02, // aka prim/part
Character = 0x04,
Land = 0x08,
Water = 0x010,
// by state
Phantom = 0x01000,
VolumeDtc = 0x02000,
Selected = 0x04000,
NoShape = 0x08000,
All = 0xffffffff
}
/// <summary>
@ -116,6 +128,7 @@ namespace OpenSim.Region.Physics.OdePlugin
Acceleration,
Force,
Torque,
Momentum,
AddForce,
AddAngForce,
@ -186,7 +199,9 @@ namespace OpenSim.Region.Physics.OdePlugin
private float waterlevel = 0f;
private int framecount = 0;
internal IntPtr WaterGeom;
private IntPtr WaterGeom = IntPtr.Zero;
private IntPtr WaterHeightmapData = IntPtr.Zero;
private GCHandle WaterMapHandler = new GCHandle();
public float avPIDD = 2200f; // make it visible
public float avPIDP = 900f; // make it visible
@ -213,9 +228,8 @@ namespace OpenSim.Region.Physics.OdePlugin
// public int geomCrossingFailuresBeforeOutofbounds = 6;
public int bodyFramesAutoDisable = 20;
public int bodyFramesAutoDisable = 5;
private float[] _watermap;
private d.NearCallback nearCallback;
@ -350,7 +364,7 @@ namespace OpenSim.Region.Physics.OdePlugin
// i must RtC#FM
}
d.HashSpaceSetLevels(TopSpace, -2, 8); // cell sizes from .25 to 256 ?? need check what this really does
d.HashSpaceSetLevels(TopSpace, -2, 8);
d.HashSpaceSetLevels(ActiveSpace, -2, 8);
d.HashSpaceSetLevels(StaticSpace, -2, 8);
@ -358,13 +372,27 @@ namespace OpenSim.Region.Physics.OdePlugin
d.SpaceSetSublevel(ActiveSpace, 1);
d.SpaceSetSublevel(StaticSpace, 1);
d.GeomSetCategoryBits(ActiveSpace, (uint)(CollisionCategories.Space |
CollisionCategories.Geom |
CollisionCategories.Character |
CollisionCategories.Phantom |
CollisionCategories.VolumeDtc
));
d.GeomSetCollideBits(ActiveSpace, 0);
d.GeomSetCategoryBits(StaticSpace, (uint)(CollisionCategories.Space |
CollisionCategories.Geom |
CollisionCategories.Land |
CollisionCategories.Water |
CollisionCategories.Phantom |
CollisionCategories.VolumeDtc
));
d.GeomSetCollideBits(StaticSpace, 0);
contactgroup = d.JointGroupCreate(0);
//contactgroup
d.WorldSetAutoDisableFlag(world, false);
}
_watermap = new float[258 * 258];
}
// Initialize the mesh plugin
@ -374,15 +402,18 @@ namespace OpenSim.Region.Physics.OdePlugin
// checkThread();
mesher = meshmerizer;
m_config = config;
/*
string ode_config = d.GetConfiguration("ODE");
m_log.WarnFormat("ODE configuration: {0}", ode_config);
if (ode_config.Contains("ODE_Ubit"))
if (ode_config != null && ode_config != "")
{
OdeUbitLib = true;
}
m_log.WarnFormat("ODE configuration: {0}", ode_config);
if (ode_config.Contains("ODE_Ubit"))
{
OdeUbitLib = true;
}
}
*/
/*
if (region != null)
{
@ -518,6 +549,15 @@ namespace OpenSim.Region.Physics.OdePlugin
waitForSpaceUnlock(newspace);
d.SpaceSetSublevel(newspace, 2);
d.HashSpaceSetLevels(newspace, -2, 8);
d.GeomSetCategoryBits(newspace, (uint)(CollisionCategories.Space |
CollisionCategories.Geom |
CollisionCategories.Land |
CollisionCategories.Water |
CollisionCategories.Phantom |
CollisionCategories.VolumeDtc
));
d.GeomSetCollideBits(newspace, 0);
staticPrimspace[i, j] = newspace;
}
// let this now be real maximum values
@ -1745,8 +1785,6 @@ namespace OpenSim.Region.Physics.OdePlugin
m_rayCastManager.ProcessQueuedRequests();
statray += Util.EnvironmentTickCountSubtract(statstart);
collision_optimized();
statcol += Util.EnvironmentTickCountSubtract(statstart);
@ -2125,14 +2163,14 @@ namespace OpenSim.Region.Physics.OdePlugin
RegionTerrain.Remove(pOffset);
if (GroundGeom != IntPtr.Zero)
{
d.GeomDestroy(GroundGeom);
if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
{
TerrainHeightFieldHeightsHandlers[GroundGeom].Free();
TerrainHeightFieldHeightsHandlers.Remove(GroundGeom);
TerrainHeightFieldHeights.Remove(GroundGeom);
}
d.SpaceRemove(StaticSpace, GroundGeom);
d.GeomDestroy(GroundGeom);
}
}
IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
@ -2147,8 +2185,8 @@ namespace OpenSim.Region.Physics.OdePlugin
GroundGeom = d.CreateHeightfield(StaticSpace, HeightmapData, 1);
if (GroundGeom != IntPtr.Zero)
{
d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
d.GeomSetCollideBits(GroundGeom, 0);
}
geom_name_map[GroundGeom] = "Terrain";
@ -2236,14 +2274,15 @@ namespace OpenSim.Region.Physics.OdePlugin
RegionTerrain.Remove(pOffset);
if (GroundGeom != IntPtr.Zero)
{
d.GeomDestroy(GroundGeom);
if (TerrainHeightFieldHeights.ContainsKey(GroundGeom))
{
TerrainHeightFieldHeightsHandlers[GroundGeom].Free();
if (TerrainHeightFieldHeightsHandlers[GroundGeom].IsAllocated)
TerrainHeightFieldHeightsHandlers[GroundGeom].Free();
TerrainHeightFieldHeightsHandlers.Remove(GroundGeom);
TerrainHeightFieldHeights.Remove(GroundGeom);
}
d.SpaceRemove(StaticSpace, GroundGeom);
d.GeomDestroy(GroundGeom);
}
}
IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
@ -2263,8 +2302,8 @@ namespace OpenSim.Region.Physics.OdePlugin
GroundGeom = d.CreateUbitTerrain(StaticSpace, HeightmapData, 1);
if (GroundGeom != IntPtr.Zero)
{
d.GeomSetCategoryBits(GroundGeom, (int)(CollisionCategories.Land));
d.GeomSetCollideBits(GroundGeom, (int)(CollisionCategories.Space));
d.GeomSetCategoryBits(GroundGeom, (uint)(CollisionCategories.Land));
d.GeomSetCollideBits(GroundGeom, 0);
}
geom_name_map[GroundGeom] = "Terrain";
@ -2359,57 +2398,76 @@ namespace OpenSim.Region.Physics.OdePlugin
public void randomizeWater(float baseheight)
{
const uint heightmapWidth = m_regionWidth + 2;
const uint heightmapHeight = m_regionHeight + 2;
const uint heightmapWidthSamples = m_regionWidth + 2;
const uint heightmapHeightSamples = m_regionHeight + 2;
const uint heightmapWidth = Constants.RegionSize + 2;
const uint heightmapHeight = Constants.RegionSize + 2;
const uint heightmapWidthSamples = heightmapWidth + 1;
const uint heightmapHeightSamples = heightmapHeight + 1;
const float scale = 1.0f;
const float offset = 0.0f;
const float thickness = 2.9f;
const int wrap = 0;
for (int i = 0; i < (258 * 258); i++)
float[] _watermap = new float[heightmapWidthSamples * heightmapWidthSamples];
float maxheigh = float.MinValue;
float minheigh = float.MaxValue;
float val;
for (int i = 0; i < (heightmapWidthSamples * heightmapHeightSamples); i++)
{
_watermap[i] = (baseheight-0.1f) + ((float)fluidRandomizer.Next(1,9) / 10f);
// m_log.Info((baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f));
val = (baseheight - 0.1f) + ((float)fluidRandomizer.Next(1, 9) / 10f);
_watermap[i] = val;
if (maxheigh < val)
maxheigh = val;
if (minheigh > val)
minheigh = val;
}
float thickness = minheigh;
lock (OdeLock)
{
if (WaterGeom != IntPtr.Zero)
{
d.SpaceRemove(StaticSpace, WaterGeom);
d.GeomDestroy(WaterGeom);
d.GeomHeightfieldDataDestroy(WaterHeightmapData);
WaterGeom = IntPtr.Zero;
WaterHeightmapData = IntPtr.Zero;
if(WaterMapHandler.IsAllocated)
WaterMapHandler.Free();
}
IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
d.GeomHeightfieldDataBuildSingle(HeightmapData, _watermap, 0, heightmapWidth, heightmapHeight,
WaterHeightmapData = d.GeomHeightfieldDataCreate();
WaterMapHandler = GCHandle.Alloc(_watermap, GCHandleType.Pinned);
d.GeomHeightfieldDataBuildSingle(WaterHeightmapData, WaterMapHandler.AddrOfPinnedObject(), 0, heightmapWidth, heightmapHeight,
(int)heightmapWidthSamples, (int)heightmapHeightSamples, scale,
offset, thickness, wrap);
d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
WaterGeom = d.CreateHeightfield(StaticSpace, HeightmapData, 1);
d.GeomHeightfieldDataSetBounds(WaterHeightmapData, minheigh, maxheigh);
WaterGeom = d.CreateHeightfield(StaticSpace, WaterHeightmapData, 1);
if (WaterGeom != IntPtr.Zero)
{
d.GeomSetCategoryBits(WaterGeom, (int)(CollisionCategories.Water));
d.GeomSetCollideBits(WaterGeom, (int)(CollisionCategories.Space));
d.GeomSetCategoryBits(WaterGeom, (uint)(CollisionCategories.Water));
d.GeomSetCollideBits(WaterGeom, 0);
geom_name_map[WaterGeom] = "Water";
d.Matrix3 R = new d.Matrix3();
Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
q1 = q1 * q2;
Vector3 v3;
float angle;
q1.GetAxisAngle(out v3, out angle);
d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
d.GeomSetRotation(WaterGeom, ref R);
d.GeomSetPosition(WaterGeom, (float)Constants.RegionSize * 0.5f, (float)Constants.RegionSize * 0.5f, 0);
}
geom_name_map[WaterGeom] = "Water";
d.Matrix3 R = new d.Matrix3();
Quaternion q1 = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), 1.5707f);
Quaternion q2 = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), 1.5707f);
q1 = q1 * q2;
Vector3 v3;
float angle;
q1.GetAxisAngle(out v3, out angle);
d.RFromAxisAndAngle(out R, v3.X, v3.Y, v3.Z, angle);
d.GeomSetRotation(WaterGeom, ref R);
d.GeomSetPosition(WaterGeom, 128, 128, 0);
}
}
public override void Dispose()
@ -2427,11 +2485,34 @@ namespace OpenSim.Region.Physics.OdePlugin
}
}
if (TerrainHeightFieldHeightsHandlers.Count > 0)
{
foreach (GCHandle gch in TerrainHeightFieldHeightsHandlers.Values)
{
if (gch.IsAllocated)
gch.Free();
}
}
if (WaterGeom != IntPtr.Zero)
{
d.GeomDestroy(WaterGeom);
WaterGeom = IntPtr.Zero;
if (WaterHeightmapData != IntPtr.Zero)
d.GeomHeightfieldDataDestroy(WaterHeightmapData);
WaterHeightmapData = IntPtr.Zero;
if (WaterMapHandler.IsAllocated)
WaterMapHandler.Free();
}
if (ContactgeomsArray != IntPtr.Zero)
Marshal.FreeHGlobal(ContactgeomsArray);
if (GlobalContactsArray != IntPtr.Zero)
Marshal.FreeHGlobal(GlobalContactsArray);
d.WorldDestroy(world);
//d.CloseODE();
}
@ -2502,6 +2583,35 @@ namespace OpenSim.Region.Physics.OdePlugin
return new List<ContactResult>(ourResults);
}
public override bool SuportsRaycastWorldFiltered()
{
return true;
}
public override object RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
{
object SyncObject = new object();
List<ContactResult> ourresults = new List<ContactResult>();
RayCallback retMethod = delegate(List<ContactResult> results)
{
lock (SyncObject)
{
ourresults = results;
Monitor.PulseAll(SyncObject);
}
};
lock (SyncObject)
{
m_rayCastManager.QueueRequest(position, direction, length, Count,filter, retMethod);
if (!Monitor.Wait(SyncObject, 500))
return null;
else
return ourresults;
}
}
public override void RaycastActor(PhysicsActor actor, Vector3 position, Vector3 direction, float length, RaycastCallback retMethod)
{
if (retMethod != null && actor !=null)