Exemple #1
0
        private void button1_Click(object sender, EventArgs e)
        {
            //1.
            MsdfGenParams msdfGenParams = new MsdfGenParams();

            //GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(tx, msdfGenParams);
            Msdfgen.Shape shape1 = new Msdfgen.Shape();
            //
            Msdfgen.Contour cnt = new Msdfgen.Contour();
            //cnt.AddLine(0, 0, 50, 0);
            //cnt.AddLine(50, 0, 50, 50);
            //cnt.AddLine(50, 50, 0, 50);
            //cnt.AddLine(0, 50, 0, 0);
            //cnt.AddLine(10, 20, 50, 0);
            //cnt.AddLine(50, 0, 80, 20);
            //cnt.AddLine(80, 20, 50, 60);
            //cnt.AddLine(50, 60, 10, 20);

            //for msdf we draw shape clock-wise
            cnt.AddLine(10, 20, 50, 60);
            cnt.AddLine(50, 60, 80, 20);
            cnt.AddLine(80, 20, 50, 0);
            cnt.AddLine(50, 0, 10, 20);
            shape1.contours.Add(cnt);
            //
            //
            var genParams = new MsdfGenParams();
            BitmapAtlasItemSource glyphImg = MsdfImageGen.CreateMsdfImageV1(shape1, genParams);

            using (Bitmap bmp = new Bitmap(glyphImg.Width, glyphImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
            {
                int[] buffer = glyphImg.GetImageBuffer();

                var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImg.Width, glyphImg.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
                System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bmpdata.Scan0, buffer.Length);
                bmp.UnlockBits(bmpdata);
                bmp.Save("msdf_shape.png");
                //
            }
        }
        //siged distance field generator

        public static void GenerateSdf(FloatBmp output,
                                       Shape shape,
                                       double range,
                                       Vector2 scale,
                                       Vector2 translate)
        {
            List <Contour> contours = shape.contours;
            int            contourCount = contours.Count;
            int            w = output.Width, h = output.Height;
            List <int>     windings = new List <int>(contourCount);

            for (int i = 0; i < contourCount; ++i)
            {
                windings.Add(contours[i].winding());
            }

            //# ifdef MSDFGEN_USE_OPENMP
            //#pragma omp parallel
            //#endif
            {
                //# ifdef MSDFGEN_USE_OPENMP
                //#pragma omp for
                //#endif
                double[] contourSD = new double[contourCount];
                for (int y = 0; y < h; ++y)
                {
                    int row = shape.InverseYAxis ? h - y - 1 : y;
                    for (int x = 0; x < w; ++x)
                    {
                        double  dummy   = 0;
                        Vector2 p       = (new Vector2(x + .5, y + .5) / scale) - translate;
                        double  negDist = -SignedDistance.INFINITE.distance;
                        double  posDist = SignedDistance.INFINITE.distance;
                        int     winding = 0;


                        for (int i = 0; i < contourCount; ++i)
                        {
                            Contour           contour     = contours[i];
                            SignedDistance    minDistance = SignedDistance.INFINITE;
                            List <EdgeHolder> edges       = contour.edges;
                            int edgeCount = edges.Count;
                            for (int ee = 0; ee < edgeCount; ++ee)
                            {
                                EdgeHolder     edge     = edges[ee];
                                SignedDistance distance = edge.edgeSegment.signedDistance(p, out dummy);
                                if (distance < minDistance)
                                {
                                    minDistance = distance;
                                }
                            }

                            contourSD[i] = minDistance.distance;
                            if (windings[i] > 0 && minDistance.distance >= 0 && Math.Abs(minDistance.distance) < Math.Abs(posDist))
                            {
                                posDist = minDistance.distance;
                            }
                            if (windings[i] < 0 && minDistance.distance <= 0 && Math.Abs(minDistance.distance) < Math.Abs(negDist))
                            {
                                negDist = minDistance.distance;
                            }
                        }

                        double sd = SignedDistance.INFINITE.distance;
                        if (posDist >= 0 && Math.Abs(posDist) <= Math.Abs(negDist))
                        {
                            sd      = posDist;
                            winding = 1;
                            for (int i = 0; i < contourCount; ++i)
                            {
                                if (windings[i] > 0 && contourSD[i] > sd && Math.Abs(contourSD[i]) < Math.Abs(negDist))
                                {
                                    sd = contourSD[i];
                                }
                            }
                        }
                        else if (negDist <= 0 && Math.Abs(negDist) <= Math.Abs(posDist))
                        {
                            sd      = negDist;
                            winding = -1;
                            for (int i = 0; i < contourCount; ++i)
                            {
                                if (windings[i] < 0 && contourSD[i] < sd && Math.Abs(contourSD[i]) < Math.Abs(posDist))
                                {
                                    sd = contourSD[i];
                                }
                            }
                        }
                        for (int i = 0; i < contourCount; ++i)
                        {
                            if (windings[i] != winding && Math.Abs(contourSD[i]) < Math.Abs(sd))
                            {
                                sd = contourSD[i];
                            }
                        }

                        output.SetPixel(x, row, (float)(sd / range + .5));
                    }
                }
            }
        }
        public static void generateMSDF(FloatRGBBmp output, Shape shape, double range, Vector2 scale, Vector2 translate, double edgeThreshold)
        {
            List <Contour> contours     = shape.contours;
            int            contourCount = contours.Count;
            int            w            = output.Width;
            int            h            = output.Height;
            List <int>     windings     = new List <int>(contourCount);

            for (int i = 0; i < contourCount; ++i)
            {
                windings.Add(contours[i].winding());
            }

            var contourSD = new MultiDistance[contourCount];

            for (int y = 0; y < h; ++y)
            {
                int row = shape.InverseYAxis ? h - y - 1 : y;
                for (int x = 0; x < w; ++x)
                {
                    Vector2   p  = (new Vector2(x + .5, y + .5) / scale) - translate;
                    EdgePoint sr = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              sg = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              sb = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    };
                    double d       = Math.Abs(SignedDistance.INFINITE.distance);
                    double negDist = -Math.Abs(SignedDistance.INFINITE.distance);
                    double posDist = Math.Abs(SignedDistance.INFINITE.distance);
                    int    winding = 0;

                    for (int n = 0; n < contourCount; ++n)
                    {
                        //for-each contour
                        Contour           contour = contours[n];
                        List <EdgeHolder> edges   = contour.edges;
                        int       edgeCount       = edges.Count;
                        EdgePoint r = new EdgePoint {
                            minDistance = SignedDistance.INFINITE
                        },
                                  g = new EdgePoint {
                            minDistance = SignedDistance.INFINITE
                        },
                                  b = new EdgePoint {
                            minDistance = SignedDistance.INFINITE
                        };
                        for (int ee = 0; ee < edgeCount; ++ee)
                        {
                            EdgeHolder     edge = edges[ee];
                            double         param;
                            SignedDistance distance = edge.edgeSegment.signedDistance(p, out param);
                            if (edge.HasComponent(EdgeColor.RED) && distance < r.minDistance)
                            {
                                r.minDistance = distance;
                                r.nearEdge    = edge;
                                r.nearParam   = param;
                            }
                            if (edge.HasComponent(EdgeColor.GREEN) && distance < g.minDistance)
                            {
                                g.minDistance = distance;
                                g.nearEdge    = edge;
                                g.nearParam   = param;
                            }
                            if (edge.HasComponent(EdgeColor.BLUE) && distance < b.minDistance)
                            {
                                b.minDistance = distance;
                                b.nearEdge    = edge;
                                b.nearParam   = param;
                            }
                        }
                        //----------------
                        if (r.minDistance < sr.minDistance)
                        {
                            sr = r;
                        }
                        if (g.minDistance < sg.minDistance)
                        {
                            sg = g;
                        }
                        if (b.minDistance < sb.minDistance)
                        {
                            sb = b;
                        }
                        //----------------
                        double medMinDistance = Math.Abs(median(r.minDistance.distance, g.minDistance.distance, b.minDistance.distance));
                        if (medMinDistance < d)
                        {
                            d       = medMinDistance;
                            winding = -windings[n];
                        }

                        if (r.nearEdge != null)
                        {
                            r.nearEdge.edgeSegment.distanceToPseudoDistance(ref r.minDistance, p, r.nearParam);
                        }
                        if (g.nearEdge != null)
                        {
                            g.nearEdge.edgeSegment.distanceToPseudoDistance(ref g.minDistance, p, g.nearParam);
                        }
                        if (b.nearEdge != null)
                        {
                            b.nearEdge.edgeSegment.distanceToPseudoDistance(ref b.minDistance, p, b.nearParam);
                        }
                        //--------------
                        medMinDistance   = median(r.minDistance.distance, g.minDistance.distance, b.minDistance.distance);
                        contourSD[n].r   = r.minDistance.distance;
                        contourSD[n].g   = g.minDistance.distance;
                        contourSD[n].b   = b.minDistance.distance;
                        contourSD[n].med = medMinDistance;
                        if (windings[n] > 0 && medMinDistance >= 0 && Math.Abs(medMinDistance) < Math.Abs(posDist))
                        {
                            posDist = medMinDistance;
                        }
                        if (windings[n] < 0 && medMinDistance <= 0 && Math.Abs(medMinDistance) < Math.Abs(negDist))
                        {
                            negDist = medMinDistance;
                        }
                    }
                    if (sr.nearEdge != null)
                    {
                        sr.nearEdge.edgeSegment.distanceToPseudoDistance(ref sr.minDistance, p, sr.nearParam);
                    }
                    if (sg.nearEdge != null)
                    {
                        sg.nearEdge.edgeSegment.distanceToPseudoDistance(ref sg.minDistance, p, sg.nearParam);
                    }
                    if (sb.nearEdge != null)
                    {
                        sb.nearEdge.edgeSegment.distanceToPseudoDistance(ref sb.minDistance, p, sb.nearParam);
                    }

                    MultiDistance msd;
                    msd.r = msd.g = msd.b = msd.med = SignedDistance.INFINITE.distance;
                    if (posDist >= 0 && Math.Abs(posDist) <= Math.Abs(negDist))
                    {
                        msd.med = SignedDistance.INFINITE.distance;
                        winding = 1;
                        for (int i = 0; i < contourCount; ++i)
                        {
                            if (windings[i] > 0 && contourSD[i].med > msd.med && Math.Abs(contourSD[i].med) < Math.Abs(negDist))
                            {
                                msd = contourSD[i];
                            }
                        }
                    }
                    else if (negDist <= 0 && Math.Abs(negDist) <= Math.Abs(posDist))
                    {
                        msd.med = -SignedDistance.INFINITE.distance;
                        winding = -1;
                        for (int i = 0; i < contourCount; ++i)
                        {
                            if (windings[i] < 0 && contourSD[i].med < msd.med && Math.Abs(contourSD[i].med) < Math.Abs(posDist))
                            {
                                msd = contourSD[i];
                            }
                        }
                    }
                    for (int i = 0; i < contourCount; ++i)
                    {
                        if (windings[i] != winding && Math.Abs(contourSD[i].med) < Math.Abs(msd.med))
                        {
                            msd = contourSD[i];
                        }
                    }
                    if (median(sr.minDistance.distance, sg.minDistance.distance, sb.minDistance.distance) == msd.med)
                    {
                        msd.r = sr.minDistance.distance;
                        msd.g = sg.minDistance.distance;
                        msd.b = sb.minDistance.distance;
                    }

                    output.SetPixel(x, row,
                                    new FloatRGB(
                                        (float)(msd.r / range + .5),
                                        (float)(msd.g / range + .5),
                                        (float)(msd.b / range + .5)
                                        ));
                }
            }

            if (edgeThreshold > 0)
            {
                msdfErrorCorrection(output, edgeThreshold / (scale * range));
            }
        }
        public static void generateMSDF_legacy(FloatRGBBmp output, Shape shape, double range, Vector2 scale, Vector2 translate,
                                               double edgeThreshold)
        {
            int w = output.Width;
            int h = output.Height;

            //#ifdef MSDFGEN_USE_OPENMP
            //    #pragma omp parallel for
            //#endif
            for (int y = 0; y < h; ++y)
            {
                int row = shape.InverseYAxis ? h - y - 1 : y;
                for (int x = 0; x < w; ++x)
                {
                    Vector2   p = (new Vector2(x + .5, y + .5) / scale) - translate;
                    EdgePoint r = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              g = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              b = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    };
                    //r.nearEdge = g.nearEdge = b.nearEdge = null;
                    //r.nearParam = g.nearParam = b.nearParam = 0;
                    List <Contour> contours = shape.contours;
                    int            m        = contours.Count;
                    for (int n = 0; n < m; ++n)
                    {
                        Contour           contour = contours[n];
                        List <EdgeHolder> edges   = contour.edges;
                        int j = edges.Count;
                        for (int i = 0; i < j; ++i)
                        {
                            EdgeHolder     edge = edges[i];
                            double         param;
                            SignedDistance distance = edge.edgeSegment.signedDistance(p, out param);

                            if (edge.HasComponent(EdgeColor.RED) && distance < r.minDistance)
                            {
                                r.minDistance = distance;
                                r.nearEdge    = edge;
                                r.nearParam   = param;
                            }
                            if (edge.HasComponent(EdgeColor.GREEN) && distance < g.minDistance)
                            {
                                g.minDistance = distance;
                                g.nearEdge    = edge;
                                g.nearParam   = param;
                            }
                            if (edge.HasComponent(EdgeColor.BLUE) && distance < b.minDistance)
                            {
                                b.minDistance = distance;
                                b.nearEdge    = edge;
                                b.nearParam   = param;
                            }
                        }
                        if (r.nearEdge != null)
                        {
                            r.nearEdge.edgeSegment.distanceToPseudoDistance(ref r.minDistance, p, r.nearParam);
                        }
                        if (g.nearEdge != null)
                        {
                            g.nearEdge.edgeSegment.distanceToPseudoDistance(ref g.minDistance, p, g.nearParam);
                        }
                        if (b.nearEdge != null)
                        {
                            b.nearEdge.edgeSegment.distanceToPseudoDistance(ref b.minDistance, p, b.nearParam);
                        }

                        output.SetPixel(x, row,
                                        new FloatRGB(
                                            (float)(r.minDistance.distance / range + .5),
                                            (float)(g.minDistance.distance / range + .5),
                                            (float)(b.minDistance.distance / range + .5)
                                            ));
                    }
                }
            }

            if (edgeThreshold > 0)
            {
                msdfErrorCorrection(output, edgeThreshold / (scale * range));
            }
        }
Exemple #5
0
        static Shape CreateShape(VertexStore vxs, out EdgeBmpLut bmpLut)
        {
            List <EdgeSegment> flattenEdges = new List <EdgeSegment>();
            Shape shape = new Shape(); //start with blank shape

            int       i = 0;
            double    x, y;
            VertexCmd cmd;
            Contour   cnt           = null;
            double    latestMoveToX = 0;
            double    latestMoveToY = 0;
            double    latestX       = 0;
            double    latestY       = 0;

            List <ContourCorner> corners              = new List <ContourCorner>();
            List <int>           edgeOfNextContours   = new List <int>();
            List <int>           cornerOfNextContours = new List <int>();

            while ((cmd = vxs.GetVertex(i, out x, out y)) != VertexCmd.NoMore)
            {
                switch (cmd)
                {
                case VertexCmd.Close:
                {
                    //close current cnt

                    if ((latestMoveToX != latestX) ||
                        (latestMoveToY != latestY))
                    {
                        //add line to close the shape
                        if (cnt != null)
                        {
                            flattenEdges.Add(cnt.AddLine(latestX, latestY, latestMoveToX, latestMoveToY));
                        }
                    }
                    if (cnt != null)
                    {
                        //***
                        CreateCorners(cnt, corners);
                        edgeOfNextContours.Add(flattenEdges.Count);
                        cornerOfNextContours.Add(corners.Count);
                        shape.contours.Add(cnt);
                        //***
                        cnt = null;
                    }
                }
                break;

                case VertexCmd.C3:
                {
                    //C3 curve (Quadratic)
                    if (cnt == null)
                    {
                        cnt = new Contour();
                    }
                    VertexCmd cmd1 = vxs.GetVertex(i + 1, out double x1, out double y1);
                    i++;
                    if (cmd1 != VertexCmd.LineTo)
                    {
                        throw new NotSupportedException();
                    }

                    //in this version,
                    //we convert Quadratic to Cubic (https://stackoverflow.com/questions/9485788/convert-quadratic-curve-to-cubic-curve)

                    //Control1X = StartX + ((2f/3) * (ControlX - StartX))
                    //Control2X = EndX + ((2f/3) * (ControlX - EndX))


                    //flattenEdges.Add(cnt.AddCubicSegment(
                    //    latestX, latestY,
                    //    ((2f / 3) * (x - latestX)) + latestX, ((2f / 3) * (y - latestY)) + latestY,
                    //    ((2f / 3) * (x - x1)) + x1, ((2f / 3) * (y - y1)) + y1,
                    //    x1, y1));

                    flattenEdges.Add(cnt.AddQuadraticSegment(latestX, latestY, x, y, x1, y1));

                    latestX = x1;
                    latestY = y1;
                }
                break;

                case VertexCmd.C4:
                {
                    //C4 curve (Cubic)
                    if (cnt == null)
                    {
                        cnt = new Contour();
                    }

                    VertexCmd cmd1 = vxs.GetVertex(i + 1, out double x2, out double y2);
                    VertexCmd cmd2 = vxs.GetVertex(i + 2, out double x3, out double y3);
                    i += 2;

                    if (cmd1 != VertexCmd.C4 || cmd2 != VertexCmd.LineTo)
                    {
                        throw new NotSupportedException();
                    }

                    flattenEdges.Add(cnt.AddCubicSegment(latestX, latestY, x, y, x2, y2, x3, y3));

                    latestX = x3;
                    latestY = y3;
                }
                break;

                case VertexCmd.LineTo:
                {
                    if (cnt == null)
                    {
                        cnt = new Contour();
                    }
                    LinearSegment lineseg = cnt.AddLine(latestX, latestY, x, y);
                    flattenEdges.Add(lineseg);

                    latestX = x;
                    latestY = y;
                }
                break;

                case VertexCmd.MoveTo:
                {
                    latestX = latestMoveToX = x;
                    latestY = latestMoveToY = y;
                    if (cnt != null)
                    {
                        shape.contours.Add(cnt);
                        cnt = null;
                    }
                }
                break;
                }
                i++;
            }

            if (cnt != null)
            {
                shape.contours.Add(cnt);
                CreateCorners(cnt, corners);
                edgeOfNextContours.Add(flattenEdges.Count);
                cornerOfNextContours.Add(corners.Count);
                cnt = null;
            }

            GroupingOverlapContours(shape);

            //from a given shape we create a corner-arm for each corner
            bmpLut = new EdgeBmpLut(corners, flattenEdges, edgeOfNextContours, cornerOfNextContours);

            return(shape);
        }