private void ParseFont(String filename) { String[] lines = System.IO.File.ReadAllLines(filename); for (int i = 0; i < lines.Length; i++) { String[] parameters = lines[i].Split(new char[] { ' ' }); switch (parameters[0]) { case "img": this.texture = Assets.GetTexture(parameters[1]); break; case "char": int id = int.Parse(parameters[1].Split(new char[] { '=' })[1]); glyphs[id] = new BitmapGlyph(); for (int j = 2; j < parameters.Length; j++) { String[] parameter = parameters[j].Split(new char[] { '=' }); switch (parameter[0]) { case "x": glyphs[id].X = int.Parse(parameter[1]); break; case "y": glyphs[id].Y = int.Parse(parameter[1]); break; case "width": glyphs[id].Width = int.Parse(parameter[1]); break; case "height": glyphs[id].Height = int.Parse(parameter[1]); if (lineHeight < glyphs[id].Height) { lineHeight = glyphs[id].Height; } break; case "xoffset": glyphs[id].xOffset = int.Parse(parameter[1]); break; case "yoffset": glyphs[id].yOffset = int.Parse(parameter[1]); break; case "xadvance": glyphs[id].xAdvance = int.Parse(parameter[1]); break; } } break; } } }
void Create() { if (m_Font == null) { Debug.LogError("Create BitmapGlyph failed. Font can't be null."); return; } if (string.IsNullOrEmpty(m_Name)) { Debug.LogError("Create BitmapGlyph failed. Name can't be null or empty."); return; } BitmapGlyph glyph = new BitmapGlyph(m_Name, m_Width, m_Height); m_Font.AddGlyph(glyph); }
// Create a display list coresponding to the give character. // return character width private int make_dlist(Face face, uint ch, uint list_base, uint[] tex_base) { int charWidth = 0; //The first thing we do is get FreeType to render our character //into a bitmap. This actually requires a couple of FreeType commands: //Load the Glyph for our character. face.LoadGlyph(face.GetCharIndex(ch), LoadFlags.Default, LoadTarget.Normal); //Move the face's glyph into a Glyph object. Glyph glyph = face.Glyph.GetGlyph(); //Convert the glyph to a bitmap. glyph.ToBitmap(RenderMode.Normal, new FTVector26Dot6(0, 0), true); BitmapGlyph bitmap_glyph = glyph.ToBitmapGlyph(); //This reference will make accessing the bitmap easier FTBitmap bitmap = bitmap_glyph.Bitmap; //Use our helper function to get the widths of //the bitmap data that we will need in order to create //our texture. int width = next_p2(bitmap.Width); int height = next_p2(bitmap.Rows); //Allocate memory for the texture data. byte[] expanded_data = new byte[2 * width * height]; //Here we fill in the data for the expanded bitmap. //Notice that we are using two channel bitmap (one for //luminocity and one for alpha), but we assign //both luminocity and alpha to the value that we //find in the FreeType bitmap. //We use the ?: operator so that value which we use //will be 0 if we are in the padding zone, and whatever //is the the Freetype bitmap otherwise. for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { expanded_data[2 * (i + j * width)] = 255; if (i >= bitmap.Width || j >= bitmap.Rows) { expanded_data[2 * (i + j * width) + 1] = 0; } else { expanded_data[2 * (i + j * width) + 1] = bitmap.BufferData[i + bitmap.Width * j]; } } } //Now we just setup some texture paramaters. glView.glBindTexture2D(tex_base[ch]); glView.glTex2DParameterMinFilterLinear(); glView.glTex2DParameterMagFilterLinear(); //Here we actually create the texture itself, notice //that we are using GL_LUMINANCE_ALPHA to indicate that //we are using 2 channel data. glView.glTexImage2D_IntFormatRGBA_formatLumAlpha_bytes(width, height, expanded_data); //So now we can create the display list glView.glNewListCompile(list_base + ch); glView.glBindTexture2D(tex_base[ch]); glView.glPushMatrix(); // better results with popping the matrix here.. //first we need to move over a little so that //the character has the right amount of space //between it and the one before it. glView.glTranslate((float)bitmap_glyph.Left, 0f, 0f); //Now we move down a little in the case that the //bitmap extends past the bottom of the line //(this is only true for characters like 'g' or 'y'. //GL.PushMatrix(); // better results without popping the matrix before top translation int topOffset = bitmap_glyph.Top - bitmap.Rows; glView.glTranslate(0f, (float)topOffset, 0f); //glTranslatef(0, (GLfloat)bitmap_glyph->top-bitmap.rows, 0); //Now we need to account for the fact that many of //our textures are filled with empty padding space. //We figure what portion of the texture is used by //the actual character and store that information in //the x and y variables, then when we draw the //quad, we will only reference the parts of the texture //that we contain the character itself. float x = (float)bitmap.Width / (float)width, y = (float)bitmap.Rows / (float)height; //Here we draw the texturemaped quads. //The bitmap that we got from FreeType was not //oriented quite like we would like it to be, //so we need to link the texture to the quad //so that the result will be properly aligned. glView.glBeginQuads(); glView.glTexCoord2(0, 0); glView.glVertex2(0f, (float)bitmap.Rows); glView.glTexCoord2(0, y); glView.glVertex2(0f, 0f); glView.glTexCoord2(x, y); glView.glVertex2((float)bitmap.Width, 0); glView.glTexCoord2(x, 0); glView.glVertex2((float)bitmap.Width, (float)bitmap.Rows); glView.glEnd(); glView.glPopMatrix(); glView.glTranslate((float)(face.Glyph.Advance.X), 0f, 0f); // set the char width charWidth = (int)face.Glyph.Advance.X; //Finish the display list glView.glEndList(); // free the glyph memory (bugfix) bitmap.Dispose(); bitmap_glyph.Dispose(); glyph.Dispose(); // return the character width return(charWidth); }
void ProcessCharacters() { Scale = 1; if (m_TagText == null) { m_TagText = new TagText(); } m_TagText.Load(Text); if (m_Lines == null) { m_Lines = new List <BitmapLine>(); } else { m_Lines.Clear(); } if (m_Characters == null) { m_Characters = new List <BitmapCharacter>(); } int delta = m_TagText.Text.Length - m_Characters.Count; for (int i = 0; i < delta; i++) { m_Characters.Add(new BitmapCharacter()); } for (int i = 0; i < m_Characters.Count; i++) { if (m_Characters[i] == null) { m_Characters[i] = new BitmapCharacter(); } BitmapCharacter character = m_Characters[i]; character.Index = -1; character.Enabled = false; character.Visible = false; character.Tint = Color.white; character.Offset = Vector2.zero; } List <BitmapCharacter> line = new List <BitmapCharacter>(); int index = 0; for (int i = 0; i < m_TagText.Text.Length; i++) { if (m_TagText.Text[i] == '\n') { m_Lines.Add(new BitmapLine(line)); line.Clear(); index++; continue; } BitmapCharacter character = m_Characters[index]; character.Index = i; character.Enabled = true; character.Character = m_TagText.Text[i]; BitmapGlyph glyph = Font.GetGlyph(character.Character); if (glyph != null) { Rect glyphRect = glyph.Rect; character.Visible = true; character.Rect = glyphRect.Scale(CharSize); character.BaselineOffset = glyph.Offset * CharSize; character.LineHeight = Font.Ascender * CharSize; character.UV = glyph.UV; character.Color = color; } else if (character.Character == ' ') { Rect glyphRect = new Rect(0, 0, Font.SpaceWidth, 0); character.Visible = false; character.Rect = glyphRect.Scale(CharSize); } line.Add(character); index++; } m_Lines.Add(new BitmapLine(line)); line.Clear(); }
public unsafe GlyphInfo CompileCharacter(Face face, uint glyphindex, char character) { // Load or generate new Texture and store the Handle in m_Textures if (m_Textures.Length <= Count) { Array.Resize(ref m_Textures, Math.Max(32, m_Textures.Length * 2)); } int TextureIndex = m_Textures [Count]; if (TextureIndex == 0) { int[] textures = new int[1]; GL.GenTextures(1, textures); if (textures [0] == 0) { return(GlyphInfo.Empty); } m_Textures [Count] = textures [0]; TextureIndex = textures [0]; } int ListIndex = (int)glyphindex; //if (m_ListBase == 0) { if (OnDemand) { ListIndex = GL.GenLists(1); if (ListIndex == 0) { return(GlyphInfo.Empty); } } try { face.LoadGlyph(glyphindex, LoadFlags.ForceAutohint, LoadTarget.Normal); } catch (Exception ex) { ex.LogWarning(); return(GlyphInfo.Empty); } Glyph glyph = face.Glyph.GetGlyph(); if (glyph == null) { return(GlyphInfo.Empty); } Height = Math.Max(Height, (float)face.Glyph.Metrics.Height); //glyph.ToBitmap (SharpFont.RenderMode.Normal, new FTVector26Dot6(0.15, 0.15), true); glyph.ToBitmap(SharpFont.RenderMode.Normal, new FTVector26Dot6(0, 0), true); BitmapGlyph bmg = glyph.ToBitmapGlyph(); int width = bmg.Bitmap.Width; int rows = bmg.Bitmap.Rows; int size = width * rows; if (size <= 0) { glyph.Dispose(); //if (Filter == GlyphFilterFlags.All) // m_ExtentsX[(int)glyphindex] = 0; int spaceWidth = 0; if (character == 32) { Count++; spaceWidth = (Size * ScaleFactor / 3f).Ceil(); GL.NewList(m_ListBase + ListIndex, ListMode.Compile); // evtl character GL.Translate(spaceWidth, 0, 0); GL.EndList(); return(new GlyphInfo(ListIndex, spaceWidth)); } return(GlyphInfo.Empty); } Count++; int expandedBitmapWidth = (width + 1).NextPowerOf2(); int expandedBitmapHeight = rows.NextPowerOf2(); byte[] expandedBitmapBytes = new byte[expandedBitmapWidth * expandedBitmapHeight]; fixed(byte *p = bmg.Bitmap.BufferData) fixed(byte *q = expandedBitmapBytes) { try { byte *pTemp = p; for (int countY = 0; countY < expandedBitmapHeight; countY++) { for (int countX = 0; countX < expandedBitmapWidth; countX++) { byte *qTemp = q + (countX + countY * expandedBitmapWidth); if ((countX >= width || countY >= rows)) { *qTemp = 0; } else { *qTemp = *(pTemp + countX); } } pTemp += width; } if (IsSpecialChar(character)) { for (int i = 0; i < expandedBitmapBytes.Length; i++) { byte *qTemp = q + i; * qTemp = (byte)(*qTemp / 2); } } } catch (Exception ex) { ex.LogError(); } } GL.BindTexture(TextureTarget.Texture2D, TextureIndex); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Clamp); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Clamp); //GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GL.TexImage2D(TextureTarget.Texture2D, 0, // level-of-detail PixelInternalFormat.Alpha, // texture-format 32bit (int)expandedBitmapWidth, // texture-width (int)expandedBitmapHeight, // texture-height 0, // border PixelFormat.Alpha, // pixel-data-format PixelType.UnsignedByte, // pixel-data-type expandedBitmapBytes); // --------------------------------------------------------------------------- //Create a display list (of precompiled GL commands) and bind a texture to it. GL.NewList(m_ListBase + ListIndex, ListMode.Compile); GL.BindTexture(TextureTarget.Texture2D, TextureIndex); // Account for freetype spacing rules. float glyphWidth = (float)glyph.Advance.X; //float left = (glyphWidth - bmg.Left) / 2f; GL.Translate(bmg.Left, 0, 0); GL.PushMatrix(); GL.Translate(0, bmg.Top - rows, 0); float x = width / (float)expandedBitmapWidth; float y = rows / (float)expandedBitmapHeight; // Draw the quad. GL.Begin(PrimitiveType.Quads); GL.TexCoord2(0, 0); GL.Vertex2(0, rows); GL.TexCoord2(0, y); GL.Vertex2(0, 0); GL.TexCoord2(x, y); GL.Vertex2(width, 0); GL.TexCoord2(x, 0); GL.Vertex2(width, rows); GL.End(); GL.PopMatrix(); //GL.Translate (face.Glyph.Metrics.HorizontalAdvance - bmg.Left, 0, 0); GL.Translate(glyphWidth - bmg.Left, 0, 0); // Advance for the next character. /*** * if (!Monospace) * GL.Translate (face.Glyph.Metrics.HorizontalAdvance - bmg.Left, 0, 0); * else * GL.Translate (glyphWidth, 0, 0); ***/ GL.EndList(); // --------------------------------------------------------------------------- //m_ExtentsX[glyphindex] = face.Glyph.Metrics.HorizontalAdvance.Ceiling(); //m_ExtentsX[ListIndex] = glyphWidth.Ceil(); glyph.Dispose(); return(new GlyphInfo(ListIndex, glyphWidth.Ceil())); }
/// <summary> /// Sets up a single character as a OpenGL texture for rendering. /// </summary> /// <param name="face"></param> /// <param name="faceptr"></param> /// <param name="c"></param> private void CompileCharacter(Face face, IntPtr faceptr, int c) { //We first convert the number index to a character index int index = Face.FT_Get_Char_Index(faceptr, Convert.ToChar(c)); //Here we load the actual glyph for the character int ret = Face.FT_Load_Glyph(faceptr, index, FT_LOAD_TYPES.FT_LOAD_DEFAULT); if (ret != 0) { return; } //Convert the glyph to a bitmap IntPtr glyph; int retb = Glyph.FT_Get_Glyph(face.glyphrec, out glyph); if (retb != 0) { return; } // Render the glphy to a bitmap Glyph.FT_Glyph_To_Bitmap(out glyph, FT_RENDER_MODES.FT_RENDER_MODE_NORMAL, 0, 1); BitmapGlyph glyph_bmp = (BitmapGlyph)Marshal.PtrToStructure(glyph, typeof(BitmapGlyph)); int size = (glyph_bmp.bitmap.width * glyph_bmp.bitmap.rows); if (size <= 0) { //space is a special `blank` character extent_x[c] = 0; if (c == 32) { Gl.glNewList((int)(list_base + c), Gl.GL_COMPILE); Gl.glTranslatef(fontSize >> 1, 0, 0); extent_x[c] = fontSize >> 1; Gl.glEndList(); } return; } // Allocate space and grab the bitmap byte[] bmp = new byte[size]; Marshal.Copy(glyph_bmp.bitmap.buffer, bmp, 0, bmp.Length); // Save the size of the bitmap and create a power of 2 version // for OpenGL. glyphSizes[c] = new SizeF(glyph_bmp.bitmap.width, glyph_bmp.bitmap.rows); baselines[c] = glyph_bmp.top - glyph_bmp.bitmap.rows; int width = next_po2(glyph_bmp.bitmap.width); int height = next_po2(glyph_bmp.bitmap.rows); byte[] expanded = new byte[2 * width * height]; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { expanded[2 * (i + j * width)] = expanded[2 * (i + j * width) + 1] = (i >= glyph_bmp.bitmap.width || j >= glyph_bmp.bitmap.rows) ? (byte)0 : bmp[i + glyph_bmp.bitmap.width * j]; } } // Set up some texture parameters for opengl Gl.glBindTexture(Gl.GL_TEXTURE_2D, textures[c]); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR); // Create the texture Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, width, height, 0, Gl.GL_LUMINANCE_ALPHA, Gl.GL_UNSIGNED_BYTE, expanded); expanded = null; bmp = null; // Create a display list and bind a texture to it Gl.glNewList((int)(list_base + c), Gl.GL_COMPILE); Gl.glBindTexture(Gl.GL_TEXTURE_2D, textures[c]); //Account for freetype spacing rules Gl.glTranslatef(glyph_bmp.left, 0, 0); Gl.glPushMatrix(); //Gl.glRotatef(180, 1f, 0, 0); Gl.glScalef(1, -1, 1); Gl.glTranslatef(0, glyph_bmp.top - glyph_bmp.bitmap.rows, 0); float x = (float)glyph_bmp.bitmap.width / (float)width; float y = (float)glyph_bmp.bitmap.rows / (float)height; //Draw the quad Gl.glBegin(Gl.GL_QUADS); { Gl.glTexCoord2d(0, 0); Gl.glVertex2f(0, glyph_bmp.bitmap.rows); Gl.glTexCoord2d(0, y); Gl.glVertex2f(0, 0); Gl.glTexCoord2d(x, y); Gl.glVertex2f(glyph_bmp.bitmap.width, 0); Gl.glTexCoord2d(x, 0); Gl.glVertex2f(glyph_bmp.bitmap.width, glyph_bmp.bitmap.rows); } Gl.glEnd(); Gl.glPopMatrix(); // Advance for the next character Gl.glTranslatef(glyph_bmp.bitmap.width, 0, 0); extent_x[c] = glyph_bmp.left + glyph_bmp.bitmap.width; Gl.glEndList(); }