예제 #1
0
        /// <summary>Computes the inverse of the matrix.</summary>
        /// <returns>The inverse matrix</returns>
        public Matrix2D Inverse()
        {
            Matrix2D invMat = new Matrix2D();

            float det = this[0, 0] * this[1, 1] - this[0, 1] * this[1, 0];

            if (Mathf.Approximately(0.0f, det))
            {
                return(zero);
            }

            float invDet = 1.0F / det;

            invMat[0, 0] = this[1, 1] * invDet;
            invMat[0, 1] = -this[0, 1] * invDet;
            invMat[1, 0] = -this[1, 0] * invDet;
            invMat[1, 1] = this[0, 0] * invDet;

            // Do the translation part
            invMat[0, 2] = -(this[0, 2] * invMat[0, 0] + this[1, 2] * invMat[0, 1]);
            invMat[1, 2] = -(this[0, 2] * invMat[1, 0] + this[1, 2] * invMat[1, 1]);

            return(invMat);
        }
        static void GenerateTip(BezierSegment segment, bool atStart, float t, PathEnding ending, float halfThickness, TessellationOptions tessellateOptions, List <Vector2> verts, List <UInt16> inds)
        {
            // The tip includes the vertices at the end itself
            Vector2 tan, nrm;
            var     pos        = VectorUtils.EvalFull(segment, t, out tan, out nrm);
            int     indexStart = verts.Count;

            switch (ending)
            {
            case PathEnding.Chop:
                if (atStart)
                {
                    verts.Add(pos + nrm * halfThickness);
                    verts.Add(pos - nrm * halfThickness);
                }
                else
                {
                    // Not much, path segments are always expected to be generated perpendicular to the path
                    // at the segment point location, so we don't have to do anything for the ending
                }
                break;

            case PathEnding.Square:
                if (atStart)
                {
                    verts.Add(pos + nrm * halfThickness - tan * halfThickness);
                    verts.Add(pos - nrm * halfThickness - tan * halfThickness);
                    verts.Add(pos + nrm * halfThickness);
                    verts.Add(pos - nrm * halfThickness);

                    inds.Add((UInt16)(indexStart + 0));
                    inds.Add((UInt16)(indexStart + 3));
                    inds.Add((UInt16)(indexStart + 1));
                    inds.Add((UInt16)(indexStart + 0));
                    inds.Add((UInt16)(indexStart + 2));
                    inds.Add((UInt16)(indexStart + 3));
                }
                else
                {
                    // Relying on the last two vertices, and just adding two of our own here
                    verts.Add(pos + nrm * halfThickness + tan * halfThickness);
                    verts.Add(pos - nrm * halfThickness + tan * halfThickness);

                    inds.Add((UInt16)(indexStart + 0 - 2));
                    inds.Add((UInt16)(indexStart + 3 - 2));
                    inds.Add((UInt16)(indexStart + 1 - 2));
                    inds.Add((UInt16)(indexStart + 0 - 2));
                    inds.Add((UInt16)(indexStart + 2 - 2));
                    inds.Add((UInt16)(indexStart + 3 - 2));
                }
                break;

            case PathEnding.Round:
                float arcSign     = atStart ? -1 : 1;
                int   arcSegments = CalculateArcSteps(halfThickness, 0, Mathf.PI, tessellateOptions);
                for (int i = 1; i < arcSegments; i++)
                {
                    float angle = Mathf.PI * (i / (float)arcSegments);
                    verts.Add(pos + Matrix2D.RotateLH(angle) * nrm * halfThickness * arcSign);
                }

                if (atStart)
                {
                    // Note how we maintain the last two vertices being setup for connection by the rest of the path vertices
                    int indexTipStart = verts.Count;
                    verts.Add(pos + nrm * halfThickness);
                    verts.Add(pos - nrm * halfThickness);

                    for (int i = 1; i < arcSegments; i++)
                    {
                        inds.Add((UInt16)(indexTipStart + 1));
                        inds.Add((UInt16)(indexStart + i - 1));
                        inds.Add((UInt16)(indexStart + i));
                    }
                }
                else
                {
                    inds.Add((UInt16)(indexStart - 1));
                    inds.Add((UInt16)(indexStart - 2));
                    inds.Add((UInt16)(indexStart + 0));
                    for (int i = 1; i < arcSegments - 1; i++)
                    {
                        inds.Add((UInt16)(indexStart - 1));
                        inds.Add((UInt16)(indexStart + i - 1));
                        inds.Add((UInt16)(indexStart + i));
                    }
                }
                break;

            default:
                System.Diagnostics.Debug.Assert(false);     // Joining has its own function
                break;
            }
        }
        static void GenerateJoining(JoiningInfo joinInfo, PathCorner corner, float halfThickness, float tippedCornerLimit, TessellationOptions tessellateOptions, List <Vector2> verts, List <UInt16> inds)
        {
            // The joining generates the vertices at both ends as well as the joining itself
            if (verts.Count == 0)
            {
                // Starting a path with a joining (meaning a loop)
                verts.Add(joinInfo.RoundPosThickness ? joinInfo.PosThicknessEnd : joinInfo.InnerCornerVertex);
                verts.Add(joinInfo.RoundPosThickness ? joinInfo.InnerCornerVertex : joinInfo.NegThicknessEnd);
            }

            System.Diagnostics.Debug.Assert(verts.Count >= 2);
            int indexStart = verts.Count - 2; // Using the last two vertices

            // Convert a tipped corner to a beveled one if tippedCornerLimit ratio is reached
            if (corner == PathCorner.Tipped && tippedCornerLimit >= 1.0f)
            {
                var theta = Vector2.Angle(-joinInfo.TanAtEnd, joinInfo.TanAtStart) * Mathf.Deg2Rad;
                var ratio = 1.0f / Mathf.Sin(theta / 2.0f);
                if (ratio > tippedCornerLimit)
                {
                    corner = PathCorner.Beveled;
                }
            }

            if (joinInfo.SimpleJoin)
            {
                // TODO
            }
            else if (corner == PathCorner.Tipped)
            {
                verts.Add(joinInfo.PosThicknessClosingPoint);
                verts.Add(joinInfo.NegThicknessClosingPoint);
                verts.Add(joinInfo.RoundPosThickness ? joinInfo.PosThicknessStart : joinInfo.InnerCornerVertex);
                verts.Add(joinInfo.RoundPosThickness ? joinInfo.InnerCornerVertex : joinInfo.NegThicknessStart);

                // Ending to tip
                inds.Add((UInt16)(indexStart + 0));
                inds.Add((UInt16)(indexStart + 3));
                inds.Add((UInt16)(indexStart + 1));
                inds.Add((UInt16)(indexStart + 0));
                inds.Add((UInt16)(indexStart + 2));
                inds.Add((UInt16)(indexStart + 3));

                // Tip to starting
                inds.Add((UInt16)(indexStart + 4));
                inds.Add((UInt16)(indexStart + 3));
                inds.Add((UInt16)(indexStart + 2));
                inds.Add((UInt16)(indexStart + 4));
                inds.Add((UInt16)(indexStart + 5));
                inds.Add((UInt16)(indexStart + 3));

                return;
            }
            else if (corner == PathCorner.Beveled)
            {
                verts.Add(joinInfo.RoundPosThickness ? joinInfo.PosThicknessEnd : joinInfo.InnerCornerVertex);   // 2
                verts.Add(joinInfo.RoundPosThickness ? joinInfo.InnerCornerVertex : joinInfo.NegThicknessEnd);   // 3
                verts.Add(joinInfo.RoundPosThickness ? joinInfo.PosThicknessStart : joinInfo.InnerCornerVertex); // 4
                verts.Add(joinInfo.RoundPosThickness ? joinInfo.InnerCornerVertex : joinInfo.NegThicknessStart); // 5

                // Ending to tip
                inds.Add((UInt16)(indexStart + 0));
                inds.Add((UInt16)(indexStart + 2));
                inds.Add((UInt16)(indexStart + 1));
                inds.Add((UInt16)(indexStart + 1));
                inds.Add((UInt16)(indexStart + 2));
                inds.Add((UInt16)(indexStart + 3));

                // Bevel
                if (joinInfo.RoundPosThickness)
                {
                    inds.Add((UInt16)(indexStart + 2));
                    inds.Add((UInt16)(indexStart + 4));
                    inds.Add((UInt16)(indexStart + 3));
                }
                else
                {
                    inds.Add((UInt16)(indexStart + 3));
                    inds.Add((UInt16)(indexStart + 2));
                    inds.Add((UInt16)(indexStart + 5));
                }

                return;
            }

            if (corner == PathCorner.Round)
            {
                float sweepAngle = Mathf.Acos(Vector2.Dot(joinInfo.NormAtEnd, joinInfo.NormAtStart));
                bool  flipArc    = false;
                if (!PointOnTheLeftOfLine(Vector2.zero, joinInfo.NormAtEnd, joinInfo.NormAtStart))
                {
                    sweepAngle = -sweepAngle;
                    flipArc    = true;
                }

                UInt16 innerCornerVertexIndex = (UInt16)verts.Count;
                verts.Add(joinInfo.InnerCornerVertex);

                int arcSegments = CalculateArcSteps(halfThickness, 0, sweepAngle, tessellateOptions);
                for (int i = 0; i <= arcSegments; i++)
                {
                    float   angle = sweepAngle * (i / (float)arcSegments);
                    Vector2 nrm   = Matrix2D.RotateLH(angle) * joinInfo.NormAtEnd;
                    if (flipArc)
                    {
                        nrm = -nrm;
                    }
                    verts.Add(nrm * halfThickness + joinInfo.JoinPos);

                    if (i == 0)
                    {
                        inds.Add((UInt16)(indexStart + 0));
                        inds.Add((UInt16)(indexStart + 3));
                        inds.Add((UInt16)(indexStart + (joinInfo.RoundPosThickness ? 2 : 1)));

                        inds.Add((UInt16)(indexStart + 0));
                        inds.Add((UInt16)(indexStart + 2));
                        inds.Add((UInt16)(indexStart + (joinInfo.RoundPosThickness ? 1 : 3)));
                    }
                    else
                    {
                        if (joinInfo.RoundPosThickness)
                        {
                            inds.Add((UInt16)(indexStart + i + (flipArc ? 3 : 2)));
                            inds.Add((UInt16)(indexStart + i + (flipArc ? 2 : 3)));
                            inds.Add(innerCornerVertexIndex);
                        }
                        else
                        {
                            inds.Add((UInt16)(indexStart + i + (flipArc ? 3 : 2)));
                            inds.Add((UInt16)(indexStart + i + (flipArc ? 2 : 3)));
                            inds.Add(innerCornerVertexIndex);
                        }
                    }
                }

                // Manually add the last segment, maintain the expected vertex positioning
                int endingVerticesIndex = verts.Count;
                if (joinInfo.RoundPosThickness)
                {
                    verts.Add(joinInfo.PosThicknessStart);
                    verts.Add(joinInfo.InnerCornerVertex);
                }
                else
                {
                    verts.Add(joinInfo.InnerCornerVertex);
                    verts.Add(joinInfo.NegThicknessStart);
                }
                inds.Add((UInt16)(endingVerticesIndex - 1));
                inds.Add((UInt16)(endingVerticesIndex + 0));
                inds.Add(innerCornerVertexIndex);
            }
        }
예제 #4
0
        #pragma warning disable 612, 618 // Silence use of deprecated IDrawable
        private static List <Geometry> TessellateNodeHierarchyRecursive(SceneNode node, TessellationOptions tessellationOptions, Matrix2D worldTransform, float worldOpacity, Dictionary <SceneNode, float> nodeOpacities)
        {
            if (node.Clipper != null)
            {
                VectorClip.PushClip(TraceNodeHierarchyShapes(node.Clipper, tessellationOptions), worldTransform);
            }

            var geoms = new List <Geometry>();

            if (node.Drawables != null)
            {
                // We process the drawables even though they are obsolete, until we remove the IDrawable interface entirely
                foreach (var drawable in node.Drawables)
                {
                    var vectorShape = drawable as Shape;
                    if (vectorShape != null)
                    {
                        bool isConvex = vectorShape.IsConvex && vectorShape.Contours.Length == 1;
                        TessellateShape(vectorShape, geoms, tessellationOptions, isConvex);
                        continue;
                    }

                    var vectorPath = drawable as Path;
                    if (vectorPath != null)
                    {
                        TessellatePath(vectorPath.Contour, vectorPath.PathProps, geoms, tessellationOptions);
                        continue;
                    }

                    var vectorRect = drawable as Rectangle;
                    if (vectorRect != null)
                    {
                        TessellateRectangle(vectorRect, geoms, tessellationOptions);
                        continue;
                    }
                }
            }

            if (node.Shapes != null)
            {
                foreach (var shape in node.Shapes)
                {
                    bool isConvex = shape.IsConvex && shape.Contours.Length == 1;
                    TessellateShape(shape, geoms, tessellationOptions, isConvex);
                }
            }

            foreach (var g in geoms)
            {
                g.Color.a        *= worldOpacity;
                g.WorldTransform  = worldTransform;
                g.UnclippedBounds = Bounds(g.Vertices);

                VectorClip.ClipGeometry(g);
            }

            if (node.Children != null)
            {
                foreach (var child in node.Children)
                {
                    var childOpacity = 1.0f;
                    if (nodeOpacities == null || !nodeOpacities.TryGetValue(child, out childOpacity))
                    {
                        childOpacity = 1.0f;
                    }

                    var transform  = worldTransform * child.Transform;
                    var opacity    = worldOpacity * childOpacity;
                    var childGeoms = TessellateNodeHierarchyRecursive(child, tessellationOptions, transform, opacity, nodeOpacities);

                    geoms.AddRange(childGeoms);
                }
            }

            if (node.Clipper != null)
            {
                VectorClip.PopClip();
            }

            return(geoms);
        }
예제 #5
0
        internal static Vector2[] GenerateShapeUVs(Vector2[] verts, Rect bounds, Matrix2D uvTransform)
        {
            UnityEngine.Profiling.Profiler.BeginSample("GenerateShapeUVs");

            uvTransform =
                Matrix2D.Translate(new Vector2(0, 1)) * Matrix2D.Scale(new Vector2(1.0f, -1.0f)) * // Do 1-uv.y
                uvTransform *
                Matrix2D.Scale(new Vector2(1.0f / bounds.width, 1.0f / bounds.height)) * Matrix2D.Translate(-bounds.position);
            var uvs       = new Vector2[verts.Length];
            int vertCount = verts.Length;

            for (int i = 0; i < vertCount; i++)
            {
                uvs[i] = uvTransform * verts[i];
            }

            UnityEngine.Profiling.Profiler.EndSample();

            return(uvs);
        }
예제 #6
0
        #pragma warning disable 612, 618 // Silence use of deprecated IDrawable
        private static List <Geometry> TessellateNodeHierarchyRecursive(SceneNode node, TessellationOptions tessellationOptions, Matrix2D worldTransform, float worldOpacity, Dictionary <SceneNode, float> nodeOpacities)
        {
            if (node.Clipper != null)
            {
                VectorClip.PushClip(TraceNodeHierarchyShapes(node.Clipper, tessellationOptions), worldTransform);
            }

            var geoms = new List <Geometry>();

            if (node.Shapes != null)
            {
                foreach (var shape in node.Shapes)
                {
                    bool isConvex = shape.IsConvex && shape.Contours.Length == 1;
                    TessellateShape(shape, geoms, tessellationOptions, isConvex);
                }
            }

            foreach (var g in geoms)
            {
                g.Color.a        *= worldOpacity;
                g.WorldTransform  = worldTransform;
                g.UnclippedBounds = Bounds(g.Vertices);

                VectorClip.ClipGeometry(g);
            }

            if (node.Children != null)
            {
                foreach (var child in node.Children)
                {
                    var childOpacity = 1.0f;
                    if (nodeOpacities == null || !nodeOpacities.TryGetValue(child, out childOpacity))
                    {
                        childOpacity = 1.0f;
                    }

                    var transform  = worldTransform * child.Transform;
                    var opacity    = worldOpacity * childOpacity;
                    var childGeoms = TessellateNodeHierarchyRecursive(child, tessellationOptions, transform, opacity, nodeOpacities);

                    geoms.AddRange(childGeoms);
                }
            }

            if (node.Clipper != null)
            {
                VectorClip.PopClip();
            }

            return(geoms);
        }