diff options
author | Michael Heilmann | 2015-05-19 15:18:45 -0400 |
---|---|---|
committer | Michael Heilmann | 2015-05-19 15:18:45 -0400 |
commit | 140ea04b9d692344d803fc87364fb252561725c3 (patch) | |
tree | d503b7ae17baca374d704b548fc7da512f512388 /OpenSim/Region/ScriptEngine/Shared | |
parent | Merge pull request #7 from gamucf/moses.metricsPhase2 (diff) | |
parent | resolve possible nullref when sending appearance packet. Thanks to zadark for... (diff) | |
download | opensim-SC-140ea04b9d692344d803fc87364fb252561725c3.zip opensim-SC-140ea04b9d692344d803fc87364fb252561725c3.tar.gz opensim-SC-140ea04b9d692344d803fc87364fb252561725c3.tar.bz2 opensim-SC-140ea04b9d692344d803fc87364fb252561725c3.tar.xz |
Merging Opensim upstream before generating patch
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared')
5 files changed, 1269 insertions, 49 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 40b7c35..089a5a8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -28,6 +28,8 @@ | |||
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.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
31 | using System.Runtime.Remoting.Lifetime; | 33 | using System.Runtime.Remoting.Lifetime; |
32 | using System.Text; | 34 | using System.Text; |
33 | using System.Threading; | 35 | using System.Threading; |
@@ -35,7 +37,9 @@ using System.Text.RegularExpressions; | |||
35 | using Nini.Config; | 37 | using Nini.Config; |
36 | using log4net; | 38 | using log4net; |
37 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | using OpenMetaverse.Assets; | ||
38 | using OpenMetaverse.Packets; | 41 | using OpenMetaverse.Packets; |
42 | using OpenMetaverse.Rendering; | ||
39 | using OpenSim; | 43 | using OpenSim; |
40 | using OpenSim.Framework; | 44 | using OpenSim.Framework; |
41 | 45 | ||
@@ -182,6 +186,55 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
182 | protected bool m_restrictEmail = false; | 186 | protected bool m_restrictEmail = false; |
183 | protected ISoundModule m_SoundModule = null; | 187 | protected ISoundModule m_SoundModule = null; |
184 | 188 | ||
189 | protected float m_avatarHeightCorrection = 0.2f; | ||
190 | protected bool m_useSimpleBoxesInGetBoundingBox = false; | ||
191 | protected bool m_addStatsInGetBoundingBox = false; | ||
192 | |||
193 | //LSL Avatar Bounding Box (lABB), lower (1) and upper (2), | ||
194 | //standing (Std), Groundsitting (Grs), Sitting (Sit), | ||
195 | //along X, Y and Z axes, constants (0) and coefficients (1) | ||
196 | protected float m_lABB1StdX0 = -0.275f; | ||
197 | protected float m_lABB2StdX0 = 0.275f; | ||
198 | protected float m_lABB1StdY0 = -0.35f; | ||
199 | protected float m_lABB2StdY0 = 0.35f; | ||
200 | protected float m_lABB1StdZ0 = -0.1f; | ||
201 | protected float m_lABB1StdZ1 = -0.5f; | ||
202 | protected float m_lABB2StdZ0 = 0.1f; | ||
203 | protected float m_lABB2StdZ1 = 0.5f; | ||
204 | protected float m_lABB1GrsX0 = -0.3875f; | ||
205 | protected float m_lABB2GrsX0 = 0.3875f; | ||
206 | protected float m_lABB1GrsY0 = -0.5f; | ||
207 | protected float m_lABB2GrsY0 = 0.5f; | ||
208 | protected float m_lABB1GrsZ0 = -0.05f; | ||
209 | protected float m_lABB1GrsZ1 = -0.375f; | ||
210 | protected float m_lABB2GrsZ0 = 0.5f; | ||
211 | protected float m_lABB2GrsZ1 = 0.0f; | ||
212 | protected float m_lABB1SitX0 = -0.5875f; | ||
213 | protected float m_lABB2SitX0 = 0.1875f; | ||
214 | protected float m_lABB1SitY0 = -0.35f; | ||
215 | protected float m_lABB2SitY0 = 0.35f; | ||
216 | protected float m_lABB1SitZ0 = -0.35f; | ||
217 | protected float m_lABB1SitZ1 = -0.375f; | ||
218 | protected float m_lABB2SitZ0 = -0.25f; | ||
219 | protected float m_lABB2SitZ1 = 0.25f; | ||
220 | |||
221 | protected float m_primSafetyCoeffX = 2.414214f; | ||
222 | protected float m_primSafetyCoeffY = 2.414214f; | ||
223 | protected float m_primSafetyCoeffZ = 1.618034f; | ||
224 | protected bool m_useCastRayV3 = false; | ||
225 | protected float m_floatToleranceInCastRay = 0.000001f; | ||
226 | protected float m_floatTolerance2InCastRay = 0.0001f; | ||
227 | protected DetailLevel m_primLodInCastRay = DetailLevel.Medium; | ||
228 | protected DetailLevel m_sculptLodInCastRay = DetailLevel.Medium; | ||
229 | protected DetailLevel m_meshLodInCastRay = DetailLevel.Highest; | ||
230 | protected DetailLevel m_avatarLodInCastRay = DetailLevel.Medium; | ||
231 | protected int m_maxHitsInCastRay = 16; | ||
232 | protected int m_maxHitsPerPrimInCastRay = 16; | ||
233 | protected int m_maxHitsPerObjectInCastRay = 16; | ||
234 | protected bool m_detectExitsInCastRay = false; | ||
235 | protected bool m_filterPartsInCastRay = false; | ||
236 | protected bool m_doAttachmentsInCastRay = false; | ||
237 | |||
185 | //An array of HTTP/1.1 headers that are not allowed to be used | 238 | //An array of HTTP/1.1 headers that are not allowed to be used |
186 | //as custom headers by llHTTPRequest. | 239 | //as custom headers by llHTTPRequest. |
187 | private string[] HttpStandardHeaders = | 240 | private string[] HttpStandardHeaders = |
@@ -257,6 +310,49 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
257 | if (lslConfig != null) | 310 | if (lslConfig != null) |
258 | { | 311 | { |
259 | m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail); | 312 | m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail); |
313 | m_avatarHeightCorrection = lslConfig.GetFloat("AvatarHeightCorrection", m_avatarHeightCorrection); | ||
314 | m_useSimpleBoxesInGetBoundingBox = lslConfig.GetBoolean("UseSimpleBoxesInGetBoundingBox", m_useSimpleBoxesInGetBoundingBox); | ||
315 | m_addStatsInGetBoundingBox = lslConfig.GetBoolean("AddStatsInGetBoundingBox", m_addStatsInGetBoundingBox); | ||
316 | m_lABB1StdX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingXconst", m_lABB1StdX0); | ||
317 | m_lABB2StdX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingXconst", m_lABB2StdX0); | ||
318 | m_lABB1StdY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingYconst", m_lABB1StdY0); | ||
319 | m_lABB2StdY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingYconst", m_lABB2StdY0); | ||
320 | m_lABB1StdZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZconst", m_lABB1StdZ0); | ||
321 | m_lABB1StdZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZcoeff", m_lABB1StdZ1); | ||
322 | m_lABB2StdZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZconst", m_lABB2StdZ0); | ||
323 | m_lABB2StdZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZcoeff", m_lABB2StdZ1); | ||
324 | m_lABB1GrsX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingXconst", m_lABB1GrsX0); | ||
325 | m_lABB2GrsX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingXconst", m_lABB2GrsX0); | ||
326 | m_lABB1GrsY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingYconst", m_lABB1GrsY0); | ||
327 | m_lABB2GrsY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingYconst", m_lABB2GrsY0); | ||
328 | m_lABB1GrsZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZconst", m_lABB1GrsZ0); | ||
329 | m_lABB1GrsZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZcoeff", m_lABB1GrsZ1); | ||
330 | m_lABB2GrsZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZconst", m_lABB2GrsZ0); | ||
331 | m_lABB2GrsZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZcoeff", m_lABB2GrsZ1); | ||
332 | m_lABB1SitX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingXconst", m_lABB1SitX0); | ||
333 | m_lABB2SitX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingXconst", m_lABB2SitX0); | ||
334 | m_lABB1SitY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingYconst", m_lABB1SitY0); | ||
335 | m_lABB2SitY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingYconst", m_lABB2SitY0); | ||
336 | m_lABB1SitZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZconst", m_lABB1SitZ0); | ||
337 | m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1); | ||
338 | m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0); | ||
339 | m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1); | ||
340 | m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); | ||
341 | m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); | ||
342 | m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); | ||
343 | m_useCastRayV3 = lslConfig.GetBoolean("UseLlCastRayV3", m_useCastRayV3); | ||
344 | m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); | ||
345 | m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); | ||
346 | m_primLodInCastRay = (DetailLevel)lslConfig.GetInt("PrimDetailLevelInLlCastRay", (int)m_primLodInCastRay); | ||
347 | m_sculptLodInCastRay = (DetailLevel)lslConfig.GetInt("SculptDetailLevelInLlCastRay", (int)m_sculptLodInCastRay); | ||
348 | m_meshLodInCastRay = (DetailLevel)lslConfig.GetInt("MeshDetailLevelInLlCastRay", (int)m_meshLodInCastRay); | ||
349 | m_avatarLodInCastRay = (DetailLevel)lslConfig.GetInt("AvatarDetailLevelInLlCastRay", (int)m_avatarLodInCastRay); | ||
350 | m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); | ||
351 | m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay); | ||
352 | m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay); | ||
353 | m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); | ||
354 | m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); | ||
355 | m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); | ||
260 | } | 356 | } |
261 | 357 | ||
262 | IConfig smtpConfig = seConfigSource.Configs["SMTP"]; | 358 | IConfig smtpConfig = seConfigSource.Configs["SMTP"]; |
@@ -7725,13 +7821,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7725 | { | 7821 | { |
7726 | profilecut.y = 1f; | 7822 | profilecut.y = 1f; |
7727 | } | 7823 | } |
7728 | if (profilecut.y - profilecut.x < 0.05f) | 7824 | if (profilecut.y - profilecut.x < 0.02f) |
7729 | { | 7825 | { |
7730 | profilecut.x = profilecut.y - 0.05f; | 7826 | profilecut.x = profilecut.y - 0.02f; |
7731 | if (profilecut.x < 0.0f) | 7827 | if (profilecut.x < 0.0f) |
7732 | { | 7828 | { |
7733 | profilecut.x = 0.0f; | 7829 | profilecut.x = 0.0f; |
7734 | profilecut.y = 0.05f; | 7830 | profilecut.y = 0.02f; |
7735 | } | 7831 | } |
7736 | } | 7832 | } |
7737 | shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x); | 7833 | shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x); |
@@ -9584,80 +9680,441 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
9584 | } | 9680 | } |
9585 | 9681 | ||
9586 | /// <summary> | 9682 | /// <summary> |
9587 | /// A partial implementation. | 9683 | /// Full implementation of llGetBoundingBox according to SL 2015-04-15. |
9684 | /// http://wiki.secondlife.com/wiki/LlGetBoundingBox | ||
9588 | /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox | 9685 | /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox |
9589 | /// So far only valid for standing/flying/ground sitting avatars and single prim objects. | 9686 | /// Returns local bounding box of avatar without attachments |
9590 | /// If the object has multiple prims and/or a sitting avatar then the bounding | 9687 | /// if target is non-seated avatar or prim/mesh in avatar attachment. |
9591 | /// box is for the root prim only. | 9688 | /// Returns local bounding box of object including seated avatars |
9689 | /// if target is seated avatar or prim/mesh in object. | ||
9690 | /// Uses meshing of prims for high accuracy | ||
9691 | /// or less accurate box models for speed. | ||
9592 | /// </summary> | 9692 | /// </summary> |
9593 | public LSL_List llGetBoundingBox(string obj) | 9693 | public LSL_List llGetBoundingBox(string obj) |
9594 | { | 9694 | { |
9595 | m_host.AddScriptLPS(1); | 9695 | m_host.AddScriptLPS(1); |
9696 | |||
9697 | // Get target avatar if non-seated avatar or attachment, or prim and object | ||
9596 | UUID objID = UUID.Zero; | 9698 | UUID objID = UUID.Zero; |
9699 | UUID.TryParse(obj, out objID); | ||
9700 | ScenePresence agent = World.GetScenePresence(objID); | ||
9701 | if (agent != null) | ||
9702 | { | ||
9703 | if (agent.ParentPart != null) | ||
9704 | { | ||
9705 | objID = agent.ParentPart.UUID; | ||
9706 | agent = null; | ||
9707 | } | ||
9708 | } | ||
9709 | SceneObjectGroup group = null; | ||
9710 | SceneObjectPart target = World.GetSceneObjectPart(objID); | ||
9711 | if (target != null) | ||
9712 | { | ||
9713 | group = target.ParentGroup; | ||
9714 | if (group.IsAttachment) { | ||
9715 | objID = group.AttachedAvatar; | ||
9716 | agent = World.GetScenePresence(objID); | ||
9717 | group = null; | ||
9718 | target = null; | ||
9719 | } | ||
9720 | } | ||
9721 | |||
9722 | // Initialize but break if no target | ||
9597 | LSL_List result = new LSL_List(); | 9723 | LSL_List result = new LSL_List(); |
9598 | if (!UUID.TryParse(obj, out objID)) | 9724 | int groupCount = 0; |
9725 | int partCount = 0; | ||
9726 | int vertexCount = 0; | ||
9727 | if (target == null && agent == null) | ||
9599 | { | 9728 | { |
9600 | result.Add(new LSL_Vector()); | 9729 | result.Add(new LSL_Vector()); |
9601 | result.Add(new LSL_Vector()); | 9730 | result.Add(new LSL_Vector()); |
9731 | if (m_addStatsInGetBoundingBox) | ||
9732 | result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); | ||
9602 | return result; | 9733 | return result; |
9603 | } | 9734 | } |
9604 | ScenePresence presence = World.GetScenePresence(objID); | 9735 | Vector3 minPosition = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); |
9605 | if (presence != null) | 9736 | Vector3 maxPosition = new Vector3(float.MinValue, float.MinValue, float.MinValue); |
9737 | |||
9738 | // Try to get a mesher | ||
9739 | IRendering primMesher = null; | ||
9740 | List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); | ||
9741 | if (renderers.Count > 0) | ||
9742 | primMesher = RenderingLoader.LoadRenderer(renderers[0]); | ||
9743 | |||
9744 | // Get bounding box of just avatar, seated or not | ||
9745 | if (agent != null) | ||
9746 | { | ||
9747 | bool hasParent = false; | ||
9748 | Vector3 lower; | ||
9749 | Vector3 upper; | ||
9750 | BoundingBoxOfScenePresence(agent, out lower, out upper); | ||
9751 | Vector3 offset = Vector3.Zero; | ||
9752 | |||
9753 | // Since local bounding box unrotated and untilted, keep it simple | ||
9754 | AddBoundingBoxOfSimpleBox(lower, upper, offset, agent.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9755 | partCount++; | ||
9756 | groupCount++; | ||
9757 | |||
9758 | // Return lower and upper bounding box corners | ||
9759 | result.Add(new LSL_Vector(minPosition)); | ||
9760 | result.Add(new LSL_Vector(maxPosition)); | ||
9761 | if (m_addStatsInGetBoundingBox) | ||
9762 | result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); | ||
9763 | return result; | ||
9764 | } | ||
9765 | // Get bounding box of object including seated avatars | ||
9766 | else if (group != null) | ||
9606 | { | 9767 | { |
9607 | if (presence.ParentID == 0) // not sat on an object | 9768 | // Merge bounding boxes of all parts (prims and mesh) |
9769 | foreach (SceneObjectPart part in group.Parts) | ||
9608 | { | 9770 | { |
9609 | LSL_Vector lower; | 9771 | bool hasParent = (!part.IsRoot); |
9610 | LSL_Vector upper; | 9772 | // When requested or if no mesher, keep it simple |
9611 | if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID | 9773 | if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) |
9612 | == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) | ||
9613 | { | 9774 | { |
9614 | // This is for ground sitting avatars | 9775 | AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); |
9615 | float height = presence.Appearance.AvatarHeight / 2.66666667f; | ||
9616 | lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f); | ||
9617 | upper = new LSL_Vector(0.3375f, 0.45f, 0.0f); | ||
9618 | } | 9776 | } |
9777 | // Do the full mounty | ||
9619 | else | 9778 | else |
9620 | { | 9779 | { |
9621 | // This is for standing/flying avatars | 9780 | Primitive omvPrim = part.Shape.ToOmvPrimitive(part.OffsetPosition, part.RotationOffset); |
9622 | float height = presence.Appearance.AvatarHeight / 2.0f; | 9781 | byte[] sculptAsset = null; |
9623 | lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f); | 9782 | if (omvPrim.Sculpt != null) |
9624 | upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f); | 9783 | sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); |
9784 | |||
9785 | // When part is mesh | ||
9786 | // Quirk: Only imports as incompletely populated faceted mesh object, so needs an own handler. | ||
9787 | if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) | ||
9788 | { | ||
9789 | AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); | ||
9790 | FacetedMesh mesh = null; | ||
9791 | FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh); | ||
9792 | meshAsset = null; | ||
9793 | if (mesh != null) | ||
9794 | { | ||
9795 | AddBoundingBoxOfFacetedMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9796 | mesh = null; | ||
9797 | } | ||
9798 | } | ||
9799 | |||
9800 | // When part is sculpt | ||
9801 | // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. | ||
9802 | else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) | ||
9803 | { | ||
9804 | IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>(); | ||
9805 | if (imgDecoder != null) | ||
9806 | { | ||
9807 | Image sculpt = imgDecoder.DecodeToImage(sculptAsset); | ||
9808 | if (sculpt != null) | ||
9809 | { | ||
9810 | SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); | ||
9811 | sculpt.Dispose(); | ||
9812 | if (mesh != null) | ||
9813 | { | ||
9814 | AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9815 | mesh = null; | ||
9816 | } | ||
9817 | } | ||
9818 | } | ||
9819 | } | ||
9820 | |||
9821 | // When part is prim | ||
9822 | else if (omvPrim.Sculpt == null) | ||
9823 | { | ||
9824 | SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); | ||
9825 | if (mesh != null) | ||
9826 | { | ||
9827 | AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9828 | mesh = null; | ||
9829 | } | ||
9830 | } | ||
9831 | |||
9832 | // When all else fails, try fallback to simple box | ||
9833 | else | ||
9834 | { | ||
9835 | AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9836 | } | ||
9625 | } | 9837 | } |
9626 | result.Add(lower); | 9838 | partCount++; |
9627 | result.Add(upper); | ||
9628 | return result; | ||
9629 | } | 9839 | } |
9840 | } | ||
9841 | |||
9842 | // Merge bounding boxes of seated avatars | ||
9843 | foreach (ScenePresence sp in group.GetSittingAvatars()) | ||
9844 | { | ||
9845 | Vector3 lower; | ||
9846 | Vector3 upper; | ||
9847 | BoundingBoxOfScenePresence(sp, out lower, out upper); | ||
9848 | Vector3 offset = sp.OffsetPosition; | ||
9849 | |||
9850 | bool hasParent = true; | ||
9851 | // When requested or if no mesher, keep it simple | ||
9852 | if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) | ||
9853 | { | ||
9854 | AddBoundingBoxOfSimpleBox(lower, upper, offset, sp.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9855 | } | ||
9856 | // Do the full mounty | ||
9630 | else | 9857 | else |
9631 | { | 9858 | { |
9632 | // sitting on an object so we need the bounding box of that | 9859 | // Prim shapes don't do center offsets, so add it here. |
9633 | // which should include the avatar so set the UUID to the | 9860 | offset = offset + (lower + upper) * 0.5f * sp.Rotation; |
9634 | // UUID of the object the avatar is sat on and allow it to fall through | 9861 | Primitive omvPrim = MakeOpenMetaversePrim(upper - lower, offset, sp.Rotation, ScriptBaseClass.PRIM_TYPE_SPHERE); |
9635 | // to processing an object | 9862 | SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); |
9636 | SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID); | 9863 | AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); |
9637 | objID = p.UUID; | 9864 | mesh = null; |
9638 | } | 9865 | } |
9866 | partCount++; | ||
9867 | } | ||
9868 | |||
9869 | groupCount++; | ||
9870 | |||
9871 | // Return lower and upper bounding box corners | ||
9872 | result.Add(new LSL_Vector(minPosition)); | ||
9873 | result.Add(new LSL_Vector(maxPosition)); | ||
9874 | if (m_addStatsInGetBoundingBox) | ||
9875 | result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); | ||
9876 | |||
9877 | primMesher = null; | ||
9878 | return result; | ||
9879 | } | ||
9880 | |||
9881 | /// <summary> | ||
9882 | /// Helper to calculate bounding box of an avatar. | ||
9883 | /// </summary> | ||
9884 | private void BoundingBoxOfScenePresence(ScenePresence sp, out Vector3 lower, out Vector3 upper) | ||
9885 | { | ||
9886 | // Adjust from OS model | ||
9887 | // avatar height = visual height - 0.2, bounding box height = visual height | ||
9888 | // to SL model | ||
9889 | // avatar height = visual height, bounding box height = visual height + 0.2 | ||
9890 | float height = sp.Appearance.AvatarHeight + m_avatarHeightCorrection; | ||
9891 | |||
9892 | // According to avatar bounding box in SL 2015-04-18: | ||
9893 | // standing = <-0.275,-0.35,-0.1-0.5*h> : <0.275,0.35,0.1+0.5*h> | ||
9894 | // groundsitting = <-0.3875,-0.5,-0.05-0.375*h> : <0.3875,0.5,0.5> | ||
9895 | // sitting = <-0.5875,-0.35,-0.35-0.375*h> : <0.1875,0.35,-0.25+0.25*h> | ||
9896 | |||
9897 | // When avatar is sitting | ||
9898 | if (sp.ParentPart != null) | ||
9899 | { | ||
9900 | lower = new Vector3(m_lABB1SitX0, m_lABB1SitY0, m_lABB1SitZ0 + m_lABB1SitZ1 * height); | ||
9901 | upper = new Vector3(m_lABB2SitX0, m_lABB2SitY0, m_lABB2SitZ0 + m_lABB2SitZ1 * height); | ||
9639 | } | 9902 | } |
9640 | SceneObjectPart part = World.GetSceneObjectPart(objID); | 9903 | // When avatar is groundsitting |
9641 | // Currently only works for single prims without a sitting avatar | 9904 | else if (sp.Animator.Animations.ImplicitDefaultAnimation.AnimID == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) |
9642 | if (part != null) | ||
9643 | { | 9905 | { |
9644 | Vector3 halfSize = part.Scale / 2.0f; | 9906 | lower = new Vector3(m_lABB1GrsX0, m_lABB1GrsY0, m_lABB1GrsZ0 + m_lABB1GrsZ1 * height); |
9645 | LSL_Vector lower = (new LSL_Vector(halfSize)) * -1.0f; | 9907 | upper = new Vector3(m_lABB2GrsX0, m_lABB2GrsY0, m_lABB2GrsZ0 + m_lABB2GrsZ1 * height); |
9646 | LSL_Vector upper = new LSL_Vector(halfSize); | ||
9647 | result.Add(lower); | ||
9648 | result.Add(upper); | ||
9649 | return result; | ||
9650 | } | 9908 | } |
9909 | // When avatar is standing or flying | ||
9910 | else | ||
9911 | { | ||
9912 | lower = new Vector3(m_lABB1StdX0, m_lABB1StdY0, m_lABB1StdZ0 + m_lABB1StdZ1 * height); | ||
9913 | upper = new Vector3(m_lABB2StdX0, m_lABB2StdY0, m_lABB2StdZ0 + m_lABB2StdZ1 * height); | ||
9914 | } | ||
9915 | } | ||
9651 | 9916 | ||
9652 | // Not found so return empty values | 9917 | /// <summary> |
9653 | result.Add(new LSL_Vector()); | 9918 | /// Helper to approximate a part with a simple box. |
9654 | result.Add(new LSL_Vector()); | 9919 | /// </summary> |
9655 | return result; | 9920 | private void AddBoundingBoxOfSimpleBox(Vector3 corner1, Vector3 corner2, Vector3 offset, Quaternion rotation, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) |
9921 | { | ||
9922 | // Parse the 8 box corners | ||
9923 | for (int i = 0; i < 8; i++) | ||
9924 | { | ||
9925 | // Calculate each box corner | ||
9926 | Vector3 position = corner1; | ||
9927 | if ((i & 1) != 0) | ||
9928 | position.X = corner2.X; | ||
9929 | if ((i & 2) != 0) | ||
9930 | position.Y = corner2.Y; | ||
9931 | if ((i & 4) != 0) | ||
9932 | position.Z = corner2.Z; | ||
9933 | // Rotate part unless part is root | ||
9934 | if (hasParent) | ||
9935 | position = position * rotation; | ||
9936 | position = position + offset; | ||
9937 | // Adjust lower and upper bounding box corners if needed | ||
9938 | lower = Vector3.Min(lower, position); | ||
9939 | upper = Vector3.Max(upper, position); | ||
9940 | count++; | ||
9941 | } | ||
9656 | } | 9942 | } |
9657 | 9943 | ||
9944 | /// <summary> | ||
9945 | /// Helper to parse a meshed prim and needed especially | ||
9946 | /// for accuracy with tortured prims and sculpts. | ||
9947 | /// </summary> | ||
9948 | private void AddBoundingBoxOfSimpleMesh(SimpleMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) | ||
9949 | { | ||
9950 | // Quirk: A meshed box contains 10 instead of the 8 necessary vertices. | ||
9951 | if (mesh != null) | ||
9952 | { | ||
9953 | // Parse each vertex in mesh | ||
9954 | foreach (Vertex vertex in mesh.Vertices) | ||
9955 | { | ||
9956 | Vector3 position = vertex.Position; | ||
9957 | position = position * prim.Scale; | ||
9958 | // Rotate part unless part is root | ||
9959 | if (hasParent) | ||
9960 | position = position * prim.Rotation; | ||
9961 | position = position + prim.Position; | ||
9962 | // Adjust lower and upper bounding box corners if needed | ||
9963 | lower = Vector3.Min(lower, position); | ||
9964 | upper = Vector3.Max(upper, position); | ||
9965 | count++; | ||
9966 | } | ||
9967 | } | ||
9968 | } | ||
9969 | |||
9970 | /// <summary> | ||
9971 | /// Helper to parse mesh because no method exists | ||
9972 | /// to parse mesh assets to SimpleMesh. | ||
9973 | /// </summary> | ||
9974 | private void AddBoundingBoxOfFacetedMesh(FacetedMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) | ||
9975 | { | ||
9976 | if (mesh != null) | ||
9977 | { | ||
9978 | // Parse each face in mesh | ||
9979 | // since vertex array isn't populated. | ||
9980 | // This parses each unique vertex 3-6 times. | ||
9981 | foreach (Face face in mesh.Faces) | ||
9982 | { | ||
9983 | // Parse each vertex in face | ||
9984 | foreach (Vertex vertex in face.Vertices) | ||
9985 | { | ||
9986 | Vector3 position = vertex.Position; | ||
9987 | position = position * prim.Scale; | ||
9988 | // Rotate part unless part is root | ||
9989 | if (hasParent) | ||
9990 | position = position * prim.Rotation; | ||
9991 | position = position + prim.Position; | ||
9992 | // Adjust lower and upper bounding box corners if needed | ||
9993 | lower = Vector3.Min(lower, position); | ||
9994 | upper = Vector3.Max(upper, position); | ||
9995 | count++; | ||
9996 | } | ||
9997 | } | ||
9998 | } | ||
9999 | } | ||
10000 | |||
10001 | /// <summary> | ||
10002 | /// Helper to make up an OpenMetaverse prim | ||
10003 | /// needed to create mesh from parts. | ||
10004 | /// </summary> | ||
10005 | private Primitive MakeOpenMetaversePrim(Vector3 scale, Vector3 position, Quaternion rotation, int primType) | ||
10006 | { | ||
10007 | // Initialize and set common parameters | ||
10008 | Primitive prim = new OpenMetaverse.Primitive(); | ||
10009 | prim.Scale = scale; | ||
10010 | prim.Position = position; | ||
10011 | prim.Rotation = rotation; | ||
10012 | prim.PrimData.PathShearX = 0.0f; | ||
10013 | prim.PrimData.PathShearY = 0.0f; | ||
10014 | prim.PrimData.PathBegin = 0.0f; | ||
10015 | prim.PrimData.PathEnd = 1.0f; | ||
10016 | prim.PrimData.PathScaleX = 1.0f; | ||
10017 | prim.PrimData.PathScaleY = 1.0f; | ||
10018 | prim.PrimData.PathTaperX = 0.0f; | ||
10019 | prim.PrimData.PathTaperY = 0.0f; | ||
10020 | prim.PrimData.PathTwistBegin = 0.0f; | ||
10021 | prim.PrimData.PathTwist = 0.0f; | ||
10022 | prim.PrimData.ProfileBegin = 0.0f; | ||
10023 | prim.PrimData.ProfileEnd = 1.0f; | ||
10024 | prim.PrimData.ProfileHollow = 0.0f; | ||
10025 | prim.PrimData.ProfileCurve = (ProfileCurve)1; | ||
10026 | prim.PrimData.ProfileHole = (HoleType)0; | ||
10027 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10028 | prim.PrimData.PathRadiusOffset = 0.0f; | ||
10029 | prim.PrimData.PathRevolutions = 1.0f; | ||
10030 | prim.PrimData.PathSkew = 0.0f; | ||
10031 | prim.PrimData.PCode = OpenMetaverse.PCode.Prim; | ||
10032 | prim.PrimData.State = (byte)0; | ||
10033 | |||
10034 | // Set type specific parameters | ||
10035 | switch (primType) | ||
10036 | { | ||
10037 | // Set specific parameters for box | ||
10038 | case ScriptBaseClass.PRIM_TYPE_BOX: | ||
10039 | prim.PrimData.PathScaleY = 1.0f; | ||
10040 | prim.PrimData.ProfileCurve = (ProfileCurve)1; | ||
10041 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10042 | break; | ||
10043 | // Set specific parameters for cylinder | ||
10044 | case ScriptBaseClass.PRIM_TYPE_CYLINDER: | ||
10045 | prim.PrimData.PathScaleY = 1.0f; | ||
10046 | prim.PrimData.ProfileCurve = (ProfileCurve)0; | ||
10047 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10048 | break; | ||
10049 | // Set specific parameters for prism | ||
10050 | case ScriptBaseClass.PRIM_TYPE_PRISM: | ||
10051 | prim.PrimData.PathScaleY = 1.0f; | ||
10052 | prim.PrimData.ProfileCurve = (ProfileCurve)3; | ||
10053 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10054 | break; | ||
10055 | // Set specific parameters for sphere | ||
10056 | case ScriptBaseClass.PRIM_TYPE_SPHERE: | ||
10057 | prim.PrimData.PathScaleY = 1.0f; | ||
10058 | prim.PrimData.ProfileCurve = (ProfileCurve)5; | ||
10059 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10060 | break; | ||
10061 | // Set specific parameters for torus | ||
10062 | case ScriptBaseClass.PRIM_TYPE_TORUS: | ||
10063 | prim.PrimData.PathScaleY = 0.5f; | ||
10064 | prim.PrimData.ProfileCurve = (ProfileCurve)0; | ||
10065 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10066 | break; | ||
10067 | // Set specific parameters for tube | ||
10068 | case ScriptBaseClass.PRIM_TYPE_TUBE: | ||
10069 | prim.PrimData.PathScaleY = 0.5f; | ||
10070 | prim.PrimData.ProfileCurve = (ProfileCurve)1; | ||
10071 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10072 | break; | ||
10073 | // Set specific parameters for ring | ||
10074 | case ScriptBaseClass.PRIM_TYPE_RING: | ||
10075 | prim.PrimData.PathScaleY = 0.5f; | ||
10076 | prim.PrimData.ProfileCurve = (ProfileCurve)3; | ||
10077 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10078 | break; | ||
10079 | // Set specific parameters for sculpt | ||
10080 | case ScriptBaseClass.PRIM_TYPE_SCULPT: | ||
10081 | prim.PrimData.PathScaleY = 1.0f; | ||
10082 | prim.PrimData.ProfileCurve = (ProfileCurve)5; | ||
10083 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10084 | break; | ||
10085 | // Default to specific parameters for box | ||
10086 | default: | ||
10087 | prim.PrimData.PathScaleY = 1.0f; | ||
10088 | prim.PrimData.ProfileCurve = (ProfileCurve)1; | ||
10089 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10090 | break; | ||
10091 | } | ||
10092 | |||
10093 | return prim; | ||
10094 | } | ||
10095 | |||
10096 | /// <summary> | ||
10097 | /// Implementation of llGetGeometricCenter according to SL 2015-04-30. | ||
10098 | /// http://wiki.secondlife.com/wiki/LlGetGeometricCenter | ||
10099 | /// Returns the average position offset of all linked parts, | ||
10100 | /// including the root prim and seated avatars, | ||
10101 | /// relative to the root prim in local coordinates. | ||
10102 | /// </summary> | ||
9658 | public LSL_Vector llGetGeometricCenter() | 10103 | public LSL_Vector llGetGeometricCenter() |
9659 | { | 10104 | { |
9660 | return new LSL_Vector(m_host.GetGeometricCenter()); | 10105 | // Subtract whatever position the root prim has to make it zero |
10106 | Vector3 offset = m_host.ParentGroup.RootPart.OffsetPosition * -1.0f; | ||
10107 | |||
10108 | // Add all prim/part position offsets | ||
10109 | foreach (SceneObjectPart part in m_host.ParentGroup.Parts) | ||
10110 | offset = offset + part.OffsetPosition; | ||
10111 | // Add all avatar/scene presence position offsets | ||
10112 | foreach (ScenePresence sp in m_host.ParentGroup.GetSittingAvatars()) | ||
10113 | offset = offset + sp.OffsetPosition; | ||
10114 | |||
10115 | // Calculate and return the average offset | ||
10116 | offset = offset / (float)(m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount()); | ||
10117 | return new LSL_Vector(offset); | ||
9661 | } | 10118 | } |
9662 | 10119 | ||
9663 | public LSL_List GetEntityParams(ISceneEntity entity, LSL_List rules) | 10120 | public LSL_List GetEntityParams(ISceneEntity entity, LSL_List rules) |
@@ -12600,6 +13057,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12600 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: | 13057 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: |
12601 | ret.Add(new LSL_Integer(0)); | 13058 | ret.Add(new LSL_Integer(0)); |
12602 | break; | 13059 | break; |
13060 | case ScriptBaseClass.OBJECT_RENDER_WEIGHT: | ||
13061 | ret.Add(new LSL_Integer(-1)); | ||
13062 | break; | ||
13063 | case ScriptBaseClass.OBJECT_HOVER_HEIGHT: | ||
13064 | ret.Add(new LSL_Float(0)); | ||
13065 | break; | ||
13066 | case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE: | ||
13067 | LSL_Float shapeType; | ||
13068 | if (av.Appearance.VisualParams[(int)AvatarAppearance.VPElement.SHAPE_MALE] != 0) | ||
13069 | shapeType = new LSL_Float(1); | ||
13070 | else | ||
13071 | shapeType = new LSL_Float(0); | ||
13072 | ret.Add(shapeType); | ||
13073 | break; | ||
13074 | case ScriptBaseClass.OBJECT_LAST_OWNER_ID: | ||
13075 | ret.Add(new LSL_Key(ScriptBaseClass.NULL_KEY)); | ||
13076 | break; | ||
12603 | default: | 13077 | default: |
12604 | // Invalid or unhandled constant. | 13078 | // Invalid or unhandled constant. |
12605 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); | 13079 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); |
@@ -12764,6 +13238,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12764 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: | 13238 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: |
12765 | ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0)); | 13239 | ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0)); |
12766 | break; | 13240 | break; |
13241 | case ScriptBaseClass.OBJECT_RENDER_WEIGHT: | ||
13242 | ret.Add(new LSL_Integer(0)); | ||
13243 | break; | ||
13244 | case ScriptBaseClass.OBJECT_HOVER_HEIGHT: | ||
13245 | ret.Add(new LSL_Float(0)); | ||
13246 | break; | ||
13247 | case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE: | ||
13248 | ret.Add(new LSL_Float(-1)); | ||
13249 | break; | ||
13250 | case ScriptBaseClass.OBJECT_LAST_OWNER_ID: | ||
13251 | ret.Add(new LSL_Key(obj.ParentGroup.LastOwnerID.ToString())); | ||
13252 | break; | ||
12767 | default: | 13253 | default: |
12768 | // Invalid or unhandled constant. | 13254 | // Invalid or unhandled constant. |
12769 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); | 13255 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); |
@@ -13335,6 +13821,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
13335 | 13821 | ||
13336 | public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) | 13822 | public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) |
13337 | { | 13823 | { |
13824 | // Use llCastRay V3 if configured | ||
13825 | if (m_useCastRayV3) | ||
13826 | return llCastRayV3(start, end, options); | ||
13827 | |||
13338 | LSL_List list = new LSL_List(); | 13828 | LSL_List list = new LSL_List(); |
13339 | 13829 | ||
13340 | m_host.AddScriptLPS(1); | 13830 | m_host.AddScriptLPS(1); |
@@ -13524,6 +14014,732 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
13524 | return list; | 14014 | return list; |
13525 | } | 14015 | } |
13526 | 14016 | ||
14017 | /// <summary> | ||
14018 | /// Implementation of llCastRay similar to SL 2015-04-21. | ||
14019 | /// http://wiki.secondlife.com/wiki/LlCastRay | ||
14020 | /// Uses pure geometry, bounding shapes, meshing and no physics | ||
14021 | /// for prims, sculpts, meshes, avatars and terrain. | ||
14022 | /// Implements all flags, reject types and data flags. | ||
14023 | /// Can handle both objects/groups and prims/parts, by config. | ||
14024 | /// May sometimes be inaccurate owing to calculation precision, | ||
14025 | /// meshing detail level and a bug in libopenmetaverse PrimMesher. | ||
14026 | /// </summary> | ||
14027 | public LSL_List llCastRayV3(LSL_Vector start, LSL_Vector end, LSL_List options) | ||
14028 | { | ||
14029 | // Initialize | ||
14030 | m_host.AddScriptLPS(1); | ||
14031 | List<RayHit> rayHits = new List<RayHit>(); | ||
14032 | LSL_List result = new LSL_List(); | ||
14033 | float tol = m_floatToleranceInCastRay; | ||
14034 | Vector3 pos1Ray = start; | ||
14035 | Vector3 pos2Ray = end; | ||
14036 | |||
14037 | // Get input options | ||
14038 | int rejectTypes = 0; | ||
14039 | int dataFlags = 0; | ||
14040 | int maxHits = 1; | ||
14041 | bool detectPhantom = false; | ||
14042 | for (int i = 0; i < options.Length; i += 2) | ||
14043 | { | ||
14044 | if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) | ||
14045 | rejectTypes = options.GetLSLIntegerItem(i + 1); | ||
14046 | else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) | ||
14047 | dataFlags = options.GetLSLIntegerItem(i + 1); | ||
14048 | else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) | ||
14049 | maxHits = options.GetLSLIntegerItem(i + 1); | ||
14050 | else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) | ||
14051 | detectPhantom = (options.GetLSLIntegerItem(i + 1) != 0); | ||
14052 | } | ||
14053 | if (maxHits > m_maxHitsInCastRay) | ||
14054 | maxHits = m_maxHitsInCastRay; | ||
14055 | bool rejectAgents = ((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != 0); | ||
14056 | bool rejectPhysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) != 0); | ||
14057 | bool rejectNonphysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) != 0); | ||
14058 | bool rejectLand = ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) != 0); | ||
14059 | bool getNormal = ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) != 0); | ||
14060 | bool getRootKey = ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) != 0); | ||
14061 | bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0); | ||
14062 | |||
14063 | // Calculate some basic parameters | ||
14064 | Vector3 vecRay = pos2Ray - pos1Ray; | ||
14065 | float rayLength = vecRay.Length(); | ||
14066 | |||
14067 | // Try to get a mesher and return failure if none, degenerate ray, or max 0 hits | ||
14068 | IRendering primMesher = null; | ||
14069 | List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); | ||
14070 | if (renderers.Count < 1 || rayLength < tol || m_maxHitsInCastRay < 1) | ||
14071 | { | ||
14072 | result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); | ||
14073 | return result; | ||
14074 | } | ||
14075 | primMesher = RenderingLoader.LoadRenderer(renderers[0]); | ||
14076 | |||
14077 | // Iterate over all objects/groups and prims/parts in region | ||
14078 | World.ForEachSOG( | ||
14079 | delegate(SceneObjectGroup group) | ||
14080 | { | ||
14081 | // Check group filters unless part filters are configured | ||
14082 | bool isPhysical = (group.RootPart != null && group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical); | ||
14083 | bool isNonphysical = !isPhysical; | ||
14084 | bool isPhantom = group.IsPhantom || group.IsVolumeDetect; | ||
14085 | bool isAttachment = group.IsAttachment; | ||
14086 | bool doGroup = true; | ||
14087 | if (isPhysical && rejectPhysical) | ||
14088 | doGroup = false; | ||
14089 | if (isNonphysical && rejectNonphysical) | ||
14090 | doGroup = false; | ||
14091 | if (isPhantom && detectPhantom) | ||
14092 | doGroup = true; | ||
14093 | if (m_filterPartsInCastRay) | ||
14094 | doGroup = true; | ||
14095 | if (isAttachment && !m_doAttachmentsInCastRay) | ||
14096 | doGroup = false; | ||
14097 | // Parse object/group if passed filters | ||
14098 | if (doGroup) | ||
14099 | { | ||
14100 | // Iterate over all prims/parts in object/group | ||
14101 | foreach(SceneObjectPart part in group.Parts) | ||
14102 | { | ||
14103 | // Check part filters if configured | ||
14104 | if (m_filterPartsInCastRay) | ||
14105 | { | ||
14106 | isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); | ||
14107 | isNonphysical = !isPhysical; | ||
14108 | isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || (part.VolumeDetectActive); | ||
14109 | bool doPart = true; | ||
14110 | if (isPhysical && rejectPhysical) | ||
14111 | doPart = false; | ||
14112 | if (isNonphysical && rejectNonphysical) | ||
14113 | doPart = false; | ||
14114 | if (isPhantom && detectPhantom) | ||
14115 | doPart = true; | ||
14116 | if (!doPart) | ||
14117 | continue; | ||
14118 | } | ||
14119 | |||
14120 | // Parse prim/part and project ray if passed filters | ||
14121 | Vector3 scalePart = part.Scale; | ||
14122 | Vector3 posPart = part.GetWorldPosition(); | ||
14123 | Quaternion rotPart = part.GetWorldRotation(); | ||
14124 | Quaternion rotPartInv = Quaternion.Inverse(rotPart); | ||
14125 | Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; | ||
14126 | Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; | ||
14127 | |||
14128 | // Filter parts by shape bounding boxes | ||
14129 | Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f); | ||
14130 | if (!part.Shape.SculptEntry) | ||
14131 | shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); | ||
14132 | shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol)); | ||
14133 | if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) | ||
14134 | { | ||
14135 | // Prepare data needed to check for ray hits | ||
14136 | RayTrans rayTrans = new RayTrans(); | ||
14137 | rayTrans.PartId = part.UUID; | ||
14138 | rayTrans.GroupId = part.ParentGroup.UUID; | ||
14139 | rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; | ||
14140 | rayTrans.ScalePart = scalePart; | ||
14141 | rayTrans.PositionPart = posPart; | ||
14142 | rayTrans.RotationPart = rotPart; | ||
14143 | rayTrans.ShapeNeedsEnds = true; | ||
14144 | rayTrans.Position1Ray = pos1Ray; | ||
14145 | rayTrans.Position1RayProj = pos1RayProj; | ||
14146 | rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; | ||
14147 | |||
14148 | // Make an OMV prim to be able to mesh part | ||
14149 | Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart); | ||
14150 | byte[] sculptAsset = null; | ||
14151 | if (omvPrim.Sculpt != null) | ||
14152 | sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); | ||
14153 | FacetedMesh mesh = null; | ||
14154 | |||
14155 | // When part is mesh, get mesh and check for hits | ||
14156 | if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) | ||
14157 | { | ||
14158 | AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); | ||
14159 | FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh); | ||
14160 | meshAsset = null; | ||
14161 | } | ||
14162 | |||
14163 | // When part is sculpt, create mesh and check for hits | ||
14164 | // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. | ||
14165 | else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) | ||
14166 | { | ||
14167 | IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>(); | ||
14168 | if (imgDecoder != null) | ||
14169 | { | ||
14170 | Image sculpt = imgDecoder.DecodeToImage(sculptAsset); | ||
14171 | if (sculpt != null) | ||
14172 | { | ||
14173 | mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay); | ||
14174 | sculpt.Dispose(); | ||
14175 | } | ||
14176 | } | ||
14177 | } | ||
14178 | |||
14179 | // When part is prim, create mesh and check for hits | ||
14180 | else if (omvPrim.Sculpt == null) | ||
14181 | { | ||
14182 | if ( | ||
14183 | omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && | ||
14184 | omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && | ||
14185 | omvPrim.PrimData.PathSkew == 0.0 && | ||
14186 | omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 | ||
14187 | ) | ||
14188 | rayTrans.ShapeNeedsEnds = false; | ||
14189 | mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay); | ||
14190 | } | ||
14191 | |||
14192 | // Check mesh for ray hits | ||
14193 | AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); | ||
14194 | mesh = null; | ||
14195 | } | ||
14196 | } | ||
14197 | } | ||
14198 | } | ||
14199 | ); | ||
14200 | |||
14201 | // Check avatar filter | ||
14202 | if (!rejectAgents) | ||
14203 | { | ||
14204 | // Iterate over all avatars in region | ||
14205 | World.ForEachRootScenePresence( | ||
14206 | delegate (ScenePresence sp) | ||
14207 | { | ||
14208 | // Get bounding box | ||
14209 | Vector3 lower; | ||
14210 | Vector3 upper; | ||
14211 | BoundingBoxOfScenePresence(sp, out lower, out upper); | ||
14212 | // Parse avatar | ||
14213 | Vector3 scalePart = upper - lower; | ||
14214 | Vector3 posPart = sp.AbsolutePosition; | ||
14215 | Quaternion rotPart = sp.GetWorldRotation(); | ||
14216 | Quaternion rotPartInv = Quaternion.Inverse(rotPart); | ||
14217 | posPart = posPart + (lower + upper) * 0.5f * rotPart; | ||
14218 | // Project ray | ||
14219 | Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; | ||
14220 | Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; | ||
14221 | |||
14222 | // Filter avatars by shape bounding boxes | ||
14223 | Vector3 shapeBoxMax = new Vector3(0.5f + tol, 0.5f + tol, 0.5f + tol); | ||
14224 | if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) | ||
14225 | { | ||
14226 | // Prepare data needed to check for ray hits | ||
14227 | RayTrans rayTrans = new RayTrans(); | ||
14228 | rayTrans.PartId = sp.UUID; | ||
14229 | rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID; | ||
14230 | rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0; | ||
14231 | rayTrans.ScalePart = scalePart; | ||
14232 | rayTrans.PositionPart = posPart; | ||
14233 | rayTrans.RotationPart = rotPart; | ||
14234 | rayTrans.ShapeNeedsEnds = false; | ||
14235 | rayTrans.Position1Ray = pos1Ray; | ||
14236 | rayTrans.Position1RayProj = pos1RayProj; | ||
14237 | rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; | ||
14238 | |||
14239 | // Make OMV prim, create and check mesh | ||
14240 | PrimitiveBaseShape prim = PrimitiveBaseShape.CreateSphere(); | ||
14241 | prim.Scale = scalePart; | ||
14242 | Primitive omvPrim = prim.ToOmvPrimitive(posPart, rotPart); | ||
14243 | FacetedMesh mesh = primMesher.GenerateFacetedMesh(omvPrim, m_meshLodInCastRay); | ||
14244 | AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); | ||
14245 | mesh = null; | ||
14246 | } | ||
14247 | } | ||
14248 | ); | ||
14249 | } | ||
14250 | |||
14251 | // Check terrain filter | ||
14252 | if (!rejectLand) | ||
14253 | { | ||
14254 | // Parse terrain | ||
14255 | |||
14256 | // Mesh terrain and check bounding box | ||
14257 | Vector3 lower; | ||
14258 | Vector3 upper; | ||
14259 | List<Tri> triangles = TrisFromHeightmapUnderRay(pos1Ray, pos2Ray, out lower, out upper); | ||
14260 | lower.Z -= tol; | ||
14261 | upper.Z += tol; | ||
14262 | if ((pos1Ray.Z >= lower.Z || pos2Ray.Z >= lower.Z) && (pos1Ray.Z <= upper.Z || pos2Ray.Z <= upper.Z)) | ||
14263 | { | ||
14264 | // Prepare data needed to check for ray hits | ||
14265 | RayTrans rayTrans = new RayTrans(); | ||
14266 | rayTrans.PartId = UUID.Zero; | ||
14267 | rayTrans.GroupId = UUID.Zero; | ||
14268 | rayTrans.Link = 0; | ||
14269 | rayTrans.ScalePart = new Vector3 (1.0f, 1.0f, 1.0f); | ||
14270 | rayTrans.PositionPart = Vector3.Zero; | ||
14271 | rayTrans.RotationPart = Quaternion.Identity; | ||
14272 | rayTrans.ShapeNeedsEnds = true; | ||
14273 | rayTrans.Position1Ray = pos1Ray; | ||
14274 | rayTrans.Position1RayProj = pos1Ray; | ||
14275 | rayTrans.VectorRayProj = vecRay; | ||
14276 | |||
14277 | // Check mesh | ||
14278 | AddRayInTris(triangles, rayTrans, ref rayHits); | ||
14279 | triangles = null; | ||
14280 | } | ||
14281 | } | ||
14282 | |||
14283 | // Sort hits by ascending distance | ||
14284 | rayHits.Sort((s1, s2) => s1.Distance.CompareTo(s2.Distance)); | ||
14285 | |||
14286 | // Check excess hits per part and group | ||
14287 | for (int t = 0; t < 2; t++) | ||
14288 | { | ||
14289 | int maxHitsPerType = 0; | ||
14290 | UUID id = UUID.Zero; | ||
14291 | if (t == 0) | ||
14292 | maxHitsPerType = m_maxHitsPerPrimInCastRay; | ||
14293 | else | ||
14294 | maxHitsPerType = m_maxHitsPerObjectInCastRay; | ||
14295 | |||
14296 | // Handle excess hits only when needed | ||
14297 | if (maxHitsPerType < m_maxHitsInCastRay) | ||
14298 | { | ||
14299 | // Find excess hits | ||
14300 | Hashtable hits = new Hashtable(); | ||
14301 | for (int i = rayHits.Count - 1; i >= 0; i--) | ||
14302 | { | ||
14303 | if (t == 0) | ||
14304 | id = rayHits[i].PartId; | ||
14305 | else | ||
14306 | id = rayHits[i].GroupId; | ||
14307 | if (hits.ContainsKey(id)) | ||
14308 | hits[id] = (int)hits[id] + 1; | ||
14309 | else | ||
14310 | hits[id] = 1; | ||
14311 | } | ||
14312 | |||
14313 | // Remove excess hits | ||
14314 | for (int i = rayHits.Count - 1; i >= 0; i--) | ||
14315 | { | ||
14316 | if (t == 0) | ||
14317 | id = rayHits[i].PartId; | ||
14318 | else | ||
14319 | id = rayHits[i].GroupId; | ||
14320 | int hit = (int)hits[id]; | ||
14321 | if (hit > m_maxHitsPerPrimInCastRay) | ||
14322 | { | ||
14323 | rayHits.RemoveAt(i); | ||
14324 | hit--; | ||
14325 | hits[id] = hit; | ||
14326 | } | ||
14327 | } | ||
14328 | } | ||
14329 | } | ||
14330 | |||
14331 | // Parse hits into result list according to data flags | ||
14332 | int hitCount = rayHits.Count; | ||
14333 | if (hitCount > maxHits) | ||
14334 | hitCount = maxHits; | ||
14335 | for (int i = 0; i < hitCount; i++) | ||
14336 | { | ||
14337 | RayHit rayHit = rayHits[i]; | ||
14338 | if (getRootKey) | ||
14339 | result.Add(new LSL_Key(rayHit.GroupId.ToString())); | ||
14340 | else | ||
14341 | result.Add(new LSL_Key(rayHit.PartId.ToString())); | ||
14342 | result.Add(new LSL_Vector(rayHit.Position)); | ||
14343 | if (getLinkNum) | ||
14344 | result.Add(new LSL_Integer(rayHit.Link)); | ||
14345 | if (getNormal) | ||
14346 | result.Add(new LSL_Vector(rayHit.Normal)); | ||
14347 | } | ||
14348 | result.Add(new LSL_Integer(hitCount)); | ||
14349 | return result; | ||
14350 | } | ||
14351 | |||
14352 | /// <summary> | ||
14353 | /// Struct for transmitting parameters required for finding llCastRay ray hits. | ||
14354 | /// </summary> | ||
14355 | public struct RayTrans | ||
14356 | { | ||
14357 | public UUID PartId; | ||
14358 | public UUID GroupId; | ||
14359 | public int Link; | ||
14360 | public Vector3 ScalePart; | ||
14361 | public Vector3 PositionPart; | ||
14362 | public Quaternion RotationPart; | ||
14363 | public bool ShapeNeedsEnds; | ||
14364 | public Vector3 Position1Ray; | ||
14365 | public Vector3 Position1RayProj; | ||
14366 | public Vector3 VectorRayProj; | ||
14367 | } | ||
14368 | |||
14369 | /// <summary> | ||
14370 | /// Struct for llCastRay ray hits. | ||
14371 | /// </summary> | ||
14372 | public struct RayHit | ||
14373 | { | ||
14374 | public UUID PartId; | ||
14375 | public UUID GroupId; | ||
14376 | public int Link; | ||
14377 | public Vector3 Position; | ||
14378 | public Vector3 Normal; | ||
14379 | public float Distance; | ||
14380 | } | ||
14381 | |||
14382 | /// <summary> | ||
14383 | /// Helper to check if a ray intersects a shape bounding box. | ||
14384 | /// </summary> | ||
14385 | private bool RayIntersectsShapeBox(Vector3 pos1RayProj, Vector3 pos2RayProj, Vector3 shapeBoxMax) | ||
14386 | { | ||
14387 | // Skip if ray can't intersect bounding box; | ||
14388 | Vector3 rayBoxProjMin = Vector3.Min(pos1RayProj, pos2RayProj); | ||
14389 | Vector3 rayBoxProjMax = Vector3.Max(pos1RayProj, pos2RayProj); | ||
14390 | if ( | ||
14391 | rayBoxProjMin.X > shapeBoxMax.X || rayBoxProjMin.Y > shapeBoxMax.Y || rayBoxProjMin.Z > shapeBoxMax.Z || | ||
14392 | rayBoxProjMax.X < -shapeBoxMax.X || rayBoxProjMax.Y < -shapeBoxMax.Y || rayBoxProjMax.Z < -shapeBoxMax.Z | ||
14393 | ) | ||
14394 | return false; | ||
14395 | |||
14396 | // Check if ray intersect any bounding box side | ||
14397 | int sign = 0; | ||
14398 | float dist = 0.0f; | ||
14399 | Vector3 posProj = Vector3.Zero; | ||
14400 | Vector3 vecRayProj = pos2RayProj - pos1RayProj; | ||
14401 | |||
14402 | // Check both X sides unless ray is parallell to them | ||
14403 | if (Math.Abs(vecRayProj.X) > m_floatToleranceInCastRay) | ||
14404 | { | ||
14405 | for (sign = -1; sign <= 1; sign += 2) | ||
14406 | { | ||
14407 | dist = ((float)sign * shapeBoxMax.X - pos1RayProj.X) / vecRayProj.X; | ||
14408 | posProj = pos1RayProj + vecRayProj * dist; | ||
14409 | if (Math.Abs(posProj.Y) <= shapeBoxMax.Y && Math.Abs(posProj.Z) <= shapeBoxMax.Z) | ||
14410 | return true; | ||
14411 | } | ||
14412 | } | ||
14413 | |||
14414 | // Check both Y sides unless ray is parallell to them | ||
14415 | if (Math.Abs(vecRayProj.Y) > m_floatToleranceInCastRay) | ||
14416 | { | ||
14417 | for (sign = -1; sign <= 1; sign += 2) | ||
14418 | { | ||
14419 | dist = ((float)sign * shapeBoxMax.Y - pos1RayProj.Y) / vecRayProj.Y; | ||
14420 | posProj = pos1RayProj + vecRayProj * dist; | ||
14421 | if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Z) <= shapeBoxMax.Z) | ||
14422 | return true; | ||
14423 | } | ||
14424 | } | ||
14425 | |||
14426 | // Check both Z sides unless ray is parallell to them | ||
14427 | if (Math.Abs(vecRayProj.Z) > m_floatToleranceInCastRay) | ||
14428 | { | ||
14429 | for (sign = -1; sign <= 1; sign += 2) | ||
14430 | { | ||
14431 | dist = ((float)sign * shapeBoxMax.Z - pos1RayProj.Z) / vecRayProj.Z; | ||
14432 | posProj = pos1RayProj + vecRayProj * dist; | ||
14433 | if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Y) <= shapeBoxMax.Y) | ||
14434 | return true; | ||
14435 | } | ||
14436 | } | ||
14437 | |||
14438 | // No hits on bounding box so return false | ||
14439 | return false; | ||
14440 | } | ||
14441 | |||
14442 | /// <summary> | ||
14443 | /// Helper to parse FacetedMesh for ray hits. | ||
14444 | /// </summary> | ||
14445 | private void AddRayInFacetedMesh(FacetedMesh mesh, RayTrans rayTrans, ref List<RayHit> rayHits) | ||
14446 | { | ||
14447 | if (mesh != null) | ||
14448 | { | ||
14449 | foreach (Face face in mesh.Faces) | ||
14450 | { | ||
14451 | for (int i = 0; i < face.Indices.Count; i += 3) | ||
14452 | { | ||
14453 | Tri triangle = new Tri(); | ||
14454 | triangle.p1 = face.Vertices[face.Indices[i]].Position; | ||
14455 | triangle.p2 = face.Vertices[face.Indices[i + 1]].Position; | ||
14456 | triangle.p3 = face.Vertices[face.Indices[i + 2]].Position; | ||
14457 | AddRayInTri(triangle, rayTrans, ref rayHits); | ||
14458 | } | ||
14459 | } | ||
14460 | } | ||
14461 | } | ||
14462 | |||
14463 | /// <summary> | ||
14464 | /// Helper to parse Tri (triangle) List for ray hits. | ||
14465 | /// </summary> | ||
14466 | private void AddRayInTris(List<Tri> triangles, RayTrans rayTrans, ref List<RayHit> rayHits) | ||
14467 | { | ||
14468 | foreach (Tri triangle in triangles) | ||
14469 | { | ||
14470 | AddRayInTri(triangle, rayTrans, ref rayHits); | ||
14471 | } | ||
14472 | } | ||
14473 | |||
14474 | /// <summary> | ||
14475 | /// Helper to add ray hit in a Tri (triangle). | ||
14476 | /// </summary> | ||
14477 | private void AddRayInTri(Tri triProj, RayTrans rayTrans, ref List<RayHit> rayHits) | ||
14478 | { | ||
14479 | // Check for hit in triangle | ||
14480 | Vector3 posHitProj; | ||
14481 | Vector3 normalProj; | ||
14482 | if (HitRayInTri(triProj, rayTrans.Position1RayProj, rayTrans.VectorRayProj, out posHitProj, out normalProj)) | ||
14483 | { | ||
14484 | // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) face plane through shape center | ||
14485 | if (Math.Abs(Vector3.Dot(posHitProj, normalProj)) < m_floatToleranceInCastRay && !rayTrans.ShapeNeedsEnds) | ||
14486 | return; | ||
14487 | |||
14488 | // Transform hit and normal to region coordinate system | ||
14489 | Vector3 posHit = rayTrans.PositionPart + (posHitProj * rayTrans.ScalePart) * rayTrans.RotationPart; | ||
14490 | Vector3 normal = Vector3.Normalize((normalProj * rayTrans.ScalePart) * rayTrans.RotationPart); | ||
14491 | |||
14492 | // Remove duplicate hits at triangle intersections | ||
14493 | float distance = Vector3.Distance(rayTrans.Position1Ray, posHit); | ||
14494 | for (int i = rayHits.Count - 1; i >= 0; i--) | ||
14495 | { | ||
14496 | if (rayHits[i].PartId != rayTrans.PartId) | ||
14497 | break; | ||
14498 | if (Math.Abs(rayHits[i].Distance - distance) < m_floatTolerance2InCastRay) | ||
14499 | return; | ||
14500 | } | ||
14501 | |||
14502 | // Build result data set | ||
14503 | RayHit rayHit = new RayHit(); | ||
14504 | rayHit.PartId = rayTrans.PartId; | ||
14505 | rayHit.GroupId = rayTrans.GroupId; | ||
14506 | rayHit.Link = rayTrans.Link; | ||
14507 | rayHit.Position = posHit; | ||
14508 | rayHit.Normal = normal; | ||
14509 | rayHit.Distance = distance; | ||
14510 | rayHits.Add(rayHit); | ||
14511 | } | ||
14512 | } | ||
14513 | |||
14514 | /// <summary> | ||
14515 | /// Helper to find ray hit in triangle | ||
14516 | /// </summary> | ||
14517 | bool HitRayInTri(Tri triProj, Vector3 pos1RayProj, Vector3 vecRayProj, out Vector3 posHitProj, out Vector3 normalProj) | ||
14518 | { | ||
14519 | float tol = m_floatToleranceInCastRay; | ||
14520 | posHitProj = Vector3.Zero; | ||
14521 | |||
14522 | // Calculate triangle edge vectors | ||
14523 | Vector3 vec1Proj = triProj.p2 - triProj.p1; | ||
14524 | Vector3 vec2Proj = triProj.p3 - triProj.p2; | ||
14525 | Vector3 vec3Proj = triProj.p1 - triProj.p3; | ||
14526 | |||
14527 | // Calculate triangle normal | ||
14528 | normalProj = Vector3.Cross(vec1Proj, vec2Proj); | ||
14529 | |||
14530 | // Skip if degenerate triangle or ray parallell with triangle plane | ||
14531 | float divisor = Vector3.Dot(vecRayProj, normalProj); | ||
14532 | if (Math.Abs(divisor) < tol) | ||
14533 | return false; | ||
14534 | |||
14535 | // Skip if exit and not configured to detect | ||
14536 | if (divisor > tol && !m_detectExitsInCastRay) | ||
14537 | return false; | ||
14538 | |||
14539 | // Skip if outside ray ends | ||
14540 | float distanceProj = Vector3.Dot(triProj.p1 - pos1RayProj, normalProj) / divisor; | ||
14541 | if (distanceProj < -tol || distanceProj > 1 + tol) | ||
14542 | return false; | ||
14543 | |||
14544 | // Calculate hit position in triangle | ||
14545 | posHitProj = pos1RayProj + vecRayProj * distanceProj; | ||
14546 | |||
14547 | // Skip if outside triangle bounding box | ||
14548 | Vector3 triProjMin = Vector3.Min(Vector3.Min(triProj.p1, triProj.p2), triProj.p3); | ||
14549 | Vector3 triProjMax = Vector3.Max(Vector3.Max(triProj.p1, triProj.p2), triProj.p3); | ||
14550 | if ( | ||
14551 | posHitProj.X < triProjMin.X - tol || posHitProj.Y < triProjMin.Y - tol || posHitProj.Z < triProjMin.Z - tol || | ||
14552 | posHitProj.X > triProjMax.X + tol || posHitProj.Y > triProjMax.Y + tol || posHitProj.Z > triProjMax.Z + tol | ||
14553 | ) | ||
14554 | return false; | ||
14555 | |||
14556 | // Skip if outside triangle | ||
14557 | if ( | ||
14558 | Vector3.Dot(Vector3.Cross(vec1Proj, normalProj), posHitProj - triProj.p1) > tol || | ||
14559 | Vector3.Dot(Vector3.Cross(vec2Proj, normalProj), posHitProj - triProj.p2) > tol || | ||
14560 | Vector3.Dot(Vector3.Cross(vec3Proj, normalProj), posHitProj - triProj.p3) > tol | ||
14561 | ) | ||
14562 | return false; | ||
14563 | |||
14564 | // Return hit | ||
14565 | return true; | ||
14566 | } | ||
14567 | |||
14568 | /// <summary> | ||
14569 | /// Helper to parse selected parts of HeightMap into a Tri (triangle) List and calculate bounding box. | ||
14570 | /// </summary> | ||
14571 | private List<Tri> TrisFromHeightmapUnderRay(Vector3 posStart, Vector3 posEnd, out Vector3 lower, out Vector3 upper) | ||
14572 | { | ||
14573 | // Get bounding X-Y rectangle of terrain under ray | ||
14574 | lower = Vector3.Min(posStart, posEnd); | ||
14575 | upper = Vector3.Max(posStart, posEnd); | ||
14576 | lower.X = (float)Math.Floor(lower.X); | ||
14577 | lower.Y = (float)Math.Floor(lower.Y); | ||
14578 | float zLower = float.MaxValue; | ||
14579 | upper.X = (float)Math.Ceiling(upper.X); | ||
14580 | upper.Y = (float)Math.Ceiling(upper.Y); | ||
14581 | float zUpper = float.MinValue; | ||
14582 | |||
14583 | // Initialize Tri (triangle) List | ||
14584 | List<Tri> triangles = new List<Tri>(); | ||
14585 | |||
14586 | // Set parsing lane direction to major ray X-Y axis | ||
14587 | Vector3 vec = posEnd - posStart; | ||
14588 | float xAbs = Math.Abs(vec.X); | ||
14589 | float yAbs = Math.Abs(vec.Y); | ||
14590 | bool bigX = true; | ||
14591 | if (yAbs > xAbs) | ||
14592 | { | ||
14593 | bigX = false; | ||
14594 | vec = vec / yAbs; | ||
14595 | } | ||
14596 | else if (xAbs > yAbs || xAbs > 0.0f) | ||
14597 | vec = vec / xAbs; | ||
14598 | else | ||
14599 | vec = new Vector3(1.0f, 1.0f, 0.0f); | ||
14600 | |||
14601 | // Simplify by start parsing in lower end of lane | ||
14602 | if ((bigX && vec.X < 0.0f) || (!bigX && vec.Y < 0.0f)) | ||
14603 | { | ||
14604 | Vector3 posTemp = posStart; | ||
14605 | posStart = posEnd; | ||
14606 | posEnd = posTemp; | ||
14607 | vec = vec * -1.0f; | ||
14608 | } | ||
14609 | |||
14610 | // First 1x1 rectangle under ray | ||
14611 | float xFloorOld = 0.0f; | ||
14612 | float yFloorOld = 0.0f; | ||
14613 | Vector3 pos = posStart; | ||
14614 | float xFloor = (float)Math.Floor(pos.X); | ||
14615 | float yFloor = (float)Math.Floor(pos.Y); | ||
14616 | AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); | ||
14617 | |||
14618 | // Parse every remaining 1x1 rectangle under ray | ||
14619 | while (pos != posEnd) | ||
14620 | { | ||
14621 | // Next 1x1 rectangle under ray | ||
14622 | xFloorOld = xFloor; | ||
14623 | yFloorOld = yFloor; | ||
14624 | pos = pos + vec; | ||
14625 | |||
14626 | // Clip position to 1x1 rectangle border | ||
14627 | xFloor = (float)Math.Floor(pos.X); | ||
14628 | yFloor = (float)Math.Floor(pos.Y); | ||
14629 | if (bigX && pos.X > xFloor) | ||
14630 | { | ||
14631 | pos.Y -= vec.Y * (pos.X - xFloor); | ||
14632 | pos.X = xFloor; | ||
14633 | } | ||
14634 | else if (!bigX && pos.Y > yFloor) | ||
14635 | { | ||
14636 | pos.X -= vec.X * (pos.Y - yFloor); | ||
14637 | pos.Y = yFloor; | ||
14638 | } | ||
14639 | |||
14640 | // Last 1x1 rectangle under ray | ||
14641 | if ((bigX && pos.X >= posEnd.X) || (!bigX && pos.Y >= posEnd.Y)) | ||
14642 | { | ||
14643 | pos = posEnd; | ||
14644 | xFloor = (float)Math.Floor(pos.X); | ||
14645 | yFloor = (float)Math.Floor(pos.Y); | ||
14646 | } | ||
14647 | |||
14648 | // Add new 1x1 rectangle in lane | ||
14649 | if ((bigX && xFloor != xFloorOld) || (!bigX && yFloor != yFloorOld)) | ||
14650 | AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); | ||
14651 | // Add last 1x1 rectangle in old lane at lane shift | ||
14652 | if (bigX && yFloor != yFloorOld) | ||
14653 | AddTrisFromHeightmap(xFloor, yFloorOld, ref triangles, ref zLower, ref zUpper); | ||
14654 | if (!bigX && xFloor != xFloorOld) | ||
14655 | AddTrisFromHeightmap(xFloorOld, yFloor, ref triangles, ref zLower, ref zUpper); | ||
14656 | } | ||
14657 | |||
14658 | // Finalize bounding box Z | ||
14659 | lower.Z = zLower; | ||
14660 | upper.Z = zUpper; | ||
14661 | |||
14662 | // Done and returning Tri (triangle)List | ||
14663 | return triangles; | ||
14664 | } | ||
14665 | |||
14666 | /// <summary> | ||
14667 | /// Helper to add HeightMap squares into Tri (triangle) List and adjust bounding box. | ||
14668 | /// </summary> | ||
14669 | private void AddTrisFromHeightmap(float xPos, float yPos, ref List<Tri> triangles, ref float zLower, ref float zUpper) | ||
14670 | { | ||
14671 | int xInt = (int)xPos; | ||
14672 | int yInt = (int)yPos; | ||
14673 | |||
14674 | // Corner 1 of 1x1 rectangle | ||
14675 | int x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1); | ||
14676 | int y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1); | ||
14677 | Vector3 pos1 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||
14678 | // Adjust bounding box | ||
14679 | zLower = Math.Min(zLower, pos1.Z); | ||
14680 | zUpper = Math.Max(zUpper, pos1.Z); | ||
14681 | |||
14682 | // Corner 2 of 1x1 rectangle | ||
14683 | x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1); | ||
14684 | y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1); | ||
14685 | Vector3 pos2 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||
14686 | // Adjust bounding box | ||
14687 | zLower = Math.Min(zLower, pos2.Z); | ||
14688 | zUpper = Math.Max(zUpper, pos2.Z); | ||
14689 | |||
14690 | // Corner 3 of 1x1 rectangle | ||
14691 | x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1); | ||
14692 | y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); | ||
14693 | Vector3 pos3 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||
14694 | // Adjust bounding box | ||
14695 | zLower = Math.Min(zLower, pos3.Z); | ||
14696 | zUpper = Math.Max(zUpper, pos3.Z); | ||
14697 | |||
14698 | // Corner 4 of 1x1 rectangle | ||
14699 | x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1); | ||
14700 | y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); | ||
14701 | Vector3 pos4 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||
14702 | // Adjust bounding box | ||
14703 | zLower = Math.Min(zLower, pos4.Z); | ||
14704 | zUpper = Math.Max(zUpper, pos4.Z); | ||
14705 | |||
14706 | // Add triangle 1 | ||
14707 | Tri triangle1 = new Tri(); | ||
14708 | triangle1.p1 = pos1; | ||
14709 | triangle1.p2 = pos2; | ||
14710 | triangle1.p3 = pos3; | ||
14711 | triangles.Add(triangle1); | ||
14712 | |||
14713 | // Add triangle 2 | ||
14714 | Tri triangle2 = new Tri(); | ||
14715 | triangle2.p1 = pos3; | ||
14716 | triangle2.p2 = pos4; | ||
14717 | triangle2.p3 = pos1; | ||
14718 | triangles.Add(triangle2); | ||
14719 | } | ||
14720 | |||
14721 | /// <summary> | ||
14722 | /// Helper to get link number for a UUID. | ||
14723 | /// </summary> | ||
14724 | private int UUID2LinkNumber(SceneObjectPart part, UUID id) | ||
14725 | { | ||
14726 | SceneObjectGroup group = part.ParentGroup; | ||
14727 | if (group != null) | ||
14728 | { | ||
14729 | // Parse every link for UUID | ||
14730 | int linkCount = group.PrimCount + group.GetSittingAvatarsCount(); | ||
14731 | for (int link = linkCount; link > 0; link--) | ||
14732 | { | ||
14733 | ISceneEntity entity = GetLinkEntity(part, link); | ||
14734 | // Return link number if UUID match | ||
14735 | if (entity != null && entity.UUID == id) | ||
14736 | return link; | ||
14737 | } | ||
14738 | } | ||
14739 | // Return link number 0 if no links or UUID matches | ||
14740 | return 0; | ||
14741 | } | ||
14742 | |||
13527 | public LSL_Integer llManageEstateAccess(int action, string avatar) | 14743 | public LSL_Integer llManageEstateAccess(int action, string avatar) |
13528 | { | 14744 | { |
13529 | m_host.AddScriptLPS(1); | 14745 | m_host.AddScriptLPS(1); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs index d02c91c..4708473 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index a96cd16..e37d3af 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs | |||
@@ -596,6 +596,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
596 | public const int OBJECT_PHYSICS = 21; | 596 | public const int OBJECT_PHYSICS = 21; |
597 | public const int OBJECT_PHANTOM = 22; | 597 | public const int OBJECT_PHANTOM = 22; |
598 | public const int OBJECT_TEMP_ON_REZ = 23; | 598 | public const int OBJECT_TEMP_ON_REZ = 23; |
599 | public const int OBJECT_RENDER_WEIGHT = 24; | ||
600 | public const int OBJECT_HOVER_HEIGHT = 25; | ||
601 | public const int OBJECT_BODY_SHAPE_TYPE = 26; | ||
602 | public const int OBJECT_LAST_OWNER_ID = 27; | ||
599 | 603 | ||
600 | // Pathfinding types | 604 | // Pathfinding types |
601 | public const int OPT_OTHER = -1; | 605 | public const int OPT_OTHER = -1; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs index 31acd44..4df09ef 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs index af7ee26..3eaaed0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||