예제 #1
0
파일: Font.cs 프로젝트: Relfos/LunarFonts
 public void Draw(GlyphBitmap other, int x, int y)
 {
     for (int j = 0; j < other.Height; j++)
     {
         for (int i = 0; i < other.Width; i++)
         {
             var srcOfs  = i + j * other.Width;
             var destOfs = (x + i) + (y + j) * this.Width;
             Pixels[destOfs] = other.Pixels[srcOfs];
         }
     }
 }
예제 #2
0
파일: Font.cs 프로젝트: Relfos/LunarFonts
        private void Rasterize(GlyphBitmap bitmap, float flatnessInPixels, List <Vertex> vertices, float scaleX, float scaleY, float shiftX, float shiftY, int XOff, int YOff, bool Invert)
        {
            float scale = scaleX < scaleY ? scaleX : scaleY;

            int[]        windingLengths;
            List <Point> windings;

            FlattenCurves(vertices, flatnessInPixels / scale, out windingLengths, out windings);
            if (windings.Count > 0)
            {
                Rasterize(bitmap, windings, windingLengths, scaleX, scaleY, shiftX, shiftY, XOff, YOff, Invert);
            }
        }
예제 #3
0
        /*
         * Computes a distance field transform of a high resolution binary source channel and returns the result as a low resolution channel.
         *
         * scale_down : The amount the source channel will be scaled down.
         * A value of 8 means the destination image will be 1/8th the size of the source
         *
         * spread: The spread in pixels before the distance field clamps to (zero/one).
         * The valueis specified in units of the destination image. The spread in the source image will be spread*scale_down.
         */
        public static GlyphBitmap CreateDistanceField(GlyphBitmap source, int scale, float spread)
        {
            var result = new GlyphBitmap(source.Width / scale, source.Height / scale);

            var values = source.Pixels.Select(x => (x / 255.0f) - 0.5f).ToArray();

            for (int y = 0; y < result.Height; y++)
            {
                for (int x = 0; x < result.Width; x++)
                {
                    var sd = SignedDistance(values, source.Width, source.Height, x * scale, y * scale, spread);
                    var n  = (sd + spread) / (spread * 2.0f);

                    var c      = (byte)(n * 255);
                    var offset = x + y * result.Width;
                    result.Pixels[offset] = c;
                }
            }

            return(result);
        }
예제 #4
0
파일: Font.cs 프로젝트: Relfos/LunarFonts
        private GlyphBitmap GetGlyphBitmap(float scale_x, float scale_y, float shift_x, float shift_y, int glyph, out int xoff, out int yoff)
        {
            var vertices = GetGlyphShape(glyph);

            if (scale_x == 0)
            {
                scale_x = scale_y;
            }

            if (scale_y == 0)
            {
                if (scale_x == 0)
                {
                    throw new Exception("invalid scale");
                }

                scale_y = scale_x;
            }

            int ix0, iy0, ix1, iy1;

            GetGlyphBitmapBox(glyph, scale_x, scale_y, shift_x, shift_y, out ix0, out iy0, out ix1, out iy1);

            int w = (ix1 - ix0);
            int h = (iy1 - iy0);

            if (w <= 0 || h <= 0)
            {
                throw new Exception("invalid glyph size");
            }

            // now we get the size
            var result = new GlyphBitmap(w, h);

            xoff = ix0;
            yoff = iy0;
            Rasterize(result, 0.35f, vertices, scale_x, scale_y, shift_x, shift_y, ix0, iy0, true);
            return(result);
        }
예제 #5
0
파일: Font.cs 프로젝트: Relfos/LunarFonts
        private void RasterizeSortedEdges(GlyphBitmap bitmap, List <Edge> e, int vSubSamples, int offX, int off_y)
        {
            int eIndex = 0;

            ActiveEdge active     = null;
            int        max_weight = 255 / vSubSamples; // weight per vertical scanline

            int y = off_y * vSubSamples;

            int n        = e.Count - 1;
            var tempEdge = e[n];

            tempEdge.y0 = (off_y + bitmap.Height) * vSubSamples + 1;
            e[n]        = tempEdge;

            var scanline = new byte[bitmap.Width];

            float scanY = 0;

            int j = 0;

            while (j < bitmap.Height)
            {
                for (int iii = 0; iii < bitmap.Width; iii++)
                {
                    scanline[iii] = 0;
                }

                for (int s = 0; s < vSubSamples; s++)
                {
                    // find center of pixel for this scanline
                    scanY = y + 0.5f;

                    // update all active edges;
                    // remove all active edges that terminate before the center of this scanline
                    var        curr = active;
                    ActiveEdge prev = null;
                    while (curr != null)
                    {
                        if (curr.ey <= scanY)
                        {
                            // delete from list
                            if (prev != null)
                            {
                                prev.next = curr.next;
                            }
                            else
                            {
                                active = curr.next;
                            }

                            curr = curr.next;
                        }

                        else
                        {
                            curr.x += curr.dx; // advance to position for current scanline

                            prev = curr;
                            curr = curr.next; // advance through list
                        }
                    }

                    // resort the list if needed
                    bool changed;
                    do
                    {
                        changed = false;

                        curr = active;
                        prev = null;
                        while (curr != null && curr.next != null)
                        {
                            var prox = curr.next;
                            if (curr.x > prox.x)
                            {
                                if (prev == null)
                                {
                                    active = prox;
                                }
                                else
                                {
                                    prev.next = prox;
                                }

                                curr.next = prox.next;
                                prox.next = curr;
                                Console.WriteLine("Sorted " + curr.ey + " with " + prox.ey);
                                changed = true;
                            }

                            prev = curr;
                            curr = curr.next; // advance through list
                        }
                    } while (changed);

                    // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline
                    while (e[eIndex].y0 <= scanY)
                    {
                        if (e[eIndex].y1 > scanY)
                        {
                            var z = CreateActiveEdge(e[eIndex], offX, scanY);
                            // find insertion point
                            if (active == null)
                            {
                                active = z;
                            }
                            else
                            if (z.x < active.x)  // insert at front
                            {
                                z.next = active;
                                active = z;
                            }
                            else
                            {
                                // find thing to insert AFTER
                                var p = active;
                                while (p.next != null && p.next.x < z.x)
                                {
                                    p = p.next;
                                }

                                // at this point, p->next->x is NOT < z->x
                                z.next = p.next;
                                p.next = z;
                            }
                        }

                        eIndex++;
                    }

                    // now process all active edges in XOR fashion
                    if (active != null)
                    {
                        FillActiveEdges(scanline, bitmap.Width, active, max_weight);
                    }

                    y++;
                }

                for (int iii = 0; iii < bitmap.Width; iii++)
                {
                    if (scanline[iii] > 0) // OPTIMIZATION?
                    {
                        int ofs = iii + j * bitmap.Width;
                        bitmap.Pixels[ofs] = scanline[iii];
                    }
                }

                j++;
            }
        }
예제 #6
0
파일: Font.cs 프로젝트: Relfos/LunarFonts
        private void Rasterize(GlyphBitmap bitmap, List <Point> points, int[] windings, float scaleX, float scaleY, float shiftX, float shiftY, int XOff, int YOff, bool invert)
        {
            int ptOfs = 0;

            float yScaleInv = invert ? -scaleY : scaleY;

            // this value should divide 255 evenly; otherwise we won't reach full opacity
            int vSubSamples = (bitmap.Height < 8) ? 15 : 5;

            var edgeList = new List <Edge>(16);
            int m        = 0;

            for (int i = 0; i < windings.Length; i++)
            {
                ptOfs = m;

                m += windings[i];
                int j = windings[i] - 1;
                int k = 0;

                while (k < windings[i])
                {
                    int a = k;
                    int b = j;

                    var en = new Edge();

                    // skip the edge if horizontal
                    if (points[ptOfs + j].y != points[ptOfs + k].y)
                    {
                        // add edge from j to k to the list
                        en.invert = false;

                        if ((invert && points[ptOfs + j].y > points[ptOfs + k].y) || (!invert && points[ptOfs + j].y < points[ptOfs + k].y))
                        {
                            en.invert = true;
                            a         = j;
                            b         = k;
                        }

                        en.x0 = points[ptOfs + a].x * scaleX + shiftX;
                        en.y0 = points[ptOfs + a].y * yScaleInv * vSubSamples + shiftY;
                        en.x1 = points[ptOfs + b].x * scaleX + shiftX;
                        en.y1 = points[ptOfs + b].y * yScaleInv * vSubSamples + shiftY;

                        edgeList.Add(en);
                    }

                    j = k;
                    k++;
                }
            }

            points.Clear();

            // now sort the edges by their highest point (should snap to integer, and then by x)
            edgeList.Sort((x, y) => EdgeCompare(x, y));

            var temp = new Edge();

            temp.y0 = 10000000;
            edgeList.Add(temp);

            // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule
            RasterizeSortedEdges(bitmap, edgeList, vSubSamples, XOff, YOff);
        }