aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs678
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 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Diagnostics;
31using System.Drawing; 32using System.Drawing;
32using System.Drawing.Imaging; 33using System.Drawing.Imaging;
33using System.Runtime.Remoting.Lifetime; 34using 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)