HGE本身并不支持中文的显示,因此我使用由 微妙的平衡 大神提供的解决方案.
大神提供的代码本来包含gfxfont.h和gfxfont.cpp文件,只需要将这两个文件添加到工程中即可使用.
但是我实在太懒,为了避免每次都添加两个文件到工程中去,于是我擅自将cpp的代码全部移到了.h文件中并做了一些细微的改动.
这样每次使用的时候就只需要将gfxfont.h引入工程就够了,当然我把这个gfxfont.h直接放到了hge的include文件夹中,这样我就可以直接
用#include
以下是gfxfont.h文件的源码:
gfxfont.h
#ifndef GDIFONT_H
#define GDIFONT_H
#include
#include
#include
#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(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(m_nFontSize)};
float nRowWidth = 0;
while(*text)
{
if (*text == L'\n' || *text == L'\r')
{
dim.cy += static_cast(m_nFontSize + m_nKerningHeight);
if (dim.cx < static_cast(nRowWidth))
dim.cx = static_cast(nRowWidth);
nRowWidth = 0;
}
else
nRowWidth += (GetWidthFromCharacter(*text) + m_nKerningWidth);
++text;
}
if (dim.cx < static_cast(nRowWidth))
dim.cx = static_cast(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(gm.gmBlackBoxX);
m_Glyphs[idx].h = static_cast(gm.gmBlackBoxY);
m_Glyphs[idx].x = static_cast(-gm.gmptGlyphOrigin.x);
m_Glyphs[idx].y = static_cast(-m_nAscent + gm.gmptGlyphOrigin.y);
m_Glyphs[idx].c = static_cast(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; 来销毁字体。
---微妙的平衡