使用 OpenGL 库(2.1) 绘制 FreeFype Outlines 导出的轮廓线
在GetDatafromOutline函数中提取和整理坐标数据,在display函数中绘制。
2次曲线没有自己写函数计算,而是使用gl2.1自带的求值器glMap,只要做一些初始设置并丢3个坐标信息到函数里就可以了。
// Code By: 523066680
// Date: 2016-11
#include <GL/glut.h>
#include <unistd.h>
#include <stdio.h>
#include <ft2build.h>
#include <freetype/ftbbox.h>
#include <freetype/ftoutln.h>
#include FT_FREETYPE_H
#define SIZE_X 500
#define SIZE_Y 500
int winID;
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
FT_Error error;
FT_Outline outline;
float curves[100][9];
float lines[100][2];
int ci;
int li;
long code = 97;
void GetDatafromOutline(void);
void LoadGlyph(long symbol);
void display(void)
{
int i, j;
// 清理颜色缓冲区
glClear( GL_COLOR_BUFFER_BIT );
glColor3f(1.0, 1.0, 1.0);
glMapGrid1f(20, 0.0, 1.0);
for (int c = 0; c < ci; c++)
{
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 3, curves[c]);
glEvalMesh1(GL_LINE, 0, 20);
}
glBegin(GL_LINES);
for (int n = 0; n < li; n++)
{
glVertex2fv( lines[n] );
}
glEnd();
glutSwapBuffers();
}
void idle(void)
{
usleep(100000);
glutPostRedisplay();
}
void reshape(int Width, int Height)
{
const float fa = 32.0;
const float half = 1500.0;
glViewport(0, 0, Width, Height); //视口范围
glMatrixMode(GL_PROJECTION); // 投影视图矩阵
glLoadIdentity();
glOrtho(-half, half, -half, half, -10.0, 100.0);
glMatrixMode(GL_MODELVIEW); // 模型视图矩阵
glLoadIdentity();
gluLookAt(0.0,0.0,fa, 0.0,0.0,0.0, 0.0,1.0,fa); //设置观察点
// 观察点, 朝向的坐标, 观察点向上坐标
}
void keypress(unsigned char key, int mousex, int mousey)
{
switch (key)
{
case 'q':
glutDestroyWindow(winID);
exit(0);
break;
case 'Q':
glutDestroyWindow(winID);
exit(0);
break;
case 'a':
code++;
LoadGlyph(code);
GetDatafromOutline();
glutPostRedisplay();
break;
}
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glLineWidth( 2.0 );
glPointSize( 2.0 );
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_MAP1_VERTEX_3);
}
void ftinit(void)
{
char* filename;
filename = "C:/windows/fonts/consola.ttf";
error = FT_Init_FreeType( &library );
error = FT_New_Face( library, filename, 0, &face ); /* create face object */
slot = face->glyph;
}
void LoadGlyph(long symbol)
{
//这里可以是unicode编码值,字体必须支持才行
FT_UInt index = FT_Get_Char_Index(face, symbol);
FT_Error error = FT_Load_Glyph(face,
index,
FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
outline = slot->outline;
}
void GetDatafromOutline(void)
{
ci = 0;
li = 0;
int bgn;
int next;
for (int cts = 0; cts < outline.n_contours ; cts++ )
{
bgn = cts == 0 ? 0 : outline.contours[cts-1] + 1;
for (int i = bgn; i <= outline.contours[cts] ; i++)
{
//i==终点时,next回到某个轮廓的起点
next = ( i == outline.contours[cts] ? bgn : i+1 );
if ( outline.tags[i] == 0 )
{
curves[ci][2] = 0.0;
curves[ci][3] = (float)outline.points[i].x; //控制点
curves[ci][4] = (float)outline.points[i].y;
curves[ci][5] = 0.0;
curves[ci][8] = 0.0;
if ( outline.tags[i-1] == 1 ) //1, 0
{
curves[ci][0] = (float)outline.points[i-1].x;
curves[ci][1] = (float)outline.points[i-1].y;
if (outline.tags[next] == 1) //1, 0, 1
{
curves[ci][6] = (float) outline.points[next].x;
curves[ci][7] = (float) outline.points[next].y;
}
else if ( outline.tags[next] == 0 ) //1, 0, 0
{
curves[ci][6] = (float)(outline.points[i].x + outline.points[next].x)/2;
curves[ci][7] = (float)(outline.points[i].y + outline.points[next].y)/2;
}
}
else //0, 0
{
curves[ci][0] = curves[ci-1][6]; //起点为上一段曲线的终点
curves[ci][1] = curves[ci-1][7];
if ( outline.tags[next] == 0 ) //0, 0, 0
{
curves[ci][6] = (float)(outline.points[i].x + outline.points[next].x)/2 ;
curves[ci][7] = (float)(outline.points[i].y + outline.points[next].y)/2 ;
}
else //0, 0, 1
{
curves[ci][6] = (float)outline.points[next].x ;
curves[ci][7] = (float)outline.points[next].y ;
}
}
ci++;
}
else
{
//直线线段
if ( outline.tags[next] == 1 ) //1, 1
{
lines[li][0] = outline.points[i].x;
lines[li][1] = outline.points[i].y;
lines[li+1][0] = outline.points[next].x;
lines[li+1][1] = outline.points[next].y;
li+=2;
}
}
}
}
}
int main( int argc, char** argv )
{
ftinit();
LoadGlyph('m');
GetDatafromOutline();
printf("n_contours: %d \n n_points: %d \n flags: %d\n", outline.n_contours,
outline.n_points,
outline.flags
);
glutInit(&argc, argv);
//显示模式 双缓冲 RGBA
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE );
glutInitWindowSize(SIZE_X, SIZE_Y); //窗口大小
glutInitWindowPosition(200, 200); //位置
winID = glutCreateWindow("Fonts"); //窗口句柄
init();
glutDisplayFunc(display); //显示
glutKeyboardFunc(keypress); //按键事件响应
glutReshapeFunc(reshape); //窗口事件响应
glutIdleFunc(idle); //闲时回调函数
glutMainLoop(); //开始主循环
FT_Done_Face ( face );
FT_Done_FreeType( library );
return 0;
}
如果你发现某个中文字体的中文显示有问题
那是因为某些汉字组成的曲线段比较多,超过100条,curves[] 数组大小不够,然后导致操作的地址跑到了lines里面去了
导致线条错乱。(这分明是因为我的代码不好)