首页
社区
课程
招聘
[求助]高手帮我看看Irrlicht输出中文的问题
发表于: 2013-7-26 10:16 3591

[求助]高手帮我看看Irrlicht输出中文的问题

2013-7-26 10:16
3591
H文件
#ifndef _GUI_FREETYPE_FONT_H
#define _GUI_FREETYPE_FONT_H

//! freetype support enabled with 1 and disabled with 0
#define COMPILE_WITH_FREETYPE 1

#if COMPILE_WITH_FREETYPE

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

class CGUITTFace : public irr::IReferenceCounted
{
public:
        CGUITTFace();
        virtual ~CGUITTFace();

        bool load(const irr::io::path& filename);

        FT_Face                face;               // handle to face

private:
        static int                        countClassObjects;
        static FT_Library        library;    // handle to library
};

class CGUIFreetypeFont;

class CGUITTGlyph : public irr::IReferenceCounted
{
public:
        CGUITTGlyph();
        virtual ~CGUITTGlyph();

    bool cached;
        void cache(irr::u32 idx_, const CGUIFreetypeFont * freetypeFont);

        irr::u32 size;
        irr::u32 top;
        irr::u32 left;
        irr::u32 texw;
        irr::u32 texh;
        irr::u32 imgw;
        irr::u32 imgh;
        irr::video::ITexture *tex;
        irr::u32 top16;
        irr::u32 left16;
        irr::u32 texw16;
        irr::u32 texh16;
        irr::u32 imgw16;
        irr::u32 imgh16;
        irr::video::ITexture *tex16;
        irr::u8 *image;

private:
        void setGlyphTextureFlags(irr::video::IVideoDriver* driver_);
    void restoreTextureFlags(irr::video::IVideoDriver* driver_);

        static bool mTexFlag16;
        static bool mTexFlag32;
        static bool mTexFlagMip;
};

class CGUIFreetypeFont : public irr::gui::IGUIFont
{
        friend class CGUITTGlyph;

public:

        //! constructor
        CGUIFreetypeFont(irr::video::IVideoDriver* Driver);

        //! destructor
        virtual ~CGUIFreetypeFont();

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

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

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

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

        //! Not yet supported
        virtual void setKerningWidth (irr::s32 kerning) {}

        //! Not yet supported
        virtual void setKerningHeight (irr::s32 kerning) {}

        //! Not yet supported
        virtual irr::s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0)        const { return 0; }

        //! Not yet supported
        virtual irr::s32 getKerningHeight()        const { return 0; }

        //! Not yet supported
    virtual void setInvisibleCharacters( const wchar_t *s ) {}

        bool AntiAlias;
        bool Transparency;

protected:
    void clearGlyphs();

private:
        irr::u32 getWidthFromCharacter(wchar_t c) const;
        irr::u32 getGlyphByChar(wchar_t c) const;
        irr::video::IVideoDriver* Driver;
        irr::core::array< CGUITTGlyph* > Glyphs;
        CGUITTFace * TrueTypeFace;
        mutable irr::core::dimension2d<irr::u32> LargestGlyph;
};

#endif // #if COMPILE_WITH_FREETYPE

#endif        // _GUI_FREETYPE_FONT_H

CPP文件
#include "stdafx.h"
#include "gui_freetype_font.h"

#if COMPILE_WITH_FREETYPE

#include <cassert>

using namespace irr;
using namespace gui;

#ifdef _MSC_VER
#pragma warning(disable: 4996)
#endif

// --------------------------------------------------------
CGUITTGlyph::CGUITTGlyph()
: IReferenceCounted()
    ,cached(false)
    ,size(0)
        ,top(0)
        ,left(0)
        ,texw(0)
        ,texh(0)
        ,imgw(0)
        ,imgh(0)
        ,tex(NULL)
        ,top16(0)
        ,left16(0)
        ,texw16(0)
        ,texh16(0)
        ,imgw16(0)
        ,imgh16(0)
        ,tex16(NULL)
        ,image(NULL)
{
}

CGUITTGlyph::~CGUITTGlyph()
{
        delete[] image;
}

//void CGUITTGlyph::cache(u32 idx_, CGUITTFace& ttFace_, video::IVideoDriver* driver_, irr::core::dimension2d<irr::u32> &largestSize)
void CGUITTGlyph::cache(u32 idx_, const CGUIFreetypeFont * freetypeFont)
{
        assert(freetypeFont);

        FT_Face face = freetypeFont->TrueTypeFace->face;

        FT_Set_Pixel_Sizes(face, 0, size);
        if ( size > freetypeFont->LargestGlyph.Height )
                freetypeFont->LargestGlyph.Height = 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;
                                delete[] image;
                                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;
                                }

                                s32 offx = left;
                                s32 offy = size - top;
                                if ( offx+texw > freetypeFont->LargestGlyph.Width )
                                        freetypeFont->LargestGlyph.Width = offx+texw;
                                if ( offy+texh > freetypeFont->LargestGlyph.Height )
                                        freetypeFont->LargestGlyph.Height = offy+texh;

                                u32 *texd = new u32[imgw*imgh];
                                memset(texd,0,imgw*imgh*sizeof(u32));
                                u32 *texp = texd;
                                bool cflag = (freetypeFont->Driver->getDriverType() == video::EDT_DIRECT3D8);
                                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,"ttf%d_%d_%p",idx_, size, freetypeFont );
                                video::IImage *img = freetypeFont->Driver->createImageFromData(video::ECF_A8R8G8B8,core::dimension2d<u32>(imgw,imgh),texd);
                                setGlyphTextureFlags(freetypeFont->Driver);
                                tex = freetypeFont->Driver->addTexture(name,img);
                                img->drop();
                                restoreTextureFlags(freetypeFont->Driver);
                                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;
                }

                s32 offx = left;
                s32 offy = size - top;
                if ( offx+texw > freetypeFont->LargestGlyph.Width )
                        freetypeFont->LargestGlyph.Width = offx+texw;
                if ( offy+texh > freetypeFont->LargestGlyph.Height )
                        freetypeFont->LargestGlyph.Height = offy+texh;

                u16 *texd16 = new u16[imgw16*imgh16];
                memset(texd16,0,imgw16*imgh16*sizeof(u16));
                u16 *texp16 = texd16;
                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,"ttf%d_%d_%p_16",idx_, size, freetypeFont );
        video::IImage *img = freetypeFont->Driver->createImageFromData(video::ECF_A1R5G5B5,core::dimension2d<u32>(imgw16,imgh16),texd16);
        setGlyphTextureFlags(freetypeFont->Driver);
                tex16 = freetypeFont->Driver->addTexture(name,img);
                img->drop();
        restoreTextureFlags(freetypeFont->Driver);
//                freetypeFont->Driver->makeColorKeyTexture(tex16,video::SColor(0,0,0,0));
                delete[] texd16;
        }
}

bool CGUITTGlyph::mTexFlag16 = false;
bool CGUITTGlyph::mTexFlag32 = true;
bool CGUITTGlyph::mTexFlagMip = false;

void CGUITTGlyph::setGlyphTextureFlags(video::IVideoDriver* driver_)
{
        mTexFlag16 = driver_->getTextureCreationFlag(video::ETCF_ALWAYS_16_BIT);
        mTexFlag32 = driver_->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT);
        mTexFlagMip = driver_->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
    driver_->setTextureCreationFlag(video::ETCF_ALWAYS_16_BIT,false);
    driver_->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT,true);
    driver_->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
}

void CGUITTGlyph::restoreTextureFlags(video::IVideoDriver* driver_)
{
    driver_->setTextureCreationFlag(video::ETCF_ALWAYS_16_BIT, mTexFlag16);
    driver_->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, mTexFlag32);
    driver_->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mTexFlagMip);
}

// --------------------------------------------------------
FT_Library        CGUITTFace::library  = 0;
int CGUITTFace::countClassObjects = 0;

CGUITTFace::CGUITTFace()
: face(0)
{
        ++countClassObjects;
}

CGUITTFace::~CGUITTFace()
{
        if ( face )
                FT_Done_Face( face );

        --countClassObjects;
        assert(countClassObjects >= 0 );
        if ( !countClassObjects && library )
        {
                FT_Done_FreeType( library );
                library = 0;
        }
}

//! loads a font file
bool CGUITTFace::load(const irr::io::path& filename)
{
    if ( !library )
    {
        if (FT_Init_FreeType( &library ))
        {
            return        false;
        }
    }
    core::stringc ansiFilename(filename);   // path can be anything but freetype can only work with ansi-filenames
        if (FT_New_Face( library,ansiFilename.c_str(),0,&face ))
        {
                return        false;
        }
        return        true;
}

// --------------------------------------------------------
//! constructor
CGUIFreetypeFont::CGUIFreetypeFont(video::IVideoDriver* driver)
: Driver(driver)
, TrueTypeFace(0)
{
        #ifdef _DEBUG
        setDebugName("CGUIFreetypeFont");
        #endif

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

//! destructor
CGUIFreetypeFont::~CGUIFreetypeFont()
{
    if ( TrueTypeFace )
        TrueTypeFace->drop();
        if (Driver)
                Driver->drop();
    clearGlyphs();
}

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

        Face->grab();
    if ( TrueTypeFace )
        TrueTypeFace->drop();
        TrueTypeFace = Face;
        if ( !TrueTypeFace )
        return false;

    clearGlyphs();
        Glyphs.reallocate(TrueTypeFace->face->num_glyphs);
        Glyphs.set_used(TrueTypeFace->face->num_glyphs);
        for (int i = 0;i < TrueTypeFace->face->num_glyphs;i++)
        {
        CGUITTGlyph * glyph = new CGUITTGlyph();

                glyph->size = size;
//                glyph->cache((wchar_t)i + 1);

        Glyphs[i] = glyph;
        }

        // TODO: this is a workaround to get a probably ok height for getDimensions. So we check a few extreme characters which usually make trouble.
        getGlyphByChar(L'A');
        getGlyphByChar(L'g');
        getGlyphByChar(L'.');
        getGlyphByChar(L'(');

        return        true;
}

void CGUIFreetypeFont::clearGlyphs()
{
    for ( unsigned int i=0; i < Glyphs.size(); ++i )
    {
            if ( Glyphs[i] )
            {
                        Glyphs[i]->drop();
                }
        Glyphs[i] = 0;
    }
}

u32 CGUIFreetypeFont::getGlyphByChar(wchar_t c) const
{
        u32 idx = FT_Get_Char_Index( TrueTypeFace->face, c );
        if ( idx && !Glyphs[idx - 1]->cached )
        Glyphs[idx - 1]->cache(idx, this);
        return        idx;
}

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

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

        // TODO: The correct solution might be working with TrueTypeFace->height but I can't figure out how to use units_per_EM
        // even if I know which FT_Render_Mode I used. I'm sure there is some way to figure that out, but I have to give up for now.
        if ( TrueTypeFace && LargestGlyph.Height > dim.Height)
                dim.Height = LargestGlyph.Height;

        return dim;
}

inline u32 CGUIFreetypeFont::getWidthFromCharacter(wchar_t c) const
{
        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 CGUIFreetypeFont::draw(const irr::core::stringw& textstring, const irr::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[i] = color;
        }

        const wchar_t * text = textstring.c_str();
    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,texw,texh),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,texw,texh),
                                    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 CGUIFreetypeFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const
{
        s32 x = 0;
        s32 idx = 0;

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

                if (x >= pixel_x)
                        return idx;

                ++idx;
        }

        return -1;
}

#endif // #if COMPILE_WITH_FREETYPE

我的代码里使用attach函数就会现不能读取内存,编译能通过。
CGUITTFace myFace;
        GetWindowsDirectory((LPWSTR)temp,511);
    strcat(temp,"\\fonts\\simsun.ttc"); //宋体
        myFace.load(temp);
    //myFace.load("simhei.ttf");

    CGUIFreetypeFont myFont(driver);
        myFont.attach(&myFace,16);///////////这里。

有没有谁会用这个啊引擎的啊。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//