GLFont2dFreeType.cpp

Go to the documentation of this file.
00001 ////////////////////////////////////////////////////////////////////////////////
00002 //    Scorched3D (c) 2000-2009
00003 //
00004 //    This file is part of Scorched3D.
00005 //
00006 //    Scorched3D is free software; you can redistribute it and/or modify
00007 //    it under the terms of the GNU General Public License as published by
00008 //    the Free Software Foundation; either version 2 of the License, or
00009 //    (at your option) any later version.
00010 //
00011 //    Scorched3D is distributed in the hope that it will be useful,
00012 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //    GNU General Public License for more details.
00015 //
00016 //    You should have received a copy of the GNU General Public License
00017 //    along with Scorched3D; if not, write to the Free Software
00018 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 ////////////////////////////////////////////////////////////////////////////////
00020 
00021 #include <GLEXT/GLFont2dFreeType.h>
00022 #include <GLEXT/GLState.h>
00023 #include <common/Defines.h>
00024 
00025 // This Function Gets The First Power Of 2 >= The
00026 // Int That We Pass It.
00027 static inline int next_p2 (int a )
00028 {
00029         int rval=1;
00030         // rval<<=1 Is A Prettier Way Of Writing rval*=2; 
00031         while(rval<a) rval<<=1;
00032         return rval;
00033 }
00034 
00035 GLFont2dFreeType::GLFont2dFreeType() : makeShadow_(false)
00036 {
00037 
00038 }
00039 
00040 GLFont2dFreeType::~GLFont2dFreeType()
00041 {
00042         // We Don't Need The Face Information Now That The Display
00043         // Lists Have Been Created, So We Free The Assosiated Resources.
00044         FT_Done_Face(face_);
00045 
00046         // Ditto For The Font Library.
00047         FT_Done_FreeType(library_);
00048 }
00049 
00050 
00051 bool GLFont2dFreeType::createFont(const std::string &typeFace, unsigned int h, bool makeShadow)
00052 {
00053         // Create And Initilize A FreeType Font Library.
00054         if (FT_Init_FreeType( &library_ )) 
00055         {
00056                 S3D::dialogMessage("GLFont2d", "FT_Init_FreeType failed"); 
00057                 return false;
00058         }
00059 
00060         // This Is Where We Load In The Font Information From The File.
00061         // Of All The Places Where The Code Might Die, This Is The Most Likely,
00062         // As FT_New_Face Will Fail If The Font File Does Not Exist Or Is Somehow Broken.
00063         if (FT_New_Face( library_, typeFace.c_str(), 0, &face_ )) 
00064         {
00065                 S3D::dialogMessage("GLFont2d", S3D::formatStringBuffer(
00066                         "FT_New_Face failed (there is probably a problem with your font file \"%s\")",
00067                         typeFace.c_str())); 
00068                 return false;
00069         }
00070 
00071         // For Some Twisted Reason, FreeType Measures Font Size
00072         // In Terms Of 1/64ths Of Pixels.  Thus, To Make A Font
00073         // h Pixels High, We Need To Request A Size Of h*64.
00074         // (h << 6 Is Just A Prettier Way Of Writing h*64)
00075         FT_Set_Char_Size( face_, h << 6, h << 6, 96, 96);
00076 
00077         makeShadow_ = makeShadow;
00078 
00079         return true;
00080 }
00081 
00082 bool GLFont2dFreeType::createCharacter(unsigned int ch, GLFont2dStorage::CharEntry *character) 
00083 {
00084         // The First Thing We Do Is Get FreeType To Render Our Character
00085         // Into A Bitmap.  This Actually Requires A Couple Of FreeType Commands:
00086 
00087         // Load The Glyph For Our Character.
00088         FT_UInt charIndex = FT_Get_Char_Index( face_, ch );
00089         if (!charIndex) {
00090                 charIndex = FT_Get_Char_Index( face_, '?');
00091         }
00092 
00093         if(FT_Load_Glyph( face_, charIndex, FT_LOAD_DEFAULT )) 
00094         { 
00095                 S3D::dialogMessage("GLFont", "FT_Load_Glyph failed"); return false; 
00096         }
00097 
00098         // Move The Face's Glyph Into A Glyph Object.
00099         FT_Glyph glyph;
00100         if(FT_Get_Glyph( face_->glyph, &glyph ))
00101         { 
00102                 S3D::dialogMessage("GLFont", "FT_Get_Glyph failed"); return false; 
00103         }
00104 
00105         // Convert The Glyph To A Bitmap.
00106         FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 );
00107         FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
00108 
00109         // This Reference Will Make Accessing The Bitmap Easier.
00110         FT_Bitmap& bitmap=bitmap_glyph->bitmap;
00111 
00112         // Get the width and height
00113         int bitmap_width = bitmap.width;
00114         int bitmap_rows = bitmap.rows;
00115         unsigned char *bitmap_buffer = bitmap.buffer;
00116 
00117         if (makeShadow_)
00118         {
00119                 int shadow_width = bitmap_width + 4;
00120                 int shadow_rows = bitmap_rows + 4;
00121                 unsigned char *shadow_buffer = new unsigned char[
00122                         shadow_width * shadow_rows];
00123                 memset(shadow_buffer, 0, shadow_width * shadow_rows);
00124                 
00125                 for(int j=2; j<shadow_rows-2;j++) 
00126                 {
00127                         for(int i=2; i< shadow_width-2; i++)
00128                         {
00129                                 int bi = i-2;
00130                                 int bj = j-2;
00131                                 unsigned char bitmapValue = bitmap_buffer[bi + bitmap_width*bj];
00132                                 
00133                                 for (int b=-2; b<=2; b++)
00134                                 {
00135                                         for (int a=-2; a<=2; a++)
00136                                         {
00137                                                 int si = i+a;
00138                                                 int sj = j+b;
00139                                                 unsigned char &shadowValue = shadow_buffer[si + shadow_width*sj];
00140 
00141                                                 int sv = int(shadowValue) + int(bitmapValue);
00142                                                 if (sv > 255) sv = 255;
00143                                                 shadowValue = (unsigned char) sv;
00144                                         }
00145                                 }
00146                         }
00147                 }
00148 
00149                 bitmap_width = shadow_width;
00150                 bitmap_rows = shadow_rows;
00151                 bitmap_buffer = shadow_buffer;
00152         }
00153 
00154         // Use Our Helper Function To Get The Widths Of
00155         // The Bitmap Data That We Will Need In Order To Create
00156         // Our Texture.
00157         int width = next_p2( bitmap_width );
00158         int height = next_p2( bitmap_rows );
00159 
00160         // Allocate Memory For The Texture Data.
00161         GLubyte* expanded_data = new GLubyte[ 2 * width * height];
00162 
00163         // Here We Fill In The Data For The Expanded Bitmap.
00164         // Notice That We Are Using A Two Channel Bitmap (One For
00165         // Channel Luminosity And One For Alpha), But We Assign
00166         // Both Luminosity And Alpha To The Value That We
00167         // Find In The FreeType Bitmap. 
00168         // We Use The ?: Operator To Say That Value Which We Use
00169         // Will Be 0 If We Are In The Padding Zone, And Whatever
00170         // Is The FreeType Bitmap Otherwise.
00171         for(int j=0; j <height;j++) {
00172                 for(int i=0; i < width; i++){
00173                         expanded_data[2*(i+j*width)]= expanded_data[2*(i+j*width)+1] = 
00174                                 (i>=bitmap_width || j>=bitmap_rows) ?
00175                                 0 : bitmap_buffer[i + bitmap_width*j];
00176                 }
00177         }
00178 
00179         if (makeShadow_) delete [] bitmap_buffer;
00180 
00181         // Now We Just Setup Some Texture Parameters.
00182         glGenTextures(1, &character->texture);
00183         glBindTexture( GL_TEXTURE_2D, character->texture);
00184         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
00185         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
00186         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
00187         glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
00188         
00189         // Here We Actually Create The Texture Itself, Notice
00190         // That We Are Using GL_LUMINANCE_ALPHA To Indicate That
00191         // We Are Using 2 Channel Data.
00192         glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
00193                 GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data );
00194 
00195         // With The Texture Created, We Don't Need The Expanded Data Anymore.
00196         delete [] expanded_data;
00197 
00198         // Now We Create The Display List
00199         character->displaylist = glGenLists(1);
00200         glNewList(character->displaylist, GL_COMPILE);
00201         glBindTexture(GL_TEXTURE_2D, character->texture);
00202         glPushMatrix();
00203 
00204         // First We Need To Move Over A Little So That
00205         // The Character Has The Right Amount Of Space
00206         // Between It And The One Before It.
00207         glTranslatef((float) bitmap_glyph->left, 0.0f, 0.0f);
00208         character->left = bitmap_glyph->left;
00209 
00210         // Now We Move Down A Little In The Case That The
00211         // Bitmap Extends Past The Bottom Of The Line 
00212         // This Is Only True For Characters Like 'g' Or 'y'.
00213         glTranslatef(0.0f,(float) bitmap_glyph->top-bitmap_rows,0.0f);
00214         character->rows = bitmap_glyph->top-bitmap_rows;
00215 
00216         // Now We Need To Account For The Fact That Many Of
00217         // Our Textures Are Filled With Empty Padding Space.
00218         // We Figure What Portion Of The Texture Is Used By 
00219         // The Actual Character And Store That Information In
00220         // The x And y Variables, Then When We Draw The
00221         // Quad, We Will Only Reference The Parts Of The Texture
00222         // That Contains The Character Itself.
00223         
00224         float x=(float)bitmap_width / (float)width;
00225         float y=(float)bitmap_rows / (float)height;
00226         character->x = x;
00227         character->y = y;
00228 
00229         // Here We Draw The Texturemapped Quads.
00230         // The Bitmap That We Got From FreeType Was Not 
00231         // Oriented Quite Like We Would Like It To Be,
00232         // But We Link The Texture To The Quad
00233         // In Such A Way That The Result Will Be Properly Aligned.
00234         character->width = (float)bitmap_width;
00235         character->height = (float)bitmap_rows;
00236 
00237         glBegin(GL_QUADS);
00238         glTexCoord2f(0.0f,0.0f); glVertex2f(0.0f,(float)bitmap_rows);
00239         glTexCoord2f(0.0f,y); glVertex2f(0.0f,0.0f);
00240         glTexCoord2f(x,y); glVertex2f((float)bitmap_width,0.0f);
00241         glTexCoord2f(x,0.0f); glVertex2f((float)bitmap_width,(float)bitmap_rows);
00242         glEnd();
00243         glPopMatrix();
00244         glTranslatef((float)(face_->glyph->advance.x >> 6) ,0.0f ,0.0f);
00245 
00246         character->advances = (face_->glyph->advance.x >> 6);
00247 
00248         // Increment The Raster Position As If We Were A Bitmap Font.
00249         // (Only Needed If You Want To Calculate Text Length)
00250         // ImageBitmap(0,0,0,0,face->glyph->advance.x >> 6,0,NULL);
00251 
00252         // Finish The Display List
00253         glEndList();
00254         return true;
00255 }

Generated on Mon Feb 16 15:14:44 2009 for Scorched3D by  doxygen 1.5.3