From 28961dd1cfc21a90510faa33af6d3c1c6f8bc0af Mon Sep 17 00:00:00 2001 From: Micheil Merlin Date: Sun, 4 Sep 2011 12:21:29 -0500 Subject: llSetPrimitiveParams Prim type params precision errors --- .../Shared/Api/Implementation/LSL_Api.cs | 76 ++++++++++++++++------ 1 file changed, 57 insertions(+), 19 deletions(-) (limited to 'OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs') diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 88e884d..cf8517d 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6570,6 +6570,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve) { + float tempFloat; // Use in float expressions below to avoid byte cast precision issues. ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT && @@ -6651,8 +6652,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { twist.y = 1.0f; } - shapeBlock.PathTwistBegin = (sbyte)(100 * twist.x); - shapeBlock.PathTwist = (sbyte)(100 * twist.y); + // A fairly large precision error occurs for some calculations, + // if a float or double is directly cast to a byte or sbyte + // variable, in both .Net and Mono. In .Net, coding + // "(sbyte)(float)(some expression)" corrects the precision + // errors. But this does not work for Mono. This longer coding + // form of creating a tempoary float variable from the + // expression first, then casting that variable to a byte or + // sbyte, works for both .Net and Mono. These types of + // assignments occur in SetPrimtiveBlockShapeParams and + // SetPrimitiveShapeParams in support of llSetPrimitiveParams. + tempFloat = (float)(100.0d * twist.x); + shapeBlock.PathTwistBegin = (sbyte)tempFloat; + tempFloat = (float)(100.0d * twist.y); + shapeBlock.PathTwist = (sbyte)tempFloat; shapeBlock.ObjectLocalID = part.LocalId; @@ -6663,6 +6676,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Prim type box, cylinder and prism. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte profileshape, byte pathcurve) { + float tempFloat; // Use in float expressions below to avoid byte cast precision issues. ObjectShapePacket.ObjectDataBlock shapeBlock; shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve); @@ -6683,8 +6697,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { taper_b.y = 2f; } - shapeBlock.PathScaleX = (byte)(100 * (2.0 - taper_b.x)); - shapeBlock.PathScaleY = (byte)(100 * (2.0 - taper_b.y)); + tempFloat = (float)(100.0d * (2.0d - taper_b.x)); + shapeBlock.PathScaleX = (byte)tempFloat; + tempFloat = (float)(100.0d * (2.0d - taper_b.y)); + shapeBlock.PathScaleY = (byte)tempFloat; if (topshear.x < -0.5f) { topshear.x = -0.5f; @@ -6701,8 +6717,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { topshear.y = 0.5f; } - shapeBlock.PathShearX = (byte)(100 * topshear.x); - shapeBlock.PathShearY = (byte)(100 * topshear.y); + tempFloat = (float)(100.0d * topshear.x); + shapeBlock.PathShearX = (byte)tempFloat; + tempFloat = (float)(100.0d * topshear.y); + shapeBlock.PathShearY = (byte)tempFloat; part.Shape.SculptEntry = false; part.UpdateShape(shapeBlock); @@ -6752,6 +6770,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Prim type torus, tube and ring. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte profileshape, byte pathcurve) { + float tempFloat; // Use in float expressions below to avoid byte cast precision issues. ObjectShapePacket.ObjectDataBlock shapeBlock; shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve); @@ -6776,8 +6795,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { holesize.y = 0.5f; } - shapeBlock.PathScaleX = (byte)(100 * (2 - holesize.x)); - shapeBlock.PathScaleY = (byte)(100 * (2 - holesize.y)); + tempFloat = (float)(100.0d * (2.0d - holesize.x)); + shapeBlock.PathScaleX = (byte)tempFloat; + tempFloat = (float)(100.0d * (2.0d - holesize.y)); + shapeBlock.PathScaleY = (byte)tempFloat; if (topshear.x < -0.5f) { topshear.x = -0.5f; @@ -6794,8 +6815,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { topshear.y = 0.5f; } - shapeBlock.PathShearX = (byte)(100 * topshear.x); - shapeBlock.PathShearY = (byte)(100 * topshear.y); + tempFloat = (float)(100.0d * topshear.x); + shapeBlock.PathShearX = (byte)tempFloat; + tempFloat = (float)(100.0d * topshear.y); + shapeBlock.PathShearY = (byte)tempFloat; if (profilecut.x < 0f) { profilecut.x = 0f; @@ -6839,8 +6862,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { taper_a.y = 1f; } - shapeBlock.PathTaperX = (sbyte)(100 * taper_a.x); - shapeBlock.PathTaperY = (sbyte)(100 * taper_a.y); + tempFloat = (float)(100.0d * taper_a.x); + shapeBlock.PathTaperX = (sbyte)tempFloat; + tempFloat = (float)(100.0d * taper_a.y); + shapeBlock.PathTaperY = (sbyte)tempFloat; if (revolutions < 1f) { revolutions = 1f; @@ -6849,7 +6874,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { revolutions = 4f; } - shapeBlock.PathRevolutions = (byte)(66.666667 * (revolutions - 1.0)); + tempFloat = 66.66667f * (revolutions - 1.0f); + shapeBlock.PathRevolutions = (byte)tempFloat; // limits on radiusoffset depend on revolutions and hole size (how?) seems like the maximum range is 0 to 1 if (radiusoffset < 0f) { @@ -6859,7 +6885,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { radiusoffset = 1f; } - shapeBlock.PathRadiusOffset = (sbyte)(100 * radiusoffset); + tempFloat = 100.0f * radiusoffset; + shapeBlock.PathRadiusOffset = (sbyte)tempFloat; if (skew < -0.95f) { skew = -0.95f; @@ -6868,7 +6895,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { skew = 0.95f; } - shapeBlock.PathSkew = (sbyte)(100 * skew); + tempFloat = 100.0f * skew; + shapeBlock.PathSkew = (sbyte)tempFloat; part.Shape.SculptEntry = false; part.UpdateShape(shapeBlock); @@ -7681,10 +7709,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0)); // float revolutions - res.Add(new LSL_Float((Shape.PathRevolutions * 0.015) + 1.0)); // Slightly inaccurate, because an unsigned - // byte is being used to represent the entire - // range of floating-point values from 1.0 - // through 4.0 (which is how SL does it). + res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d); + // Slightly inaccurate, because an unsigned byte is being used to represent + // the entire range of floating-point values from 1.0 through 4.0 (which is how + // SL does it). + // + // Using these formulas to store and retrieve PathRevolutions, it is not + // possible to use all values between 1.00 and 4.00. For instance, you can't + // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you + // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them + // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar + // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11. + // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value + // such as 1.10. So, SL must store and retreive the actual user input rather + // than only storing the encoded value. // float radiusoffset res.Add(new LSL_Float(Shape.PathRadiusOffset / 100.0)); -- cgit v1.1