// 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); }
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())); }