渲染FreeType位图字形

时间:2018-12-19 23:28:09

标签: c++ directx-9 freetype2

我试图将字形加载到具有freetype的位图中,然后将每个字形加载到d3d9纹理中,但是由于某种原因纹理设置不正确。

我想将每个字形加载到其自己的纹理中,以便可以分别绘制每个字符。

我如何为字体创建字形纹理:

new_font_t::new_font_t( const char* szFontFilename, int iHeight, std::size_t _sRangeBegin, std::size_t _sRangeEnd ): sRangeBegin( _sRangeBegin ), sRangeEnd( _sRangeEnd )
{
    assert( !FT_New_Face( _RenderContext.ftLibrary, ( std::string( R"(C:\Windows\Fonts\)" ) + szFontFilename ).c_str( ), 0, &fFont ) );
    FT_Set_Char_Size( fFont, 0, iHeight * 64, 96, 96 );
    pGlyphs = new IDirect3DTexture9*[ sRangeEnd - sRangeBegin ];

    for( auto u = sRangeBegin; u <= sRangeEnd; u++ )
    {
        const auto iIndex = FT_Get_Char_Index( fFont, u );
        D3DLOCKED_RECT recGlyph;

        FT_Load_Glyph( fFont, iIndex, FT_LOAD_DEFAULT );
        FT_Render_Glyph( fFont->glyph, FT_RENDER_MODE_NORMAL );
        const auto uWidth = fFont->glyph->bitmap.width;
        D3DXCreateTexture( _RenderContext.pDevice, uWidth, iHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pGlyphs[ u ] );
        pGlyphs[ u ]->LockRect( 0, &recGlyph, nullptr, 0 );

        for ( auto i = 0; i < int( uWidth ); i++ )
        {
            for ( auto j = 0; j < iHeight; j++ )
                if( fFont->glyph->bitmap.buffer[ i + j * uWidth ] > 0 )
                    reinterpret_cast< DWORD* >( recGlyph.pBits )[ i + j * uWidth ] = 0xFFFFFFFF;
        }

        pGlyphs[ u ]->UnlockRect( 0 );
    }
}

这就是我呈现文本的方式:

void new_font_t::RenderText( const char* szText )
{
    if( _RenderContext.pSprite->Begin( D3DXSPRITE_ALPHABLEND ) == D3D_OK )
    {
        auto loc = D3DXVECTOR3( 50, 100, 0 );

        for ( auto u = 0u; u < strlen( szText ); u++ )
            _RenderContext.pSprite->Draw( pGlyphs[ szText[ u ] ], nullptr, nullptr, &loc, 0xFFFFFFFF );
        _RenderContext.pSprite->End( );
    }
}

我这样创建一个字体结构:

test_font = new new_font_t( "arial.ttf", 32, 0, 0xFF );

然后我调用渲染函数:

test_font->RenderText( "!" );

如您所见,它应该呈现一个感叹号,但是呈现为:https://i.imgur.com/Chqnltt.png

1 个答案:

答案 0 :(得分:0)

尝试将您的字符转换为wchar_t,这对我来说已经解决了。

这是一段代码,可将彩色文本渲染到具有alpha透明度的32位图像缓冲区中:

void DrawTxt(char *txt, int x, int y, int w, int h, uint32_t col, uint8_t *buf) {

    int origx = x;
    wchar_t wstr[512];

    int len = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS|MB_PRECOMPOSED, txt, -1, wstr, 512);

    for(int n=0; n<len; n++) {
        wchar_t wc = wstr[n];

        if(wc=='\0') { continue; }
        if(wc=='\r') { x = origx; continue; }
        if(wc=='\n') { y += _ph; x = origx; continue; } // line spacing
        if(wc==' ' && x>w) { y += _ph; x = origx; } // word break

        FT_Load_Char(_face, wc, FT_LOAD_RENDER);
        FT_GlyphSlot g = _face->glyph;

        x += g->bitmap_left; // horizontal adjust

        uint8_t *src = g->bitmap.buffer;
        uint8_t *end = buf + w*h*4 - 1;

        uint32_t *dst = (uint32_t*)buf+x + y*w;

        dst += w * (_ph - g->bitmap_top); // adjust to baseline

        for(int gy=0; gy<g->bitmap.rows; gy++) {
            for(int gx=0; gx<g->bitmap.width; gx++) {

                if(x+gx>=w) break; // out right edge in pixmap

                uint8_t *c = (uint8_t *)&col;
                uint8_t *d = (uint8_t *)&dst[gx];

                if(d<buf || d>end) continue; // avoid under/overflow

                uint32_t alpha = *src; // premultiply alpha
                d[0] |= unsigned char((alpha * c[2]) / 255);
                d[1] |= unsigned char((alpha * c[1]) / 255);
                d[2] |= unsigned char((alpha * c[0]) / 255);
                d[3] |= unsigned char(alpha);

                src++;
            }
            dst += w;
        }
        x -= g->bitmap_left;
        x += g->advance.x >> 6;
    }
}