예제 #1
0
        /// <summary>
        /// Upload a character's bitmap into the current cache.
        /// </summary>
        /// <param name="character">The character specifications corresponding to the bitmap</param>
        public void UploadCharacterBitmap(CommandList commandList, CharacterSpecification character)
        {
            if(character.Bitmap == null)
                throw new ArgumentNullException("character");

            if(character.IsBitmapUploaded)
                throw new InvalidOperationException("The character '"+character.Character+"' upload has been requested while its current glyph is valid.");

            var targetSize = new Int2(character.Bitmap.Width, character.Bitmap.Rows);
            if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
            {
                // not enough space to place the new character -> remove less used characters and try again
                RemoveLessUsedCharacters();
                if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
                {
                    // memory is too fragmented in order to place the new character -> clear all the characters and restart.
                    ClearCache();
                    if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
                        throw new InvalidOperationException("The rendered character is too big for the cache texture");
                }
            }
            // updload the bitmap on the texture (if the size in the bitmap is not null)
            if (character.Bitmap.Rows != 0 && character.Bitmap.Width != 0)
            {
                var dataBox = new DataBox(character.Bitmap.Buffer, character.Bitmap.Pitch, character.Bitmap.Pitch * character.Bitmap.Rows);
                var region = new ResourceRegion(character.Glyph.Subrect.Left, character.Glyph.Subrect.Top, 0, character.Glyph.Subrect.Right, character.Glyph.Subrect.Bottom, 1);
                commandList.UpdateSubresource(cacheTextures[0], 0, dataBox, region);
            }

            // update the glyph data
            character.IsBitmapUploaded = true;
            character.Glyph.BitmapIndex = 0;
        }
예제 #2
0
 private static void ResetGlyph(CharacterSpecification character)
 {
     character.Glyph.Offset         = Vector2.Zero;
     character.Glyph.XAdvance       = 0;
     character.Glyph.BitmapIndex    = 0;
     character.Glyph.Subrect.X      = 0;
     character.Glyph.Subrect.Y      = 0;
     character.Glyph.Subrect.Width  = 0;
     character.Glyph.Subrect.Height = 0;
 }
예제 #3
0
        public void NotifyCharacterUtilization(CharacterSpecification character)
        {
            character.LastUsedFrame = system.FrameCount;

            if (character.ListNode.List != null)
            {
                cachedCharacters.Remove(character.ListNode);
            }
            cachedCharacters.AddFirst(character.ListNode);
        }
예제 #4
0
        private CharacterSpecification GetOrCreateCharacterData(Vector2 size, char character)
        {
            // build the dictionary look up key
            var lookUpKey = new CharacterKey(character, size);

            // get the entry (creates it if it does not exist)
            CharacterSpecification characterData;

            if (!sizedCharacterToCharacterData.TryGetValue(lookUpKey, out characterData))
            {
                characterData = new CharacterSpecification(character, FontName, size, Style, AntiAlias);
                sizedCharacterToCharacterData[lookUpKey] = characterData;
            }
            return(characterData);
        }
예제 #5
0
        /// <summary>
        /// Start the generation of the specified character's bitmap.
        /// </summary>
        /// <remarks>Does nothing if the bitmap already exist or if the generation is currently running.</remarks>
        /// <param name="characterSpecification">The character we want the bitmap of</param>
        /// <param name="synchronously">Indicate if the generation of the bitmap must by done synchronously or asynchronously</param>
        public void GenerateBitmap(CharacterSpecification characterSpecification, bool synchronously)
        {
            // generate the glyph info (and the bitmap if required) synchronously
            GenerateCharacterGlyph(characterSpecification, synchronously);

            // add the bitmap rendering job to a request queue if rendering is asynchronous
            if (!synchronously)
            {
                lock (dataStructuresLock)
                {
                    if (characterSpecification.Bitmap == null && !bitmapsToGenerate.Contains(characterSpecification))
                    {
                        bitmapsToGenerate.Enqueue(characterSpecification);
                        bitmapBuildSignal.Set();
                    }
                }
            }
        }
예제 #6
0
        private void GenerateCharacterGlyph(CharacterSpecification character, bool renderBitmap)
        {
            // first the possible current glyph info
            ResetGlyph(character);

            // let the glyph info null if the size is not valid
            if (character.Size.X < 1 || character.Size.Y < 1)
            {
                return;
            }

            // get the face of the font
            var fontFace = GetOrCreateFontFace(character.FontName, character.Style);

            lock (freetypeLibrary)
            {
                // set the font size
                SetFontFaceSize(fontFace, character.Size);

                // get the glyph and render the bitmap
                var glyphIndex = fontFace.GetCharIndex(character.Character);

                // the character does not exit => let the glyph info null
                if (glyphIndex == 0)
                {
                    return;
                }

                // load the character glyph
                fontFace.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);

                // set glyph information
                character.Glyph.XAdvance = fontFace.Glyph.Advance.X.ToSingle();

                // render the bitmap
                if (renderBitmap)
                {
                    RenderBitmap(character, fontFace);
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Upload a character's bitmap into the current cache.
        /// </summary>
        /// <param name="character">The character specifications corresponding to the bitmap</param>
        public void UploadCharacterBitmap(CommandList commandList, CharacterSpecification character)
        {
            if (character.Bitmap == null)
            {
                throw new ArgumentNullException("character");
            }

            if (character.IsBitmapUploaded)
            {
                throw new InvalidOperationException("The character '" + character.Character + "' upload has been requested while its current glyph is valid.");
            }

            var targetSize = new Int2(character.Bitmap.Width, character.Bitmap.Rows);

            if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
            {
                // not enough space to place the new character -> remove less used characters and try again
                RemoveLessUsedCharacters();
                if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
                {
                    // memory is too fragmented in order to place the new character -> clear all the characters and restart.
                    ClearCache();
                    if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
                    {
                        throw new InvalidOperationException("The rendered character is too big for the cache texture");
                    }
                }
            }
            // updload the bitmap on the texture (if the size in the bitmap is not null)
            if (character.Bitmap.Rows != 0 && character.Bitmap.Width != 0)
            {
                var dataBox = new DataBox(character.Bitmap.Buffer, character.Bitmap.Pitch, character.Bitmap.Pitch * character.Bitmap.Rows);
                var region  = new ResourceRegion(character.Glyph.Subrect.Left, character.Glyph.Subrect.Top, 0, character.Glyph.Subrect.Right, character.Glyph.Subrect.Bottom, 1);
                commandList.UpdateSubresource(cacheTextures[0], 0, dataBox, region);
            }

            // update the glyph data
            character.IsBitmapUploaded  = true;
            character.Glyph.BitmapIndex = 0;
        }
예제 #8
0
        private void RenderBitmap(CharacterSpecification character, Face fontFace)
        {
            // choose the rendering type and render the glyph
            var renderingMode = character.AntiAlias == FontAntiAliasMode.Aliased ? RenderMode.Mono : RenderMode.Normal;

            fontFace.Glyph.RenderGlyph(renderingMode);

            // create the bitmap
            var bitmap = fontFace.Glyph.Bitmap;

            if (bitmap.Width != 0 && bitmap.Rows != 0)
            {
                character.Bitmap = new CharacterBitmap(bitmap.Buffer, ref borderSize, bitmap.Width, bitmap.Rows, bitmap.Pitch, bitmap.GrayLevels, bitmap.PixelMode);
            }
            else
            {
                character.Bitmap = new CharacterBitmap();
            }

            // set the glyph offsets
            character.Glyph.Offset = new Vector2(fontFace.Glyph.BitmapLeft - borderSize.X, -fontFace.Glyph.BitmapTop - borderSize.Y);
        }
예제 #9
0
        public void TestGenerateBitmap()
        {
            var fontManager = new FontManager();
            const int waitTime = 250;
            const int defaultSize = 4;

            // test that a simple bitmap generation success
            var characterA = new CharacterSpecification('a', "Arial", new Vector2(1.73f, 3.57f), FontStyle.Regular, FontAntiAliasMode.Default);
            fontManager.GenerateBitmap(characterA, false);
            WaitAndCheck(characterA, waitTime);
            Assert.AreEqual(4, characterA.Bitmap.Width);
            Assert.AreEqual(6, characterA.Bitmap.Rows);
            
            // test that rendering an already existing character to a new size works
            var characterA2 = new CharacterSpecification('a', "Arial", 10f * Vector2.One, FontStyle.Regular, FontAntiAliasMode.Default);
            fontManager.GenerateBitmap(characterA2, false);
            WaitAndCheck(characterA2, waitTime);
            Assert.AreNotEqual(2, characterA2.Bitmap.Width);
            Assert.AreNotEqual(4, characterA2.Bitmap.Rows);

            // test that trying to render a character that does not exist does not crash the system
            var characterTo = new CharacterSpecification('都', "Arial", defaultSize * Vector2.One, FontStyle.Regular, FontAntiAliasMode.Default);
            var characterB = new CharacterSpecification('b', "Arial", defaultSize * Vector2.One, FontStyle.Regular, FontAntiAliasMode.Default);
            fontManager.GenerateBitmap(characterTo, false);
            fontManager.GenerateBitmap(characterB, false);
            WaitAndCheck(characterB, 2 * waitTime);
            Assert.AreEqual(null, characterTo.Bitmap);

            // test that trying to render a character that does not exist does not crash the system
            var characterC = new CharacterSpecification('c', "Arial", -1 * Vector2.One, FontStyle.Regular, FontAntiAliasMode.Default);
            var characterD = new CharacterSpecification('d', "Arial", defaultSize * Vector2.One, FontStyle.Regular, FontAntiAliasMode.Default);
            fontManager.GenerateBitmap(characterC, false);
            fontManager.GenerateBitmap(characterD, false);
            WaitAndCheck(characterD, 2 * waitTime);
            Assert.AreEqual(null, characterC.Bitmap);
            
            fontManager.Dispose();
        }
예제 #10
0
 public static bool Equals(CharacterSpecification left, CharacterSpecification right)
 {
     return(left.Character == right.Character && left.FontName == right.FontName && left.Size == right.Size && left.Style == right.Style && left.AntiAlias == right.AntiAlias);
 }
예제 #11
0
        private void GenerateCharacterGlyph(CharacterSpecification character, bool renderBitmap)
        {
            // first the possible current glyph info
            ResetGlyph(character);

            // let the glyph info null if the size is not valid
            if (character.Size.X < 1 || character.Size.Y < 1)
                return;

            // get the face of the font 
            var fontFace = GetOrCreateFontFace(character.FontName, character.Style);
            lock (freetypeLibrary)
            {
                // set the font size
                SetFontFaceSize(fontFace, character.Size);

                // get the glyph and render the bitmap
                var glyphIndex = fontFace.GetCharIndex(character.Character);

                // the character does not exit => let the glyph info null
                if (glyphIndex == 0)
                    return;

                // load the character glyph
                fontFace.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);

                // set glyph information
                character.Glyph.XAdvance = fontFace.Glyph.Advance.X.ToSingle();

                // render the bitmap
                if (renderBitmap)
                    RenderBitmap(character, fontFace);
            }
        }
예제 #12
0
        /// <summary>
        /// Start the generation of the specified character's bitmap. 
        /// </summary>
        /// <remarks>Does nothing if the bitmap already exist or if the generation is currently running.</remarks>
        /// <param name="characterSpecification">The character we want the bitmap of</param>
        /// <param name="synchronously">Indicate if the generation of the bitmap must by done synchronously or asynchronously</param>
        public void GenerateBitmap(CharacterSpecification characterSpecification, bool synchronously)
        {
            // generate the glyph info (and the bitmap if required) synchronously
            GenerateCharacterGlyph(characterSpecification, synchronously);

            // add the bitmap rendering job to a request queue if rendering is asynchronous
            if (!synchronously)
            {
                lock (dataStructuresLock)
                {
                    if (characterSpecification.Bitmap == null && !bitmapsToGenerate.Contains(characterSpecification))
                    {
                        bitmapsToGenerate.Enqueue(characterSpecification);
                        bitmapBuildSignal.Set();
                    }
                }
            }
        }
예제 #13
0
        private void RenderBitmap(CharacterSpecification character, Face fontFace)
        {
            // choose the rendering type and render the glyph
            var renderingMode = character.AntiAlias == FontAntiAliasMode.Aliased ? RenderMode.Mono : RenderMode.Normal;
            fontFace.Glyph.RenderGlyph(renderingMode);

            // create the bitmap
            var bitmap = fontFace.Glyph.Bitmap;
            if (bitmap.Width != 0 && bitmap.Rows != 0)
                character.Bitmap = new CharacterBitmap(bitmap.Buffer, ref borderSize, bitmap.Width, bitmap.Rows, bitmap.Pitch, bitmap.GrayLevels, bitmap.PixelMode);
            else
                character.Bitmap = new CharacterBitmap();

            // set the glyph offsets
            character.Glyph.Offset = new Vector2(fontFace.Glyph.BitmapLeft - borderSize.X, -fontFace.Glyph.BitmapTop - borderSize.Y);
        }
예제 #14
0
 private static void ResetGlyph(CharacterSpecification character)
 {
     character.Glyph.Offset = Vector2.Zero;
     character.Glyph.XAdvance = 0;
     character.Glyph.BitmapIndex = 0;
     character.Glyph.Subrect.X = 0;
     character.Glyph.Subrect.Y = 0;
     character.Glyph.Subrect.Width = 0;
     character.Glyph.Subrect.Height = 0;
 }
예제 #15
0
        public void NotifyCharacterUtilization(CharacterSpecification character)
        {
            character.LastUsedFrame = system.FrameCount;

            if(character.ListNode.List != null)
                cachedCharacters.Remove(character.ListNode);
            cachedCharacters.AddFirst(character.ListNode);
        }
예제 #16
0
 public static bool Equals(CharacterSpecification left, CharacterSpecification right)
 {
     return left.Character == right.Character && left.FontName == right.FontName && left.Size == right.Size && left.Style == right.Style && left.AntiAlias == right.AntiAlias;
 }
예제 #17
0
 private void WaitAndCheck(CharacterSpecification character, int sleepTime)
 {
     Thread.Sleep(sleepTime);
     Assert.AreNotEqual(null, character.Bitmap);
 }