00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef LUGRE_OGREFONTHELPER_H
00025 #define LUGRE_OGREFONTHELPER_H
00026
00028 #include <Ogre.h>
00029 #include <OgreFont.h>
00030 #include <OgreTextAreaOverlayElement.h>
00031
00032
00033 namespace Lugre {
00034
00037 class cOgreFontHelper { public:
00038 typedef Ogre::UTFString::unicode_char unicode_char;
00039 typedef Ogre::UTFString::const_iterator itor;
00040
00042 enum eAlignment {
00043 Align_Left,
00044 Align_Center,
00045 Align_Right,
00046 };
00047
00048 Ogre::FontPtr mpFont;
00049 eAlignment mAlign;
00050 float mfCharHeight;
00051 float mfLineHeight;
00052 float mfSpaceWidth;
00053 float mfTabWidth;
00054 float mfGlyphWidthFactor;
00055 float mfWrapMaxW;
00056
00059 cOgreFontHelper (Ogre::FontPtr mpFont,const float mfGlyphWidthFactor,const float mfCharHeight,
00060 const float mfSpaceWidth,const float mfWrapMaxW=0,eAlignment mAlign=Align_Left)
00061 : mpFont(mpFont), mfGlyphWidthFactor(mfGlyphWidthFactor), mfCharHeight(mfCharHeight),
00062 mfSpaceWidth(mfSpaceWidth), mfLineHeight(mfCharHeight), mfWrapMaxW(mfWrapMaxW), mAlign(mAlign) {
00063 mfTabWidth = 4*mfSpaceWidth;
00064 }
00065
00067 static eAlignment Alignment (Ogre::TextAreaOverlayElement::Alignment align) {
00068 switch (align) {
00069 case Ogre::TextAreaOverlayElement::Center: return Align_Center;
00070 case Ogre::TextAreaOverlayElement::Right: return Align_Right;
00071 default: return Align_Left;
00072 }
00073 }
00074
00076 static eAlignment Alignment (Ogre::GuiHorizontalAlignment align) {
00077 switch (align) {
00078 case Ogre::GHA_CENTER: return Align_Center;
00079 case Ogre::GHA_RIGHT: return Align_Right;
00080 default: return Align_Left;
00081 }
00082 }
00083
00085 enum {
00086 UNICODE_NEL = 0x0085,
00087 UNICODE_CR = 0x000D,
00088 UNICODE_LF = 0x000A,
00089 UNICODE_TAB = 0x0009,
00090 UNICODE_SPACE = 0x0020,
00091 UNICODE_ZERO = 0x0030,
00092 };
00093
00094 static inline bool IsTab (unicode_char c) { return c == UNICODE_TAB; }
00095 static inline bool IsSpace (unicode_char c) { return c == UNICODE_SPACE; }
00096 static inline bool IsNewLine (unicode_char c) { return c == UNICODE_CR || c == UNICODE_LF || c == UNICODE_NEL; }
00097 static inline bool IsWhiteSpace (unicode_char c) { return IsTab(c) || IsSpace(c) || IsNewLine(c); }
00098 static inline bool IsCRLF (unicode_char a,unicode_char b) { return a == UNICODE_CR && b == UNICODE_LF; }
00099
00100 static inline bool IsTab (itor i) { return IsTab( i.getCharacter()); }
00101 static inline bool IsSpace (itor i) { return IsSpace( i.getCharacter()); }
00102 static inline bool IsNewLine (itor i) { return IsNewLine( i.getCharacter()); }
00103 static inline bool IsWhiteSpace (itor i) { return IsWhiteSpace( i.getCharacter()); }
00104
00105
00106
00107 inline float GetCharWidth(unicode_char c) {
00108 if (IsNewLine(c)) return 0;
00109 if (IsTab(c)) return mfTabWidth;
00110 return IsSpace(c) ? mfSpaceWidth : (mpFont->getGlyphAspectRatio(c) * mfGlyphWidthFactor);
00111 }
00112
00113 inline float CalcLineLen (itor i,const itor iEnd) {
00114 float len = 0.0;
00115 unicode_char c = 0;
00116 bool bFirstChar = true;
00117 for (;i != iEnd;) {
00118 unicode_char lastc = c;
00119 c = i.getCharacter();
00120 if (IsNewLine(c)) break;
00121 if (!bFirstChar && mfWrapMaxW > 0 && TestAutoWrap(i,iEnd,len,IsWhiteSpace(lastc))) break;
00122 ++i;
00123 len += GetCharWidth(c);
00124 bFirstChar = false;
00125 }
00126 return len;
00127 }
00128
00130 inline float CalcWordLen (itor i,const itor iEnd) {
00131 float len = 0.0;
00132 for (;i != iEnd;++i) {
00133 unicode_char c = i.getCharacter();
00134 if (IsWhiteSpace(c)) break;
00135 len += GetCharWidth(c);
00136 }
00137 return len;
00138 }
00139
00140 bool TestAutoWrap (itor i,const itor iEnd,const float x,const bool bKeepWords) {
00141 if (i == iEnd) return false;
00142 bool bDebug = false;
00143 unicode_char c = i.getCharacter();
00144 if (mfWrapMaxW > 0 && !IsWhiteSpace(c)) {
00145 if (bDebug) printf(" aw? charlen=%f",GetCharWidth(c));
00146 if (x + GetCharWidth(c) > mfWrapMaxW) {
00147 if (bDebug) printf(" forcedWrap\n");
00148 return true;
00149 } else if (bKeepWords) {
00150 float wordlen = CalcWordLen(i,iEnd);
00151 if (bDebug) printf(" wordlen=%f x=%f x+wl=%f max=%f",wordlen,x,(x+wordlen),mfWrapMaxW);
00152
00153 if (wordlen > 0.0 && x + wordlen > mfWrapMaxW && wordlen < mfWrapMaxW) {
00154 if (bDebug) printf(" wordWrap\n");
00155 return true;
00156 }
00157 }
00158 }
00159 if (bDebug) printf("\n");
00160 return false;
00161 }
00162
00163
00164
00165 static inline void WriteVertex (float* &pVert,const float x,const float y,const float z,const float u,const float v) {
00166 *pVert++ = x;
00167 *pVert++ = y;
00168 *pVert++ = z;
00169 *pVert++ = u;
00170 *pVert++ = v;
00171 }
00172
00176 float WriteChar_NoIndex (float* &pVert,unicode_char c,const float left,const float top,const float z) {
00177 const Ogre::Font::UVRect& uvRect = mpFont->getGlyphTexCoords(c);
00178 float h = mfCharHeight;
00179 float w = mfGlyphWidthFactor * mpFont->getGlyphAspectRatio(c);
00180
00181
00182 WriteVertex(pVert,left ,top ,z,uvRect.left, uvRect.top);
00183 WriteVertex(pVert,left ,top+h,z,uvRect.left, uvRect.bottom);
00184 WriteVertex(pVert,left+w,top ,z,uvRect.right,uvRect.top);
00185
00186
00187 WriteVertex(pVert,left+w,top ,z,uvRect.right,uvRect.top);
00188 WriteVertex(pVert,left ,top+h,z,uvRect.left, uvRect.bottom);
00189 WriteVertex(pVert,left+w,top+h,z,uvRect.right,uvRect.bottom);
00190 return w;
00191 }
00192
00194 class cTextIterator { public:
00195 float x,y;
00196
00197 cTextIterator (cOgreFontHelper& mFontHelper,const Ogre::UTFString& sText)
00198 : mFontHelper(mFontHelper), mCur(sText.begin()), mEnd(sText.end()),
00199 x(0),y(0),c(0),mfLineStartX(0), mbFirstChar(true), mbLineFeed(false) {
00200 StartLine();
00201 }
00202
00203 cTextIterator (cOgreFontHelper& mFontHelper,itor mCur,itor mEnd)
00204 : mFontHelper(mFontHelper), mCur(mCur), mEnd(mEnd),
00205 x(0),y(0),c(0),mfLineStartX(0), mbFirstChar(true), mbLineFeed(false) {
00206 StartLine();
00207 }
00208
00209 inline bool HasNext () { return mCur != mEnd; }
00210
00212 inline unicode_char Next () {
00213 if (mCur == mEnd) return 0;
00214 unicode_char lastc = c;
00215 c = mCur.getCharacter();
00216
00217 if (!mbFirstChar) x += mFontHelper.GetCharWidth(lastc);
00218
00219
00220 if (mbLineFeed) {
00221 mbLineFeed = false;
00222 LineFeed();
00223 }
00224
00225
00226 if (mFontHelper.mfWrapMaxW > 0 && !mbFirstChar && mFontHelper.TestAutoWrap(mCur,mEnd,x-mfLineStartX,IsWhiteSpace(lastc)))
00227 LineFeed();
00228
00229 ++mCur;
00230
00231
00232 mbLineFeed = IsNewLine(c) && (mCur == mEnd || !IsCRLF(c,mCur.getCharacter()));
00233
00234 mbFirstChar = false;
00235 return c;
00236 }
00237
00241 inline void StartLine () {
00242 switch (mFontHelper.mAlign) {
00243 case Align_Left: x = 0;break;
00244 case Align_Center: x = - 0.5 * mFontHelper.CalcLineLen(mCur,mEnd);break;
00245 case Align_Right: x = - mFontHelper.CalcLineLen(mCur,mEnd);break;
00246 default: x = 0;break;
00247 }
00248 mfLineStartX = x;
00249 }
00250
00251 inline void LineFeed () {
00252 StartLine();
00253 y += mFontHelper.mfLineHeight;
00254 }
00255
00256
00257 private:
00258 cOgreFontHelper& mFontHelper;
00259 itor mCur;
00260 itor mEnd;
00261 bool mbFirstChar;
00262 bool mbLineFeed;
00263 float mfLineStartX;
00264 unicode_char c;
00265 };
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00285 void GetTextBounds (const Ogre::UTFString& text,Ogre::Real& w,Ogre::Real &h) {
00286 w = h = 0;
00287
00288 cOgreFontHelper::cTextIterator itor(*this,text);
00289 while (itor.HasNext()) {
00290 unicode_char c = itor.Next();
00291 w = mymax(w,itor.x + GetCharWidth(c));
00292 }
00293 h = mfLineHeight + itor.y;
00294 }
00295
00298 void GetGlyphBounds (const Ogre::UTFString& text,const int iCharIndex,Ogre::Real& l,Ogre::Real& t,Ogre::Real& r,Ogre::Real& b) {
00299 l=t=r=b=0;
00300
00301 int iCurIndex = 0;
00302 cOgreFontHelper::cTextIterator itor(*this,text);
00303 while (itor.HasNext()) {
00304 unicode_char c = itor.Next();
00305 ++iCurIndex;
00306 if (iCurIndex == iCharIndex) {
00307 l = itor.x; t = itor.y; r = l + GetCharWidth(c); b = t + mfCharHeight;
00308 return;
00309 }
00310 }
00311 }
00312
00317 int GetGlyphAtPos (const Ogre::UTFString& text,const float x,const float y) {
00318
00319 int iCurIndex = 0;
00320 cOgreFontHelper::cTextIterator itor(*this,text);
00321 float curx,cury;
00322 while (itor.HasNext()) {
00323 unicode_char c = itor.Next();
00324 ++iCurIndex;
00325 curx = x - itor.x;
00326 cury = y - itor.y;
00327 if (curx >= 0 && cury >= 0 && cury < mfCharHeight && curx < GetCharWidth(c))
00328 return iCurIndex;
00329 }
00330 return -1;
00331 }
00332 };
00333
00334
00335
00336 #if 0
00337 Ogre::FontManager::load (String &name, String &group,...)
00338
00339 void TextAreaOverlayElement::setFontName( String& font )
00340 {
00341 mpFont = FontManager::getSingleton().getByName( font );
00342 if (mpFont.isNull())
00343 OGRE_EXCEPT( Exception::ERR_ITEM_NOT_FOUND, "Could not find font " + font,
00344 "TextAreaOverlayElement::setFontName" );
00345 mpFont->load();
00346 mpMaterial = mpFont->getMaterial();
00347 mpMaterial->setDepthCheckEnabled(false);
00348 mpMaterial->setLightingEnabled(false);
00349
00350 mGeomPositionsOutOfDate = true;
00351 mGeomUVsOutOfDate = true;
00352 }
00353
00354 #if OGRE_UNICODE_SUPPORT
00355 typedef UTFString DisplayString;
00356 # define OGRE_DEREF_DISPLAYSTRING_ITERATOR(it) it.getCharacter()
00357 #else
00358 typedef String DisplayString;
00359 # define OGRE_DEREF_DISPLAYSTRING_ITERATOR(it) *it
00360 #endif
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 #endif
00372
00373 };
00374
00375 #endif
00376