feat():initial version
This commit is contained in:
413
insDavi2.0/src/lib/InsFont.c
Normal file
413
insDavi2.0/src/lib/InsFont.c
Normal file
@@ -0,0 +1,413 @@
|
||||
#include <InsCfg.h>
|
||||
#include <lib/InsFont.h>
|
||||
|
||||
#include <ft2build.h>
|
||||
#include <freetype/freetype.h>
|
||||
#include <freetype/ftglyph.h>
|
||||
|
||||
#define DBG_LEVEL DBG_INFO
|
||||
#define DBG_TAG "LibFont"
|
||||
#include <InsDbg.h>
|
||||
|
||||
static FT_Library mFtLib = NULL;
|
||||
static FT_Face mFtFace[MAX_FT_FACE_NUM];
|
||||
static Int32 mFtFaceIdCnt = 0;
|
||||
|
||||
/*
|
||||
根据指定的字体文件初始化ftLib,
|
||||
成功返回Ins_TRUE, libIDs数组中存放初始化完成的ftLib ID
|
||||
失败或者部分成功返回Ins_FALSE, libIDs数组中可能会被赋值为INS_INVALID_RES_ID
|
||||
*/
|
||||
Bool InitFtLibs
|
||||
(
|
||||
const char *ftFiles[], /*[in] 字体文件路径名字符串数组*/
|
||||
Int32 *libIDs, /*[out] ftLib id数组, 从0开始[0,n]*/
|
||||
Int32 num /*[in] 字体文件数量, ftLib数量*/
|
||||
)
|
||||
{
|
||||
Int32 i;
|
||||
Bool retv = INS_TRUE;
|
||||
|
||||
if(mFtLib == NULL && FT_Init_FreeType(&mFtLib) != 0)
|
||||
{
|
||||
for(i = 0; i < num; i++)libIDs[i] = INS_INVALID_RES_ID;
|
||||
printf("FT_Init_FreeType fail\n");
|
||||
return INS_FALSE;
|
||||
}
|
||||
|
||||
for(i = 0; i < num && i < MAX_FT_FACE_NUM; i++)
|
||||
{
|
||||
if(FT_New_Face(mFtLib, ftFiles[i], 0, &mFtFace[mFtFaceIdCnt]) != 0)
|
||||
{
|
||||
mFtFace[mFtFaceIdCnt] = NULL;
|
||||
retv = INS_FALSE;
|
||||
libIDs[i] = INS_INVALID_RES_ID;
|
||||
printf("FT_New_Face %s fail\n", ftFiles[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
libIDs[i] = mFtFaceIdCnt;
|
||||
mFtFaceIdCnt++;
|
||||
}
|
||||
}
|
||||
for(; i < num; i++) /*(num >= MAX_FT_FACE_NUM)out of range?*/
|
||||
{
|
||||
retv = INS_FALSE;
|
||||
libIDs[i] = INS_INVALID_RES_ID;
|
||||
}
|
||||
|
||||
return retv;
|
||||
}
|
||||
|
||||
/*释放ftLib占用的资源*/
|
||||
void DeInitFtLibs
|
||||
(
|
||||
Int32 *libIDs, /*[in] 需要释放的ftLib ID数组*/
|
||||
Int32 num /*[in]数组大小*/
|
||||
)
|
||||
{
|
||||
if(mFtLib == NULL)return;
|
||||
|
||||
int i;
|
||||
|
||||
for(i = 0; i < MAX_FT_FACE_NUM; i++)
|
||||
{
|
||||
if(mFtFace[i] != NULL)
|
||||
{
|
||||
FT_Done_Face(mFtFace[i]);
|
||||
mFtFace[i] = NULL;
|
||||
}
|
||||
}
|
||||
FT_Done_FreeType(mFtLib);
|
||||
mFtLib = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
根据指定的ftLib ID及字符编码生成字形图
|
||||
*/
|
||||
Bool GenFontBmps
|
||||
(
|
||||
Int32 libID, /*[in] ftLib ID*/
|
||||
Int32 charSize, /*[in] 单个字符最大宽度(最大高度为最大宽度的1.5倍)*/
|
||||
Int32 texWidth, /*[in] 自行图宽度(=2^n)*/
|
||||
Int32 codeNum, /*[in] 字符编码数组大小*/
|
||||
const UInt32 *ucsCode, /*[in] 字符编码数组*/
|
||||
Int32 *texHigh, /*[out] 字形图中包含有效字形的像素高度*/
|
||||
UInt08 **pixelBuff, /*[out] 自行图像素(灰度/Alpha)数据(一个字节对应一个像素的Alpha值), 字节数大于texWidth x texHigh */
|
||||
Flt32 **widthRate, /*[out] 字形实际宽度比值数组(实际宽度/charSize)*/
|
||||
Flt32 **texcoord, /*[out] 与字符编码数组对应的OpenGL纹理坐标(左上角、右下角两组坐标)*/
|
||||
Bool tight /*[in] 左右相邻的两个字形是否紧密排列, Ins_FALSE则按每个字形占charSize个像素宽度排列,无论字形的"肥瘦"*/
|
||||
)
|
||||
{
|
||||
Int32 x, y, n, column, row;
|
||||
Int32 texX0, texY0;
|
||||
UInt08 *tmpBuff;
|
||||
|
||||
if(charSize > texWidth
|
||||
|| pixelBuff == NULL
|
||||
|| texHigh == NULL
|
||||
|| codeNum < 1
|
||||
|| libID >= mFtFaceIdCnt
|
||||
|| libID < 0)
|
||||
{
|
||||
return INS_FALSE;
|
||||
}
|
||||
FT_Set_Pixel_Sizes(mFtFace[libID], charSize, charSize);
|
||||
texX0 = 0;
|
||||
texY0 = 0;
|
||||
column = texWidth/charSize; /*glyph_num per line */
|
||||
row = (codeNum+column-1)/column; /*line count*/
|
||||
tmpBuff = (UInt08*)malloc(row*3*charSize/2*texWidth); /*glyph high is [3 x charSize / 2]*/
|
||||
if(widthRate != NULL)widthRate[0] = (Flt32*)malloc(codeNum*sizeof(Flt32));
|
||||
if(texcoord != NULL)texcoord[0] = (Flt32*)malloc(codeNum*4*sizeof(Flt32));
|
||||
memset(tmpBuff, 0, row*3*charSize/2*texWidth);
|
||||
for(n = 0; n < codeNum; n++)
|
||||
{
|
||||
FT_Glyph glyph;
|
||||
UInt08 *bmpBuff;
|
||||
Int32 left, top, innx, inny, w, h;
|
||||
|
||||
FT_Load_Glyph(mFtFace[libID], FT_Get_Char_Index(mFtFace[libID], ucsCode[n]), FT_LOAD_DEFAULT);
|
||||
if(FT_Get_Glyph(mFtFace[libID]->glyph, &glyph) != 0)
|
||||
{
|
||||
if(texcoord != NULL)
|
||||
{
|
||||
texcoord[0][4*n+0] = 0.0f;
|
||||
texcoord[0][4*n+1] = 0.0f;
|
||||
texcoord[0][4*n+2] = 0.0f;
|
||||
texcoord[0][4*n+3] = 0.0f;
|
||||
}
|
||||
if(widthRate != NULL)widthRate[0][n] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(glyph->format != FT_GLYPH_FORMAT_BITMAP)
|
||||
{
|
||||
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
|
||||
}
|
||||
FT_BitmapGlyph bmpGlyph = (FT_BitmapGlyph)glyph;
|
||||
|
||||
w = bmpGlyph->bitmap.width;
|
||||
h = bmpGlyph->bitmap.rows;
|
||||
left = bmpGlyph->left;
|
||||
top = bmpGlyph->top;
|
||||
if(top > charSize)
|
||||
top = charSize;
|
||||
|
||||
bmpBuff = bmpGlyph->bitmap.buffer;
|
||||
if(w == 0) /*space*/
|
||||
{
|
||||
w = charSize/2;
|
||||
h = 0;
|
||||
left = 0;
|
||||
top = 0;
|
||||
bmpBuff = NULL;
|
||||
}
|
||||
if(tight)
|
||||
{
|
||||
if(widthRate != NULL)widthRate[0][n] = 1.0f*w/charSize;
|
||||
if(texX0 + w > texWidth)
|
||||
{
|
||||
texX0 = 0;
|
||||
texY0 += 3*charSize/2;
|
||||
}
|
||||
x = texX0;
|
||||
y = texY0 + charSize - top;
|
||||
if(texcoord != NULL)
|
||||
{
|
||||
texcoord[0][4*n+0] = 1.0f*texX0/texWidth;
|
||||
texcoord[0][4*n+1] = texY0;
|
||||
texcoord[0][4*n+2] = 1.0f*(texX0+w)/texWidth;
|
||||
texcoord[0][4*n+3] = texY0+3.0f*charSize/2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(widthRate != NULL)widthRate[0][n] = 1.0f;
|
||||
if(texX0 + charSize > texWidth)
|
||||
{
|
||||
texX0 = 0;
|
||||
texY0 += 3*charSize/2;
|
||||
}
|
||||
x = texX0 + left;
|
||||
y = texY0 + charSize - top;
|
||||
if(texcoord != NULL)
|
||||
{
|
||||
texcoord[0][4*n+0] = 1.0f*texX0/texWidth;
|
||||
texcoord[0][4*n+1] = texY0;
|
||||
texcoord[0][4*n+2] = 1.0f*(texX0+charSize)/texWidth;
|
||||
texcoord[0][4*n+3] = texY0+3.0f*charSize/2;
|
||||
}
|
||||
}
|
||||
|
||||
for(inny = 0; inny < h; inny++)
|
||||
{
|
||||
for(innx = 0; innx < w; innx++)
|
||||
{
|
||||
tmpBuff[(y+inny)*texWidth + x + innx] = bmpBuff[inny*w+innx];
|
||||
}
|
||||
}
|
||||
|
||||
if(tight)
|
||||
{
|
||||
texX0 += w+2;/* +2 to make a gap between glyphs*/
|
||||
}
|
||||
else
|
||||
{
|
||||
texX0 += charSize;
|
||||
}
|
||||
//printf("texX0:%d\n", texX0);
|
||||
FT_Done_Glyph(glyph);
|
||||
}
|
||||
pixelBuff[0] = tmpBuff;
|
||||
*texHigh = texY0 + 3.0f*charSize/2;
|
||||
if(texcoord != NULL)for(n = 0; n < codeNum; n++)
|
||||
{
|
||||
texcoord[0][4*n+1] = *texHigh - texcoord[0][4*n+1];
|
||||
texcoord[0][4*n+3] = *texHigh - texcoord[0][4*n+3];
|
||||
texcoord[0][4*n+1] /= *texHigh;
|
||||
texcoord[0][4*n+3] /= *texHigh;
|
||||
//printf("(%f, %f), (%f, %f)\n", texcoord[0][4*n+0], texcoord[0][4*n+1], texcoord[0][4*n+2], texcoord[0][4*n+3]);
|
||||
}
|
||||
/*
|
||||
if(widthRate != NULL)for(n = 0; n < codeNum; n++)
|
||||
{
|
||||
printf("%f\n", widthRate[0][n]);
|
||||
}
|
||||
for(y = 0; y < 0; y++)// *texHigh; y++)
|
||||
{
|
||||
for(x = 0; x < texWidth; x++)
|
||||
{
|
||||
if(pixelBuff[0][y*texWidth+x] < 10)printf("00%d ", pixelBuff[0][y*texWidth+x]);
|
||||
else if(pixelBuff[0][y*texWidth+x] < 100)printf("0%d ", pixelBuff[0][y*texWidth+x]);
|
||||
else printf("%d ", pixelBuff[0][y*texWidth+x]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
*/
|
||||
for(y = 0; y < *texHigh/2; y++)
|
||||
{
|
||||
for(x = 0; x < texWidth; x++)
|
||||
{
|
||||
texY0 = *texHigh-y-1;
|
||||
n = pixelBuff[0][y*texWidth + x];
|
||||
pixelBuff[0][y*texWidth + x] = pixelBuff[0][texY0*texWidth + x];
|
||||
pixelBuff[0][texY0*texWidth + x] = n;
|
||||
}
|
||||
}
|
||||
return INS_TRUE;
|
||||
}
|
||||
|
||||
Bool DrawSingleLineTxtBmp
|
||||
(
|
||||
Int32 libID,
|
||||
Int32 charSize,
|
||||
Int32 *bmpWidth,
|
||||
Int32 *bmpHigh,
|
||||
const UInt32 *ucsCode,
|
||||
UInt08 *bmpPixel,
|
||||
Bool tight,
|
||||
Int32 *numDrawn
|
||||
)
|
||||
{
|
||||
Int32 x, y, n, cursorX, failWidth;
|
||||
FT_Glyph glyph[1];
|
||||
|
||||
if(charSize > *bmpWidth
|
||||
|| bmpPixel == NULL
|
||||
|| libID >= mFtFaceIdCnt
|
||||
|| libID < 0)
|
||||
{
|
||||
if(numDrawn != NULL)*numDrawn = 0;
|
||||
return INS_FALSE;
|
||||
}
|
||||
|
||||
FT_Set_Pixel_Sizes(mFtFace[libID], charSize, charSize);
|
||||
|
||||
/* use '_' rectangle info for invalid(fail) character */
|
||||
if(FT_Load_Glyph(mFtFace[libID], FT_Get_Char_Index(mFtFace[libID], '_'), FT_LOAD_DEFAULT) != 0
|
||||
|| FT_Get_Glyph(mFtFace[libID]->glyph, glyph) != 0)
|
||||
{
|
||||
failWidth = charSize/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(glyph[0]->format != FT_GLYPH_FORMAT_BITMAP)
|
||||
{
|
||||
FT_Glyph_To_Bitmap(glyph, FT_RENDER_MODE_NORMAL, 0, 1);
|
||||
}
|
||||
FT_BitmapGlyph bmpGlyph = (FT_BitmapGlyph)glyph[0];
|
||||
|
||||
failWidth = bmpGlyph->bitmap.width;
|
||||
}
|
||||
|
||||
FT_Done_Glyph(glyph[0]);
|
||||
glyph[0] = NULL;
|
||||
|
||||
cursorX = 0;
|
||||
for(n = 0; ucsCode[n] != 0; n++)
|
||||
{
|
||||
UInt08 *buff = NULL;
|
||||
UInt32 idx, innx, inny;
|
||||
Int32 glyphLeft, glyphTop, glyphWidth, glyphHeight;
|
||||
|
||||
if((idx = FT_Get_Char_Index(mFtFace[libID], ucsCode[n])) == 0 /*invalid character*/
|
||||
|| FT_Load_Glyph(mFtFace[libID], idx, FT_LOAD_DEFAULT) != 0 /*load fail*/
|
||||
|| FT_Get_Glyph(mFtFace[libID]->glyph, glyph) != 0) /*get fail*/
|
||||
{
|
||||
printf("load glyph fail[ucs:0x%x]\n", ucsCode[n]);
|
||||
glyphWidth = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(glyph[0]->format != FT_GLYPH_FORMAT_BITMAP)
|
||||
{
|
||||
FT_Glyph_To_Bitmap(glyph, FT_RENDER_MODE_NORMAL, 0, 1);
|
||||
}
|
||||
FT_BitmapGlyph bmpGlyph = (FT_BitmapGlyph)glyph[0];
|
||||
|
||||
glyphWidth = bmpGlyph->bitmap.width;
|
||||
glyphHeight = bmpGlyph->bitmap.rows;
|
||||
glyphLeft = bmpGlyph->left;
|
||||
glyphTop = bmpGlyph->top;
|
||||
// printf("load glyph ok[ucs:0x%x]\n", ucsCode[n]);
|
||||
// printf("(%d, %d, %d, %d)\n", glyphLeft, glyphTop, glyphWidth, glyphHeight);
|
||||
|
||||
buff = bmpGlyph->bitmap.buffer;
|
||||
}
|
||||
if(glyphWidth == 0)
|
||||
{
|
||||
glyphWidth = failWidth;
|
||||
glyphHeight = 0;
|
||||
glyphLeft = 0;
|
||||
glyphTop = 0;
|
||||
}
|
||||
if(tight)
|
||||
{
|
||||
if(cursorX + glyphWidth > (*bmpWidth))
|
||||
{
|
||||
FT_Done_Glyph(glyph[0]);
|
||||
glyph[0] = NULL;
|
||||
break;
|
||||
}
|
||||
x = cursorX;
|
||||
y = charSize - glyphTop;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(cursorX + charSize > (*bmpWidth))
|
||||
{
|
||||
FT_Done_Glyph(glyph[0]);
|
||||
glyph[0] = NULL;
|
||||
break;
|
||||
}
|
||||
x = cursorX + glyphLeft;
|
||||
y = charSize - glyphTop;
|
||||
}
|
||||
if(y < 0)y = 0;
|
||||
|
||||
// printf("cursorX:%d, bmpWidth:%d, bmpHeight:%d, (%d,%d)\n", cursorX, *bmpWidth, *bmpHigh, x, y);
|
||||
for(inny = 0; inny < glyphHeight; inny++)
|
||||
{
|
||||
for(innx = 0; innx < glyphWidth; innx++)
|
||||
{
|
||||
// printf("%x%x,", buff[inny*glyphWidth+innx]/16, buff[inny*glyphWidth+innx]%16);
|
||||
if((*bmpHigh) <= y+inny)continue;
|
||||
bmpPixel[((*bmpHigh)-y-inny-1)*(*bmpWidth) + x + innx] = buff[inny*glyphWidth+innx];
|
||||
// bmpPixel[(y+inny)*(*bmpWidth) + x + innx] = buff[inny*glyphWidth+innx];
|
||||
}
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
if(tight)
|
||||
{
|
||||
cursorX += glyphWidth+2;/* +2 to make a gap between glyphs*/
|
||||
}
|
||||
else
|
||||
{
|
||||
cursorX += charSize;
|
||||
}
|
||||
FT_Done_Glyph(glyph[0]);
|
||||
glyph[0] = NULL;
|
||||
}
|
||||
if(numDrawn != NULL)*numDrawn = n;
|
||||
|
||||
if(tight)cursorX -= 2;
|
||||
for(y = 1; y < *bmpHigh; y++)
|
||||
{
|
||||
for(x = 0; x < cursorX; x++)
|
||||
{
|
||||
bmpPixel[y*cursorX+x] = bmpPixel[y*(*bmpWidth)+x];
|
||||
}
|
||||
}
|
||||
|
||||
x = (*bmpHigh)*cursorX;
|
||||
y = (*bmpHigh)*(*bmpWidth);
|
||||
while(x < y)bmpPixel[(x++)] = 0;
|
||||
|
||||
*(bmpWidth) = cursorX;
|
||||
// printf("width:%d, height:%d\n", (*bmpWidth), (*bmpHigh));
|
||||
|
||||
return INS_TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user