public TextureFontFace(FontFace nOpenTypeFontFace, string xmlFontInfo, GlyphImage glyphImg) { //for msdf font //1 font atlas may support mutliple font size atlasBuilder = new SimpleFontAtlasBuilder(); fontAtlas = atlasBuilder.LoadFontInfo(xmlFontInfo); fontAtlas.TotalGlyph = glyphImg; this.nOpenTypeFontFace = nOpenTypeFontFace; }
public ActualFont ResolveForTextureFont(RequestFont font) { //check if we have texture font fot this font TextureFont t = TextureFont.GetCacheFontAsTextureFont(font); if (t != null) { return t; } //-------------------------------------------------------------------- LateTextureFontInfo lateFontInfo; if (!textureBitmapInfos.TryGetValue(font.Name, out lateFontInfo)) { //not found return null; } //check if we have create TextureFont TextureFontFace textureFontface = lateFontInfo.Fontface; if (textureFontface == null) { //load glyh image here GlyphImage glyphImage = null; using (var nativeImg = new PixelFarm.Drawing.Imaging.NativeImage(lateFontInfo.TextureBitmapFile)) { glyphImage = new GlyphImage(nativeImg.Width, nativeImg.Height); var buffer = new int[nativeImg.Width * nativeImg.Height]; System.Runtime.InteropServices.Marshal.Copy(nativeImg.GetNativeImageHandle(), buffer, 0, buffer.Length); glyphImage.SetImageBuffer(buffer, true); } InstalledFont installedFont = GLES2PlatformFontMx.GetInstalledFont(font.Name, InstalledFontStyle.Regular); FontFace nOpenTypeFontFace = NOpenTypeFontLoader.LoadFont(installedFont.FontPath, GLES2PlatformFontMx.defaultLang, GLES2PlatformFontMx.defaultHbDirection, GLES2PlatformFontMx.defaultScriptCode); textureFontface = new TextureFontFace(nOpenTypeFontFace, lateFontInfo.FontMapFile, glyphImage); lateFontInfo.Fontface = textureFontface; return textureFontface.GetFontAtPointsSize(font.SizeInPoints); } if (textureFontface != null) { t = (TextureFont)(textureFontface.GetFontAtPointsSize(font.SizeInPoints)); t.AssignToRequestFont(font); return t; } else { // //need to create font face //create fontface first } return null; }
const double FT_RESIZE = 64; //essential to be floating point internal unsafe static GlyphImage BuildMsdfFontImage(FontGlyph fontGlyph) { IntPtr shape = MyFtLib.CreateShape(); FT_Outline outline = (*(FT_Outline*)fontGlyph.glyphMatrix.outline); //outline version //------------------------------ int npoints = outline.n_points; List<PixelFarm.VectorMath.Vector2> points = new List<PixelFarm.VectorMath.Vector2>(npoints); int startContour = 0; int cpoint_index = 0; int todoContourCount = outline.n_contours; int controlPointCount = 0; while (todoContourCount > 0) { int nextContour = outline.contours[startContour] + 1; bool isFirstPoint = true; //--------------- //create contour IntPtr cnt = MyFtLib.ShapeAddBlankContour(shape); FtVec2 secondControlPoint = new FtVec2(); FtVec2 thirdControlPoint = new FtVec2(); bool justFromCurveMode = false; FtVec2 lastMoveTo = new FtVec2(); FtVec2 lastPoint = new FtVec2(); FtVec2 current_point = new Fonts.FtVec2(); for (; cpoint_index < nextContour; ++cpoint_index) { FT_Vector xvpoint = outline.points[cpoint_index]; current_point = new FtVec2(xvpoint.x / FT_RESIZE, xvpoint.y / FT_RESIZE); //Console.WriteLine(xvpoint.x.ToString() + "," + xvpoint.y); byte vtag = outline.tags[cpoint_index]; bool has_dropout = (((vtag >> 2) & 0x1) != 0); int dropoutMode = vtag >> 3; if ((vtag & 0x1) != 0) { if (justFromCurveMode) { switch (controlPointCount) { case 1: { MyFtLib.ContourAddQuadraticSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, current_point.x, current_point.y); lastPoint = current_point; } break; case 2: { MyFtLib.ContourAddCubicSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, thirdControlPoint.x, thirdControlPoint.y, current_point.x, current_point.y); lastPoint = current_point; } break; default: { throw new NotSupportedException(); } } controlPointCount = 0; justFromCurveMode = false; } else { //line mode if (isFirstPoint) { isFirstPoint = false; lastMoveTo = lastPoint = current_point; } else { MyFtLib.ContourAddLinearSegment(cnt, lastPoint.x, lastPoint.y, current_point.x, current_point.y); lastPoint = current_point; } } } else { if (isFirstPoint) { isFirstPoint = false; lastMoveTo = lastPoint = current_point; } switch (controlPointCount) { case 0: { //bit 1 set=> off curve, this is a control point //if this is a 2nd order or 3rd order control point if (((vtag >> 1) & 0x1) != 0) { ////printf("[%d] bzc3rd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); thirdControlPoint = new FtVec2(current_point.x, current_point.y); } else { ////printf("[%d] bzc2nd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); secondControlPoint = new FtVec2(current_point.x, current_point.y); } } break; case 1: { if (((vtag >> 1) & 0x1) != 0) { ////printf("[%d] bzc3rd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); thirdControlPoint = new FtVec2(current_point.x, current_point.y); } else { //we already have prev second control point //so auto calculate line to //between 2 point FtVec2 mid = GetMidPoint(secondControlPoint, current_point); MyFtLib.ContourAddQuadraticSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, mid.x, mid.y); lastPoint = mid; //------------------------ controlPointCount--; //------------------------ //printf("[%d] bzc2nd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); secondControlPoint = current_point; } } break; default: { throw new NotSupportedException(); } } controlPointCount++; justFromCurveMode = true; } } //-------- //close figure //if in curve mode if (justFromCurveMode) { switch (controlPointCount) { case 0: break; case 1: { MyFtLib.ContourAddQuadraticSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, lastMoveTo.x, lastMoveTo.y); lastPoint = current_point; } break; case 2: { MyFtLib.ContourAddCubicSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, thirdControlPoint.x, thirdControlPoint.y, lastMoveTo.x, lastMoveTo.y); lastPoint = current_point; } break; default: { throw new NotSupportedException(); } } justFromCurveMode = false; controlPointCount = 0; } else { MyFtLib.ContourAddLinearSegment(cnt, current_point.x, current_point.y, lastMoveTo.x, lastMoveTo.y); lastPoint = current_point; } //ps.CloseFigure(); //-------- startContour++; todoContourCount--; } //------------ double s_left, s_bottom, s_right, s_top; MyFtLib.ShapeFindBounds(shape, out s_left, out s_bottom, out s_right, out s_top); RectangleF glyphBounds = new RectangleF((float)s_left, (float)s_top, (float)(s_right - s_left), (float)(s_top - s_bottom)); //then create msdf texture if (!MyFtLib.ShapeValidate(shape)) { throw new NotSupportedException(); } MyFtLib.ShapeNormalize(shape); int borderXY = 0; int w = (int)Math.Ceiling(glyphBounds.Width) + (borderXY + borderXY); int h = (int)(Math.Ceiling(glyphBounds.Height)) + (borderXY + borderXY); if (w == 0) { w = 5; h = 5; } int[] outputBuffer = new int[w * h]; GlyphImage glyphImage = new GlyphImage(w, h); glyphImage.BorderXY = borderXY; glyphImage.OriginalGlyphBounds = glyphBounds; unsafe { fixed (int* output_header = &outputBuffer[0]) { float dx = 0; float dy = 0; if (s_left < 0) { //make it positive dx = (float)-s_left; } else if (s_left > 0) { } if (s_bottom < 0) { //make it positive dy = (float)-s_bottom; } else if (s_bottom > 0) { } //this glyph image has border (for msdf to render correctly) MyFtLib.MyFtGenerateMsdf(shape, w, h, 4, 1, dx + borderXY, dy + borderXY, -1, 3, output_header); MyFtLib.DeleteUnmanagedObj(shape); } glyphImage.SetImageBuffer(outputBuffer, true); } return glyphImage; }
public GlyphImage BuildSingleImage() { //1. add to list var glyphList = new List<GlyphData>(glyphs.Count); foreach (GlyphData glyphData in glyphs.Values) { //sort data glyphList.Add(glyphData); } //2. sort glyphList.Sort((a, b) => { return a.glyphImage.Width.CompareTo(b.glyphImage.Width); }); //3. layout int totalMaxLim = 800; int maxRowHeight = 0; int currentY = 0; int currentX = 0; for (int i = glyphList.Count - 1; i >= 0; --i) { GlyphData g = glyphList[i]; if (g.glyphImage.Height > maxRowHeight) { maxRowHeight = g.glyphImage.Height; } if (currentX + g.glyphImage.Width > totalMaxLim) { //start new row currentY += maxRowHeight; currentX = 0; } //------------------- g.pxArea = new Rectangle(currentX, currentY, g.glyphImage.Width, g.glyphImage.Height); currentX += g.glyphImage.Width; } currentY += maxRowHeight; int imgH = currentY; //4. create array that can hold data int[] totalBuffer = new int[totalMaxLim * imgH]; for (int i = glyphList.Count - 1; i >= 0; --i) { GlyphData g = glyphList[i]; //copy data to totalBuffer GlyphImage img = g.glyphImage; CopyToDest(img.GetImageBuffer(), img.Width, img.Height, totalBuffer, g.pxArea.Left, g.pxArea.Top, totalMaxLim); } //------------------ GlyphImage glyphImage = new Fonts.GlyphImage(totalMaxLim, imgH); glyphImage.SetImageBuffer(totalBuffer, true); return latestGenGlyphImage = glyphImage; }
public void AddGlyph(int codePoint, char c, FontGlyph fontGlyph, GlyphImage glyphImage) { glyphs[codePoint] = new GlyphData(codePoint, c, fontGlyph, glyphImage); }
public GlyphData(int codePoint, char c, FontGlyph fontGlyph, GlyphImage glyphImage) { this.codePoint = codePoint; this.character = c; this.fontGlyph = fontGlyph; this.glyphImage = glyphImage; }