diff --git a/OpenSim/Region/Physics/Meshing/Extruder.cs b/OpenSim/Region/Physics/Meshing/Extruder.cs deleted file mode 100644 index 1fc65e3fd6..0000000000 --- a/OpenSim/Region/Physics/Meshing/Extruder.cs +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -//#define SPAM - -using OpenMetaverse; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.Meshing -{ - internal class Extruder - { - //public float startParameter; - //public float stopParameter; - public PhysicsVector size; - - public float taperTopFactorX = 1f; - public float taperTopFactorY = 1f; - public float taperBotFactorX = 1f; - public float taperBotFactorY = 1f; - - public float pushX = 0f; - public float pushY = 0f; - - // twist amount in radians. NOT DEGREES. - public float twistTop = 0; - public float twistBot = 0; - public float twistMid = 0; - public float pathScaleX = 1.0f; - public float pathScaleY = 0.5f; - public float skew = 0.0f; - public float radius = 0.0f; - public float revolutions = 1.0f; - - public float pathCutBegin = 0.0f; - public float pathCutEnd = 1.0f; - - public ushort pathBegin = 0; - public ushort pathEnd = 0; - - public float pathTaperX = 0.0f; - public float pathTaperY = 0.0f; - - /// - /// Creates an extrusion of a profile along a linear path. Used to create prim types box, cylinder, and prism. - /// - /// - /// A mesh of the extruded shape - public Mesh ExtrudeLinearPath(Mesh m) - { - Mesh result = new Mesh(); - - Mesh newLayer; - Mesh lastLayer = null; - - int step = 0; - int steps = 1; - - float twistTotal = twistTop - twistBot; - // if the profile has a lot of twist, add more layers otherwise the layers may overlap - // and the resulting mesh may be quite inaccurate. This method is arbitrary and may not - // accurately match the viewer - float twistTotalAbs = System.Math.Abs(twistTotal); - if (twistTotalAbs > 0.01) - steps += (int)(twistTotalAbs * 3.66f); // dahlia's magic number ;) - -#if SPAM - System.Console.WriteLine("ExtrudeLinearPath: twistTotalAbs: " + twistTotalAbs.ToString() + " steps: " + steps.ToString()); -#endif - - double percentOfPathMultiplier = 1.0 / steps; - - float start = -0.5f; - - float stepSize = 1.0f / (float)steps; - - float xProfileScale = 1.0f; - float yProfileScale = 1.0f; - - float xOffset = 0.0f; - float yOffset = 0.0f; - float zOffset = start; - - float xOffsetStepIncrement = pushX / steps; - float yOffsetStepIncrement = pushY / steps; - -#if SPAM - System.Console.WriteLine("Extruder: twistTop: " + twistTop.ToString() + " twistbot: " + twistBot.ToString() + " twisttotal: " + twistTotal.ToString()); - System.Console.WriteLine("Extruder: taperBotFactorX: " + taperBotFactorX.ToString() + " taperBotFactorY: " + taperBotFactorY.ToString() - + " taperTopFactorX: " + taperTopFactorX.ToString() + " taperTopFactorY: " + taperTopFactorY.ToString()); - System.Console.WriteLine("Extruder: PathScaleX: " + pathScaleX.ToString() + " pathScaleY: " + pathScaleY.ToString()); -#endif - - //float percentOfPath = 0.0f; - float percentOfPath = (float)pathBegin * 2.0e-5f; - zOffset += percentOfPath; - bool done = false; - do // loop through the length of the path and add the layers - { - newLayer = m.Clone(); - - if (taperBotFactorX < 1.0f) - xProfileScale = 1.0f - (1.0f - percentOfPath) * (1.0f - taperBotFactorX); - else if (taperTopFactorX < 1.0f) - xProfileScale = 1.0f - percentOfPath * (1.0f - taperTopFactorX); - else xProfileScale = 1.0f; - - if (taperBotFactorY < 1.0f) - yProfileScale = 1.0f - (1.0f - percentOfPath) * (1.0f - taperBotFactorY); - else if (taperTopFactorY < 1.0f) - yProfileScale = 1.0f - percentOfPath * (1.0f - taperTopFactorY); - else yProfileScale = 1.0f; - -#if SPAM - //System.Console.WriteLine("xProfileScale: " + xProfileScale.ToString() + " yProfileScale: " + yProfileScale.ToString()); -#endif - Vertex vTemp = new Vertex(0.0f, 0.0f, 0.0f); - - // apply the taper to the profile before any rotations - if (xProfileScale != 1.0f || yProfileScale != 1.0f) - { - foreach (Vertex v in newLayer.vertices) - { - if (v != null) - { - v.X *= xProfileScale; - v.Y *= yProfileScale; - } - } - } - - - float twist = twistBot + (twistTotal * (float)percentOfPath); -#if SPAM - System.Console.WriteLine("Extruder: percentOfPath: " + percentOfPath.ToString() + " zOffset: " + zOffset.ToString() - + " xProfileScale: " + xProfileScale.ToString() + " yProfileScale: " + yProfileScale.ToString()); -#endif - - // apply twist rotation to the profile layer and position the layer in the prim - - Quaternion profileRot = Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), twist); - foreach (Vertex v in newLayer.vertices) - { - if (v != null) - { - vTemp = v * profileRot; - v.X = vTemp.X + xOffset; - v.Y = vTemp.Y + yOffset; - v.Z = vTemp.Z + zOffset; - } - } - - if (step == 0) // the first layer, invert normals - { - foreach (Triangle t in newLayer.triangles) - { - t.invertNormal(); - } - } - - result.Append(newLayer); - - int iLastNull = 0; - - if (lastLayer != null) - { - int i, count = newLayer.vertices.Count; - - for (i = 0; i < count; i++) - { - int iNext = (i + 1); - - if (lastLayer.vertices[i] == null) // cant make a simplex here - { - iLastNull = i + 1; - } - else - { - if (i == count - 1) // End of list - iNext = iLastNull; - - if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment - iNext = iLastNull; - - result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext])); - result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext])); - } - } - } - lastLayer = newLayer; - - // calc the step for the next interation of the loop - - if (step < steps) - { - step++; - percentOfPath += (float)percentOfPathMultiplier; - - xOffset += xOffsetStepIncrement; - yOffset += yOffsetStepIncrement; - zOffset += stepSize; - - if (percentOfPath > 1.0f - (float)pathEnd * 2.0e-5f) - done = true; - } - else done = true; - - } while (!done); // loop until all the layers in the path are completed - - // scale the mesh to the desired size - float xScale = size.X; - float yScale = size.Y; - float zScale = size.Z; - - foreach (Vertex v in result.vertices) - { - if (v != null) - { - v.X *= xScale; - v.Y *= yScale; - v.Z *= zScale; - } - } - - return result; - } - - /// - /// Extrudes a shape around a circular path. Used to create prim types torus, ring, and tube. - /// - /// - /// a mesh of the extruded shape - public Mesh ExtrudeCircularPath(Mesh m) - { - Mesh result = new Mesh(); - - Mesh newLayer; - Mesh lastLayer = null; - - int step; - int steps = 24; - - float twistTotal = twistTop - twistBot; - // if the profile has a lot of twist, add more layers otherwise the layers may overlap - // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't - // accurately match the viewer - if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 1.5f) steps *= 2; - if (System.Math.Abs(twistTotal) > (float)System.Math.PI * 3.0f) steps *= 2; - - // double percentOfPathMultiplier = 1.0 / steps; - // double angleStepMultiplier = System.Math.PI * 2.0 / steps; - - float yPathScale = pathScaleY * 0.5f; - float pathLength = pathCutEnd - pathCutBegin; - float totalSkew = skew * 2.0f * pathLength; - float skewStart = (-skew) + pathCutBegin * 2.0f * skew; - - // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end - // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used - // to calculate the sine for generating the path radius appears to approximate it's effects there - // too, but there are some subtle differences in the radius which are noticeable as the prim size - // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on - // the meshes generated with this technique appear nearly identical in shape to the same prims when - // displayed by the viewer. - - - float startAngle = (float)(System.Math.PI * 2.0 * pathCutBegin * revolutions) - pushY * 0.9f; - float endAngle = (float)(System.Math.PI * 2.0 * pathCutEnd * revolutions) - pushY * 0.9f; - float stepSize = (float)0.2617993878; // 2*PI / 24 segments per revolution - - step = (int)(startAngle / stepSize); - float angle = startAngle; - - float xProfileScale = 1.0f; - float yProfileScale = 1.0f; - - -#if SPAM - System.Console.WriteLine("Extruder: twistTop: " + twistTop.ToString() + " twistbot: " + twistBot.ToString() + " twisttotal: " + twistTotal.ToString()); - System.Console.WriteLine("Extruder: startAngle: " + startAngle.ToString() + " endAngle: " + endAngle.ToString() + " step: " + step.ToString()); - System.Console.WriteLine("Extruder: taperBotFactorX: " + taperBotFactorX.ToString() + " taperBotFactorY: " + taperBotFactorY.ToString() - + " taperTopFactorX: " + taperTopFactorX.ToString() + " taperTopFactorY: " + taperTopFactorY.ToString()); - System.Console.WriteLine("Extruder: PathScaleX: " + pathScaleX.ToString() + " pathScaleY: " + pathScaleY.ToString()); -#endif - - bool done = false; - do // loop through the length of the path and add the layers - { - newLayer = m.Clone(); - - float percentOfPath = (angle - startAngle) / (endAngle - startAngle); // endAngle should always be larger than startAngle - - if (pathTaperX > 0.001f) // can't really compare to 0.0f as the value passed is never exactly zero - xProfileScale = 1.0f - percentOfPath * pathTaperX; - else if (pathTaperX < -0.001f) - xProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperX; - else xProfileScale = 1.0f; - - if (pathTaperY > 0.001f) - yProfileScale = 1.0f - percentOfPath * pathTaperY; - else if (pathTaperY < -0.001f) - yProfileScale = 1.0f + (1.0f - percentOfPath) * pathTaperY; - else yProfileScale = 1.0f; - -#if SPAM - //System.Console.WriteLine("xProfileScale: " + xProfileScale.ToString() + " yProfileScale: " + yProfileScale.ToString()); -#endif - Vertex vTemp = new Vertex(0.0f, 0.0f, 0.0f); - - // apply the taper to the profile before any rotations - if (xProfileScale != 1.0f || yProfileScale != 1.0f) - { - foreach (Vertex v in newLayer.vertices) - { - if (v != null) - { - v.X *= xProfileScale; - v.Y *= yProfileScale; - } - } - } - - float radiusScale; - - if (radius > 0.001f) - radiusScale = 1.0f - radius * percentOfPath; - else if (radius < 0.001f) - radiusScale = 1.0f + radius * (1.0f - percentOfPath); - else - radiusScale = 1.0f; - -#if SPAM - System.Console.WriteLine("Extruder: angle: " + angle.ToString() + " percentOfPath: " + percentOfPath.ToString() - + " radius: " + radius.ToString() + " radiusScale: " + radiusScale.ToString() - + " xProfileScale: " + xProfileScale.ToString() + " yProfileScale: " + yProfileScale.ToString()); -#endif - - float twist = twistBot + (twistTotal * (float)percentOfPath); - - float xOffset; - float yOffset; - float zOffset; - - xOffset = 0.5f * (skewStart + totalSkew * (float)percentOfPath); - xOffset += (float) System.Math.Sin(angle) * pushX * 0.45f; - yOffset = (float)(System.Math.Cos(angle) * (0.5f - yPathScale)) * radiusScale; - zOffset = (float)(System.Math.Sin(angle + pushY * 0.9f) * (0.5f - yPathScale)) * radiusScale; - - // next apply twist rotation to the profile layer - if (twistTotal != 0.0f || twistBot != 0.0f) - { - Quaternion profileRot = new Quaternion(new Vector3(0.0f, 0.0f, 1.0f), twist); - foreach (Vertex v in newLayer.vertices) - { - if (v != null) - { - vTemp = v * profileRot; - v.X = vTemp.X; - v.Y = vTemp.Y; - v.Z = vTemp.Z; - } - } - } - - // now orient the rotation of the profile layer relative to it's position on the path - // adding pushY to the angle used to generate the quat appears to approximate the viewer - Quaternion layerRot = Quaternion.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), (float)angle + pushY * 0.9f); - foreach (Vertex v in newLayer.vertices) - { - if (v != null) - { - vTemp = v * layerRot; - v.X = vTemp.X + xOffset; - v.Y = vTemp.Y + yOffset; - v.Z = vTemp.Z + zOffset; - } - } - - if (angle == startAngle) // the first layer, invert normals - { - foreach (Triangle t in newLayer.triangles) - { - t.invertNormal(); - } - } - - result.Append(newLayer); - - int iLastNull = 0; - - if (lastLayer != null) - { - int i, count = newLayer.vertices.Count; - - for (i = 0; i < count; i++) - { - int iNext = (i + 1); - - if (lastLayer.vertices[i] == null) // cant make a simplex here - { - iLastNull = i + 1; - } - else - { - if (i == count - 1) // End of list - iNext = iLastNull; - - if (lastLayer.vertices[iNext] == null) // Null means wrap to begin of last segment - iNext = iLastNull; - - result.Add(new Triangle(newLayer.vertices[i], lastLayer.vertices[i], newLayer.vertices[iNext])); - result.Add(new Triangle(newLayer.vertices[iNext], lastLayer.vertices[i], lastLayer.vertices[iNext])); - } - } - } - lastLayer = newLayer; - - // calc the angle for the next interation of the loop - if (angle >= endAngle) - { - done = true; - } - else - { - angle = stepSize * ++step; - if (angle > endAngle) - angle = endAngle; - } - } while (!done); // loop until all the layers in the path are completed - - // scale the mesh to the desired size - float xScale = size.X; - float yScale = size.Y; - float zScale = size.Z; - - foreach (Vertex v in result.vertices) - { - if (v != null) - { - v.X *= xScale; - v.Y *= yScale; - v.Z *= zScale; - } - } - - return result; - } - } -} diff --git a/OpenSim/Region/Physics/Meshing/HelperTypes.cs b/OpenSim/Region/Physics/Meshing/HelperTypes.cs index 7491782293..7198cae5d3 100644 --- a/OpenSim/Region/Physics/Meshing/HelperTypes.cs +++ b/OpenSim/Region/Physics/Meshing/HelperTypes.cs @@ -356,20 +356,6 @@ public class Triangle radius_square = (float) (rx*rx + ry*ry); } - public List GetSimplices() - { - List result = new List(); - Simplex s1 = new Simplex(v1, v2); - Simplex s2 = new Simplex(v2, v3); - Simplex s3 = new Simplex(v3, v1); - - result.Add(s1); - result.Add(s2); - result.Add(s3); - - return result; - } - public override String ToString() { NumberFormatInfo nfi = new NumberFormatInfo(); diff --git a/OpenSim/Region/Physics/Meshing/Mesh.cs b/OpenSim/Region/Physics/Meshing/Mesh.cs index 583b485995..5a565ffcc8 100644 --- a/OpenSim/Region/Physics/Meshing/Mesh.cs +++ b/OpenSim/Region/Physics/Meshing/Mesh.cs @@ -115,26 +115,6 @@ namespace OpenSim.Region.Physics.Meshing vertices.Remove(v); } - public void RemoveTrianglesOutside(SimpleHull hull) - { - int i; - - for (i = 0; i < triangles.Count; i++) - { - Triangle t = triangles[i]; - Vertex v1 = t.v1; - Vertex v2 = t.v2; - Vertex v3 = t.v3; - PhysicsVector m = v1 + v2 + v3; - m /= 3.0f; - if (!hull.IsPointIn(new Vertex(m))) - { - triangles.RemoveAt(i); - i--; - } - } - } - public void Add(List lv) { foreach (Vertex v in lv) diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 6955aa0ff6..a65d0f457e 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs @@ -31,6 +31,9 @@ using System.Collections.Generic; using OpenSim.Framework; using OpenSim.Region.Physics.Manager; using OpenMetaverse; +using OpenMetaverse.Imaging; +using System.Drawing; +using System.Drawing.Imaging; using PrimMesher; namespace OpenSim.Region.Physics.Meshing @@ -54,8 +57,6 @@ namespace OpenSim.Region.Physics.Meshing public class Meshmerizer : IMesher { - private bool usePrimMesher = true; - //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); // Setting baseDir to a path will enable the dumping of raw files @@ -65,277 +66,9 @@ namespace OpenSim.Region.Physics.Meshing #else private const string baseDir = null; //"rawFiles"; #endif - private const float DEG_TO_RAD = 0.01745329238f; private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh -// private static void IntersectionParameterPD(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2, -// PhysicsVector r2, ref float lambda, ref float mu) -// { - // p1, p2, points on the straight - // r1, r2, directional vectors of the straight. Not necessarily of length 1! - // note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points, - // thus allowing to decide whether an intersection is between two points - -// float r1x = r1.X; -// float r1y = r1.Y; -// float r2x = r2.X; -// float r2y = r2.Y; -// -// float denom = r1y * r2x - r1x * r2y; -// -// if (denom == 0.0) -// { -// lambda = Single.NaN; -// mu = Single.NaN; -// return; -// } -// -// float p1x = p1.X; -// float p1y = p1.Y; -// float p2x = p2.X; -// float p2y = p2.Y; -// lambda = (-p2x * r2y + p1x * r2y + (p2y - p1y) * r2x) / denom; -// mu = (-p2x * r1y + p1x * r1y + (p2y - p1y) * r1x) / denom; -// } - - private static List FindInfluencedTriangles(List triangles, Vertex v) - { - List influenced = new List(); - foreach (Triangle t in triangles) - { - if (t.isInCircle(v.X, v.Y)) - { - influenced.Add(t); - } - } - return influenced; - } - - private static void InsertVertices(List vertices, int usedForSeed, List triangles) - { - // This is a variant of the delaunay algorithm - // each time a new vertex is inserted, all triangles that are influenced by it are deleted - // and replaced by new ones including the new vertex - // It is not very time efficient but easy to implement. - - int iCurrentVertex; - int iMaxVertex = vertices.Count; - for (iCurrentVertex = usedForSeed; iCurrentVertex < iMaxVertex; iCurrentVertex++) - { - // Background: A triangle mesh fulfills the delaunay condition if (iff!) - // each circumlocutory circle (i.e. the circle that touches all three corners) - // of each triangle is empty of other vertices. - // Obviously a single (seeding) triangle fulfills this condition. - // If we now add one vertex, we need to reconstruct all triangles, that - // do not fulfill this condition with respect to the new triangle - - // Find the triangles that are influenced by the new vertex - Vertex v = vertices[iCurrentVertex]; - if (v == null) - continue; // Null is polygon stop marker. Ignore it - List influencedTriangles = FindInfluencedTriangles(triangles, v); - - List simplices = new List(); - - // Reconstruction phase. First step, dissolve each triangle into it's simplices, - // i.e. it's "border lines" - // Goal is to find "inner" borders and delete them, while the hull gets conserved. - // Inner borders are special in the way that they always come twice, which is how we detect them - foreach (Triangle t in influencedTriangles) - { - List newSimplices = t.GetSimplices(); - simplices.AddRange(newSimplices); - triangles.Remove(t); - } - // Now sort the simplices. That will make identical ones reside side by side in the list - simplices.Sort(); - - // Look for duplicate simplices here. - // Remember, they are directly side by side in the list right now, - // So we only check directly neighbours - int iSimplex; - List innerSimplices = new List(); - for (iSimplex = 1; iSimplex < simplices.Count; iSimplex++) // Startindex=1, so we can refer backwards - { - if (simplices[iSimplex - 1].CompareTo(simplices[iSimplex]) == 0) - { - innerSimplices.Add(simplices[iSimplex - 1]); - innerSimplices.Add(simplices[iSimplex]); - } - } - - foreach (Simplex s in innerSimplices) - { - simplices.Remove(s); - } - - // each simplex still in the list belongs to the hull of the region in question - // The new vertex (yes, we still deal with verices here :-)) forms a triangle - // with each of these simplices. Build the new triangles and add them to the list - foreach (Simplex s in simplices) - { - Triangle t = new Triangle(s.v1, s.v2, vertices[iCurrentVertex]); - if (!t.isDegraded()) - { - triangles.Add(t); - } - } - } - } - - private static SimpleHull BuildHoleHull(PrimitiveBaseShape pbs, ProfileShape pshape, HollowShape hshape, UInt16 hollowFactor) - { - // Tackle HollowShape.Same - float fhollowFactor = (float)hollowFactor; - - switch (pshape) - { - case ProfileShape.Square: - if (hshape == HollowShape.Same) - hshape= HollowShape.Square; - break; - case ProfileShape.EquilateralTriangle: - fhollowFactor = ((float)hollowFactor / 1.9f); - if (hshape == HollowShape.Same) - { - hshape = HollowShape.Triangle; - } - - break; - - case ProfileShape.HalfCircle: - case ProfileShape.Circle: - if (pbs.PathCurve == (byte)Extrusion.Straight) - { - if (hshape == HollowShape.Same) - { - hshape = HollowShape.Circle; - } - } - break; - - - default: - if (hshape == HollowShape.Same) - hshape= HollowShape.Square; - break; - } - - - SimpleHull holeHull = null; - - if (hshape == HollowShape.Square) - { - float hollowFactorF = (float)fhollowFactor / (float)50000; - Vertex IMM; - Vertex IPM; - Vertex IPP; - Vertex IMP; - - if (pshape == ProfileShape.Circle) - { // square cutout in cylinder is 45 degress rotated - IMM = new Vertex(0.0f, -0.707f * hollowFactorF, 0.0f); - IPM = new Vertex(0.707f * hollowFactorF, 0.0f, 0.0f); - IPP = new Vertex(0.0f, 0.707f * hollowFactorF, 0.0f); - IMP = new Vertex(-0.707f * hollowFactorF, 0.0f, 0.0f); - } - else if (pshape == ProfileShape.EquilateralTriangle) - { - IMM = new Vertex(0.0f, -0.667f * hollowFactorF, 0.0f); - IPM = new Vertex(0.667f * hollowFactorF, 0.0f, 0.0f); - IPP = new Vertex(0.0f, 0.667f * hollowFactorF, 0.0f); - IMP = new Vertex(-0.667f * hollowFactorF, 0.0f, 0.0f); - } - else - { - IMM = new Vertex(-0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f); - IPM = new Vertex(+0.5f * hollowFactorF, -0.5f * hollowFactorF, 0.0f); - IPP = new Vertex(+0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f); - IMP = new Vertex(-0.5f * hollowFactorF, +0.5f * hollowFactorF, 0.0f); - } - - holeHull = new SimpleHull(); - - holeHull.AddVertex(IMM); - holeHull.AddVertex(IMP); - holeHull.AddVertex(IPP); - holeHull.AddVertex(IPM); - } - //if (hshape == HollowShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) - if (hshape == HollowShape.Circle) - { - float hollowFactorF = (float)fhollowFactor / (float)50000; - - //Counter clockwise around the quadrants - holeHull = new SimpleHull(); - - holeHull.AddVertex(new Vertex(0.353553f * hollowFactorF, 0.353553f * hollowFactorF, 0.0f)); // 45 degrees - holeHull.AddVertex(new Vertex(0.433013f * hollowFactorF, 0.250000f * hollowFactorF, 0.0f)); // 30 degrees - holeHull.AddVertex(new Vertex(0.482963f * hollowFactorF, 0.129410f * hollowFactorF, 0.0f)); // 15 degrees - holeHull.AddVertex(new Vertex(0.500000f * hollowFactorF, 0.000000f * hollowFactorF, 0.0f)); // 0 degrees - holeHull.AddVertex(new Vertex(0.482963f * hollowFactorF, -0.129410f * hollowFactorF, 0.0f)); // 345 degrees - holeHull.AddVertex(new Vertex(0.433013f * hollowFactorF, -0.250000f * hollowFactorF, 0.0f)); // 330 degrees - holeHull.AddVertex(new Vertex(0.353553f * hollowFactorF, -0.353553f * hollowFactorF, 0.0f)); // 315 degrees - holeHull.AddVertex(new Vertex(0.250000f * hollowFactorF, -0.433013f * hollowFactorF, 0.0f)); // 300 degrees - holeHull.AddVertex(new Vertex(0.129410f * hollowFactorF, -0.482963f * hollowFactorF, 0.0f)); // 285 degrees - holeHull.AddVertex(new Vertex(0.000000f * hollowFactorF, -0.500000f * hollowFactorF, 0.0f)); // 270 degrees - holeHull.AddVertex(new Vertex(-0.129410f * hollowFactorF, -0.482963f * hollowFactorF, 0.0f)); // 255 degrees - holeHull.AddVertex(new Vertex(-0.250000f * hollowFactorF, -0.433013f * hollowFactorF, 0.0f)); // 240 degrees - holeHull.AddVertex(new Vertex(-0.353553f * hollowFactorF, -0.353553f * hollowFactorF, 0.0f)); // 225 degrees - holeHull.AddVertex(new Vertex(-0.433013f * hollowFactorF, -0.250000f * hollowFactorF, 0.0f)); // 210 degrees - holeHull.AddVertex(new Vertex(-0.482963f * hollowFactorF, -0.129410f * hollowFactorF, 0.0f)); // 195 degrees - holeHull.AddVertex(new Vertex(-0.500000f * hollowFactorF, 0.000000f * hollowFactorF, 0.0f)); // 180 degrees - holeHull.AddVertex(new Vertex(-0.482963f * hollowFactorF, 0.129410f * hollowFactorF, 0.0f)); // 165 degrees - holeHull.AddVertex(new Vertex(-0.433013f * hollowFactorF, 0.250000f * hollowFactorF, 0.0f)); // 150 degrees - holeHull.AddVertex(new Vertex(-0.353553f * hollowFactorF, 0.353553f * hollowFactorF, 0.0f)); // 135 degrees - holeHull.AddVertex(new Vertex(-0.250000f * hollowFactorF, 0.433013f * hollowFactorF, 0.0f)); // 120 degrees - holeHull.AddVertex(new Vertex(-0.129410f * hollowFactorF, 0.482963f * hollowFactorF, 0.0f)); // 105 degrees - holeHull.AddVertex(new Vertex(0.000000f * hollowFactorF, 0.500000f * hollowFactorF, 0.0f)); // 90 degrees - holeHull.AddVertex(new Vertex(0.129410f * hollowFactorF, 0.482963f * hollowFactorF, 0.0f)); // 75 degrees - holeHull.AddVertex(new Vertex(0.250000f * hollowFactorF, 0.433013f * hollowFactorF, 0.0f)); // 60 degrees - holeHull.AddVertex(new Vertex(0.353553f * hollowFactorF, 0.353553f * hollowFactorF, 0.0f)); // 45 degrees - - } - if (hshape == HollowShape.Triangle) - { - float hollowFactorF = (float)fhollowFactor / (float)50000; - Vertex IMM; - Vertex IPM; - Vertex IPP; - - if (pshape == ProfileShape.Square) - { - // corner points are at 345, 105, and 225 degrees for the triangle within a box - - //IMM = new Vertex(((float)Math.Cos(345.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, ((float)Math.Sin(345.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, 0.0f); - //IPM = new Vertex(((float)Math.Cos(105.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, ((float)Math.Sin(105.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, 0.0f); - //IPP = new Vertex(((float)Math.Cos(225.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, ((float)Math.Sin(225.0 * DEG_TO_RAD) * 0.5f) * hollowFactorF, 0.0f); - - // hard coded here for speed, the equations are in the commented out lines above - IMM = new Vertex(0.48296f * hollowFactorF, -0.12941f * hollowFactorF, 0.0f); - IPM = new Vertex(-0.12941f * hollowFactorF, 0.48296f * hollowFactorF, 0.0f); - IPP = new Vertex(-0.35355f * hollowFactorF, -0.35355f * hollowFactorF, 0.0f); - } - else - { - IMM = new Vertex(-0.25f * hollowFactorF, -0.45f * hollowFactorF, 0.0f); - IPM = new Vertex(+0.5f * hollowFactorF, +0f * hollowFactorF, 0.0f); - IPP = new Vertex(-0.25f * hollowFactorF, +0.45f * hollowFactorF, 0.0f); - } - - holeHull = new SimpleHull(); - - holeHull.AddVertex(IMM); - holeHull.AddVertex(IPP); - holeHull.AddVertex(IPM); - - } - - return holeHull; - - - } /// /// creates a simple box mesh of the specified size @@ -420,1364 +153,197 @@ namespace OpenSim.Region.Physics.Meshing return CreateSimpleBoxMesh(minX, maxX, minY, maxY, minZ, maxZ); } - - private static Mesh CreateBoxMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size) - // Builds the z (+ and -) surfaces of a box shaped prim - { - UInt16 hollowFactor = primShape.ProfileHollow; - UInt16 profileBegin = primShape.ProfileBegin; - UInt16 profileEnd = primShape.ProfileEnd; - UInt16 taperX = primShape.PathScaleX; - UInt16 taperY = primShape.PathScaleY; - UInt16 pathShearX = primShape.PathShearX; - UInt16 pathShearY = primShape.PathShearY; - -#if SPAM - reportPrimParams("[BOX] " + primName, primShape); -#endif - - // Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface - // of a block are basically the same - // They may be warped differently but the shape is identical - // So we only create one surface as a model and derive both plus and minus surface of the block from it - // This is done in a model space where the block spans from -.5 to +.5 in X and Y - // The mapping to Scene space is done later during the "extrusion" phase - - // Base - Vertex MM = new Vertex(-0.5f, -0.5f, 0.0f); - Vertex PM = new Vertex(+0.5f, -0.5f, 0.0f); - Vertex PP = new Vertex(+0.5f, +0.5f, 0.0f); - Vertex MP = new Vertex(-0.5f, +0.5f, 0.0f); - - SimpleHull outerHull = new SimpleHull(); - - outerHull.AddVertex(PP); - outerHull.AddVertex(MP); - outerHull.AddVertex(MM); - outerHull.AddVertex(PM); - - // Deal with cuts now - if ((profileBegin != 0) || (profileEnd != 0)) - { - double fProfileBeginAngle = profileBegin / 50000.0*360.0; - // In degree, for easier debugging and understanding - fProfileBeginAngle -= (90.0 + 45.0); // for some reasons, the SL client counts from the corner -X/-Y - double fProfileEndAngle = 360.0 - profileEnd / 50000.0*360.0; // Pathend comes as complement to 1.0 - fProfileEndAngle -= (90.0 + 45.0); - - // avoid some problem angles until the hull subtraction routine is fixed - if ((fProfileBeginAngle + 45.0f) % 90.0f == 0.0f) - fProfileBeginAngle += 5.0f; - if ((fProfileEndAngle + 45.0f) % 90.0f == 0.0f) - fProfileEndAngle -= 5.0f; - if (fProfileBeginAngle % 90.0f == 0.0f) - fProfileBeginAngle += 1.0f; - if (fProfileEndAngle % 90.0f == 0.0f) - fProfileEndAngle -= 1.0f; - - if (fProfileBeginAngle < fProfileEndAngle) - fProfileEndAngle -= 360.0; - -#if SPAM - Console.WriteLine("Meshmerizer: fProfileBeginAngle: " + fProfileBeginAngle.ToString() + " fProfileEndAngle: " + fProfileEndAngle.ToString()); -#endif - - // Note, that we don't want to cut out a triangle, even if this is a - // good approximation for small cuts. Indeed we want to cut out an arc - // and we approximate this arc by a polygon chain - // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space - // So it can easily be subtracted from the outer hull - int iSteps = (int) (((fProfileBeginAngle - fProfileEndAngle)/45.0) + .5); - // how many steps do we need with approximately 45 degree - double dStepWidth = (fProfileBeginAngle - fProfileEndAngle)/iSteps; - - Vertex origin = new Vertex(0.0f, 0.0f, 0.0f); - - // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull - SimpleHull cutHull = new SimpleHull(); - cutHull.AddVertex(origin); - for (int i = 0; i < iSteps; i++) - { - double angle = fProfileBeginAngle - i*dStepWidth; // we count against the angle orientation!!!! - Vertex v = Vertex.FromAngle(angle*Math.PI/180.0); - cutHull.AddVertex(v); - } - Vertex legEnd = Vertex.FromAngle(fProfileEndAngle*Math.PI/180.0); - // Calculated separately to avoid errors - cutHull.AddVertex(legEnd); - - //m_log.DebugFormat("Starting cutting of the hollow shape from the prim {1}", 0, primName); - SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull); - - outerHull = cuttedHull; - } - - // Deal with the hole here - if (hollowFactor > 0) - { - if (hollowFactor < 1000) - hollowFactor = 1000; // some sane minimum for our beloved SimpleHull routines - - SimpleHull holeHull = BuildHoleHull(primShape, primShape.ProfileShape, primShape.HollowShape, hollowFactor); - if (holeHull != null) - { - SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull); - - outerHull = hollowedHull; - } - } - - Mesh m = new Mesh(); - - Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f); - Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f); - Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f); - - m.Add(Seed1); - m.Add(Seed2); - m.Add(Seed3); - - m.Add(new Triangle(Seed1, Seed2, Seed3)); - m.Add(outerHull.getVertices()); - - InsertVertices(m.vertices, 3, m.triangles); - m.DumpRaw(baseDir, primName, "Proto first Mesh"); - - m.Remove(Seed1); - m.Remove(Seed2); - m.Remove(Seed3); - m.DumpRaw(baseDir, primName, "Proto seeds removed"); - - m.RemoveTrianglesOutside(outerHull); - m.DumpRaw(baseDir, primName, "Proto outsides removed"); - - foreach (Triangle t in m.triangles) - { - PhysicsVector n = t.getNormal(); - if (n.Z < 0.0) - t.invertNormal(); - } - - Extruder extr = new Extruder(); - - extr.size = size; - - if (taperX != 100) - { - if (taperX > 100) - { - extr.taperTopFactorX = 1.0f - ((float)(taperX - 100) / 100); - } - else - { - extr.taperBotFactorX = 1.0f - ((100 - (float)taperX) / 100); - } - - } - - if (taperY != 100) - { - if (taperY > 100) - { - extr.taperTopFactorY = 1.0f - ((float)(taperY - 100) / 100); - } - else - { - extr.taperBotFactorY = 1.0f - ((100 - (float)taperY) / 100); - } - } - - if (pathShearX != 0) - { - if (pathShearX > 50) - { - // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 - extr.pushX = (((float)(256 - pathShearX) / 100) * -1f); - } - else - { - extr.pushX = (float)pathShearX / 100; - } - } - - if (pathShearY != 0) - { - if (pathShearY > 50) - { - // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 - extr.pushY = (((float)(256 - pathShearY) / 100) * -1f); - } - else - { - extr.pushY = (float)pathShearY / 100; - } - } - - extr.twistTop = (float)primShape.PathTwist * (float)Math.PI * 0.01f; - extr.twistBot = (float)primShape.PathTwistBegin * (float)Math.PI * 0.01f; - extr.pathBegin = primShape.PathBegin; - extr.pathEnd = primShape.PathEnd; - - Mesh result = extr.ExtrudeLinearPath(m); - result.DumpRaw(baseDir, primName, "Z extruded"); -#if SPAM - int vCount = 0; - - foreach (Vertex v in result.vertices) - if (v != null) - vCount++; - System.Console.WriteLine("Mesh vertex count: " + vCount.ToString()); -#endif - return result; - } - - private static Mesh CreateCylinderMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size) - // Builds the z (+ and -) surfaces of a box shaped prim - { - - UInt16 hollowFactor = primShape.ProfileHollow; - UInt16 profileBegin = primShape.ProfileBegin; - UInt16 profileEnd = primShape.ProfileEnd; - UInt16 taperX = primShape.PathScaleX; - UInt16 taperY = primShape.PathScaleY; - UInt16 pathShearX = primShape.PathShearX; - UInt16 pathShearY = primShape.PathShearY; - -#if SPAM - reportPrimParams("[CYLINDER] " + primName, primShape); -#endif - - - // Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface - // of a block are basically the same - // They may be warped differently but the shape is identical - // So we only create one surface as a model and derive both plus and minus surface of the block from it - // This is done in a model space where the block spans from -.5 to +.5 in X and Y - // The mapping to Scene space is done later during the "extrusion" phase - - // Base - - SimpleHull outerHull = new SimpleHull(); - - // counter-clockwise around the quadrants, start at 45 degrees - - outerHull.AddVertex(new Vertex(0.353553f, 0.353553f, 0.0f)); // 45 degrees - outerHull.AddVertex(new Vertex(0.250000f, 0.433013f, 0.0f)); // 60 degrees - outerHull.AddVertex(new Vertex(0.129410f, 0.482963f, 0.0f)); // 75 degrees - outerHull.AddVertex(new Vertex(0.000000f, 0.500000f, 0.0f)); // 90 degrees - outerHull.AddVertex(new Vertex(-0.129410f, 0.482963f, 0.0f)); // 105 degrees - outerHull.AddVertex(new Vertex(-0.250000f, 0.433013f, 0.0f)); // 120 degrees - outerHull.AddVertex(new Vertex(-0.353553f, 0.353553f, 0.0f)); // 135 degrees - outerHull.AddVertex(new Vertex(-0.433013f, 0.250000f, 0.0f)); // 150 degrees - outerHull.AddVertex(new Vertex(-0.482963f, 0.129410f, 0.0f)); // 165 degrees - outerHull.AddVertex(new Vertex(-0.500000f, 0.000000f, 0.0f)); // 180 degrees - outerHull.AddVertex(new Vertex(-0.482963f, -0.129410f, 0.0f)); // 195 degrees - outerHull.AddVertex(new Vertex(-0.433013f, -0.250000f, 0.0f)); // 210 degrees - outerHull.AddVertex(new Vertex(-0.353553f, -0.353553f, 0.0f)); // 225 degrees - outerHull.AddVertex(new Vertex(-0.250000f, -0.433013f, 0.0f)); // 240 degrees - outerHull.AddVertex(new Vertex(-0.129410f, -0.482963f, 0.0f)); // 255 degrees - outerHull.AddVertex(new Vertex(0.000000f, -0.500000f, 0.0f)); // 270 degrees - outerHull.AddVertex(new Vertex(0.129410f, -0.482963f, 0.0f)); // 285 degrees - outerHull.AddVertex(new Vertex(0.250000f, -0.433013f, 0.0f)); // 300 degrees - outerHull.AddVertex(new Vertex(0.353553f, -0.353553f, 0.0f)); // 315 degrees - outerHull.AddVertex(new Vertex(0.433013f, -0.250000f, 0.0f)); // 330 degrees - outerHull.AddVertex(new Vertex(0.482963f, -0.129410f, 0.0f)); // 345 degrees - outerHull.AddVertex(new Vertex(0.500000f, 0.000000f, 0.0f)); // 0 degrees - outerHull.AddVertex(new Vertex(0.482963f, 0.129410f, 0.0f)); // 15 degrees - outerHull.AddVertex(new Vertex(0.433013f, 0.250000f, 0.0f)); // 30 degrees - - - - // Deal with cuts now - if ((profileBegin != 0) || (profileEnd != 0)) - { - double fProfileBeginAngle = profileBegin / 50000.0 * 360.0; - // In degree, for easier debugging and understanding - double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0 - -#if SPAM - Console.WriteLine("Extruder: Cylinder fProfileBeginAngle: " + fProfileBeginAngle.ToString() + " fProfileEndAngle: " + fProfileEndAngle.ToString()); -#endif - if (fProfileBeginAngle > 270.0f && fProfileBeginAngle < 271.8f) // a problem angle for the hull subtract routine :( - fProfileBeginAngle = 271.8f; // workaround - use the smaller slice - - if (fProfileBeginAngle < fProfileEndAngle) - fProfileEndAngle -= 360.0; -#if SPAM - Console.WriteLine("Extruder: Cylinder fProfileBeginAngle: " + fProfileBeginAngle.ToString() + " fProfileEndAngle: " + fProfileEndAngle.ToString()); -#endif - - // Note, that we don't want to cut out a triangle, even if this is a - // good approximation for small cuts. Indeed we want to cut out an arc - // and we approximate this arc by a polygon chain - // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space - // So it can easily be subtracted from the outer hull - int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5); - // how many steps do we need with approximately 45 degree - double dStepWidth = (fProfileBeginAngle - fProfileEndAngle) / iSteps; - - Vertex origin = new Vertex(0.0f, 0.0f, 0.0f); - - // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull - SimpleHull cutHull = new SimpleHull(); - cutHull.AddVertex(origin); - for (int i = 0; i < iSteps; i++) - { - double angle = fProfileBeginAngle - i * dStepWidth; // we count against the angle orientation!!!! - Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0); - cutHull.AddVertex(v); - } - Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0); - // Calculated separately to avoid errors - cutHull.AddVertex(legEnd); - - SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull); - - outerHull = cuttedHull; - } - - // Deal with the hole here - if (hollowFactor > 0) - { - if (hollowFactor < 1000) - hollowFactor = 1000; // some sane minimum for our beloved SimpleHull routines - - SimpleHull holeHull = BuildHoleHull(primShape, primShape.ProfileShape, primShape.HollowShape, hollowFactor); - if (holeHull != null) - { - SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull); - - outerHull = hollowedHull; - } - } - - Mesh m = new Mesh(); - - Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f); - Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f); - Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f); - - m.Add(Seed1); - m.Add(Seed2); - m.Add(Seed3); - - m.Add(new Triangle(Seed1, Seed2, Seed3)); - m.Add(outerHull.getVertices()); - - InsertVertices(m.vertices, 3, m.triangles); - m.DumpRaw(baseDir, primName, "Proto first Mesh"); - - m.Remove(Seed1); - m.Remove(Seed2); - m.Remove(Seed3); - m.DumpRaw(baseDir, primName, "Proto seeds removed"); - - m.RemoveTrianglesOutside(outerHull); - m.DumpRaw(baseDir, primName, "Proto outsides removed"); - - foreach (Triangle t in m.triangles) - { - PhysicsVector n = t.getNormal(); - if (n.Z < 0.0) - t.invertNormal(); - } - - Extruder extr = new Extruder(); - - extr.size = size; - - if (taperX != 100) - { - if (taperX > 100) - { - extr.taperTopFactorX = 1.0f - ((float)(taperX - 100) / 100); } - else - { - extr.taperBotFactorX = 1.0f - ((100 - (float)taperX) / 100); - } - - } - - if (taperY != 100) - { - if (taperY > 100) - { - extr.taperTopFactorY = 1.0f - ((float)(taperY - 100) / 100); - } - else - { - extr.taperBotFactorY = 1.0f - ((100 - (float)taperY) / 100); - } - } - - if (pathShearX != 0) - { - if (pathShearX > 50) - { - // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 - extr.pushX = (((float)(256 - pathShearX) / 100) * -1f); - } - else - { - extr.pushX = (float)pathShearX / 100; - } - } - - if (pathShearY != 0) - { - if (pathShearY > 50) - { - // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 - extr.pushY = (((float)(256 - pathShearY) / 100) * -1f); - } - else - { - extr.pushY = (float)pathShearY / 100; - } - - } - - extr.twistTop = (float)primShape.PathTwist * (float)Math.PI * 0.01f; - extr.twistBot = (float)primShape.PathTwistBegin * (float)Math.PI * 0.01f; - extr.pathBegin = primShape.PathBegin; - extr.pathEnd = primShape.PathEnd; - - Mesh result = extr.ExtrudeLinearPath(m); - result.DumpRaw(baseDir, primName, "Z extruded"); -#if SPAM - int vCount = 0; - - foreach (Vertex v in result.vertices) - if (v != null) - vCount++; - System.Console.WriteLine("Mesh vertex count: " + vCount.ToString()); -#endif - return result; - } - - private static Mesh CreatePrismMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size) - // Builds the z (+ and -) surfaces of a box shaped prim - { - UInt16 hollowFactor = primShape.ProfileHollow; - UInt16 profileBegin = primShape.ProfileBegin; - UInt16 profileEnd = primShape.ProfileEnd; - UInt16 taperX = primShape.PathScaleX; - UInt16 taperY = primShape.PathScaleY; - UInt16 pathShearX = primShape.PathShearX; - UInt16 pathShearY = primShape.PathShearY; - - -#if SPAM - reportPrimParams("[PRISM] " + primName, primShape); -#endif - // Procedure: This is based on the fact that the upper (plus) and lower (minus) Z-surface - // of a block are basically the same - // They may be warped differently but the shape is identical - // So we only create one surface as a model and derive both plus and minus surface of the block from it - // This is done in a model space where the block spans from -.5 to +.5 in X and Y - // The mapping to Scene space is done later during the "extrusion" phase - - // Base - Vertex MM = new Vertex(-0.25f, -0.45f, 0.0f); - Vertex PM = new Vertex(+0.5f, 0f, 0.0f); - Vertex PP = new Vertex(-0.25f, +0.45f, 0.0f); - - - SimpleHull outerHull = new SimpleHull(); - - outerHull.AddVertex(PP); - outerHull.AddVertex(MM); - outerHull.AddVertex(PM); - - // Deal with cuts now - if ((profileBegin != 0) || (profileEnd != 0)) - { - double fProfileBeginAngle = profileBegin / 50000.0 * 360.0; - // In degree, for easier debugging and understanding - double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0 - - if (fProfileBeginAngle < fProfileEndAngle) - fProfileEndAngle -= 360.0; - - // Note, that we don't want to cut out a triangle, even if this is a - // good approximation for small cuts. Indeed we want to cut out an arc - // and we approximate this arc by a polygon chain - // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space - // So it can easily be subtracted from the outer hull - int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5); - // how many steps do we need with approximately 45 degree - double dStepWidth = (fProfileBeginAngle - fProfileEndAngle) / iSteps; - - Vertex origin = new Vertex(0.0f, 0.0f, 0.0f); - - // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull - SimpleHull cutHull = new SimpleHull(); - cutHull.AddVertex(origin); - for (int i = 0; i < iSteps; i++) - { - double angle = fProfileBeginAngle - i * dStepWidth; // we count against the angle orientation!!!! - Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0); - cutHull.AddVertex(v); - } - Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0); - // Calculated separately to avoid errors - cutHull.AddVertex(legEnd); - - SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull); - - outerHull = cuttedHull; - } - - // Deal with the hole here - if (hollowFactor > 0) - { - if (hollowFactor < 1000) - hollowFactor = 1000; // some sane minimum for our beloved SimpleHull routines - - SimpleHull holeHull = BuildHoleHull(primShape, primShape.ProfileShape, primShape.HollowShape, hollowFactor); - if (holeHull != null) - { - SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull); - - outerHull = hollowedHull; - } - } - - Mesh m = new Mesh(); - - Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f); - Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f); - Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f); - - m.Add(Seed1); - m.Add(Seed2); - m.Add(Seed3); - - m.Add(new Triangle(Seed1, Seed2, Seed3)); - m.Add(outerHull.getVertices()); - - InsertVertices(m.vertices, 3, m.triangles); - m.DumpRaw(baseDir, primName, "Proto first Mesh"); - - m.Remove(Seed1); - m.Remove(Seed2); - m.Remove(Seed3); - m.DumpRaw(baseDir, primName, "Proto seeds removed"); - - m.RemoveTrianglesOutside(outerHull); - m.DumpRaw(baseDir, primName, "Proto outsides removed"); - - foreach (Triangle t in m.triangles) - { - PhysicsVector n = t.getNormal(); - if (n.Z < 0.0) - t.invertNormal(); - } - - Extruder extr = new Extruder(); - - extr.size = size; - - if (taperX != 100) - { - if (taperX > 100) - { - extr.taperTopFactorX = 1.0f - ((float)(taperX - 100) / 100); - } - else - { - extr.taperBotFactorX = 1.0f - ((100 - (float)taperX) / 100); - } - - } - - if (taperY != 100) - { - if (taperY > 100) - { - extr.taperTopFactorY = 1.0f - ((float)(taperY - 100) / 100); - } - else - { - extr.taperBotFactorY = 1.0f - ((100 - (float)taperY) / 100); - } - } - - if (pathShearX != 0) - { - if (pathShearX > 50) - { - // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 - extr.pushX = (((float)(256 - pathShearX) / 100) * -1f); - } - else - { - extr.pushX = (float)pathShearX / 100; - } - } - - if (pathShearY != 0) - { - if (pathShearY > 50) - { - // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 - extr.pushY = (((float)(256 - pathShearY) / 100) * -1f); - } - else - { - extr.pushY = (float)pathShearY / 100; - } - } - - extr.twistTop = (float)primShape.PathTwist * (float)Math.PI * 0.01f; - extr.twistBot = (float)primShape.PathTwistBegin * (float)Math.PI * 0.01f; - extr.pathBegin = primShape.PathBegin; - extr.pathEnd = primShape.PathEnd; - - Mesh result = extr.ExtrudeLinearPath(m); - result.DumpRaw(baseDir, primName, "Z extruded"); -#if SPAM - int vCount = 0; - - foreach (Vertex v in result.vertices) - if (v != null) - vCount++; - System.Console.WriteLine("Mesh vertex count: " + vCount.ToString()); -#endif - return result; - } - - /// - /// builds an icosahedral geodesic sphere - used as default in place of problem meshes - /// - /// - /// - /// - /// - private static Mesh CreateSphereMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size) - { - // Builds an icosahedral geodesic sphere - // based on an article by Paul Bourke - // http://local.wasp.uwa.edu.au/~pbourke/ - // articles: - // http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonmesh/ - // and - // http://local.wasp.uwa.edu.au/~pbourke/geometry/polyhedra/index.html - - // Still have more to do here. - - Mesh m = new Mesh(); - -#if SPAM - reportPrimParams("[SPHERE] " + primName, primShape); -#endif - - float LOD = 0.2f; - float diameter = 0.5f;// Our object will result in -0.5 to 0.5 - float sq5 = (float) Math.Sqrt(5.0); - float phi = (1 + sq5) * 0.5f; - float rat = (float) Math.Sqrt(10f + (2f * sq5)) / (4f * phi); - float a = (diameter / rat) * 0.5f; - float b = (diameter / rat) / (2.0f * phi); - - - // 12 Icosahedron vertexes - Vertex v1 = new Vertex(0f, b, -a); - Vertex v2 = new Vertex(b, a, 0f); - Vertex v3 = new Vertex(-b, a, 0f); - Vertex v4 = new Vertex(0f, b, a); - Vertex v5 = new Vertex(0f, -b, a); - Vertex v6 = new Vertex(-a, 0f, b); - Vertex v7 = new Vertex(0f, -b, -a); - Vertex v8 = new Vertex(a, 0f, -b); - Vertex v9 = new Vertex(a, 0f, b); - Vertex v10 = new Vertex(-a, 0f, -b); - Vertex v11 = new Vertex(b, -a, 0); - Vertex v12 = new Vertex(-b, -a, 0); - - - - // Base Faces of the Icosahedron (20) - SphereLODTriangle(v1, v2, v3, diameter, LOD, m); - SphereLODTriangle(v4, v3, v2, diameter, LOD, m); - SphereLODTriangle(v4, v5, v6, diameter, LOD, m); - SphereLODTriangle(v4, v9, v5, diameter, LOD, m); - SphereLODTriangle(v1, v7, v8, diameter, LOD, m); - SphereLODTriangle(v1, v10, v7, diameter, LOD, m); - SphereLODTriangle(v5, v11, v12, diameter, LOD, m); - SphereLODTriangle(v7, v12, v11, diameter, LOD, m); - SphereLODTriangle(v3, v6, v10, diameter, LOD, m); - SphereLODTriangle(v12, v10, v6, diameter, LOD, m); - SphereLODTriangle(v2, v8, v9, diameter, LOD, m); - SphereLODTriangle(v11, v9, v8, diameter, LOD, m); - SphereLODTriangle(v4, v6, v3, diameter, LOD, m); - SphereLODTriangle(v4, v2, v9, diameter, LOD, m); - SphereLODTriangle(v1, v3, v10, diameter, LOD, m); - SphereLODTriangle(v1, v8, v2, diameter, LOD, m); - SphereLODTriangle(v7, v10, v12, diameter, LOD, m); - SphereLODTriangle(v7, v11, v8, diameter, LOD, m); - SphereLODTriangle(v5, v12, v6, diameter, LOD, m); - SphereLODTriangle(v5, v9, v11, diameter, LOD, m); - - // Scale the mesh based on our prim scale - foreach (Vertex v in m.vertices) - { - v.X *= size.X; - v.Y *= size.Y; - v.Z *= size.Z; - } - - // This was built with the normals pointing inside.. - // therefore we have to invert the normals - foreach (Triangle t in m.triangles) - { - t.invertNormal(); - } - // Dump the faces for visualization in blender. - m.DumpRaw(baseDir, primName, "Icosahedron"); -#if SPAM - int vCount = 0; - - foreach (Vertex v in m.vertices) - if (v != null) - vCount++; - System.Console.WriteLine("Mesh vertex count: " + vCount.ToString()); -#endif - - return m; - } - private SculptMesh CreateSculptMesh(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod) - { - -#if SPAM - reportPrimParams("[SCULPT] " + primName, primShape); -#endif - - SculptMesh sm = new SculptMesh(primShape.SculptData, lod); - // Scale the mesh based on our prim scale - foreach (Vertex v in sm.vertices) - { - v.X *= 0.5f; - v.Y *= 0.5f; - v.Z *= 0.5f; - v.X *= size.X; - v.Y *= size.Y; - v.Z *= size.Z; - } - // This was built with the normals pointing inside.. - // therefore we have to invert the normals - foreach (Triangle t in sm.triangles) - { - t.invertNormal(); - } - sm.DumpRaw(baseDir, primName, "Sculpt"); - return sm; - - } - - /// - /// Creates a mesh for prim types torus, ring, tube, and sphere - /// - /// - /// - /// - /// - private static Mesh CreateCircularPathMesh(String primName, PrimitiveBaseShape primShape, PhysicsVector size) - { - - UInt16 hollowFactor = primShape.ProfileHollow; - UInt16 profileBegin = primShape.ProfileBegin; - UInt16 profileEnd = primShape.ProfileEnd; - UInt16 pathShearX = primShape.PathShearX; - UInt16 pathShearY = primShape.PathShearY; - HollowShape hollowShape = primShape.HollowShape; - -#if SPAM - reportPrimParams("[CIRCULAR PATH PRIM] " + primName, primShape); - Console.WriteLine("pathTwist: " + primShape.PathTwist.ToString() + " pathTwistBegin: " + primShape.PathTwistBegin.ToString()); - Console.WriteLine("primShape.ProfileCurve & 0x07: " + Convert.ToString(primShape.ProfileCurve & 0x07)); - -#endif - - SimpleHull outerHull = new SimpleHull(); - - if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) - { -#if SPAM - Console.WriteLine("Meshmerizer thinks " + primName + " is a TORUS"); -#endif - if (hollowShape == HollowShape.Same) - hollowShape = HollowShape.Circle; - - // build the profile shape - // counter-clockwise around the quadrants, start at 45 degrees - - outerHull.AddVertex(new Vertex(0.353553f, 0.353553f, 0.0f)); // 45 degrees - outerHull.AddVertex(new Vertex(0.250000f, 0.433013f, 0.0f)); // 60 degrees - outerHull.AddVertex(new Vertex(0.129410f, 0.482963f, 0.0f)); // 75 degrees - outerHull.AddVertex(new Vertex(0.000000f, 0.500000f, 0.0f)); // 90 degrees - outerHull.AddVertex(new Vertex(-0.129410f, 0.482963f, 0.0f)); // 105 degrees - outerHull.AddVertex(new Vertex(-0.250000f, 0.433013f, 0.0f)); // 120 degrees - outerHull.AddVertex(new Vertex(-0.353553f, 0.353553f, 0.0f)); // 135 degrees - outerHull.AddVertex(new Vertex(-0.433013f, 0.250000f, 0.0f)); // 150 degrees - outerHull.AddVertex(new Vertex(-0.482963f, 0.129410f, 0.0f)); // 165 degrees - outerHull.AddVertex(new Vertex(-0.500000f, 0.000000f, 0.0f)); // 180 degrees - outerHull.AddVertex(new Vertex(-0.482963f, -0.129410f, 0.0f)); // 195 degrees - outerHull.AddVertex(new Vertex(-0.433013f, -0.250000f, 0.0f)); // 210 degrees - outerHull.AddVertex(new Vertex(-0.353553f, -0.353553f, 0.0f)); // 225 degrees - outerHull.AddVertex(new Vertex(-0.250000f, -0.433013f, 0.0f)); // 240 degrees - outerHull.AddVertex(new Vertex(-0.129410f, -0.482963f, 0.0f)); // 255 degrees - outerHull.AddVertex(new Vertex(0.000000f, -0.500000f, 0.0f)); // 270 degrees - outerHull.AddVertex(new Vertex(0.129410f, -0.482963f, 0.0f)); // 285 degrees - outerHull.AddVertex(new Vertex(0.250000f, -0.433013f, 0.0f)); // 300 degrees - outerHull.AddVertex(new Vertex(0.353553f, -0.353553f, 0.0f)); // 315 degrees - outerHull.AddVertex(new Vertex(0.433013f, -0.250000f, 0.0f)); // 330 degrees - outerHull.AddVertex(new Vertex(0.482963f, -0.129410f, 0.0f)); // 345 degrees - outerHull.AddVertex(new Vertex(0.500000f, 0.000000f, 0.0f)); // 0 degrees - outerHull.AddVertex(new Vertex(0.482963f, 0.129410f, 0.0f)); // 15 degrees - outerHull.AddVertex(new Vertex(0.433013f, 0.250000f, 0.0f)); // 30 degrees - } - - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square) // a ring - { -#if SPAM - Console.WriteLine("Meshmerizer thinks " + primName + " is a TUBE"); -#endif - if (hollowShape == HollowShape.Same) - hollowShape = HollowShape.Square; - - outerHull.AddVertex(new Vertex(+0.5f, +0.5f, 0.0f)); - outerHull.AddVertex(new Vertex(-0.5f, +0.5f, 0.0f)); - outerHull.AddVertex(new Vertex(-0.5f, -0.5f, 0.0f)); - outerHull.AddVertex(new Vertex(+0.5f, -0.5f, 0.0f)); - } - - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) - { -#if SPAM - Console.WriteLine("Meshmerizer thinks " + primName + " is a RING"); -#endif - if (hollowShape == HollowShape.Same) - hollowShape = HollowShape.Triangle; - - outerHull.AddVertex(new Vertex(+0.255f, -0.375f, 0.0f)); - outerHull.AddVertex(new Vertex(+0.25f, +0.375f, 0.0f)); - outerHull.AddVertex(new Vertex(-0.5f, +0.0f, 0.0f)); - - } - - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { -#if SPAM - Console.WriteLine("Meshmerizer thinks " + primName + " is a SPHERE"); -#endif - - // sanity check here... some spheres have inverted normals which can trap avatars - // so for now if the shape parameters are such that this may happen, revert to the - // geodesic sphere mesh.. the threshold is arbitrary as it seems any twist on a sphere - // will create some inverted normals - if ( - (System.Math.Abs(primShape.PathTwist - primShape.PathTwistBegin) > 65) - || (primShape.PathBegin == 0 - && primShape.PathEnd == 0 - && primShape.PathTwist == 0 - && primShape.PathTwistBegin == 0 - && primShape.ProfileBegin == 0 - && primShape.ProfileEnd == 0 - && hollowFactor == 0 - ) // simple sphere, revert to geodesic shape - - ) - { -#if SPAM - System.Console.WriteLine("reverting to geodesic sphere for prim: " + primName); -#endif - return CreateSphereMesh(primName, primShape, size); - } - - if (hollowFactor == 0) - { - // the hull triangulator is happier with a minimal hollow - hollowFactor = 2000; - } - - if (hollowShape == HollowShape.Same) - hollowShape = HollowShape.Circle; - - outerHull.AddVertex(new Vertex(0.250000f, 0.433013f, 0.0f)); // 60 degrees - outerHull.AddVertex(new Vertex(0.129410f, 0.482963f, 0.0f)); // 75 degrees - outerHull.AddVertex(new Vertex(0.000000f, 0.500000f, 0.0f)); // 90 degrees - outerHull.AddVertex(new Vertex(-0.129410f, 0.482963f, 0.0f)); // 105 degrees - outerHull.AddVertex(new Vertex(-0.250000f, 0.433013f, 0.0f)); // 120 degrees - outerHull.AddVertex(new Vertex(-0.353553f, 0.353553f, 0.0f)); // 135 degrees - outerHull.AddVertex(new Vertex(-0.433013f, 0.250000f, 0.0f)); // 150 degrees - outerHull.AddVertex(new Vertex(-0.482963f, 0.129410f, 0.0f)); // 165 degrees - outerHull.AddVertex(new Vertex(-0.500000f, 0.000000f, 0.0f)); // 180 degrees - - outerHull.AddVertex(new Vertex(0.500000f, 0.000000f, 0.0f)); // 0 degrees - outerHull.AddVertex(new Vertex(0.482963f, 0.129410f, 0.0f)); // 15 degrees - outerHull.AddVertex(new Vertex(0.433013f, 0.250000f, 0.0f)); // 30 degrees - outerHull.AddVertex(new Vertex(0.353553f, 0.353553f, 0.0f)); // 45 degrees - } - - // Deal with cuts now - if ((profileBegin != 0) || (profileEnd != 0)) - { - double fProfileBeginAngle = profileBegin / 50000.0 * 360.0; - // In degree, for easier debugging and understanding - double fProfileEndAngle = 360.0 - profileEnd / 50000.0 * 360.0; // Pathend comes as complement to 1.0 - - if (fProfileBeginAngle < fProfileEndAngle) - fProfileEndAngle -= 360.0; - - if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { // dimpled sphere uses profile cut but since it's a half circle the angles are smaller - fProfileBeginAngle = 0.0036f * (float)primShape.ProfileBegin; - fProfileEndAngle = 180.0f - 0.0036f * (float)primShape.ProfileEnd; - if (fProfileBeginAngle < fProfileEndAngle) - fProfileEndAngle -= 360.0f; - // a cut starting at 0 degrees with a hollow causes an infinite loop so move the start angle - // past it into the empty part of the circle to avoid this condition - if (fProfileBeginAngle == 0.0f) fProfileBeginAngle = -10.0f; - -#if SPAM - Console.WriteLine("Sphere dimple: fProfileBeginAngle: " + fProfileBeginAngle.ToString() + " fProfileEndAngle: " + fProfileEndAngle.ToString()); -#endif - } - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square) - { // tube profile cut is offset 45 degrees from other prim types - fProfileBeginAngle += 45.0f; - fProfileEndAngle += 45.0f; - if (fProfileBeginAngle < fProfileEndAngle) - fProfileEndAngle -= 360.0; - } - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) - { // ring profile cut is offset 180 degrees from other prim types - fProfileBeginAngle += 180.0f; - fProfileEndAngle += 180.0f; - if (fProfileBeginAngle < fProfileEndAngle) - fProfileEndAngle -= 360.0; - } - - // Note, that we don't want to cut out a triangle, even if this is a - // good approximation for small cuts. Indeed we want to cut out an arc - // and we approximate this arc by a polygon chain - // Also note, that these vectors are of length 1.0 and thus their endpoints lay outside the model space - // So it can easily be subtracted from the outer hull - int iSteps = (int)(((fProfileBeginAngle - fProfileEndAngle) / 45.0) + .5); - // how many steps do we need with approximately 45 degree - double dStepWidth = (fProfileBeginAngle - fProfileEndAngle) / iSteps; - - Vertex origin = new Vertex(0.0f, 0.0f, 0.0f); - - // Note the sequence of vertices here. It's important to have the other rotational sense than in outerHull - SimpleHull cutHull = new SimpleHull(); - cutHull.AddVertex(origin); - for (int i = 0; i < iSteps; i++) - { - double angle = fProfileBeginAngle - i * dStepWidth; // we count against the angle orientation!!!! - Vertex v = Vertex.FromAngle(angle * Math.PI / 180.0); - cutHull.AddVertex(v); - } - Vertex legEnd = Vertex.FromAngle(fProfileEndAngle * Math.PI / 180.0); - // Calculated separately to avoid errors - cutHull.AddVertex(legEnd); - - // m_log.DebugFormat("Starting cutting of the hollow shape from the prim {1}", 0, primName); - SimpleHull cuttedHull = SimpleHull.SubtractHull(outerHull, cutHull); - - if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) - { - Quaternion zFlip = Quaternion.CreateFromAxisAngle(new Vector3(0.0f, 0.0f, 1.0f), (float)Math.PI); - Vertex vTmp = new Vertex(0.0f, 0.0f, 0.0f); - foreach (Vertex v in cuttedHull.getVertices()) - if (v != null) - { - vTmp = v * zFlip; - v.X = vTmp.X; - v.Y = vTmp.Y; - v.Z = vTmp.Z; - } - } - - outerHull = cuttedHull; - } - - // Deal with the hole here - if (hollowFactor > 0) - { - SimpleHull holeHull; - - if (hollowShape == HollowShape.Triangle) - { - holeHull = new SimpleHull(); - - float hollowFactorF = (float)hollowFactor * 2.0e-5f; - - if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) - { - holeHull.AddVertex(new Vertex(+0.125f * hollowFactorF, -0.1875f * hollowFactorF, 0.0f)); - holeHull.AddVertex(new Vertex(-0.25f * hollowFactorF, -0f * hollowFactorF, 0.0f)); - holeHull.AddVertex(new Vertex(+0.125f * hollowFactorF, +0.1875f * hollowFactorF, 0.0f)); - } - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { - holeHull.AddVertex(new Vertex(-0.500000f * hollowFactorF, 0.000000f * hollowFactorF, 0.0f)); // 180 degrees - holeHull.AddVertex(new Vertex(-0.250000f * hollowFactorF, 0.433013f * hollowFactorF, 0.0f)); // 120 degrees - holeHull.AddVertex(new Vertex(0.250000f * hollowFactorF, 0.433013f * hollowFactorF, 0.0f)); // 60 degrees - holeHull.AddVertex(new Vertex(0.500000f * hollowFactorF, 0.000000f * hollowFactorF, 0.0f)); // 0 degrees - } - else - { - holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, -0.45f * hollowFactorF, 0.0f)); - holeHull.AddVertex(new Vertex(-0.5f * hollowFactorF, -0f * hollowFactorF, 0.0f)); - holeHull.AddVertex(new Vertex(+0.25f * hollowFactorF, +0.45f * hollowFactorF, 0.0f)); - } - } - else if (hollowShape == HollowShape.Square && (primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { - holeHull = new SimpleHull(); - - float hollowFactorF = (float)hollowFactor * 2.0e-5f; - - holeHull.AddVertex(new Vertex(-0.707f * hollowFactorF, 0.0f, 0.0f)); // 180 degrees - holeHull.AddVertex(new Vertex(0.0f, 0.707f * hollowFactorF, 0.0f)); // 120 degrees - holeHull.AddVertex(new Vertex(0.707f * hollowFactorF, 0.0f, 0.0f)); // 60 degrees - } - else - { - holeHull = BuildHoleHull(primShape, primShape.ProfileShape, hollowShape, hollowFactor); - } - - if (holeHull != null) - { - SimpleHull hollowedHull = SimpleHull.SubtractHull(outerHull, holeHull); - - outerHull = hollowedHull; - } - } - - Mesh m = new Mesh(); - - Vertex Seed1 = new Vertex(0.0f, -10.0f, 0.0f); - Vertex Seed2 = new Vertex(-10.0f, 10.0f, 0.0f); - Vertex Seed3 = new Vertex(10.0f, 10.0f, 0.0f); - - m.Add(Seed1); - m.Add(Seed2); - m.Add(Seed3); - - m.Add(new Triangle(Seed1, Seed2, Seed3)); - m.Add(outerHull.getVertices()); - - InsertVertices(m.vertices, 3, m.triangles); - m.DumpRaw(baseDir, primName, "Proto first Mesh"); - - m.Remove(Seed1); - m.Remove(Seed2); - m.Remove(Seed3); - m.DumpRaw(baseDir, primName, "Proto seeds removed"); - - m.RemoveTrianglesOutside(outerHull); - m.DumpRaw(baseDir, primName, "Proto outsides removed"); - - foreach (Triangle t in m.triangles) - t.invertNormal(); - - - float skew = primShape.PathSkew * 0.01f; - float pathScaleX = (float)(200 - primShape.PathScaleX) * 0.01f; - float pathScaleY = (float)(200 - primShape.PathScaleY) * 0.01f; - float profileXComp = pathScaleX * (1.0f - Math.Abs(skew)); - -#if SPAM - //Console.WriteLine("primShape.PathScaleX: " + primShape.PathScaleX.ToString() + " primShape.PathScaleY: " + primShape.PathScaleY.ToString()); - //Console.WriteLine("primShape.PathSkew: " + primShape.PathSkew.ToString() + " primShape.PathRadiusOffset: " + primShape.PathRadiusOffset.ToString() + " primShape.pathRevolutions: " + primShape.PathRevolutions.ToString()); - Console.WriteLine("PathScaleX: " + pathScaleX.ToString() + " pathScaleY: " + pathScaleY.ToString()); - Console.WriteLine("skew: " + skew.ToString() + " profileXComp: " + profileXComp.ToString()); -#endif - - foreach (Vertex v in m.vertices) - if (v != null) - { - v.X *= profileXComp; - v.Y *= pathScaleY; - } - - Extruder extr = new Extruder(); - - extr.size = size; - extr.pathScaleX = pathScaleX; - extr.pathScaleY = pathScaleY; - extr.pathCutBegin = 0.00002f * primShape.PathBegin; - extr.pathCutEnd = 0.00002f * (50000 - primShape.PathEnd); - extr.pathBegin = primShape.PathBegin; - extr.pathEnd = primShape.PathEnd; - extr.skew = skew; - extr.revolutions = 1.0f + (float)primShape.PathRevolutions * 3.0f / 200.0f; - extr.pathTaperX = 0.01f * (float)primShape.PathTaperX; - extr.pathTaperY = 0.01f * (float)primShape.PathTaperY; - - extr.radius = 0.01f * (float)primShape.PathRadiusOffset; - -#if SPAM - //System.Console.WriteLine("primShape.PathBegin: " + primShape.PathBegin.ToString() + " primShape.PathEnd: " + primShape.PathEnd.ToString()); - System.Console.WriteLine("extr.pathCutBegin: " + extr.pathCutBegin.ToString() + " extr.pathCutEnd: " + extr.pathCutEnd.ToString()); - System.Console.WriteLine("extr.revolutions: " + extr.revolutions.ToString()); - - //System.Console.WriteLine("primShape.PathTaperX: " + primShape.PathTaperX.ToString()); - //System.Console.WriteLine("primShape.PathTaperY: " + primShape.PathTaperY.ToString()); - - - //System.Console.WriteLine("primShape.PathRadiusOffset: " + primShape.PathRadiusOffset.ToString()); -#endif - - - - - if (pathShearX != 0) - { - if (pathShearX > 50) - { - // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 - extr.pushX = (((float)(256 - pathShearX) / 100) * -1f); - } - else - { - extr.pushX = (float)pathShearX / 100; - } - } - - if (pathShearY != 0) - { - if (pathShearY > 50) - { - // Complimentary byte. Negative values wrap around the byte. Positive values go up to 50 - extr.pushY = (((float)(256 - pathShearY) / 100) * -1f); - } - else - { - extr.pushY = (float)pathShearY / 100; - } - - } - - extr.twistTop = (float)primShape.PathTwist * (float)Math.PI * 0.02f; - extr.twistBot = (float)primShape.PathTwistBegin * (float)Math.PI * 0.02f; - - Mesh result = extr.ExtrudeCircularPath(m); - result.DumpRaw(baseDir, primName, "Z extruded"); - -#if SPAM - int vCount = 0; - - foreach (Vertex v in result.vertices) - { - if (v != null) - vCount++; - } - - System.Console.WriteLine("Mesh vertex count: " + vCount.ToString()); -#endif - - return result; - } - - public static Vertex midUnitRadialPoint(Vertex a, Vertex b, float radius) - { - Vertex midpoint = new Vertex(a + b) * 0.5f; - return (midpoint.normalize() * radius); - } - - public static void SphereLODTriangle(Vertex a, Vertex b, Vertex c, float diameter, float LOD, Mesh m) - { - Vertex aa = a - b; - Vertex ba = b - c; - Vertex da = c - a; - - if (((aa.length() < LOD) && (ba.length() < LOD) && (da.length() < LOD))) - { - // We don't want duplicate verticies. Duplicates cause the scale algorithm to produce a spikeball - // spikes are novel, but we want ellipsoids. - - if (!m.vertices.Contains(a)) - m.Add(a); - if (!m.vertices.Contains(b)) - m.Add(b); - if (!m.vertices.Contains(c)) - m.Add(c); - - // Add the triangle to the mesh - Triangle t = new Triangle(a, b, c); - m.Add(t); - } - else - { - Vertex ab = midUnitRadialPoint(a, b, diameter); - Vertex bc = midUnitRadialPoint(b, c, diameter); - Vertex ca = midUnitRadialPoint(c, a, diameter); - - // Recursive! Splits the triangle up into 4 smaller triangles - SphereLODTriangle(a, ab, ca, diameter, LOD, m); - SphereLODTriangle(ab, b, bc, diameter, LOD, m); - SphereLODTriangle(ca, bc, c, diameter, LOD, m); - SphereLODTriangle(ab, bc, ca, diameter, LOD, m); - - } - } - private void ReportPrimError(string message, string primName, PrimMesh primMesh) { Console.WriteLine(message); Console.WriteLine("\nPrim Name: " + primName); - Console.WriteLine("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); + Console.WriteLine("****** PrimMesh Parameters ******\n" + primMesh.ParamsToDisplayString()); } public Mesh CreateMeshFromPrimMesher(string primName, PrimitiveBaseShape primShape, PhysicsVector size, float lod) { Mesh mesh = new Mesh(); + PrimMesh primMesh; + PrimMesher.SculptMesh sculptMesh; - float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; - float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; - float pathBegin = (float)primShape.PathBegin * 2.0e-5f; - float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; - float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; - float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; + List coords; + List faces; - float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f; - float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f; - float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f; + Image idata = null; - int sides = 4; - if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) - sides = 3; - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) - sides = 24; - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { // half circle, prim is a sphere - sides = 24; + if (primShape.SculptEntry) + { + if (primShape.SculptData.Length == 0) + return null; - profileBegin = 0.5f * profileBegin + 0.5f; - profileEnd = 0.5f * profileEnd + 0.5f; + try + { + ManagedImage managedImage; // we never use this + OpenJPEG.DecodeToImage(primShape.SculptData, out managedImage, out idata); + } + catch (Exception) + { + System.Console.WriteLine("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed!"); + return null; + } + + PrimMesher.SculptMesh.SculptType sculptType; + switch ((OpenMetaverse.SculptType)primShape.SculptType) + { + case OpenMetaverse.SculptType.Cylinder: + sculptType = PrimMesher.SculptMesh.SculptType.cylinder; + break; + case OpenMetaverse.SculptType.Plane: + sculptType = PrimMesher.SculptMesh.SculptType.plane; + break; + case OpenMetaverse.SculptType.Torus: + sculptType = PrimMesher.SculptMesh.SculptType.torus; + break; + case OpenMetaverse.SculptType.Sphere: + default: + sculptType = PrimMesher.SculptMesh.SculptType.sphere; + break; + } + sculptMesh = new PrimMesher.SculptMesh((Bitmap)idata, sculptType, (int)lod, false); + + idata.Dispose(); + + sculptMesh.DumpRaw(baseDir, primName, "primMesh"); + + sculptMesh.Scale(size.X, size.Y, size.Z); + + coords = sculptMesh.coords; + faces = sculptMesh.faces; } - int hollowSides = sides; - if (primShape.HollowShape == HollowShape.Circle) - hollowSides = 24; - else if (primShape.HollowShape == HollowShape.Square) - hollowSides = 4; - else if (primShape.HollowShape == HollowShape.Triangle) - hollowSides = 3; - - PrimMesh primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); - - primMesh.topShearX = pathShearX; - primMesh.topShearY = pathShearY; - primMesh.pathCutBegin = pathBegin; - primMesh.pathCutEnd = pathEnd; - - if (primShape.PathCurve == (byte)Extrusion.Straight) + else { - primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; - primMesh.twistEnd = primShape.PathTwist * 18 / 10; - primMesh.taperX = pathScaleX; - primMesh.taperY = pathScaleY; + float pathShearX = primShape.PathShearX < 128 ? (float)primShape.PathShearX * 0.01f : (float)(primShape.PathShearX - 256) * 0.01f; + float pathShearY = primShape.PathShearY < 128 ? (float)primShape.PathShearY * 0.01f : (float)(primShape.PathShearY - 256) * 0.01f; + float pathBegin = (float)primShape.PathBegin * 2.0e-5f; + float pathEnd = 1.0f - (float)primShape.PathEnd * 2.0e-5f; + float pathScaleX = (float)(primShape.PathScaleX - 100) * 0.01f; + float pathScaleY = (float)(primShape.PathScaleY - 100) * 0.01f; + + float profileBegin = (float)primShape.ProfileBegin * 2.0e-5f; + float profileEnd = 1.0f - (float)primShape.ProfileEnd * 2.0e-5f; + float profileHollow = (float)primShape.ProfileHollow * 2.0e-5f; + + int sides = 4; + if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) + sides = 3; + else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) + sides = 24; + else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) + { // half circle, prim is a sphere + sides = 24; + + profileBegin = 0.5f * profileBegin + 0.5f; + profileEnd = 0.5f * profileEnd + 0.5f; - if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) - { - ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); - if (profileBegin < 0.0f) profileBegin = 0.0f; - if (profileEnd > 1.0f) profileEnd = 1.0f; } + + int hollowSides = sides; + if (primShape.HollowShape == HollowShape.Circle) + hollowSides = 24; + else if (primShape.HollowShape == HollowShape.Square) + hollowSides = 4; + else if (primShape.HollowShape == HollowShape.Triangle) + hollowSides = 3; + + primMesh = new PrimMesh(sides, profileBegin, profileEnd, profileHollow, hollowSides); + + primMesh.topShearX = pathShearX; + primMesh.topShearY = pathShearY; + primMesh.pathCutBegin = pathBegin; + primMesh.pathCutEnd = pathEnd; + + if (primShape.PathCurve == (byte)Extrusion.Straight) + { + primMesh.twistBegin = primShape.PathTwistBegin * 18 / 10; + primMesh.twistEnd = primShape.PathTwist * 18 / 10; + primMesh.taperX = pathScaleX; + primMesh.taperY = pathScaleY; + + if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) + { + ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); + if (profileBegin < 0.0f) profileBegin = 0.0f; + if (profileEnd > 1.0f) profileEnd = 1.0f; + } #if SPAM Console.WriteLine("****** PrimMesh Parameters (Linear) ******\n" + primMesh.ParamsToDisplayString()); #endif - try - { - primMesh.ExtrudeLinear(); + try + { + primMesh.ExtrudeLinear(); + } + catch (Exception ex) + { + ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); + return null; + } } - catch (Exception ex) + else { - ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); - return null; - } - } - else - { - primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; - primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; - primMesh.radius = 0.01f * primShape.PathRadiusOffset; - primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; - primMesh.skew = 0.01f * primShape.PathSkew; - primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; - primMesh.twistEnd = primShape.PathTwist * 36 / 10; - primMesh.taperX = primShape.PathTaperX * 0.01f; - primMesh.taperY = primShape.PathTaperY * 0.01f; + primMesh.holeSizeX = (200 - primShape.PathScaleX) * 0.01f; + primMesh.holeSizeY = (200 - primShape.PathScaleY) * 0.01f; + primMesh.radius = 0.01f * primShape.PathRadiusOffset; + primMesh.revolutions = 1.0f + 0.015f * primShape.PathRevolutions; + primMesh.skew = 0.01f * primShape.PathSkew; + primMesh.twistBegin = primShape.PathTwistBegin * 36 / 10; + primMesh.twistEnd = primShape.PathTwist * 36 / 10; + primMesh.taperX = primShape.PathTaperX * 0.01f; + primMesh.taperY = primShape.PathTaperY * 0.01f; - if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) - { - ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); - if (profileBegin < 0.0f) profileBegin = 0.0f; - if (profileEnd > 1.0f) profileEnd = 1.0f; - } + if (profileBegin < 0.0f || profileBegin >= profileEnd || profileEnd > 1.0f) + { + ReportPrimError("*** CORRUPT PRIM!! ***", primName, primMesh); + if (profileBegin < 0.0f) profileBegin = 0.0f; + if (profileEnd > 1.0f) profileEnd = 1.0f; + } #if SPAM Console.WriteLine("****** PrimMesh Parameters (Circular) ******\n" + primMesh.ParamsToDisplayString()); #endif - try - { - primMesh.ExtrudeCircular(); - } - catch (Exception ex) - { - ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); - return null; + try + { + primMesh.ExtrudeCircular(); + } + catch (Exception ex) + { + ReportPrimError("Extrusion failure: exception: " + ex.ToString(), primName, primMesh); + return null; + } } + + primMesh.DumpRaw(baseDir, primName, "primMesh"); + + primMesh.Scale(size.X, size.Y, size.Z); + + coords = primMesh.coords; + faces = primMesh.faces; + } - primMesh.DumpRaw(baseDir, primName, "primMesh"); - primMesh.Scale(size.X, size.Y, size.Z); + int numCoords = coords.Count; + int numFaces = faces.Count; - int numCoords = primMesh.coords.Count; - int numFaces = primMesh.faces.Count; - - List coords = primMesh.coords; for (int i = 0; i < numCoords; i++) { Coord c = coords[i]; mesh.vertices.Add(new Vertex(c.X, c.Y, c.Z)); } - List faces = primMesh.faces; List vertices = mesh.vertices; - for (int i = 0; i < numFaces; i++) { Face f = faces[i]; mesh.triangles.Add(new Triangle(vertices[f.v1], vertices[f.v2], vertices[f.v3])); } - //for (int i = 0; i < numFaces; i++) - //{ - // Face f = primMesh.faces[i]; - // Coord vert = primMesh.coords[f.v1]; - // Vertex v1 = new Vertex(vert.X, vert.Y, vert.Z); - // mesh.vertices.Add(v1); - // vert = primMesh.coords[f.v2]; - // Vertex v2 = new Vertex(vert.X, vert.Y, vert.Z); - // mesh.vertices.Add(v2); - // vert = primMesh.coords[f.v3]; - // Vertex v3 = new Vertex(vert.X, vert.Y, vert.Z); - // mesh.vertices.Add(v3); - // mesh.triangles.Add(new Triangle(v1, v2, v3)); - //} - - //mesh.DumpRaw(baseDir, primName, "Mesh"); - - //mesh.primMesh = primMesh; - return mesh; } @@ -1794,83 +360,16 @@ namespace OpenSim.Region.Physics.Meshing if (size.Y < 0.01f) size.Y = 0.01f; if (size.Z < 0.01f) size.Z = 0.01f; -#if SPAM - reportPrimParams(primName, primShape); -#endif - - if (primShape.SculptEntry && primShape.SculptType != (byte)0 && primShape.SculptData.Length > 0) - { - SculptMesh smesh = CreateSculptMesh(primName, primShape, size, lod); - mesh = (Mesh)smesh; - } - - else if (usePrimMesher) - { - mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); - } - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Square) - { - if (primShape.PathCurve == (byte)Extrusion.Straight) - { // its a box - mesh = CreateBoxMesh(primName, primShape, size); - //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); - } - else if (primShape.PathCurve == (byte)Extrusion.Curve1) - { // tube - // do a cylinder for now - mesh = CreateCylinderMesh(primName, primShape, size); - //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); - } - } - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) - { - if (primShape.PathCurve == (byte)Extrusion.Straight) - { - mesh = CreateCylinderMesh(primName, primShape, size); - //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); - } - - // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits - else if (primShape.PathCurve == (byte) Extrusion.Curve1) - { // dahlia's favorite, a torus :) - mesh = CreateCircularPathMesh(primName, primShape, size); - //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod);\ - } - } - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { - if (primShape.PathCurve == (byte)Extrusion.Curve1 || primShape.PathCurve == (byte) Extrusion.Curve2) - { - //mesh = CreateSphereMesh(primName, primShape, size); - mesh = CreateCircularPathMesh(primName, primShape, size); - //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); - } - } - else if ((primShape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) - { - if (primShape.PathCurve == (byte)Extrusion.Straight) - { - mesh = CreatePrismMesh(primName, primShape, size); - //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); - } - else if (primShape.PathCurve == (byte) Extrusion.Curve1) - { // a ring - do a cylinder for now - //mesh = CreateCylinderMesh(primName, primShape, size); - mesh = CreateCircularPathMesh(primName, primShape, size); - //mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); - } - } - else // just do a box - { - mesh = CreateBoxMesh(primName, primShape, size); - } + mesh = CreateMeshFromPrimMesher(primName, primShape, size, lod); if (mesh != null) { if ((!isPhysical) && size.X < minSizeForComplexMesh && size.Y < minSizeForComplexMesh && size.Z < minSizeForComplexMesh) { #if SPAM - Console.WriteLine("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " + minSizeForComplexMesh.ToString() + " - creating simple bounding box" ); + Console.WriteLine("Meshmerizer: prim " + primName + " has a size of " + size.ToString() + " which is below threshold of " + + +minSizeForComplexMesh.ToString() + " - creating simple bounding box" ); #endif mesh = CreateBoundingBoxMesh(mesh); mesh.DumpRaw(baseDir, primName, "Z extruded"); @@ -1884,6 +383,8 @@ namespace OpenSim.Region.Physics.Meshing return mesh; } + + #if SPAM // please dont comment this out until I'm done with this module - dahlia private static void reportPrimParams(string name, PrimitiveBaseShape primShape) diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs index 282bbd5dd7..d79a480a02 100644 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) Contributors, http://opensimulator.org/ + * Copyright (c) Contributors * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without @@ -243,10 +243,11 @@ namespace PrimMesher public int n2; public int n3; - //// UVs - //public int uv1; - //public int uv2; - //public int uv3; + // uvs + public int uv1; + public int uv2; + public int uv3; + public Face(int v1, int v2, int v3) { @@ -260,9 +261,10 @@ namespace PrimMesher this.n2 = 0; this.n3 = 0; - //this.uv1 = 0; - //this.uv2 = 0; - //this.uv3 = 0; + this.uv1 = 0; + this.uv2 = 0; + this.uv3 = 0; + } public Face(int v1, int v2, int v3, int n1, int n2, int n3) @@ -277,9 +279,21 @@ namespace PrimMesher this.n2 = n2; this.n3 = n3; - //this.uv1 = 0; - //this.uv2 = 0; - //this.uv3 = 0; + this.uv1 = 0; + this.uv2 = 0; + this.uv3 = 0; + } + + public Coord SurfaceNormal(List coordList) + { + Coord c1 = coordList[this.v1]; + Coord c2 = coordList[this.v2]; + Coord c3 = coordList[this.v3]; + + Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); + Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); + + return Coord.Cross(edge1, edge2).Normalize(); } } @@ -560,7 +574,7 @@ namespace PrimMesher /// /// generates a profile for extrusion /// - public class Profile + internal class Profile { private const float twoPi = 2.0f * (float)Math.PI; @@ -569,6 +583,7 @@ namespace PrimMesher internal List vertexNormals; internal List us; internal List faceUVs; + internal List faceNumbers; internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); internal Coord cutNormal1 = new Coord(); @@ -578,6 +593,8 @@ namespace PrimMesher internal int numHollowVerts = 0; internal bool calcVertexNormals = false; + internal int bottomFaceNumber = 0; + internal int numPrimFaces = 0; internal Profile() { @@ -586,9 +603,10 @@ namespace PrimMesher this.vertexNormals = new List(); this.us = new List(); this.faceUVs = new List(); + this.faceNumbers = new List(); } - public Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) + internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) { this.calcVertexNormals = calcVertexNormals; this.coords = new List(); @@ -596,6 +614,8 @@ namespace PrimMesher this.vertexNormals = new List(); this.us = new List(); this.faceUVs = new List(); + this.faceNumbers = new List(); + Coord center = new Coord(0.0f, 0.0f, 0.0f); List hollowCoords = new List(); @@ -674,7 +694,7 @@ namespace PrimMesher hollowCoords.Add(newVert); if (this.calcVertexNormals) { - if (sides < 5) + if (hollowSides < 5) hollowNormals.Add(hollowAngles.normals[i].Invert()); else hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); @@ -689,7 +709,7 @@ namespace PrimMesher for (int i = 0; i < numAngles; i++) { - //int iNext = i == numAngles ? i + 1 : 0; + int iNext = i == numAngles ? i + 1 : 0; angle = angles.angles[i]; newVert.X = angle.X * xScale; newVert.Y = angle.Y * yScale; @@ -884,21 +904,46 @@ namespace PrimMesher hollowNormals = null; hollowUs = null; + if (calcVertexNormals) + { // calculate prim face numbers + // I know it's ugly but so is the whole concept of prim face numbers + int faceNum = 1; + int startVert = hasProfileCut && !hasHollow ? 1 : 0; + if (startVert > 0) + this.faceNumbers.Add(0); + for (int i = 0; i < numOuterVerts; i++) + this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); + if (sides > 4) + faceNum++; + if (hasProfileCut) + this.faceNumbers.Add(0); + for (int i = 0; i < numHollowVerts; i++) + this.faceNumbers.Add(faceNum++); + this.bottomFaceNumber = faceNum++; + if (hasHollow && hasProfileCut) + this.faceNumbers.Add(faceNum++); + for (int i = 0; i < this.faceNumbers.Count; i++) + if (this.faceNumbers[i] == 0) + this.faceNumbers[i] = faceNum++; + + this.numPrimFaces = faceNum; + } + } - public void MakeFaceUVs() + internal void MakeFaceUVs() { this.faceUVs = new List(); foreach (Coord c in this.coords) this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); } - public Profile Clone() + internal Profile Clone() { return this.Clone(true); } - public Profile Clone(bool needFaces) + internal Profile Clone(bool needFaces) { Profile clone = new Profile(); @@ -914,6 +959,7 @@ namespace PrimMesher clone.cutNormal1 = this.cutNormal1; clone.cutNormal2 = this.cutNormal2; clone.us.AddRange(this.us); + clone.faceNumbers.AddRange(this.faceNumbers); } clone.numOuterVerts = this.numOuterVerts; clone.numHollowVerts = this.numHollowVerts; @@ -921,12 +967,12 @@ namespace PrimMesher return clone; } - public void AddPos(Coord v) + internal void AddPos(Coord v) { this.AddPos(v.X, v.Y, v.Z); } - public void AddPos(float x, float y, float z) + internal void AddPos(float x, float y, float z) { int i; int numVerts = this.coords.Count; @@ -942,7 +988,7 @@ namespace PrimMesher } } - public void AddRot(Quat q) + internal void AddRot(Quat q) { int i; int numVerts = this.coords.Count; @@ -963,7 +1009,7 @@ namespace PrimMesher } } - public void Scale(float x, float y) + internal void Scale(float x, float y) { int i; int numVerts = this.coords.Count; @@ -981,7 +1027,7 @@ namespace PrimMesher /// /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices /// - public void FlipNormals() + internal void FlipNormals() { int i; int numFaces = this.faces.Count; @@ -1021,7 +1067,7 @@ namespace PrimMesher } } - public void AddValue2FaceVertexIndices(int num) + internal void AddValue2FaceVertexIndices(int num) { int numFaces = this.faces.Count; Face tmpFace; @@ -1036,7 +1082,7 @@ namespace PrimMesher } } - public void AddValue2FaceNormalIndices(int num) + internal void AddValue2FaceNormalIndices(int num) { if (this.calcVertexNormals) { @@ -1054,7 +1100,7 @@ namespace PrimMesher } } - public void DumpRaw(String path, String name, String title) + internal void DumpRaw(String path, String name, String title) { if (path == null) return; @@ -1113,6 +1159,12 @@ namespace PrimMesher private bool normalsProcessed = false; public bool viewerMode = false; + public int numPrimFaces = 0; + + /// + /// Human readable string representation of the parameters used to create a mesh. + /// + /// public string ParamsToDisplayString() { string s = ""; @@ -1141,7 +1193,14 @@ namespace PrimMesher return s; } - + /// + /// Constructs a PrimMesh object and creates the profile for extrusion. + /// + /// + /// + /// + /// + /// public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) { this.coords = new List(); @@ -1174,6 +1233,9 @@ namespace PrimMesher this.hasHollow = (this.hollow > 0.001f); } + /// + /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. + /// public void ExtrudeLinear() { this.coords = new List(); @@ -1248,6 +1310,7 @@ namespace PrimMesher hollow *= 1.414f; Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); + this.numPrimFaces = profile.numPrimFaces; int cut1Vert = -1; int cut2Vert = -1; @@ -1398,7 +1461,7 @@ namespace PrimMesher if (u2 < 0.1f) u2 = 1.0f; - newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; + //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; } newViewerFace1.uv1.U = u1; @@ -1462,6 +1525,8 @@ namespace PrimMesher } } + newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = newLayer.faceNumbers[whichVert]; + this.viewerFaces.Add(newViewerFace1); this.viewerFaces.Add(newViewerFace2); @@ -1492,7 +1557,7 @@ namespace PrimMesher // add the top faces to the viewerFaces list here Coord faceNormal = newLayer.faceNormal; ViewerFace newViewerFace = new ViewerFace(); - newViewerFace.primFaceNumber = 0; + newViewerFace.primFaceNumber = newLayer.bottomFaceNumber; foreach (Face face in newLayer.faces) { newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; @@ -1513,6 +1578,9 @@ namespace PrimMesher } } + /// + /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. + /// public void ExtrudeCircular() { this.coords = new List(); @@ -1615,6 +1683,7 @@ namespace PrimMesher needEndFaces = true; Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, needEndFaces, calcVertexNormals); + this.numPrimFaces = profile.numPrimFaces; int cut1Vert = -1; int cut2Vert = -1; @@ -1787,7 +1856,7 @@ namespace PrimMesher if (u2 < 0.1f) u2 = 1.0f; - newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; + //newViewerFace2.primFaceNumber = newViewerFace1.primFaceNumber = whichVert + 1; } newViewerFace1.uv1.U = u1; @@ -1865,6 +1934,7 @@ namespace PrimMesher } } + newViewerFace1.primFaceNumber = newViewerFace2.primFaceNumber = newLayer.faceNumbers[whichVert]; this.viewerFaces.Add(newViewerFace1); this.viewerFaces.Add(newViewerFace2); @@ -1894,7 +1964,7 @@ namespace PrimMesher // add the bottom faces to the viewerFaces list here Coord faceNormal = newLayer.faceNormal; ViewerFace newViewerFace = new ViewerFace(); - newViewerFace.primFaceNumber = 0; + newViewerFace.primFaceNumber = newLayer.bottomFaceNumber; foreach (Face face in newLayer.faces) { newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; @@ -1932,6 +2002,11 @@ namespace PrimMesher return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); } + /// + /// Calculate the surface normal for a face in the list of faces + /// + /// + /// public Coord SurfaceNormal(int faceIndex) { int numFaces = this.faces.Count; @@ -1941,6 +2016,9 @@ namespace PrimMesher return SurfaceNormal(this.faces[faceIndex]); } + /// + /// Calculate surface normals for all of the faces in the list of faces in this mesh + /// public void CalcNormals() { if (normalsProcessed) @@ -1968,6 +2046,12 @@ namespace PrimMesher } } + /// + /// Adds a value to each XYZ vertex coordinate in the mesh + /// + /// + /// + /// public void AddPos(float x, float y, float z) { int i; @@ -1984,9 +2068,12 @@ namespace PrimMesher } } + /// + /// Rotates the mesh + /// + /// public void AddRot(Quat q) { - Console.WriteLine("AddRot(" + q.ToString() + ")"); int i; int numVerts = this.coords.Count; @@ -2020,6 +2107,12 @@ namespace PrimMesher } + /// + /// Scales the mesh + /// + /// + /// + /// public void Scale(float x, float y, float z) { int i; @@ -2046,6 +2139,12 @@ namespace PrimMesher } + /// + /// Dumps the mesh to a Blender compatible "Raw" format file + /// + /// + /// + /// public void DumpRaw(String path, String name, String title) { if (path == null) diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs index 0dc7ef2028..826030bad2 100644 --- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs +++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs @@ -1,5 +1,5 @@ /* - * Copyright (c) Contributors, http://opensimulator.org/ + * Copyright (c) Contributors * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without @@ -27,314 +27,317 @@ using System; using System.Collections.Generic; +using System.Text; +using System.IO; using System.Drawing; using System.Drawing.Imaging; -using System.Text; -using OpenMetaverse.Imaging; -namespace OpenSim.Region.Physics.Meshing +namespace PrimMesher { - // This functionality based on the XNA SculptPreview by John Hurliman. - public class SculptMesh : Mesh - { - Image idata = null; - Bitmap bLOD = null; - Bitmap bBitmap = null; - Vertex northpole = new Vertex(0, 0, 0); - Vertex southpole = new Vertex(0, 0, 0); + public class SculptMesh + { + public List coords; + public List faces; - private int lod = 32; - private const float RANGE = 128.0f; + public List viewerFaces; + public List normals; + public List uvs; - public SculptMesh(byte[] jpegData, float _lod) + public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; + private const float pixScale = 0.00390625f; // 1.0 / 256 + + private Bitmap ScaleImage(Bitmap srcImage, float scale) { - if (_lod == 2f || _lod == 4f || _lod == 8f || _lod == 16f || _lod == 32f || _lod == 64f) - lod = (int)_lod; + int sourceWidth = srcImage.Width; + int sourceHeight = srcImage.Height; + int sourceX = 0; + int sourceY = 0; - try - { - ManagedImage managedImage; // we never use this - OpenJPEG.DecodeToImage(jpegData, out managedImage, out idata); - //int i = 0; - //i = i / i; - } - catch (Exception) - { - System.Console.WriteLine("[PHYSICS]: Unable to generate a Sculpty physics proxy. Sculpty texture decode failed!"); - return; - } + int destX = 0; + int destY = 0; + int destWidth = (int)(sourceWidth * scale); + int destHeight = (int)(sourceHeight * scale); - if (idata != null) - { - bBitmap = new Bitmap(idata); - if (bBitmap.Width == bBitmap.Height) + Bitmap scaledImage = new Bitmap(destWidth, destHeight, + PixelFormat.Format24bppRgb); + scaledImage.SetResolution(srcImage.HorizontalResolution, + srcImage.VerticalResolution); + + Graphics grPhoto = Graphics.FromImage(scaledImage); + grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; + + grPhoto.DrawImage(srcImage, + new Rectangle(destX, destY, destWidth, destHeight), + new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), + GraphicsUnit.Pixel); + + grPhoto.Dispose(); + return scaledImage; + } + + public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) + { + Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); + SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); + bitmap.Dispose(); + return sculptMesh; + } + + public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) + { + coords = new List(); + faces = new List(); + normals = new List(); + uvs = new List(); + + float sourceScaleFactor = (float)lod / (float)Math.Max(sculptBitmap.Width, sculptBitmap.Height); + bool scaleSourceImage = sourceScaleFactor < 1.0f ? true : false; + + Bitmap bitmap; + if (scaleSourceImage) + bitmap = ScaleImage(sculptBitmap, sourceScaleFactor); + else + bitmap = sculptBitmap; + + viewerFaces = new List(); + + int width = bitmap.Width; + int height = bitmap.Height; + + float widthUnit = 1.0f / width; + float heightUnit = 1.0f / (height - 1); + + int p1, p2, p3, p4; + Color color; + float x, y, z; + + int imageX, imageY; + + if (sculptType == SculptType.sphere) + { // average the top and bottom row pixel values so the resulting vertices appear to converge + int lastRow = height - 1; + int r1 = 0, g1 = 0, b1 = 0; + int r2 = 0, g2 = 0, b2 = 0; + for (imageX = 0; imageX < width; imageX++) { - DoLOD(); + Color c1 = bitmap.GetPixel(imageX, 0); + Color c2 = bitmap.GetPixel(imageX, lastRow); - LoadPoles(); + r1 += c1.R; + g1 += c1.G; + b1 += c1.B; - processSculptTexture(); + r2 += c2.R; + g2 += c2.G; + b2 += c2.B; + } - bLOD.Dispose(); - bBitmap.Dispose(); - idata.Dispose(); + Color newC1 = Color.FromArgb(r1 / width, g1 / width, b1 / width); + Color newC2 = Color.FromArgb(r2 / width, g2 / width, b2 / width); + + for (imageX = 0; imageX < width; imageX++) + { + bitmap.SetPixel(imageX, 0, newC1); + bitmap.SetPixel(imageX, lastRow, newC2); } } - } - - private Vertex ColorToVertex(Color input) - { - return new Vertex( - ((float)input.R - 128) / RANGE, - ((float)input.G - 128) / RANGE, - ((float)input.B - 128) / RANGE); - } - - private void LoadPoles() - { - northpole = new Vertex(0, 0, 0); - for (int x = 0; x < bLOD.Width; x++) - { - northpole += ColorToVertex(GetPixel(0, 0)); - } - northpole /= bLOD.Width; - southpole = new Vertex(0, 0, 0); - for (int x = 0; x < bLOD.Width; x++) - { - //System.Console.WriteLine("Height: " + bLOD.Height.ToString()); - southpole += ColorToVertex(GetPixel(bLOD.Height - 1, (bLOD.Height - 1))); - } - southpole /= bBitmap.Width; - } - private Color GetPixel(int x, int y) - { - return bLOD.GetPixel(x, y); - } + int pixelsAcross = sculptType == SculptType.plane ? width : width + 1; + int pixelsDown = sculptType == SculptType.sphere || sculptType == SculptType.cylinder ? height + 1 : height; - public int LOD - { - get + for (imageY = 0; imageY < pixelsDown; imageY++) { - return (int)Math.Log(Scale, 2); - } - set - { - int power = value; - if (power == 0) - power = 6; - if (power < 2) - power = 2; - if (power > 9) - power = 9; - int t = (int)Math.Pow(2, power); - if (t != Scale) + int rowOffset = imageY * width; + + for (imageX = 0; imageX < pixelsAcross; imageX++) { - lod = t; - } - } - } + /* + * p1-----p2 + * | \ f2 | + * | \ | + * | f1 \| + * p3-----p4 + */ - public int Scale - { - get - { - return lod; - } - } - - private void DoLOD() - { - int x_max = Math.Min(Scale, bBitmap.Width); - int y_max = Math.Min(Scale, bBitmap.Height); - if (bBitmap.Width == x_max && bBitmap.Height == y_max) - bLOD = bBitmap; - - else if (bLOD == null || x_max != bLOD.Width || y_max != bLOD.Height)//don't resize if you don't need to. - { - System.Drawing.Bitmap tile = new System.Drawing.Bitmap(bBitmap.Width * 2, bBitmap.Height, PixelFormat.Format24bppRgb); - System.Drawing.Bitmap tile_LOD = new System.Drawing.Bitmap(x_max * 2, y_max, PixelFormat.Format24bppRgb); - - bLOD = new System.Drawing.Bitmap(x_max, y_max, PixelFormat.Format24bppRgb); - bLOD.SetResolution(bBitmap.HorizontalResolution, bBitmap.VerticalResolution); - - System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(tile); - grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; - - grPhoto.DrawImage(bBitmap, - new System.Drawing.Rectangle(0, 0, bBitmap.Width / 2, bBitmap.Height), - new System.Drawing.Rectangle(bBitmap.Width / 2, 0, bBitmap.Width / 2, bBitmap.Height), - System.Drawing.GraphicsUnit.Pixel); - - grPhoto.DrawImage(bBitmap, - new System.Drawing.Rectangle((3 * bBitmap.Width) / 2, 0, bBitmap.Width / 2, bBitmap.Height), - new System.Drawing.Rectangle(0, 0, bBitmap.Width / 2, bBitmap.Height), - System.Drawing.GraphicsUnit.Pixel); - - grPhoto.DrawImage(bBitmap, - new System.Drawing.Rectangle(bBitmap.Width / 2, 0, bBitmap.Width, bBitmap.Height), - new System.Drawing.Rectangle(0, 0, bBitmap.Width, bBitmap.Height), - System.Drawing.GraphicsUnit.Pixel); - - grPhoto = System.Drawing.Graphics.FromImage(tile_LOD); - //grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear; - grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear; - - grPhoto.DrawImage(tile, - new System.Drawing.Rectangle(0, 0, tile_LOD.Width, tile_LOD.Height), - new System.Drawing.Rectangle(0, 0, tile.Width, tile.Height), - System.Drawing.GraphicsUnit.Pixel); - - grPhoto = System.Drawing.Graphics.FromImage(bLOD); - grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; - - grPhoto.DrawImage(tile_LOD, - new System.Drawing.Rectangle(0, 0, bLOD.Width, bLOD.Height), - new System.Drawing.Rectangle(tile_LOD.Width / 4, 0, tile_LOD.Width / 2, tile_LOD.Height), - System.Drawing.GraphicsUnit.Pixel); - - grPhoto.Dispose(); - tile_LOD.Dispose(); - tile.Dispose(); - } - - } - - public void clearStuff() - { - this.triangles.Clear(); - this.vertices.Clear(); - //normals = new float[0]; - } - - public void processSculptTexture() - { - int x_max = Math.Min(Scale, bBitmap.Width); - int y_max = Math.Min(Scale, bBitmap.Height); - - int COLUMNS = x_max + 1; - - Vertex[] sVertices = new Vertex[COLUMNS * y_max]; - //float[] indices = new float[COLUMNS * (y_max - 1) * 6]; - - for (int y = 0; y < y_max; y++) - { - for (int x = 0; x < x_max; x++) - { - // Create the vertex - Vertex v1 = new Vertex(0,0,0); - - // Create a vertex position from the RGB channels in the current pixel - // int ypos = y * bLOD.Width; - - - if (y == 0) + if (imageX < width) { - v1 = northpole; - } - else if (y == y_max - 1) - { - v1 = southpole; + p4 = rowOffset + imageX; + p3 = p4 - 1; } else { - v1 = ColorToVertex(GetPixel(x, y)); + p4 = rowOffset; // wrap around to beginning + p3 = rowOffset + imageX - 1; } - // Add the vertex for use later - if (!vertices.Contains(v1)) - Add(v1); + p2 = p4 - width; + p1 = p3 - width; - sVertices[y * COLUMNS + x] = v1; - //System.Console.WriteLine("adding: " + v1.ToString()); - } - //Vertex tempVertex = vertices[y * COLUMNS]; - // sVertices[y * COLUMNS + x_max] = tempVertex; - } + color = bitmap.GetPixel(imageX == width ? 0 : imageX, imageY == height ? height - 1 : imageY); - // Create the Triangles - //int i = 0; + x = (color.R - 128) * pixScale; + y = (color.G - 128) * pixScale; + z = (color.B - 128) * pixScale; - for (int y = 0; y < y_max - 1; y++) - { - int x; - - for (x = 0; x < x_max; x++) - { - Vertex vt11 = sVertices[(y * COLUMNS + x)]; - Vertex vt12 = sVertices[(y * COLUMNS + (x + 1))]; - Vertex vt13 = sVertices[((y + 1) * COLUMNS + (x + 1))]; - if (vt11 != null && vt12 != null && vt13 != null) + Coord c = new Coord(x, y, z); + this.coords.Add(c); + if (viewerMode) { - if (vt11 != vt12 && vt11 != vt13 && vt12 != vt13) - { - Triangle tri1 = new Triangle(vt11, vt12, vt13); - //indices[i++] = (ushort)(y * COLUMNS + x); - //indices[i++] = (ushort)(y * COLUMNS + (x + 1)); - //indices[i++] = (ushort)((y + 1) * COLUMNS + (x + 1)); - Add(tri1); - } + this.normals.Add(new Coord()); + this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); } - Vertex vt21 = sVertices[(y * COLUMNS + x)]; - Vertex vt22 = sVertices[((y + 1) * COLUMNS + (x + 1))]; - Vertex vt23 = sVertices[((y + 1) * COLUMNS + x)]; - if (vt21 != null && vt22 != null && vt23 != null) + if (imageY > 0 && imageX > 0) { - if (vt21.Equals(vt22, 0.022f) || vt21.Equals(vt23, 0.022f) || vt22.Equals(vt23, 0.022f)) + Face f1, f2; + + if (viewerMode) { + f1 = new Face(p1, p3, p4, p1, p3, p4); + f1.uv1 = p1; + f1.uv2 = p3; + f1.uv3 = p4; + + f2 = new Face(p1, p4, p2, p1, p4, p2); + f2.uv1 = p1; + f2.uv2 = p4; + f2.uv3 = p2; } else { - Triangle tri2 = new Triangle(vt21, vt22, vt23); - //indices[i++] = (ushort)(y * COLUMNS + x); - //indices[i++] = (ushort)((y + 1) * COLUMNS + (x + 1)); - //indices[i++] = (ushort)((y + 1) * COLUMNS + x); - Add(tri2); + f1 = new Face(p1, p3, p4); + f2 = new Face(p1, p4, p2); } + + this.faces.Add(f1); + this.faces.Add(f2); } - } - //Vertex vt31 = sVertices[(y * x_max + x)]; - //Vertex vt32 = sVertices[(y * x_max + 0)]; - //Vertex vt33 = sVertices[((y + 1) * x_max + 0)]; - //if (vt31 != null && vt32 != null && vt33 != null) - //{ - //if (vt31.Equals(vt32, 0.022f) || vt31.Equals(vt33, 0.022f) || vt32.Equals(vt33, 0.022f)) - //{ - //} - //else - //{ - //Triangle tri3 = new Triangle(vt31, vt32, vt33); - // Wrap the last cell in the row around - //indices[i++] = (ushort)(y * x_max + x); //a - //indices[i++] = (ushort)(y * x_max + 0); //b - //indices[i++] = (ushort)((y + 1) * x_max + 0); //c - //Add(tri3); - // } - //} - - //Vertex vt41 = sVertices[(y * x_max + x)]; - //Vertex vt42 = sVertices[((y + 1) * x_max + 0)]; - //Vertex vt43 = sVertices[((y + 1) * x_max + x)]; - //if (vt41 != null && vt42 != null && vt43 != null) - //{ - //if (vt41.Equals(vt42, 0.022f) || vt31.Equals(vt43, 0.022f) || vt32.Equals(vt43, 0.022f)) - //{ - //} - // else - // { - //Triangle tri4 = new Triangle(vt41, vt42, vt43); - //indices[i++] = (ushort)(y * x_max + x); //a - //indices[i++] = (ushort)((y + 1) * x_max + 0); //b - //indices[i++] = (ushort)((y + 1) * x_max + x); //c - //Add(tri4); - //} - //} - } + + if (scaleSourceImage) + bitmap.Dispose(); + + if (viewerMode) + { // compute vertex normals by summing all the surface normals of all the triangles sharing + // each vertex and then normalizing + int numFaces = this.faces.Count; + for (int i = 0; i < numFaces; i++) + { + Face face = this.faces[i]; + Coord surfaceNormal = face.SurfaceNormal(this.coords); + this.normals[face.v1] += surfaceNormal; + this.normals[face.v2] += surfaceNormal; + this.normals[face.v3] += surfaceNormal; + } + + int numCoords = this.coords.Count; + for (int i = 0; i < numCoords; i++) + this.coords[i].Normalize(); + + if (sculptType != SculptType.plane) + { // blend the vertex normals at the cylinder seam + pixelsAcross = width + 1; + for (imageY = 0; imageY < height; imageY++) + { + int rowOffset = imageY * pixelsAcross; + + this.normals[rowOffset] = this.normals[rowOffset + width - 1] = (this.normals[rowOffset] + this.normals[rowOffset + width - 1]).Normalize(); + } + } + + foreach (Face face in this.faces) + { + ViewerFace vf = new ViewerFace(0); + vf.v1 = this.coords[face.v1]; + vf.v2 = this.coords[face.v2]; + vf.v3 = this.coords[face.v3]; + + vf.n1 = this.normals[face.n1]; + vf.n2 = this.normals[face.n2]; + vf.n3 = this.normals[face.n3]; + + vf.uv1 = this.uvs[face.uv1]; + vf.uv2 = this.uvs[face.uv2]; + vf.uv3 = this.uvs[face.uv3]; + + this.viewerFaces.Add(vf); + } + } + } + + public void AddRot(Quat q) + { + int i; + int numVerts = this.coords.Count; + + for (i = 0; i < numVerts; i++) + this.coords[i] *= q; + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= q; + v.v2 *= q; + v.v3 *= q; + + v.n1 *= q; + v.n2 *= q; + v.n3 *= q; + + this.viewerFaces[i] = v; + } + } + } + + public void Scale(float x, float y, float z) + { + int i; + int numVerts = this.coords.Count; + //Coord vert; + + Coord m = new Coord(x, y, z); + for (i = 0; i < numVerts; i++) + this.coords[i] *= m; + + if (this.viewerFaces != null) + { + int numViewerFaces = this.viewerFaces.Count; + for (i = 0; i < numViewerFaces; i++) + { + ViewerFace v = this.viewerFaces[i]; + v.v1 *= m; + v.v2 *= m; + v.v3 *= m; + this.viewerFaces[i] = v; + } + } + } + + public void DumpRaw(String path, String name, String title) + { + if (path == null) + return; + String fileName = name + "_" + title + ".raw"; + String completePath = Path.Combine(path, fileName); + StreamWriter sw = new StreamWriter(completePath); + + for (int i = 0; i < this.faces.Count; i++) + { + string s = this.coords[this.faces[i].v1].ToString(); + s += " " + this.coords[this.faces[i].v2].ToString(); + s += " " + this.coords[this.faces[i].v3].ToString(); + + sw.WriteLine(s); + } + + sw.Close(); } } } diff --git a/OpenSim/Region/Physics/Meshing/SimpleHull.cs b/OpenSim/Region/Physics/Meshing/SimpleHull.cs deleted file mode 100644 index 5eeadae132..0000000000 --- a/OpenSim/Region/Physics/Meshing/SimpleHull.cs +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.Meshing -{ - // A simple hull is a set of vertices building up to simplices that border a region - // The word simple referes to the fact, that this class assumes, that all simplices - // do not intersect - // Simple hulls can be added and subtracted. - // Vertices can be checked to lie inside a hull - // Also note, that the sequence of the vertices is important and defines if the region that - // is defined by the hull lies inside or outside the simplex chain - public class SimpleHull - { - //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - - private List vertices = new List(); - private List holeVertices = new List(); // Only used, when the hull is hollow - - // Adds a vertex to the end of the list - public void AddVertex(Vertex v) - { - vertices.Add(v); - } - - public override String ToString() - { - String result = String.Empty; - foreach (Vertex v in vertices) - { - result += "b:" + v.ToString() + "\n"; - } - - return result; - } - - - public List getVertices() - { - List newVertices = new List(); - - newVertices.AddRange(vertices); - newVertices.Add(null); - newVertices.AddRange(holeVertices); - - return newVertices; - } - - public SimpleHull Clone() - { - SimpleHull result = new SimpleHull(); - foreach (Vertex v in vertices) - { - result.AddVertex(v.Clone()); - } - - foreach (Vertex v in holeVertices) - { - result.holeVertices.Add(v.Clone()); - } - - return result; - } - - public bool IsPointIn(Vertex v1) - { - int iCounter = 0; - List simplices = buildSimplexList(); - foreach (Simplex s in simplices) - { - // Send a ray along the positive X-Direction - // Note, that this direction must correlate with the "below" interpretation - // of handling for the special cases below - PhysicsVector intersection = s.RayIntersect(v1, new PhysicsVector(1.0f, 0.0f, 0.0f), true); - - if (intersection == null) - continue; // No intersection. Done. More tests to follow otherwise - - // Did we hit the end of a simplex? - // Then this can be one of two special cases: - // 1. we go through a border exactly at a joint - // 2. we have just marginally touched a corner - // 3. we can slide along a border - // Solution: If the other vertex is "below" the ray, we don't count it - // Thus corners pointing down are counted twice, corners pointing up are not counted - // borders are counted once - if (intersection.IsIdentical(s.v1, 0.001f)) - { - if (s.v2.Y < v1.Y) - continue; - } - // Do this for the other vertex two - if (intersection.IsIdentical(s.v2, 0.001f)) - { - if (s.v1.Y < v1.Y) - continue; - } - iCounter++; - } - - return iCounter%2 == 1; // Point is inside if the number of intersections is odd - } - - public bool containsPointsFrom(SimpleHull otherHull) - { - foreach (Vertex v in otherHull.vertices) - { - if (IsPointIn(v)) - return true; - } - - return false; - } - - - private List buildSimplexList() - { - List result = new List(); - - // Not asserted but assumed: at least three vertices - for (int i = 0; i < vertices.Count - 1; i++) - { - Simplex s = new Simplex(vertices[i], vertices[i + 1]); - result.Add(s); - } - Simplex s1 = new Simplex(vertices[vertices.Count - 1], vertices[0]); - result.Add(s1); - - if (holeVertices.Count == 0) - return result; - - // Same here. At least three vertices in hole assumed - for (int i = 0; i < holeVertices.Count - 1; i++) - { - Simplex s = new Simplex(holeVertices[i], holeVertices[i + 1]); - result.Add(s); - } - - s1 = new Simplex(holeVertices[holeVertices.Count - 1], holeVertices[0]); - result.Add(s1); - return result; - } - -// TODO: unused -// private bool InsertVertex(Vertex v, int iAfter) -// { -// vertices.Insert(iAfter + 1, v); -// return true; -// } - - private Vertex getNextVertex(Vertex currentVertex) - { - int iCurrentIndex; - iCurrentIndex = vertices.IndexOf(currentVertex); - - // Error handling for iCurrentIndex==-1 should go here (and probably never will) - - iCurrentIndex++; - if (iCurrentIndex == vertices.Count) - iCurrentIndex = 0; - - return vertices[iCurrentIndex]; - } - - public Vertex FindVertex(Vertex vBase, float tolerance) - { - foreach (Vertex v in vertices) - { - if (v.IsIdentical(vBase, tolerance)) - return v; - } - - return null; - } - - public void FindIntersection(Simplex s, ref Vertex Intersection, ref Vertex nextVertex) - { - Vertex bestIntersection = null; - float distToV1 = Single.PositiveInfinity; - Simplex bestIntersectingSimplex = null; - - List simple = buildSimplexList(); - foreach (Simplex sTest in simple) - { - PhysicsVector vvTemp = Simplex.Intersect(sTest, s, -.001f, -.001f, 0.999f, .999f); - - Vertex vTemp = null; - if (vvTemp != null) - vTemp = new Vertex(vvTemp); - - if (vTemp != null) - { - PhysicsVector diff = (s.v1 - vTemp); - float distTemp = diff.length(); - - if (bestIntersection == null || distTemp < distToV1) - { - bestIntersection = vTemp; - distToV1 = distTemp; - bestIntersectingSimplex = sTest; - } - } - } - - Intersection = bestIntersection; - if (bestIntersectingSimplex != null) - nextVertex = bestIntersectingSimplex.v2; - else - nextVertex = null; - } - - - public static SimpleHull SubtractHull(SimpleHull baseHull, SimpleHull otherHull) - { - SimpleHull baseHullClone = baseHull.Clone(); - SimpleHull otherHullClone = otherHull.Clone(); - bool intersects = false; - - //m_log.Debug("State before intersection detection"); - //m_log.DebugFormat("The baseHull is:\n{1}", 0, baseHullClone.ToString()); - //m_log.DebugFormat("The otherHull is:\n{1}", 0, otherHullClone.ToString()); - - { - int iBase, iOther; - - // Insert into baseHull - for (iBase = 0; iBase < baseHullClone.vertices.Count; iBase++) - { - int iBaseNext = (iBase + 1)%baseHullClone.vertices.Count; - Simplex sBase = new Simplex(baseHullClone.vertices[iBase], baseHullClone.vertices[iBaseNext]); - - for (iOther = 0; iOther < otherHullClone.vertices.Count; iOther++) - { - int iOtherNext = (iOther + 1)%otherHullClone.vertices.Count; - Simplex sOther = - new Simplex(otherHullClone.vertices[iOther], otherHullClone.vertices[iOtherNext]); - - PhysicsVector intersect = Simplex.Intersect(sBase, sOther, 0.001f, -.001f, 0.999f, 1.001f); - if (intersect != null) - { - Vertex vIntersect = new Vertex(intersect); - baseHullClone.vertices.Insert(iBase + 1, vIntersect); - sBase.v2 = vIntersect; - intersects = true; - } - } - } - } - - //m_log.Debug("State after intersection detection for the base hull"); - //m_log.DebugFormat("The baseHull is:\n{1}", 0, baseHullClone.ToString()); - - { - int iOther, iBase; - - // Insert into otherHull - for (iOther = 0; iOther < otherHullClone.vertices.Count; iOther++) - { - int iOtherNext = (iOther + 1)%otherHullClone.vertices.Count; - Simplex sOther = new Simplex(otherHullClone.vertices[iOther], otherHullClone.vertices[iOtherNext]); - - for (iBase = 0; iBase < baseHullClone.vertices.Count; iBase++) - { - int iBaseNext = (iBase + 1)%baseHullClone.vertices.Count; - Simplex sBase = new Simplex(baseHullClone.vertices[iBase], baseHullClone.vertices[iBaseNext]); - - PhysicsVector intersect = Simplex.Intersect(sBase, sOther, -.001f, 0.001f, 1.001f, 0.999f); - if (intersect != null) - { - Vertex vIntersect = new Vertex(intersect); - otherHullClone.vertices.Insert(iOther + 1, vIntersect); - sOther.v2 = vIntersect; - intersects = true; - } - } - } - } - - //m_log.Debug("State after intersection detection for the base hull"); - //m_log.DebugFormat("The otherHull is:\n{1}", 0, otherHullClone.ToString()); - - bool otherIsInBase = baseHullClone.containsPointsFrom(otherHullClone); - if (!intersects && otherIsInBase) - { - // We have a hole here - baseHullClone.holeVertices = otherHullClone.vertices; - return baseHullClone; - } - - SimpleHull result = new SimpleHull(); - - // Find a good starting Simplex from baseHull - // A good starting simplex is one that is outside otherHull - // Such a simplex must exist, otherwise the result will be empty - Vertex baseStartVertex = null; - { - int iBase; - for (iBase = 0; iBase < baseHullClone.vertices.Count; iBase++) - { - int iBaseNext = (iBase + 1)%baseHullClone.vertices.Count; - Vertex center = new Vertex((baseHullClone.vertices[iBase] + baseHullClone.vertices[iBaseNext])/2.0f); - bool isOutside = !otherHullClone.IsPointIn(center); - if (isOutside) - { - baseStartVertex = baseHullClone.vertices[iBaseNext]; - break; - } - } - } - - - if (baseStartVertex == null) // i.e. no simplex fulfilled the "outside" condition. - // In otherwords, subtractHull completely embraces baseHull - { - return result; - } - - // The simplex that *starts* with baseStartVertex is outside the cutting hull, - // so we can start our walk with the next vertex without loosing a branch - Vertex V1 = baseStartVertex; - bool onBase = true; - - // And here is how we do the magic :-) - // Start on the base hull. - // Walk the vertices in the positive direction - // For each vertex check, whether it is a vertex shared with the other hull - // if this is the case, switch over to walking the other vertex list. - // Note: The other hull *must* go backwards to our starting point (via several orther vertices) - // Thus it is important that the cutting hull has the inverse directional sense than the - // base hull!!!!!!!!! (means if base goes CW around it's center cutting hull must go CCW) - - bool done = false; - while (!done) - { - result.AddVertex(V1); - Vertex nextVertex = null; - if (onBase) - { - nextVertex = otherHullClone.FindVertex(V1, 0.001f); - } - else - { - nextVertex = baseHullClone.FindVertex(V1, 0.001f); - } - - if (nextVertex != null) // A node that represents an intersection - { - V1 = nextVertex; // Needed to find the next vertex on the other hull - onBase = !onBase; - } - - if (onBase) - V1 = baseHullClone.getNextVertex(V1); - else - V1 = otherHullClone.getNextVertex(V1); - - if (V1 == baseStartVertex) - done = true; - } - - //m_log.DebugFormat("The resulting Hull is:\n{1}", 0, result.ToString()); - - return result; - } - } -} diff --git a/OpenSim/Region/Physics/Meshing/Simplex.cs b/OpenSim/Region/Physics/Meshing/Simplex.cs deleted file mode 100644 index aeeef11b46..0000000000 --- a/OpenSim/Region/Physics/Meshing/Simplex.cs +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSim Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using OpenSim.Region.Physics.Manager; - -namespace OpenSim.Region.Physics.Meshing -{ - // A simplex is a section of a straight line. - // It is defined by its endpoints, i.e. by two vertices - // Operation on vertices are - public class Simplex : IComparable - { - public Vertex v1; - public Vertex v2; - - public Simplex(Vertex _v1, Vertex _v2) - { - v1 = _v1; - v2 = _v2; - } - - public int CompareTo(Simplex other) - { - Vertex lv1, lv2, ov1, ov2, temp; - - lv1 = v1; - lv2 = v2; - ov1 = other.v1; - ov2 = other.v2; - - if (lv1 > lv2) - { - temp = lv1; - lv1 = lv2; - lv2 = temp; - } - - if (ov1 > ov2) - { - temp = ov1; - ov1 = ov2; - ov2 = temp; - } - - if (lv1 > ov1) - { - return 1; - } - if (lv1 < ov1) - { - return -1; - } - - if (lv2 > ov2) - { - return 1; - } - if (lv2 < ov2) - { - return -1; - } - - return 0; - } - - private static void intersectParameter(PhysicsVector p1, PhysicsVector r1, PhysicsVector p2, PhysicsVector r2, - ref float lambda, ref float mu) - { - // Intersects two straights - // p1, p2, points on the straight - // r1, r2, directional vectors of the straight. Not necessarily of length 1! - // note, that l, m can be scaled such, that the range 0..1 is mapped to the area between two points, - // thus allowing to decide whether an intersection is between two points - - float r1x = r1.X; - float r1y = r1.Y; - float r2x = r2.X; - float r2y = r2.Y; - - float denom = r1y*r2x - r1x*r2y; - - float p1x = p1.X; - float p1y = p1.Y; - float p2x = p2.X; - float p2y = p2.Y; - - float z1 = -p2x*r2y + p1x*r2y + (p2y - p1y)*r2x; - float z2 = -p2x*r1y + p1x*r1y + (p2y - p1y)*r1x; - - if (denom == 0.0f) // Means the straights are parallel. Either no intersection or an infinite number of them - { - if (z1 == 0.0f) - { -// Means they are identical -> many, many intersections - lambda = Single.NaN; - mu = Single.NaN; - } - else - { - lambda = Single.PositiveInfinity; - mu = Single.PositiveInfinity; - } - return; - } - - - lambda = z1/denom; - mu = z2/denom; - } - - - // Intersects the simplex with another one. - // the borders are used to deal with float inaccuracies - // As a rule of thumb, the borders are - // lowerBorder1 : 0.0 - // lowerBorder2 : 0.0 - // upperBorder1 : 1.0 - // upperBorder2 : 1.0 - // Set these to values near the given parameters (e.g. 0.001 instead of 1 to exclude simplex starts safely, or to -0.001 to include them safely) - public static PhysicsVector Intersect( - Simplex s1, - Simplex s2, - float lowerBorder1, - float lowerBorder2, - float upperBorder1, - float upperBorder2) - { - PhysicsVector firstSimplexDirection = s1.v2 - s1.v1; - PhysicsVector secondSimplexDirection = s2.v2 - s2.v1; - - float lambda = 0.0f; - float mu = 0.0f; - - // Give us the parameters of an intersection. This subroutine does *not* take the constraints - // (intersection must be between v1 and v2 and it must be in the positive direction of the ray) - // into account. We do that afterwards. - intersectParameter(s1.v1, firstSimplexDirection, s2.v1, secondSimplexDirection, ref lambda, ref mu); - - if (Single.IsInfinity(lambda)) // Special case. No intersection at all. directions parallel. - return null; - - if (Single.IsNaN(lambda)) // Special case. many, many intersections. - return null; - - if (lambda > upperBorder1) // We're behind v2 - return null; - - if (lambda < lowerBorder1) - return null; - - if (mu < lowerBorder2) // outside simplex 2 - return null; - - if (mu > upperBorder2) // outside simplex 2 - return null; - - return s1.v1 + lambda*firstSimplexDirection; - } - - // Intersects the simplex with a ray. The ray is defined as all p=origin + lambda*direction - // where lambda >= 0 - public PhysicsVector RayIntersect(Vertex origin, PhysicsVector direction, bool bEndsIncluded) - { - PhysicsVector simplexDirection = v2 - v1; - - float lambda = 0.0f; - float mu = 0.0f; - - // Give us the parameters of an intersection. This subroutine does *not* take the constraints - // (intersection must be between v1 and v2 and it must be in the positive direction of the ray) - // into account. We do that afterwards. - intersectParameter(v1, simplexDirection, origin, direction, ref lambda, ref mu); - - if (Single.IsInfinity(lambda)) // Special case. No intersection at all. directions parallel. - return null; - - if (Single.IsNaN(lambda)) // Special case. many, many intersections. - return null; - - if (mu < 0.0) // We're on the wrong side of the ray - return null; - - if (lambda > 1.0) // We're behind v2 - return null; - - if (lambda == 1.0 && !bEndsIncluded) - return null; // The end of the simplices are not included - - if (lambda < 0.0f) // we're before v1; - return null; - - return v1 + lambda*simplexDirection; - } - } -}