Merge branch 'master' of ssh://melanie@3dhosting.de/var/git/careminster into careminster

avinationmerge
Melanie 2012-04-17 01:50:49 +01:00
commit ab1a3688e2
13 changed files with 1214 additions and 813 deletions

View File

@ -1891,6 +1891,19 @@ namespace OpenSim.Region.Framework.Scenes
EventManager.TriggerPrimsLoaded(this);
}
public bool SuportsRayCastFiltered()
{
if (PhysicsScene == null)
return false;
return PhysicsScene.SuportsRaycastWorldFiltered();
}
public object RayCastFiltered(Vector3 position, Vector3 direction, float length, int Count, RayFilterFlags filter)
{
if (PhysicsScene == null)
return null;
return PhysicsScene.RaycastWorld(position, direction, length, Count,filter);
}
/// <summary>
/// Gets a new rez location based on the raycast and the size of the object that is being rezzed.

View File

@ -753,7 +753,7 @@ namespace OpenSim.Region.Framework.Scenes
if (m_movementAnimationUpdateCounter >= 2)
{
m_movementAnimationUpdateCounter = 0;
if (Animator != null)
if (Animator != null && ParentID == 0) // skip it if sitting
{
Animator.UpdateMovementAnimations();
}
@ -1077,10 +1077,13 @@ namespace OpenSim.Region.Framework.Scenes
public void TeleportWithMomentum(Vector3 pos)
{
bool isFlying = Flying;
Vector3 vel = Velocity;
RemoveFromPhysicalScene();
CheckLandingPoint(ref pos);
AbsolutePosition = pos;
AddToPhysicalScene(isFlying);
if (PhysicsActor != null)
PhysicsActor.SetMomentum(vel);
SendTerseUpdateToAllClients();
}
@ -1385,8 +1388,16 @@ namespace OpenSim.Region.Framework.Scenes
{
if (m_followCamAuto)
{
Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT;
m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback);
// Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT;
// m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback);
Vector3 posAdjusted = AbsolutePosition + HEAD_ADJUSTMENT;
Vector3 distTocam = CameraPosition - posAdjusted;
float distTocamlen = distTocam.Length();
if (distTocamlen > 0)
{
distTocam *= 1.0f / distTocamlen;
m_scene.PhysicsScene.RaycastWorld(posAdjusted, distTocam, distTocamlen + 0.3f, RayCastCameraCallback);
}
}
}

View File

@ -140,6 +140,10 @@ namespace OpenSim.Region.Physics.OdePlugin
public int m_eventsubscription = 0;
private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
private Vector3 m_taintMomentum = Vector3.Zero;
private bool m_haveTaintMomentum = false;
// unique UUID of this character object
public UUID m_uuid;
public bool bad = false;
@ -800,8 +804,8 @@ namespace OpenSim.Region.Physics.OdePlugin
{
if (value.IsFinite())
{
m_pidControllerActive = true;
_target_velocity = value;
m_pidControllerActive = true;
}
else
{
@ -911,6 +915,14 @@ namespace OpenSim.Region.Physics.OdePlugin
public override void SetMomentum(Vector3 momentum)
{
if (momentum.IsFinite())
{
m_taintMomentum = momentum;
m_haveTaintMomentum = true;
_parent_scene.AddPhysicsActorTaint(this);
}
else
m_log.Warn("[PHYSICS] !isFinite momentum");
}
@ -1110,9 +1122,18 @@ namespace OpenSim.Region.Physics.OdePlugin
}
// end add Kitto Flora
}
if (vel.X * vel.X + vel.Y * vel.Y + vel.Z * vel.Z > 2500.0f) // 50ms apply breaks
{
float breakfactor = 0.16f * m_mass; // will give aprox 60m/s terminal velocity at free fall
vec.X -= breakfactor * vel.X;
vec.Y -= breakfactor * vel.Y;
vec.Z -= breakfactor * vel.Z;
}
if (vec.IsFinite())
{
if (!vec.ApproxEquals(Vector3.Zero, 0.02f)) // 0.01 allows 0.002 !!
if (vec.LengthSquared() > 0.0004f) // 0.01 allows 0.002 !!
{
//Console.WriteLine("DF 2"); // ##
@ -1327,7 +1348,6 @@ namespace OpenSim.Region.Physics.OdePlugin
{
lock (m_syncRoot)
{
if (m_tainted_isPhysical != m_isPhysical)
{
if (m_tainted_isPhysical)
@ -1369,9 +1389,9 @@ namespace OpenSim.Region.Physics.OdePlugin
{
d.GeomDestroy(Shell);
}
catch (System.AccessViolationException)
catch (Exception e)
{
m_log.Error("[PHYSICS]: PrimGeom dead");
m_log.ErrorFormat("[PHYSICS]: Failed to destroy character shell {0}",e.Message);
}
// Remove any old entries
//string tShell;
@ -1418,12 +1438,21 @@ namespace OpenSim.Region.Physics.OdePlugin
{
d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z);
_position.X = m_taintPosition.X;
_position.Y = m_taintPosition.Y;
_position.Z = m_taintPosition.Z;
}
_position.X = m_taintPosition.X;
_position.Y = m_taintPosition.Y;
_position.Z = m_taintPosition.Z;
}
if (m_haveTaintMomentum)
{
m_haveTaintMomentum = false;
_velocity = m_taintMomentum;
_target_velocity = m_taintMomentum;
m_pidControllerActive = true;
if (Body != IntPtr.Zero)
d.BodySetLinearVel(Body, _velocity.X, _velocity.Y, _velocity.Z);
}
}
}

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

@ -335,7 +335,7 @@ namespace OpenSim.Region.Physics.Meshing
if (primShape.SculptData.Length <= 0)
{
m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
m_log.InfoFormat("[MESH]: asset data for {0} is zero length", primName);
return false;
}

View File

@ -339,7 +339,7 @@ namespace OpenSim.Region.Physics.Meshing
if (primShape.SculptData.Length <= 0)
{
m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
m_log.InfoFormat("[MESH]: asset data for {0} is zero length", primName);
return false;
}

View File

@ -115,12 +115,11 @@ 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
| CollisionCategories.VolumeDtc
);
// 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 +638,8 @@ namespace OpenSim.Region.Physics.OdePlugin
public override void SetMomentum(Vector3 momentum)
{
if (momentum.IsFinite())
AddChange(changes.Momentum, momentum);
}
@ -663,8 +664,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 +760,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;
}
}
@ -991,6 +991,14 @@ namespace OpenSim.Region.Physics.OdePlugin
// end add Kitto Flora
}
if (vel.X * vel.X + vel.Y * vel.Y + vel.Z * vel.Z > 2500.0f) // 50m/s apply breaks
{
float breakfactor = 0.16f * m_mass; // will give aprox 60m/s terminal velocity at free fall
vec.X -= breakfactor * vel.X;
vec.Y -= breakfactor * vel.Y;
vec.Z -= breakfactor * vel.Z;
}
if (vec.IsFinite())
{
if (vec.X != 0 || vec.Y !=0 || vec.Z !=0)
@ -1324,6 +1332,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 +1413,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.AllPrims;
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.AllPrims;
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.AllPrims;
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.AllPrims;
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.AllPrims;
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.AllPrims;
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.AllPrims;
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.AllPrims;
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++)
{
if (!GetCurContactGeom(i, ref curcontact))
break;
if (p1 != null) {
if (p1 is OdePrim)
{
ContactResult collisionresult = new ContactResult();
collisionresult.ConsumerID = ((OdePrim)p1).m_localID;
// closestHit for now only works for meshs, so must do it for others
if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0)
{
// 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)
{
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)

View File

@ -9980,7 +9980,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
// return total object mass
SceneObjectGroup obj = World.GetGroupByPrim(World.Entities[key].LocalId);
if (obj != null)
return (double)obj.GetMass();
return obj.GetMass();
// the object is null so the key is for an avatar
ScenePresence avatar = World.GetScenePresence(key);
@ -9990,7 +9990,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
// child agents have a mass of 1.0
return 1;
else
return (double)avatar.PhysicsActor.Mass;
return avatar.GetMass();
}
catch (KeyNotFoundException)
{
@ -11834,6 +11834,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return contacts[0];
}
/*
// not done:
private ContactResult[] testRay2NonPhysicalPhantom(Vector3 rayStart, Vector3 raydir, float raylenght)
{
ContactResult[] contacts = null;
World.ForEachSOG(delegate(SceneObjectGroup group)
{
if (m_host.ParentGroup == group)
return;
if (group.IsAttachment)
return;
if(group.RootPart.PhysActor != null)
return;
contacts = group.RayCastGroupPartsOBBNonPhysicalPhantom(rayStart, raydir, raylenght);
});
return contacts;
}
*/
public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
{
@ -11874,38 +11895,101 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL);
bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL);
if (checkTerrain)
{
ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
if (groundContact != null)
results.Add((ContactResult)groundContact);
}
if (checkAgents)
if (World.SuportsRayCastFiltered())
{
ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
foreach (ContactResult r in agentHits)
results.Add(r);
}
if (dist == 0)
return list;
if (checkPhysical || checkNonPhysical)
RayFilterFlags rayfilter = RayFilterFlags.ClosestAndBackCull;
if (checkTerrain)
rayfilter |= RayFilterFlags.land;
// if (checkAgents)
// rayfilter |= RayFilterFlags.agent;
if (checkPhysical)
rayfilter |= RayFilterFlags.physical;
if (checkNonPhysical)
rayfilter |= RayFilterFlags.nonphysical;
if (detectPhantom)
rayfilter |= RayFilterFlags.LSLPhanton;
Vector3 direction = dir * ( 1/dist);
if(rayfilter == 0)
{
list.Add(new LSL_Integer(0));
return list;
}
// get some more contacts to sort ???
int physcount = 4 * count;
if (physcount > 20)
physcount = 20;
object physresults;
physresults = World.RayCastFiltered(rayStart, direction, dist, physcount, rayfilter);
if (physresults == null)
{
list.Add(new LSL_Integer(-3)); // timeout error
return list;
}
results = (List<ContactResult>)physresults;
// for now physics doesn't detect sitted avatars so do it outside physics
if (checkAgents)
{
ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
foreach (ContactResult r in agentHits)
results.Add(r);
}
// bug: will not detect phantom unless they are physical
// don't use ObjectIntersection because its also bad
}
else
{
ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
foreach (ContactResult r in objectHits)
results.Add(r);
if (checkTerrain)
{
ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
if (groundContact != null)
results.Add((ContactResult)groundContact);
}
if (checkAgents)
{
ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
foreach (ContactResult r in agentHits)
results.Add(r);
}
if (checkPhysical || checkNonPhysical || detectPhantom)
{
ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
foreach (ContactResult r in objectHits)
results.Add(r);
}
}
results.Sort(delegate(ContactResult a, ContactResult b)
{
return (int)(a.Depth - b.Depth);
return a.Depth.CompareTo(b.Depth);
});
int values = 0;
SceneObjectGroup thisgrp = m_host.ParentGroup;
foreach (ContactResult result in results)
{
if (result.Depth > dist)
continue;
// physics ray can return colisions with host prim
if (m_host.LocalId == result.ConsumerID)
continue;
UUID itemID = UUID.Zero;
int linkNum = 0;
@ -11913,6 +11997,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
// It's a prim!
if (part != null)
{
// dont detect members of same object ???
if (part.ParentGroup == thisgrp)
continue;
if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY)
itemID = part.ParentGroup.UUID;
else
@ -11934,14 +12022,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM)
list.Add(new LSL_Integer(linkNum));
if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z));
values++;
count--;
if (count == 0)
if (values >= count)
break;
}