aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorMagnuz Binder2015-05-03 07:50:13 +0200
committerdahlia2015-05-03 23:41:11 -0700
commit43b8bd0c35c1d7ca0c97a4e64fe255943148d333 (patch)
tree212cbce67281817d2884924ef8ac0ab9a9dcefd3
parentOnly send parcel layer data around the point of interest. Can be disabled (diff)
downloadopensim-SC_OLD-43b8bd0c35c1d7ca0c97a4e64fe255943148d333.zip
opensim-SC_OLD-43b8bd0c35c1d7ca0c97a4e64fe255943148d333.tar.gz
opensim-SC_OLD-43b8bd0c35c1d7ca0c97a4e64fe255943148d333.tar.bz2
opensim-SC_OLD-43b8bd0c35c1d7ca0c97a4e64fe255943148d333.tar.xz
Implement llCastRay fully, simplified.
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs760
-rw-r--r--bin/OpenSimDefaults.ini38
2 files changed, 797 insertions, 1 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index e20e4c4..cf1bd2b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -218,6 +218,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
218 protected float m_lABB2SitZ0 = -0.25f; 218 protected float m_lABB2SitZ0 = -0.25f;
219 protected float m_lABB2SitZ1 = 0.25f; 219 protected float m_lABB2SitZ1 = 0.25f;
220 220
221 protected float m_primSafetyCoeffX = 2.414214f;
222 protected float m_primSafetyCoeffY = 2.414214f;
223 protected float m_primSafetyCoeffZ = 1.618034f;
224 protected float m_floatToleranceInCastRay = 0.000001f;
225 protected float m_floatTolerance2InCastRay = 0.0001f;
226 protected int m_maxHitsInCastRay = 16;
227 protected int m_maxHitsPerPrimInCastRay = 16;
228 protected int m_maxHitsPerObjectInCastRay = 16;
229 protected bool m_detectExitsInCastRay = false;
230 protected bool m_filterPartsInCastRay = false;
231 protected bool m_doAttachmentsInCastRay = false;
232 protected bool m_useCastRayV1 = true;
233
221 //An array of HTTP/1.1 headers that are not allowed to be used 234 //An array of HTTP/1.1 headers that are not allowed to be used
222 //as custom headers by llHTTPRequest. 235 //as custom headers by llHTTPRequest.
223 private string[] HttpStandardHeaders = 236 private string[] HttpStandardHeaders =
@@ -320,6 +333,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
320 m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1); 333 m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1);
321 m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0); 334 m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0);
322 m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1); 335 m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1);
336 m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX);
337 m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY);
338 m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ);
339 m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay);
340 m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay);
341 m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay);
342 m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay);
343 m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay);
344 m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay);
345 m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay);
346 m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay);
347 m_useCastRayV1 = lslConfig.GetBoolean("UseLlCastRayV1", m_useCastRayV1);
323 } 348 }
324 349
325 IConfig smtpConfig = seConfigSource.Configs["SMTP"]; 350 IConfig smtpConfig = seConfigSource.Configs["SMTP"];
@@ -13738,7 +13763,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
13738 return contacts[0]; 13763 return contacts[0];
13739 } 13764 }
13740 13765
13741 public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) 13766 public LSL_List llCastRayV1(LSL_Vector start, LSL_Vector end, LSL_List options)
13742 { 13767 {
13743 LSL_List list = new LSL_List(); 13768 LSL_List list = new LSL_List();
13744 13769
@@ -13929,6 +13954,739 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
13929 return list; 13954 return list;
13930 } 13955 }
13931 13956
13957 /// <summary>
13958 /// Full implementation of llCastRay similar to SL 2015-04-21.
13959 /// http://wiki.secondlife.com/wiki/LlCastRay
13960 /// Uses pure geometry, bounding shapes, meshing and no physics
13961 /// for prims, sculpts, meshes, avatars and terrain.
13962 /// Implements all flags, reject types and data flags.
13963 /// Can handle both objects/groups and prims/parts, by config.
13964 /// May give poor results with multi-part meshes where "root"
13965 /// part doesn't dominate, owing to "guessed" bounding boxes.
13966 /// May sometimes be inaccurate owing to calculation precision
13967 /// and a bug in libopenmetaverse PrimMesher.
13968 /// </summary>
13969 public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options)
13970 {
13971 // Use llCastRay v1 if configured
13972 if (m_useCastRayV1)
13973 return llCastRayV1(start, end, options);
13974
13975 // Initialize
13976 m_host.AddScriptLPS(1);
13977 List<RayHit> rayHits = new List<RayHit>();
13978 LSL_List result = new LSL_List();
13979 float tol = m_floatToleranceInCastRay;
13980 float tol2 = m_floatTolerance2InCastRay;
13981
13982 // Get input options
13983 int rejectTypes = 0;
13984 int dataFlags = 0;
13985 int maxHits = 1;
13986 bool detectPhantom = false;
13987 for (int i = 0; i < options.Length; i += 2)
13988 {
13989 if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES)
13990 rejectTypes = options.GetLSLIntegerItem(i + 1);
13991 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS)
13992 dataFlags = options.GetLSLIntegerItem(i + 1);
13993 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS)
13994 maxHits = options.GetLSLIntegerItem(i + 1);
13995 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM)
13996 detectPhantom = (options.GetLSLIntegerItem(i + 1) != 0);
13997 }
13998 if (maxHits > m_maxHitsInCastRay)
13999 maxHits = m_maxHitsInCastRay;
14000 bool rejectAgents = ((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != 0);
14001 bool rejectPhysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) != 0);
14002 bool rejectNonphysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) != 0);
14003 bool rejectLand = ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) != 0);
14004 bool getNormal = ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) != 0);
14005 bool getRootKey = ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) != 0);
14006 bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0);
14007
14008 // Calculate some basic parameters
14009 Vector3 ray = end - start;
14010 float rayLength = ray.Length();
14011
14012 // Try to get a mesher and return failure if none or degenerate ray
14013 IRendering primMesher = null;
14014 List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
14015 if (renderers.Count < 1 || rayLength < tol)
14016 {
14017 result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN));
14018 return result;
14019 }
14020 primMesher = RenderingLoader.LoadRenderer(renderers[0]);
14021
14022 // Used to translate and rotate world so ray is along negative Z axis from origo and
14023 // calculations mostly simplified to a 2D projecttion on the X-Y plane
14024 Vector3 posProj = new Vector3(-start);
14025 Quaternion rotProj = Vector3.RotationBetween(ray, new Vector3(0.0f, 0.0f, -1.0f));
14026 Quaternion rotBack = Quaternion.Inverse(rotProj);
14027
14028 // Iterate over all objects/groups and prims/parts in region
14029 World.ForEachSOG(
14030 delegate(SceneObjectGroup group)
14031 {
14032 // Check group filters unless part filters are configured
14033 bool isPhysical = (group.RootPart != null && group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical);
14034 bool isNonphysical = !isPhysical;
14035 bool isPhantom = group.IsPhantom || group.IsVolumeDetect;
14036 bool isAttachment = group.IsAttachment;
14037 bool doGroup = true;
14038 if (isPhysical && rejectPhysical)
14039 doGroup = false;
14040 if (isNonphysical && rejectNonphysical)
14041 doGroup = false;
14042 if (isPhantom && detectPhantom)
14043 doGroup = true;
14044 if (m_filterPartsInCastRay)
14045 doGroup = true;
14046 if (isAttachment && !m_doAttachmentsInCastRay)
14047 doGroup = false;
14048 // Parse object/group if passed filters
14049 if (doGroup)
14050 {
14051 // Iterate over all prims/parts in object/group
14052 foreach(SceneObjectPart part in group.Parts)
14053 {
14054 // Check part filters if configured
14055 if (m_filterPartsInCastRay)
14056 {
14057 isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical);
14058 isNonphysical = !isPhysical;
14059 isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || (part.VolumeDetectActive);
14060 bool doPart = true;
14061 if (isPhysical && rejectPhysical)
14062 doPart = false;
14063 if (isNonphysical && rejectNonphysical)
14064 doPart = false;
14065 if (isPhantom && detectPhantom)
14066 doPart = true;
14067 if (!doPart)
14068 continue;
14069 }
14070 // Parse prim/part if passed filters
14071
14072 // Estimate bounding box from size box
14073 Vector3 scaleSafe = part.Scale;
14074 if (!part.Shape.SculptEntry)
14075 scaleSafe = scaleSafe * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ));
14076
14077 // Filter parts by bounding shapes
14078 Vector3 posPartRel = part.GetWorldPosition() + posProj;
14079 Vector3 posPartProj = posPartRel * rotProj;
14080 if (InBoundingShapes(ray, rayLength, scaleSafe, posPartRel, posPartProj, rotProj))
14081 {
14082 // Prepare data needed to check for ray hits
14083 RayTrans rayTrans = new RayTrans();
14084 rayTrans.PartId = part.UUID;
14085 rayTrans.GroupId = part.ParentGroup.UUID;
14086 rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0;
14087 rayTrans.Scale = part.Scale;
14088 rayTrans.PositionPartProj = posPartProj;
14089 rayTrans.PositionProj = posProj;
14090 rayTrans.RotationPartProj = rotProj * part.GetWorldRotation();
14091 rayTrans.RotationBack = rotBack;
14092 rayTrans.NeedsEnds = true;
14093 rayTrans.RayLength = rayLength;
14094 rayTrans.Tolerance = tol;
14095 rayTrans.Tolerance2 = tol2;
14096
14097 // Make an OMV prim to be able to mesh part
14098 Primitive omvPrim = part.Shape.ToOmvPrimitive(posPartProj, rayTrans.RotationPartProj);
14099 byte[] sculptAsset = null;
14100 if (omvPrim.Sculpt != null)
14101 sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());
14102
14103 // When part is mesh, get and check mesh
14104 if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null)
14105 {
14106 AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
14107 FacetedMesh mesh = null;
14108 FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh);
14109 meshAsset = null;
14110 AddRayInFacetedMesh(mesh, rayTrans, ref rayHits);
14111 mesh = null;
14112 }
14113
14114 // When part is sculpt, create and check mesh
14115 // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt.
14116 else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null)
14117 {
14118 IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>();
14119 if (imgDecoder != null)
14120 {
14121 Image sculpt = imgDecoder.DecodeToImage(sculptAsset);
14122 if (sculpt != null)
14123 {
14124 SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium);
14125 sculpt.Dispose();
14126 AddRayInSimpleMesh(mesh, rayTrans, ref rayHits);
14127 mesh = null;
14128 }
14129 }
14130 }
14131
14132 // When part is prim, create and check mesh
14133 else if (omvPrim.Sculpt == null)
14134 {
14135 if (
14136 omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 &&
14137 omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 &&
14138 omvPrim.PrimData.PathSkew == 0.0 &&
14139 omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0
14140 )
14141 rayTrans.NeedsEnds = false;
14142 SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium);
14143 AddRayInSimpleMesh(mesh, rayTrans, ref rayHits);
14144 mesh = null;
14145 }
14146
14147 }
14148 }
14149 }
14150 }
14151 );
14152
14153 // Check avatar filter
14154 if (!rejectAgents)
14155 {
14156 // Iterate over all avatars in region
14157 World.ForEachRootScenePresence(
14158 delegate (ScenePresence sp)
14159 {
14160 // Parse avatar
14161
14162 // Get bounding box
14163 Vector3 lower;
14164 Vector3 upper;
14165 BoundingBoxOfScenePresence(sp, out lower, out upper);
14166 Vector3 scale = upper - lower;
14167
14168 // Filter avatars by bounding shapes
14169 Vector3 posPartRel = sp.AbsolutePosition + posProj + (lower + upper) * 0.5f * sp.Rotation;
14170 Vector3 posPartProj = posPartRel * rotProj;
14171 if (InBoundingShapes(ray, rayLength, scale, posPartRel, posPartProj, rotProj))
14172 {
14173 // Prepare data needed to check for ray hits
14174 RayTrans rayTrans = new RayTrans();
14175 rayTrans.PartId = sp.UUID;
14176 rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID;
14177 rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0;
14178 rayTrans.Scale = scale;
14179 rayTrans.PositionPartProj = posPartProj;
14180 rayTrans.PositionProj = posProj;
14181 rayTrans.RotationPartProj = rotProj * sp.Rotation;
14182 rayTrans.RotationBack = rotBack;
14183 rayTrans.NeedsEnds = false;
14184 rayTrans.RayLength = rayLength;
14185 rayTrans.Tolerance = tol;
14186 rayTrans.Tolerance2 = tol2;
14187
14188 // Make OMV prim, create and check mesh
14189 Primitive omvPrim = MakeOpenMetaversePrim(scale, posPartProj, rayTrans.RotationPartProj, ScriptBaseClass.PRIM_TYPE_SPHERE);
14190 SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium);
14191 AddRayInSimpleMesh(mesh, rayTrans, ref rayHits);
14192 mesh = null;
14193 }
14194 }
14195 );
14196 }
14197
14198 // Check terrain filter
14199 if (!rejectLand)
14200 {
14201 // Parse terrain
14202
14203 // Mesh terrain and check projected bounding box
14204 Vector3 posPartProj = posProj * rotProj;
14205 Quaternion rotPartProj = rotProj;
14206 Vector3 lower;
14207 Vector3 upper;
14208 List<Tri> triangles = TrisFromHeightmapUnderRay(start, end, out lower, out upper);
14209 Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
14210 Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue);
14211 int dummy = 0;
14212 AddBoundingBoxOfSimpleBox(lower, upper, posPartProj, rotPartProj, true, ref lowerBox, ref upperBox, ref dummy);
14213 if (lowerBox.X <= tol && lowerBox.Y <= tol && lowerBox.Z <= tol && upperBox.X >= -tol && upperBox.Y >= -tol && upperBox.Z >= -rayLength - tol)
14214 {
14215 // Prepare data needed to check for ray hits
14216 RayTrans rayTrans = new RayTrans();
14217 rayTrans.PartId = UUID.Zero;
14218 rayTrans.GroupId = UUID.Zero;
14219 rayTrans.Link = 0;
14220 rayTrans.Scale = new Vector3 (1.0f, 1.0f, 1.0f);
14221 rayTrans.PositionPartProj = posPartProj;
14222 rayTrans.PositionProj = posProj;
14223 rayTrans.RotationPartProj = rotPartProj;
14224 rayTrans.RotationBack = rotBack;
14225 rayTrans.NeedsEnds = true;
14226 rayTrans.RayLength = rayLength;
14227 rayTrans.Tolerance = tol;
14228 rayTrans.Tolerance2 = tol2;
14229
14230 // Check mesh
14231 AddRayInTris(triangles, rayTrans, ref rayHits);
14232 triangles = null;
14233 }
14234 }
14235
14236 // Sort hits by ascending distance
14237 rayHits.Sort((s1, s2) => s1.Distance.CompareTo(s2.Distance));
14238
14239 // Check excess hits per part and group
14240 for (int t = 0; t < 2; t++)
14241 {
14242 int maxHitsPerType = 0;
14243 UUID id = UUID.Zero;
14244 if (t == 0)
14245 maxHitsPerType = m_maxHitsPerPrimInCastRay;
14246 else
14247 maxHitsPerType = m_maxHitsPerObjectInCastRay;
14248
14249 // Handle excess hits only when needed
14250 if (maxHitsPerType < m_maxHitsInCastRay)
14251 {
14252 // Find excess hits
14253 Hashtable hits = new Hashtable();
14254 for (int i = rayHits.Count - 1; i >= 0; i--)
14255 {
14256 if (t == 0)
14257 id = rayHits[i].PartId;
14258 else
14259 id = rayHits[i].GroupId;
14260 if (hits.ContainsKey(id))
14261 hits[id] = (int)hits[id] + 1;
14262 else
14263 hits[id] = 1;
14264 }
14265
14266 // Remove excess hits
14267 for (int i = rayHits.Count - 1; i >= 0; i--)
14268 {
14269 if (t == 0)
14270 id = rayHits[i].PartId;
14271 else
14272 id = rayHits[i].GroupId;
14273 int hit = (int)hits[id];
14274 if (hit > m_maxHitsPerPrimInCastRay)
14275 {
14276 rayHits.RemoveAt(i);
14277 hit--;
14278 hits[id] = hit;
14279 }
14280 }
14281 }
14282 }
14283
14284 // Parse hits into result list according to data flags
14285 int hitCount = rayHits.Count;
14286 if (hitCount > maxHits)
14287 hitCount = maxHits;
14288 for (int i = 0; i < hitCount; i++)
14289 {
14290 RayHit rayHit = rayHits[i];
14291 if (getRootKey)
14292 result.Add(new LSL_Key(rayHit.GroupId.ToString()));
14293 else
14294 result.Add(new LSL_Key(rayHit.PartId.ToString()));
14295 result.Add(new LSL_Vector(rayHit.Position));
14296 if (getLinkNum)
14297 result.Add(new LSL_Integer(rayHit.Link));
14298 if (getNormal)
14299 result.Add(new LSL_Vector(rayHit.Normal));
14300 }
14301 result.Add(new LSL_Integer(hitCount));
14302 return result;
14303 }
14304
14305 /// <summary>
14306 /// Struct for transmitting parameters required for finding llCastRay ray hits.
14307 /// </summary>
14308 public struct RayTrans
14309 {
14310 public UUID PartId;
14311 public UUID GroupId;
14312 public int Link;
14313 public Vector3 Scale;
14314 public Vector3 PositionPartProj;
14315 public Vector3 PositionProj;
14316 public Quaternion RotationPartProj;
14317 public Quaternion RotationBack;
14318 public bool NeedsEnds;
14319 public float RayLength;
14320 public float Tolerance;
14321 public float Tolerance2;
14322 }
14323
14324 /// <summary>
14325 /// Struct for llCastRay ray hits.
14326 /// </summary>
14327 public struct RayHit
14328 {
14329 public UUID PartId;
14330 public UUID GroupId;
14331 public int Link;
14332 public Vector3 Position;
14333 public Vector3 Normal;
14334 public float Distance;
14335 }
14336
14337 /// <summary>
14338 /// Helper to parse SimpleMesh for ray hits.
14339 /// </summary>
14340 private void AddRayInSimpleMesh(SimpleMesh mesh, RayTrans rayTrans, ref List<RayHit> rayHits)
14341 {
14342 if (mesh != null)
14343 {
14344 for (int i = 0; i < mesh.Indices.Count; i += 3)
14345 {
14346 Tri triangle = new Tri();
14347 triangle.p1 = mesh.Vertices[mesh.Indices[i]].Position;
14348 triangle.p2 = mesh.Vertices[mesh.Indices[i + 1]].Position;
14349 triangle.p3 = mesh.Vertices[mesh.Indices[i + 2]].Position;
14350 AddRayInTri(triangle, rayTrans, ref rayHits);
14351 }
14352 }
14353 }
14354
14355 /// <summary>
14356 /// Helper to parse FacetedMesh for ray hits.
14357 /// </summary>
14358 private void AddRayInFacetedMesh(FacetedMesh mesh, RayTrans rayTrans, ref List<RayHit> rayHits)
14359 {
14360 if (mesh != null)
14361 {
14362 foreach (Face face in mesh.Faces)
14363 {
14364 for (int i = 0; i <face.Indices.Count; i += 3)
14365 {
14366 Tri triangle = new Tri();
14367 triangle.p1 = face.Vertices[face.Indices[i]].Position;
14368 triangle.p2 = face.Vertices[face.Indices[i + 1]].Position;
14369 triangle.p3 = face.Vertices[face.Indices[i + 2]].Position;
14370 AddRayInTri(triangle, rayTrans, ref rayHits);
14371 }
14372 }
14373 }
14374 }
14375
14376 /// <summary>
14377 /// Helper to parse Tri (triangle) List for ray hits.
14378 /// </summary>
14379 private void AddRayInTris(List<Tri> triangles, RayTrans rayTrans, ref List<RayHit> rayHits)
14380 {
14381 foreach (Tri triangle in triangles)
14382 {
14383 AddRayInTri(triangle, rayTrans, ref rayHits);
14384 }
14385 }
14386
14387 /// <summary>
14388 /// Helper to add ray hit in a Tri (triangle).
14389 /// </summary>
14390 private void AddRayInTri(Tri triangle, RayTrans rayTrans, ref List<RayHit> rayHits)
14391 {
14392 // Check for hit in triangle
14393 float distance;
14394 Vector3 posHit;
14395 Vector3 normal;
14396 if (HitRayInTri(triangle, rayTrans, out distance, out posHit, out normal))
14397 {
14398 // Project hit part back to normal coordinate system
14399 Vector3 posPart = rayTrans.PositionPartProj * rayTrans.RotationBack - rayTrans.PositionProj;
14400 // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) faces plane through shape center
14401 if (Math.Abs(Vector3.Dot(posPart, normal) - Vector3.Dot(posHit, normal)) < rayTrans.Tolerance && !rayTrans.NeedsEnds)
14402 return;
14403 // Remove duplicate hits at triangle edges and intersections
14404 for (int i = rayHits.Count - 1; i >= 0; i--)
14405 {
14406 if (rayHits[i].PartId == rayTrans.PartId && Math.Abs(rayHits[i].Distance - distance) < rayTrans.Tolerance2)
14407 return;
14408 }
14409
14410 // Build result data set
14411 RayHit rayHit = new RayHit();
14412 rayHit.PartId = rayTrans.PartId;
14413 rayHit.GroupId = rayTrans.GroupId;
14414 rayHit.Link = rayTrans.Link;
14415 rayHit.Position = posHit;
14416 rayHit.Normal = normal;
14417 rayHit.Distance = distance;
14418 rayHits.Add(rayHit);
14419 }
14420 }
14421
14422 /// <summary>
14423 /// Helper to find ray hit in a Tri (triangle).
14424 /// </summary>
14425 private bool HitRayInTri(Tri triangle, RayTrans rayTrans, out float distance, out Vector3 posHit, out Vector3 normal)
14426 {
14427 // Initialize
14428 distance = 0.0f;
14429 posHit = Vector3.Zero;
14430 normal = Vector3.Zero;
14431 float tol = rayTrans.Tolerance;
14432
14433 // Project triangle on X-Y plane
14434 Vector3 pos1 = triangle.p1 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj;
14435 Vector3 pos2 = triangle.p2 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj;
14436 Vector3 pos3 = triangle.p3 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj;
14437
14438 // Check if ray/origo inside triangle bounding rectangle
14439 Vector3 lower = Vector3.Min(pos1, Vector3.Min(pos2, pos3));
14440 Vector3 upper = Vector3.Max(pos1, Vector3.Max(pos2, pos3));
14441 if (lower.X > tol || lower.Y > tol || lower.Z > tol || upper.X < -tol || upper.Y < -tol || upper.Z < -rayTrans.RayLength - tol)
14442 return false;
14443
14444 // Check if ray/origo inside every edge or reverse "outside" every edge on exit
14445 float dist;
14446 bool inside = true;
14447 bool outside = true;
14448 Vector3 vec1 = pos2 - pos1;
14449 dist = pos1.X * vec1.Y - pos1.Y * vec1.X;
14450 if (dist < -tol)
14451 inside = false;
14452 if (dist > tol)
14453 outside = false;
14454 Vector3 vec2 = pos3 - pos2;
14455 dist = pos2.X * vec2.Y - pos2.Y * vec2.X;
14456 if (dist < -tol)
14457 inside = false;
14458 if (dist > tol)
14459 outside = false;
14460 Vector3 vec3 = pos1 - pos3;
14461 dist = pos3.X * vec3.Y - pos3.Y * vec3.X;
14462 if (dist < -tol)
14463 inside = false;
14464 if (dist > tol)
14465 outside = false;
14466
14467 // Skip if ray/origo outside
14468 if (!inside && !(outside && m_detectExitsInCastRay))
14469 return false;
14470
14471 // Calculate normal
14472 Vector3 normalProj = Vector3.Cross(vec1, vec2);
14473 float normalLength = normalProj.Length();
14474 // Skip if degenerate triangle
14475 if (normalLength < tol)
14476 return false;
14477 normalProj = normalProj / normalLength;
14478 // Skip if ray parallell to triangle plane
14479 if (Math.Abs(normalProj.Z) < tol)
14480 return false;
14481
14482 // Calculate distance
14483 distance = Vector3.Dot(normalProj, pos2) / normalProj.Z * -1.0f;
14484 // Skip if outside ray
14485 if (distance < -tol || distance > rayTrans.RayLength + tol)
14486 return false;
14487
14488 // Calculate projected hit position
14489 Vector3 posHitProj = new Vector3(0.0f, 0.0f, -distance);
14490 // Project hit back to normal coordinate system
14491 posHit = posHitProj * rayTrans.RotationBack - rayTrans.PositionProj;
14492 normal = normalProj * rayTrans.RotationBack;
14493 return true;
14494 }
14495
14496 /// <summary>
14497 /// Helper to parse selected parts of HeightMap into a Tri (triangle) List and calculate bounding box.
14498 /// </summary>
14499 private List<Tri> TrisFromHeightmapUnderRay(Vector3 posStart, Vector3 posEnd, out Vector3 lower, out Vector3 upper)
14500 {
14501 // Get bounding X-Y rectangle of terrain under ray
14502 lower = Vector3.Min(posStart, posEnd);
14503 upper = Vector3.Max(posStart, posEnd);
14504 lower.X = (float)Math.Floor(lower.X);
14505 lower.Y = (float)Math.Floor(lower.Y);
14506 float zLower = float.MaxValue;
14507 upper.X = (float)Math.Ceiling(upper.X);
14508 upper.Y = (float)Math.Ceiling(upper.Y);
14509 float zUpper = float.MinValue;
14510
14511 // Initialize Tri (triangle) List
14512 List<Tri> triangles = new List<Tri>();
14513
14514 // Set parsing lane direction to major ray X-Y axis
14515 Vector3 vec = posEnd - posStart;
14516 float xAbs = Math.Abs(vec.X);
14517 float yAbs = Math.Abs(vec.Y);
14518 bool bigX = true;
14519 if (yAbs > xAbs)
14520 {
14521 bigX = false;
14522 vec = vec / yAbs;
14523 }
14524 else if (xAbs > yAbs || xAbs > 0.0f)
14525 vec = vec / xAbs;
14526 else
14527 vec = new Vector3(1.0f, 1.0f, 0.0f);
14528
14529 // Simplify by start parsing in lower end of lane
14530 if ((bigX && vec.X < 0.0f) || (!bigX && vec.Y < 0.0f))
14531 {
14532 Vector3 posTemp = posStart;
14533 posStart = posEnd;
14534 posEnd = posTemp;
14535 vec = vec * -1.0f;
14536 }
14537
14538 // First 1x1 rectangle under ray
14539 float xFloorOld = 0.0f;
14540 float yFloorOld = 0.0f;
14541 Vector3 pos = posStart;
14542 float xFloor = (float)Math.Floor(pos.X);
14543 float yFloor = (float)Math.Floor(pos.Y);
14544 AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper);
14545
14546 // Parse every remaining 1x1 rectangle under ray
14547 while (pos != posEnd)
14548 {
14549 // Next 1x1 rectangle under ray
14550 xFloorOld = xFloor;
14551 yFloorOld = yFloor;
14552 pos = pos + vec;
14553
14554 // Clip position to 1x1 rectangle border
14555 xFloor = (float)Math.Floor(pos.X);
14556 yFloor = (float)Math.Floor(pos.Y);
14557 if (bigX && pos.X > xFloor)
14558 {
14559 pos.Y -= vec.Y * (pos.X - xFloor);
14560 pos.X = xFloor;
14561 }
14562 else if (!bigX && pos.Y > yFloor)
14563 {
14564 pos.X -= vec.X * (pos.Y - yFloor);
14565 pos.Y = yFloor;
14566 }
14567
14568 // Last 1x1 rectangle under ray
14569 if ((bigX && pos.X >= posEnd.X) || (!bigX && pos.Y >= posEnd.Y))
14570 {
14571 pos = posEnd;
14572 xFloor = (float)Math.Floor(pos.X);
14573 yFloor = (float)Math.Floor(pos.Y);
14574 }
14575
14576 // Add new 1x1 rectangle in lane
14577 if ((bigX && xFloor != xFloorOld) || (!bigX && yFloor != yFloorOld))
14578 AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper);
14579 // Add last 1x1 rectangle in old lane at lane shift
14580 if (bigX && yFloor != yFloorOld)
14581 AddTrisFromHeightmap(xFloor, yFloorOld, ref triangles, ref zLower, ref zUpper);
14582 if (!bigX && xFloor != xFloorOld)
14583 AddTrisFromHeightmap(xFloorOld, yFloor, ref triangles, ref zLower, ref zUpper);
14584 }
14585
14586 // Finalize bounding box Z
14587 lower.Z = zLower;
14588 upper.Z = zUpper;
14589
14590 // Done and returning Tri (triangle)List
14591 return triangles;
14592 }
14593
14594 /// <summary>
14595 /// Helper to add HeightMap squares into Tri (triangle) List and adjust bounding box.
14596 /// </summary>
14597 private void AddTrisFromHeightmap(float xPos, float yPos, ref List<Tri> triangles, ref float zLower, ref float zUpper)
14598 {
14599 int xInt = (int)xPos;
14600 int yInt = (int)yPos;
14601
14602 // Corner 1 of 1x1 rectangle
14603 int x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1);
14604 int y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1);
14605 Vector3 pos1 = new Vector3(x, y, (float)World.Heightmap[x, y]);
14606 // Adjust bounding box
14607 zLower = Math.Min(zLower, pos1.Z);
14608 zUpper = Math.Max(zUpper, pos1.Z);
14609
14610 // Corner 2 of 1x1 rectangle
14611 x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1);
14612 y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1);
14613 Vector3 pos2 = new Vector3(x, y, (float)World.Heightmap[x, y]);
14614 // Adjust bounding box
14615 zLower = Math.Min(zLower, pos1.Z);
14616 zUpper = Math.Max(zUpper, pos1.Z);
14617
14618 // Corner 3 of 1x1 rectangle
14619 x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1);
14620 y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1);
14621 Vector3 pos3 = new Vector3(x, y, (float)World.Heightmap[x, y]);
14622 // Adjust bounding box
14623 zLower = Math.Min(zLower, pos1.Z);
14624 zUpper = Math.Max(zUpper, pos1.Z);
14625
14626 // Corner 4 of 1x1 rectangle
14627 x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1);
14628 y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1);
14629 Vector3 pos4 = new Vector3(x, y, (float)World.Heightmap[x, y]);
14630 // Adjust bounding box
14631 zLower = Math.Min(zLower, pos1.Z);
14632 zUpper = Math.Max(zUpper, pos1.Z);
14633
14634 // Add triangle 1
14635 Tri triangle1 = new Tri();
14636 triangle1.p1 = pos1;
14637 triangle1.p2 = pos2;
14638 triangle1.p3 = pos3;
14639 triangles.Add(triangle1);
14640
14641 // Add triangle 2
14642 Tri triangle2 = new Tri();
14643 triangle2.p1 = pos3;
14644 triangle2.p2 = pos4;
14645 triangle2.p3 = pos1;
14646 triangles.Add(triangle2);
14647 }
14648
14649 /// <summary>
14650 /// Helper to check if a ray intersects bounding shapes.
14651 /// </summary>
14652 private bool InBoundingShapes(Vector3 ray, float rayLength, Vector3 scale, Vector3 posPartRel, Vector3 posPartProj, Quaternion rotProj)
14653 {
14654 float tol = m_floatToleranceInCastRay;
14655
14656 // Check if ray intersects projected bounding box
14657 Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
14658 Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue);
14659 int dummy = 0;
14660 AddBoundingBoxOfSimpleBox(scale * -0.5f, scale * 0.5f, posPartProj, rotProj, true, ref lowerBox, ref upperBox, ref dummy);
14661 if (lowerBox.X > tol || lowerBox.Y > tol || lowerBox.Z > tol || upperBox.X < -tol || upperBox.Y < -tol || upperBox.Z < -rayLength - tol)
14662 return false;
14663
14664 // Passed bounding shape filters, so return true
14665 return true;
14666 }
14667
14668 /// <summary>
14669 /// Helper to get link number for a UUID.
14670 /// </summary>
14671 private int UUID2LinkNumber(SceneObjectPart part, UUID id)
14672 {
14673 SceneObjectGroup group = part.ParentGroup;
14674 if (group != null)
14675 {
14676 // Parse every link for UUID
14677 int linkCount = group.PrimCount + group.GetSittingAvatarsCount();
14678 for (int link = linkCount; link > 0; link--)
14679 {
14680 ISceneEntity entity = GetLinkEntity(part, link);
14681 // Return link number if UUID match
14682 if (entity != null && entity.UUID == id)
14683 return link;
14684 }
14685 }
14686 // Return link number 0 if no links or UUID matches
14687 return 0;
14688 }
14689
13932 public LSL_Integer llManageEstateAccess(int action, string avatar) 14690 public LSL_Integer llManageEstateAccess(int action, string avatar)
13933 { 14691 {
13934 m_host.AddScriptLPS(1); 14692 m_host.AddScriptLPS(1);
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index a5d7f1d..d3f183e 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -1477,6 +1477,44 @@
1477 ; Avatar bounding box, upper Z value, coefficient to multiply with avatar height, when sitting 1477 ; Avatar bounding box, upper Z value, coefficient to multiply with avatar height, when sitting
1478 UpperAvatarBoundingBoxSittingZcoeff = 0.25 1478 UpperAvatarBoundingBoxSittingZcoeff = 0.25
1479 1479
1480 ; Safety coefficient for max bounding box from prim size box X coordinate
1481 ; Worst case is twisted and sheared box, 1+sqrt(2)
1482 PrimBoundingBoxSafetyCoefficientX = 2.414214
1483
1484 ; Safety coefficient for max bounding box from prim size box Y coordinate
1485 ; Worst case is twisted and sheared box, 1+sqrt(2)
1486 PrimBoundingBoxSafetyCoefficientY = 2.414214
1487
1488 ; Safety coefficient for max bounding box from prim size box Z coordinate
1489 ; Worst case is twisted tube, 0.5+sqrt(1.25)
1490 PrimBoundingBoxSafetyCoefficientZ = 1.618034
1491
1492 ; Accepted calculation precision error in calculations in llCastRay
1493 FloatToleranceInLlCastRay = 0.000001
1494
1495 ; Accepted distance difference between duplicate hits in llCastRay
1496 FloatTolerance2InLlCastRay = 0.0001
1497
1498 ; Maximum number of returned hits from llCastRay
1499 MaxHitsInLlCastRay = 16
1500
1501 ; Maximum number of returned hits per prim from llCastRay
1502 MaxHitsPerPrimInLlCastRay = 16
1503
1504 ; Maximum number of returned hits per object from llCastRay
1505 MaxHitsPerObjectInLlCastRay = 16
1506
1507 ; Report ray intersections with surfaces on exits from a prim as hits in llCastRay if true
1508 DetectExitHitsInLlCastRay = false
1509
1510 ; Filter on parts instead of groups in llCastRay if true
1511 FilterPartsInLlCastRay = false
1512
1513 ; Detect attachments in llCastRay if true
1514 DoAttachmentsInLlCastRay = false
1515
1516 ; Use legacy version 1 of llCastRay if true
1517 UseLlCastRayV1 = true
1480 1518
1481[DataSnapshot] 1519[DataSnapshot]
1482 ; The following set of configs pertains to search. 1520 ; The following set of configs pertains to search.