Font.h
#ifndef __Font_H__
#define __Font_H__
#include <vector>
#include <D3D9.h>
typedef unsigned char uint8;
template<typename T> struct TRect
{
T left, top, right, bottom;
TRect() {}
TRect(T const & l, T const & t, T const & r, T const & b)
: left(l), top(t), right(r), bottom(b)
{
}
TRect(TRect const & o)
: left(o.left), top(o.top), right(o.right), bottom(o.bottom)
{
}
TRect & operator=(TRect const & o)
{
left = o.left;
top = o.top;
right = o.right;
bottom = o.bottom;
return *this;
}
T width() const
{
return right - left;
}
T height() const
{
return bottom - top;
}
};
typedef unsigned int uint32;
typedef TRect<float> FloatRect;
class Font
{
public:
Font(IDirect3DDevice9* device);
typedef uint32 CodePoint;
typedef FloatRect UVRect;
typedef std::pair<CodePoint, CodePoint> PairCodePoint;
typedef std::vector<PairCodePoint> VectorPairCodePoint;
struct GlyphInfo
{
CodePoint codePoint;//codePoint码
UVRect uvRect;//纹理区域
float aspectRatio;
GlyphInfo():codePoint(0),uvRect(UVRect(0, 0, 0, 0)),aspectRatio(1)
{
}
GlyphInfo(CodePoint _code, const UVRect& _rect, float _aspect) : codePoint(_code), uvRect(_rect), aspectRatio(_aspect)
{
}
};
typedef std::vector<GlyphInfo> VectorGlyphInfo;
struct RangeInfo
{
CodePoint first;
CodePoint second;
VectorGlyphInfo range;
RangeInfo(CodePoint _first, CodePoint _second) : first(_first), second(_second) { }
};
enum constCodePoints
{
FONT_CODE_SELECT = 0,
FONT_CODE_TAB = 0x0009,
FONT_CODE_LF = 0x000A,
FONT_CODE_CR = 0x000D,
FONT_CODE_SPACE = 0x0020,
FONT_CODE_LATIN_START = 0x0021,
FONT_CODE_NEL = 0x0085,
FONT_CODE_LATIN_END = 0x00A6,
};
typedef std::vector<RangeInfo> VectorRangeInfo;
bool loadFont();
inline bool checkHidePointCode(CodePoint _id)
{
for (VectorPairCodePoint::iterator iter=mVectorHideCodePoint.begin(); iter!=mVectorHideCodePoint.end(); ++iter) {
if ((_id >= iter->first) && (_id <= iter->second)) return true;
}
return false;
}
public:
VectorPairCodePoint mVectorHideCodePoint;
//字体范围
VectorRangeInfo mVectorRangeInfo;
uint8 mCountSpaceTab;
uint8 mCharSpacer;
GlyphInfo mSpaceGlyphInfo, mTabGlyphInfo, mSelectGlyphInfo, mSelectDeactiveGlyphInfo, mCursorGlyphInfo;
IDirect3DDevice9* p;
};
#endif
Font.cpp
#include "Font.h"
#include <d3dx9tex.h>
#include <windows.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
const unsigned char FONT_MASK_SELECT = 0x88;
const unsigned char FONT_MASK_SELECT_DEACTIVE = 0x60;
const unsigned char FONT_MASK_SPACE = 0x00;
const unsigned char FONT_MASK_CHAR = 0xFF;
const size_t FONT_TEXTURE_WIDTH = 1024;
typedef unsigned char uchar;
Font::Font(IDirect3DDevice9* device)
{
p = device;
mCharSpacer = 5;
mCountSpaceTab = 4;
}
bool Font::loadFont()
{
if (mVectorRangeInfo.empty())
mVectorRangeInfo.push_back(RangeInfo(FONT_CODE_LATIN_START, FONT_CODE_LATIN_END));
FT_Library ftLibrary;//定义FT库
//第一步:初始化库
if(FT_Init_FreeType(&ftLibrary))
MessageBox(NULL,"FreeType初始化库时发生了一个错误!", NULL, NULL);
//第二步:装载一个字体face (可以从一个字体文件装载, 也可以内存装载)
//字体文件装载:
FT_Face face;
if(FT_New_Face(ftLibrary, "msyh.ttf", 0, &face))
MessageBox(NULL,"Could not open font face!",NULL,NULL);
//内存装载:
//FT_New_Memory_Face( library,
//buffer, /* 缓存的第一个字节 */
//size, /* 缓存的大小(以字节表示) */
//0, /* face索引 */
//&face ); 内存装载
//第三步:设置当前象素尺寸
//当一个新的face对象建立时,对于可伸缩字体格式,size对象默认值为字符大小水平和垂直均为10象素。
//对于定长字体格式,这个大小是未定义的,这就是你必须在装载一个字形前设置该值的原因。
//设置FreeType2字体大小
//FT_Set_Char_Size(
// face, /* face对象的句柄 */
// 0, /* 以1/64点为单位的字符宽度 */
// 16*64, /* 以1/64点为单位的字符高度 */
// 300, /* 设备水平分辨率 */
// 300 ); /* 设备垂直分辨率 */
FT_F26Dot6 ftSize = (FT_F26Dot6)(24 * (1 << 6));
if(FT_Set_Char_Size( face, ftSize, 0, 72, 72))
MessageBox(NULL,"Could not set char size!",NULL,NULL);
int max_height = 0, max_width = 0, max_bear = 0;
//读取字体
FT_Error ftResult = FT_Load_Char( face, 97, FT_LOAD_RENDER );
if(ftResult)
MessageBox(NULL ,"cannot load character 97", NULL, NULL);
FT_Int advance = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
//位图指针
unsigned char* buffer = face->glyph->bitmap.buffer;
if(NULL == buffer)
MessageBox(NULL,"位图指针error", NULL, NULL);
//计算 最大宽, 高
size_t glyphCount = 4;
size_t l = glyphCount * (advance + 5), m = 0;
//在这里计算字体纹理需要的大小
for (VectorRangeInfo::iterator iter=mVectorRangeInfo.begin(); iter!=mVectorRangeInfo.end(); ++iter) {
for (CodePoint index=iter->first; index<=iter->second; ++index, ++glyphCount) {
if (checkHidePointCode(index)) continue;
//读取字体(单个)
if (FT_Load_Char( face, index, FT_LOAD_RENDER )) continue;
//这里判断是否有这个CodePoint码
if (NULL == face->glyph->bitmap.buffer) continue;
//应该是字宽
FT_Int advance = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
if ( ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY ) > max_height )
max_height = ( 2 * ( face->glyph->bitmap.rows << 6 ) - face->glyph->metrics.horiBearingY );
if ( face->glyph->metrics.horiBearingY > max_bear )
max_bear = face->glyph->metrics.horiBearingY;
if ( (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 ) > max_width)
max_width = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
l += (advance + 5);
if ( (FONT_TEXTURE_WIDTH - 1) < (l + advance) ) { m ++; l = 0;}
}
}
max_height >>= 6;
max_bear >>= 6;
size_t finalWidth = FONT_TEXTURE_WIDTH;//字体纹理的宽度
size_t finalHeight = (m+1) * (max_height + 5);//字体纹理的高度
//字节对齐
size_t needHeight = 1;
while (needHeight < finalHeight) needHeight <<= 1;
finalHeight = needHeight;
//字体文理宽高比例
float textureAspect = (float)finalWidth / (float)finalHeight;
//图象格式A8L8
const size_t pixel_bytes = 2;
size_t data_width = finalWidth * pixel_bytes;
size_t data_size = finalWidth * finalHeight * pixel_bytes;//字体纹理需要的字节数
//字体位图指针
uchar* imageData = new uchar[data_size];
//8位表示亮度8位表示alpha值
for (size_t i = 0; i < data_size; i += pixel_bytes) {
imageData[i + 0] = 0x00; //亮度
imageData[i + 1] = 0x00; //alpha值
}
l = 0;
m = 0;
ftResult = FT_Load_Char( face, 97, FT_LOAD_RENDER );
if (ftResult)
MessageBox(NULL, "cannot load character ", NULL, NULL);
advance = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
buffer = face->glyph->bitmap.buffer;
//得到y的空隙
int y_bearnig = max_bear - ( face->glyph->metrics.horiBearingY >> 6 );
///////////////////////////////////////////////////////////////////////////////////////
//设置空格符纹理
for (int j = 0; j < face->glyph->bitmap.rows; j++ ) {
int row = j + (int)m + y_bearnig;
uchar* pDest = &imageData[(row * data_width) + l * pixel_bytes];//找起点
for (int k = 0; k < face->glyph->bitmap.width; k++ ) {
*pDest++= FONT_MASK_CHAR;
*pDest++= FONT_MASK_SPACE;
buffer++;
}
}
//设置空格符纹理坐标
mSpaceGlyphInfo.codePoint = FONT_CODE_SPACE;
mSpaceGlyphInfo.uvRect.left = (float)l / (float)finalWidth; // u1
mSpaceGlyphInfo.uvRect.top = (float)m / (float)finalHeight; // v1
mSpaceGlyphInfo.uvRect.right = (float)( l + ( face->glyph->advance.x >> 6 ) ) / (float)finalWidth; // u2
mSpaceGlyphInfo.uvRect.bottom = ( m + max_height ) / (float)finalHeight; // v2
mSpaceGlyphInfo.aspectRatio = textureAspect * (mSpaceGlyphInfo.uvRect.right - mSpaceGlyphInfo.uvRect.left) / (mSpaceGlyphInfo.uvRect.bottom - mSpaceGlyphInfo.uvRect.top);
///////////////////////////////////////////////////////////////////////////////////////
mTabGlyphInfo = mSpaceGlyphInfo;
mTabGlyphInfo.aspectRatio = textureAspect * (float)mCountSpaceTab;
l += (advance + mCharSpacer);
if ( (FONT_TEXTURE_WIDTH - 1) < (l + advance) ) { m += max_height + mCharSpacer;l = 0;}
///////////////////////////////////////////////////////////////////////////////////////
for (int j = 0; j < face->glyph->bitmap.rows; j++ ) {
int row = j + (int)m + y_bearnig;
uchar* pDest = &imageData[(row * data_width) + l * pixel_bytes];
for(int k = 0; k < face->glyph->bitmap.width; k++ ) {
*pDest++= FONT_MASK_CHAR;
*pDest++= FONT_MASK_SELECT;
buffer++;
}
}
mSelectGlyphInfo.codePoint = FONT_CODE_SELECT;
mSelectGlyphInfo.uvRect.left = (float)l / (float)finalWidth; // u1
mSelectGlyphInfo.uvRect.top = (float)m / (float)finalHeight; // v1
mSelectGlyphInfo.uvRect.right = (float)( l + ( face->glyph->advance.x >> 6 ) ) / (float)finalWidth; // u2
mSelectGlyphInfo.uvRect.bottom = ( m + max_height ) / (float)finalHeight; // v2
mSelectGlyphInfo.aspectRatio = textureAspect * (mSelectGlyphInfo.uvRect.right - mSelectGlyphInfo.uvRect.left) / (mSelectGlyphInfo.uvRect.bottom - mSelectGlyphInfo.uvRect.top);
//l+= 本字宽+字空
l += (advance + mCharSpacer);
//如果到头容不下一个字
if ( (FONT_TEXTURE_WIDTH - 1) < (l + advance) ) { m += max_height + mCharSpacer;l = 0;}
///////////////////////////////////////////////////////////////////////////////////////
for (int j = 0; j < face->glyph->bitmap.rows; j++ ) {
int row = j + (int)m + y_bearnig;
uchar* pDest = &imageData[(row * data_width) + l * pixel_bytes];
for(int k = 0; k < face->glyph->bitmap.width; k++ ) {
*pDest++= FONT_MASK_CHAR;
*pDest++= FONT_MASK_SELECT_DEACTIVE;
buffer++;
}
}
mSelectDeactiveGlyphInfo.codePoint = FONT_CODE_SELECT;
mSelectDeactiveGlyphInfo.uvRect.left = (float)l / (float)finalWidth; // u1
mSelectDeactiveGlyphInfo.uvRect.top = (float)m / (float)finalHeight; // v1
mSelectDeactiveGlyphInfo.uvRect.right = (float)( l + ( face->glyph->advance.x >> 6 ) ) / (float)finalWidth; // u2
mSelectDeactiveGlyphInfo.uvRect.bottom = ( m + max_height ) / (float)finalHeight; // v2
mSelectDeactiveGlyphInfo.aspectRatio = textureAspect * (mSelectDeactiveGlyphInfo.uvRect.right - mSelectDeactiveGlyphInfo.uvRect.left) / (mSelectDeactiveGlyphInfo.uvRect.bottom - mSelectDeactiveGlyphInfo.uvRect.top);
l += (advance + mCharSpacer);
if ( (FONT_TEXTURE_WIDTH - 1) < (l + advance) ) { m += max_height + mCharSpacer;l = 0;}
///////////////////////////////////////////////////////////////////////////////////////
for (int j = 0; j < face->glyph->bitmap.rows; j++ ) {
int row = j + (int)m + y_bearnig;
uchar* pDest = &imageData[(row * data_width) + l * pixel_bytes];
for(int k = 0; k < face->glyph->bitmap.width; k++ ) {
*pDest++= FONT_MASK_CHAR;
*pDest++= FONT_MASK_CHAR;
buffer++;
}
}
mCursorGlyphInfo.codePoint = FONT_CODE_SELECT;
mCursorGlyphInfo.uvRect.left = (float)l / (float)finalWidth; // u1
mCursorGlyphInfo.uvRect.top = (float)m / (float)finalHeight; // v1
mCursorGlyphInfo.uvRect.right = (float)( l + ( face->glyph->advance.x >> 6 ) ) / (float)finalWidth; // u2
mCursorGlyphInfo.uvRect.bottom = ( m + max_height ) / (float)finalHeight; // v2
mCursorGlyphInfo.aspectRatio = textureAspect * (mCursorGlyphInfo.uvRect.right - mCursorGlyphInfo.uvRect.left) / (mCursorGlyphInfo.uvRect.bottom - mCursorGlyphInfo.uvRect.top);
l += (advance + mCharSpacer);
if ( (FONT_TEXTURE_WIDTH - 1) < (l + advance) ) { m += max_height + mCharSpacer;l = 0;}
///////////////////////////////////////////////////////////////////////////////////////
for (VectorRangeInfo::iterator iter=mVectorRangeInfo.begin(); iter!=mVectorRangeInfo.end(); ++iter)
{
iter->range.resize(iter->second - iter->first + 1);
size_t pos = 0;
for (CodePoint index=iter->first; index<=iter->second; ++index, ++pos) {
if (checkHidePointCode(index)) continue;
GlyphInfo & info = iter->range.at(pos);
ftResult = FT_Load_Char( face, index, FT_LOAD_RENDER );
if (ftResult) {
MessageBox(NULL, "cannot load character ", NULL, NULL);
continue;
}
FT_Int advance = (face->glyph->advance.x >> 6 ) + ( face->glyph->metrics.horiBearingX >> 6 );
//位图指针
unsigned char* buffer = face->glyph->bitmap.buffer;
if (NULL == buffer) {
MessageBox(NULL, "Freetype returned null for character ", NULL, NULL);
continue;
}
int y_bearnig = max_bear - ( face->glyph->metrics.horiBearingY >> 6 );
for(int j = 0; j < face->glyph->bitmap.rows; j++ ) {//TTF字体纹理高度
int row = j + (int)m + y_bearnig;
uchar* pDest = &imageData[(row * data_width) + l * pixel_bytes];
for(int k = 0; k < face->glyph->bitmap.width; k++ )
{
if(true)//WBW TEST
{
*pDest++= *buffer;
}
else
{
*pDest++= FONT_MASK_CHAR;
}
*pDest++= *buffer;//D3DFMT_A8L8
buffer++;
}
}
//CodePoint码(字符对应的纹理坐标)a,b,c,d,e. . .一,二,三. . .
info.codePoint = index;
info.uvRect.left = (float)l / (float)finalWidth; // u1
info.uvRect.top = (float)m / (float)finalHeight; // v1
info.uvRect.right = (float)( l + ( face->glyph->advance.x >> 6 ) ) / (float)finalWidth; // u2
info.uvRect.bottom = ( m + max_height ) / (float)finalHeight; // v2
info.aspectRatio = textureAspect * (info.uvRect.right - info.uvRect.left) / (info.uvRect.bottom - info.uvRect.top);
l += (advance + mCharSpacer);
if ( (FONT_TEXTURE_WIDTH - 1) < (l + advance) ) { m += max_height + mCharSpacer;l = 0;}
}
}
//保存到D3D纹理
IDirect3DTexture9* _tex;
HRESULT hr = 0;
hr = ::D3DXCreateTexture(
p,
finalWidth, finalHeight,
0,
0,
D3DFMT_A8L8,//纹理格式
D3DPOOL_MANAGED, &_tex);
if(FAILED(hr))
::MessageBox(NULL,"D3DXCreateTexture error", NULL, NULL);
D3DSURFACE_DESC textureDesc;
_tex->GetLevelDesc(0, &textureDesc);
if(textureDesc.Format != D3DFMT_A8L8)
return false;
D3DLOCKED_RECT lockedRect;
_tex->LockRect(0, &lockedRect,0, 0);
//使用类型要对应(unsigned short --- D3DFMT_A8L8)
unsigned short* imageData2 = (unsigned short*)lockedRect.pBits;
for(int i = 0; i < finalHeight; i++){
for(int j = 0; j < finalWidth; j++){
//Pitch数据的总长度
int index = i * lockedRect.Pitch / 2/*D3DFMT_A8L8 二字节*/ + j;
//if(i < finalHeight/2)
// imageData2[index] = 0x00;
//else
// imageData2[index] = 0xFF;
imageData2[index] = imageData[index*2];
}
}
_tex->UnlockRect(0);
//保存纹理
hr = ::D3DXSaveTextureToFile("test.jpg", D3DXIFF_JPG, _tex, NULL);
if(D3DERR_INVALIDCALL == hr)
::MessageBox(NULL,NULL,NULL,NULL);
return true;
}