Beispiel #1
0
        private FontAtlas GetCurrentAtlas(ITexture2DManager device, int textureWidth, int textureHeight)
#endif
        {
            if (_currentAtlas == null)
            {
                Texture2D existingTexture = null;
                if (ExistingTexture != null && Atlases.Count == 0)
                {
                    existingTexture = ExistingTexture;
                }

                _currentAtlas = new FontAtlas(textureWidth, textureHeight, 256, existingTexture);

                // If existing texture is used, mark existing used rect as used
                if (existingTexture != null && !ExistingTextureUsedSpace.IsEmpty)
                {
                    if (!_currentAtlas.AddSkylineLevel(0, ExistingTextureUsedSpace.X, ExistingTextureUsedSpace.Y, ExistingTextureUsedSpace.Width, ExistingTextureUsedSpace.Height))
                    {
                        throw new Exception(string.Format("Unable to specify existing texture used space: {0}", ExistingTextureUsedSpace));
                    }

                    // TODO: Clear remaining space
                }

                Atlases.Add(_currentAtlas);
            }

            return(_currentAtlas);
        }
Beispiel #2
0
        public FontSystem(IFontLoader fontLoader, ITexture2DManager textureCreator, int width = 1024, int height = 1024, int blurAmount = 0, int strokeAmount = 0, bool premultiplyAlpha = true)
#endif
        {
            if (fontLoader == null)
            {
                throw new ArgumentNullException(nameof(fontLoader));
            }

#if MONOGAME || FNA || STRIDE
            if (graphicsDevice == null)
            {
                throw new ArgumentNullException(nameof(graphicsDevice));
            }

            _graphicsDevice = graphicsDevice;
#else
            if (textureCreator == null)
            {
                throw new ArgumentNullException(nameof(textureCreator));
            }

            _textureCreator = textureCreator;
#endif

            _fontLoader = fontLoader;

            if (width <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(width));
            }

            if (height <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(height));
            }

            if (blurAmount < 0 || blurAmount > 20)
            {
                throw new ArgumentOutOfRangeException(nameof(blurAmount));
            }

            if (strokeAmount < 0 || strokeAmount > 20)
            {
                throw new ArgumentOutOfRangeException(nameof(strokeAmount));
            }

            if (strokeAmount != 0 && blurAmount != 0)
            {
                throw new ArgumentException("Cannot have both blur and stroke.");
            }

            BlurAmount       = blurAmount;
            StrokeAmount     = strokeAmount;
            PremultiplyAlpha = premultiplyAlpha;

            _size = new Point(width, height);
        }
        protected internal override FontGlyph GetGlyph(ITexture2DManager device, int codepoint)
#endif
        {
            var result = InternalGetGlyph(codepoint);

            if (result == null && DefaultCharacter != null)
            {
                result = InternalGetGlyph(DefaultCharacter.Value);
            }
            return(result);
        }
        private DynamicFontGlyph GetDynamicGlyph(ITexture2DManager device, int codepoint)
#endif
        {
            var result = GetGlyphInternal(device, codepoint);

            if (result == null && FontSystem.DefaultCharacter != null)
            {
                result = GetGlyphInternal(device, FontSystem.DefaultCharacter.Value);
            }

            return(result);
        }
        private DynamicFontGlyph GetGlyphInternal(ITexture2DManager device, int codepoint)
#endif
        {
            var glyph = GetGlyphWithoutBitmap(codepoint);

            if (glyph == null)
            {
                return(null);
            }

            if (device == null || glyph.Texture != null)
            {
                return(glyph);
            }

            FontSystem.RenderGlyphOnAtlas(device, glyph);

            return(glyph);
        }
Beispiel #6
0
        internal void RenderGlyphOnAtlas(ITexture2DManager device, DynamicFontGlyph glyph)
#endif
        {
            var textureSize = new Point(TextureWidth, TextureHeight);

            if (ExistingTexture != null)
            {
#if MONOGAME || FNA || STRIDE
                textureSize = new Point(ExistingTexture.Width, ExistingTexture.Height);
#else
                textureSize = device.GetTextureSize(ExistingTexture);
#endif
            }

            int gx = 0, gy = 0;
            var gw = glyph.Bounds.Width;
            var gh = glyph.Bounds.Height;

            var currentAtlas = GetCurrentAtlas(device, textureSize.X, textureSize.Y);
            if (!currentAtlas.AddRect(gw, gh, ref gx, ref gy))
            {
                CurrentAtlasFull?.Invoke(this, EventArgs.Empty);

                // This code will force creation of new atlas
                _currentAtlas = null;
                currentAtlas  = GetCurrentAtlas(device, textureSize.X, textureSize.Y);

                // Try to add again
                if (!currentAtlas.AddRect(gw, gh, ref gx, ref gy))
                {
                    throw new Exception(string.Format("Could not add rect to the newly created atlas. gw={0}, gh={1}", gw, gh));
                }
            }

            glyph.Bounds.X = gx;
            glyph.Bounds.Y = gy;

            currentAtlas.RenderGlyph(device, glyph, FontSources[glyph.FontSourceIndex], BlurAmount, StrokeAmount, PremultiplyAlpha, KernelWidth, KernelHeight);

            glyph.Texture = currentAtlas.Texture;
        }
        public unsafe static StaticSpriteFont FromBMFont(string data, Func <string, Stream> imageStreamOpener, ITexture2DManager textureManager)
#endif
        {
            var bmFont = LoadBMFont(data);

            var textures = new Dictionary <string, Texture2D>();

            for (var i = 0; i < bmFont.Pages.Length; ++i)
            {
                var    fileName = bmFont.Pages[i].FileName;
                Stream stream   = null;
                try
                {
                    stream = imageStreamOpener(fileName);
                    if (!stream.CanSeek)
                    {
                        // If stream isn't seekable, use MemoryStream instead
                        var ms = new MemoryStream();
                        stream.CopyTo(ms);
                        ms.Seek(0, SeekOrigin.Begin);
                        stream.Dispose();
                        stream = ms;
                    }

                    var image = ImageResult.FromStream(stream, ColorComponents.RedGreenBlueAlpha);
                    if (image.SourceComp == ColorComponents.Grey)
                    {
                        // If input image is single byte per pixel, then StbImageSharp will set alpha to 255 in the resulting 32-bit image
                        // Such behavior isn't acceptable for us
                        // So reset alpha to color value
                        for (var j = 0; j < image.Data.Length / 4; ++j)
                        {
                            image.Data[j * 4 + 3] = image.Data[j * 4];
                        }
                    }

#if MONOGAME || FNA || STRIDE
                    var texture = Texture2DManager.CreateTexture(device, image.Width, image.Height);
                    Texture2DManager.SetTextureData(texture, new Rectangle(0, 0, image.Width, image.Height), image.Data);
#else
                    var texture = textureManager.CreateTexture(image.Width, image.Height);
                    textureManager.SetTextureData(texture, new Rectangle(0, 0, image.Width, image.Height), image.Data);
#endif

                    textures[fileName] = texture;
                }
                finally
                {
                    stream.Dispose();
                }
            }

            return(FromBMFont(bmFont, fileName => new TextureWithOffset(textures[fileName])));
        }
Beispiel #8
0
        public void RenderGlyph(ITexture2DManager textureManager, DynamicFontGlyph glyph, IFontSource fontSource, int blurAmount, int strokeAmount, bool premultiplyAlpha, int kernelWidth, int kernelHeight)
#endif
        {
            var pad = Math.Max(DynamicFontGlyph.PadFromBlur(blurAmount), DynamicFontGlyph.PadFromBlur(strokeAmount));

            // Render glyph to byte buffer
            var bufferSize = glyph.Bounds.Width * glyph.Bounds.Height;
            var buffer     = _byteBuffer;

            if ((buffer == null) || (buffer.Length < bufferSize))
            {
                buffer      = new byte[bufferSize];
                _byteBuffer = buffer;
            }
            Array.Clear(buffer, 0, bufferSize);

            var colorBuffer = _colorBuffer;

            if ((colorBuffer == null) || (colorBuffer.Length < bufferSize * 4))
            {
                colorBuffer  = new byte[bufferSize * 4];
                _colorBuffer = colorBuffer;
            }

            fontSource.RasterizeGlyphBitmap(glyph.Id,
                                            glyph.Size,
                                            buffer,
                                            pad + pad * glyph.Bounds.Width,
                                            glyph.Bounds.Width - pad * 2,
                                            glyph.Bounds.Height - pad * 2,
                                            glyph.Bounds.Width);

            if (strokeAmount > 0)
            {
                var width  = glyph.Bounds.Width;
                var top    = width * strokeAmount;
                var bottom = (glyph.Bounds.Height - strokeAmount) * glyph.Bounds.Width;
                var right  = glyph.Bounds.Width - strokeAmount;
                var left   = strokeAmount;

                byte d;
                for (var i = 0; i < bufferSize; ++i)
                {
                    var ci    = i * 4;
                    var col   = buffer[i];
                    var black = 0;
                    if (col == 255)
                    {
                        colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = colorBuffer[ci + 3] = 255;
                        continue;
                    }

                    if (i >= top)
                    {
                        black = buffer[i - top];
                    }
                    if (i < bottom)
                    {
                        d     = buffer[i + top];
                        black = ((255 - d) * black + 255 * d) / 255;
                    }
                    if (i % width >= left)
                    {
                        d     = buffer[i - strokeAmount];
                        black = ((255 - d) * black + 255 * d) / 255;
                    }
                    if (i % width < right)
                    {
                        d     = buffer[i + strokeAmount];
                        black = ((255 - d) * black + 255 * d) / 255;
                    }

                    if (black == 0)
                    {
                        if (col == 0)
                        {
                            colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = colorBuffer[ci + 3] = 0;                             //black transparency to suit stroke
                            continue;
                        }

                        if (premultiplyAlpha)
                        {
                            colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = colorBuffer[ci + 3] = col;
                        }
                        else
                        {
                            colorBuffer[ci]     = colorBuffer[ci + 1] = colorBuffer[ci + 2] = 255;
                            colorBuffer[ci + 3] = col;
                        }
                    }
                    else
                    {
                        if (col == 0)
                        {
                            colorBuffer[ci]     = colorBuffer[ci + 1] = colorBuffer[ci + 2] = 0;
                            colorBuffer[ci + 3] = (byte)black;
                            continue;
                        }

                        if (premultiplyAlpha)
                        {
                            var alpha = ((255 - col) * black + 255 * col) / 255;
                            colorBuffer[ci]     = colorBuffer[ci + 1] = colorBuffer[ci + 2] = (byte)((alpha * col) / 255);
                            colorBuffer[ci + 3] = (byte)alpha;
                        }
                        else
                        {
                            colorBuffer[ci]     = colorBuffer[ci + 1] = colorBuffer[ci + 2] = col;
                            colorBuffer[ci + 3] = (byte)(((255 - col) * black + 255 * col) / 255);
                        }
                    }
                }
            }
            else
            {
                if (blurAmount > 0)
                {
                    fixed(byte *bdst = &buffer[0])
                    {
                        Blur(bdst, glyph.Bounds.Width, glyph.Bounds.Height, glyph.Bounds.Width, blurAmount);
                    }
                }

                for (var i = 0; i < bufferSize; ++i)
                {
                    var ci = i * 4;
                    var c  = buffer[i];

                    if (premultiplyAlpha)
                    {
                        colorBuffer[ci] = colorBuffer[ci + 1] = colorBuffer[ci + 2] = colorBuffer[ci + 3] = c;
                    }
                    else
                    {
                        colorBuffer[ci]     = colorBuffer[ci + 1] = colorBuffer[ci + 2] = 255;
                        colorBuffer[ci + 3] = c;
                    }
                }
            }

#if MONOGAME || FNA || STRIDE
            // Write to texture
            if (Texture == null)
            {
                Texture = Texture2DManager.CreateTexture(graphicsDevice, Width, Height);
            }

            Texture2DManager.SetTextureData(Texture, glyph.Bounds, colorBuffer);
#else
            // Write to texture
            if (Texture == null)
            {
                Texture = textureManager.CreateTexture(Width, Height);
            }

            textureManager.SetTextureData(Texture, glyph.Bounds, colorBuffer);
#endif
        }
Beispiel #9
0
 protected internal abstract FontGlyph GetGlyph(ITexture2DManager device, int codepoint);
Beispiel #10
0
 public FontSystem(ITexture2DManager textureCreator, int width, int height, int blurAmount = 0, int strokeAmount = 0, bool premultiplyAlpha = true) :
     this(StbTrueTypeSharpFontLoader.Instance, textureCreator, width, height, blurAmount, strokeAmount, premultiplyAlpha)
 {
 }
        protected internal override FontGlyph GetGlyph(ITexture2DManager device, int codepoint)
#endif
        {
            return(GetDynamicGlyph(device, codepoint));
        }