Example #1
0
        /*public LibTessDotNet.Tess Tesselate(Color color, bool withAntialiasing) {
         *      var tess = new LibTessDotNet.Tess();
         *
         *      for (int i = 0, count = points.Count; i < count; ++i) {
         *              var path = points[i];
         *              var contour = new LibTessDotNet.ContourVertex[path.Count];
         *
         *              for (int j = 0, pathCount = path.Count; j < pathCount; ++j) {
         *                      contour[j].Position = path[j].ToVectorTess();
         *                      contour[j].Data = color;
         *              }
         *
         *              tess.AddContour(contour);
         *      }
         *
         *      tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3, VertexCombine);
         *
         *      return tess;
         * }*/

        static void AddContours(LibTessDotNet.Tess tess, Shape shape, Color color)
        {
            for (int i = 0, count = shape.points.Count; i < count; ++i)
            {
                var path    = shape.points[i];
                var contour = new LibTessDotNet.ContourVertex[path.Count];

                for (int j = 0, pathCount = path.Count; j < pathCount; ++j)
                {
                    contour[j].Position = path[j].ToVectorTess();
                    contour[j].Data     = color;
                }

                tess.AddContour(contour);
            }
        }
Example #2
0
        static void Main(string[] args)
        {
            // Example input data in the form of a star that intersects itself.
            var inputData = new float[] { 0.0f, 3.0f, -1.0f, 0.0f, 1.6f, 1.9f, -1.6f, 1.9f, 1.0f, 0.0f };

            // Create an instance of the tessellator. Can be reused.
            var tess = new LibTessDotNet.Tess();

            // Construct the contour from inputData.
            // A polygon can be composed of multiple contours which are all tessellated at the same time.
            int numPoints = inputData.Length / 2;
            var contour   = new LibTessDotNet.ContourVertex[numPoints];

            for (int i = 0; i < numPoints; i++)
            {
                // NOTE : Z is here for convenience if you want to keep a 3D vertex position throughout the tessellation process but only X and Y are important.
                contour[i].Position = new LibTessDotNet.Vec3 {
                    X = inputData[i * 2], Y = inputData[i * 2 + 1], Z = 0.0f
                };
                // Data can contain any per-vertex data, here a constant color.
                contour[i].Data = Color.Azure;
            }
            // Add the contour with a specific orientation, use "Original" if you want to keep the input orientation.
            tess.AddContour(contour, LibTessDotNet.ContourOrientation.Clockwise);

            // Tessellate!
            // The winding rule determines how the different contours are combined together.
            // See http://www.glprogramming.com/red/chapter11.html (section "Winding Numbers and Winding Rules") for more information.
            // If you want triangles as output, you need to use "Polygons" type as output and 3 vertices per polygon.
            tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3, VertexCombine);

            // Same call but the last callback is optional. Data will be null because no interpolated data would have been generated.
            //tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3); // Some vertices will have null Data in this case.

            Console.WriteLine("Output triangles:");
            int numTriangles = tess.ElementCount;

            for (int i = 0; i < numTriangles; i++)
            {
                var v0 = tess.Vertices[tess.Elements[i * 3]].Position;
                var v1 = tess.Vertices[tess.Elements[i * 3 + 1]].Position;
                var v2 = tess.Vertices[tess.Elements[i * 3 + 2]].Position;
                Console.WriteLine("#{0} ({1:F1},{2:F1}) ({3:F1},{4:F1}) ({5:F1},{6:F1})", i, v0.X, v0.Y, v1.X, v1.Y, v2.X, v2.Y);
            }
            Console.ReadLine();
        }
Example #3
0
        public static bool CreatePolygon(List <List <Vector2> > inputShapes, SVGPaintable paintable, SVGMatrix matrix, out SVGShape layer, out SVGShape antialiasingLayer, bool isStroke = false, bool antialiasing = false)
        {
            layer             = new SVGShape();
            antialiasingLayer = new SVGShape();

            if (inputShapes == null || inputShapes.Count == 0)
            {
                return(false);
            }

            List <List <Vector2> > simplifiedShapes = new List <List <Vector2> >();
            PolyFillType           fillType         = PolyFillType.pftNonZero;

            if (paintable.fillRule == SVGFillRule.EvenOdd)
            {
                fillType = PolyFillType.pftEvenOdd;
            }
            simplifiedShapes = SVGGeom.SimplifyPolygons(inputShapes, fillType);
            if (simplifiedShapes == null || simplifiedShapes.Count == 0)
            {
                return(false);
            }

            AddInputShape(simplifiedShapes);

            Rect bounds   = GetRect(simplifiedShapes);
            Rect viewport = paintable.viewport;

            if (!isStroke)
            {
                switch (paintable.GetPaintType())
                {
                case SVGPaintMethod.SolidFill:
                {
                    layer.type = SVGShapeType.FILL;
                    Color        color     = Color.black;
                    SVGColorType colorType = paintable.fillColor.Value.colorType;
                    if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None)
                    {
                        color.a          *= paintable.fillOpacity;
                        paintable.svgFill = new SVGFill(color);
                    }
                    else
                    {
                        color             = paintable.fillColor.Value.color;
                        color.a          *= paintable.fillOpacity;
                        paintable.svgFill = new SVGFill(color);
                    }

                    paintable.svgFill.fillType = FILL_TYPE.SOLID;
                    if (color.a == 1)
                    {
                        paintable.svgFill.blend = FILL_BLEND.OPAQUE;
                    }
                    else
                    {
                        paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                    }
                }
                break;

                case SVGPaintMethod.LinearGradientFill:
                {
                    layer.type = SVGShapeType.FILL;
                    SVGLinearGradientBrush linearGradBrush = paintable.GetLinearGradientBrush(bounds, matrix, viewport);
                    paintable.svgFill = linearGradBrush.fill;
                }
                break;

                case SVGPaintMethod.RadialGradientFill:
                {
                    layer.type = SVGShapeType.FILL;
                    SVGRadialGradientBrush radialGradBrush = paintable.GetRadialGradientBrush(bounds, matrix, viewport);
                    paintable.svgFill = radialGradBrush.fill;
                }
                break;

                case SVGPaintMethod.ConicalGradientFill:
                {
                    layer.type = SVGShapeType.FILL;
                    SVGConicalGradientBrush conicalGradBrush = paintable.GetConicalGradientBrush(bounds, matrix, viewport);
                    paintable.svgFill = conicalGradBrush.fill;
                }
                break;

                case SVGPaintMethod.PathDraw:
                {
                    layer.type = SVGShapeType.STROKE;
                    Color        color     = Color.black;
                    SVGColorType colorType = paintable.fillColor.Value.colorType;
                    if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None)
                    {
                        color.a          *= paintable.strokeOpacity;
                        paintable.svgFill = new SVGFill(color);
                    }
                    else
                    {
                        color             = paintable.fillColor.Value.color;
                        color.a          *= paintable.strokeOpacity;
                        paintable.svgFill = new SVGFill(color);
                    }

                    paintable.svgFill.fillType = FILL_TYPE.SOLID;
                    if (color.a == 1)
                    {
                        paintable.svgFill.blend = FILL_BLEND.OPAQUE;
                    }
                    else
                    {
                        paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                    }
                }
                break;

                default:
                    break;
                }
            }
            else
            {
                layer.type = SVGShapeType.STROKE;
                Color color = paintable.strokeColor.Value.color;
                color.a          *= paintable.strokeOpacity;
                paintable.svgFill = new SVGFill(color, FILL_BLEND.OPAQUE, FILL_TYPE.SOLID);
                if (color.a != 1f)
                {
                    paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                }
                paintable.svgFill.color = color;
            }

            // Use LibTessDotNet
            if (true)
            {
                LibTessDotNet.Tess            tesselation = new LibTessDotNet.Tess();
                LibTessDotNet.ContourVertex[] path;
                int pathLength;
                for (int i = 0; i < simplifiedShapes.Count; i++)
                {
                    if (simplifiedShapes[i] == null)
                    {
                        continue;
                    }

                    pathLength = simplifiedShapes[i].Count;
                    path       = new LibTessDotNet.ContourVertex[pathLength];
                    Vector2 position;
                    for (int j = 0; j < pathLength; j++)
                    {
                        position         = simplifiedShapes[i][j];
                        path[j].Position = new LibTessDotNet.Vec3 {
                            X = position.x, Y = position.y, Z = 0f
                        };
                    }
                    tesselation.AddContour(path, SVGImporter.LibTessDotNet.ContourOrientation.Clockwise);
                }

                tesselation.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3);
                int meshVertexCount = tesselation.Vertices.Length;
                if (meshVertexCount == 0)
                {
                    return(false);
                }

                int numTriangles = tesselation.ElementCount;
                layer.triangles = new int[numTriangles * 3];
                layer.vertices  = new Vector2[meshVertexCount];

                for (int i = 0; i < numTriangles; i++)
                {
                    layer.triangles[i * 3]     = tesselation.Elements[i * 3];
                    layer.triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1];
                    layer.triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2];
                }

                for (int i = 0; i < meshVertexCount; i++)
                {
                    layer.vertices[i] = new Vector2(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y) * SVGAssetImport.meshScale;
                }
            }

            /*
             * else {
             *  // Use Triangle.net library
             *  SVGImporter.TriangleNet.Mesh triangleMesh = new SVGImporter.TriangleNet.Mesh();
             *  SVGImporter.TriangleNet.Geometry.InputGeometry triangleInput = new SVGImporter.TriangleNet.Geometry.InputGeometry();
             *
             *  int pathLength, m = 0;
             *  for(int i = 0; i < simplifiedShapes.Count; i++)
             *  {
             *      if(simplifiedShapes[i] == null)
             *          continue;
             *
             *      pathLength = simplifiedShapes[i].Count;
             *      Vector2 position;
             *      for(int j = 0; j < pathLength; j++)
             *      {
             *          triangleInput.AddPoint(simplifiedShapes[i][j].x, simplifiedShapes[i][j].y);
             *      }
             *  }
             *
             *  triangleMesh.Triangulate(triangleInput);
             *
             *  int totalVertices = triangleMesh.vertices.Count;
             *  layer.vertices = new Vector2[totalVertices];
             *  for(int i = 0; i < totalVertices; i++)
             *  {
             *      layer.vertices[i].x = (float)triangleMesh.vertices[i].x * SVGAssetImport.meshScale;
             *      layer.vertices[i].y = (float)triangleMesh.vertices[i].y * SVGAssetImport.meshScale;
             *  }
             *
             *  int totalTriangles = triangleMesh.triangles.Count;
             *  layer.triangles = new int[totalTriangles * 3];
             *  int ti = 0;
             *  for(int i = 0; i < totalTriangles; i++)
             *  {
             *      ti = i * 3;
             *      layer.triangles[ti] = triangleMesh.triangles[i].P0;
             *      layer.triangles[ti + 1] = triangleMesh.triangles[i].P1;
             *      layer.triangles[ti + 2] = triangleMesh.triangles[i].P2;
             *  }
             * }
             */

            layer.fill         = paintable.svgFill;
            layer.fill.opacity = paintable.opacity;
            if (layer.fill.opacity < 1f && layer.fill.blend == FILL_BLEND.OPAQUE)
            {
                layer.fill.blend = FILL_BLEND.ALPHA_BLENDED;
            }

            if (layer.fill.fillType == FILL_TYPE.GRADIENT && layer.fill.gradientColors != null)
            {
                layer.fill.color = Color.white;
            }
            else if (layer.fill.fillType == FILL_TYPE.TEXTURE)
            {
                layer.fill.color = Color.white;
            }

            viewport.x         *= SVGAssetImport.meshScale;
            viewport.y         *= SVGAssetImport.meshScale;
            viewport.size      *= SVGAssetImport.meshScale;
            layer.fill.viewport = viewport;

            SVGMatrix scaleMatrix = SVGMatrix.identity.Scale(SVGAssetImport.meshScale);

            layer.fill.transform = scaleMatrix.Multiply(layer.fill.transform);
            layer.fill.transform = layer.fill.transform.Multiply(scaleMatrix.Inverse());

            Vector2 boundsMin = bounds.min * SVGAssetImport.meshScale;
            Vector2 boundsMax = bounds.max * SVGAssetImport.meshScale;

            layer.bounds = new Rect(boundsMin.x,
                                    boundsMin.y,
                                    boundsMax.x - boundsMin.x,
                                    boundsMax.y - boundsMin.y);

            if (antialiasing)
            {
                if (CreateAntialiasing(simplifiedShapes, out antialiasingLayer, Color.white, -1f, ClosePathRule.ALWAYS))
                {
                    int verticesLength = antialiasingLayer.vertices.Length;
                    for (int i = 0; i < verticesLength; i++)
                    {
                        antialiasingLayer.vertices[i] *= SVGAssetImport.meshScale;
                    }
                    antialiasingLayer.type = SVGShapeType.ANTIALIASING;
                    antialiasingLayer.RecalculateBounds();
                    antialiasingLayer.fill       = layer.fill.Clone();
                    antialiasingLayer.fill.blend = FILL_BLEND.ALPHA_BLENDED;
                }
            }

            return(true);
        }
        public static void TesselateStroke(List<List<Vector2>> inputShapes, Color32 color, out List<List<Vector2>> simplifiedShapes, out Vector3[] vertices, out int[] triangles, out Color32[] colors32)
        {
            simplifiedShapes = null;
            vertices = null;
            triangles = null;
            colors32 = null;

            if(inputShapes == null || inputShapes.Count == 0) return;
            
            int i, j;
            
            simplifiedShapes = new List<List<Vector2>>();
            
            PolyFillType fillType = PolyFillType.pftNonZero;
            
            for(i = 0; i < inputShapes.Count; i++)
            {
                if(inputShapes[i] == null || inputShapes.Count == 0)
                    continue;
                
                List<List<Vector2>> output = SVGGeom.SimplifyPolygon(inputShapes[i], fillType);
                if(output == null || output.Count == 0)
                {
                    simplifiedShapes.Add(inputShapes[i]);
                } else {
                    simplifiedShapes.AddRange(output);
                }
            }
            
            LibTessDotNet.Tess tesselation = new LibTessDotNet.Tess();
            
            LibTessDotNet.ContourVertex[] path;
            for(i = 0; i < simplifiedShapes.Count; i++)
            {
                if(simplifiedShapes[i] == null || simplifiedShapes[i].Count < 2)
                    continue;
                
                path = new LibTessDotNet.ContourVertex[simplifiedShapes[i].Count];
                for(j = 0; j < simplifiedShapes[i].Count; j++)
                {
                    path[j].Position = new LibTessDotNet.Vec3{X = simplifiedShapes[i][j].x, Y = simplifiedShapes[i][j].y, Z = 0f };
                }
                tesselation.AddContour(path);
            }
            
            tesselation.Tessellate(LibTessDotNet.WindingRule.Positive, LibTessDotNet.ElementType.Polygons, 3);
            if(tesselation.Vertices == null || tesselation.Vertices.Length == 0) return;
            
            Mesh mesh = new Mesh();
            
            int numVertices = tesselation.Vertices.Length;
            int numTriangles = tesselation.ElementCount * 3;
            
            triangles = new int[numTriangles];
            vertices = new Vector3[numVertices];
            colors32 = new Color32[numVertices];
            
            for(i = 0; i < numVertices; i++)
            {
                vertices[i] = new Vector3(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y, 0f);
                colors32[i] = color;
            }
            for (i = 0; i < numTriangles; i += 3)
            {
                triangles[i] = tesselation.Elements[i];
                triangles[i + 1] = tesselation.Elements[i + 1];
                triangles[i + 2] = tesselation.Elements[i + 2];
            }
        }
Example #5
0
        public static Mesh CreatePolygon(List <List <Vector2> > inputShapes, SVGPaintable paintable, SVGMatrix matrix, out Mesh antialiasingMesh)
        {
            antialiasingMesh = null;
            if (inputShapes == null || inputShapes.Count == 0)
            {
                return(null);
            }

            List <List <Vector2> > simplifiedShapes = new List <List <Vector2> >();

            PolyFillType fillType = PolyFillType.pftNonZero;

            if (paintable.fillRule == SVGFillRule.EvenOdd)
            {
                fillType = PolyFillType.pftEvenOdd;
            }

            simplifiedShapes = SVGGeom.SimplifyPolygons(inputShapes, fillType);
            if (simplifiedShapes == null || simplifiedShapes.Count == 0)
            {
                return(null);
            }

            AddInputShape(simplifiedShapes);

            Rect bounds = GetRect(simplifiedShapes);

            switch (paintable.GetPaintType())
            {
            case SVGPaintMethod.SolidGradientFill:
            {
                Color        color     = Color.black;
                SVGColorType colorType = paintable.fillColor.Value.colorType;
                if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None)
                {
                    color.a          *= paintable.fillOpacity;
                    paintable.svgFill = new SVGFill(color);
                }
                else
                {
                    color             = paintable.fillColor.Value.color;
                    color.a          *= paintable.fillOpacity;
                    paintable.svgFill = new SVGFill(color);
                }

                paintable.svgFill.fillType = FILL_TYPE.SOLID;
                if (color.a == 1)
                {
                    paintable.svgFill.blend = FILL_BLEND.OPAQUE;
                }
                else
                {
                    paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                }
            }
            break;

            case SVGPaintMethod.LinearGradientFill:
            {
                SVGLinearGradientBrush linearGradBrush = paintable.GetLinearGradientBrush(bounds, matrix);
                paintable.svgFill = linearGradBrush.fill;
            }
            break;

            case SVGPaintMethod.RadialGradientFill:
            {
                SVGRadialGradientBrush radialGradBrush = paintable.GetRadialGradientBrush(bounds, matrix);
                paintable.svgFill = radialGradBrush.fill;
            }
            break;

            case SVGPaintMethod.ConicalGradientFill:
            {
                SVGConicalGradientBrush conicalGradBrush = paintable.GetConicalGradientBrush(bounds, matrix);
                paintable.svgFill = conicalGradBrush.fill;
            }
            break;

            case SVGPaintMethod.PathDraw:
            {
                Color        color     = Color.black;
                SVGColorType colorType = paintable.fillColor.Value.colorType;
                if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None)
                {
                    color.a          *= paintable.strokeOpacity;
                    paintable.svgFill = new SVGFill(color);
                }
                else
                {
                    color             = paintable.fillColor.Value.color;
                    color.a          *= paintable.strokeOpacity;
                    paintable.svgFill = new SVGFill(color);
                }

                paintable.svgFill.fillType = FILL_TYPE.SOLID;
                if (color.a == 1)
                {
                    paintable.svgFill.blend = FILL_BLEND.OPAQUE;
                }
                else
                {
                    paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                }
            }
            break;

            default:
                break;
            }

            LibTessDotNet.Tess            tesselation = new LibTessDotNet.Tess();
            LibTessDotNet.ContourVertex[] path;
            int pathLength;

            for (int i = 0; i < simplifiedShapes.Count; i++)
            {
                if (simplifiedShapes[i] == null)
                {
                    continue;
                }

                pathLength = simplifiedShapes[i].Count;
                path       = new LibTessDotNet.ContourVertex[pathLength];
                Vector2 position;
                for (int j = 0; j < pathLength; j++)
                {
                    position         = simplifiedShapes[i][j];
                    path[j].Position = new LibTessDotNet.Vec3 {
                        X = position.x, Y = position.y, Z = 0f
                    };
                }
                tesselation.AddContour(path);
            }

            tesselation.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3);

            Mesh mesh            = new Mesh();
            int  meshVertexCount = tesselation.Vertices.Length;

            Vector3[] vertices = new Vector3[meshVertexCount];
            Vector2[] uv       = null;
            Vector2[] uv2      = null;

            for (int i = 0; i < meshVertexCount; i++)
            {
                vertices[i] = new Vector3(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y, 0f);
            }

            int numTriangles = tesselation.ElementCount;

            int[] triangles = new int[numTriangles * 3];
            for (int i = 0; i < numTriangles; i++)
            {
                triangles[i * 3]     = tesselation.Elements[i * 3];
                triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1];
                triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2];
            }

            SVGFill svgFill   = paintable.svgFill;
            Color32 fillColor = Color.white;

            if (svgFill.fillType != FILL_TYPE.GRADIENT && svgFill.gradientColors == null)
            {
                fillColor = svgFill.color;
            }

            antialiasingMesh = CreateAntialiasing(simplifiedShapes, fillColor, -SVGAssetImport.antialiasingWidth, false, SVGImporter.Utils.ClosePathRule.ALWAYS);

            Color32[] colors32 = new Color32[meshVertexCount];

            for (int i = 0; i < meshVertexCount; i++)
            {
                colors32 [i].r = fillColor.r;
                colors32 [i].g = fillColor.g;
                colors32 [i].b = fillColor.b;
                colors32 [i].a = fillColor.a;
            }

            if (antialiasingMesh != null)
            {
                Vector3[] antialiasingVertices = antialiasingMesh.vertices;
                Vector2[] antialiasingUV       = antialiasingMesh.uv;
                Vector2[] antialiasingUV2      = antialiasingMesh.uv2;
                WriteUVGradientCoordinates(ref antialiasingUV, antialiasingVertices, paintable, bounds);
                WriteUVGradientIndexType(ref antialiasingUV2, antialiasingVertices.Length, paintable);
                antialiasingMesh.uv  = antialiasingUV;
                antialiasingMesh.uv2 = antialiasingUV2;
            }

            WriteUVGradientCoordinates(ref uv, vertices, paintable, bounds);
            WriteUVGradientIndexType(ref uv2, meshVertexCount, paintable);

            mesh.vertices  = vertices;
            mesh.triangles = triangles;
            if (colors32 != null)
            {
                mesh.colors32 = colors32;
            }
            if (uv != null)
            {
                mesh.uv = uv;
            }
            if (uv2 != null)
            {
                mesh.uv2 = uv2;
            }

            return(mesh);
        }
        public static Mesh CreatePolygon(List<List<Vector2>> inputShapes, SVGPaintable paintable, SVGMatrix matrix, out Mesh antialiasingMesh)
        {   
            antialiasingMesh = null;
            if(inputShapes == null || inputShapes.Count == 0)
            {
                return null;
            }

            List<List<Vector2>> simplifiedShapes = new List<List<Vector2>>();

            PolyFillType fillType = PolyFillType.pftNonZero;
            if(paintable.fillRule == SVGFillRule.EvenOdd) { fillType = PolyFillType.pftEvenOdd; }

            simplifiedShapes = SVGGeom.SimplifyPolygons(inputShapes, fillType);
            if(simplifiedShapes == null || simplifiedShapes.Count == 0) return null;

            AddInputShape(simplifiedShapes);

            Rect bounds = GetRect(simplifiedShapes);

            switch (paintable.GetPaintType())
            {
                case SVGPaintMethod.SolidGradientFill:
                {
                    Color color = Color.black;
                    SVGColorType colorType = paintable.fillColor.Value.colorType;
                    if(colorType == SVGColorType.Unknown || colorType == SVGColorType.None)
                    {
                        color.a *= paintable.fillOpacity;
                        paintable.svgFill = new SVGFill(color);
                    } else {
                        color = paintable.fillColor.Value.color;
                        color.a *= paintable.fillOpacity; 
                        paintable.svgFill = new SVGFill(color);
                    }
                    
                    paintable.svgFill.fillType = FILL_TYPE.SOLID;
                    if(color.a == 1)
                    {
                        paintable.svgFill.blend = FILL_BLEND.OPAQUE;
                    } else {
                        paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                    }
                }
                    break;
                case SVGPaintMethod.LinearGradientFill:      
                {
                    SVGLinearGradientBrush linearGradBrush = paintable.GetLinearGradientBrush(bounds, matrix);
                    paintable.svgFill = linearGradBrush.fill;
                }
                    break;
                case SVGPaintMethod.RadialGradientFill:
                {
                    SVGRadialGradientBrush radialGradBrush = paintable.GetRadialGradientBrush(bounds, matrix);
                    paintable.svgFill = radialGradBrush.fill;
                }
                    break;
                case SVGPaintMethod.ConicalGradientFill:
                {
                    SVGConicalGradientBrush conicalGradBrush = paintable.GetConicalGradientBrush(bounds, matrix);
                    paintable.svgFill = conicalGradBrush.fill;
                }
                    break;
                case SVGPaintMethod.PathDraw:  
                {
                    Color color = Color.black;
                    SVGColorType colorType = paintable.fillColor.Value.colorType;
                    if(colorType == SVGColorType.Unknown || colorType == SVGColorType.None)
                    {
                        color.a *= paintable.strokeOpacity;
                        paintable.svgFill = new SVGFill(color);
                    } else {
                        color = paintable.fillColor.Value.color;
                        color.a *= paintable.strokeOpacity;
                        paintable.svgFill = new SVGFill(color);
                    }
                    
                    paintable.svgFill.fillType = FILL_TYPE.SOLID;
                    if(color.a == 1)
                    {
                        paintable.svgFill.blend = FILL_BLEND.OPAQUE;
                    } else {
                        paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                    }
                }
                    break;
                default:
                    break;
            }

            LibTessDotNet.Tess tesselation = new LibTessDotNet.Tess();
            LibTessDotNet.ContourVertex[] path;
            int pathLength;
            for(int i = 0; i < simplifiedShapes.Count; i++)
            {
                if(simplifiedShapes[i] == null)
                    continue;
                
                pathLength = simplifiedShapes[i].Count;
                path = new LibTessDotNet.ContourVertex[pathLength];
                Vector2 position;
                for(int j = 0; j < pathLength; j++)
                {
                    position = simplifiedShapes[i][j];
                    path[j].Position = new LibTessDotNet.Vec3{X = position.x, Y = position.y, Z = 0f};
                }
                tesselation.AddContour(path);
            }

            tesselation.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3);

            Mesh mesh = new Mesh();
            int meshVertexCount = tesselation.Vertices.Length;
            Vector3[] vertices = new Vector3[meshVertexCount];
            Vector2[] uv = null;
            Vector2[] uv2 = null;

            for(int i = 0; i < meshVertexCount; i++)
            {
                vertices[i] = new Vector3(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y, 0f);
            }

            int numTriangles = tesselation.ElementCount;
            int[] triangles = new int[numTriangles * 3];
            for (int i = 0; i < numTriangles; i++)
            {
                triangles[i * 3] = tesselation.Elements[i * 3];
                triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1];
                triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2];
            }

            SVGFill svgFill = paintable.svgFill;
            Color32 fillColor = Color.white;
            if (svgFill.fillType != FILL_TYPE.GRADIENT && svgFill.gradientColors == null)
                fillColor = svgFill.color;

            antialiasingMesh = CreateAntialiasing(simplifiedShapes, fillColor, -SVGAssetImport.antialiasingWidth, false, SVGImporter.Utils.ClosePathRule.ALWAYS);

            Color32[] colors32 = new Color32[meshVertexCount];

            for (int i = 0; i < meshVertexCount; i++) 
            {
                colors32 [i].r = fillColor.r;
                colors32 [i].g = fillColor.g;
                colors32 [i].b = fillColor.b;
                colors32 [i].a = fillColor.a;
            }

            if(antialiasingMesh != null)
            {
                Vector3[] antialiasingVertices = antialiasingMesh.vertices;
                Vector2[] antialiasingUV = antialiasingMesh.uv;
                Vector2[] antialiasingUV2 = antialiasingMesh.uv2;
                WriteUVGradientCoordinates(ref antialiasingUV, antialiasingVertices, paintable, bounds);
                WriteUVGradientIndexType(ref antialiasingUV2, antialiasingVertices.Length, paintable);
                antialiasingMesh.uv = antialiasingUV;
                antialiasingMesh.uv2 = antialiasingUV2;
            }

            WriteUVGradientCoordinates(ref uv, vertices, paintable, bounds);
            WriteUVGradientIndexType(ref uv2, meshVertexCount, paintable);

            mesh.vertices = vertices;
            mesh.triangles = triangles;
            if(colors32 != null) mesh.colors32 = colors32;
            if(uv != null) mesh.uv = uv;
            if(uv2 != null) mesh.uv2 = uv2;

            return mesh;
        }
Example #7
0
        public static void TesselateStroke(List <List <Vector2> > inputShapes, Color32 color, out List <List <Vector2> > simplifiedShapes, out Vector3[] vertices, out int[] triangles, out Color32[] colors32)
        {
            simplifiedShapes = null;
            vertices         = null;
            triangles        = null;
            colors32         = null;

            if (inputShapes == null || inputShapes.Count == 0)
            {
                return;
            }

            int i, j;

            simplifiedShapes = new List <List <Vector2> >();

            PolyFillType fillType = PolyFillType.pftNonZero;

            for (i = 0; i < inputShapes.Count; i++)
            {
                if (inputShapes[i] == null || inputShapes.Count == 0)
                {
                    continue;
                }

                List <List <Vector2> > output = SVGGeom.SimplifyPolygon(inputShapes[i], fillType);
                if (output == null || output.Count == 0)
                {
                    simplifiedShapes.Add(inputShapes[i]);
                }
                else
                {
                    simplifiedShapes.AddRange(output);
                }
            }

            LibTessDotNet.Tess tesselation = new LibTessDotNet.Tess();

            LibTessDotNet.ContourVertex[] path;
            for (i = 0; i < simplifiedShapes.Count; i++)
            {
                if (simplifiedShapes[i] == null || simplifiedShapes[i].Count < 2)
                {
                    continue;
                }

                path = new LibTessDotNet.ContourVertex[simplifiedShapes[i].Count];
                for (j = 0; j < simplifiedShapes[i].Count; j++)
                {
                    path[j].Position = new LibTessDotNet.Vec3 {
                        X = simplifiedShapes[i][j].x, Y = simplifiedShapes[i][j].y, Z = 0f
                    };
                }
                tesselation.AddContour(path);
            }

            tesselation.Tessellate(LibTessDotNet.WindingRule.Positive, LibTessDotNet.ElementType.Polygons, 3);
            if (tesselation.Vertices == null || tesselation.Vertices.Length == 0)
            {
                return;
            }

            int numVertices  = tesselation.Vertices.Length;
            int numTriangles = tesselation.ElementCount * 3;

            triangles = new int[numTriangles];
            vertices  = new Vector3[numVertices];
            colors32  = new Color32[numVertices];

            for (i = 0; i < numVertices; i++)
            {
                vertices[i] = new Vector3(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y, 0f);
                colors32[i] = color;
            }
            for (i = 0; i < numTriangles; i += 3)
            {
                triangles[i]     = tesselation.Elements[i];
                triangles[i + 1] = tesselation.Elements[i + 1];
                triangles[i + 2] = tesselation.Elements[i + 2];
            }
        }
Example #8
0
        /// <summary>
        /// Creates the double-sided submesh based on vertices and triangles.
        /// </summary>
        public void CreateMesh()
        {
            //clear mesh definitions
            if (subMesh)
            {
                subMesh.Clear();
            }
            //get components
            MeshFilter subFilter = null;

            MeshFilter[] subFilters = GetComponentsInChildren <MeshFilter>(true);

            //find corresponding MeshFilter
            for (int i = 0; i < subFilters.Length; i++)
            {
                if (subFilters[i].sharedMesh == subMesh)
                {
                    subFilter = subFilters[i];
                    break;
                }
            }

            var tess = new LibTessDotNet.Tess();

            // Construct the contour from inputData.
            // A polygon can be composed of multiple contours which are all tessellated at the same time.
            int numPoints = list.Count;
            var contour   = new LibTessDotNet.ContourVertex[numPoints];

            for (int i = 0; i < numPoints; i++)
            {
                // NOTE : Z is here for convenience if you want to keep a 3D vertex position throughout the tessellation process but only X and Y are important.
                contour[i].Position = new LibTessDotNet.Vec3 {
                    X = list[i].x, Y = list[i].y, Z = list[i].z
                };
            }
            // Add the contour with a specific orientation, use "Original" if you want to keep the input orientation.
            tess.AddContour(contour, LibTessDotNet.ContourOrientation.Clockwise);

            // Tessellate!
            // The winding rule determines how the different contours are combined together.
            // See http://www.glprogramming.com/red/chapter11.html (section "Winding Numbers and Winding Rules") for more information.
            // If you want triangles as output, you need to use "Polygons" type as output and 3 vertices per polygon.
            tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3);

            Vector3[] vertex = new Vector3[tess.VertexCount];
            for (int i = 0; i < tess.VertexCount; i++)
            {
                vertex[i] = new Vector3(tess.Vertices[i].Position.X, tess.Vertices[i].Position.Y,
                                        tess.Vertices[i].Position.Z);
            }

            Vector2[] uvs = new Vector2[vertex.Length];
            for (int i = 0; i < vertex.Length; i++)
            {
                if ((i % 2) == 0)
                {
                    uvs[i] = new Vector2(0, 0);
                }
                else
                {
                    uvs[i] = new Vector2(1, 1);
                }
            }

            int[] tris = tess.Elements.Concat(tess.Elements.Reverse()).ToArray();

            //             //get vertex positions of current submesh
            //             Vector3[] vertex = new Vector3[current.Count];
            //             for (int i = 0; i < current.Count; i++)
            //                 vertex[i] = list[current[i]];
            //
            //             //don't continue without meshfilter or not enough points
            //             if (!subFilter || vertex.Length < 3) return;
            //
            //             //set uvs of vertices
            //             Vector2[] uvs = new Vector2[vertex.Length];
            //             for (int i = 0; i < vertex.Length; i++)
            //             {
            //                 if ((i % 2) == 0)
            //                     uvs[i] = new Vector2(0, 0);
            //                 else
            //                     uvs[i] = new Vector2(1, 1);
            //             }

            //assign data to mesh
            subMesh.vertices  = vertex;
            subMesh.uv        = uvs;
            subMesh.triangles = tris;

            //recalculate and optimize
            subMesh.RecalculateNormals();
            subMesh.RecalculateBounds();
            subMesh.Optimize();

            //assign mesh to filter
            subFilter.mesh = subMesh;
        }
Example #9
0
        /// <summary>
        /// Updates the mesh with new vertex positions.
        /// </summary>
        public void UpdateMesh(Vector3[] verts)
        {
            //convert passed in vertices to relative positioning
            MeshFilter myFilter = GetComponent <MeshFilter>();

            for (int i = 0; i < verts.Length; i++)
            {
                verts[i] = transform.InverseTransformPoint(verts[i]);
            }

            //assign vertices
            //myFilter.sharedMesh.vertices = verts;


            var tess = new LibTessDotNet.Tess();

            // Construct the contour from inputData.
            // A polygon can be composed of multiple contours which are all tessellated at the same time.
            int numPoints = list.Count;
            var contour   = new LibTessDotNet.ContourVertex[numPoints];

            for (int i = 0; i < numPoints; i++)
            {
                // NOTE : Z is here for convenience if you want to keep a 3D vertex position throughout the tessellation process but only X and Y are important.
                contour[i].Position = new LibTessDotNet.Vec3 {
                    X = list[i].x, Y = list[i].y, Z = list[i].z
                };
            }
            // Add the contour with a specific orientation, use "Original" if you want to keep the input orientation.
            tess.AddContour(contour, LibTessDotNet.ContourOrientation.Clockwise);

            // Tessellate!
            // The winding rule determines how the different contours are combined together.
            // See http://www.glprogramming.com/red/chapter11.html (section "Winding Numbers and Winding Rules") for more information.
            // If you want triangles as output, you need to use "Polygons" type as output and 3 vertices per polygon.
            tess.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3);

            Vector3[] vertex = new Vector3[tess.VertexCount];
            for (int i = 0; i < tess.VertexCount; i++)
            {
                vertex[i] = new Vector3(tess.Vertices[i].Position.X, tess.Vertices[i].Position.Y,
                                        tess.Vertices[i].Position.Z);
            }

            Vector2[] uvs = new Vector2[vertex.Length];
            for (int i = 0; i < vertex.Length; i++)
            {
                if ((i % 2) == 0)
                {
                    uvs[i] = new Vector2(0, 0);
                }
                else
                {
                    uvs[i] = new Vector2(1, 1);
                }
            }

            int[] tris = tess.Elements.Concat(tess.Elements.Reverse()).ToArray();

            myFilter.sharedMesh.Clear();

            myFilter.sharedMesh.vertices  = vertex;
            myFilter.sharedMesh.uv        = uvs;
            myFilter.sharedMesh.triangles = tris;
        }
Example #10
0
        public static bool CreatePolygon(List <List <Vector2> > inputShapes, SVGPaintable paintable, SVGMatrix matrix, out SVGLayer layer, bool isStroke = false)
        {
            layer = new SVGLayer();
            if (inputShapes == null || inputShapes.Count == 0)
            {
                return(false);
            }

            List <List <Vector2> > simplifiedShapes = new List <List <Vector2> >();
            PolyFillType           fillType         = PolyFillType.pftNonZero;

            if (paintable.fillRule == SVGFillRule.EvenOdd)
            {
                fillType = PolyFillType.pftEvenOdd;
            }
            simplifiedShapes = SVGGeom.SimplifyPolygons(inputShapes, fillType);
            if (simplifiedShapes == null || simplifiedShapes.Count == 0)
            {
                return(false);
            }

            AddInputShape(simplifiedShapes);

            Rect bounds   = GetRect(simplifiedShapes);
            Rect viewport = paintable.viewport;

            if (!isStroke)
            {
                switch (paintable.GetPaintType())
                {
                case SVGPaintMethod.SolidFill:
                {
                    Color        color     = Color.black;
                    SVGColorType colorType = paintable.fillColor.Value.colorType;
                    if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None)
                    {
                        color.a          *= paintable.fillOpacity;
                        paintable.svgFill = new SVGFill(color);
                    }
                    else
                    {
                        color             = paintable.fillColor.Value.color;
                        color.a          *= paintable.fillOpacity;
                        paintable.svgFill = new SVGFill(color);
                    }

                    paintable.svgFill.fillType = FILL_TYPE.SOLID;
                    if (color.a == 1)
                    {
                        paintable.svgFill.blend = FILL_BLEND.OPAQUE;
                    }
                    else
                    {
                        paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                    }
                }
                break;

                case SVGPaintMethod.LinearGradientFill:
                {
                    SVGLinearGradientBrush linearGradBrush = paintable.GetLinearGradientBrush(bounds, matrix, viewport);
                    paintable.svgFill = linearGradBrush.fill;
                }
                break;

                case SVGPaintMethod.RadialGradientFill:
                {
                    SVGRadialGradientBrush radialGradBrush = paintable.GetRadialGradientBrush(bounds, matrix, viewport);
                    paintable.svgFill = radialGradBrush.fill;
                }
                break;

                case SVGPaintMethod.ConicalGradientFill:
                {
                    SVGConicalGradientBrush conicalGradBrush = paintable.GetConicalGradientBrush(bounds, matrix, viewport);
                    paintable.svgFill = conicalGradBrush.fill;
                }
                break;

                case SVGPaintMethod.PathDraw:
                {
                    Color        color     = Color.black;
                    SVGColorType colorType = paintable.fillColor.Value.colorType;
                    if (colorType == SVGColorType.Unknown || colorType == SVGColorType.None)
                    {
                        color.a          *= paintable.strokeOpacity;
                        paintable.svgFill = new SVGFill(color);
                    }
                    else
                    {
                        color             = paintable.fillColor.Value.color;
                        color.a          *= paintable.strokeOpacity;
                        paintable.svgFill = new SVGFill(color);
                    }

                    paintable.svgFill.fillType = FILL_TYPE.SOLID;
                    if (color.a == 1)
                    {
                        paintable.svgFill.blend = FILL_BLEND.OPAQUE;
                    }
                    else
                    {
                        paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                    }
                }
                break;

                default:
                    break;
                }
            }
            else
            {
                Color color = paintable.strokeColor.Value.color;
                color.a          *= paintable.strokeOpacity;
                paintable.svgFill = new SVGFill(color, FILL_BLEND.OPAQUE, FILL_TYPE.SOLID);
                if (color.a != 1f)
                {
                    paintable.svgFill.blend = FILL_BLEND.ALPHA_BLENDED;
                }
                paintable.svgFill.color = color;
            }

            LibTessDotNet.Tess            tesselation = new LibTessDotNet.Tess();
            LibTessDotNet.ContourVertex[] path;
            int pathLength;

            for (int i = 0; i < simplifiedShapes.Count; i++)
            {
                if (simplifiedShapes[i] == null)
                {
                    continue;
                }

                pathLength = simplifiedShapes[i].Count;
                path       = new LibTessDotNet.ContourVertex[pathLength];
                Vector2 position;
                for (int j = 0; j < pathLength; j++)
                {
                    position         = simplifiedShapes[i][j];
                    path[j].Position = new LibTessDotNet.Vec3 {
                        X = position.x, Y = position.y, Z = 0f
                    };
                }
                tesselation.AddContour(path, SVGImporter.LibTessDotNet.ContourOrientation.Clockwise);
            }

            tesselation.Tessellate(LibTessDotNet.WindingRule.EvenOdd, LibTessDotNet.ElementType.Polygons, 3);

            int meshVertexCount = tesselation.Vertices.Length;

            layer.vertices = new Vector2[meshVertexCount];

            for (int i = 0; i < meshVertexCount; i++)
            {
                layer.vertices[i] = new Vector2(tesselation.Vertices[i].Position.X, tesselation.Vertices[i].Position.Y) * SVGAssetImport.meshScale;
            }

            int numTriangles = tesselation.ElementCount;

            layer.triangles = new int[numTriangles * 3];
            for (int i = 0; i < numTriangles; i++)
            {
                layer.triangles[i * 3]     = tesselation.Elements[i * 3];
                layer.triangles[i * 3 + 1] = tesselation.Elements[i * 3 + 1];
                layer.triangles[i * 3 + 2] = tesselation.Elements[i * 3 + 2];
            }

            layer.fill         = paintable.svgFill;
            layer.fill.opacity = paintable.opacity;
            if (layer.fill.opacity < 1f && layer.fill.blend == FILL_BLEND.OPAQUE)
            {
                layer.fill.blend = FILL_BLEND.ALPHA_BLENDED;
            }

            if (layer.fill.fillType == FILL_TYPE.GRADIENT && layer.fill.gradientColors != null)
            {
                layer.fill.color = Color.white;
            }
            else if (layer.fill.fillType == FILL_TYPE.TEXTURE)
            {
                layer.fill.color = Color.white;
            }

            viewport.x         *= SVGAssetImport.meshScale;
            viewport.y         *= SVGAssetImport.meshScale;
            viewport.size      *= SVGAssetImport.meshScale;
            layer.fill.viewport = viewport;

            if (layer.fill.transform != null)
            {
                SVGMatrix scaleMatrix = SVGMatrix.Identity().Scale(SVGAssetImport.meshScale);
                layer.fill.transform = scaleMatrix.Multiply(layer.fill.transform);
                layer.fill.transform = layer.fill.transform.Multiply(scaleMatrix.Inverse());
            }

            Vector2 boundsMin = bounds.min * SVGAssetImport.meshScale;
            Vector2 boundsMax = bounds.max * SVGAssetImport.meshScale;

            layer.bounds = new Rect(boundsMin.x,
                                    boundsMin.y,
                                    boundsMax.x - boundsMin.x,
                                    boundsMax.y - boundsMin.y);

            return(true);
        }