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