From 3e456163dd284fa04ab17465041a1a27f7b632b9 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 12 Jul 2011 22:13:15 +0100 Subject: [PATCH] Port implementation of llCastRay() from Aurora. I haven't been able to test this since the viewer won't parse the llCastRay() function. Maybe some activation cap is missing. Could wait until it is activated by default in the viewer. --- .../Region/Physics/Manager/PhysicsScene.cs | 24 ++- .../OdePlugin/ODERayCastRequestManager.cs | 94 ++++++++-- OpenSim/Region/Physics/OdePlugin/OdeScene.cs | 28 +++ .../Shared/Api/Implementation/LSL_Api.cs | 166 ++++++++++++++++-- .../Shared/Api/Interface/ILSL_Api.cs | 5 +- .../Shared/Api/Runtime/LSL_Constants.cs | 16 ++ 6 files changed, 299 insertions(+), 34 deletions(-) diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index 13ea084978..0de46266b5 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -37,6 +37,18 @@ namespace OpenSim.Region.Physics.Manager public delegate void physicsCrash(); public delegate void RaycastCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 normal); + public delegate void RayCallback(List list); + + /// + /// Contact result from a raycast. + /// + public struct ContactResult + { + public Vector3 Pos; + public float Depth; + public uint ConsumerID; + public Vector3 Normal; + } public abstract class PhysicsScene { @@ -61,7 +73,6 @@ namespace OpenSim.Region.Physics.Manager } } - public abstract void Initialise(IMesher meshmerizer, IConfigSource config); public abstract PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying); @@ -225,6 +236,17 @@ namespace OpenSim.Region.Physics.Manager retMethod(false, Vector3.Zero, 0, 999999999999f, Vector3.Zero); } + public virtual void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) + { + if (retMethod != null) + retMethod(new List()); + } + + public virtual List RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) + { + return new List(); + } + private class NullPhysicsScene : PhysicsScene { private static int m_workIndicator; diff --git a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs index ba77daebae..6c2bdde353 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODERayCastRequestManager.cs @@ -45,10 +45,15 @@ namespace OpenSim.Region.Physics.OdePlugin public class ODERayCastRequestManager { /// - /// Pending Raycast Requests + /// Pending raycast requests /// protected List m_PendingRequests = new List(); + /// + /// Pending ray requests + /// + protected List m_PendingRayRequests = new List(); + /// /// Scene that created this object. /// @@ -95,6 +100,29 @@ namespace OpenSim.Region.Physics.OdePlugin } } + /// + /// Queues a raycast + /// + /// Origin of Ray + /// Ray normal + /// Ray length + /// + /// Return method to send the results + public void QueueRequest(Vector3 position, Vector3 direction, float length, int count, RayCallback retMethod) + { + lock (m_PendingRequests) + { + ODERayRequest req = new ODERayRequest(); + req.callbackMethod = retMethod; + req.length = length; + req.Normal = direction; + req.Origin = position; + req.Count = count; + + m_PendingRayRequests.Add(req); + } + } + /// /// Process all queued raycast requests /// @@ -112,18 +140,26 @@ namespace OpenSim.Region.Physics.OdePlugin if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast RayCast(reqs[i]); // if there isn't anyone to send results } - /* - foreach (ODERayCastRequest req in m_PendingRequests) - { - if (req.callbackMethod != null) // quick optimization here, don't raycast - RayCast(req); // if there isn't anyone to send results to - - } - */ + m_PendingRequests.Clear(); } } + lock (m_PendingRayRequests) + { + if (m_PendingRayRequests.Count > 0) + { + ODERayRequest[] reqs = m_PendingRayRequests.ToArray(); + for (int i = 0; i < reqs.Length; i++) + { + if (reqs[i].callbackMethod != null) // quick optimization here, don't raycast + RayCast(reqs[i]); // if there isn't anyone to send results + } + + m_PendingRayRequests.Clear(); + } + } + lock (m_contactResults) m_contactResults.Clear(); @@ -146,7 +182,6 @@ namespace OpenSim.Region.Physics.OdePlugin // Remove Ray d.GeomDestroy(ray); - // Define default results bool hitYN = false; uint hitConsumerID = 0; @@ -177,6 +212,31 @@ namespace OpenSim.Region.Physics.OdePlugin req.callbackMethod(hitYN, closestcontact, hitConsumerID, distance, snormal); } + /// + /// Method that actually initiates the raycast + /// + /// + private void RayCast(ODERayRequest req) + { + // Create the ray + IntPtr ray = d.CreateRay(m_scene.space, 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.space, ray, IntPtr.Zero, nearCallback); + + // Remove Ray + d.GeomDestroy(ray); + + // Find closest contact and object. + lock (m_contactResults) + { + // Return results + if (req.callbackMethod != null) + req.callbackMethod(m_contactResults); + } + } + // This is the standard Near. Uses space AABBs to speed up detection. private void near(IntPtr space, IntPtr g1, IntPtr g2) { @@ -342,10 +402,7 @@ namespace OpenSim.Region.Physics.OdePlugin m_contactResults.Add(collisionresult); } } - - } - } /// @@ -365,11 +422,12 @@ namespace OpenSim.Region.Physics.OdePlugin public RaycastCallback callbackMethod; } - public struct ContactResult + public struct ODERayRequest { - public Vector3 Pos; - public float Depth; - public uint ConsumerID; + public Vector3 Origin; public Vector3 Normal; + public int Count; + public float length; + public RayCallback callbackMethod; } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 7b8a80cbd3..ba8cba4434 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -3736,6 +3736,34 @@ Console.WriteLine("AddPhysicsActorTaint to " + taintedprim.Name); } } + public override void RaycastWorld(Vector3 position, Vector3 direction, float length, int Count, RayCallback retMethod) + { + if (retMethod != null) + { + m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); + } + } + + public override List RaycastWorld(Vector3 position, Vector3 direction, float length, int Count) + { + ContactResult[] ourResults = null; + RayCallback retMethod = delegate(List results) + { + ourResults = new ContactResult[results.Count]; + results.CopyTo(ourResults, 0); + }; + int waitTime = 0; + m_rayCastManager.QueueRequest(position, direction, length, Count, retMethod); + while (ourResults == null && waitTime < 1000) + { + Thread.Sleep(1); + waitTime++; + } + if (ourResults == null) + return new List (); + return new List(ourResults); + } + #if USE_DRAWSTUFF // Keyboard callback public void command(int cmd) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index fd6d64c498..c8bce6058f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -10309,51 +10309,191 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return rq.ToString(); } + public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) + { + m_host.AddScriptLPS(1); + + Vector3 dir = new Vector3((float)(end-start).x, (float)(end-start).y, (float)(end-start).z); + Vector3 startvector = new Vector3((float)start.x, (float)start.y, (float)start.z); + Vector3 endvector = new Vector3((float)end.x, (float)end.y, (float)end.z); + + int count = 0; +// int detectPhantom = 0; + int dataFlags = 0; + int rejectTypes = 0; + + for (int i = 0; i < options.Length; i += 2) + { + if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) + { + count = options.GetLSLIntegerItem(i + 1); + } +// else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) +// { +// detectPhantom = options.GetLSLIntegerItem(i + 1); +// } + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) + { + dataFlags = options.GetLSLIntegerItem(i + 1); + } + else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) + { + rejectTypes = options.GetLSLIntegerItem(i + 1); + } + } + + LSL_List list = new LSL_List(); + List results = World.PhysicsScene.RaycastWorld(startvector, dir, dir.Length(), count); + + double distance = Util.GetDistanceTo(startvector, endvector); + + if (distance == 0) + distance = 0.001; + + Vector3 posToCheck = startvector; + ITerrainChannel channel = World.RequestModuleInterface(); + + bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND); + bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS); + bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL); + bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL); + + for (float i = 0; i <= distance; i += 0.1f) + { + posToCheck = startvector + (dir * (i / (float)distance)); + + if (checkTerrain && channel[(int)(posToCheck.X + startvector.X), (int)(posToCheck.Y + startvector.Y)] < posToCheck.Z) + { + ContactResult result = new ContactResult(); + result.ConsumerID = 0; + result.Depth = 0; + result.Normal = Vector3.Zero; + result.Pos = posToCheck; + results.Add(result); + checkTerrain = false; + } + + if (checkAgents) + { + World.ForEachScenePresence(delegate(ScenePresence sp) + { + if (sp.AbsolutePosition.ApproxEquals(posToCheck, sp.PhysicsActor.Size.X)) + { + ContactResult result = new ContactResult (); + result.ConsumerID = sp.LocalId; + result.Depth = 0; + result.Normal = Vector3.Zero; + result.Pos = posToCheck; + results.Add(result); + } + }); + } + } + + int refcount = 0; + foreach (ContactResult result in results) + { + if ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) + == ScriptBaseClass.RC_REJECT_LAND && result.ConsumerID == 0) + continue; + + ISceneEntity entity = World.GetSceneObjectPart(result.ConsumerID); + + if (entity == null && (rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != ScriptBaseClass.RC_REJECT_AGENTS) + entity = World.GetScenePresence(result.ConsumerID); //Only check if we should be looking for agents + + if (entity == null) + { + list.Add(UUID.Zero); + + if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) + list.Add(0); + + list.Add(result.Pos); + + if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) + list.Add(result.Normal); + + continue; //Can't find it, so add UUID.Zero + } + + /*if (detectPhantom == 0 && intersection.obj is ISceneChildEntity && + ((ISceneChildEntity)intersection.obj).PhysActor == null) + continue;*/ //Can't do this ATM, physics engine knows only of non phantom objects + + if (entity is SceneObjectPart) + { + if (((SceneObjectPart)entity).PhysActor != null && ((SceneObjectPart)entity).PhysActor.IsPhysical) + { + if (!checkPhysical) + continue; + } + else + { + if (!checkNonPhysical) + continue; + } + } + + refcount++; + if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY && entity is SceneObjectPart) + list.Add(((SceneObjectPart)entity).ParentGroup.UUID); + else + list.Add(entity.UUID); + + if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) + { + if (entity is SceneObjectPart) + list.Add(((SceneObjectPart)entity).LinkNum); + else + list.Add(0); + } + + list.Add(result.Pos); + + if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) + list.Add(result.Normal); + } + + list.Add(refcount); //The status code, either the # of contacts, RCERR_SIM_PERF_LOW, or RCERR_CAST_TIME_EXCEEDED + + return list; + } + #region Not Implemented // // Listing the unimplemented lsl functions here, please move // them from this region as they are completed // - public void llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) - { - m_host.AddScriptLPS(1); - NotImplemented("llCastRay"); - - } public void llGetEnv(LSL_String name) { m_host.AddScriptLPS(1); NotImplemented("llGetEnv"); - } public void llGetSPMaxMemory() { m_host.AddScriptLPS(1); NotImplemented("llGetSPMaxMemory"); - } public void llGetUsedMemory() { m_host.AddScriptLPS(1); NotImplemented("llGetUsedMemory"); - } - public void llRegionSayTo( LSL_Key target, LSL_Integer channel, LSL_String msg ) + public void llRegionSayTo(LSL_Key target, LSL_Integer channel, LSL_String msg) { m_host.AddScriptLPS(1); NotImplemented("llRegionSayTo"); - } - public void llScriptProfiler( LSL_Integer flags ) + public void llScriptProfiler(LSL_Integer flags) { m_host.AddScriptLPS(1); NotImplemented("llScriptProfiler"); - } public void llSetSoundQueueing(int queue) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index 654ea8129a..27f9c84611 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -60,6 +60,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String llBase64ToString(string str); void llBreakAllLinks(); void llBreakLink(int linknum); + LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options); LSL_Integer llCeil(double f); void llClearCameraParams(); LSL_Integer llClearPrimMedia(LSL_Integer face); @@ -404,7 +405,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String llXorBase64StringsCorrect(string str1, string str2); void print(string str); - void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); - LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules); + void SetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); + LSL_List GetLinkPrimitiveParamsEx(LSL_Key prim, LSL_List rules); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 9377cdafd8..3f90788433 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -593,5 +593,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const string URL_REQUEST_GRANTED = "URL_REQUEST_GRANTED"; public const string URL_REQUEST_DENIED = "URL_REQUEST_DENIED"; + + public static readonly LSLInteger RC_REJECT_TYPES = 2; + public static readonly LSLInteger RC_DATA_FLAGS = 4; + public static readonly LSLInteger RC_MAX_HITS = 8; + public static readonly LSLInteger RC_DETECT_PHANTOM = 16; + + public static readonly LSLInteger RC_REJECT_AGENTS = 2; + public static readonly LSLInteger RC_REJECT_PHYSICAL = 4; + public static readonly LSLInteger RC_REJECT_NONPHYSICAL = 8; + public static readonly LSLInteger RC_REJECT_LAND = 16; + + public static readonly LSLInteger RC_GET_NORMAL = 2; + public static readonly LSLInteger RC_GET_ROOT_KEY = 4; + public static readonly LSLInteger RC_GET_LINK_NUM = 8; + + public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 1; } }