让irrlicht-1.4beta支持中文

来在研究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, &currentchar, 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, &currentchar, 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[n];
 }
 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("../../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;
  }

 

用来支持中文输入

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值