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; }
public void NotifyCharacterUtilization(CharacterSpecification character) { character.LastUsedFrame = system.FrameCount; if (character.ListNode.List != null) { cachedCharacters.Remove(character.ListNode); } cachedCharacters.AddFirst(character.ListNode); }
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); }
/// <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(); } } } }
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); } } }
/// <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. // TODO: This is invalid, we might delete character from current frame! 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; }
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); }
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); }