/// <summary> /// Reloads the font /// </summary> public void ReloadFont() { if (mProject == null) return; int borderWidth = 2; string fullPath = mProject.ProjectDirectory + "/" + mFontFile; if (System.IO.File.Exists(fullPath)) { // Ensure that the character list ALWAYS contains at least the ? character. if (!Characters.Contains('?')) Characters.Add('?'); // Load the image glyph textures foreach (FontBuilder.ImageGlyph imageGlyph in Images) imageGlyph.Load(mProject.ProjectDirectory); if (mFontData != null) mFontData.Dispose(); mFontData = new FontBuilder.FontData(Characters, Images); FontBuilder.Glyph[] glyphs = mFontData.GetGlyphs(fullPath, mFontSize); // Clear out our existing textures and texture atlasses foreach (TextureAtlas atlas in mTextureAtlasses) { DisposeAtlasNode(atlas.mRoot); } mTextureAtlasses.Clear(); mTextures.Clear(); mCharInfoList.Clear(); mMaxTop = -99999; Image texture = null; Bitmap textureBitmap = null; if (File.Exists(mProject.ProjectDirectory + "/" + mTextureFile)) { texture = Image.FromFile(mProject.ProjectDirectory + "/" + mTextureFile); textureBitmap = new Bitmap(texture); } TextureAtlas curAtlas = null; foreach (FontBuilder.Glyph glyph in glyphs) { if (glyph == null) continue; if (mMaxTop < glyph.mTop) mMaxTop = glyph.mTop; Bitmap finalBitmap = null; if (glyph.mBitmap != null) { finalBitmap = (borderWidth == 0) ? new Bitmap(glyph.mBitmap) : Utils.ExpandImageBorder(glyph.mBitmap, borderWidth, true); if (finalBitmap == null) continue; Bitmap outlinedBitmap = null; Bitmap texturedBitmap = null; if (OutlineAmount > 0.0f && OutlineColor.A != 0) { float s = Math.Min(1.0f, Math.Max(OutlineSharpness, 0.0f)); outlinedBitmap = BlurBitmap(finalBitmap, OutlineAmount, OutlineSharpness, OutlineColor); finalBitmap.Dispose(); finalBitmap = outlinedBitmap; } BitmapData texturedBitmapData = null; if (textureBitmap != null && glyph.mImageGlyph == 0) { texturedBitmap = ApplyTexture(textureBitmap, glyph.mBitmap, mTextureBaseline, glyph.mTop); texturedBitmapData = texturedBitmap.LockBits(new Rectangle(0, 0, texturedBitmap.Width, texturedBitmap.Height), ImageLockMode.ReadOnly, texturedBitmap.PixelFormat); } // Now we need to use the original bitmap (from the glyph) and reapply it to the new // bitmap (that may or may not have been blurred) with the fill color BitmapData sourceBitmapData = glyph.mBitmap.LockBits( new Rectangle(0, 0, glyph.mBitmap.Width, glyph.mBitmap.Height), ImageLockMode.ReadOnly, glyph.mBitmap.PixelFormat); BitmapData targetBitmapData = finalBitmap.LockBits(new Rectangle((finalBitmap.Width - glyph.mBitmap.Width) / 2, (finalBitmap.Height - glyph.mBitmap.Height) / 2, glyph.mBitmap.Width, glyph.mBitmap.Height), ImageLockMode.WriteOnly, finalBitmap.PixelFormat); try { for (int x = 0; x < sourceBitmapData.Width; x++) { for (int y = 0; y < sourceBitmapData.Height; y++) { IntPtr sourcePixel = (IntPtr)((int)sourceBitmapData.Scan0 + sourceBitmapData.Stride * y + x * 4); IntPtr targetPixel = (IntPtr)((int)targetBitmapData.Scan0 + targetBitmapData.Stride * y + x * 4); IntPtr texturePixel = IntPtr.Zero; if(texturedBitmapData != null) texturePixel = (IntPtr)((int)texturedBitmapData.Scan0 + texturedBitmapData.Stride * y + x * 4); Color srcColor = Color.FromArgb(Marshal.ReadInt32(sourcePixel)); Color tgtColor = Color.FromArgb(Marshal.ReadInt32(targetPixel)); Color texColor = (texturePixel != IntPtr.Zero) ? Color.FromArgb(Marshal.ReadInt32(texturePixel)) : Color.White; float alpha = srcColor.A / 255.0f; if (alpha == 0.0f) continue; byte r = (byte)(tgtColor.R * (1.0f - alpha) + FillColor.R * (srcColor.R / 255.0f) * (texColor.R / 255.0f) * alpha); byte g = (byte)(tgtColor.G * (1.0f - alpha) + FillColor.G * (srcColor.G / 255.0f) * (texColor.G / 255.0f) * alpha); byte b = (byte)(tgtColor.B * (1.0f - alpha) + FillColor.B * (srcColor.B / 255.0f) * (texColor.B / 255.0f) * alpha); byte a = (byte)(tgtColor.A * (1.0f - alpha) + FillColor.A * (srcColor.A / 255.0f) * (texColor.A / 255.0f) * alpha); Color finalColor = Color.FromArgb(a, r, g, b); Marshal.WriteInt32(targetPixel, finalColor.ToArgb()); } } } catch (Exception ex) { System.Console.WriteLine("Exception : " + ex); } glyph.mBitmap.UnlockBits(sourceBitmapData); finalBitmap.UnlockBits(targetBitmapData); if (texturedBitmapData != null) texturedBitmap.UnlockBits(texturedBitmapData); } else { finalBitmap = new Bitmap(4, 4); } if (curAtlas == null || !curAtlas.AddTexture(finalBitmap, glyph)) { curAtlas = new TextureAtlas(0, AtlasSize.Width, AtlasSize.Height, "tmp"); mTextureAtlasses.Add(curAtlas); curAtlas.AddTexture(finalBitmap, glyph); } } if (textureBitmap != null) textureBitmap.Dispose(); if (texture != null) texture.Dispose(); // Unload the image glyph textures foreach (FontBuilder.ImageGlyph imageGlyph in Images) imageGlyph.Unload(); // Then iterate and add to the texture atlas(ses). if (Otter.Interface.Graphics.Instance != null) { foreach(int textureID in mTextures) Otter.Interface.Graphics.Instance.UnloadTexture(textureID); foreach (TextureAtlas atlas in mTextureAtlasses) { Bitmap bitmap = atlas.GetBitmap(); // BitmapData BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); // Get the address of the first line. IntPtr ptr = bitmapData.Scan0; // Declare an array to hold the bytes of the bitmap. int size = Math.Abs(bitmapData.Stride) * bitmap.Height; byte[] bytes = new byte[size]; System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, size); int textureID = Otter.Interface.Graphics.Instance.LoadTexture(bytes, bitmap.Width, bitmap.Height, 32); bitmap.UnlockBits(bitmapData); mTextures.Add(textureID); bitmap.Dispose(); // SLOW foreach (FontBuilder.Glyph glyph in glyphs) { if (glyph == null) continue; AtlasNode node = atlas.FindNode(glyph); if(node != null) { NewCharInfo info = new NewCharInfo(); int diffW = node.mRectangle.Width - borderWidth * 2 - glyph.mW; int diffH = node.mRectangle.Height - borderWidth * 2 - glyph.mH; info.mCharCode = glyph.mCharCode; info.mImageGlyph = glyph.mImageGlyph; info.mX = node.mRectangle.X + borderWidth; info.mY = node.mRectangle.Y + borderWidth; info.mW = glyph.mW + diffW; info.mH = glyph.mH + diffH; info.mTop = glyph.mTop + diffH / 2; info.mAdvance = glyph.mAdvance; info.mLeftBearing = glyph.mLeftBearing - diffW / 2; info.mAtlasIndex = mTextureAtlasses.IndexOf(atlas); mCharInfoList.Add(info); } } } MemoryStream stream = new MemoryStream(); Platform platform = new Platform(); platform.Endianness = Endian.Little; platform.ColorFormat = ColorFormat.ARGB; PlatformBinaryWriter bw = new PlatformBinaryWriter(stream, platform); this.Export(bw); mFontID = Otter.Interface.Graphics.Instance.LoadFont(this.Name, stream.GetBuffer(), mTextures); bw.Close(); stream.Close(); } } }
/// <summary> /// Reloads the font /// </summary> public void ReloadFont() { if (mProject == null) { return; } int borderWidth = 2; string fullPath = mProject.ProjectDirectory + "/" + mFontFile; if (System.IO.File.Exists(fullPath)) { // Ensure that the character list ALWAYS contains at least the ? character. if (!Characters.Contains('?')) { Characters.Add('?'); } // Load the image glyph textures foreach (FontBuilder.ImageGlyph imageGlyph in Images) { imageGlyph.Load(mProject.ProjectDirectory); } if (mFontData != null) { mFontData.Dispose(); } mFontData = new FontBuilder.FontData(Characters, Images); FontBuilder.Glyph[] glyphs = mFontData.GetGlyphs(fullPath, mFontSize); // Clear out our existing textures and texture atlasses foreach (TextureAtlas atlas in mTextureAtlasses) { DisposeAtlasNode(atlas.mRoot); } mTextureAtlasses.Clear(); mTextures.Clear(); mCharInfoList.Clear(); mMaxTop = -99999; Image texture = null; Bitmap textureBitmap = null; if (File.Exists(mProject.ProjectDirectory + "/" + mTextureFile)) { texture = Image.FromFile(mProject.ProjectDirectory + "/" + mTextureFile); textureBitmap = new Bitmap(texture); } TextureAtlas curAtlas = null; foreach (FontBuilder.Glyph glyph in glyphs) { if (glyph == null) { continue; } if (mMaxTop < glyph.mTop) { mMaxTop = glyph.mTop; } Bitmap finalBitmap = null; if (glyph.mBitmap != null) { finalBitmap = (borderWidth == 0) ? new Bitmap(glyph.mBitmap) : Utils.ExpandImageBorder(glyph.mBitmap, borderWidth, true); if (finalBitmap == null) { continue; } Bitmap outlinedBitmap = null; Bitmap texturedBitmap = null; if (OutlineAmount > 0.0f && OutlineColor.A != 0) { float s = Math.Min(1.0f, Math.Max(OutlineSharpness, 0.0f)); outlinedBitmap = BlurBitmap(finalBitmap, OutlineAmount, OutlineSharpness, OutlineColor); finalBitmap.Dispose(); finalBitmap = outlinedBitmap; } BitmapData texturedBitmapData = null; if (textureBitmap != null && glyph.mImageGlyph == 0) { texturedBitmap = ApplyTexture(textureBitmap, glyph.mBitmap, mTextureBaseline, glyph.mTop); texturedBitmapData = texturedBitmap.LockBits(new Rectangle(0, 0, texturedBitmap.Width, texturedBitmap.Height), ImageLockMode.ReadOnly, texturedBitmap.PixelFormat); } // Now we need to use the original bitmap (from the glyph) and reapply it to the new // bitmap (that may or may not have been blurred) with the fill color BitmapData sourceBitmapData = glyph.mBitmap.LockBits(new Rectangle(0, 0, glyph.mBitmap.Width, glyph.mBitmap.Height), ImageLockMode.ReadOnly, glyph.mBitmap.PixelFormat); BitmapData targetBitmapData = finalBitmap.LockBits(new Rectangle((finalBitmap.Width - glyph.mBitmap.Width) / 2, (finalBitmap.Height - glyph.mBitmap.Height) / 2, glyph.mBitmap.Width, glyph.mBitmap.Height), ImageLockMode.WriteOnly, finalBitmap.PixelFormat); try { for (int x = 0; x < sourceBitmapData.Width; x++) { for (int y = 0; y < sourceBitmapData.Height; y++) { IntPtr sourcePixel = (IntPtr)((int)sourceBitmapData.Scan0 + sourceBitmapData.Stride * y + x * 4); IntPtr targetPixel = (IntPtr)((int)targetBitmapData.Scan0 + targetBitmapData.Stride * y + x * 4); IntPtr texturePixel = IntPtr.Zero; if (texturedBitmapData != null) { texturePixel = (IntPtr)((int)texturedBitmapData.Scan0 + texturedBitmapData.Stride * y + x * 4); } Color srcColor = Color.FromArgb(Marshal.ReadInt32(sourcePixel)); Color tgtColor = Color.FromArgb(Marshal.ReadInt32(targetPixel)); Color texColor = (texturePixel != IntPtr.Zero) ? Color.FromArgb(Marshal.ReadInt32(texturePixel)) : Color.White; float alpha = srcColor.A / 255.0f; if (alpha == 0.0f) { continue; } byte r = (byte)(tgtColor.R * (1.0f - alpha) + FillColor.R * (srcColor.R / 255.0f) * (texColor.R / 255.0f) * alpha); byte g = (byte)(tgtColor.G * (1.0f - alpha) + FillColor.G * (srcColor.G / 255.0f) * (texColor.G / 255.0f) * alpha); byte b = (byte)(tgtColor.B * (1.0f - alpha) + FillColor.B * (srcColor.B / 255.0f) * (texColor.B / 255.0f) * alpha); byte a = (byte)(tgtColor.A * (1.0f - alpha) + FillColor.A * (srcColor.A / 255.0f) * (texColor.A / 255.0f) * alpha); Color finalColor = Color.FromArgb(a, r, g, b); Marshal.WriteInt32(targetPixel, finalColor.ToArgb()); } } } catch (Exception ex) { System.Console.WriteLine("Exception : " + ex); } glyph.mBitmap.UnlockBits(sourceBitmapData); finalBitmap.UnlockBits(targetBitmapData); if (texturedBitmapData != null) { texturedBitmap.UnlockBits(texturedBitmapData); } } else { finalBitmap = new Bitmap(4, 4); } if (curAtlas == null || !curAtlas.AddTexture(finalBitmap, glyph)) { curAtlas = new TextureAtlas(0, AtlasSize.Width, AtlasSize.Height, "tmp"); mTextureAtlasses.Add(curAtlas); curAtlas.AddTexture(finalBitmap, glyph); } } if (textureBitmap != null) { textureBitmap.Dispose(); } if (texture != null) { texture.Dispose(); } // Unload the image glyph textures foreach (FontBuilder.ImageGlyph imageGlyph in Images) { imageGlyph.Unload(); } // Then iterate and add to the texture atlas(ses). if (Otter.Interface.Graphics.Instance != null) { foreach (int textureID in mTextures) { Otter.Interface.Graphics.Instance.UnloadTexture(textureID); } foreach (TextureAtlas atlas in mTextureAtlasses) { Bitmap bitmap = atlas.GetBitmap(); // BitmapData BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); // Get the address of the first line. IntPtr ptr = bitmapData.Scan0; // Declare an array to hold the bytes of the bitmap. int size = Math.Abs(bitmapData.Stride) * bitmap.Height; byte[] bytes = new byte[size]; System.Runtime.InteropServices.Marshal.Copy(ptr, bytes, 0, size); int textureID = Otter.Interface.Graphics.Instance.LoadTexture(bytes, bitmap.Width, bitmap.Height, 32); bitmap.UnlockBits(bitmapData); mTextures.Add(textureID); bitmap.Dispose(); // SLOW foreach (FontBuilder.Glyph glyph in glyphs) { if (glyph == null) { continue; } AtlasNode node = atlas.FindNode(glyph); if (node != null) { NewCharInfo info = new NewCharInfo(); int diffW = node.mRectangle.Width - borderWidth * 2 - glyph.mW; int diffH = node.mRectangle.Height - borderWidth * 2 - glyph.mH; info.mCharCode = glyph.mCharCode; info.mImageGlyph = glyph.mImageGlyph; info.mX = node.mRectangle.X + borderWidth; info.mY = node.mRectangle.Y + borderWidth; info.mW = glyph.mW + diffW; info.mH = glyph.mH + diffH; info.mTop = glyph.mTop + diffH / 2; info.mAdvance = glyph.mAdvance; info.mLeftBearing = glyph.mLeftBearing - diffW / 2; info.mAtlasIndex = mTextureAtlasses.IndexOf(atlas); mCharInfoList.Add(info); } } } MemoryStream stream = new MemoryStream(); Platform platform = new Platform(); platform.Endianness = Endian.Little; platform.ColorFormat = ColorFormat.ARGB; PlatformBinaryWriter bw = new PlatformBinaryWriter(stream, platform); this.Export(bw); mFontID = Otter.Interface.Graphics.Instance.LoadFont(this.Name, stream.GetBuffer(), mTextures); bw.Close(); stream.Close(); } } }