您的位置:首页 > 其它

让irrlicht-1.4beta支持中文

2009-10-09 11:53 375 查看
近来在研究irrlicht 下了个1.4的发现不支持中文输入输出,在网上找了些发现都是以前版本的发法,用的是FreeType,试了试,发现跟irrlicht 1.4 不是很好接,最后没办法看了一下代码。发现1.4其实是支持中文的,只不过要改一些东西。

irrlicht的字体用的是BMP的,所以首先我想到的就是他的字体导出工具,打开一看有两个,一个老的,一个是新的。用新的试了半天才发现,他的字体图片上都打有点。。而新的工具不能打点。 没办法。。用老的吧。结果老的又不支持中文改吧。

第一步。在StdAfx.h的#include <windows.h>前加入

#define _WIN32_WINNT 0x0500

第二步,将工程属性改为 UNICODE 的

第三。改IrrFontTool.cpp的代码。因为改的挺多,就直接贴上吧。以下是代码

// Copyright (C) 2002-2005 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in Irrlicht.h

// This is the Font tool for the Irrlicht Engine. It only runs and compiles
// with windows.
// I hacked this program within a few minutes, so the code is currently not
// documentated and very C.

#include "stdafx.h"
#include <tchar.h>
#include "resource.h"
#include "stdio.h"
#include "stdlib.h"

struct SCharData
{
wchar_t character;
int width;
int height;

int posX;
int posY;
};

int CALLBACK EnumFamCallBack(CONST LOGFONT *lplf, CONST TEXTMETRIC *lptm, DWORD FontType, LPARAM lpData)
{
SendDlgItemMessage ((HWND)lpData, IDC_LIST1, LB_ADDSTRING, 0, (LONG)lplf->lfFaceName);
return 1;
}

void updateFontPreview(HWND hWnd)
{
int sizeSel = SendDlgItemMessage(hWnd, IDC_LIST2, LB_GETCURSEL, 0, 0);
int sel = SendDlgItemMessage(hWnd, IDC_LIST1, LB_GETCURSEL, 0, 0);
int bold = SendDlgItemMessage(hWnd, IDC_CHECK1, BM_GETCHECK, 0, 0);
int italic = SendDlgItemMessage(hWnd, IDC_CHECK2, BM_GETCHECK, 0, 0);

if (sel != LB_ERR && sizeSel != LB_ERR)
{
TCHAR str[1024];

SendDlgItemMessage(hWnd, IDC_LIST2, LB_GETTEXT, sizeSel, (LPARAM) str);
int fontSize = _wtoi(str);

SendDlgItemMessage(hWnd, IDC_LIST1, LB_GETTEXT, sel, (LPARAM) str);

HDC dc = GetDC(hWnd);

HFONT font = CreateFontW(
-MulDiv(fontSize, GetDeviceCaps(dc, LOGPIXELSY), 72),
0,0,0,
bold ? FW_BOLD : 0,
italic,
0,0,0,0,0,0,0,
str);

ReleaseDC(hWnd, dc);

RECT r;
HWND preview = GetDlgItem(hWnd, IDC_PREVIEW);
GetClientRect(preview, &r);

LOGBRUSH lbrush;
lbrush.lbColor = GetSysColor(COLOR_3DFACE);
lbrush.lbHatch = 0;
lbrush.lbStyle = BS_SOLID;

HBRUSH brush = CreateBrushIndirect(&lbrush);
HPEN pen = CreatePen(PS_NULL, 0, 0);

dc = GetDC(preview);

HGDIOBJ oldfont = SelectObject(dc, font);
HGDIOBJ oldpen = SelectObject(dc, pen);
HGDIOBJ oldbrush = SelectObject(dc, brush);

const TCHAR *text = L"ABCDEF abcdef 12345";

SetBkMode(dc, OPAQUE);
SetBkColor(dc, GetSysColor(COLOR_3DFACE));
Rectangle(dc, 0,0, r.right, r.bottom);

DrawText(dc, text, wcslen(text), &r, DT_VCENTER | DT_CENTER | DT_SINGLELINE);

SelectObject(dc, oldfont);
SelectObject(dc, oldpen);
SelectObject(dc, oldbrush);

ReleaseDC(preview, dc);

DeleteObject(font);
DeleteObject(brush);
DeleteObject(pen);
}
}

void FillFontList(HWND hWnd)
{
// Fill list with font names

SendDlgItemMessage(hWnd, IDC_LIST1, LB_RESETCONTENT, 0, 0);
HDC dc = GetDC(hWnd);
EnumFonts(dc, 0, &EnumFamCallBack, (LPARAM)hWnd);
ReleaseDC(hWnd, dc);

SendDlgItemMessage (hWnd, IDC_LIST1, LB_SETCURSEL, 0, 0);

// Fill list with font sizes

TCHAR buf[128];
int sc[] = {4,6,8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,56,68,72,0};
for (int i=0; sc[i] != 0; ++i)
SendDlgItemMessage (hWnd, IDC_LIST2, LB_ADDSTRING, 0, (LONG)_itow(sc[i], buf, 10));

SendDlgItemMessage (hWnd, IDC_LIST2, LB_SETCURSEL, 4, 0);

// Fill texture size list

int tc[] = {64,128,256,512,1024,2048,0};
for (int t=0; tc[t] != 0; ++t)
{
_stprintf(buf, L"%d pixels width", tc[t]);
SendDlgItemMessage (hWnd, IDC_COMBO1, CB_ADDSTRING, 0, (LONG)buf);
}

SendDlgItemMessage (hWnd, IDC_COMBO1, CB_SETCURSEL, 2, 0);
}

inline int getTextureSizeFromSurfaceSize(int size)
{
int ts = 0x01;
while(ts < size)
ts <<= 1;

return ts;
}

void copyFontToClipBoard(HWND hWnd, int lastChar)
{
int surfaceSel = SendDlgItemMessage(hWnd, IDC_COMBO1, CB_GETCURSEL, 0, 0);
int sizeSel = SendDlgItemMessage(hWnd, IDC_LIST2, LB_GETCURSEL, 0, 0);
int sel = SendDlgItemMessage(hWnd, IDC_LIST1, LB_GETCURSEL, 0, 0);
int bold = SendDlgItemMessage(hWnd, IDC_CHECK1, BM_GETCHECK, 0, 0);
int italic = SendDlgItemMessage(hWnd, IDC_CHECK2, BM_GETCHECK, 0, 0);

if (sel == LB_ERR || sizeSel == LB_ERR || surfaceSel == CB_ERR)
return;

int i;

// We use the font render preview area as dc

HWND preview = GetDlgItem(hWnd, IDC_PREVIEW);
HDC dc = GetDC(NULL);

TCHAR str[1024];

SendDlgItemMessage(hWnd, IDC_LIST2, LB_GETTEXT, sizeSel, (LPARAM) (LPCTSTR)str);
int fontSize = _wtoi(str);

SendDlgItemMessage(hWnd, IDC_COMBO1, CB_GETLBTEXT, surfaceSel, (LPARAM) (LPCTSTR)str);
int surfaceWidth = _wtoi(str);

SendDlgItemMessage(hWnd, IDC_LIST1, LB_GETTEXT, sel, (LPARAM) (LPCTSTR)str);

HFONT font = CreateFontW(
-MulDiv(fontSize, GetDeviceCaps(dc, LOGPIXELSY), 72),
0,0,0,
bold ? FW_BOLD : 0,
italic,
0,0,0,0,0,0,0,
str);

HGDIOBJ oldfont = SelectObject(dc, font);

// calculate text extents.

DWORD dwSize = GetFontUnicodeRanges( dc, 0);
char *buf = new char[dwSize];
LPGLYPHSET glyphs = (LPGLYPHSET)buf;

GetFontUnicodeRanges( dc, glyphs);

SIZE size;
size.cx = 0;
size.cy = 0;
int posx = 0;
int posy = 0;
int k= 0;
for (unsigned int range=0; range < glyphs->cRanges; range++)
{
WCRANGE* current = &glyphs->ranges[range];

//maxy=0;

// loop through each glyph and write its size and position
for (int ch=current->wcLow; ch< current->wcLow + current->cGlyphs; ch++)
{
k++;
}
}

SCharData *asciiTable = new SCharData[k];

i=0;
for (unsigned int range=0; range < glyphs->cRanges; range++)
{
WCRANGE* current = &glyphs->ranges[range];

//maxy=0;

// loop through each glyph and write its size and position
for (int ch=current->wcLow; ch< current->wcLow + current->cGlyphs; ch++)
{
wchar_t currentchar = ch;

GetTextExtentPoint32W(dc, ¤tchar, 1, &size);

++size.cx;

if (posx + size.cx > surfaceWidth)
{
posx = 0;
posy += size.cy+1;
}

asciiTable[i].posX = posx;
asciiTable[i].posY = posy;
asciiTable[i].width = size.cx;
asciiTable[i].height = size.cy;

posx += size.cx;
i++;
}
}

int surfaceHeight = asciiTable[k-1].posY + asciiTable[k-1].height + 1;

surfaceHeight = getTextureSizeFromSurfaceSize(surfaceHeight);

// draw characters

HBITMAP bmp = CreateCompatibleBitmap(dc, surfaceWidth, surfaceHeight);
HDC bmpdc = CreateCompatibleDC(dc);

LOGBRUSH lbrush;
lbrush.lbColor = RGB(0,0,0);
lbrush.lbHatch = 0;
lbrush.lbStyle = BS_SOLID;

HBRUSH brush = CreateBrushIndirect(&lbrush);
HPEN pen = CreatePen(PS_NULL, 0, 0);

HGDIOBJ oldbmp = SelectObject(bmpdc, bmp);
HGDIOBJ oldbmppen = SelectObject(bmpdc, pen);
HGDIOBJ oldbmpbrush = SelectObject(bmpdc, brush);
HGDIOBJ oldbmpfont = SelectObject(bmpdc, font);

SetTextColor(bmpdc, RGB(255,255,255));

Rectangle(bmpdc, 0,0,surfaceWidth,surfaceHeight);
SetBkMode(bmpdc, TRANSPARENT);

SCharData* d;

i = 0;
for (unsigned int range=0; range < glyphs->cRanges; range++)
{
WCRANGE* current = &glyphs->ranges[range];

//maxy=0;

// loop through each glyph and write its size and position
for (int ch=current->wcLow; ch< current->wcLow + current->cGlyphs; ch++)
{
wchar_t currentchar = ch;

d = &asciiTable[i];

TextOutW(bmpdc, d->posX, d->posY, ¤tchar, 1);
SetPixel(bmpdc, d->posX, d->posY, RGB(255,255,0));// left upper corner mark
SetPixel(bmpdc, d->posX+ d->width -1, d->posY + d->height, RGB(255,0,0));// right lower corner mark
i++;
}
}

// draw index pixels
SetPixel(bmpdc, 0,0, RGB(255,255,0)); // left upper corner mark
SetPixel(bmpdc, 1,0, RGB(255,0,0)); // right lower corner mark
SetPixel(bmpdc, 2,0, RGB(0,0,0)); // background color mark

// copy to clipboard

OpenClipboard(hWnd);
EmptyClipboard();
SetClipboardData(CF_BITMAP, bmp);
CloseClipboard();

SelectObject(bmpdc, oldbmp);
SelectObject(bmpdc, oldbmppen);
SelectObject(bmpdc, oldbmpbrush);
SelectObject(bmpdc, oldbmpfont);

SelectObject(dc, oldfont);
ReleaseDC(preview, dc);

DeleteDC(bmpdc);
DeleteObject(font);
DeleteObject(brush);
DeleteObject(pen);
DeleteObject(bmp);
}

BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
{
int wNotifyCode = HIWORD(wParam);
int wID = LOWORD(wParam);
HWND hwndCtl = (HWND)lParam;

switch(wID)
{
case IDOK:
case IDCANCEL:
EndDialog(hwndDlg, wNotifyCode);
PostQuitMessage(0);
return TRUE;
case IDC_CHECK1:
case IDC_CHECK2:
case IDC_LIST1:
case IDC_LIST2:
updateFontPreview(hwndDlg);
return TRUE;
case IDC_BUTTON2:

return TRUE;
case IDC_BUTTON1:
copyFontToClipBoard(hwndDlg, 381);
return TRUE;
}
}
break;
}

return FALSE;
}

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
HWND hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc);

ShowWindow(hWnd , SW_SHOW);

FillFontList(hWnd);

MSG msg;
do
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
while (msg.message != WM_QUIT);

return 0;
}

编译运行之后就可以导出了,不过图片的宽度要选的大一些。否则可能会有问题。

下面进行引擎的改造。

CGUIFont.h

// Copyright (C) 2002-2007 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h

#ifndef __C_GUI_FONT_H_INCLUDED__
#define __C_GUI_FONT_H_INCLUDED__

#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_GUI_

#include "IGUIFontBitmap.h"
#include "irrString.h"
#include "irrMap.h"
#include "IXMLReader.h"
#include "IReadFile.h"
#include "irrArray.h"

namespace irr
{

namespace video
{
class IVideoDriver;
class IImage;
}

namespace gui
{

class IGUIEnvironment;

class CGUIFont : public IGUIFontBitmap
{
public:

//! constructor
CGUIFont(IGUIEnvironment* env, const c8* filename);

//! destructor
virtual ~CGUIFont();

//! loads a font from a texture file
bool load(const c8* filename,wchar_t *sFontName = NULL);

//! loads a font from a texture file
bool load(io::IReadFile* file,wchar_t *sFontName = NULL);

//! loads a font from an XML file
bool load(io::IXMLReader* xml,wchar_t *sFontName = NULL);

//! 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) const;

//! 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) const;

//! Returns the type of this font
virtual EGUI_FONT_TYPE getType() const { return EGFT_BITMAP; }

//! set an Pixel Offset on Drawing ( scale position on width )
virtual void setKerningWidth (s32 kerning);
virtual void setKerningHeight (s32 kerning);

//! set an Pixel Offset on Drawing ( scale position on width )
virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const;
virtual s32 getKerningHeight() const;

//! gets the sprite bank
virtual IGUISpriteBank* getSpriteBank() const;

//! returns the sprite number from a given character
virtual u32 getSpriteNoFromChar(const wchar_t *c) const;

private:

struct SFontArea
{
SFontArea() : underhang(0), overhang(0), width(0), spriteno(0) {}
s32 underhang;
s32 overhang;
s32 width;
u32 spriteno;
};

//! load & prepare font from ITexture
bool loadTexture(video::IImage * image, const c8* name);

void readPositions16bit(video::IImage* texture, s32& lowerRightPositions);
void readPositions32bit(video::IImage* texture, s32& lowerRightPositions);

bool loadFont(wchar_t *sFontName);

wchar_t GetChar(int n);

s32 getAreaFromCharacter (const wchar_t c) const;
void setMaxHeight();

core::array<SFontArea> Areas;
core::map<wchar_t, s32> CharacterMap;
video::IVideoDriver* Driver;
IGUISpriteBank* SpriteBank;
IGUIEnvironment* Environment;
u32 WrongCharacter;
s32 MaxHeight;
s32 GlobalKerningWidth, GlobalKerningHeight;
wchar_t *m_pFontTemp;
};

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

#endif // _IRR_COMPILE_WITH_GUI_

#endif // __C_GUI_FONT_H_INCLUDED__

CGUIFont.cpp

// Copyright (C) 2002-2007 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h

#include "CGUIFont.h"
#ifdef _IRR_COMPILE_WITH_GUI_
#define UNICODE
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <tchar.h>
#include "os.h"
#include "IGUIEnvironment.h"
#include "IXMLReader.h"
#include "IReadFile.h"
#include "IVideoDriver.h"
#include "IGUISpriteBank.h"
#include "CImage.h"

namespace irr
{
namespace gui
{

//! constructor
CGUIFont::CGUIFont(IGUIEnvironment *env, const c8* filename)
: Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0),
MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
{
#ifdef _DEBUG
setDebugName("CGUIFont");
#endif

if (Environment)
{
// don't grab environment, to avoid circular references
Driver = Environment->getVideoDriver();

SpriteBank = Environment->addEmptySpriteBank(filename);
}

m_pFontTemp = NULL;

if (Driver)
Driver->grab();
}

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

if (SpriteBank)
SpriteBank->drop();
if(m_pFontTemp != NULL)
{
delete []m_pFontTemp;
m_pFontTemp = NULL;
}

}

bool CGUIFont::loadFont(wchar_t *sFontName)
{
HDC dc = GetDC(NULL);
HFONT font = CreateFontW(
-MulDiv(10, GetDeviceCaps(dc, LOGPIXELSY), 72),
0,0,0,
0,
false,
0,0,0,0,0,0,0,
sFontName);
HGDIOBJ oldFont = SelectObject(dc, font);
s32 size = GetFontUnicodeRanges( dc, 0);
c8 *buf = new c8[size];
LPGLYPHSET glyphs = (LPGLYPHSET)buf;
GetFontUnicodeRanges( dc, glyphs);

int num = 0;
for (unsigned int range=0; range < glyphs->cRanges; range++)
{
WCRANGE* current = &glyphs->ranges[range];
//maxy=0;
// loop through each glyph and write its size and position
for (int ch=current->wcLow; ch< current->wcLow + current->cGlyphs; ch++)
{
num ++;

}
}

if(m_pFontTemp!=NULL)
{
delete []m_pFontTemp;
m_pFontTemp = NULL;
}

m_pFontTemp = new wchar_t[num];

num = 0;
for (unsigned int range=0; range < glyphs->cRanges; range++)
{
WCRANGE* current = &glyphs->ranges[range];
//maxy=0;
// loop through each glyph and write its size and position
for (int ch=current->wcLow; ch< current->wcLow + current->cGlyphs; ch++)
{
m_pFontTemp[num] = ch;
num ++;

}
}

DeleteObject(oldFont);
DeleteDC(dc);
delete []buf;
return true;
}

//! loads a font file from xml
bool CGUIFont::load(io::IXMLReader* xml,wchar_t *sFontName)
{
if (!SpriteBank)
return false;

if(sFontName!=NULL)
{
loadFont(sFontName);
}

while (xml->read())
{
if (io::EXN_ELEMENT == xml->getNodeType())
{
if (core::stringw(L"Texture") == xml->getNodeName())
{
// add a texture
core::stringc fn = xml->getAttributeValue(L"filename");
u32 i = (u32)xml->getAttributeValueAsInt(L"index");
core::stringw alpha = xml->getAttributeValue(L"hasAlpha");

while (i+1 > SpriteBank->getTextureCount())
SpriteBank->addTexture(0);

// disable mipmaps+filtering
bool mipmap = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);

// load texture
SpriteBank->setTexture(i, Driver->getTexture(fn.c_str()));

// set previous mip-map+filter state
Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap);

// couldn't load texture, abort.
if (!SpriteBank->getTexture(i))
{
os::Printer::log("Unable to load all textures in the font, aborting", ELL_ERROR);
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return false;
}
else
{
// colorkey texture rather than alpha channel?
if (alpha == core::stringw("false"))
Driver->makeColorKeyTexture(SpriteBank->getTexture(i), core::position2di(0,0));
}
}
else if (core::stringw(L"c") == xml->getNodeName())
{
// adding a character to this font
SFontArea a;
SGUISpriteFrame f;
SGUISprite s;
core::rect<s32> rectangle;

a.underhang = xml->getAttributeValueAsInt(L"u");
a.overhang = xml->getAttributeValueAsInt(L"o");
a.spriteno = SpriteBank->getSprites().size();
s32 texno = xml->getAttributeValueAsInt(L"i");

// parse rectangle
core::stringc rectstr = xml->getAttributeValue(L"r");
wchar_t ch = xml->getAttributeValue(L"c")[0];

const c8 *c = rectstr.c_str();
s32 val;
val = 0;
while (*c >= '0' && *c <= '9')
{
val *= 10;
val += *c - '0';
c++;
}
rectangle.UpperLeftCorner.X = val;
while (*c == L' ' || *c == L',') c++;

val = 0;
while (*c >= '0' && *c <= '9')
{
val *= 10;
val += *c - '0';
c++;
}
rectangle.UpperLeftCorner.Y = val;
while (*c == L' ' || *c == L',') c++;

val = 0;
while (*c >= '0' && *c <= '9')
{
val *= 10;
val += *c - '0';
c++;
}
rectangle.LowerRightCorner.X = val;
while (*c == L' ' || *c == L',') c++;

val = 0;
while (*c >= '0' && *c <= '9')
{
val *= 10;
val += *c - '0';
c++;
}
rectangle.LowerRightCorner.Y = val;

CharacterMap.insert(ch,Areas.size());

// make frame
f.rectNumber = SpriteBank->getPositions().size();
f.textureNumber = texno;

// add frame to sprite
s.Frames.push_back(f);
s.frameTime = 0;

// add rectangle to sprite bank
SpriteBank->getPositions().push_back(rectangle);
a.width = rectangle.getWidth();

// add sprite to sprite bank
SpriteBank->getSprites().push_back(s);

// add character to font
Areas.push_back(a);
}
}
}

// set bad character
WrongCharacter = getAreaFromCharacter(L' ');

setMaxHeight();

return true;
}

void CGUIFont::setMaxHeight()
{
MaxHeight = 0;
s32 t;

core::array< core::rect<s32> >& p = SpriteBank->getPositions();

for (u32 i=0; i<p.size(); ++i)
{
t = p[i].getHeight();
if (t>MaxHeight)
MaxHeight = t;
}

}

//! loads a font file, native file needed, for texture parsing
bool CGUIFont::load(io::IReadFile* file,wchar_t *sFontName)
{
if (!Driver)
return false;

if(sFontName!=NULL)
{
loadFont(sFontName);
}

return loadTexture(Driver->createImageFromFile(file),
file->getFileName());
}

//! loads a font file, native file needed, for texture parsing
bool CGUIFont::load(const c8* filename,wchar_t *sFontName)
{
if (!Driver)
return false;
if(sFontName!=NULL)
{
loadFont(sFontName);
}
return loadTexture(Driver->createImageFromFile( filename ),
filename);
}

//! load & prepare font from ITexture
bool CGUIFont::loadTexture(video::IImage* image, const c8* name)
{
if (!image)
return false;

s32 lowerRightPositions = 0;

video::IImage* tmpImage=image;
bool deleteTmpImage=false;
switch(image->getColorFormat())
{
case video::ECF_R5G6B5:
tmpImage = new video::CImage(video::ECF_A1R5G5B5,image);
deleteTmpImage=true;
case video::ECF_A1R5G5B5:
readPositions16bit(tmpImage, lowerRightPositions);
break;
case video::ECF_R8G8B8:
tmpImage = new video::CImage(video::ECF_A8R8G8B8,image);
deleteTmpImage=true;
case video::ECF_A8R8G8B8:
readPositions32bit (tmpImage, lowerRightPositions);
break;
}

WrongCharacter = getAreaFromCharacter(L' ');

// output warnings
if (!lowerRightPositions || !SpriteBank->getSprites().size())
os::Printer::log("The amount of upper corner pixels or lower corner pixels is == 0, font file may be corrupted.", ELL_ERROR);
else
if (lowerRightPositions != (s32)SpriteBank->getPositions().size())
os::Printer::log("The amount of upper corner pixels and the lower corner pixels is not equal, font file may be corrupted.", ELL_ERROR);

bool ret = ( !SpriteBank->getSprites().empty() && lowerRightPositions );

if ( ret )
{
SpriteBank->addTexture(Driver->addTexture(name, tmpImage));
}
if (deleteTmpImage)
tmpImage->drop();
image->drop();

setMaxHeight();

return ret;
}

wchar_t CGUIFont::GetChar(int n)
{
if(m_pFontTemp!= NULL)
{
return m_pFontTemp
;
}
return 0;
}

void CGUIFont::readPositions32bit(video::IImage* image, s32& lowerRightPositions)
{
const core::dimension2d<s32>& size = image->getDimension();

s32* p = (s32*)image->lock();
if (!p)
{
os::Printer::log("Could not lock texture while preparing texture for a font.", ELL_ERROR);
return;
}

// fix half alpha of top left pixel in some font textures
p[0] |= 0xFF000000;

s32 colorTopLeft = p[0];
s32 colorLowerRight = *(p+1);
s32 colorBackGround = *(p+2);
s32 colorBackGroundTransparent = 0; // 0x00FFFFFF & colorBackGround;

*(p+1) = colorBackGround;

// start parsing

core::position2d<s32> pos(0,0);
for (pos.Y=0; pos.Y<size.Height; ++pos.Y)
{
for (pos.X=0; pos.X<size.Width; ++pos.X)
{
if ( *p == colorTopLeft)
{
*p = colorBackGroundTransparent;
SpriteBank->getPositions().push_back(core::rect<s32>(pos, pos));
}
else
if (*p == colorLowerRight)
{
if (SpriteBank->getPositions().size()<=(u32)lowerRightPositions)
{
image->unlock();
lowerRightPositions = 0;
return;
}

*p = colorBackGroundTransparent;
SpriteBank->getPositions()[lowerRightPositions].LowerRightCorner = pos;
// add frame to sprite bank
SGUISpriteFrame f;
f.rectNumber = lowerRightPositions;
f.textureNumber = 0;
SGUISprite s;
s.Frames.push_back(f);
s.frameTime = 0;
SpriteBank->getSprites().push_back(s);
// add character to font
SFontArea a;
a.overhang = 0;
a.underhang = 0;
a.spriteno = lowerRightPositions;
a.width = SpriteBank->getPositions()[lowerRightPositions].getWidth();
Areas.push_back(a);
// map letter to character

wchar_t ch ;

if(m_pFontTemp != NULL)
ch = GetChar(lowerRightPositions);
else
ch = (wchar_t)(lowerRightPositions + 32);
CharacterMap.set(ch, lowerRightPositions);

++lowerRightPositions;
}
else
if (*p == colorBackGround)
{
*p = colorBackGroundTransparent;
}
++p;
}
}

// Positions parsed.

image->unlock();
}

void CGUIFont::readPositions16bit(video::IImage* image, s32& lowerRightPositions)
{
core::dimension2d<s32> size = image->getDimension();

s16* p = (s16*)image->lock();
if (!p)
{
os::Printer::log("Could not lock texture while preparing texture for a font.", ELL_ERROR);
return;
}

// fix half alpha of top left pixel in some font textures
p[0] |= 0x8000;

s16 colorTopLeft = p[0];
s16 colorLowerRight = *(p+1);
s16 colorBackGround = *(p+2);
s16 colorBackGroundTransparent = 0; // 0x7FFF & colorBackGround;

*(p+1) = colorBackGround;

// start parsing

core::position2d<s32> pos(0,0);
for (pos.Y=0; pos.Y<size.Height; ++pos.Y)
{
for (pos.X=0; pos.X<size.Width; ++pos.X)
{
if (*p == colorTopLeft)
{
*p = colorBackGroundTransparent;
SpriteBank->getPositions().push_back(core::rect<s32>(pos, pos));
}
else
if (*p == colorLowerRight)
{
// too many lower right points
if (SpriteBank->getPositions().size()<=(u32)lowerRightPositions)
{
image->unlock();
lowerRightPositions = 0;
return;
}

*p = colorBackGroundTransparent;
SpriteBank->getPositions()[lowerRightPositions].LowerRightCorner = pos;
// add frame to sprite bank
SGUISpriteFrame f;
f.rectNumber = lowerRightPositions;
f.textureNumber = 0;
SGUISprite s;
s.Frames.push_back(f);
s.frameTime = 0;
SpriteBank->getSprites().push_back(s);
// add character to font
SFontArea a;
a.overhang = 0;
a.underhang = 0;
a.spriteno = lowerRightPositions;
a.width = SpriteBank->getPositions()[lowerRightPositions].getWidth();
Areas.push_back(a);
// map letter to character
//wchar_t ch = (wchar_t)(lowerRightPositions + 32);
wchar_t ch ;
if(m_pFontTemp != NULL)
ch = GetChar(lowerRightPositions);
else
ch = (wchar_t)(lowerRightPositions + 32);
CharacterMap.set(ch, lowerRightPositions);

++lowerRightPositions;
}
else
if (*p == colorBackGround)
*p = colorBackGroundTransparent;
++p;
}
}

// Positions parsed.

image->unlock();
}

//! returns the dimension of text
core::dimension2d<s32> CGUIFont::getDimension(const wchar_t* text) const
{
core::dimension2d<s32> dim(0, 0);
core::dimension2d<s32> thisLine(0, MaxHeight);

for (const wchar_t* p = text; *p; ++p)
{
bool lineBreak=false;
if (*p == L'\r') // Mac or Windows breaks
{
lineBreak = true;
if (p[1] == L'\n') // Windows breaks
++p;
}
else if (*p == L'\n') // Unix breaks
{
lineBreak = true;
}
if (lineBreak)
{
dim.Height += thisLine.Height;
if (dim.Width < thisLine.Width)
dim.Width = thisLine.Width;
thisLine.Width = 0;
continue;
}

const SFontArea &area = Areas[getAreaFromCharacter(*p)];

thisLine.Width += area.underhang;
thisLine.Width += area.width + area.overhang + GlobalKerningWidth;
}

dim.Height += thisLine.Height;
if (dim.Width < thisLine.Width)
dim.Width = thisLine.Width;

return dim;
}

//! set an Pixel Offset on Drawing ( scale position on width )
void CGUIFont::setKerningWidth ( s32 kerning )
{
GlobalKerningWidth = kerning;
}

//! set an Pixel Offset on Drawing ( scale position on width )
s32 CGUIFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* previousLetter) const
{
s32 ret = GlobalKerningWidth;

if (thisLetter)
{
ret += Areas[getAreaFromCharacter(*thisLetter)].overhang;

if (previousLetter)
{
ret += Areas[getAreaFromCharacter(*previousLetter)].underhang;
}
}

return ret;
}

//! set an Pixel Offset on Drawing ( scale position on height )
void CGUIFont::setKerningHeight ( s32 kerning )
{
GlobalKerningHeight = kerning;
}

//! set an Pixel Offset on Drawing ( scale position on height )
s32 CGUIFont::getKerningHeight () const
{
return GlobalKerningHeight;
}

//! returns the sprite number from a given character
u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const
{
return Areas[getAreaFromCharacter(*c)].spriteno;
}

s32 CGUIFont::getAreaFromCharacter(const wchar_t c) const
{
core::map<wchar_t, s32>::Node* n = CharacterMap.find(c);
if (n)
return n->getValue();
else
return WrongCharacter;
}

/*
//! draws an text and clips it to the specified rectangle if wanted
void CGUIFont::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;

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;
}

core::array<s32> indices;
indices.reallocate(core::stringw(text).size());
u32 n;
while(*text)
{
n = (*text) - 32;
if ( n > Positions.size())
n = WrongCharacter;
indices.push_back(n);
++text;
}
Driver->draw2DImage(Texture, offset, Positions, indices, GlobalKerningWidth, clip, color, true);
}
*/

//! draws some text and clips it to the specified rectangle if wanted
void CGUIFont::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;
core::rect<s32> pos;

if (hcenter || vcenter || clip)
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;

if (clip)
{
core::rect<s32> clippedRect(offset, textDimension);
clippedRect.clipAgainst(*clip);
if (!clippedRect.isValid())
return;
}

while(*text)
{
SFontArea& area = Areas[getAreaFromCharacter(*text)];

offset.X += area.underhang;

SpriteBank->draw2DSprite(area.spriteno, offset, clip, color);

offset.X += area.width + area.overhang + GlobalKerningWidth;

++text;
}
}

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

while (text[idx])
{
const SFontArea& a = Areas[getAreaFromCharacter(text[idx])];

x += a.width + a.overhang + a.underhang;

if (x >= pixel_x)
return idx;

++idx;
}

return -1;
}

IGUISpriteBank* CGUIFont::getSpriteBank() const
{
return SpriteBank;
}

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

#endif // _IRR_COMPILE_WITH_GUI_

将 IGUIEnvironment.h

virtual IGUIFont* getFont(const c8* filename) = 0;

改为 virtual IGUIFont* getFont(const c8* filename,wchar_t *sFontName=NULL) = 0;

同样将 CGUIEnvironment.h

virtual IGUIFont* getFont(const c8* filename) = 0;

改为 virtual IGUIFont* getFont(const c8* filename,wchar_t *sFontName=NULL) = 0;

将CGUIEnvironment.cpp的getFont改为如下

//! returns the font
IGUIFont* CGUIEnvironment::getFont(const c8* filename,wchar_t *sFontName)
{
// search existing font

SFont f;
IGUIFont* ifont=0;
if (!filename)
f.Filename = "";
else
f.Filename = filename;

f.Filename.make_lower();

s32 index = Fonts.binary_search(f);
if (index != -1)
return Fonts[index].Font;

// font doesn't exist, attempt to load it

// does the file exist?

if (!FileSystem->existFile(filename))
{
os::Printer::log("Could not load font because the file does not exist", f.Filename.c_str(), ELL_ERROR);
return 0;
}

io::IXMLReader *xml = FileSystem->createXMLReader(filename);
if (xml)
{
// this is an XML font, but we need to know what type
EGUI_FONT_TYPE t = EGFT_CUSTOM;

bool found=false;
while(xml->read() && !found)
{
if (xml->getNodeType() == io::EXN_ELEMENT)
{
if (core::stringw(L"font") == xml->getNodeName())
{
if (core::stringw(L"vector") == xml->getAttributeValue(L"type"))
{
t = EGFT_VECTOR;
found=true;
}
else if (core::stringw(L"bitmap") == xml->getAttributeValue(L"type"))
{
t = EGFT_BITMAP;
found=true;
}
else found=true;
}
}
}

if (t==EGFT_BITMAP)
{
CGUIFont* font = new CGUIFont(this, filename);
ifont = (IGUIFont*)font;
// change working directory, for loading textures
core::stringc workingDir = FileSystem->getWorkingDirectory();
FileSystem->changeWorkingDirectoryTo(FileSystem->getFileDir(f.Filename).c_str());

// load the font
if (!font->load(xml,sFontName))
{
font->drop();
font = 0;
ifont = 0;
}
// change working dir back again
FileSystem->changeWorkingDirectoryTo( workingDir.c_str());
}
else if (t==EGFT_VECTOR)
{
// todo: vector fonts
os::Printer::log("Unable to load font, XML vector fonts are not supported yet", f.Filename.c_str(), ELL_ERROR);

//CGUIFontVector* font = new CGUIFontVector(Driver);
//ifont = (IGUIFont*)font;
//if (!font->load(xml))
}
xml->drop();
}

if (!ifont)
{

CGUIFont* font = new CGUIFont(this, f.Filename.c_str());
ifont = (IGUIFont*)font;
if (!font->load(f.Filename.c_str(),sFontName))
{
font->drop();
return 0;
}
}

// add to fonts.

f.Font = ifont;
Fonts.push_back(f);

return ifont;
}

好了,我们可以使用了 ,在主函数里加入

IGUISkin* skin = env->getSkin();
IGUIFont* font = env->getFont("http://www.cnblogs.com/media/myfont0.bmp",L"宋体");//图片是刚才生成的图片,字体也是刚才字体工具上选中的字体
if (font)
skin->setFont(font);

skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP);

最后CIrrDeviceWin32.cpp 里的WndProc里加入

case WM_IME_CHAR:
{
event.EventType = irr::EET_KEY_INPUT_EVENT;
event.KeyInput.PressedDown = true;
event.KeyInput.Key = irr::KEY_OEM_CLEAR ;
event.KeyInput.Shift = 0;
event.KeyInput.Control = 0;

char p1[2];
p1[0]=(char)((wParam&0xff00)>>8);
p1[1]=(char)(wParam&0xff);

if(p1[0]==0)
{
event.KeyInput.Char=(wchar_t)wParam;
}
else
//多字节代码转unicode
MultiByteToWideChar(CP_OEMCP,MB_PRECOMPOSED,p1,2,&(event.KeyInput.Char),1);

dev = getDeviceFromHWnd(hWnd);

if (dev)
dev->postEventFromUser(event);

break;
}

用来支持中文输入
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: