HGE的中文显示解决方案

最近在自己借鉴hge写一个2d游戏引擎,无意中看到中文字体的简单解决方案,先记下来备忘。

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; 来销毁字体。

---微妙的平衡

你可能感兴趣的:(HGE的中文显示解决方案)