Implement llCastRay fully, simplified.
							parent
							
								
									30f9e5372e
								
							
						
					
					
						commit
						43b8bd0c35
					
				|  | @ -218,6 +218,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | ||||||
|         protected float m_lABB2SitZ0 = -0.25f; |         protected float m_lABB2SitZ0 = -0.25f; | ||||||
|         protected float m_lABB2SitZ1 = 0.25f; |         protected float m_lABB2SitZ1 = 0.25f; | ||||||
| 
 | 
 | ||||||
|  |         protected float m_primSafetyCoeffX = 2.414214f; | ||||||
|  |         protected float m_primSafetyCoeffY = 2.414214f; | ||||||
|  |         protected float m_primSafetyCoeffZ = 1.618034f; | ||||||
|  |         protected float m_floatToleranceInCastRay = 0.000001f; | ||||||
|  |         protected float m_floatTolerance2InCastRay = 0.0001f; | ||||||
|  |         protected int m_maxHitsInCastRay = 16; | ||||||
|  |         protected int m_maxHitsPerPrimInCastRay = 16; | ||||||
|  |         protected int m_maxHitsPerObjectInCastRay = 16; | ||||||
|  |         protected bool m_detectExitsInCastRay = false; | ||||||
|  |         protected bool m_filterPartsInCastRay = false; | ||||||
|  |         protected bool m_doAttachmentsInCastRay = false; | ||||||
|  |         protected bool m_useCastRayV1 = true; | ||||||
|  | 
 | ||||||
|         //An array of HTTP/1.1 headers that are not allowed to be used |         //An array of HTTP/1.1 headers that are not allowed to be used | ||||||
|         //as custom headers by llHTTPRequest. |         //as custom headers by llHTTPRequest. | ||||||
|         private string[] HttpStandardHeaders = |         private string[] HttpStandardHeaders = | ||||||
|  | @ -320,6 +333,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | ||||||
|                     m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1); |                     m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1); | ||||||
|                     m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0); |                     m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0); | ||||||
|                     m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1); |                     m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1); | ||||||
|  |                     m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); | ||||||
|  |                     m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); | ||||||
|  |                     m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); | ||||||
|  |                     m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); | ||||||
|  |                     m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); | ||||||
|  |                     m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); | ||||||
|  |                     m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay); | ||||||
|  |                     m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay); | ||||||
|  |                     m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); | ||||||
|  |                     m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); | ||||||
|  |                     m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); | ||||||
|  |                     m_useCastRayV1 = lslConfig.GetBoolean("UseLlCastRayV1", m_useCastRayV1); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 IConfig smtpConfig = seConfigSource.Configs["SMTP"]; |                 IConfig smtpConfig = seConfigSource.Configs["SMTP"]; | ||||||
|  | @ -13738,7 +13763,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | ||||||
|             return contacts[0]; |             return contacts[0]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) |         public LSL_List llCastRayV1(LSL_Vector start, LSL_Vector end, LSL_List options) | ||||||
|         { |         { | ||||||
|             LSL_List list = new LSL_List(); |             LSL_List list = new LSL_List(); | ||||||
| 
 | 
 | ||||||
|  | @ -13929,6 +13954,739 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | ||||||
|             return list; |             return list; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Full implementation of llCastRay similar to SL 2015-04-21. | ||||||
|  |         /// http://wiki.secondlife.com/wiki/LlCastRay | ||||||
|  |         /// Uses pure geometry, bounding shapes, meshing and no physics | ||||||
|  |         /// for prims, sculpts, meshes, avatars and terrain. | ||||||
|  |         /// Implements all flags, reject types and data flags. | ||||||
|  |         /// Can handle both objects/groups and prims/parts, by config. | ||||||
|  |         /// May give poor results with multi-part meshes where "root" | ||||||
|  |         /// part doesn't dominate, owing to "guessed" bounding boxes. | ||||||
|  |         /// May sometimes be inaccurate owing to calculation precision | ||||||
|  |         /// and a bug in libopenmetaverse PrimMesher. | ||||||
|  |         /// </summary> | ||||||
|  |         public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) | ||||||
|  |         { | ||||||
|  |             // Use llCastRay v1 if configured | ||||||
|  |             if (m_useCastRayV1) | ||||||
|  |                 return llCastRayV1(start, end, options); | ||||||
|  | 
 | ||||||
|  |             // Initialize | ||||||
|  |             m_host.AddScriptLPS(1); | ||||||
|  |             List<RayHit> rayHits = new List<RayHit>(); | ||||||
|  |             LSL_List result = new LSL_List(); | ||||||
|  |             float tol = m_floatToleranceInCastRay; | ||||||
|  |             float tol2 = m_floatTolerance2InCastRay; | ||||||
|  | 
 | ||||||
|  |             // Get input options | ||||||
|  |             int rejectTypes = 0; | ||||||
|  |             int dataFlags = 0; | ||||||
|  |             int maxHits = 1; | ||||||
|  |             bool detectPhantom = false; | ||||||
|  |             for (int i = 0; i < options.Length; i += 2) | ||||||
|  |             { | ||||||
|  |                 if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) | ||||||
|  |                     rejectTypes = 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_MAX_HITS) | ||||||
|  |                     maxHits = options.GetLSLIntegerItem(i + 1); | ||||||
|  |                 else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) | ||||||
|  |                     detectPhantom = (options.GetLSLIntegerItem(i + 1) != 0); | ||||||
|  |             } | ||||||
|  |             if (maxHits > m_maxHitsInCastRay) | ||||||
|  |                 maxHits = m_maxHitsInCastRay; | ||||||
|  |             bool rejectAgents = ((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != 0); | ||||||
|  |             bool rejectPhysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) != 0); | ||||||
|  |             bool rejectNonphysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) != 0); | ||||||
|  |             bool rejectLand = ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) != 0); | ||||||
|  |             bool getNormal = ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) != 0); | ||||||
|  |             bool getRootKey = ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) != 0); | ||||||
|  |             bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0); | ||||||
|  | 
 | ||||||
|  |             // Calculate some basic parameters | ||||||
|  |             Vector3 ray = end - start; | ||||||
|  |             float rayLength = ray.Length(); | ||||||
|  | 
 | ||||||
|  |             // Try to get a mesher and return failure if none or degenerate ray | ||||||
|  |             IRendering primMesher = null; | ||||||
|  |             List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); | ||||||
|  |             if (renderers.Count < 1 || rayLength < tol) | ||||||
|  |             { | ||||||
|  |                 result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); | ||||||
|  |                 return result; | ||||||
|  |             } | ||||||
|  |             primMesher = RenderingLoader.LoadRenderer(renderers[0]); | ||||||
|  | 
 | ||||||
|  |             // Used to translate and rotate world so ray is along negative Z axis from origo and | ||||||
|  |             // calculations mostly simplified to a 2D projecttion on the X-Y plane | ||||||
|  |             Vector3 posProj = new Vector3(-start); | ||||||
|  |             Quaternion rotProj = Vector3.RotationBetween(ray, new Vector3(0.0f, 0.0f, -1.0f)); | ||||||
|  |             Quaternion rotBack = Quaternion.Inverse(rotProj); | ||||||
|  | 
 | ||||||
|  |             // Iterate over all objects/groups and prims/parts in region | ||||||
|  |             World.ForEachSOG( | ||||||
|  |                 delegate(SceneObjectGroup group) | ||||||
|  |                 { | ||||||
|  |                     // Check group filters unless part filters are configured | ||||||
|  |                     bool isPhysical = (group.RootPart != null && group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical); | ||||||
|  |                     bool isNonphysical = !isPhysical; | ||||||
|  |                     bool isPhantom = group.IsPhantom || group.IsVolumeDetect; | ||||||
|  |                     bool isAttachment = group.IsAttachment; | ||||||
|  |                     bool doGroup = true; | ||||||
|  |                     if (isPhysical && rejectPhysical) | ||||||
|  |                         doGroup = false; | ||||||
|  |                     if (isNonphysical && rejectNonphysical) | ||||||
|  |                         doGroup = false; | ||||||
|  |                     if (isPhantom && detectPhantom) | ||||||
|  |                         doGroup = true; | ||||||
|  |                     if (m_filterPartsInCastRay) | ||||||
|  |                         doGroup = true; | ||||||
|  |                     if (isAttachment && !m_doAttachmentsInCastRay) | ||||||
|  |                         doGroup = false; | ||||||
|  |                     // Parse object/group if passed filters | ||||||
|  |                     if (doGroup) | ||||||
|  |                     { | ||||||
|  |                         // Iterate over all prims/parts in object/group | ||||||
|  |                         foreach(SceneObjectPart part in group.Parts) | ||||||
|  |                         { | ||||||
|  |                             // Check part filters if configured | ||||||
|  |                             if (m_filterPartsInCastRay) | ||||||
|  |                             { | ||||||
|  |                                 isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); | ||||||
|  |                                 isNonphysical = !isPhysical; | ||||||
|  |                                 isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || (part.VolumeDetectActive); | ||||||
|  |                                 bool doPart = true; | ||||||
|  |                                 if (isPhysical && rejectPhysical) | ||||||
|  |                                     doPart = false; | ||||||
|  |                                 if (isNonphysical && rejectNonphysical) | ||||||
|  |                                     doPart = false; | ||||||
|  |                                 if (isPhantom && detectPhantom) | ||||||
|  |                                     doPart = true; | ||||||
|  |                                 if (!doPart) | ||||||
|  |                                     continue; | ||||||
|  |                             } | ||||||
|  |                             // Parse prim/part if passed filters | ||||||
|  | 
 | ||||||
|  |                             // Estimate bounding box from size box | ||||||
|  |                             Vector3 scaleSafe = part.Scale; | ||||||
|  |                             if (!part.Shape.SculptEntry) | ||||||
|  |                                 scaleSafe = scaleSafe * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); | ||||||
|  | 
 | ||||||
|  |                             // Filter parts by bounding shapes | ||||||
|  |                             Vector3 posPartRel = part.GetWorldPosition() + posProj; | ||||||
|  |                             Vector3 posPartProj = posPartRel * rotProj; | ||||||
|  |                             if (InBoundingShapes(ray, rayLength, scaleSafe, posPartRel, posPartProj, rotProj)) | ||||||
|  |                             { | ||||||
|  |                                 // Prepare data needed to check for ray hits | ||||||
|  |                                 RayTrans rayTrans = new RayTrans(); | ||||||
|  |                                 rayTrans.PartId = part.UUID; | ||||||
|  |                                 rayTrans.GroupId = part.ParentGroup.UUID; | ||||||
|  |                                 rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; | ||||||
|  |                                 rayTrans.Scale = part.Scale; | ||||||
|  |                                 rayTrans.PositionPartProj = posPartProj; | ||||||
|  |                                 rayTrans.PositionProj = posProj; | ||||||
|  |                                 rayTrans.RotationPartProj = rotProj * part.GetWorldRotation(); | ||||||
|  |                                 rayTrans.RotationBack = rotBack; | ||||||
|  |                                 rayTrans.NeedsEnds = true; | ||||||
|  |                                 rayTrans.RayLength = rayLength; | ||||||
|  |                                 rayTrans.Tolerance = tol; | ||||||
|  |                                 rayTrans.Tolerance2 = tol2; | ||||||
|  | 
 | ||||||
|  |                                 // Make an OMV prim to be able to mesh part | ||||||
|  |                                 Primitive omvPrim = part.Shape.ToOmvPrimitive(posPartProj, rayTrans.RotationPartProj); | ||||||
|  |                                 byte[] sculptAsset = null; | ||||||
|  |                                 if (omvPrim.Sculpt != null) | ||||||
|  |                                     sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); | ||||||
|  | 
 | ||||||
|  |                                 // When part is mesh, get and check mesh | ||||||
|  |                                 if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) | ||||||
|  |                                 { | ||||||
|  |                                     AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); | ||||||
|  |                                     FacetedMesh mesh = null; | ||||||
|  |                                     FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh); | ||||||
|  |                                     meshAsset = null; | ||||||
|  |                                     AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); | ||||||
|  |                                     mesh = null; | ||||||
|  |                                 } | ||||||
|  | 
 | ||||||
|  |                                 // When part is sculpt, create and check mesh | ||||||
|  |                                 // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. | ||||||
|  |                                 else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) | ||||||
|  |                                 { | ||||||
|  |                                     IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>(); | ||||||
|  |                                     if (imgDecoder != null) | ||||||
|  |                                     { | ||||||
|  |                                         Image sculpt = imgDecoder.DecodeToImage(sculptAsset); | ||||||
|  |                                         if (sculpt != null) | ||||||
|  |                                         { | ||||||
|  |                                             SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); | ||||||
|  |                                             sculpt.Dispose(); | ||||||
|  |                                             AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); | ||||||
|  |                                             mesh = null; | ||||||
|  |                                         } | ||||||
|  |                                     } | ||||||
|  |                                } | ||||||
|  | 
 | ||||||
|  |                                 // When part is prim, create and check mesh | ||||||
|  |                                 else if (omvPrim.Sculpt == null) | ||||||
|  |                                 { | ||||||
|  |                                     if ( | ||||||
|  |                                         omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && | ||||||
|  |                                         omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && | ||||||
|  |                                         omvPrim.PrimData.PathSkew == 0.0 && | ||||||
|  |                                         omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 | ||||||
|  |                                     ) | ||||||
|  |                                         rayTrans.NeedsEnds = false; | ||||||
|  |                                     SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); | ||||||
|  |                                     AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); | ||||||
|  |                                     mesh = null; | ||||||
|  |                                 } | ||||||
|  | 
 | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             // Check avatar filter | ||||||
|  |             if (!rejectAgents) | ||||||
|  |             { | ||||||
|  |                 // Iterate over all avatars in region | ||||||
|  |                 World.ForEachRootScenePresence( | ||||||
|  |                     delegate (ScenePresence sp) | ||||||
|  |                     { | ||||||
|  |                         // Parse avatar | ||||||
|  | 
 | ||||||
|  |                         // Get bounding box | ||||||
|  |                         Vector3 lower; | ||||||
|  |                         Vector3 upper; | ||||||
|  |                         BoundingBoxOfScenePresence(sp, out lower, out upper); | ||||||
|  |                         Vector3 scale = upper - lower; | ||||||
|  | 
 | ||||||
|  |                         // Filter avatars by bounding shapes | ||||||
|  |                         Vector3 posPartRel = sp.AbsolutePosition + posProj + (lower + upper) * 0.5f * sp.Rotation; | ||||||
|  |                         Vector3 posPartProj = posPartRel * rotProj; | ||||||
|  |                         if (InBoundingShapes(ray, rayLength, scale, posPartRel, posPartProj, rotProj)) | ||||||
|  |                         { | ||||||
|  |                             // Prepare data needed to check for ray hits | ||||||
|  |                             RayTrans rayTrans = new RayTrans(); | ||||||
|  |                             rayTrans.PartId = sp.UUID; | ||||||
|  |                             rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID; | ||||||
|  |                             rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0; | ||||||
|  |                             rayTrans.Scale = scale; | ||||||
|  |                             rayTrans.PositionPartProj = posPartProj; | ||||||
|  |                             rayTrans.PositionProj = posProj; | ||||||
|  |                             rayTrans.RotationPartProj = rotProj * sp.Rotation; | ||||||
|  |                             rayTrans.RotationBack = rotBack; | ||||||
|  |                             rayTrans.NeedsEnds = false; | ||||||
|  |                             rayTrans.RayLength = rayLength; | ||||||
|  |                             rayTrans.Tolerance = tol; | ||||||
|  |                             rayTrans.Tolerance2 = tol2; | ||||||
|  | 
 | ||||||
|  |                             // Make OMV prim, create and check mesh | ||||||
|  |                             Primitive omvPrim = MakeOpenMetaversePrim(scale, posPartProj, rayTrans.RotationPartProj, ScriptBaseClass.PRIM_TYPE_SPHERE); | ||||||
|  |                             SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); | ||||||
|  |                             AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); | ||||||
|  |                             mesh = null; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Check terrain filter | ||||||
|  |             if (!rejectLand) | ||||||
|  |             { | ||||||
|  |                 // Parse terrain | ||||||
|  | 
 | ||||||
|  |                 // Mesh terrain and check projected bounding box | ||||||
|  |                 Vector3 posPartProj = posProj * rotProj; | ||||||
|  |                 Quaternion rotPartProj = rotProj; | ||||||
|  |                 Vector3 lower; | ||||||
|  |                 Vector3 upper; | ||||||
|  |                 List<Tri> triangles = TrisFromHeightmapUnderRay(start, end, out lower, out upper); | ||||||
|  |                 Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); | ||||||
|  |                 Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue); | ||||||
|  |                 int dummy = 0; | ||||||
|  |                 AddBoundingBoxOfSimpleBox(lower, upper, posPartProj, rotPartProj, true, ref lowerBox, ref upperBox, ref dummy); | ||||||
|  |                 if (lowerBox.X <= tol && lowerBox.Y <= tol && lowerBox.Z <= tol && upperBox.X >= -tol && upperBox.Y >= -tol && upperBox.Z >= -rayLength - tol) | ||||||
|  |                 { | ||||||
|  |                     // Prepare data needed to check for ray hits | ||||||
|  |                     RayTrans rayTrans = new RayTrans(); | ||||||
|  |                     rayTrans.PartId = UUID.Zero; | ||||||
|  |                     rayTrans.GroupId = UUID.Zero; | ||||||
|  |                     rayTrans.Link = 0; | ||||||
|  |                     rayTrans.Scale = new Vector3 (1.0f, 1.0f, 1.0f); | ||||||
|  |                     rayTrans.PositionPartProj = posPartProj; | ||||||
|  |                     rayTrans.PositionProj = posProj; | ||||||
|  |                     rayTrans.RotationPartProj = rotPartProj; | ||||||
|  |                     rayTrans.RotationBack = rotBack; | ||||||
|  |                     rayTrans.NeedsEnds = true; | ||||||
|  |                     rayTrans.RayLength = rayLength; | ||||||
|  |                     rayTrans.Tolerance = tol; | ||||||
|  |                     rayTrans.Tolerance2 = tol2; | ||||||
|  | 
 | ||||||
|  |                     // Check mesh | ||||||
|  |                     AddRayInTris(triangles, rayTrans, ref rayHits); | ||||||
|  |                     triangles = null; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Sort hits by ascending distance | ||||||
|  |             rayHits.Sort((s1, s2) => s1.Distance.CompareTo(s2.Distance)); | ||||||
|  | 
 | ||||||
|  |             // Check excess hits per part and group | ||||||
|  |             for (int t = 0; t < 2; t++) | ||||||
|  |             { | ||||||
|  |                 int maxHitsPerType = 0; | ||||||
|  |                 UUID id = UUID.Zero; | ||||||
|  |                 if (t == 0) | ||||||
|  |                     maxHitsPerType = m_maxHitsPerPrimInCastRay; | ||||||
|  |                 else | ||||||
|  |                     maxHitsPerType = m_maxHitsPerObjectInCastRay; | ||||||
|  | 
 | ||||||
|  |                 // Handle excess hits only when needed | ||||||
|  |                 if (maxHitsPerType < m_maxHitsInCastRay) | ||||||
|  |                 { | ||||||
|  |                     // Find excess hits | ||||||
|  |                     Hashtable hits = new Hashtable(); | ||||||
|  |                     for (int i = rayHits.Count - 1; i >= 0; i--) | ||||||
|  |                     { | ||||||
|  |                         if (t == 0) | ||||||
|  |                             id = rayHits[i].PartId; | ||||||
|  |                         else | ||||||
|  |                             id = rayHits[i].GroupId; | ||||||
|  |                         if (hits.ContainsKey(id)) | ||||||
|  |                             hits[id] = (int)hits[id] + 1; | ||||||
|  |                         else | ||||||
|  |                             hits[id] = 1; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     // Remove excess hits | ||||||
|  |                     for (int i = rayHits.Count - 1; i >= 0; i--) | ||||||
|  |                     { | ||||||
|  |                         if (t == 0) | ||||||
|  |                             id = rayHits[i].PartId; | ||||||
|  |                         else | ||||||
|  |                             id = rayHits[i].GroupId; | ||||||
|  |                         int hit = (int)hits[id]; | ||||||
|  |                         if (hit > m_maxHitsPerPrimInCastRay) | ||||||
|  |                         { | ||||||
|  |                             rayHits.RemoveAt(i); | ||||||
|  |                             hit--; | ||||||
|  |                             hits[id] = hit; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Parse hits into result list according to data flags | ||||||
|  |             int hitCount = rayHits.Count; | ||||||
|  |             if (hitCount > maxHits) | ||||||
|  |                 hitCount = maxHits; | ||||||
|  |             for (int i = 0; i < hitCount; i++) | ||||||
|  |             { | ||||||
|  |                 RayHit rayHit = rayHits[i]; | ||||||
|  |                 if (getRootKey) | ||||||
|  |                     result.Add(new LSL_Key(rayHit.GroupId.ToString())); | ||||||
|  |                 else | ||||||
|  |                     result.Add(new LSL_Key(rayHit.PartId.ToString())); | ||||||
|  |                 result.Add(new LSL_Vector(rayHit.Position)); | ||||||
|  |                 if (getLinkNum) | ||||||
|  |                     result.Add(new LSL_Integer(rayHit.Link)); | ||||||
|  |                 if (getNormal) | ||||||
|  |                     result.Add(new LSL_Vector(rayHit.Normal)); | ||||||
|  |             } | ||||||
|  |             result.Add(new LSL_Integer(hitCount)); | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Struct for transmitting parameters required for finding llCastRay ray hits. | ||||||
|  |         /// </summary> | ||||||
|  |         public struct RayTrans | ||||||
|  |         { | ||||||
|  |             public UUID PartId; | ||||||
|  |             public UUID GroupId; | ||||||
|  |             public int Link; | ||||||
|  |             public Vector3 Scale; | ||||||
|  |             public Vector3 PositionPartProj; | ||||||
|  |             public Vector3 PositionProj; | ||||||
|  |             public Quaternion RotationPartProj; | ||||||
|  |             public Quaternion RotationBack; | ||||||
|  |             public bool NeedsEnds; | ||||||
|  |             public float RayLength; | ||||||
|  |             public float Tolerance; | ||||||
|  |             public float Tolerance2; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Struct for llCastRay ray hits. | ||||||
|  |         /// </summary> | ||||||
|  |         public struct RayHit | ||||||
|  |         { | ||||||
|  |             public UUID PartId; | ||||||
|  |             public UUID GroupId; | ||||||
|  |             public int Link; | ||||||
|  |             public Vector3 Position; | ||||||
|  |             public Vector3 Normal; | ||||||
|  |             public float Distance; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Helper to parse SimpleMesh for ray hits. | ||||||
|  |         /// </summary> | ||||||
|  |         private void AddRayInSimpleMesh(SimpleMesh mesh, RayTrans rayTrans, ref List<RayHit> rayHits) | ||||||
|  |         { | ||||||
|  |             if (mesh != null) | ||||||
|  |             { | ||||||
|  |                 for (int i = 0; i < mesh.Indices.Count; i += 3) | ||||||
|  |                 { | ||||||
|  |                     Tri triangle = new Tri(); | ||||||
|  |                     triangle.p1 = mesh.Vertices[mesh.Indices[i]].Position; | ||||||
|  |                     triangle.p2 = mesh.Vertices[mesh.Indices[i + 1]].Position; | ||||||
|  |                     triangle.p3 = mesh.Vertices[mesh.Indices[i + 2]].Position; | ||||||
|  |                     AddRayInTri(triangle, rayTrans, ref rayHits); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Helper to parse FacetedMesh for ray hits. | ||||||
|  |         /// </summary> | ||||||
|  |         private void AddRayInFacetedMesh(FacetedMesh mesh, RayTrans rayTrans, ref List<RayHit> rayHits) | ||||||
|  |         { | ||||||
|  |             if (mesh != null) | ||||||
|  |             { | ||||||
|  |                 foreach (Face face in mesh.Faces) | ||||||
|  |                 { | ||||||
|  |                     for (int i = 0; i <face.Indices.Count; i += 3) | ||||||
|  |                     { | ||||||
|  |                         Tri triangle = new Tri(); | ||||||
|  |                         triangle.p1 = face.Vertices[face.Indices[i]].Position; | ||||||
|  |                         triangle.p2 = face.Vertices[face.Indices[i + 1]].Position; | ||||||
|  |                         triangle.p3 = face.Vertices[face.Indices[i + 2]].Position; | ||||||
|  |                         AddRayInTri(triangle, rayTrans, ref rayHits); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Helper to parse Tri (triangle) List for ray hits. | ||||||
|  |         /// </summary> | ||||||
|  |         private void AddRayInTris(List<Tri> triangles, RayTrans rayTrans, ref List<RayHit> rayHits) | ||||||
|  |         { | ||||||
|  |             foreach (Tri triangle in triangles) | ||||||
|  |             { | ||||||
|  |                 AddRayInTri(triangle, rayTrans, ref rayHits); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Helper to add ray hit in a Tri (triangle). | ||||||
|  |         /// </summary> | ||||||
|  |         private void AddRayInTri(Tri triangle, RayTrans rayTrans, ref List<RayHit> rayHits) | ||||||
|  |         { | ||||||
|  |             // Check for hit in triangle | ||||||
|  |             float distance; | ||||||
|  |             Vector3 posHit; | ||||||
|  |             Vector3 normal; | ||||||
|  |             if (HitRayInTri(triangle, rayTrans, out distance, out posHit, out normal)) | ||||||
|  |             { | ||||||
|  |                 // Project hit part back to normal coordinate system | ||||||
|  |                 Vector3 posPart = rayTrans.PositionPartProj * rayTrans.RotationBack - rayTrans.PositionProj; | ||||||
|  |                 // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) faces plane through shape center | ||||||
|  |                 if (Math.Abs(Vector3.Dot(posPart, normal) - Vector3.Dot(posHit, normal)) < rayTrans.Tolerance && !rayTrans.NeedsEnds) | ||||||
|  |                     return; | ||||||
|  |                 // Remove duplicate hits at triangle edges and intersections | ||||||
|  |                 for (int i = rayHits.Count - 1; i >= 0; i--) | ||||||
|  |                 { | ||||||
|  |                     if (rayHits[i].PartId == rayTrans.PartId && Math.Abs(rayHits[i].Distance - distance) < rayTrans.Tolerance2) | ||||||
|  |                         return; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Build result data set | ||||||
|  |                 RayHit rayHit = new RayHit(); | ||||||
|  |                 rayHit.PartId = rayTrans.PartId; | ||||||
|  |                 rayHit.GroupId = rayTrans.GroupId; | ||||||
|  |                 rayHit.Link = rayTrans.Link; | ||||||
|  |                 rayHit.Position = posHit; | ||||||
|  |                 rayHit.Normal = normal; | ||||||
|  |                 rayHit.Distance = distance; | ||||||
|  |                 rayHits.Add(rayHit); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Helper to find ray hit in a Tri (triangle). | ||||||
|  |         /// </summary> | ||||||
|  |         private bool HitRayInTri(Tri triangle, RayTrans rayTrans, out float distance, out Vector3 posHit, out Vector3 normal) | ||||||
|  |         { | ||||||
|  |             // Initialize | ||||||
|  |             distance = 0.0f; | ||||||
|  |             posHit = Vector3.Zero; | ||||||
|  |             normal = Vector3.Zero; | ||||||
|  |             float tol = rayTrans.Tolerance; | ||||||
|  | 
 | ||||||
|  |             // Project triangle on X-Y plane | ||||||
|  |             Vector3 pos1 = triangle.p1 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; | ||||||
|  |             Vector3 pos2 = triangle.p2 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; | ||||||
|  |             Vector3 pos3 = triangle.p3 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; | ||||||
|  | 
 | ||||||
|  |             // Check if ray/origo inside triangle bounding rectangle | ||||||
|  |             Vector3 lower = Vector3.Min(pos1, Vector3.Min(pos2, pos3)); | ||||||
|  |             Vector3 upper = Vector3.Max(pos1, Vector3.Max(pos2, pos3)); | ||||||
|  |             if (lower.X > tol || lower.Y > tol || lower.Z > tol || upper.X < -tol || upper.Y < -tol || upper.Z < -rayTrans.RayLength - tol) | ||||||
|  |                 return false; | ||||||
|  | 
 | ||||||
|  |             // Check if ray/origo inside every edge or reverse "outside" every edge on exit | ||||||
|  |             float dist; | ||||||
|  |             bool inside = true; | ||||||
|  |             bool outside = true; | ||||||
|  |             Vector3 vec1 = pos2 - pos1; | ||||||
|  |             dist = pos1.X * vec1.Y - pos1.Y * vec1.X; | ||||||
|  |             if (dist < -tol) | ||||||
|  |                 inside = false; | ||||||
|  |             if (dist > tol) | ||||||
|  |                 outside = false; | ||||||
|  |             Vector3 vec2 = pos3 - pos2; | ||||||
|  |             dist = pos2.X * vec2.Y - pos2.Y * vec2.X; | ||||||
|  |             if (dist < -tol) | ||||||
|  |                 inside = false; | ||||||
|  |             if (dist > tol) | ||||||
|  |                 outside = false; | ||||||
|  |             Vector3 vec3 = pos1 - pos3; | ||||||
|  |             dist = pos3.X * vec3.Y - pos3.Y * vec3.X; | ||||||
|  |             if (dist < -tol) | ||||||
|  |                 inside = false; | ||||||
|  |             if (dist > tol) | ||||||
|  |                 outside = false; | ||||||
|  | 
 | ||||||
|  |             // Skip if ray/origo outside | ||||||
|  |             if (!inside && !(outside && m_detectExitsInCastRay)) | ||||||
|  |                 return false; | ||||||
|  | 
 | ||||||
|  |             // Calculate normal | ||||||
|  |             Vector3 normalProj = Vector3.Cross(vec1, vec2); | ||||||
|  |             float normalLength = normalProj.Length(); | ||||||
|  |             // Skip if degenerate triangle | ||||||
|  |             if (normalLength < tol) | ||||||
|  |                 return false; | ||||||
|  |             normalProj = normalProj / normalLength; | ||||||
|  |             // Skip if ray parallell to triangle plane | ||||||
|  |             if (Math.Abs(normalProj.Z) < tol) | ||||||
|  |                 return false; | ||||||
|  | 
 | ||||||
|  |             // Calculate distance | ||||||
|  |             distance = Vector3.Dot(normalProj, pos2) / normalProj.Z * -1.0f; | ||||||
|  |             // Skip if outside ray | ||||||
|  |             if (distance < -tol || distance > rayTrans.RayLength + tol) | ||||||
|  |                 return false; | ||||||
|  | 
 | ||||||
|  |             // Calculate projected hit position | ||||||
|  |             Vector3 posHitProj = new Vector3(0.0f, 0.0f, -distance); | ||||||
|  |             // Project hit back to normal coordinate system | ||||||
|  |             posHit = posHitProj * rayTrans.RotationBack - rayTrans.PositionProj; | ||||||
|  |             normal = normalProj * rayTrans.RotationBack; | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Helper to parse selected parts of HeightMap into a Tri (triangle) List and calculate bounding box. | ||||||
|  |         /// </summary> | ||||||
|  |         private List<Tri> TrisFromHeightmapUnderRay(Vector3 posStart, Vector3 posEnd, out Vector3 lower, out Vector3 upper) | ||||||
|  |         { | ||||||
|  |             // Get bounding X-Y rectangle of terrain under ray | ||||||
|  |             lower = Vector3.Min(posStart, posEnd); | ||||||
|  |             upper = Vector3.Max(posStart, posEnd); | ||||||
|  |             lower.X = (float)Math.Floor(lower.X); | ||||||
|  |             lower.Y = (float)Math.Floor(lower.Y); | ||||||
|  |             float zLower = float.MaxValue; | ||||||
|  |             upper.X = (float)Math.Ceiling(upper.X); | ||||||
|  |             upper.Y = (float)Math.Ceiling(upper.Y); | ||||||
|  |             float zUpper = float.MinValue; | ||||||
|  | 
 | ||||||
|  |             // Initialize Tri (triangle) List | ||||||
|  |             List<Tri> triangles = new List<Tri>(); | ||||||
|  | 
 | ||||||
|  |             // Set parsing lane direction to major ray X-Y axis | ||||||
|  |             Vector3 vec = posEnd - posStart; | ||||||
|  |             float xAbs = Math.Abs(vec.X); | ||||||
|  |             float yAbs = Math.Abs(vec.Y); | ||||||
|  |             bool bigX = true; | ||||||
|  |             if (yAbs > xAbs) | ||||||
|  |             { | ||||||
|  |                 bigX = false; | ||||||
|  |                 vec = vec / yAbs; | ||||||
|  |             } | ||||||
|  |             else if (xAbs > yAbs || xAbs > 0.0f) | ||||||
|  |                 vec = vec / xAbs; | ||||||
|  |             else | ||||||
|  |                 vec = new Vector3(1.0f, 1.0f, 0.0f); | ||||||
|  | 
 | ||||||
|  |             // Simplify by start parsing in lower end of lane | ||||||
|  |             if ((bigX && vec.X < 0.0f) || (!bigX && vec.Y < 0.0f)) | ||||||
|  |             { | ||||||
|  |                 Vector3 posTemp = posStart; | ||||||
|  |                 posStart = posEnd; | ||||||
|  |                 posEnd = posTemp; | ||||||
|  |                 vec = vec * -1.0f; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // First 1x1 rectangle under ray | ||||||
|  |             float xFloorOld = 0.0f; | ||||||
|  |             float yFloorOld = 0.0f; | ||||||
|  |             Vector3 pos = posStart; | ||||||
|  |             float xFloor = (float)Math.Floor(pos.X); | ||||||
|  |             float yFloor = (float)Math.Floor(pos.Y); | ||||||
|  |             AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); | ||||||
|  | 
 | ||||||
|  |             // Parse every remaining 1x1 rectangle under ray | ||||||
|  |             while (pos != posEnd) | ||||||
|  |             { | ||||||
|  |                 // Next 1x1 rectangle under ray | ||||||
|  |                 xFloorOld = xFloor; | ||||||
|  |                 yFloorOld = yFloor; | ||||||
|  |                 pos = pos + vec; | ||||||
|  | 
 | ||||||
|  |                 // Clip position to 1x1 rectangle border | ||||||
|  |                 xFloor = (float)Math.Floor(pos.X); | ||||||
|  |                 yFloor = (float)Math.Floor(pos.Y); | ||||||
|  |                 if (bigX && pos.X > xFloor) | ||||||
|  |                 { | ||||||
|  |                     pos.Y -= vec.Y * (pos.X - xFloor); | ||||||
|  |                     pos.X = xFloor; | ||||||
|  |                 } | ||||||
|  |                 else if (!bigX && pos.Y > yFloor) | ||||||
|  |                 { | ||||||
|  |                     pos.X -= vec.X * (pos.Y - yFloor); | ||||||
|  |                     pos.Y = yFloor; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Last 1x1 rectangle under ray | ||||||
|  |                 if ((bigX && pos.X >= posEnd.X) || (!bigX && pos.Y >= posEnd.Y)) | ||||||
|  |                 { | ||||||
|  |                     pos = posEnd; | ||||||
|  |                     xFloor = (float)Math.Floor(pos.X); | ||||||
|  |                     yFloor = (float)Math.Floor(pos.Y); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 // Add new 1x1 rectangle in lane | ||||||
|  |                 if ((bigX && xFloor != xFloorOld) || (!bigX && yFloor != yFloorOld)) | ||||||
|  |                     AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); | ||||||
|  |                 // Add last 1x1 rectangle in old lane at lane shift | ||||||
|  |                 if (bigX && yFloor != yFloorOld) | ||||||
|  |                     AddTrisFromHeightmap(xFloor, yFloorOld, ref triangles, ref zLower, ref zUpper); | ||||||
|  |                 if (!bigX && xFloor != xFloorOld) | ||||||
|  |                     AddTrisFromHeightmap(xFloorOld, yFloor, ref triangles, ref zLower, ref zUpper); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Finalize bounding box Z | ||||||
|  |             lower.Z = zLower; | ||||||
|  |             upper.Z = zUpper; | ||||||
|  | 
 | ||||||
|  |             // Done and returning Tri (triangle)List | ||||||
|  |             return triangles; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Helper to add HeightMap squares into Tri (triangle) List and adjust bounding box. | ||||||
|  |         /// </summary> | ||||||
|  |         private void AddTrisFromHeightmap(float xPos, float yPos, ref List<Tri> triangles, ref float zLower, ref float zUpper) | ||||||
|  |         { | ||||||
|  |             int xInt = (int)xPos; | ||||||
|  |             int yInt = (int)yPos; | ||||||
|  | 
 | ||||||
|  |             // Corner 1 of 1x1 rectangle | ||||||
|  |             int x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1); | ||||||
|  |             int y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1); | ||||||
|  |             Vector3 pos1 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||||||
|  |             // Adjust bounding box | ||||||
|  |             zLower = Math.Min(zLower, pos1.Z); | ||||||
|  |             zUpper = Math.Max(zUpper, pos1.Z); | ||||||
|  | 
 | ||||||
|  |             // Corner 2 of 1x1 rectangle | ||||||
|  |             x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1); | ||||||
|  |             y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1); | ||||||
|  |             Vector3 pos2 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||||||
|  |             // Adjust bounding box | ||||||
|  |             zLower = Math.Min(zLower, pos1.Z); | ||||||
|  |             zUpper = Math.Max(zUpper, pos1.Z); | ||||||
|  | 
 | ||||||
|  |             // Corner 3 of 1x1 rectangle | ||||||
|  |             x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1); | ||||||
|  |             y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); | ||||||
|  |             Vector3 pos3 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||||||
|  |             // Adjust bounding box | ||||||
|  |             zLower = Math.Min(zLower, pos1.Z); | ||||||
|  |             zUpper = Math.Max(zUpper, pos1.Z); | ||||||
|  | 
 | ||||||
|  |             // Corner 4 of 1x1 rectangle | ||||||
|  |             x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1); | ||||||
|  |             y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); | ||||||
|  |             Vector3 pos4 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||||||
|  |             // Adjust bounding box | ||||||
|  |             zLower = Math.Min(zLower, pos1.Z); | ||||||
|  |             zUpper = Math.Max(zUpper, pos1.Z); | ||||||
|  | 
 | ||||||
|  |             // Add triangle 1 | ||||||
|  |             Tri triangle1 = new Tri(); | ||||||
|  |             triangle1.p1 = pos1; | ||||||
|  |             triangle1.p2 = pos2; | ||||||
|  |             triangle1.p3 = pos3; | ||||||
|  |             triangles.Add(triangle1); | ||||||
|  | 
 | ||||||
|  |             // Add triangle 2 | ||||||
|  |             Tri triangle2 = new Tri(); | ||||||
|  |             triangle2.p1 = pos3; | ||||||
|  |             triangle2.p2 = pos4; | ||||||
|  |             triangle2.p3 = pos1; | ||||||
|  |             triangles.Add(triangle2); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Helper to check if a ray intersects bounding shapes. | ||||||
|  |         /// </summary> | ||||||
|  |         private bool InBoundingShapes(Vector3 ray, float rayLength, Vector3 scale, Vector3 posPartRel, Vector3 posPartProj, Quaternion rotProj) | ||||||
|  |         { | ||||||
|  |             float tol = m_floatToleranceInCastRay; | ||||||
|  | 
 | ||||||
|  |             // Check if ray intersects projected bounding box | ||||||
|  |             Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); | ||||||
|  |             Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue); | ||||||
|  |             int dummy = 0; | ||||||
|  |             AddBoundingBoxOfSimpleBox(scale * -0.5f, scale * 0.5f, posPartProj, rotProj, true, ref lowerBox, ref upperBox, ref dummy); | ||||||
|  |             if (lowerBox.X > tol || lowerBox.Y > tol || lowerBox.Z > tol || upperBox.X < -tol || upperBox.Y < -tol || upperBox.Z < -rayLength - tol) | ||||||
|  |                 return false; | ||||||
|  | 
 | ||||||
|  |             // Passed bounding shape filters, so return true | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Helper to get link number for a UUID. | ||||||
|  |         /// </summary> | ||||||
|  |         private int UUID2LinkNumber(SceneObjectPart part, UUID id) | ||||||
|  |         { | ||||||
|  |             SceneObjectGroup group = part.ParentGroup; | ||||||
|  |             if (group != null) | ||||||
|  |             { | ||||||
|  |                 // Parse every link for UUID | ||||||
|  |                 int linkCount = group.PrimCount + group.GetSittingAvatarsCount(); | ||||||
|  |                 for (int link = linkCount; link > 0; link--) | ||||||
|  |                 { | ||||||
|  |                     ISceneEntity entity = GetLinkEntity(part, link); | ||||||
|  |                     // Return link number if UUID match | ||||||
|  |                     if (entity != null && entity.UUID == id) | ||||||
|  |                         return link; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             // Return link number 0 if no links or UUID matches | ||||||
|  |             return 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         public LSL_Integer llManageEstateAccess(int action, string avatar) |         public LSL_Integer llManageEstateAccess(int action, string avatar) | ||||||
|         { |         { | ||||||
|             m_host.AddScriptLPS(1); |             m_host.AddScriptLPS(1); | ||||||
|  |  | ||||||
|  | @ -1477,6 +1477,44 @@ | ||||||
|     ; Avatar bounding box, upper Z value, coefficient to multiply with avatar height, when sitting |     ; Avatar bounding box, upper Z value, coefficient to multiply with avatar height, when sitting | ||||||
|     UpperAvatarBoundingBoxSittingZcoeff = 0.25 |     UpperAvatarBoundingBoxSittingZcoeff = 0.25 | ||||||
| 
 | 
 | ||||||
|  |     ; Safety coefficient for max bounding box from prim size box X coordinate | ||||||
|  |     ; Worst case is twisted and sheared box, 1+sqrt(2) | ||||||
|  |     PrimBoundingBoxSafetyCoefficientX = 2.414214 | ||||||
|  | 
 | ||||||
|  |     ; Safety coefficient for max bounding box from prim size box Y coordinate | ||||||
|  |     ; Worst case is twisted and sheared box, 1+sqrt(2) | ||||||
|  |     PrimBoundingBoxSafetyCoefficientY = 2.414214 | ||||||
|  | 
 | ||||||
|  |     ; Safety coefficient for max bounding box from prim size box Z coordinate | ||||||
|  |     ; Worst case is twisted tube, 0.5+sqrt(1.25) | ||||||
|  |     PrimBoundingBoxSafetyCoefficientZ = 1.618034 | ||||||
|  | 
 | ||||||
|  |     ; Accepted calculation precision error in calculations in llCastRay | ||||||
|  |     FloatToleranceInLlCastRay = 0.000001 | ||||||
|  | 
 | ||||||
|  |     ; Accepted distance difference between duplicate hits in llCastRay | ||||||
|  |     FloatTolerance2InLlCastRay = 0.0001 | ||||||
|  | 
 | ||||||
|  |     ; Maximum number of returned hits from llCastRay | ||||||
|  |     MaxHitsInLlCastRay = 16 | ||||||
|  | 
 | ||||||
|  |     ; Maximum number of returned hits per prim from llCastRay | ||||||
|  |     MaxHitsPerPrimInLlCastRay = 16 | ||||||
|  | 
 | ||||||
|  |     ; Maximum number of returned hits per object from llCastRay | ||||||
|  |     MaxHitsPerObjectInLlCastRay = 16 | ||||||
|  | 
 | ||||||
|  |     ; Report ray intersections with surfaces on exits from a prim as hits in llCastRay if true | ||||||
|  |     DetectExitHitsInLlCastRay = false | ||||||
|  | 
 | ||||||
|  |     ; Filter on parts instead of groups in llCastRay if true | ||||||
|  |     FilterPartsInLlCastRay = false | ||||||
|  | 
 | ||||||
|  |     ; Detect attachments in llCastRay if true | ||||||
|  |     DoAttachmentsInLlCastRay = false | ||||||
|  | 
 | ||||||
|  |     ; Use legacy version 1 of llCastRay if true | ||||||
|  |     UseLlCastRayV1 = true | ||||||
| 
 | 
 | ||||||
| [DataSnapshot] | [DataSnapshot] | ||||||
|     ; The following set of configs pertains to search. |     ; The following set of configs pertains to search. | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Magnuz Binder
						Magnuz Binder