Example #1
0
        public Texture2D(Pixels.PixelMap pixels)
        {
            GL.ActiveTexture(TextureUnit.Texture0);
            Alpha = pixels.Alpha;
            W     = pixels.Width;
            H     = pixels.Height;
            ID    = GL.GenTexture();
            GL.BindTexture(TextureTarget.Texture2D, ID);
            if (pixels.Alpha)
            {
                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, W, H, 0, PixelFormat.Rgba, PixelType.UnsignedByte, pixels.Data);
            }
            else
            {
                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, W, H, 0, PixelFormat.Rgb, PixelType.UnsignedByte, pixels.Data);
            }

            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);

            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
            GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);

            GL.PixelStore(PixelStoreParameter.PackAlignment, 4 * 4);
            pixs = pixels.Data;
        }
Example #2
0
        public Vivid.Texture.Texture2D GenString(string text, Color fore, Color bg)
        {
            if (Cache.ContainsKey(text))
            {
                return(Cache[text]);
            }

            var   measuredChars = new List <DebugChar>();
            var   renderedChars = new List <DebugChar>();
            float penX = 0, penY = 0;
            float stringWidth      = 0; // the measured width of the string
            float stringHeight     = 0; // the measured height of the string
            float overrun          = 0;
            float underrun         = 0;
            float kern             = 0;
            int   spacingError     = 0;
            bool  trackingUnderrun = true;
            int   rightEdge        = 0; // tracking rendered right side for debugging

            // Bottom and top are both positive for simplicity.
            // Drawing in .Net has 0,0 at the top left corner, with positive X to the right
            // and positive Y downward.
            // Glyph metrics have an origin typically on the left side and at baseline
            // of the visual data, but can draw parts of the glyph in any quadrant, and
            // even move the origin (via kerning).
            float top = 0, bottom = 0;

            // Measure the size of the string before rendering it. We need to do this so
            // we can create the proper size of bitmap (canvas) to draw the characters on.
            for (int i = 0; i < text.Length; i++)
            {
                #region Load character

                char c = text[i];

                // Look up the glyph index for this character.
                uint glyphIndex = _Face.GetCharIndex(c);

                // Load the glyph into the font's glyph slot. There is usually only one slot in the font.
                _Face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);

                // Refer to the diagram entitled "Glyph Metrics" at http://www.freetype.org/freetype2/docs/tutorial/step2.html.
                // There is also a glyph diagram included in this example (glyph-dims.svg).
                // The metrics below are for the glyph loaded in the slot.
                float gAdvanceX = (float)_Face.Glyph.Advance.X; // same as the advance in metrics
                float gBearingX = (float)_Face.Glyph.Metrics.HorizontalBearingX;
                float gWidth    = _Face.Glyph.Metrics.Width.ToSingle();
                var   rc        = new DebugChar(c, gAdvanceX, gBearingX, gWidth);

                #endregion Load character

                #region Underrun

                // Negative bearing would cause clipping of the first character
                // at the left boundary, if not accounted for.
                // A positive bearing would cause empty space.
                underrun += -(gBearingX);
                if (stringWidth == 0)
                {
                    stringWidth += underrun;
                }
                if (trackingUnderrun)
                {
                    rc.Underrun = underrun;
                }
                if (trackingUnderrun && underrun <= 0)
                {
                    underrun         = 0;
                    trackingUnderrun = false;
                }

                #endregion Underrun

                #region Overrun

                // Accumulate overrun, which coould cause clipping at the right side of characters near
                // the end of the string (typically affects fonts with slanted characters)
                if (gBearingX + gWidth > 0 || gAdvanceX > 0)
                {
                    overrun -= Math.Max(gBearingX + gWidth, gAdvanceX);
                    if (overrun <= 0)
                    {
                        overrun = 0;
                    }
                }
                overrun += (float)(gBearingX == 0 && gWidth == 0 ? 0 : gBearingX + gWidth - gAdvanceX);
                // On the last character, apply whatever overrun we have to the overall width.
                // Positive overrun prevents clipping, negative overrun prevents extra space.
                if (i == text.Length - 1)
                {
                    stringWidth += overrun;
                }
                rc.Overrun = overrun; // accumulating (per above)

                #endregion Overrun

                #region Top/Bottom

                // If this character goes higher or lower than any previous character, adjust
                // the overall height of the bitmap.
                float glyphTop    = (float)_Face.Glyph.Metrics.HorizontalBearingY;
                float glyphBottom = (float)(_Face.Glyph.Metrics.Height - _Face.Glyph.Metrics.HorizontalBearingY);
                if (glyphTop > top)
                {
                    top = glyphTop;
                }
                if (glyphBottom > bottom)
                {
                    bottom = glyphBottom;
                }

                #endregion Top/Bottom

                // Accumulate the distance between the origin of each character (simple width).
                stringWidth += gAdvanceX;
                rc.RightEdge = stringWidth;
                measuredChars.Add(rc);

                #region Kerning (for NEXT character)

                // Calculate kern for the NEXT character (if any)
                // The kern value adjusts the origin of the next character (positive or negative).
                if (_Face.HasKerning && i < text.Length - 1)
                {
                    char cNext = text[i + 1];
                    kern = (float)_Face.GetKerning(glyphIndex, _Face.GetCharIndex(cNext), KerningMode.Default).X;
                    // sanity check for some fonts that have kern way out of whack
                    if (kern > gAdvanceX * 5 || kern < -(gAdvanceX * 5))
                    {
                        kern = 0;
                    }
                    rc.Kern      = kern;
                    stringWidth += kern;
                }

                #endregion Kerning (for NEXT character)
            }

            stringHeight = top + bottom;

            // If any dimension is 0, we can't create a bitmap
            if (stringWidth == 0 || stringHeight == 0)
            {
                return(null);
            }

            // Create a new bitmap that fits the string.
            //Bitmap bmp = new Bitmap((int)Math.Ceiling(stringWidth), (int)Math.Ceiling(stringHeight));
            Pixels.PixelMap pmp = new Pixels.PixelMap((int)Math.Ceiling(stringWidth), (int)Math.Ceiling(stringHeight), true);

            trackingUnderrun = true;
            underrun         = 0;
            overrun          = 0;
            stringWidth      = 0;

            // Draw the string into the bitmap.
            // A lot of this is a repeat of the measuring steps, but this time we have
            // an actual bitmap to work with (both canvas and bitmaps in the glyph slot).
            for (int i = 0; i < text.Length; i++)
            {
                #region Load character

                char c = text[i];

                // Same as when we were measuring, except RenderGlyph() causes the glyph data
                // to be converted to a bitmap.
                uint glyphIndex = _Face.GetCharIndex(c);
                _Face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                _Face.Glyph.RenderGlyph(RenderMode.Normal);
                FTBitmap ftbmp = _Face.Glyph.Bitmap;

                float gAdvanceX = (float)_Face.Glyph.Advance.X;
                float gBearingX = (float)_Face.Glyph.Metrics.HorizontalBearingX;
                float gWidth    = (float)_Face.Glyph.Metrics.Width;

                var rc = new DebugChar(c, gAdvanceX, gBearingX, gWidth);

                #endregion Load character

                #region Underrun

                // Underrun
                underrun += -(gBearingX);
                if (penX == 0)
                {
                    penX += underrun;
                }
                if (trackingUnderrun)
                {
                    rc.Underrun = underrun;
                }
                if (trackingUnderrun && underrun <= 0)
                {
                    underrun         = 0;
                    trackingUnderrun = false;
                }

                #endregion Underrun

                #region Draw glyph

                // Whitespace characters sometimes have a bitmap of zero size, but a non-zero advance.
                // We can't draw a 0-size bitmap, but the pen position will still get advanced (below).
                if ((ftbmp.Width > 0 && ftbmp.Rows > 0))
                {
                    // Get a bitmap that .Net can draw (GDI+ in this case).
                    Bitmap cBmp = ftbmp.ToGdipBitmap(fore);
                    rc.Width    = cBmp.Width;
                    rc.BearingX = _Face.Glyph.BitmapLeft;
                    int x = (int)Math.Round(penX + _Face.Glyph.BitmapLeft);
                    int y = (int)Math.Round(penY + top - (float)_Face.Glyph.Metrics.HorizontalBearingY);
                    //Not using g.DrawImage because some characters come out blurry/clipped. (Is this still true?)
                    for (int yr = 0; yr < cBmp.Height; yr++)
                    {
                        for (int xr = 0; xr < cBmp.Width; xr++)
                        {
                            byte r, g, b, a;
                            var  opix = cBmp.GetPixel(xr, yr);
                            r = opix.R;
                            g = opix.G;
                            b = opix.B;
                            a = opix.A;

                            pmp.SetRGB(x + xr, y + yr, r, g, b, a);
                        }
                    }

                    //    g.DrawImageUnscaled(cBmp, x, y);

                    rc.Overrun = _Face.Glyph.BitmapLeft + cBmp.Width - gAdvanceX;
                    // Check if we are aligned properly on the right edge (for debugging)
                    rightEdge    = Math.Max(rightEdge, x + cBmp.Width);
                    spacingError = pmp.Width - rightEdge;
                }
                else
                {
                    rightEdge    = (int)(penX + gAdvanceX);
                    spacingError = pmp.Width - rightEdge;
                }

                #endregion Draw glyph

                #region Overrun

                if (gBearingX + gWidth > 0 || gAdvanceX > 0)
                {
                    overrun -= Math.Max(gBearingX + gWidth, gAdvanceX);
                    if (overrun <= 0)
                    {
                        overrun = 0;
                    }
                }
                overrun += (float)(gBearingX == 0 && gWidth == 0 ? 0 : gBearingX + gWidth - gAdvanceX);
                if (i == text.Length - 1)
                {
                    penX += overrun;
                }
                rc.Overrun = overrun;

                #endregion Overrun

                // Advance pen positions for drawing the next character.
                penX += (float)_Face.Glyph.Advance.X; // same as Metrics.HorizontalAdvance?
                penY += (float)_Face.Glyph.Advance.Y;

                rc.RightEdge = penX;
                spacingError = pmp.Width - (int)Math.Round(rc.RightEdge);
                renderedChars.Add(rc);

                #region Kerning (for NEXT character)

                // Adjust for kerning between this character and the next.
                if (_Face.HasKerning && i < text.Length - 1)
                {
                    char cNext = text[i + 1];
                    kern = (float)_Face.GetKerning(glyphIndex, _Face.GetCharIndex(cNext), KerningMode.Default).X;
                    if (kern > gAdvanceX * 5 || kern < -(gAdvanceX * 5))
                    {
                        kern = 0;
                    }
                    rc.Kern = kern;
                    penX   += (float)kern;
                }

                #endregion Kerning (for NEXT character)
            }

            bool printedHeader = false;
            if (spacingError != 0)
            {
                for (int i = 0; i < renderedChars.Count; i++)
                {
                    //if (measuredChars[i].RightEdge != renderedChars[i].RightEdge)
                    //{
                    if (!printedHeader)
                    {
                        DebugChar.PrintHeader();
                    }
                    printedHeader = true;
                    // Debug.Print(measuredChars[i].ToString());
                    // Debug.Print(renderedChars[i].ToString());

                    //}
                }
                string msg = string.Format("Right edge: {0,3} ({1}) {2}",
                                           spacingError,
                                           spacingError == 0 ? "perfect" : spacingError > 0 ? "space  " : "clipped",
                                           _Face.FamilyName);
                System.Diagnostics.Debug.Print(msg);
                //throw new ApplicationException(msg);
            }

            int loc = 0;

            Texture.Texture2D new_Tex = new Texture.Texture2D(pmp);
            Cache.Add(text, new_Tex);

            return(new_Tex);
        }