static void msdfErrorCorrection(FloatRGBBmp output, Vector2 threshold)
        {
            List <Pair <int, int> > clashes = new List <Msdfgen.Pair <int, int> >();
            int w = output.Width, h = output.Height;

            for (int y = 0; y < h; ++y)
            {
                for (int x = 0; x < w; ++x)
                {
                    if ((x > 0 && pixelClash(output.GetPixel(x, y), output.GetPixel(x - 1, y), threshold.x)) ||
                        (x < w - 1 && pixelClash(output.GetPixel(x, y), output.GetPixel(x + 1, y), threshold.x)) ||
                        (y > 0 && pixelClash(output.GetPixel(x, y), output.GetPixel(x, y - 1), threshold.y)) ||
                        (y < h - 1 && pixelClash(output.GetPixel(x, y), output.GetPixel(x, y + 1), threshold.y)))
                    {
                        clashes.Add(new Pair <int, int>(x, y));
                    }
                }
            }
            int clash_count = clashes.Count;

            for (int i = 0; i < clash_count; ++i)
            {
                Pair <int, int> clash = clashes[i];
                FloatRGB        pixel = output.GetPixel(clash.first, clash.second);
                float           med   = median(pixel.r, pixel.g, pixel.b);
                pixel.r = med; pixel.g = med; pixel.b = med;
            }
            //for (std::vector<std::pair<int, int>>::const_iterator clash = clashes.begin(); clash != clashes.end(); ++clash)
            //{
            //    FloatRGB & pixel = output(clash->first, clash->second);
            //    float med = median(pixel.r, pixel.g, pixel.b);
            //    pixel.r = med, pixel.g = med, pixel.b = med;
            //}
        }
Beispiel #2
0
        internal static PixelFarm.CpuBlit.BitmapAtlas.BitmapAtlasItemSource CreateMsdfImage(Shape shape, MsdfGenParams genParams, int w, int h, Vector2 translate, EdgeBmpLut lutBuffer = null)
        {
            double edgeThreshold = genParams.edgeThreshold;

            if (edgeThreshold < 0)
            {
                edgeThreshold = 1.00000001; //use default if  edgeThreshold <0
            }

            var    scale = new Vector2(genParams.scaleX, genParams.scaleY); //scale
            double range = genParams.pxRange / Math.Min(scale.x, scale.y);
            //---------
            FloatRGBBmp frgbBmp = new FloatRGBBmp(w, h);

            EdgeColoring.edgeColoringSimple(shape, genParams.angleThreshold);

            bool flipY = false;

            if (lutBuffer != null)
            {
                GenerateMSDF3(frgbBmp,
                              shape,
                              range,
                              scale,
                              translate,//translate to positive quadrant
                              edgeThreshold,
                              lutBuffer);
                flipY = shape.InverseYAxis;
            }
            else
            {
                //use original msdf
                MsdfGenerator.generateMSDF(frgbBmp,
                                           shape,
                                           range,
                                           scale,
                                           translate,//translate to positive quadrant
                                           edgeThreshold);
            }

            return(new PixelFarm.CpuBlit.BitmapAtlas.BitmapAtlasItemSource(w, h)
            {
                Source = ConvertToIntBmp(frgbBmp, flipY),
                TextureXOffset = (float)translate.x,
                TextureYOffset = (float)translate.y
            });
        }
Beispiel #3
0
        public static int[] ConvertToIntBmp(FloatRGBBmp input)
        {
            int height = input.Height;
            int width  = input.Width;

            int[] output = new int[input.Width * input.Height];

            for (int y = height - 1; y >= 0; --y)
            {
                for (int x = 0; x < width; ++x)
                {
                    //a b g r
                    //----------------------------------
                    FloatRGB pixel = input.GetPixel(x, y);
                    //a b g r
                    //for big-endian color
                    //int abgr = (255 << 24) |
                    //    Vector2.Clamp((int)(pixel.r * 0x100), 0xff) |
                    //    Vector2.Clamp((int)(pixel.g * 0x100), 0xff) << 8 |
                    //    Vector2.Clamp((int)(pixel.b * 0x100), 0xff) << 16;

                    //for little-endian color

                    int abgr = (255 << 24) |
                               Vector2.Clamp((int)(pixel.r * 0x100), 0xff) << 16 |
                               Vector2.Clamp((int)(pixel.g * 0x100), 0xff) << 8 |
                               Vector2.Clamp((int)(pixel.b * 0x100), 0xff);

                    output[(y * width) + x] = abgr;
                    //----------------------------------

                    /**it++ = clamp(int(bitmap(x, y).r*0x100), 0xff);
                    * it++ = clamp(int(bitmap(x, y).g*0x100), 0xff);
                    * it++ = clamp(int(bitmap(x, y).b*0x100), 0xff);*/
                }
            }
            return(output);
        }
        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));
            }
        }
        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));
            }
        }
Beispiel #6
0
        public static int[] ConvertToIntBmp(FloatRGBBmp input, bool flipY)
        {
            int height = input.Height;
            int width  = input.Width;

            int[] output = new int[input.Width * input.Height];


            if (flipY)
            {
                int dstLineHead = width * (height - 1);
                for (int y = 0; y < height; ++y)
                {
                    for (int x = 0; x < width; ++x)
                    {
                        //a b g r
                        //----------------------------------
                        FloatRGB pixel = input.GetPixel(x, y);
                        //a b g r
                        //for big-endian color
                        //int abgr = (255 << 24) |
                        //    Vector2.Clamp((int)(pixel.r * 0x100), 0xff) |
                        //    Vector2.Clamp((int)(pixel.g * 0x100), 0xff) << 8 |
                        //    Vector2.Clamp((int)(pixel.b * 0x100), 0xff) << 16;

                        //for little-endian color

                        output[dstLineHead + x] = (255 << 24) |
                                                  Vector2.Clamp((int)(pixel.r * 0x100), 0xff) << 16 |
                                                  Vector2.Clamp((int)(pixel.g * 0x100), 0xff) << 8 |
                                                  Vector2.Clamp((int)(pixel.b * 0x100), 0xff);

                        //output[(y * width) + x] = abgr;
                        //----------------------------------

                        /**it++ = clamp(int(bitmap(x, y).r*0x100), 0xff);
                        * it++ = clamp(int(bitmap(x, y).g*0x100), 0xff);
                        * it++ = clamp(int(bitmap(x, y).b*0x100), 0xff);*/
                    }

                    dstLineHead -= width;
                }
            }
            else
            {
                int dstLineHead = 0;
                for (int y = 0; y < height; ++y)
                {
                    for (int x = 0; x < width; ++x)
                    {
                        //a b g r
                        //----------------------------------
                        FloatRGB pixel = input.GetPixel(x, y);
                        //a b g r
                        //for big-endian color
                        //int abgr = (255 << 24) |
                        //    Vector2.Clamp((int)(pixel.r * 0x100), 0xff) |
                        //    Vector2.Clamp((int)(pixel.g * 0x100), 0xff) << 8 |
                        //    Vector2.Clamp((int)(pixel.b * 0x100), 0xff) << 16;

                        //for little-endian color

                        output[dstLineHead + x] = (255 << 24) |
                                                  Vector2.Clamp((int)(pixel.r * 0x100), 0xff) << 16 |
                                                  Vector2.Clamp((int)(pixel.g * 0x100), 0xff) << 8 |
                                                  Vector2.Clamp((int)(pixel.b * 0x100), 0xff);

                        //output[(y * width) + x] = abgr;
                        //----------------------------------

                        /**it++ = clamp(int(bitmap(x, y).r*0x100), 0xff);
                        * it++ = clamp(int(bitmap(x, y).g*0x100), 0xff);
                        * it++ = clamp(int(bitmap(x, y).b*0x100), 0xff);*/
                    }

                    dstLineHead += width;
                }
            }
            return(output);
        }
Beispiel #7
0
        static void GenerateMSDF3(FloatRGBBmp output, Shape shape, double range, Vector2 scale, Vector2 translate, double edgeThreshold, EdgeBmpLut lut)
        {
            //----------------------
            //this is our extension,
            //we use lookup bitmap (lut) to check
            //what is the nearest contour of a given pixel.
            //----------------------

            int w = output.Width;
            int h = output.Height;

            EdgeSegment[] singleSegment = new EdgeSegment[1];//temp array for



            for (int y = 0; y < h; ++y)
            {
                for (int x = 0; x < w; ++x)
                {
                    //PER-PIXEL-OPERATION
                    //check preview pixel

                    int lutPix  = lut.GetPixel(x, y);
                    int lutPixR = (lutPix & 0xFF);
                    int lutPixG = (lutPix >> 8) & 0xff;
                    int lutPixB = (lutPix >> 16) & 0xff;

                    if (lutPixG == 0)
                    {
                        continue;               //black=> completely outside, skip
                    }
                    if (lutPixG == EdgeBmpLut.AREA_INSIDE_COVERAGE100 ||
                        lutPixG == EdgeBmpLut.AREA_INSIDE_COVERAGE50 ||
                        lutPixG == EdgeBmpLut.AREA_INSIDE_COVERAGEX)
                    {
                        //inside the contour => fill all with white
                        output.SetPixel(x, y, new FloatRGB(1f, 1f, 1f));
                        continue;
                    }

                    //reset variables
                    EdgePoint r = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              g = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    },
                              b = new EdgePoint {
                        minDistance = SignedDistance.INFINITE
                    };

                    bool useR, useG, useB;
                    useR = useG = useB = true;
                    //------

                    Vector2 p = (new Vector2(x + .5, y + .5) / scale) - translate;

                    EdgeStructure edgeStructure = lut.GetEdgeStructure(x, y);

#if DEBUG
                    if (edgeStructure.IsEmpty)
                    {
                        //should not occurs
                        throw new NotSupportedException();
                    }
#endif
                    EdgeSegment[] edges = null;
                    if (edgeStructure.HasOverlappedSegments)
                    {
                        edges = edgeStructure.Segments;
                    }
                    else
                    {
                        singleSegment[0] = edgeStructure.Segment;
                        edges            = singleSegment;
                    }
                    //-------------

                    for (int i = 0; i < edges.Length; ++i)
                    {
                        EdgeSegment edge = edges[i];

                        SignedDistance distance = edge.signedDistance(p, out double param);//***

                        if (edge.HasComponent(EdgeColor.RED) && distance < r.minDistance)
                        {
                            r.minDistance = distance;
                            r.nearEdge    = edge;
                            r.nearParam   = param;
                            useR          = false;
                        }
                        if (edge.HasComponent(EdgeColor.GREEN) && distance < g.minDistance)
                        {
                            g.minDistance = distance;
                            g.nearEdge    = edge;
                            g.nearParam   = param;
                            useG          = false;
                        }
                        if (edge.HasComponent(EdgeColor.BLUE) && distance < b.minDistance)
                        {
                            b.minDistance = distance;
                            b.nearEdge    = edge;
                            b.nearParam   = param;
                            useB          = false;
                        }
                    }

                    double contour_r = r.CalculateContourColor(p);
                    double contour_g = g.CalculateContourColor(p);
                    double contour_b = b.CalculateContourColor(p);

                    if (useB && contour_b <= SignedDistance.INFINITE.distance)
                    {
                        contour_b = 1 * range;
                    }
                    if (useG && contour_g <= SignedDistance.INFINITE.distance)
                    {
                        contour_g = 1 * range;
                    }
                    if (useR && contour_r <= SignedDistance.INFINITE.distance)
                    {
                        contour_r = 1 * range;
                    }

                    output.SetPixel(x, y,
                                    new FloatRGB(
                                        (float)(contour_r / range + .5),
                                        (float)(contour_g / range + .5),
                                        (float)(contour_b / range + .5)
                                        ));
                }
            }
        }