00001 #include "SdlArs.h"
00002
00003 namespace Ars
00004 {
00005
00006 XRenderedString::XRenderedString( CFontEngine* pFontEngine , EVAlign eVertAlign , EHAlign eHorzAlign )
00007 : m_pFontEngine(pFontEngine), m_eVertAlign(eVertAlign), m_eHorzAlign(eHorzAlign)
00008 , m_bCachedMetricsValid(false), m_MaskChar(' '), m_MaxFontHeight(-1)
00009 {
00010 }
00011
00012 void XRenderedString::_TextOut( SDL_Surface* pSurface , CRect &drawRect , CPoint &OriginPoint , const std::string &str , const CRGBColor &FontColor , CPainter::EPaintMode eMode )
00013 {
00014 m_bCachedMetricsValid = false;
00015 CPoint OriginOffset , linebox;
00016 std::vector<CRect> CharacterRects;
00017 GetMetrics( str , &linebox , &OriginOffset , &CharacterRects );
00018
00019 textSize.SetX( max( textSize.XPos() , linebox.XPos() ) );
00020 switch( m_eVertAlign )
00021 {
00022 case VALIGN_TOP : OriginPoint = CPoint( OriginPoint.XPos() , drawRect.Top() ); break;
00023 case VALIGN_BOTTOM : OriginPoint = CPoint( OriginPoint.XPos() , drawRect.Bottom() ); break;
00024 }
00025
00026 switch( m_eHorzAlign )
00027 {
00028 case HALIGN_LEFT : OriginPoint = CPoint( drawRect.Left() , OriginPoint.YPos() ); break;
00029 case HALIGN_CENTER : OriginPoint = CPoint( drawRect.Left() + drawRect.Width() / 2 , OriginPoint.YPos() ); break;
00030 case HALIGN_RIGHT : OriginPoint = CPoint( drawRect.Right() , OriginPoint.YPos() ); break;
00031 }
00032
00033 for( unsigned int i = 0 ; i < str.size() ; ++i )
00034 {
00035 FT_BitmapGlyphRec *pGlyph;
00036 if( m_MaskChar == ' ' )
00037 pGlyph = m_pFontEngine->RenderGlyph( str[i] );
00038 else
00039 pGlyph = m_pFontEngine->RenderGlyph( m_MaskChar );
00040
00041 CPainter Painter( pSurface , eMode );
00042
00043 for (int y = 0; y < pGlyph->bitmap.rows; ++y )
00044 {
00045 for (int x = 0; x < pGlyph->bitmap.width; ++x )
00046 {
00047 unsigned char *PixelOffset = pGlyph->bitmap.buffer + y * pGlyph->bitmap.width + x;
00048 if( *PixelOffset != 0x00 )
00049 {
00050 CRGBColor PixelColor(FontColor.red, FontColor.green, FontColor.blue, *PixelOffset);
00051
00052 CPoint PixelPoint( CPoint( x + pGlyph->left, y ) + OriginPoint + OriginOffset + CharacterRects[i].TopLeft() );
00053
00054 if( drawRect.HitTest( PixelPoint ) == RELPOS_INSIDE)
00055 Painter.DrawPoint(PixelPoint, PixelColor);
00056 }
00057 }
00058 }
00059 }
00060 }
00061
00062 void XRenderedString::TextOut( SDL_Surface* pSurface, const CRect &BoundingRect, const std::string &str , const CRGBColor &FontColor , CPainter::EPaintMode eMode )
00063 {
00064 m_bCachedMetricsValid = false;
00065 textSize = CPoint( 0 , 0 );
00066
00067 CPoint OriginPoint = BoundingRect.TopLeft();
00068 CRect drawRect = BoundingRect;
00069
00070 int nrlines = 1;
00071 string s = str;
00072 string::size_type n0 = 0 , n1 = s.find( '\n' , n0 );
00073 while( n1 != string::npos )
00074 {
00075 n0 = n1 + 1;
00076 n1 = s.find( '\n' , n0 );
00077 nrlines += 1;
00078 }
00079 if( m_eVertAlign == VALIGN_CENTER )
00080 OriginPoint = CPoint( OriginPoint.XPos() , OriginPoint.YPos() + (drawRect.Height() - (GetMaxFontHeight() * (nrlines - 1))) / 2 );
00081
00082 textSize.SetY( GetMaxFontHeight() * nrlines );
00083 n0 = 0 , n1 = s.find( '\n' , n0 );
00084 while( n1 != string::npos )
00085 {
00086 _TextOut( pSurface , drawRect , OriginPoint , s.substr( n0 , n1 - n0 ) , FontColor , eMode );
00087
00088 n0 = n1 + 1;
00089 n1 = s.find( '\n' , n0 );
00090 if( m_eVertAlign == VALIGN_CENTER )
00091 OriginPoint = CPoint( OriginPoint.XPos() , OriginPoint.YPos() + GetMaxFontHeight() );
00092 else
00093 drawRect.SetTop( drawRect.Top() + GetMaxFontHeight() );
00094 }
00095
00096 _TextOut( pSurface , drawRect , OriginPoint , s.substr( n0 ) , FontColor , eMode );
00097 }
00098
00099 CPoint XRenderedString::GetTextSize( const string &str )
00100 {
00101 CPoint ans( 0 , 0 );
00102
00103 int nrlines = 1;
00104 string s = str;
00105 string::size_type n0 = 0 , n1 = s.find( '\n' , n0 );
00106 while( n1 != string::npos )
00107 {
00108 CPoint lineBox( 0 , 0 );
00109
00110 m_bCachedMetricsValid = false;
00111 GetMetrics( s.substr( n0 , n1 - n0 ) , &lineBox , 0 , 0 );
00112 ans.SetX( max( ans.XPos() , lineBox.XPos() ) );
00113 n0 = n1 + 1;
00114 n1 = s.find( '\n' , n0 );
00115 nrlines += 1;
00116 }
00117 CPoint lineBox( 0 , 0 );
00118 m_bCachedMetricsValid = false;
00119 GetMetrics( s.substr( n0 ) , &lineBox , 0 , 0 );
00120 ans.SetX( max( ans.XPos() , lineBox.XPos() ) );
00121
00122 ans.SetY( GetMaxFontHeight() * nrlines );
00123
00124 return ans;
00125 }
00126
00127 unsigned int XRenderedString::GetMaxFontHeight()
00128 {
00129 if (m_MaxFontHeight < 0)
00130 {
00131 int maxHeight=0;
00132 FT_Glyph_Metrics* pMetrics;
00133 for(int i=0; i < 256; i++)
00134 {
00135 pMetrics = m_pFontEngine->GetMetrics((char)i);
00136 if ((pMetrics->height >> 6) > maxHeight)
00137 {
00138 maxHeight = (pMetrics->height >> 6);
00139 }
00140
00141 }
00142 m_MaxFontHeight = maxHeight + 2;
00143 }
00144 return m_MaxFontHeight;
00145 }
00146
00147 void XRenderedString::GetMetrics( const std::string &str , CPoint* pBoundedDimensions, CPoint* pOriginOffset, std::vector<CRect>* pCharacterRects) const
00148 {
00149 if (! m_bCachedMetricsValid )
00150 {
00151 m_CachedCharacterRects.clear();
00152
00153 int iMinY = 0;
00154 int iMaxY = 0;
00155 int iLength = 0;
00156 for (unsigned int i = 0; i < str.size(); ++i)
00157 {
00158 FT_Glyph_Metrics* pMetrics;
00159 if (m_MaskChar == ' ')
00160 {
00161 pMetrics = m_pFontEngine->GetMetrics(str[i]);
00162 }
00163 else
00164 {
00165 pMetrics = m_pFontEngine->GetMetrics(m_MaskChar);
00166 }
00167
00168
00169 if ((pMetrics->horiBearingY - pMetrics->height) < iMinY)
00170 {
00171 iMinY = pMetrics->horiBearingY - pMetrics->height;
00172 }
00173 if (pMetrics->horiBearingY > iMaxY)
00174 {
00175 iMaxY = pMetrics->horiBearingY;
00176 }
00177 iLength += (pMetrics->horiAdvance);
00178
00179 m_CachedCharacterRects.push_back(
00180 CRect((iLength - pMetrics->horiAdvance) >> 6, pMetrics->horiBearingY >> 6, iLength >> 6, pMetrics->height >> 6));
00181 }
00182
00183 iMinY = iMinY >> 6;
00184 iMaxY = iMaxY >> 6;
00185 iLength = iLength >> 6;
00186
00187
00188 for(std::vector<CRect>::iterator iter = m_CachedCharacterRects.begin(); iter != m_CachedCharacterRects.end(); ++iter)
00189 {
00190 iter->SetTop(iMaxY - iter->Top());
00191 iter->SetBottom(iter->Top() + iter->Bottom());
00192 }
00193
00194
00195 m_CachedCharacterRects.push_back(CRect(iLength, iMaxY, iLength, iMinY));
00196
00197 m_CachedBoundedDimensions = CPoint(iLength, iMaxY - iMinY);
00198
00199 switch (m_eHorzAlign)
00200 {
00201 case HALIGN_CENTER:
00202 m_OriginOffset.SetX(-iLength / 2);
00203 break;
00204 case HALIGN_RIGHT:
00205 m_OriginOffset.SetX(-iLength);
00206 break;
00207 case HALIGN_LEFT:
00208 default:
00209 m_OriginOffset.SetX(0);
00210 break;
00211 }
00212
00213 switch (m_eVertAlign)
00214 {
00215 case VALIGN_TOP:
00216 m_OriginOffset.SetY(0);
00217 break;
00218 case VALIGN_BOTTOM:
00219 m_OriginOffset.SetY(iMinY - iMaxY);
00220 break;
00221 case VALIGN_CENTER:
00222 m_OriginOffset.SetY((iMinY - iMaxY) / 2);
00223 break;
00224 case VALIGN_NORMAL:
00225 default:
00226 m_OriginOffset.SetY(-iMaxY);
00227 break;
00228 }
00229
00230 m_bCachedMetricsValid = true;
00231 }
00232
00233 if (pBoundedDimensions)
00234 {
00235 *pBoundedDimensions = m_CachedBoundedDimensions;
00236 }
00237
00238 if (pOriginOffset)
00239 {
00240 *pOriginOffset = m_OriginOffset;
00241 }
00242
00243 if (pCharacterRects)
00244 {
00245 *pCharacterRects = m_CachedCharacterRects;
00246 }
00247 }
00248
00249 }