HGE本身并不支持中文的显示,因此我使用由 微妙的平衡 大神提供的解决方案.
大神提供的代码本来包含gfxfont.h和gfxfont.cpp文件,只需要将这两个文件添加到工程中即可使用.
但是我实在太懒,为了避免每次都添加两个文件到工程中去,于是我擅自将cpp的代码全部移到了.h文件中并做了一些细微的改动.
这样每次使用的时候就只需要将gfxfont.h引入工程就够了,当然我把这个gfxfont.h直接放到了hge的include文件夹中,这样我就可以直接
用#include <gfxfont.h>来引用这个文件了.(当然,要先hge的include目录添加到工程中去.)
以下是gfxfont.h文件的源码:
gfxfont.h #ifndef GDIFONT_H #define GDIFONT_H #include <hgesprite.h> #include <atlbase.h> #include <stdio.h> #pragma comment(linker,"/NODEFAULTLIB:libc.lib") __inline float _floor(float f) { static int _n; _asm fld f _asm fistp _n return (float)_n; } class GfxFont { public: static const unsigned char g_byAlphaLevel[65]; GfxFont(const char* lpsFontName, int nFaceSize, BOOL bBold = FALSE, BOOL bItalic = FALSE, BOOL bAntialias = TRUE) { m_pHGE = hgeCreate(HGE_VERSION); // 创建GDI相关设备 HDC hDC = GetDC(m_pHGE->System_GetState(HGE_HWND)); m_hMemDC = CreateCompatibleDC(hDC); if (NULL == m_hMemDC) return; ReleaseDC(m_pHGE->System_GetState(HGE_HWND),hDC); ::SetMapMode(m_hMemDC, MM_TEXT); ::SetTextColor(m_hMemDC,RGB(255,255,255)); ::SetBkColor(m_hMemDC,RGB(0,0,0)); m_hFont = CreateFont( -nFaceSize, 0, 0, 0, (bBold) ? FW_BOLD : FW_NORMAL, bItalic, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE | DEFAULT_PITCH, lpsFontName); if (NULL == (m_hFont)) return; SelectObject(m_hMemDC, m_hFont); memset(m_Glyphs,0,sizeof(TENGINEFONTGLYPH)*font_count); m_nAntialias = bAntialias ? GGO_GRAY8_BITMAP : GGO_BITMAP; TEXTMETRIC tm; ::GetTextMetrics(m_hMemDC,&tm); m_nAscent = tm.tmAscent; m_nFontSize = static_cast<float>(nFaceSize); m_nKerningWidth = 0; m_nKerningHeight= 0; m_pSprite = new hgeSprite(0, 0, 0, 0, 0); m_pSprite->SetColor(ARGB(255, 255, 255, 255)); } ~GfxFont(void) { for (int nIdx = 0; nIdx < font_count; ++nIdx) { if (m_Glyphs[nIdx].t) m_pHGE->Texture_Free(m_Glyphs[nIdx].t); } if ((m_hFont)) DeleteObject(m_hFont); if ((m_hMemDC)) DeleteDC(m_hMemDC); if(m_pSprite) delete m_pSprite; if(m_pHGE) m_pHGE->Release(); } public: // 渲染文本 virtual void Print( float x, float y, const char *format, ... ) { char sBuffer[10240] = {0}; char *lpsArg=(char*)&format+sizeof(format); vsprintf_s(sBuffer,10240, format,lpsArg); Render(x,y,CA2W(sBuffer)); } virtual void Render(float x, float y, const wchar_t* text ) { float offsetX = x; float offsetY = y; while(*text) { if (*text == L'\n' || *text == L'\r') { offsetX = x; offsetY += (m_nFontSize + m_nKerningHeight); } else { unsigned int idx = GetGlyphByCharacter(*text); if (idx > 0) { m_pSprite->SetTexture(m_Glyphs[idx].t); m_pSprite->SetTextureRect(0, 0, m_Glyphs[idx].w, m_Glyphs[idx].h); m_pSprite->Render(offsetX - m_Glyphs[idx].x, offsetY - m_Glyphs[idx].y); offsetX += (GetWidthFromCharacter(*text) + m_nKerningWidth); } else { offsetX += (GetWidthFromCharacter(*text) + m_nKerningWidth); } } ++text; } } // 设置与获取颜色 virtual void SetColor( DWORD dwColor, int i = -1 ) { m_pSprite->SetColor(dwColor,i); } virtual DWORD GetColor( int i = 0 ) { return m_pSprite->GetColor(i); } // 获取文本宽高 virtual SIZE GetTextSize( const wchar_t* text ) { SIZE dim = {0, static_cast<LONG>(m_nFontSize)}; float nRowWidth = 0; while(*text) { if (*text == L'\n' || *text == L'\r') { dim.cy += static_cast<LONG>(m_nFontSize + m_nKerningHeight); if (dim.cx < static_cast<LONG>(nRowWidth)) dim.cx = static_cast<LONG>(nRowWidth); nRowWidth = 0; } else nRowWidth += (GetWidthFromCharacter(*text) + m_nKerningWidth); ++text; } if (dim.cx < static_cast<LONG>(nRowWidth)) dim.cx = static_cast<LONG>(nRowWidth); return dim; } // 根据坐标获取字符 virtual wchar_t GetCharacterFromPos( const wchar_t* text, float pixel_x, float pixel_y ) { float x = 0; float y = 0; while (*text) { if (*text == L'\n' || *text == L'\r') { x = 0; y += (m_nFontSize+m_nKerningHeight); text++; if (!(*text)) break; } float w = GetWidthFromCharacter(*text); if (pixel_x > x && pixel_x <= x + w && pixel_y > y && pixel_y <= y + m_nFontSize) return *text; x += (w+m_nKerningWidth); text++; } return L'\0'; } // 设置字间距 virtual void SetKerningWidth( float kerning ) { m_nKerningWidth = kerning; } virtual void SetKerningHeight( float kerning ) { m_nKerningHeight = kerning; } // 获取字间距 virtual float GetKerningWidth() { return m_nKerningWidth; } virtual float GetKerningHeight() { return m_nKerningHeight; } // 字体大小 virtual float GetFontSize() { return m_nFontSize; } private: // 根据字符获取轮廓 unsigned int GetGlyphByCharacter( wchar_t c ) { unsigned int idx = (unsigned int)c; if (NULL == (m_Glyphs[idx].t)) CacheCharacter(idx,c); return idx; } inline float GetWidthFromCharacter( wchar_t c, bool original = false ) { unsigned int idx = GetGlyphByCharacter(c); if (original && idx > 0 && idx < font_count) return m_Glyphs[idx].c; return (idx >= 0x2000) ? m_nFontSize : _floor(m_nFontSize / 2); } inline void CacheCharacter(unsigned int idx, wchar_t c) { if (idx < font_count && NULL == m_Glyphs[idx].t) { UINT nChar = (UINT)c; MAT2 mat2 = {{0,1},{0,0},{0,0},{0,1}}; GLYPHMETRICS gm; DWORD nLen = ::GetGlyphOutlineW(m_hMemDC,nChar,m_nAntialias,&gm,0,NULL,&mat2); HTEXTURE hTex = m_pHGE->Texture_Create(gm.gmBlackBoxX,gm.gmBlackBoxY); if (NULL == hTex) return; if((signed)nLen > 0) { LPBYTE lpBuf = new BYTE[nLen]; if (nLen == ::GetGlyphOutlineW(m_hMemDC,nChar,m_nAntialias,&gm,nLen,lpBuf,&mat2)) { BYTE* lpSrc = lpBuf; DWORD* lpDst = m_pHGE->Texture_Lock(hTex,FALSE); if (GGO_BITMAP == m_nAntialias) { LONG nSrcPitch = (gm.gmBlackBoxX / 32 + (gm.gmBlackBoxX % 32 == 0 ? 0 : 1)) * 4; LONG nDstPitch = m_pHGE->Texture_GetWidth(hTex); for (UINT y = 0; y < gm.gmBlackBoxY; ++y) { for (UINT x = 0; x < gm.gmBlackBoxX; ++x) { for(UINT k = 0; k < 8; ++k) { UINT i = 8 * x + k; if (i >= gm.gmBlackBoxX) { x+=7; break; } lpDst[i] = ((lpSrc[x] >> (7 - k)) & 1) ? 0xFFFFFFFF : 0x0; } } lpSrc += nSrcPitch; lpDst += nDstPitch; } } else { LONG nSrcPitch = (gm.gmBlackBoxX / 4 + (gm.gmBlackBoxX % 4 == 0 ? 0 : 1)) * 4; LONG nDstPitch = m_pHGE->Texture_GetWidth(hTex); for (UINT y = 0; y < gm.gmBlackBoxY; ++y) { for (UINT x = 0; x < gm.gmBlackBoxX; ++x) { lpDst[x] = ARGB(g_byAlphaLevel[lpSrc[x]],0xFF,0xFF,0xFF); } lpSrc += nSrcPitch; lpDst += nDstPitch; } } m_pHGE->Texture_Unlock(hTex); } delete lpBuf; } else { // 非正常显示字符 } m_Glyphs[idx].t = hTex; m_Glyphs[idx].w = static_cast<float>(gm.gmBlackBoxX); m_Glyphs[idx].h = static_cast<float>(gm.gmBlackBoxY); m_Glyphs[idx].x = static_cast<float>(-gm.gmptGlyphOrigin.x); m_Glyphs[idx].y = static_cast<float>(-m_nAscent + gm.gmptGlyphOrigin.y); m_Glyphs[idx].c = static_cast<float>(gm.gmCellIncX); } } typedef struct tagEngineFontGlyph { HTEXTURE t; float w; float h; float x; float y; float c; }TENGINEFONTGLYPH; static const unsigned int font_count = 0xFFFF;// = sizeof(wchar_t); TENGINEFONTGLYPH m_Glyphs[font_count]; UINT m_nAntialias;//反锯齿 LONG m_nAscent;//基线 DWORD m_dwFontColor; float m_nFontSize; float m_nKerningWidth; float m_nKerningHeight; HGE* m_pHGE; hgeSprite* m_pSprite; // GDI设备 HDC m_hMemDC; HFONT m_hFont; }; const unsigned char GfxFont::g_byAlphaLevel[65] = { 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96,100, 104,108,112,116,120,124,128,132,136,140,144,148,152, 156,160,164,168,172,176,180,184,188,192,196,200,204, 208,212,216,220,224,228,232,236,240,244,248,252,255 }; #endif//GDIFONT_H
直接复制源码保存为gfxfont.h并引入工程后即可使用.
使用方法:
本方法是为解决HGE项目中支持中文显示的新方案。
本解决方案不需要依赖任何图片字模,并支持丰富的显示方法。
使用方法很简单,只需如下几步即可:
一、包含 "gfxFont.h" 头文件。
二、创建字体指针:GfxFont* fontspr = new GfxFont(字体名,字体大小,是否粗体,是否斜体,是否平滑模式);
三、文本颜色:fontspr->SetColor(ARGB);
三、文本渲染:fontspr->Print(坐标x,坐标y,文本内容);
四、销毁字体:当程序结束时,使用 delete fontspr; 来销毁字体。
---微妙的平衡