aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs445
1 files changed, 345 insertions, 100 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 89f2068..a8679e2 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -10781,155 +10781,400 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
10781 return rq.ToString(); 10781 return rq.ToString();
10782 } 10782 }
10783 10783
10784 private struct Tri
10785 {
10786 public Vector3 p1;
10787 public Vector3 p2;
10788 public Vector3 p3;
10789 }
10790
10791 private bool InBoundingBox(ScenePresence avatar, Vector3 point)
10792 {
10793 float height = avatar.Appearance.AvatarHeight;
10794 Vector3 b1 = avatar.AbsolutePosition + new Vector3(-0.22f, -0.22f, -height/2);
10795 Vector3 b2 = avatar.AbsolutePosition + new Vector3(0.22f, 0.22f, height/2);
10796
10797 if (point.X > b1.X && point.X < b2.X &&
10798 point.Y > b1.Y && point.Y < b2.Y &&
10799 point.Z > b1.Z && point.Z < b2.Z)
10800 return true;
10801 return false;
10802 }
10803
10804 private ContactResult[] AvatarIntersection(Vector3 rayStart, Vector3 rayEnd)
10805 {
10806 List<ContactResult> contacts = new List<ContactResult>();
10807
10808 Vector3 ab = rayEnd - rayStart;
10809
10810 World.ForEachScenePresence(delegate(ScenePresence sp)
10811 {
10812 Vector3 ac = sp.AbsolutePosition - rayStart;
10813 Vector3 bc = sp.AbsolutePosition - rayEnd;
10814
10815 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
10816
10817 if (d > 1.5)
10818 return;
10819
10820 double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
10821
10822 if (d2 > 0)
10823 return;
10824
10825 double dp = Math.Sqrt(Vector3.Mag(ac) * Vector3.Mag(ac) - d * d);
10826 Vector3 p = rayStart + Vector3.Divide(Vector3.Multiply(ab, (float)dp), (float)Vector3.Mag(ab));
10827
10828 if (!InBoundingBox(sp, p))
10829 return;
10830
10831 ContactResult result = new ContactResult ();
10832 result.ConsumerID = sp.LocalId;
10833 result.Depth = Vector3.Distance(rayStart, p);
10834 result.Normal = Vector3.Zero;
10835 result.Pos = p;
10836
10837 contacts.Add(result);
10838 });
10839
10840 return contacts.ToArray();
10841 }
10842
10843 private ContactResult[] ObjectIntersection(Vector3 rayStart, Vector3 rayEnd, bool includePhysical, bool includeNonPhysical, bool includePhantom)
10844 {
10845 Ray ray = new Ray(rayStart, Vector3.Normalize(rayEnd - rayStart));
10846 List<ContactResult> contacts = new List<ContactResult>();
10847
10848 Vector3 ab = rayEnd - rayStart;
10849
10850 World.ForEachSOG(delegate(SceneObjectGroup group)
10851 {
10852 if (m_host.ParentGroup == group)
10853 return;
10854
10855 if (group.IsAttachment)
10856 return;
10857
10858 if (group.RootPart.PhysActor == null)
10859 {
10860 if (!includePhantom)
10861 return;
10862 }
10863 else
10864 {
10865 if (group.RootPart.PhysActor.IsPhysical)
10866 {
10867 if (!includePhysical)
10868 return;
10869 }
10870 else
10871 {
10872 if (!includeNonPhysical)
10873 return;
10874 }
10875 }
10876
10877 // Find the radius ouside of which we don't even need to hit test
10878 float minX;
10879 float maxX;
10880 float minY;
10881 float maxY;
10882 float minZ;
10883 float maxZ;
10884
10885 float radius = 0.0f;
10886
10887 group.GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
10888
10889 if (Math.Abs(minX) > radius)
10890 radius = Math.Abs(minX);
10891 if (Math.Abs(minY) > radius)
10892 radius = Math.Abs(minY);
10893 if (Math.Abs(minZ) > radius)
10894 radius = Math.Abs(minZ);
10895 if (Math.Abs(maxX) > radius)
10896 radius = Math.Abs(maxX);
10897 if (Math.Abs(maxY) > radius)
10898 radius = Math.Abs(maxY);
10899 if (Math.Abs(maxZ) > radius)
10900 radius = Math.Abs(maxZ);
10901
10902 Vector3 ac = group.AbsolutePosition - rayStart;
10903 Vector3 bc = group.AbsolutePosition - rayEnd;
10904
10905 double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
10906
10907 // Too far off ray, don't bother
10908 if (d > radius)
10909 return;
10910
10911 // Behind ray, drop
10912 double d2 = Vector3.Dot(Vector3.Negate(ab), ac);
10913 if (d2 > 0)
10914 return;
10915
10916 EntityIntersection intersection = group.TestIntersection(ray, true, false);
10917 // Miss.
10918 if (!intersection.HitTF)
10919 return;
10920
10921 ContactResult result = new ContactResult ();
10922 result.ConsumerID = group.LocalId;
10923 result.Depth = intersection.distance;
10924 result.Normal = intersection.normal;
10925 result.Pos = intersection.ipoint;
10926
10927 contacts.Add(result);
10928 });
10929
10930 return contacts.ToArray();
10931 }
10932
10933 private ContactResult? GroundIntersection(Vector3 rayStart, Vector3 rayEnd)
10934 {
10935 double[,] heightfield = World.Heightmap.GetDoubles();
10936 List<ContactResult> contacts = new List<ContactResult>();
10937
10938 double min = 2048.0;
10939 double max = 0.0;
10940
10941 // Find the min and max of the heightfield
10942 for (int x = 0 ; x < World.Heightmap.Width ; x++)
10943 {
10944 for (int y = 0 ; y < World.Heightmap.Height ; y++)
10945 {
10946 if (heightfield[x, y] > max)
10947 max = heightfield[x, y];
10948 if (heightfield[x, y] < min)
10949 min = heightfield[x, y];
10950 }
10951 }
10952
10953
10954 // A ray extends past rayEnd, but doesn't go back before
10955 // rayStart. If the start is above the highest point of the ground
10956 // and the ray goes up, we can't hit the ground. Ever.
10957 if (rayStart.Z > max && rayEnd.Z >= rayStart.Z)
10958 return null;
10959
10960 // Same for going down
10961 if (rayStart.Z < min && rayEnd.Z <= rayStart.Z)
10962 return null;
10963
10964 List<Tri> trilist = new List<Tri>();
10965
10966 // Create our triangle list
10967 for (int x = 1 ; x < World.Heightmap.Width ; x++)
10968 {
10969 for (int y = 1 ; y < World.Heightmap.Height ; y++)
10970 {
10971 Tri t1 = new Tri();
10972 Tri t2 = new Tri();
10973
10974 Vector3 p1 = new Vector3(x-1, y-1, (float)heightfield[x-1, y-1]);
10975 Vector3 p2 = new Vector3(x, y-1, (float)heightfield[x, y-1]);
10976 Vector3 p3 = new Vector3(x, y, (float)heightfield[x, y]);
10977 Vector3 p4 = new Vector3(x-1, y, (float)heightfield[x-1, y]);
10978
10979 t1.p1 = p1;
10980 t1.p2 = p2;
10981 t1.p3 = p3;
10982
10983 t2.p1 = p3;
10984 t2.p2 = p4;
10985 t2.p3 = p1;
10986
10987 trilist.Add(t1);
10988 trilist.Add(t2);
10989 }
10990 }
10991
10992 // Ray direction
10993 Vector3 rayDirection = rayEnd - rayStart;
10994
10995 foreach (Tri t in trilist)
10996 {
10997 // Compute triangle plane normal and edges
10998 Vector3 u = t.p2 - t.p1;
10999 Vector3 v = t.p3 - t.p1;
11000 Vector3 n = Vector3.Cross(u, v);
11001
11002 if (n == Vector3.Zero)
11003 continue;
11004
11005 Vector3 w0 = rayStart - t.p1;
11006 double a = -Vector3.Dot(n, w0);
11007 double b = Vector3.Dot(n, rayDirection);
11008
11009 // Not intersecting the plane, or in plane (same thing)
11010 // Ignoring this MAY cause the ground to not be detected
11011 // sometimes
11012 if (Math.Abs(b) < 0.000001)
11013 continue;
11014
11015 double r = a / b;
11016
11017 // ray points away from plane
11018 if (r < 0.0)
11019 continue;
11020
11021 Vector3 ip = rayStart + Vector3.Multiply(rayDirection, (float)r);
11022
11023 float uu = Vector3.Dot(u, u);
11024 float uv = Vector3.Dot(u, v);
11025 float vv = Vector3.Dot(v, v);
11026 Vector3 w = ip - t.p1;
11027 float wu = Vector3.Dot(w, u);
11028 float wv = Vector3.Dot(w, v);
11029 float d = uv * uv - uu * vv;
11030
11031 float cs = (uv * wv - vv * wu) / d;
11032 if (cs < 0 || cs > 1.0)
11033 continue;
11034 float ct = (uv * wu - uu * wv) / d;
11035 if (ct < 0 || (cs + ct) > 1.0)
11036 continue;
11037
11038 // Add contact point
11039 ContactResult result = new ContactResult ();
11040 result.ConsumerID = 0;
11041 result.Depth = Vector3.Distance(rayStart, ip);
11042 result.Normal = n;
11043 result.Pos = ip;
11044
11045 contacts.Add(result);
11046 }
11047
11048 if (contacts.Count == 0)
11049 return null;
11050
11051 contacts.Sort(delegate(ContactResult a, ContactResult b)
11052 {
11053 return (int)(a.Depth - b.Depth);
11054 });
11055
11056 return contacts[0];
11057 }
11058
10784 public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) 11059 public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
10785 { 11060 {
11061 LSL_List list = new LSL_List();
11062
10786 m_host.AddScriptLPS(1); 11063 m_host.AddScriptLPS(1);
10787 11064
10788 Vector3 dir = new Vector3((float)(end-start).x, (float)(end-start).y, (float)(end-start).z); 11065 Vector3 rayStart = new Vector3((float)start.x, (float)start.y, (float)start.z);
10789 Vector3 startvector = new Vector3((float)start.x, (float)start.y, (float)start.z); 11066 Vector3 rayEnd = new Vector3((float)end.x, (float)end.y, (float)end.z);
10790 Vector3 endvector = new Vector3((float)end.x, (float)end.y, (float)end.z); 11067 Vector3 dir = rayEnd - rayStart;
10791 11068
10792 int count = 0; 11069 float dist = Vector3.Mag(dir);
10793// int detectPhantom = 0; 11070
11071 int count = 1;
11072 bool detectPhantom = false;
10794 int dataFlags = 0; 11073 int dataFlags = 0;
10795 int rejectTypes = 0; 11074 int rejectTypes = 0;
10796 11075
10797 for (int i = 0; i < options.Length; i += 2) 11076 for (int i = 0; i < options.Length; i += 2)
10798 { 11077 {
10799 if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) 11078 if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS)
10800 {
10801 count = options.GetLSLIntegerItem(i + 1); 11079 count = options.GetLSLIntegerItem(i + 1);
10802 } 11080 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM)
10803// else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) 11081 detectPhantom = (options.GetLSLIntegerItem(i + 1) > 0);
10804// {
10805// detectPhantom = options.GetLSLIntegerItem(i + 1);
10806// }
10807 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) 11082 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS)
10808 {
10809 dataFlags = options.GetLSLIntegerItem(i + 1); 11083 dataFlags = options.GetLSLIntegerItem(i + 1);
10810 }
10811 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) 11084 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES)
10812 {
10813 rejectTypes = options.GetLSLIntegerItem(i + 1); 11085 rejectTypes = options.GetLSLIntegerItem(i + 1);
10814 }
10815 } 11086 }
10816 11087
10817 LSL_List list = new LSL_List(); 11088 if (count > 16)
10818 List<ContactResult> results = World.PhysicsScene.RaycastWorld(startvector, dir, dir.Length(), count); 11089 count = 16;
10819
10820 double distance = Util.GetDistanceTo(startvector, endvector);
10821 11090
10822 if (distance == 0) 11091 List<ContactResult> results = new List<ContactResult>();
10823 distance = 0.001;
10824
10825 Vector3 posToCheck = startvector;
10826 ITerrainChannel channel = World.RequestModuleInterface<ITerrainChannel>();
10827 11092
10828 bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND); 11093 bool checkTerrain = !((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) == ScriptBaseClass.RC_REJECT_LAND);
10829 bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS); 11094 bool checkAgents = !((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) == ScriptBaseClass.RC_REJECT_AGENTS);
10830 bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL); 11095 bool checkNonPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) == ScriptBaseClass.RC_REJECT_NONPHYSICAL);
10831 bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL); 11096 bool checkPhysical = !((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) == ScriptBaseClass.RC_REJECT_PHYSICAL);
10832 11097
10833 for (float i = 0; i <= distance; i += 0.1f) 11098
11099 if (checkTerrain)
10834 { 11100 {
10835 posToCheck = startvector + (dir * (i / (float)distance)); 11101 ContactResult? groundContact = GroundIntersection(rayStart, rayEnd);
11102 if (groundContact != null)
11103 results.Add((ContactResult)groundContact);
11104 }
10836 11105
10837 if (checkTerrain && channel[(int)(posToCheck.X + startvector.X), (int)(posToCheck.Y + startvector.Y)] < posToCheck.Z) 11106 if (checkAgents)
10838 { 11107 {
10839 ContactResult result = new ContactResult(); 11108 ContactResult[] agentHits = AvatarIntersection(rayStart, rayEnd);
10840 result.ConsumerID = 0; 11109 foreach (ContactResult r in agentHits)
10841 result.Depth = 0; 11110 results.Add(r);
10842 result.Normal = Vector3.Zero; 11111 }
10843 result.Pos = posToCheck;
10844 results.Add(result);
10845 checkTerrain = false;
10846 }
10847 11112
10848 if (checkAgents) 11113 if (checkPhysical || checkNonPhysical || detectPhantom)
10849 { 11114 {
10850 World.ForEachRootScenePresence(delegate(ScenePresence sp) 11115 ContactResult[] objectHits = ObjectIntersection(rayStart, rayEnd, checkPhysical, checkNonPhysical, detectPhantom);
10851 { 11116 foreach (ContactResult r in objectHits)
10852 if (sp.AbsolutePosition.ApproxEquals(posToCheck, sp.PhysicsActor.Size.X)) 11117 results.Add(r);
10853 {
10854 ContactResult result = new ContactResult ();
10855 result.ConsumerID = sp.LocalId;
10856 result.Depth = 0;
10857 result.Normal = Vector3.Zero;
10858 result.Pos = posToCheck;
10859 results.Add(result);
10860 }
10861 });
10862 }
10863 } 11118 }
10864 11119
10865 int refcount = 0; 11120 results.Sort(delegate(ContactResult a, ContactResult b)
11121 {
11122 return a.Depth.CompareTo(b.Depth);
11123 });
11124
11125 int values = 0;
11126 SceneObjectGroup thisgrp = m_host.ParentGroup;
11127
10866 foreach (ContactResult result in results) 11128 foreach (ContactResult result in results)
10867 { 11129 {
10868 if ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) 11130 if (result.Depth > dist)
10869 == ScriptBaseClass.RC_REJECT_LAND && result.ConsumerID == 0)
10870 continue; 11131 continue;
10871 11132
10872 ISceneEntity entity = World.GetSceneObjectPart(result.ConsumerID); 11133 // physics ray can return colisions with host prim
11134 if (m_host.LocalId == result.ConsumerID)
11135 continue;
10873 11136
10874 if (entity == null && (rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != ScriptBaseClass.RC_REJECT_AGENTS) 11137 UUID itemID = UUID.Zero;
10875 entity = World.GetScenePresence(result.ConsumerID); //Only check if we should be looking for agents 11138 int linkNum = 0;
10876 11139
10877 if (entity == null) 11140 SceneObjectPart part = World.GetSceneObjectPart(result.ConsumerID);
11141 // It's a prim!
11142 if (part != null)
10878 { 11143 {
10879 list.Add(UUID.Zero); 11144 // dont detect members of same object ???
10880 11145 if (part.ParentGroup == thisgrp)
10881 if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) 11146 continue;
10882 list.Add(0);
10883 11147
10884 list.Add(result.Pos); 11148 if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY)
10885 11149 itemID = part.ParentGroup.UUID;
10886 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) 11150 else
10887 list.Add(result.Normal); 11151 itemID = part.UUID;
10888 11152
10889 continue; //Can't find it, so add UUID.Zero 11153 linkNum = part.LinkNum;
10890 } 11154 }
10891 11155 else
10892 /*if (detectPhantom == 0 && intersection.obj is ISceneChildEntity &&
10893 ((ISceneChildEntity)intersection.obj).PhysActor == null)
10894 continue;*/ //Can't do this ATM, physics engine knows only of non phantom objects
10895
10896 if (entity is SceneObjectPart)
10897 { 11156 {
10898 PhysicsActor pa = ((SceneObjectPart)entity).PhysActor; 11157 ScenePresence sp = World.GetScenePresence(result.ConsumerID);
10899 11158 /// It it a boy? a girl?
10900 if (pa != null && pa.IsPhysical) 11159 if (sp != null)
10901 { 11160 itemID = sp.UUID;
10902 if (!checkPhysical)
10903 continue;
10904 }
10905 else
10906 {
10907 if (!checkNonPhysical)
10908 continue;
10909 }
10910 } 11161 }
10911 11162
10912 refcount++; 11163 list.Add(new LSL_String(itemID.ToString()));
10913 if ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) == ScriptBaseClass.RC_GET_ROOT_KEY && entity is SceneObjectPart) 11164 list.Add(new LSL_String(result.Pos.ToString()));
10914 list.Add(((SceneObjectPart)entity).ParentGroup.UUID);
10915 else
10916 list.Add(entity.UUID);
10917 11165
10918 if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM) 11166 if ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) == ScriptBaseClass.RC_GET_LINK_NUM)
10919 { 11167 list.Add(new LSL_Integer(linkNum));
10920 if (entity is SceneObjectPart)
10921 list.Add(((SceneObjectPart)entity).LinkNum);
10922 else
10923 list.Add(0);
10924 }
10925
10926 list.Add(result.Pos);
10927 11168
10928 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL) 11169 if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
10929 list.Add(result.Normal); 11170 list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z));
11171
11172 values++;
11173 if (values >= count)
11174 break;
10930 } 11175 }
10931 11176
10932 list.Add(refcount); //The status code, either the # of contacts, RCERR_SIM_PERF_LOW, or RCERR_CAST_TIME_EXCEEDED 11177 list.Add(new LSL_Integer(values));
10933 11178
10934 return list; 11179 return list;
10935 } 11180 }