aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine
diff options
context:
space:
mode:
authorMichael Heilmann2015-05-19 15:18:45 -0400
committerMichael Heilmann2015-05-19 15:18:45 -0400
commit140ea04b9d692344d803fc87364fb252561725c3 (patch)
treed503b7ae17baca374d704b548fc7da512f512388 /OpenSim/Region/ScriptEngine
parentMerge pull request #7 from gamucf/moses.metricsPhase2 (diff)
parentresolve possible nullref when sending appearance packet. Thanks to zadark for... (diff)
downloadopensim-SC_OLD-140ea04b9d692344d803fc87364fb252561725c3.zip
opensim-SC_OLD-140ea04b9d692344d803fc87364fb252561725c3.tar.gz
opensim-SC_OLD-140ea04b9d692344d803fc87364fb252561725c3.tar.bz2
opensim-SC_OLD-140ea04b9d692344d803fc87364fb252561725c3.tar.xz
Merging Opensim upstream before generating patch
Diffstat (limited to 'OpenSim/Region/ScriptEngine')
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs1308
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs2
6 files changed, 1270 insertions, 50 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 @@
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Imaging;
31using System.Runtime.Remoting.Lifetime; 33using System.Runtime.Remoting.Lifetime;
32using System.Text; 34using System.Text;
33using System.Threading; 35using System.Threading;
@@ -35,7 +37,9 @@ using System.Text.RegularExpressions;
35using Nini.Config; 37using Nini.Config;
36using log4net; 38using log4net;
37using OpenMetaverse; 39using OpenMetaverse;
40using OpenMetaverse.Assets;
38using OpenMetaverse.Packets; 41using OpenMetaverse.Packets;
42using OpenMetaverse.Rendering;
39using OpenSim; 43using OpenSim;
40using OpenSim.Framework; 44using 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
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs
index 03612ef..0094af6 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs
@@ -30,7 +30,7 @@ using Mono.Addins;
30// Build Number 30// Build Number
31// Revision 31// Revision
32// 32//
33[assembly: AssemblyVersion("0.8.1.*")] 33[assembly: AssemblyVersion("0.8.2.*")]
34 34
35[assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)] 35[assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] 36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]