00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "wgui_include_config.h"
00026 #include "wg_renderedstring.h"
00027 #include "wg_painter.h"
00028 #include "wg_error.h"
00029 #include <algorithm>
00030
00031 namespace wGui
00032 {
00033
00034 CRenderedString::CRenderedString(CFontEngine* pFontEngine, const std::wstring& sString, EVAlign eVertAlign, EHAlign eHorzAlign) :
00035 m_pFontEngine(pFontEngine),
00036 m_sString(sString),
00037 m_eVertAlign(eVertAlign),
00038 m_eHorzAlign(eHorzAlign),
00039 m_bCachedMetricsValid(false),
00040 m_MaskChar(L' '),
00041 m_MaxFontHeight(-1),
00042 m_MaxFontWidth(-1)
00043 {
00044 if (! m_pFontEngine)
00045 {
00046 throw(Wg_Ex_App(L"CRenderedString::CRenderedString : Bad pFontEngine pointer! (This is usually the result of the wgui.conf file missing or misconfigured. See the Global Config section of the docs.)"));
00047 }
00048 }
00049
00050
00051 void CRenderedString::Draw(SDL_Surface* pSurface, const CRect& BoundingRect, const CPoint& OriginPoint, const CRGBColor& FontColor) const
00052 {
00053 CPoint OriginOffset;
00054 std::vector<CRect> CharacterRects;
00055 GetMetrics(0, &OriginOffset, &CharacterRects);
00056 for (unsigned int i = 0; i < m_sString.size(); ++i)
00057 {
00058 FT_BitmapGlyphRec* pGlyph;
00059 if (m_MaskChar == L' ')
00060 {
00061 pGlyph = m_pFontEngine->RenderGlyph(m_sString[i]);
00062 }
00063 else
00064 {
00065 pGlyph = m_pFontEngine->RenderGlyph(m_MaskChar);
00066 }
00067 CPainter Painter(pSurface, CPainter::PAINT_NORMAL);
00068 for (int y = 0; y < pGlyph->bitmap.rows; ++y)
00069 {
00070 for (int x = 0; x < pGlyph->bitmap.width; ++x)
00071 {
00072 unsigned char* PixelOffset = pGlyph->bitmap.buffer + y * pGlyph->bitmap.width + x;
00073 if (*PixelOffset != 0x00)
00074 {
00075 CRGBColor PixelColor(FontColor.red, FontColor.green, FontColor.blue, *PixelOffset);
00076 CPoint PixelPoint(CPoint(x + pGlyph->left, y) + OriginPoint + OriginOffset + CharacterRects.at(i).TopLeft());
00077 if (BoundingRect.HitTest(PixelPoint) == CRect::RELPOS_INSIDE)
00078 {
00079 Painter.DrawPoint(PixelPoint, PixelColor);
00080 }
00081 }
00082 }
00083 }
00084 }
00085 }
00086
00087
00088 unsigned int CRenderedString::GetMaxFontHeight(void)
00089 {
00090 if (m_MaxFontHeight < 0)
00091 {
00092 int maxHeight = 0;
00093 FT_Glyph_Metrics* pMetrics;
00094 for(int i = 0; i < 256; i++)
00095 {
00096 pMetrics = m_pFontEngine->GetMetrics(static_cast<char>(i));
00097 if ((pMetrics->height >> 6) > maxHeight)
00098 {
00099 maxHeight = (pMetrics->height >> 6);
00100 }
00101 }
00102 m_MaxFontHeight = maxHeight;
00103 }
00104 return m_MaxFontHeight;
00105 }
00106
00107
00108 unsigned int CRenderedString::GetMaxFontWidth(void)
00109 {
00110 if (m_MaxFontWidth < 0)
00111 {
00112 int maxWidth = 0;
00113 FT_Glyph_Metrics* pMetrics;
00114 for(int i = 0; i < 256; i++)
00115 {
00116 pMetrics = m_pFontEngine->GetMetrics(static_cast<char>(i));
00117 if ((pMetrics->width >> 6) > maxWidth)
00118 {
00119 maxWidth = (pMetrics->width >> 6);
00120 }
00121 }
00122 m_MaxFontWidth = maxWidth;
00123 }
00124 return m_MaxFontWidth;
00125 }
00126
00127
00128 void CRenderedString::GetMetrics(CPoint* pBoundedDimensions, CPoint* pOriginOffset, std::vector<CRect>* pCharacterRects) const
00129 {
00130 if (! m_bCachedMetricsValid)
00131 {
00132 m_CachedCharacterRects.clear();
00133
00134 int iMinY = 0;
00135 int iMaxY = 0;
00136 int iLength = 0;
00137 for (unsigned int i = 0; i < m_sString.size(); ++i)
00138 {
00139 FT_Glyph_Metrics* pMetrics;
00140 if (m_MaskChar == L' ')
00141 {
00142 pMetrics = m_pFontEngine->GetMetrics(m_sString[i]);
00143 }
00144 else
00145 {
00146 pMetrics = m_pFontEngine->GetMetrics(m_MaskChar);
00147 }
00148
00149 if ((pMetrics->horiBearingY - pMetrics->height) < iMinY)
00150 {
00151 iMinY = pMetrics->horiBearingY - pMetrics->height;
00152 }
00153 if (pMetrics->horiBearingY > iMaxY)
00154 {
00155 iMaxY = pMetrics->horiBearingY;
00156 }
00157 iLength += (pMetrics->horiAdvance);
00158
00159 m_CachedCharacterRects.push_back(
00160 CRect((iLength - pMetrics->horiAdvance) >> 6, pMetrics->horiBearingY >> 6, iLength >> 6, pMetrics->height >> 6));
00161 }
00162
00163 iMinY = iMinY >> 6;
00164 iMaxY = iMaxY >> 6;
00165 iLength = iLength >> 6;
00166
00167
00168 for(std::vector<CRect>::iterator iter = m_CachedCharacterRects.begin(); iter != m_CachedCharacterRects.end(); ++iter)
00169 {
00170 iter->SetTop(iMaxY - iter->Top());
00171 iter->SetBottom(iter->Top() + iter->Bottom());
00172 }
00173
00174
00175 m_CachedCharacterRects.push_back(CRect(iLength, iMaxY, iLength, iMinY));
00176
00177 m_CachedBoundedDimensions = CPoint(iLength, iMaxY - iMinY);
00178
00179 switch (m_eHorzAlign)
00180 {
00181 case HALIGN_CENTER:
00182 m_OriginOffset.SetX(-iLength / 2);
00183 break;
00184 case HALIGN_RIGHT:
00185 m_OriginOffset.SetX(-iLength);
00186 break;
00187 case HALIGN_LEFT:
00188 default:
00189 m_OriginOffset.SetX(0);
00190 break;
00191 }
00192
00193 switch (m_eVertAlign)
00194 {
00195 case VALIGN_TOP:
00196 m_OriginOffset.SetY(0);
00197 break;
00198 case VALIGN_BOTTOM:
00199 m_OriginOffset.SetY(iMinY - iMaxY);
00200 break;
00201 case VALIGN_CENTER:
00202 m_OriginOffset.SetY((iMinY - iMaxY) / 2);
00203 break;
00204 case VALIGN_NORMAL:
00205 default:
00206 m_OriginOffset.SetY(-iMaxY);
00207 break;
00208 }
00209
00210 m_bCachedMetricsValid = true;
00211 }
00212
00213 if (pBoundedDimensions)
00214 {
00215 *pBoundedDimensions = m_CachedBoundedDimensions;
00216 }
00217
00218 if (pOriginOffset)
00219 {
00220 *pOriginOffset = m_OriginOffset;
00221 }
00222
00223 if (pCharacterRects)
00224 {
00225 *pCharacterRects = m_CachedCharacterRects;
00226 }
00227 }
00228
00229 }
00230