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,
00065 0,
00066 64*size,
00067 dpiHRes,
00068 dpiVRes
00069 );
00070
00071
00072 unsigned int x = 256;
00073
00074 unsigned int y = 0;
00075
00076 unsigned int curMaxHeight = 0;
00077
00078 mRowHeight = 0;
00079
00080
00081 std::vector<unsigned int> heights;
00082
00083
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
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
00112 unsigned int requiredHeight = 1;
00113
00114 y+=1;
00115 while(requiredHeight < y)
00116 {
00117 requiredHeight*=2;
00118 }
00119
00120
00121
00122 boost::scoped_array<unsigned char> imageBuffer
00123 (new unsigned char[256*requiredHeight]);
00124
00125
00126 memset(imageBuffer.get(), 0x00, 256*requiredHeight*sizeof(unsigned char));
00127
00128
00129 x=0;
00130 y=0;
00131 curMaxHeight = 0;
00132
00133
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;
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
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
00213
00214
00215
00216
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;
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;
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