コード例 #1
0
        List<LinkedList<ControlPoint>> CreateContours(Glyph glyphData, out List<Triangle> triangles)
        {
            triangles = new List<Triangle>();
            var contours = new List<LinkedList<ControlPoint>>();

            foreach (List<ControlPoint> contour in glyphData.Contours)
            {
                if (contour.Count > 1)
                {
                    var innerPoints = new LinkedList<ControlPoint>();
                    contours.Add(innerPoints);

                    Triangle firstTriangle = null;
                    for (int i = 0, a = contour.Count - 1, b = 1; i < contour.Count; a = i, b = (b + 1) % contour.Count, i++)
                    {
                        ControlPoint point = contour[i];

                        if (point.IsOnCurve)
                        {
                            innerPoints.AddLast(point);
                        }
                        else
                        {
                            var pointBefore = contour[a];
                            if (!pointBefore.IsOnCurve)
                            {
                                pointBefore = (pointBefore + point) / 2;
                                innerPoints.AddLast(pointBefore);
                            }

                            var pointAfter = contour[b];
                            if (!pointAfter.IsOnCurve) pointAfter = (pointAfter + point) / 2;

                            var triangle = new Triangle(point, pointBefore, pointAfter);
                            if (i > 0)
                                triangle.BNode = innerPoints.Last;
                            else
                                firstTriangle = triangle;
                            triangles.Add(triangle);
                        }
                    }
                    if (firstTriangle != null && firstTriangle.BNode == null)
                        firstTriangle.BNode = contour.Last().IsOnCurve ? innerPoints.Last : innerPoints.First;
                }
            }

            return contours;
        }
コード例 #2
0
ファイル: TrueTypeFile.cs プロジェクト: Artentus/GameUtils
        Glyph[] ParseGlyfTable(Stream stream, BinaryReader reader, TableHeader glyfHeader, TableHeader locaHeader, int glyphCount, bool useLongIndexFormat)
        {
            stream.Position = locaHeader.Offset;

            var glyphOffsets = new long[glyphCount + 1];
            Func<long> read = useLongIndexFormat
                ? new Func<long>(() => (long)reader.ReadUInt32())
                : new Func<long>(() => reader.ReadUInt16() * 2L);
            for (int i = 0; i < glyphCount + 1; i++)
                glyphOffsets[i] = read();

            var glyphs = new Glyph[glyphCount];
            for (int i = 0; i < glyphCount; i++)
            {
                if (glyphOffsets[i + 1] - glyphOffsets[i] <= 0)
                {
                    glyphs[i] = Glyph.Empty;
                }
                else
                {
                    stream.Position = glyfHeader.Offset + glyphOffsets[i];
                    glyphs[i] = new Glyph(stream, reader);
                }
            }
            return glyphs;
        }
コード例 #3
0
        public TriangulatedGlyph(Glyph glyphData, TrueTypeFile.HorizontalMetric horizontalMetric)
        {
            indices = new List<int>();
            vertices = new List<Vertex>();
            advanceWidth = horizontalMetric.AdvanceWidth;
            leftSideBearing = horizontalMetric.LeftSideBearing;

            if (glyphData.IsCompound)
            {
                
            }
            else
            {
                if (glyphData.Contours.Length == 0)
                    return;

                List<Triangle> triangles;
                List<LinkedList<ControlPoint>> contours = CreateContours(glyphData, out triangles);

                int count = 0;
                bool split;
                do
                {
                    split = SplitTriangles(ref triangles);
                    count++;
                } while (split && count < 4);

                foreach (var triangle in triangles)
                {
                    ControlPoint p = (triangle.B + triangle.C) / 2;
                    int windingNumber = GetWindingNumber(p, glyphData);
                    triangle.IsInside = windingNumber == 0;

                    if (triangle.IsInside) triangle.Contour.AddAfter(triangle.BNode, triangle.A);
                }

                PolyTree tree = ClipperHelper.Combine(contours.Select(contour => contour.ToList()).ToList());

                int pointIndex = 0;
                var inputGeometry = new InputGeometry();
                SearchTree(inputGeometry, ref pointIndex, tree);

                if (inputGeometry.Count > 0)
                {
                    var mesh = new Mesh();
                    mesh.Triangulate(inputGeometry);

                    int highestIndex = 0;
                    var indexDict = new Dictionary<int, int>();
                    foreach (TriangleNet.Data.Triangle triangle in mesh.Triangles)
                    {
                        int[] newIndices;
                        List<Vertex> newVertices = IndexVertices(triangle, indexDict, ref highestIndex, out newIndices);

                        indices.AddRange(newIndices);
                        vertices.AddRange(newVertices);
                    }

                    foreach (var triangle in triangles)
                    {
                        indices.Add(vertices.Count);
                        vertices.Add(new Vertex((float)triangle.B.X, (float)triangle.B.Y, 0, 0, triangle.IsInside));
                        indices.Add(vertices.Count);
                        vertices.Add(new Vertex((float)triangle.A.X, (float)triangle.A.Y, 0.5f, 0, triangle.IsInside));
                        indices.Add(vertices.Count);
                        vertices.Add(new Vertex((float)triangle.C.X, (float)triangle.C.Y, 1, 1, triangle.IsInside));
                    }
                }
            }
        }
コード例 #4
0
        int GetWindingNumber(ControlPoint p, Glyph glyphData)
        {
            ControlPoint p2 = new ControlPoint(p.X + 1000, p.Y);
            int result = 0;

            foreach (var contour in glyphData.Contours)
            {
                for (int a = contour.Count - 1, b = 0; b < contour.Count; a = b, b++)
                {
                    ControlPoint pa = contour[a];
                    ControlPoint pb = contour[b];
                    
                    if (pa.Y > p.Y && pb.Y < p.Y)
                    {
                        if (pa.X > p.X && pb.X > p.X)
                        {
                            result++;
                        }
                        else if ((pa.X > p.X && pb.X < p.X) || (pa.X < p.X && pb.X > p.X))
                        {
                            ControlPoint r = p2 - p;
                            ControlPoint s = pb - pa;

                            double t = ControlPoint.VectorProduct((pa - p), s) / ControlPoint.VectorProduct(r, s);
                            double u = ControlPoint.VectorProduct((p - pa), r) / ControlPoint.VectorProduct(s, r);

                            if (t >= 0 && u >= 0 && u <= 1) result++;
                        }
                    }
                    else if (pa.Y < p.Y && pb.Y > p.Y)
                    {
                        if (pa.X > p.X && pb.X > p.X)
                        {
                            result--;
                        }
                        else if ((pa.X > p.X && pb.X < p.X) || (pa.X < p.X && pb.X > p.X))
                        {
                            ControlPoint r = p2 - p;
                            ControlPoint s = pb - pa;

                            double t = ControlPoint.VectorProduct((pa - p), s) / ControlPoint.VectorProduct(r, s);
                            double u = ControlPoint.VectorProduct((p - pa), r) / ControlPoint.VectorProduct(s, r);

                            if (t >= 0 && u >= 0 && u <= 1) result--;
                        }
                    }
                }
            }

            return result;
        }