Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

font.cpp

Go to the documentation of this file.
00001 #include "font.h"
00002 #include <stdio.h>
00003 #include <stdarg.h>
00004 #include <salt/gmath.h>
00005 #include <boost/scoped_array.hpp>
00006 #include <zeitgeist/logserver/logserver.h>
00007 #include <zeitgeist/scriptserver/scriptserver.h>
00008 #include "fontserver.h"
00009 
00010 #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__)
00011 #define WIN32_LEAN_AND_MEAN 1
00012 #include <windows.h>
00013 #endif
00014 
00015 #include <GL/gl.h>
00016 
00017 using namespace kerosin;
00018 using namespace salt;
00019 
00020 Font::Font(FontServer &fontServer)
00021   : mTexID(0), mRowHeight(0), mSize(0), mFontServer(fontServer)
00022 {
00023 }
00024 
00025 Font::~Font()
00026 {
00027 }
00028 
00029 bool Font::Init(const std::string &name, unsigned int size, FT_Face face)
00030 {
00031   mName = name;
00032   mSize = size;
00033 
00034   if (mTexID != 0)
00035     {
00036       glDeleteTextures(1, &mTexID);
00037       mTexID = 0;
00038 
00039       GLenum error = glGetError();
00040       if (error)
00041         {
00042           mFontServer.GetLog()->Debug()
00043             << "(Font) ERROR: glGetError() reports error " << error
00044             << " after deleting my font texture\n";
00045           return false;
00046         }
00047     }
00048 
00049   int dpiHRes, dpiVRes;
00050   bool getConfig =
00051     (
00052      mFontServer.GetScript()->GetVariable("Viewport.DpiHRes", dpiHRes) &&
00053      mFontServer.GetScript()->GetVariable("Viewport.DpiVRes", dpiVRes)
00054      );
00055 
00056   if (! getConfig)
00057     {
00058       mFontServer.GetLog()->Debug()
00059         << "(Font) ERROR: cannot read Viewport dpi values from ScriptServer\n";
00060       return false;
00061     }
00062 
00063   FT_Set_Char_Size(
00064                    face,        /* handle to face object           */
00065                    0,           /* char_width in 1/64th of points  */
00066                    64*size,     /* char_height in 1/64th of points */
00067                    dpiHRes,     /* horizontal device resolution    */
00068                    dpiVRes      /* vertical device resolution      */
00069                    );
00070 
00071   // x resolution of font texture
00072   unsigned int x = 256;
00073   // y resolution of font texture ... to be determined
00074   unsigned int y = 0;
00075   // the current maximum height
00076   unsigned int curMaxHeight = 0;
00077   // we also want to determine the (maximum) height of a row
00078   mRowHeight = 0;
00079 
00080   // here we will store the maximum height of each row
00081   std::vector<unsigned int> heights;
00082 
00083   // first pass to determine dimensions
00084   Glyph glyph;
00085 
00086   for(int i=32; i<128; ++i)
00087     {
00088       if (! glyph.LoadGlyph(face, i))
00089         {
00090           mFontServer.GetLog()->Debug()
00091             << "(Font) ERROR: LoadGlyph() failed in first pass\n";
00092           return false;
00093         }
00094 
00095       curMaxHeight = gMax(curMaxHeight, glyph.mByteHeight);
00096 
00097       if(x+glyph.mByteWidth > 256)
00098         {
00099           // move to next row
00100           x = glyph.mByteWidth+1;
00101           y+= curMaxHeight+1;
00102           mRowHeight = gMax(mRowHeight, curMaxHeight);
00103           heights.push_back(curMaxHeight);
00104           curMaxHeight = 0;
00105         } else
00106         {
00107           x+= glyph.mByteWidth+1;
00108         }
00109     }
00110 
00111   // calculate the texture height (has to be power of two)
00112   unsigned int requiredHeight = 1;
00113 
00114   y+=1;
00115   while(requiredHeight < y)
00116     {
00117       requiredHeight*=2;
00118     }
00119 
00120   // setup image buffer now we create a texture that is big enough for
00121   // this data
00122   boost::scoped_array<unsigned char> imageBuffer
00123     (new unsigned char[256*requiredHeight]);
00124 
00125   // clear the image
00126   memset(imageBuffer.get(), 0x00, 256*requiredHeight*sizeof(unsigned char));
00127 
00128   // copy glyphs to the imageBuffer
00129   x=0;
00130   y=0;
00131   curMaxHeight = 0;
00132 
00133   // loop through our characters
00134   for(int i=32; i<128; ++i)
00135     {
00136       if (glyph.LoadGlyph(face, i) == false)
00137         {
00138           mFontServer.GetLog()->Debug()
00139             << "(Font) ERROR: LoadGlyph() failed in second pass\n";
00140           return false;
00141         }
00142 
00143       curMaxHeight = gMax(curMaxHeight, glyph.mByteHeight);
00144 
00145       if(x+glyph.mByteWidth+1>256)
00146         {
00147           x=0;
00148           y+=curMaxHeight+1;    // height of a row of characters plus 2 pixels space
00149           curMaxHeight = 0;
00150         }
00151 
00152       if(glyph.mByteWidth*glyph.mByteHeight > 0)
00153         {
00154           for (unsigned int copyY = 0; copyY < glyph.mByteHeight; ++copyY)
00155             {
00156               for (unsigned int copyX = 0; copyX < glyph.mByteWidth; ++copyX)
00157                 {
00158                   imageBuffer[(y+1+copyY)*256 + x+1+copyX] = glyph.mData[copyY*glyph.mByteWidth + copyX];
00159                 }
00160             }
00161           mMetrics[i-32].mByteWidth     = glyph.mByteWidth;
00162           mMetrics[i-32].mByteHeight    = glyph.mByteHeight;
00163           mMetrics[i-32].mXOffset       = glyph.mXOffset;
00164           mMetrics[i-32].mYOffset       = glyph.mYOffset;
00165           mMetrics[i-32].mAdvance       = glyph.mAdvance;
00166           mMetrics[i-32].mTC1.Set((x+0.5f)/256.0f, (y+0.5f)/(float)requiredHeight);
00167           mMetrics[i-32].mTC2.Set((x+1.5f+glyph.mByteWidth)/256.0f, (y+1.5f+glyph.mByteHeight)/(float)requiredHeight);
00168         }
00169       x += glyph.mByteWidth+1;
00170     }
00171 
00172   // Spacing of a blank should be similar to 'i'
00173   mMetrics[' '-32].mAdvance  = mMetrics['i'-32].mAdvance;
00174 
00175   glGenTextures(1, &mTexID);
00176 
00177   GLenum error = glGetError();
00178   if (error)
00179     {
00180       mFontServer.GetLog()->Debug()
00181         << "(Font) ERROR: glGetError() reports error " << error
00182         << " after generating my font texture()\n";
00183       mTexID = 0;
00184       return false;
00185     }
00186 
00187   glBindTexture(GL_TEXTURE_2D, mTexID);
00188   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, 256, requiredHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, imageBuffer.get());
00189   glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00190   glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00191 
00192   error = glGetError();
00193   if (error)
00194     {
00195       mFontServer.GetLog()->Debug()
00196         << "(Font) ERROR: glGetError() reports error " << error
00197         << " after binding my font texture()\n";
00198       return false;
00199     }
00200 
00201   return true;
00202 }
00203 
00204 bool Font::Bind(int vRows)
00205 {
00206   glEnable(GL_TEXTURE_2D);
00207   glBindTexture(GL_TEXTURE_2D, mTexID);
00208   glMatrixMode(GL_PROJECTION);
00209   glPushMatrix();
00210   glLoadIdentity();
00211 
00212   //    int xRes;
00213   //    int yRes;
00214 
00215   //if (!mFontServer.GetScript()->GetVariable("Viewport.xRes", xRes)) return false;
00216   //if (!mFontServer.GetScript()->GetVariable("Viewport.yRes", yRes)) return false;
00217 
00218   if(vRows == -1)
00219     {
00220       glOrtho(0, 1024, 768, 0, 1, 1000);
00221     }
00222   else
00223     {
00224       glOrtho(0, 1024*(mRowHeight*vRows/(float)768), mRowHeight*vRows, 0, 1, 1000);
00225     }
00226 
00227   return true;
00228 }
00229 
00230 void Font::Dump()
00231 {
00232   glBegin(GL_QUADS);
00233   glTexCoord2f(0, 0);
00234   glVertex2f(0,0);
00235   glTexCoord2f(1, 0);
00236   glVertex2f(255, 0);
00237   glTexCoord2f(1, 1);
00238   glVertex2f(255, 255);
00239   glTexCoord2f(0, 1);
00240   glVertex2f(0, 255);
00241   glEnd();
00242 }
00243 
00244 void Font::DrawString(float x, float y, const char *string)
00245 {
00246   const char *c = string;
00247 
00248   float curx;
00249   float cury;
00250   y += mRowHeight;
00251   while(*c != 0)
00252     {
00253       int i = *c-32;            // rebase the index
00254       if(i>=0 && i<96)
00255         {
00256           GlyphMetric &metric = mMetrics[i];
00257 
00258           curx = x;
00259           cury = y;
00260           curx+= metric.mXOffset;
00261           cury-= metric.mYOffset;
00262           glBegin(GL_QUADS);
00263           glTexCoord2f(metric.mTC1.x(), metric.mTC1.y());
00264           glVertex2f(curx,cury);
00265           glTexCoord2f(metric.mTC2.x(), metric.mTC1.y());
00266           glVertex2f(curx+metric.mByteWidth, cury);
00267           glTexCoord2f(metric.mTC2.x(), metric.mTC2.y());
00268           glVertex2f(curx+metric.mByteWidth, cury+metric.mByteHeight);
00269           glTexCoord2f(metric.mTC1.x(), metric.mTC2.y());
00270           glVertex2f(curx, cury+metric.mByteHeight);
00271           glEnd();
00272           x+=(float)metric.mAdvance;
00273         }
00274       ++c;
00275     }
00276 }
00277 
00278 void Font::Printf(float x, float y, const char *format, ...)
00279 {
00280   char buffer[4096];
00281   va_list args;
00282   va_start(args, format);
00283   vsprintf(buffer, format, args);
00284   va_end(args);
00285   DrawString(x, y, buffer);
00286 }
00287 
00288 void Font::RowPrintf(float x, float row, const char *format, ...)
00289 {
00290   char buffer[4096];
00291   va_list args;
00292   va_start(args, format);
00293   vsprintf(buffer, format, args);
00294   va_end(args);
00295   DrawString(x, row*mRowHeight, buffer);
00296 }
00297 
00298 float Font::GetStringWidth(const char* string, int numChar)
00299 {
00300   if (numChar == -1) numChar = strlen(string);
00301 
00302   const char *c = string;
00303   float  len            = 0;
00304   int chCount           = 0;
00305 
00306   while ( (*c != 0) && (chCount < numChar) )
00307     {
00308       int i = *c-32;            // rebase the index
00309       if(i>=0 && i<96)
00310         {
00311           GlyphMetric &metric = mMetrics[i];
00312           len += metric.mAdvance;
00313         }
00314       ++c;
00315       ++chCount;
00316     }
00317 
00318   return len;
00319 }
00320 
00321 float Font::GetRowHeight()
00322 {
00323   return (float)mRowHeight;
00324 }
00325 
00326 const std::string& Font::GetName() const
00327 {
00328   return mName;
00329 }
00330 
00331 unsigned int Font::GetSize() const
00332 {
00333   return mSize;
00334 }
00335 

Generated on Thu Apr 6 15:25:37 2006 for rcssserver3d by  doxygen 1.4.4