diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 678 |
1 files changed, 435 insertions, 243 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index c90f015..c5e02a6 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -28,6 +28,7 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Diagnostics; | ||
31 | using System.Drawing; | 32 | using System.Drawing; |
32 | using System.Drawing.Imaging; | 33 | using System.Drawing.Imaging; |
33 | using System.Runtime.Remoting.Lifetime; | 34 | using System.Runtime.Remoting.Lifetime; |
@@ -221,15 +222,27 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
221 | protected float m_primSafetyCoeffX = 2.414214f; | 222 | protected float m_primSafetyCoeffX = 2.414214f; |
222 | protected float m_primSafetyCoeffY = 2.414214f; | 223 | protected float m_primSafetyCoeffY = 2.414214f; |
223 | protected float m_primSafetyCoeffZ = 1.618034f; | 224 | protected float m_primSafetyCoeffZ = 1.618034f; |
224 | protected float m_floatToleranceInCastRay = 0.000001f; | 225 | protected bool m_useCastRayV3 = false; |
225 | protected float m_floatTolerance2InCastRay = 0.0001f; | 226 | protected float m_floatToleranceInCastRay = 0.00001f; |
227 | protected float m_floatTolerance2InCastRay = 0.001f; | ||
228 | protected DetailLevel m_primLodInCastRay = DetailLevel.Medium; | ||
229 | protected DetailLevel m_sculptLodInCastRay = DetailLevel.Medium; | ||
230 | protected DetailLevel m_meshLodInCastRay = DetailLevel.Highest; | ||
231 | protected DetailLevel m_avatarLodInCastRay = DetailLevel.Medium; | ||
226 | protected int m_maxHitsInCastRay = 16; | 232 | protected int m_maxHitsInCastRay = 16; |
227 | protected int m_maxHitsPerPrimInCastRay = 16; | 233 | protected int m_maxHitsPerPrimInCastRay = 16; |
228 | protected int m_maxHitsPerObjectInCastRay = 16; | 234 | protected int m_maxHitsPerObjectInCastRay = 16; |
229 | protected bool m_detectExitsInCastRay = false; | 235 | protected bool m_detectExitsInCastRay = false; |
230 | protected bool m_filterPartsInCastRay = false; | 236 | protected bool m_filterPartsInCastRay = false; |
231 | protected bool m_doAttachmentsInCastRay = false; | 237 | protected bool m_doAttachmentsInCastRay = false; |
232 | protected bool m_useCastRayV1 = true; | 238 | protected int m_msThrottleInCastRay = 200; |
239 | protected int m_msPerRegionInCastRay = 40; | ||
240 | protected int m_msPerAvatarInCastRay = 10; | ||
241 | protected int m_msMinInCastRay = 2; | ||
242 | protected int m_msMaxInCastRay = 40; | ||
243 | protected static List<CastRayCall> m_castRayCalls = new List<CastRayCall>(); | ||
244 | protected bool m_useMeshCacheInCastRay = true; | ||
245 | protected static Dictionary<ulong, FacetedMesh> m_cachedMeshes = new Dictionary<ulong, FacetedMesh>(); | ||
233 | 246 | ||
234 | //An array of HTTP/1.1 headers that are not allowed to be used | 247 | //An array of HTTP/1.1 headers that are not allowed to be used |
235 | //as custom headers by llHTTPRequest. | 248 | //as custom headers by llHTTPRequest. |
@@ -336,15 +349,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
336 | m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); | 349 | m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); |
337 | m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); | 350 | m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); |
338 | m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); | 351 | m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); |
352 | m_useCastRayV3 = lslConfig.GetBoolean("UseLlCastRayV3", m_useCastRayV3); | ||
339 | m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); | 353 | m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); |
340 | m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); | 354 | m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); |
355 | m_primLodInCastRay = (DetailLevel)lslConfig.GetInt("PrimDetailLevelInLlCastRay", (int)m_primLodInCastRay); | ||
356 | m_sculptLodInCastRay = (DetailLevel)lslConfig.GetInt("SculptDetailLevelInLlCastRay", (int)m_sculptLodInCastRay); | ||
357 | m_meshLodInCastRay = (DetailLevel)lslConfig.GetInt("MeshDetailLevelInLlCastRay", (int)m_meshLodInCastRay); | ||
358 | m_avatarLodInCastRay = (DetailLevel)lslConfig.GetInt("AvatarDetailLevelInLlCastRay", (int)m_avatarLodInCastRay); | ||
341 | m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); | 359 | m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); |
342 | m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay); | 360 | m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay); |
343 | m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay); | 361 | m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay); |
344 | m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); | 362 | m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); |
345 | m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); | 363 | m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); |
346 | m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); | 364 | m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); |
347 | m_useCastRayV1 = lslConfig.GetBoolean("UseLlCastRayV1", m_useCastRayV1); | 365 | m_msThrottleInCastRay = lslConfig.GetInt("ThrottleTimeInMsInLlCastRay", m_msThrottleInCastRay); |
366 | m_msPerRegionInCastRay = lslConfig.GetInt("AvailableTimeInMsPerRegionInLlCastRay", m_msPerRegionInCastRay); | ||
367 | m_msPerAvatarInCastRay = lslConfig.GetInt("AvailableTimeInMsPerAvatarInLlCastRay", m_msPerAvatarInCastRay); | ||
368 | m_msMinInCastRay = lslConfig.GetInt("RequiredAvailableTimeInMsInLlCastRay", m_msMinInCastRay); | ||
369 | m_msMaxInCastRay = lslConfig.GetInt("MaximumAvailableTimeInMsInLlCastRay", m_msMaxInCastRay); | ||
370 | m_useMeshCacheInCastRay = lslConfig.GetBoolean("UseMeshCacheInLlCastRay", m_useMeshCacheInCastRay); | ||
348 | } | 371 | } |
349 | 372 | ||
350 | IConfig smtpConfig = seConfigSource.Configs["SMTP"]; | 373 | IConfig smtpConfig = seConfigSource.Configs["SMTP"]; |
@@ -5777,7 +5800,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5777 | public LSL_String llGetEnv(LSL_String name) | 5800 | public LSL_String llGetEnv(LSL_String name) |
5778 | { | 5801 | { |
5779 | m_host.AddScriptLPS(1); | 5802 | m_host.AddScriptLPS(1); |
5780 | if (name == "dynamic_pathfinding") | 5803 | if (name == "agent_limit") |
5804 | { | ||
5805 | return World.RegionInfo.RegionSettings.AgentLimit.ToString(); | ||
5806 | } | ||
5807 | else if (name == "dynamic_pathfinding") | ||
5781 | { | 5808 | { |
5782 | return "0"; | 5809 | return "0"; |
5783 | } | 5810 | } |
@@ -5785,14 +5812,37 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5785 | { | 5812 | { |
5786 | return World.RegionInfo.EstateSettings.EstateID.ToString(); | 5813 | return World.RegionInfo.EstateSettings.EstateID.ToString(); |
5787 | } | 5814 | } |
5815 | else if (name == "estate_name") | ||
5816 | { | ||
5817 | return World.RegionInfo.EstateSettings.EstateName; | ||
5818 | } | ||
5788 | else if (name == "frame_number") | 5819 | else if (name == "frame_number") |
5789 | { | 5820 | { |
5790 | return World.Frame.ToString(); | 5821 | return World.Frame.ToString(); |
5791 | } | 5822 | } |
5823 | else if (name == "region_cpu_ratio") | ||
5824 | { | ||
5825 | return "1"; | ||
5826 | } | ||
5792 | else if (name == "region_idle") | 5827 | else if (name == "region_idle") |
5793 | { | 5828 | { |
5794 | return "0"; | 5829 | return "0"; |
5795 | } | 5830 | } |
5831 | else if (name == "region_product_name") | ||
5832 | { | ||
5833 | if (World.RegionInfo.RegionType != String.Empty) | ||
5834 | return World.RegionInfo.RegionType; | ||
5835 | else | ||
5836 | return ""; | ||
5837 | } | ||
5838 | else if (name == "region_product_sku") | ||
5839 | { | ||
5840 | return "OpenSim"; | ||
5841 | } | ||
5842 | else if (name == "region_start_time") | ||
5843 | { | ||
5844 | return World.UnixStartTime.ToString(); | ||
5845 | } | ||
5796 | else if (name == "sim_channel") | 5846 | else if (name == "sim_channel") |
5797 | { | 5847 | { |
5798 | return "OpenSim"; | 5848 | return "OpenSim"; |
@@ -5801,6 +5851,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5801 | { | 5851 | { |
5802 | return World.GetSimulatorVersion(); | 5852 | return World.GetSimulatorVersion(); |
5803 | } | 5853 | } |
5854 | else if (name == "simulator_hostname") | ||
5855 | { | ||
5856 | IUrlModule UrlModule = World.RequestModuleInterface<IUrlModule>(); | ||
5857 | return UrlModule.ExternalHostNameForLSL; | ||
5858 | } | ||
5804 | else | 5859 | else |
5805 | { | 5860 | { |
5806 | return ""; | 5861 | return ""; |
@@ -13811,8 +13866,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
13811 | return contacts[0]; | 13866 | return contacts[0]; |
13812 | } | 13867 | } |
13813 | 13868 | ||
13814 | public LSL_List llCastRayV1(LSL_Vector start, LSL_Vector end, LSL_List options) | 13869 | public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) |
13815 | { | 13870 | { |
13871 | // Use llCastRay V3 if configured | ||
13872 | if (m_useCastRayV3) | ||
13873 | return llCastRayV3(start, end, options); | ||
13874 | |||
13816 | LSL_List list = new LSL_List(); | 13875 | LSL_List list = new LSL_List(); |
13817 | 13876 | ||
13818 | m_host.AddScriptLPS(1); | 13877 | m_host.AddScriptLPS(1); |
@@ -14003,29 +14062,75 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14003 | } | 14062 | } |
14004 | 14063 | ||
14005 | /// <summary> | 14064 | /// <summary> |
14006 | /// Full implementation of llCastRay similar to SL 2015-04-21. | 14065 | /// Implementation of llCastRay similar to SL 2015-04-21. |
14007 | /// http://wiki.secondlife.com/wiki/LlCastRay | 14066 | /// http://wiki.secondlife.com/wiki/LlCastRay |
14008 | /// Uses pure geometry, bounding shapes, meshing and no physics | 14067 | /// Uses pure geometry, bounding shapes, meshing and no physics |
14009 | /// for prims, sculpts, meshes, avatars and terrain. | 14068 | /// for prims, sculpts, meshes, avatars and terrain. |
14010 | /// Implements all flags, reject types and data flags. | 14069 | /// Implements all flags, reject types and data flags. |
14011 | /// Can handle both objects/groups and prims/parts, by config. | 14070 | /// Can handle both objects/groups and prims/parts, by config. |
14012 | /// May give poor results with multi-part meshes where "root" | 14071 | /// May sometimes be inaccurate owing to calculation precision, |
14013 | /// part doesn't dominate, owing to "guessed" bounding boxes. | 14072 | /// meshing detail level and a bug in libopenmetaverse PrimMesher. |
14014 | /// May sometimes be inaccurate owing to calculation precision | ||
14015 | /// and a bug in libopenmetaverse PrimMesher. | ||
14016 | /// </summary> | 14073 | /// </summary> |
14017 | public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) | 14074 | public LSL_List llCastRayV3(LSL_Vector start, LSL_Vector end, LSL_List options) |
14018 | { | 14075 | { |
14019 | // Use llCastRay v1 if configured | 14076 | m_host.AddScriptLPS(1); |
14020 | if (m_useCastRayV1) | 14077 | LSL_List result = new LSL_List(); |
14021 | return llCastRayV1(start, end, options); | 14078 | |
14079 | // Prepare throttle data | ||
14080 | int calledMs = Environment.TickCount; | ||
14081 | Stopwatch stopWatch = new Stopwatch(); | ||
14082 | stopWatch.Start(); | ||
14083 | UUID regionId = World.RegionInfo.RegionID; | ||
14084 | UUID userId = UUID.Zero; | ||
14085 | int msAvailable = 0; | ||
14086 | // Throttle per owner when attachment or "vehicle" (sat upon) | ||
14087 | if (m_host.ParentGroup.IsAttachment || m_host.ParentGroup.GetSittingAvatars().Count > 0) | ||
14088 | { | ||
14089 | userId = m_host.OwnerID; | ||
14090 | msAvailable = m_msPerAvatarInCastRay; | ||
14091 | } | ||
14092 | // Throttle per parcel when not attachment or vehicle | ||
14093 | else | ||
14094 | { | ||
14095 | LandData land = World.GetLandData(m_host.GetWorldPosition()); | ||
14096 | if (land != null) | ||
14097 | msAvailable = m_msPerRegionInCastRay * land.Area / 65536; | ||
14098 | } | ||
14099 | // Clamp for "oversized" parcels on varregions | ||
14100 | if (msAvailable > m_msMaxInCastRay) | ||
14101 | msAvailable = m_msMaxInCastRay; | ||
14102 | |||
14103 | // Check throttle data | ||
14104 | int fromCalledMs = calledMs - m_msThrottleInCastRay; | ||
14105 | lock (m_castRayCalls) | ||
14106 | { | ||
14107 | for (int i = m_castRayCalls.Count - 1; i >= 0; i--) | ||
14108 | { | ||
14109 | // Delete old calls from throttle data | ||
14110 | if (m_castRayCalls[i].CalledMs < fromCalledMs) | ||
14111 | m_castRayCalls.RemoveAt(i); | ||
14112 | // Use current region (in multi-region sims) | ||
14113 | else if (m_castRayCalls[i].RegionId == regionId) | ||
14114 | { | ||
14115 | // Reduce available time with recent calls | ||
14116 | if (m_castRayCalls[i].UserId == userId) | ||
14117 | msAvailable -= m_castRayCalls[i].UsedMs; | ||
14118 | } | ||
14119 | } | ||
14120 | } | ||
14121 | |||
14122 | // Return failure if not enough available time | ||
14123 | if (msAvailable < m_msMinInCastRay) | ||
14124 | { | ||
14125 | result.Add(new LSL_Integer(ScriptBaseClass.RCERR_CAST_TIME_EXCEEDED)); | ||
14126 | return result; | ||
14127 | } | ||
14022 | 14128 | ||
14023 | // Initialize | 14129 | // Initialize |
14024 | m_host.AddScriptLPS(1); | ||
14025 | List<RayHit> rayHits = new List<RayHit>(); | 14130 | List<RayHit> rayHits = new List<RayHit>(); |
14026 | LSL_List result = new LSL_List(); | ||
14027 | float tol = m_floatToleranceInCastRay; | 14131 | float tol = m_floatToleranceInCastRay; |
14028 | float tol2 = m_floatTolerance2InCastRay; | 14132 | Vector3 pos1Ray = start; |
14133 | Vector3 pos2Ray = end; | ||
14029 | 14134 | ||
14030 | // Get input options | 14135 | // Get input options |
14031 | int rejectTypes = 0; | 14136 | int rejectTypes = 0; |
@@ -14054,25 +14159,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14054 | bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0); | 14159 | bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0); |
14055 | 14160 | ||
14056 | // Calculate some basic parameters | 14161 | // Calculate some basic parameters |
14057 | Vector3 ray = end - start; | 14162 | Vector3 vecRay = pos2Ray - pos1Ray; |
14058 | float rayLength = ray.Length(); | 14163 | float rayLength = vecRay.Length(); |
14059 | 14164 | ||
14060 | // Try to get a mesher and return failure if none or degenerate ray | 14165 | // Try to get a mesher and return failure if none, degenerate ray, or max 0 hits |
14061 | IRendering primMesher = null; | 14166 | IRendering primMesher = null; |
14062 | List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); | 14167 | List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); |
14063 | if (renderers.Count < 1 || rayLength < tol) | 14168 | if (renderers.Count < 1 || rayLength < tol || m_maxHitsInCastRay < 1) |
14064 | { | 14169 | { |
14065 | result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); | 14170 | result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); |
14066 | return result; | 14171 | return result; |
14067 | } | 14172 | } |
14068 | primMesher = RenderingLoader.LoadRenderer(renderers[0]); | 14173 | primMesher = RenderingLoader.LoadRenderer(renderers[0]); |
14069 | 14174 | ||
14070 | // Used to translate and rotate world so ray is along negative Z axis from origo and | ||
14071 | // calculations mostly simplified to a 2D projecttion on the X-Y plane | ||
14072 | Vector3 posProj = new Vector3(-start); | ||
14073 | Quaternion rotProj = Vector3.RotationBetween(ray, new Vector3(0.0f, 0.0f, -1.0f)); | ||
14074 | Quaternion rotBack = Quaternion.Inverse(rotProj); | ||
14075 | |||
14076 | // Iterate over all objects/groups and prims/parts in region | 14175 | // Iterate over all objects/groups and prims/parts in region |
14077 | World.ForEachSOG( | 14176 | World.ForEachSOG( |
14078 | delegate(SceneObjectGroup group) | 14177 | delegate(SceneObjectGroup group) |
@@ -14115,83 +14214,118 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14115 | if (!doPart) | 14214 | if (!doPart) |
14116 | continue; | 14215 | continue; |
14117 | } | 14216 | } |
14118 | // Parse prim/part if passed filters | ||
14119 | 14217 | ||
14120 | // Estimate bounding box from size box | 14218 | // Parse prim/part and project ray if passed filters |
14121 | Vector3 scaleSafe = part.Scale; | 14219 | Vector3 scalePart = part.Scale; |
14122 | if (!part.Shape.SculptEntry) | 14220 | Vector3 posPart = part.GetWorldPosition(); |
14123 | scaleSafe = scaleSafe * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); | 14221 | Quaternion rotPart = part.GetWorldRotation(); |
14222 | Quaternion rotPartInv = Quaternion.Inverse(rotPart); | ||
14223 | Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; | ||
14224 | Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; | ||
14124 | 14225 | ||
14125 | // Filter parts by bounding shapes | 14226 | // Filter parts by shape bounding boxes |
14126 | Vector3 posPartRel = part.GetWorldPosition() + posProj; | 14227 | Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f); |
14127 | Vector3 posPartProj = posPartRel * rotProj; | 14228 | if (!part.Shape.SculptEntry) |
14128 | if (InBoundingShapes(ray, rayLength, scaleSafe, posPartRel, posPartProj, rotProj)) | 14229 | shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); |
14230 | shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol)); | ||
14231 | if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) | ||
14129 | { | 14232 | { |
14130 | // Prepare data needed to check for ray hits | 14233 | // Prepare data needed to check for ray hits |
14131 | RayTrans rayTrans = new RayTrans(); | 14234 | RayTrans rayTrans = new RayTrans(); |
14132 | rayTrans.PartId = part.UUID; | 14235 | rayTrans.PartId = part.UUID; |
14133 | rayTrans.GroupId = part.ParentGroup.UUID; | 14236 | rayTrans.GroupId = part.ParentGroup.UUID; |
14134 | rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; | 14237 | rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; |
14135 | rayTrans.Scale = part.Scale; | 14238 | rayTrans.ScalePart = scalePart; |
14136 | rayTrans.PositionPartProj = posPartProj; | 14239 | rayTrans.PositionPart = posPart; |
14137 | rayTrans.PositionProj = posProj; | 14240 | rayTrans.RotationPart = rotPart; |
14138 | rayTrans.RotationPartProj = rotProj * part.GetWorldRotation(); | 14241 | rayTrans.ShapeNeedsEnds = true; |
14139 | rayTrans.RotationBack = rotBack; | 14242 | rayTrans.Position1Ray = pos1Ray; |
14140 | rayTrans.NeedsEnds = true; | 14243 | rayTrans.Position1RayProj = pos1RayProj; |
14141 | rayTrans.RayLength = rayLength; | 14244 | rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; |
14142 | rayTrans.Tolerance = tol; | 14245 | |
14143 | rayTrans.Tolerance2 = tol2; | 14246 | // Get detail level depending on type |
14144 | 14247 | int lod = 0; | |
14145 | // Make an OMV prim to be able to mesh part | 14248 | // Mesh detail level |
14146 | Primitive omvPrim = part.Shape.ToOmvPrimitive(posPartProj, rayTrans.RotationPartProj); | 14249 | if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) |
14147 | byte[] sculptAsset = null; | 14250 | lod = (int)m_meshLodInCastRay; |
14148 | if (omvPrim.Sculpt != null) | 14251 | // Sculpt detail level |
14149 | sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); | 14252 | else if (part.Shape.SculptEntry && part.Shape.SculptType == (byte)SculptType.Mesh) |
14150 | 14253 | lod = (int)m_sculptLodInCastRay; | |
14151 | // When part is mesh, get and check mesh | 14254 | // Shape detail level |
14152 | if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) | 14255 | else if (!part.Shape.SculptEntry) |
14256 | lod = (int)m_primLodInCastRay; | ||
14257 | |||
14258 | // Try to get cached mesh if configured | ||
14259 | ulong meshKey = 0; | ||
14260 | FacetedMesh mesh = null; | ||
14261 | if (m_useMeshCacheInCastRay) | ||
14153 | { | 14262 | { |
14154 | AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); | 14263 | meshKey = part.Shape.GetMeshKey(Vector3.One, (float)(4 << lod)); |
14155 | FacetedMesh mesh = null; | 14264 | lock (m_cachedMeshes) |
14156 | FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh); | 14265 | { |
14157 | meshAsset = null; | 14266 | m_cachedMeshes.TryGetValue(meshKey, out mesh); |
14158 | AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); | 14267 | } |
14159 | mesh = null; | ||
14160 | } | 14268 | } |
14161 | 14269 | ||
14162 | // When part is sculpt, create and check mesh | 14270 | // Create mesh if no cached mesh |
14163 | // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. | 14271 | if (mesh == null) |
14164 | else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) | ||
14165 | { | 14272 | { |
14166 | IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>(); | 14273 | // Make an OMV prim to be able to mesh part |
14167 | if (imgDecoder != null) | 14274 | Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart); |
14275 | byte[] sculptAsset = null; | ||
14276 | if (omvPrim.Sculpt != null) | ||
14277 | sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); | ||
14278 | |||
14279 | // When part is mesh, get mesh | ||
14280 | if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) | ||
14281 | { | ||
14282 | AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); | ||
14283 | FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh); | ||
14284 | meshAsset = null; | ||
14285 | } | ||
14286 | |||
14287 | // When part is sculpt, create mesh | ||
14288 | // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. | ||
14289 | else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) | ||
14168 | { | 14290 | { |
14169 | Image sculpt = imgDecoder.DecodeToImage(sculptAsset); | 14291 | IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>(); |
14170 | if (sculpt != null) | 14292 | if (imgDecoder != null) |
14171 | { | 14293 | { |
14172 | SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); | 14294 | Image sculpt = imgDecoder.DecodeToImage(sculptAsset); |
14173 | sculpt.Dispose(); | 14295 | if (sculpt != null) |
14174 | AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); | 14296 | { |
14175 | mesh = null; | 14297 | mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay); |
14298 | sculpt.Dispose(); | ||
14299 | } | ||
14176 | } | 14300 | } |
14301 | } | ||
14302 | |||
14303 | // When part is shape, create mesh | ||
14304 | else if (omvPrim.Sculpt == null) | ||
14305 | { | ||
14306 | if ( | ||
14307 | omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && | ||
14308 | omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && | ||
14309 | omvPrim.PrimData.PathSkew == 0.0 && | ||
14310 | omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 | ||
14311 | ) | ||
14312 | rayTrans.ShapeNeedsEnds = false; | ||
14313 | mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay); | ||
14177 | } | 14314 | } |
14178 | } | ||
14179 | 14315 | ||
14180 | // When part is prim, create and check mesh | 14316 | // Cache mesh if configured |
14181 | else if (omvPrim.Sculpt == null) | 14317 | if (m_useMeshCacheInCastRay && mesh != null) |
14182 | { | 14318 | { |
14183 | if ( | 14319 | lock(m_cachedMeshes) |
14184 | omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && | 14320 | { |
14185 | omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && | 14321 | if (!m_cachedMeshes.ContainsKey(meshKey)) |
14186 | omvPrim.PrimData.PathSkew == 0.0 && | 14322 | m_cachedMeshes.Add(meshKey, mesh); |
14187 | omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 | 14323 | } |
14188 | ) | 14324 | } |
14189 | rayTrans.NeedsEnds = false; | ||
14190 | SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); | ||
14191 | AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); | ||
14192 | mesh = null; | ||
14193 | } | 14325 | } |
14194 | 14326 | // Check mesh for ray hits | |
14327 | AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); | ||
14328 | mesh = null; | ||
14195 | } | 14329 | } |
14196 | } | 14330 | } |
14197 | } | 14331 | } |
@@ -14205,38 +14339,71 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14205 | World.ForEachRootScenePresence( | 14339 | World.ForEachRootScenePresence( |
14206 | delegate (ScenePresence sp) | 14340 | delegate (ScenePresence sp) |
14207 | { | 14341 | { |
14208 | // Parse avatar | ||
14209 | |||
14210 | // Get bounding box | 14342 | // Get bounding box |
14211 | Vector3 lower; | 14343 | Vector3 lower; |
14212 | Vector3 upper; | 14344 | Vector3 upper; |
14213 | BoundingBoxOfScenePresence(sp, out lower, out upper); | 14345 | BoundingBoxOfScenePresence(sp, out lower, out upper); |
14214 | Vector3 scale = upper - lower; | 14346 | // Parse avatar |
14215 | 14347 | Vector3 scalePart = upper - lower; | |
14216 | // Filter avatars by bounding shapes | 14348 | Vector3 posPart = sp.AbsolutePosition; |
14217 | Vector3 posPartRel = sp.AbsolutePosition + posProj + (lower + upper) * 0.5f * sp.Rotation; | 14349 | Quaternion rotPart = sp.GetWorldRotation(); |
14218 | Vector3 posPartProj = posPartRel * rotProj; | 14350 | Quaternion rotPartInv = Quaternion.Inverse(rotPart); |
14219 | if (InBoundingShapes(ray, rayLength, scale, posPartRel, posPartProj, rotProj)) | 14351 | posPart = posPart + (lower + upper) * 0.5f * rotPart; |
14352 | // Project ray | ||
14353 | Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; | ||
14354 | Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; | ||
14355 | |||
14356 | // Filter avatars by shape bounding boxes | ||
14357 | Vector3 shapeBoxMax = new Vector3(0.5f + tol, 0.5f + tol, 0.5f + tol); | ||
14358 | if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) | ||
14220 | { | 14359 | { |
14221 | // Prepare data needed to check for ray hits | 14360 | // Prepare data needed to check for ray hits |
14222 | RayTrans rayTrans = new RayTrans(); | 14361 | RayTrans rayTrans = new RayTrans(); |
14223 | rayTrans.PartId = sp.UUID; | 14362 | rayTrans.PartId = sp.UUID; |
14224 | rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID; | 14363 | rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID; |
14225 | rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0; | 14364 | rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0; |
14226 | rayTrans.Scale = scale; | 14365 | rayTrans.ScalePart = scalePart; |
14227 | rayTrans.PositionPartProj = posPartProj; | 14366 | rayTrans.PositionPart = posPart; |
14228 | rayTrans.PositionProj = posProj; | 14367 | rayTrans.RotationPart = rotPart; |
14229 | rayTrans.RotationPartProj = rotProj * sp.Rotation; | 14368 | rayTrans.ShapeNeedsEnds = false; |
14230 | rayTrans.RotationBack = rotBack; | 14369 | rayTrans.Position1Ray = pos1Ray; |
14231 | rayTrans.NeedsEnds = false; | 14370 | rayTrans.Position1RayProj = pos1RayProj; |
14232 | rayTrans.RayLength = rayLength; | 14371 | rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; |
14233 | rayTrans.Tolerance = tol; | 14372 | |
14234 | rayTrans.Tolerance2 = tol2; | 14373 | // Try to get cached mesh if configured |
14235 | 14374 | PrimitiveBaseShape prim = PrimitiveBaseShape.CreateSphere(); | |
14236 | // Make OMV prim, create and check mesh | 14375 | int lod = (int)m_avatarLodInCastRay; |
14237 | Primitive omvPrim = MakeOpenMetaversePrim(scale, posPartProj, rayTrans.RotationPartProj, ScriptBaseClass.PRIM_TYPE_SPHERE); | 14376 | ulong meshKey = prim.GetMeshKey(Vector3.One, (float)(4 << lod)); |
14238 | SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); | 14377 | FacetedMesh mesh = null; |
14239 | AddRayInSimpleMesh(mesh, rayTrans, ref rayHits); | 14378 | if (m_useMeshCacheInCastRay) |
14379 | { | ||
14380 | lock (m_cachedMeshes) | ||
14381 | { | ||
14382 | m_cachedMeshes.TryGetValue(meshKey, out mesh); | ||
14383 | } | ||
14384 | } | ||
14385 | |||
14386 | // Create mesh if no cached mesh | ||
14387 | if (mesh == null) | ||
14388 | { | ||
14389 | // Make OMV prim and create mesh | ||
14390 | prim.Scale = scalePart; | ||
14391 | Primitive omvPrim = prim.ToOmvPrimitive(posPart, rotPart); | ||
14392 | mesh = primMesher.GenerateFacetedMesh(omvPrim, m_avatarLodInCastRay); | ||
14393 | |||
14394 | // Cache mesh if configured | ||
14395 | if (m_useMeshCacheInCastRay && mesh != null) | ||
14396 | { | ||
14397 | lock(m_cachedMeshes) | ||
14398 | { | ||
14399 | if (!m_cachedMeshes.ContainsKey(meshKey)) | ||
14400 | m_cachedMeshes.Add(meshKey, mesh); | ||
14401 | } | ||
14402 | } | ||
14403 | } | ||
14404 | |||
14405 | // Check mesh for ray hits | ||
14406 | AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); | ||
14240 | mesh = null; | 14407 | mesh = null; |
14241 | } | 14408 | } |
14242 | } | 14409 | } |
@@ -14248,32 +14415,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14248 | { | 14415 | { |
14249 | // Parse terrain | 14416 | // Parse terrain |
14250 | 14417 | ||
14251 | // Mesh terrain and check projected bounding box | 14418 | // Mesh terrain and check bounding box |
14252 | Vector3 posPartProj = posProj * rotProj; | ||
14253 | Quaternion rotPartProj = rotProj; | ||
14254 | Vector3 lower; | 14419 | Vector3 lower; |
14255 | Vector3 upper; | 14420 | Vector3 upper; |
14256 | List<Tri> triangles = TrisFromHeightmapUnderRay(start, end, out lower, out upper); | 14421 | List<Tri> triangles = TrisFromHeightmapUnderRay(pos1Ray, pos2Ray, out lower, out upper); |
14257 | Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); | 14422 | lower.Z -= tol; |
14258 | Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue); | 14423 | upper.Z += tol; |
14259 | int dummy = 0; | 14424 | if ((pos1Ray.Z >= lower.Z || pos2Ray.Z >= lower.Z) && (pos1Ray.Z <= upper.Z || pos2Ray.Z <= upper.Z)) |
14260 | AddBoundingBoxOfSimpleBox(lower, upper, posPartProj, rotPartProj, true, ref lowerBox, ref upperBox, ref dummy); | ||
14261 | if (lowerBox.X <= tol && lowerBox.Y <= tol && lowerBox.Z <= tol && upperBox.X >= -tol && upperBox.Y >= -tol && upperBox.Z >= -rayLength - tol) | ||
14262 | { | 14425 | { |
14263 | // Prepare data needed to check for ray hits | 14426 | // Prepare data needed to check for ray hits |
14264 | RayTrans rayTrans = new RayTrans(); | 14427 | RayTrans rayTrans = new RayTrans(); |
14265 | rayTrans.PartId = UUID.Zero; | 14428 | rayTrans.PartId = UUID.Zero; |
14266 | rayTrans.GroupId = UUID.Zero; | 14429 | rayTrans.GroupId = UUID.Zero; |
14267 | rayTrans.Link = 0; | 14430 | rayTrans.Link = 0; |
14268 | rayTrans.Scale = new Vector3 (1.0f, 1.0f, 1.0f); | 14431 | rayTrans.ScalePart = new Vector3 (1.0f, 1.0f, 1.0f); |
14269 | rayTrans.PositionPartProj = posPartProj; | 14432 | rayTrans.PositionPart = Vector3.Zero; |
14270 | rayTrans.PositionProj = posProj; | 14433 | rayTrans.RotationPart = Quaternion.Identity; |
14271 | rayTrans.RotationPartProj = rotPartProj; | 14434 | rayTrans.ShapeNeedsEnds = true; |
14272 | rayTrans.RotationBack = rotBack; | 14435 | rayTrans.Position1Ray = pos1Ray; |
14273 | rayTrans.NeedsEnds = true; | 14436 | rayTrans.Position1RayProj = pos1Ray; |
14274 | rayTrans.RayLength = rayLength; | 14437 | rayTrans.VectorRayProj = vecRay; |
14275 | rayTrans.Tolerance = tol; | ||
14276 | rayTrans.Tolerance2 = tol2; | ||
14277 | 14438 | ||
14278 | // Check mesh | 14439 | // Check mesh |
14279 | AddRayInTris(triangles, rayTrans, ref rayHits); | 14440 | AddRayInTris(triangles, rayTrans, ref rayHits); |
@@ -14347,6 +14508,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14347 | result.Add(new LSL_Vector(rayHit.Normal)); | 14508 | result.Add(new LSL_Vector(rayHit.Normal)); |
14348 | } | 14509 | } |
14349 | result.Add(new LSL_Integer(hitCount)); | 14510 | result.Add(new LSL_Integer(hitCount)); |
14511 | |||
14512 | // Add to throttle data | ||
14513 | stopWatch.Stop(); | ||
14514 | CastRayCall castRayCall = new CastRayCall(); | ||
14515 | castRayCall.RegionId = regionId; | ||
14516 | castRayCall.UserId = userId; | ||
14517 | castRayCall.CalledMs = calledMs; | ||
14518 | castRayCall.UsedMs = (int)stopWatch.ElapsedMilliseconds; | ||
14519 | lock (m_castRayCalls) | ||
14520 | { | ||
14521 | m_castRayCalls.Add(castRayCall); | ||
14522 | } | ||
14523 | |||
14524 | // Return hits | ||
14350 | return result; | 14525 | return result; |
14351 | } | 14526 | } |
14352 | 14527 | ||
@@ -14358,15 +14533,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14358 | public UUID PartId; | 14533 | public UUID PartId; |
14359 | public UUID GroupId; | 14534 | public UUID GroupId; |
14360 | public int Link; | 14535 | public int Link; |
14361 | public Vector3 Scale; | 14536 | public Vector3 ScalePart; |
14362 | public Vector3 PositionPartProj; | 14537 | public Vector3 PositionPart; |
14363 | public Vector3 PositionProj; | 14538 | public Quaternion RotationPart; |
14364 | public Quaternion RotationPartProj; | 14539 | public bool ShapeNeedsEnds; |
14365 | public Quaternion RotationBack; | 14540 | public Vector3 Position1Ray; |
14366 | public bool NeedsEnds; | 14541 | public Vector3 Position1RayProj; |
14367 | public float RayLength; | 14542 | public Vector3 VectorRayProj; |
14368 | public float Tolerance; | ||
14369 | public float Tolerance2; | ||
14370 | } | 14543 | } |
14371 | 14544 | ||
14372 | /// <summary> | 14545 | /// <summary> |
@@ -14383,21 +14556,74 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14383 | } | 14556 | } |
14384 | 14557 | ||
14385 | /// <summary> | 14558 | /// <summary> |
14386 | /// Helper to parse SimpleMesh for ray hits. | 14559 | /// Struct for llCastRay throttle data. |
14387 | /// </summary> | 14560 | /// </summary> |
14388 | private void AddRayInSimpleMesh(SimpleMesh mesh, RayTrans rayTrans, ref List<RayHit> rayHits) | 14561 | public struct CastRayCall |
14389 | { | 14562 | { |
14390 | if (mesh != null) | 14563 | public UUID RegionId; |
14564 | public UUID UserId; | ||
14565 | public int CalledMs; | ||
14566 | public int UsedMs; | ||
14567 | } | ||
14568 | |||
14569 | /// <summary> | ||
14570 | /// Helper to check if a ray intersects a shape bounding box. | ||
14571 | /// </summary> | ||
14572 | private bool RayIntersectsShapeBox(Vector3 pos1RayProj, Vector3 pos2RayProj, Vector3 shapeBoxMax) | ||
14573 | { | ||
14574 | // Skip if ray can't intersect bounding box; | ||
14575 | Vector3 rayBoxProjMin = Vector3.Min(pos1RayProj, pos2RayProj); | ||
14576 | Vector3 rayBoxProjMax = Vector3.Max(pos1RayProj, pos2RayProj); | ||
14577 | if ( | ||
14578 | rayBoxProjMin.X > shapeBoxMax.X || rayBoxProjMin.Y > shapeBoxMax.Y || rayBoxProjMin.Z > shapeBoxMax.Z || | ||
14579 | rayBoxProjMax.X < -shapeBoxMax.X || rayBoxProjMax.Y < -shapeBoxMax.Y || rayBoxProjMax.Z < -shapeBoxMax.Z | ||
14580 | ) | ||
14581 | return false; | ||
14582 | |||
14583 | // Check if ray intersect any bounding box side | ||
14584 | int sign = 0; | ||
14585 | float dist = 0.0f; | ||
14586 | Vector3 posProj = Vector3.Zero; | ||
14587 | Vector3 vecRayProj = pos2RayProj - pos1RayProj; | ||
14588 | |||
14589 | // Check both X sides unless ray is parallell to them | ||
14590 | if (Math.Abs(vecRayProj.X) > m_floatToleranceInCastRay) | ||
14591 | { | ||
14592 | for (sign = -1; sign <= 1; sign += 2) | ||
14593 | { | ||
14594 | dist = ((float)sign * shapeBoxMax.X - pos1RayProj.X) / vecRayProj.X; | ||
14595 | posProj = pos1RayProj + vecRayProj * dist; | ||
14596 | if (Math.Abs(posProj.Y) <= shapeBoxMax.Y && Math.Abs(posProj.Z) <= shapeBoxMax.Z) | ||
14597 | return true; | ||
14598 | } | ||
14599 | } | ||
14600 | |||
14601 | // Check both Y sides unless ray is parallell to them | ||
14602 | if (Math.Abs(vecRayProj.Y) > m_floatToleranceInCastRay) | ||
14603 | { | ||
14604 | for (sign = -1; sign <= 1; sign += 2) | ||
14605 | { | ||
14606 | dist = ((float)sign * shapeBoxMax.Y - pos1RayProj.Y) / vecRayProj.Y; | ||
14607 | posProj = pos1RayProj + vecRayProj * dist; | ||
14608 | if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Z) <= shapeBoxMax.Z) | ||
14609 | return true; | ||
14610 | } | ||
14611 | } | ||
14612 | |||
14613 | // Check both Z sides unless ray is parallell to them | ||
14614 | if (Math.Abs(vecRayProj.Z) > m_floatToleranceInCastRay) | ||
14391 | { | 14615 | { |
14392 | for (int i = 0; i < mesh.Indices.Count; i += 3) | 14616 | for (sign = -1; sign <= 1; sign += 2) |
14393 | { | 14617 | { |
14394 | Tri triangle = new Tri(); | 14618 | dist = ((float)sign * shapeBoxMax.Z - pos1RayProj.Z) / vecRayProj.Z; |
14395 | triangle.p1 = mesh.Vertices[mesh.Indices[i]].Position; | 14619 | posProj = pos1RayProj + vecRayProj * dist; |
14396 | triangle.p2 = mesh.Vertices[mesh.Indices[i + 1]].Position; | 14620 | if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Y) <= shapeBoxMax.Y) |
14397 | triangle.p3 = mesh.Vertices[mesh.Indices[i + 2]].Position; | 14621 | return true; |
14398 | AddRayInTri(triangle, rayTrans, ref rayHits); | ||
14399 | } | 14622 | } |
14400 | } | 14623 | } |
14624 | |||
14625 | // No hits on bounding box so return false | ||
14626 | return false; | ||
14401 | } | 14627 | } |
14402 | 14628 | ||
14403 | /// <summary> | 14629 | /// <summary> |
@@ -14409,7 +14635,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14409 | { | 14635 | { |
14410 | foreach (Face face in mesh.Faces) | 14636 | foreach (Face face in mesh.Faces) |
14411 | { | 14637 | { |
14412 | for (int i = 0; i <face.Indices.Count; i += 3) | 14638 | for (int i = 0; i < face.Indices.Count; i += 3) |
14413 | { | 14639 | { |
14414 | Tri triangle = new Tri(); | 14640 | Tri triangle = new Tri(); |
14415 | triangle.p1 = face.Vertices[face.Indices[i]].Position; | 14641 | triangle.p1 = face.Vertices[face.Indices[i]].Position; |
@@ -14435,23 +14661,28 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14435 | /// <summary> | 14661 | /// <summary> |
14436 | /// Helper to add ray hit in a Tri (triangle). | 14662 | /// Helper to add ray hit in a Tri (triangle). |
14437 | /// </summary> | 14663 | /// </summary> |
14438 | private void AddRayInTri(Tri triangle, RayTrans rayTrans, ref List<RayHit> rayHits) | 14664 | private void AddRayInTri(Tri triProj, RayTrans rayTrans, ref List<RayHit> rayHits) |
14439 | { | 14665 | { |
14440 | // Check for hit in triangle | 14666 | // Check for hit in triangle |
14441 | float distance; | 14667 | Vector3 posHitProj; |
14442 | Vector3 posHit; | 14668 | Vector3 normalProj; |
14443 | Vector3 normal; | 14669 | if (HitRayInTri(triProj, rayTrans.Position1RayProj, rayTrans.VectorRayProj, out posHitProj, out normalProj)) |
14444 | if (HitRayInTri(triangle, rayTrans, out distance, out posHit, out normal)) | 14670 | { |
14445 | { | 14671 | // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) face plane through shape center |
14446 | // Project hit part back to normal coordinate system | 14672 | if (Math.Abs(Vector3.Dot(posHitProj, normalProj)) < m_floatToleranceInCastRay && !rayTrans.ShapeNeedsEnds) |
14447 | Vector3 posPart = rayTrans.PositionPartProj * rayTrans.RotationBack - rayTrans.PositionProj; | ||
14448 | // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) faces plane through shape center | ||
14449 | if (Math.Abs(Vector3.Dot(posPart, normal) - Vector3.Dot(posHit, normal)) < rayTrans.Tolerance && !rayTrans.NeedsEnds) | ||
14450 | return; | 14673 | return; |
14451 | // Remove duplicate hits at triangle edges and intersections | 14674 | |
14675 | // Transform hit and normal to region coordinate system | ||
14676 | Vector3 posHit = rayTrans.PositionPart + (posHitProj * rayTrans.ScalePart) * rayTrans.RotationPart; | ||
14677 | Vector3 normal = Vector3.Normalize((normalProj * rayTrans.ScalePart) * rayTrans.RotationPart); | ||
14678 | |||
14679 | // Remove duplicate hits at triangle intersections | ||
14680 | float distance = Vector3.Distance(rayTrans.Position1Ray, posHit); | ||
14452 | for (int i = rayHits.Count - 1; i >= 0; i--) | 14681 | for (int i = rayHits.Count - 1; i >= 0; i--) |
14453 | { | 14682 | { |
14454 | if (rayHits[i].PartId == rayTrans.PartId && Math.Abs(rayHits[i].Distance - distance) < rayTrans.Tolerance2) | 14683 | if (rayHits[i].PartId != rayTrans.PartId) |
14684 | break; | ||
14685 | if (Math.Abs(rayHits[i].Distance - distance) < m_floatTolerance2InCastRay) | ||
14455 | return; | 14686 | return; |
14456 | } | 14687 | } |
14457 | 14688 | ||
@@ -14468,76 +14699,56 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14468 | } | 14699 | } |
14469 | 14700 | ||
14470 | /// <summary> | 14701 | /// <summary> |
14471 | /// Helper to find ray hit in a Tri (triangle). | 14702 | /// Helper to find ray hit in triangle |
14472 | /// </summary> | 14703 | /// </summary> |
14473 | private bool HitRayInTri(Tri triangle, RayTrans rayTrans, out float distance, out Vector3 posHit, out Vector3 normal) | 14704 | bool HitRayInTri(Tri triProj, Vector3 pos1RayProj, Vector3 vecRayProj, out Vector3 posHitProj, out Vector3 normalProj) |
14474 | { | 14705 | { |
14475 | // Initialize | 14706 | float tol = m_floatToleranceInCastRay; |
14476 | distance = 0.0f; | 14707 | posHitProj = Vector3.Zero; |
14477 | posHit = Vector3.Zero; | 14708 | |
14478 | normal = Vector3.Zero; | 14709 | // Calculate triangle edge vectors |
14479 | float tol = rayTrans.Tolerance; | 14710 | Vector3 vec1Proj = triProj.p2 - triProj.p1; |
14480 | 14711 | Vector3 vec2Proj = triProj.p3 - triProj.p2; | |
14481 | // Project triangle on X-Y plane | 14712 | Vector3 vec3Proj = triProj.p1 - triProj.p3; |
14482 | Vector3 pos1 = triangle.p1 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; | ||
14483 | Vector3 pos2 = triangle.p2 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; | ||
14484 | Vector3 pos3 = triangle.p3 * rayTrans.Scale * rayTrans.RotationPartProj + rayTrans.PositionPartProj; | ||
14485 | |||
14486 | // Check if ray/origo inside triangle bounding rectangle | ||
14487 | Vector3 lower = Vector3.Min(pos1, Vector3.Min(pos2, pos3)); | ||
14488 | Vector3 upper = Vector3.Max(pos1, Vector3.Max(pos2, pos3)); | ||
14489 | if (lower.X > tol || lower.Y > tol || lower.Z > tol || upper.X < -tol || upper.Y < -tol || upper.Z < -rayTrans.RayLength - tol) | ||
14490 | return false; | ||
14491 | 14713 | ||
14492 | // Check if ray/origo inside every edge or reverse "outside" every edge on exit | 14714 | // Calculate triangle normal |
14493 | float dist; | 14715 | normalProj = Vector3.Cross(vec1Proj, vec2Proj); |
14494 | bool inside = true; | 14716 | |
14495 | bool outside = true; | 14717 | // Skip if degenerate triangle or ray parallell with triangle plane |
14496 | Vector3 vec1 = pos2 - pos1; | 14718 | float divisor = Vector3.Dot(vecRayProj, normalProj); |
14497 | dist = pos1.X * vec1.Y - pos1.Y * vec1.X; | 14719 | if (Math.Abs(divisor) < tol) |
14498 | if (dist < -tol) | ||
14499 | inside = false; | ||
14500 | if (dist > tol) | ||
14501 | outside = false; | ||
14502 | Vector3 vec2 = pos3 - pos2; | ||
14503 | dist = pos2.X * vec2.Y - pos2.Y * vec2.X; | ||
14504 | if (dist < -tol) | ||
14505 | inside = false; | ||
14506 | if (dist > tol) | ||
14507 | outside = false; | ||
14508 | Vector3 vec3 = pos1 - pos3; | ||
14509 | dist = pos3.X * vec3.Y - pos3.Y * vec3.X; | ||
14510 | if (dist < -tol) | ||
14511 | inside = false; | ||
14512 | if (dist > tol) | ||
14513 | outside = false; | ||
14514 | |||
14515 | // Skip if ray/origo outside | ||
14516 | if (!inside && !(outside && m_detectExitsInCastRay)) | ||
14517 | return false; | 14720 | return false; |
14518 | 14721 | ||
14519 | // Calculate normal | 14722 | // Skip if exit and not configured to detect |
14520 | Vector3 normalProj = Vector3.Cross(vec1, vec2); | 14723 | if (divisor > tol && !m_detectExitsInCastRay) |
14521 | float normalLength = normalProj.Length(); | ||
14522 | // Skip if degenerate triangle | ||
14523 | if (normalLength < tol) | ||
14524 | return false; | 14724 | return false; |
14525 | normalProj = normalProj / normalLength; | 14725 | |
14526 | // Skip if ray parallell to triangle plane | 14726 | // Skip if outside ray ends |
14527 | if (Math.Abs(normalProj.Z) < tol) | 14727 | float distanceProj = Vector3.Dot(triProj.p1 - pos1RayProj, normalProj) / divisor; |
14728 | if (distanceProj < -tol || distanceProj > 1 + tol) | ||
14528 | return false; | 14729 | return false; |
14529 | 14730 | ||
14530 | // Calculate distance | 14731 | // Calculate hit position in triangle |
14531 | distance = Vector3.Dot(normalProj, pos2) / normalProj.Z * -1.0f; | 14732 | posHitProj = pos1RayProj + vecRayProj * distanceProj; |
14532 | // Skip if outside ray | 14733 | |
14533 | if (distance < -tol || distance > rayTrans.RayLength + tol) | 14734 | // Skip if outside triangle bounding box |
14735 | Vector3 triProjMin = Vector3.Min(Vector3.Min(triProj.p1, triProj.p2), triProj.p3); | ||
14736 | Vector3 triProjMax = Vector3.Max(Vector3.Max(triProj.p1, triProj.p2), triProj.p3); | ||
14737 | if ( | ||
14738 | posHitProj.X < triProjMin.X - tol || posHitProj.Y < triProjMin.Y - tol || posHitProj.Z < triProjMin.Z - tol || | ||
14739 | posHitProj.X > triProjMax.X + tol || posHitProj.Y > triProjMax.Y + tol || posHitProj.Z > triProjMax.Z + tol | ||
14740 | ) | ||
14534 | return false; | 14741 | return false; |
14535 | 14742 | ||
14536 | // Calculate projected hit position | 14743 | // Skip if outside triangle |
14537 | Vector3 posHitProj = new Vector3(0.0f, 0.0f, -distance); | 14744 | if ( |
14538 | // Project hit back to normal coordinate system | 14745 | Vector3.Dot(Vector3.Cross(vec1Proj, normalProj), posHitProj - triProj.p1) > tol || |
14539 | posHit = posHitProj * rayTrans.RotationBack - rayTrans.PositionProj; | 14746 | Vector3.Dot(Vector3.Cross(vec2Proj, normalProj), posHitProj - triProj.p2) > tol || |
14540 | normal = normalProj * rayTrans.RotationBack; | 14747 | Vector3.Dot(Vector3.Cross(vec3Proj, normalProj), posHitProj - triProj.p3) > tol |
14748 | ) | ||
14749 | return false; | ||
14750 | |||
14751 | // Return hit | ||
14541 | return true; | 14752 | return true; |
14542 | } | 14753 | } |
14543 | 14754 | ||
@@ -14660,24 +14871,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14660 | y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1); | 14871 | y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1); |
14661 | Vector3 pos2 = new Vector3(x, y, (float)World.Heightmap[x, y]); | 14872 | Vector3 pos2 = new Vector3(x, y, (float)World.Heightmap[x, y]); |
14662 | // Adjust bounding box | 14873 | // Adjust bounding box |
14663 | zLower = Math.Min(zLower, pos1.Z); | 14874 | zLower = Math.Min(zLower, pos2.Z); |
14664 | zUpper = Math.Max(zUpper, pos1.Z); | 14875 | zUpper = Math.Max(zUpper, pos2.Z); |
14665 | 14876 | ||
14666 | // Corner 3 of 1x1 rectangle | 14877 | // Corner 3 of 1x1 rectangle |
14667 | x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1); | 14878 | x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1); |
14668 | y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); | 14879 | y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); |
14669 | Vector3 pos3 = new Vector3(x, y, (float)World.Heightmap[x, y]); | 14880 | Vector3 pos3 = new Vector3(x, y, (float)World.Heightmap[x, y]); |
14670 | // Adjust bounding box | 14881 | // Adjust bounding box |
14671 | zLower = Math.Min(zLower, pos1.Z); | 14882 | zLower = Math.Min(zLower, pos3.Z); |
14672 | zUpper = Math.Max(zUpper, pos1.Z); | 14883 | zUpper = Math.Max(zUpper, pos3.Z); |
14673 | 14884 | ||
14674 | // Corner 4 of 1x1 rectangle | 14885 | // Corner 4 of 1x1 rectangle |
14675 | x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1); | 14886 | x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1); |
14676 | y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); | 14887 | y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); |
14677 | Vector3 pos4 = new Vector3(x, y, (float)World.Heightmap[x, y]); | 14888 | Vector3 pos4 = new Vector3(x, y, (float)World.Heightmap[x, y]); |
14678 | // Adjust bounding box | 14889 | // Adjust bounding box |
14679 | zLower = Math.Min(zLower, pos1.Z); | 14890 | zLower = Math.Min(zLower, pos4.Z); |
14680 | zUpper = Math.Max(zUpper, pos1.Z); | 14891 | zUpper = Math.Max(zUpper, pos4.Z); |
14681 | 14892 | ||
14682 | // Add triangle 1 | 14893 | // Add triangle 1 |
14683 | Tri triangle1 = new Tri(); | 14894 | Tri triangle1 = new Tri(); |
@@ -14695,25 +14906,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
14695 | } | 14906 | } |
14696 | 14907 | ||
14697 | /// <summary> | 14908 | /// <summary> |
14698 | /// Helper to check if a ray intersects bounding shapes. | ||
14699 | /// </summary> | ||
14700 | private bool InBoundingShapes(Vector3 ray, float rayLength, Vector3 scale, Vector3 posPartRel, Vector3 posPartProj, Quaternion rotProj) | ||
14701 | { | ||
14702 | float tol = m_floatToleranceInCastRay; | ||
14703 | |||
14704 | // Check if ray intersects projected bounding box | ||
14705 | Vector3 lowerBox = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); | ||
14706 | Vector3 upperBox = new Vector3(float.MinValue, float.MinValue, float.MinValue); | ||
14707 | int dummy = 0; | ||
14708 | AddBoundingBoxOfSimpleBox(scale * -0.5f, scale * 0.5f, posPartProj, rotProj, true, ref lowerBox, ref upperBox, ref dummy); | ||
14709 | if (lowerBox.X > tol || lowerBox.Y > tol || lowerBox.Z > tol || upperBox.X < -tol || upperBox.Y < -tol || upperBox.Z < -rayLength - tol) | ||
14710 | return false; | ||
14711 | |||
14712 | // Passed bounding shape filters, so return true | ||
14713 | return true; | ||
14714 | } | ||
14715 | |||
14716 | /// <summary> | ||
14717 | /// Helper to get link number for a UUID. | 14909 | /// Helper to get link number for a UUID. |
14718 | /// </summary> | 14910 | /// </summary> |
14719 | private int UUID2LinkNumber(SceneObjectPart part, UUID id) | 14911 | private int UUID2LinkNumber(SceneObjectPart part, UUID id) |