幻想森林

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 5174|回复: 0

[分享]Irrlicht中显示中文的办法

[复制链接]

136

主题

1751

帖子

548

积分

版主

Rank: 7Rank: 7Rank: 7

积分
548
发表于 2006-9-20 10:15:01 | 显示全部楼层 |阅读模式
用到的是日本人Zgock做的TrueType类库,CGUITTFont
原来支持的是dx8的,我机子上没有,所以改了一下,支持dx9,需要opengl也可以自己动手。
这是基于FreeType开发的,因此得去下FreeType的支持库。http://www.freetype.org/

我用的是自己编译的静态连接库,编译后的exe大约是多了250K左右。
个人觉得,这样至少比多带一个dll看起来舒服一点。

-----------------------main.cpp代码-------------------------------------------
#include <windows.h>
#include <irrlicht.h>
#include <CGUITTFont.h>

using namespace irr;      
using namespace core;   
using namespace video;
using namespace gui;

#pragma comment (lib, "Irrlicht.lib")          //irrlicht的库文件
#pragma comment (lib, "freetype221.lib")  //freetype的库文件

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
{
     IrrlichtDevice *Device = createDevice(EDT_DIRECT3D9, dimension2d<s32>(400, 300),16, false, false, 0);//这里用的是dx9
    Device->setWindowCaption(L"这是一个显示简体中文的简单例子");
    IVideoDriver  *Driver  = Device->getVideoDriver();
    CGUITTFace face;
    face.load("C:\\windows\\fonts\\simsun.ttc");     //载入字体,这里用的是微软的宋体
    CGUITTFont *Font = new CGUITTFont(Driver);
    Font->attach(&face,26); //字体大小      
    Font->AntiAlias = true;  //反锯齿,使得字体显示更好看

    while(Device->run())
           {
       Driver->beginScene(true, true, SColor(0,100,100,100));
         Font->draw(L"Hello  World !",rect<s32>(50,50,0,0),SColor(255,255,0,0)); //SColor格式似乎是ARGB
          Font->draw(L"你好  世界!",rect<s32>(50,100,0,0),SColor(255,0,255,0));
       Driver->endScene();
           }

       Device->drop();     //释放资源
    return 0;
    }
----------------------------------------------------------------------
但是这样只是支持了中文的显示,对于中文输入还是不行。
估计那要去改irr::gui里面的东西了,不懂了,而且没找到现成的解决办法。 [s:6]


ps:没法上传附件,干脆用文本传了。
-----------CGUITTFont.h-----------------
#ifndef __C_GUI_TTFONT_H_INCLUDED__
#define __C_GUI_TTFONT_H_INCLUDED__

#include <ft2build.h>
#include <freetype/freetype.h>
#include <irrlicht.h>

namespace irr
{
namespace gui
{
class CGUITTFace : public IUnknown
{
public:
    FT_Library    library;
    FT_Face        face;
    bool load(const c8* filename);
};
class CGUITTGlyph : public IUnknown
{
public:
    bool cached;
    video::IVideoDriver* Driver;
    CGUITTGlyph();
    virtual ~CGUITTGlyph();
    void cache(u32 idx);
    FT_Face *face;
    u32 size;
    u32 top;
    u32 left;
    u32 texw;
    u32 texh;
    u32 imgw;
    u32 imgh;
    video::ITexture *tex;
    u32 top16;
    u32 left16;
    u32 texw16;
    u32 texh16;
    u32 imgw16;
    u32 imgh16;
    video::ITexture *tex16;
    s32 offset;
    u8 *image;
};
class CGUITTFont : public IGUIFont
{
public:

    //! constructor
    CGUITTFont(video::IVideoDriver* Driver);

    //! destructor
    virtual ~CGUITTFont();

    //! loads a truetype font file
    bool attach(CGUITTFace *Face,u32 size);

    //! draws an text and clips it to the specified rectangle if wanted
    virtual void draw(const wchar_t* text, const core::rect<s32>& position, video::SColor color, bool hcenter=false, bool vcenter=false, const core::rect<s32>* clip=0);

    //! returns the dimension of a text
    virtual core::dimension2d<s32> getDimension(const wchar_t* text);

    //! Calculates the index of the character in the text which is on a specific position.
    virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x);

    bool AntiAlias;
    bool TransParency;
private:
    s32 CGUITTFont::getWidthFromCharacter(wchar_t c);
    u32 getGlyphByChar(wchar_t c);
    video::IVideoDriver* Driver;
    core::array< CGUITTGlyph > Glyphs;
    CGUITTFace *tt_face;
};

} // end namespace gui
} // end namespace irr

#endif

-----------------CGUITTFont.h----------------------------------

-----------------CGUITTFont.cpp-------------------------------
#include "irrlicht.h"
#include "CGUITTFont.h"

namespace irr

{
namespace gui
{

CGUITTGlyph::CGUITTGlyph() : IUnknown()
{
    tex = NULL;
    image = NULL;
}

CGUITTGlyph::~CGUITTGlyph()
{
    if (image) delete image;
//    if (tex) Driver->removeTexture(tex);
}

void CGUITTGlyph::cache(u32 idx)
{
    FT_Set_Pixel_Sizes(*face,0,size);
    if (!FT_Load_Glyph(*face,idx,FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP)){
        FT_GlyphSlot glyph = (*face)->glyph;
        FT_Bitmap  bits;
        if (glyph->format == ft_glyph_format_outline ){
            if (!FT_Render_Glyph( glyph, FT_RENDER_MODE_NORMAL)){
                bits = glyph->bitmap;
                u8 *pt = bits.buffer;
                image = new u8[bits.width * bits.rows];
                memcpy(image,pt,bits.width * bits.rows);
                top = glyph->bitmap_top;
                left = glyph->bitmap_left;
                imgw = 1;
                imgh = 1;
                texw = bits.width;
                texh = bits.rows;
                for(;;){
                    if (imgw > texw){
                        break;
                    } else {
                        imgw <<= 1;
                    }
                }
                for(;;){
                    if (imgh > texh){
                        break;
                    } else {
                        imgh <<= 1;
                    }
                }
                if (imgw > imgh){
                    imgh = imgw;
                } else {
                    imgw = imgh;
                }
                u32 *texd = new u32[imgw*imgh];
                memset(texd,0,imgw*imgh*sizeof(u32));
                u32 *texp = texd;
                offset = size - bits.rows;
                bool cflag = (Driver->getDriverType() == video::EDT_DIRECT3D9);
                for (int i = 0;i < bits.rows;i++){
                    u32 *rowp = texp;
                    for (int j = 0;j < bits.width;j++){
                        if (*pt){
                            if (cflag){
                                *rowp = *pt;
                                *rowp *= 0x01010101;
                            } else {
                                *rowp = *pt << 24;
                                *rowp |= 0xffffff;
                            }
                        } else {
                            *rowp = 0;
                        }
                        pt++;
                        rowp++;
                    }
                    texp += imgw;
                }
                c8 name[128];
                sprintf(name,"TTFontGlyph%d",idx);
                video::IImage *img = Driver->createImageFromData(video::ECF_A8R8G8B8,core::dimension2d<s32>(imgw,imgh),texd);
                bool flg16 = Driver->getTextureCreationFlag(video::ETCF_ALWAYS_16_BIT);
                bool flg32 = Driver->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT);
                Driver->setTextureCreationFlag(video::ETCF_ALWAYS_16_BIT,false);
                Driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true);
                tex = Driver->addTexture(name,img);
                Driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,flg32);
                Driver->setTextureCreationFlag(video::ETCF_ALWAYS_16_BIT,flg16);
                delete texd;
                cached = true;
            }
        }
    }
    if (!FT_Load_Glyph(*face,idx,FT_LOAD_NO_HINTING|FT_LOAD_RENDER|FT_LOAD_MONOCHROME)){
        FT_GlyphSlot glyph = (*face)->glyph;
        FT_Bitmap bits = glyph->bitmap;
        u8 *pt = bits.buffer;
        top16 = glyph->bitmap_top;
        left16 = glyph->bitmap_left;
        imgw16 = 1;
        imgh16 = 1;
        texw16 = bits.width;
        texh16 = bits.rows;
        for(;;){
            if (imgw16 >= texw16){
                break;
            } else {
                imgw16 <<= 1;
            }
        }
        for(;;){
            if (imgh16 >= texh16){
                break;
            } else {
                imgh16 <<= 1;
            }
        }
        if (imgw16 > imgh16){
            imgh16 = imgw16;
        } else {
            imgw16 = imgh16;
        }
        u16 *texd16 = new u16[imgw16*imgh16];
        memset(texd16,0,imgw16*imgh16*sizeof(u16));
        u16 *texp16 = texd16;
        offset = size - bits.rows;
        for (int y = 0;y < bits.rows;y++){
            u16 *rowp = texp16;
            for (int x = 0;x < bits.width;x++){
                if (pt[y * bits.pitch + (x / 8)] & (0x80 >> (x % 8))){
                    *rowp = 0xffff;
                }
                rowp++;
            }
            texp16 += imgw16;
        }
        c8 name[128];
        sprintf(name,"TTFontGlyph%d_16",idx);
        video::IImage *img = Driver->createImageFromData(video::ECF_A1R5G5B5,core::dimension2d<s32>(imgw16,imgh16),texd16);
        tex16 = Driver->addTexture(name,img);
        Driver->makeColorKeyTexture(tex16,video::SColor(0,0,0,0));
        delete texd16;
    }
}

//! constructor
CGUITTFont::CGUITTFont(video::IVideoDriver* driver)
: Driver(driver)
{
    #ifdef _DEBUG
    setDebugName("CGUITTFont");
    #endif

    if (Driver)
        Driver->grab();
    AntiAlias = false;
    TransParency = false;
}



//! destructor
CGUITTFont::~CGUITTFont()
{
    if (Driver)
        Driver->drop();
}

//! loads a font file
bool CGUITTFace::load(const c8* filename)
{
    if (FT_Init_FreeType( &library )){
        return    false;
    }
    if (FT_New_Face( library,filename,0,&face )){
        return    false;
    }
    return    true;
}

bool CGUITTFont::attach(CGUITTFace *Face,u32 size)
{
    if (!Driver)
        return false;

    tt_face = Face;

    Glyphs.reallocate(tt_face->face->num_glyphs);
    Glyphs.set_used(tt_face->face->num_glyphs);
    for (int i = 0;i < tt_face->face->num_glyphs;i++){
        Glyphs.Driver = Driver;
        Glyphs.size = size;
        Glyphs.face = &(tt_face->face);
        Glyphs.cached = false;
//        Glyphs.cache((wchar_t)i + 1);
    }
    return    true;
}

u32 CGUITTFont::getGlyphByChar(wchar_t c){
    u32 idx = FT_Get_Char_Index( tt_face->face, c );
    if (idx && !Glyphs[idx - 1].cached)    Glyphs[idx - 1].cache(idx);
    return    idx;
}

//! returns the dimension of a text
core::dimension2d<s32> CGUITTFont::getDimension(const wchar_t* text)
{
    core::dimension2d<s32> dim(0, Glyphs[0].size);

    for(const wchar_t* p = text; *p; ++p)
    {
        dim.Width += getWidthFromCharacter(*p);
    }

    return dim;
}


inline s32 CGUITTFont::getWidthFromCharacter(wchar_t c)
{
    u32 n = getGlyphByChar(c);
    if ( n > 0){
        int w = Glyphs[n - 1].texw;
        s32 left = Glyphs[n - 1].left;
        if (w + left > 0) return w + left;
    }
    if (c >= 0x2000){
        return    Glyphs[0].size;
    } else {
        return    Glyphs[0].size / 2;
    }
}


//! draws an text and clips it to the specified rectangle if wanted
void CGUITTFont::draw(const wchar_t* text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
{
    if (!Driver)
        return;

    core::dimension2d<s32> textDimension;
    core::position2d<s32> offset = position.UpperLeftCorner;
    video::SColor colors[4];
    for (int i = 0;i < 4;i++){
        colors = color;
    }

    if (hcenter || vcenter)
    {
        textDimension = getDimension(text);

        if (hcenter)
            offset.X = ((position.getWidth() - textDimension.Width)>>1) + offset.X;

        if (vcenter)
            offset.Y = ((position.getHeight() - textDimension.Height)>>1) + offset.Y;
    }

    u32 n;

    while(*text)
    {
        n = getGlyphByChar(*text);
        if ( n > 0){
            if (AntiAlias){
                s32 imgw = Glyphs[n-1].imgw;
                s32 imgh = Glyphs[n-1].imgh;
                s32 texw = Glyphs[n-1].texw;
                s32 texh = Glyphs[n-1].texh;
                s32 offx = Glyphs[n-1].left;
                s32 offy = Glyphs[n-1].size - Glyphs[n-1].top;
                if (Driver->getDriverType() != video::EDT_SOFTWARE){
                    if (!TransParency)    color.color |= 0xff000000;
                    Driver->draw2DImage(Glyphs[n-1].tex,core::position2d<s32>(offset.X+offx,offset.Y+offy),core::rect<s32>(0,0,imgw-1,imgh-1),clip,color,true);
                } else {
                    s32 a = color.getAlpha();
                    s32 r = color.getRed();
                    s32 g = color.getGreen();
                    s32 b = color.getBlue();
                    u8 *pt = Glyphs[n-1].image;
                    if (!TransParency)    a = 255;
                    for (int y = 0;y < texh;y++){
                        for (int x = 0;x < texw;x++){
                            if (!clip || clip->isPointInside(core::position2d<s32>(offset.X+x+offx,offset.Y+y+offy))){
                                if (*pt){
                                    Driver->draw2DRectangle(video::SColor((a * *pt)/255,r,g,b),core::rect<s32>(offset.X+x+offx,offset.Y+y+offy,offset.X+x+offx+1,offset.Y+y+offy+1));
                                }
                                pt++;
                            }
                        }
                    }
                }
            } else {
                s32 imgw = Glyphs[n-1].imgw16;
                s32 imgh = Glyphs[n-1].imgh16;
                s32 texw = Glyphs[n-1].texw16;
                s32 texh = Glyphs[n-1].texh16;
                s32 offx = Glyphs[n-1].left16;
                s32 offy = Glyphs[n-1].size - Glyphs[n-1].top16;
                if (!TransParency){
                    color.color |= 0xff000000;
                }
                Driver->draw2DImage(Glyphs[n-1].tex16,core::position2d<s32>(offset.X+offx,offset.Y+offy),core::rect<s32>(0,0,imgw-1,imgh-1),clip,color,true);
            }
            offset.X += getWidthFromCharacter(*text);
        } else {
            offset.X += getWidthFromCharacter(*text);
        }

        ++text;
    }
}

//! Calculates the index of the character in the text which is on a specific position.
s32 CGUITTFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x)
{
    s32 x = 0;
    s32 idx = 0;

    while (text[idx])
    {
        x += getWidthFromCharacter(text[idx]);

        if (x >= pixel_x)
            return idx;

        ++idx;
    }

    return -1;
}

#if    0

#endif
} // end namespace gui
} // end namespace irr

-----------------------CGUITTFont.cpp----------------------------
え~え~お!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|幻想森林

GMT+8, 2024-3-29 07:33 , Processed in 0.019721 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表