#include <windows.h>
#include <stdio.h>
#include <gl/glut.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>
#ifdef _WIN32
#pragma comment(lib , "libfreetype.lib")
#endif
#define MAX_NO_TEXTURES 1
#define CUBE_TEXTURE 0
GLuint texture_id[MAX_NO_TEXTURES];
struct xCharTexture
{
GLuint m_texID;
wchar_t m_chaID;
int m_Width;
int m_Height;
int m_adv_x;
int m_adv_y;
int m_delta_x;
int m_delta_y;
public:
xCharTexture()
{
m_texID = 0;
m_chaID = 0;
m_Width = 0;
m_Height = 0;
}
}g_TexID[65536];
class xFreeTypeLib
{
FT_Library m_FT2Lib;
FT_Face m_FT_Face;
int m_w;
int m_h;
public:
xFreeTypeLib()
{
if (FT_Init_FreeType( &m_FT2Lib) )
exit(0);
}
void load(const char* font_file , int _w , int _h)
{
//加载一个字体,取默认的Face,一般为Regualer
if (FT_New_Face( m_FT2Lib, font_file, 0, &m_FT_Face ))
exit(0);
FT_Select_Charmap(m_FT_Face, FT_ENCODING_UNICODE);
m_w = _w ; m_h = _h;
m_FT_Face->num_fixed_sizes;
//大小要乘64.这是规定。照做就可以了。
//FT_Set_Char_Size( m_FT_Face , 0 , m_w << 6, 96, 96);
FT_Set_Pixel_Sizes(m_FT_Face,m_w, m_h);
}
GLuint loadChar(wchar_t ch)
{
if(g_TexID[ch].m_texID)
return g_TexID[ch].m_texID;
if(FT_Load_Char(m_FT_Face, ch,FT_LOAD_RENDER|FT_LOAD_FORCE_AUTOHINT|
(true ? FT_LOAD_TARGET_NORMAL : FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO) ) )
{
return 0;
}
xCharTexture& charTex = g_TexID[ch];
//得到字模
FT_Glyph glyph;
if(FT_Get_Glyph( m_FT_Face->glyph, &glyph ))
return 0;
//转化成位图
FT_Render_Glyph( m_FT_Face->glyph, FT_RENDER_MODE_LCD );//FT_RENDER_MODE_NORMAL );
FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 );
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
//取道位图数据
FT_Bitmap& bitmap=bitmap_glyph->bitmap;
//把位图数据拷贝自己定义的数据区里.这样旧可以画到需要的东西上面了。
int width = bitmap.width;
int height = bitmap.rows;
m_FT_Face->size->metrics.y_ppem;
m_FT_Face->glyph->metrics.horiAdvance;
charTex.m_Width = width;
charTex.m_Height = height;
charTex.m_adv_x = m_FT_Face->glyph->advance.x / 64.0f;
charTex.m_adv_y = m_FT_Face->size->metrics.y_ppem; //m_FT_Face->glyph->metrics.horiBearingY / 64.0f;
charTex.m_delta_x = (float)bitmap_glyph->left;
charTex.m_delta_y = (float)bitmap_glyph->top - height;
glGenTextures(1,&charTex.m_texID);
glBindTexture(GL_TEXTURE_2D,charTex.m_texID);
char* pBuf = new char[width * height * 4];
bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
for(int j=0; j < height ; j++)
{
for(int i=0; i < width; i++)
{
unsigned char _vl = (i>=bitmap.width || j>=bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j];
pBuf[(4*i + (height - j - 1) * width * 4) ] = 0xff;
pBuf[(4*i + (height - j - 1) * width * 4)+1] = 0xff;
pBuf[(4*i + (height - j - 1) * width * 4)+2] = 0xff;
pBuf[(4*i + (height - j - 1) * width * 4)+3] = _vl;
}
}
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pBuf);//creates 2-D mipmaps
//glTexImage2D( GL_TEXTURE_2D,0,GL_RGBA,width, height,0,GL_RGBA,GL_UNSIGNED_BYTE,pBuf);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexEnvi(GL_TEXTURE_2D,GL_TEXTURE_ENV_MODE,GL_REPLACE);
delete[]pBuf;
return charTex.m_chaID;
}
}g_FreeTypeLib;
float ratio;
xCharTexture* getTextChar(wchar_t ch)
{
g_FreeTypeLib.loadChar(ch);
return &g_TexID[ch];
}
wchar_t g_UnicodeString[]=L"远交华盖欲何求,未敢翻身已碰头。/n/
破帽遮颜过闹市,漏船载酒泛中流。/n/
横眉冷对千夫指,俯首甘为孺子牛。/n/
躲进小楼成一统,管他冬夏与春秋。";
void drawText(wchar_t* _strText,int x , int y, int maxW , int h)
{
int sx = x;
int sy = y;
int maxH = h;
for(int i = 0 ; i < wcslen(_strText) ; i ++)
{
if(_strText[i] =='/n')
{
sx = x ; sy += maxH + 12;
continue;
}
xCharTexture* pCharTex = getTextChar(_strText[i]);
glBindTexture(GL_TEXTURE_2D,pCharTex->m_texID);
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
//glDisable(GL_TEXTURE_2D);
int w = pCharTex->m_Width;
int h = pCharTex->m_Height;
int ch_x = sx + pCharTex->m_delta_x;
int ch_y = sy - h - pCharTex->m_delta_y;
if(maxH < h) maxH = h;
glBegin ( GL_QUADS );
{
glTexCoord2f(0.0f, 1.0f); glVertex3f(ch_x , ch_y , 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(ch_x + w, ch_y , 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(ch_x + w, ch_y + h, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(ch_x , ch_y + h, 1.0f);
}
glEnd();
sx += pCharTex->m_adv_x;
if(sx > x + maxW)
{
sx = x ; sy += maxH + 12;
}
}
}
void init(void)
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glEnable ( GL_COLOR_MATERIAL );
glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
g_FreeTypeLib.load("simhei.ttf",24,24);
glDisable ( GL_CULL_FACE );
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
void reshape( int w, int h )
{
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0)
h = 1;
ratio = 1.0f * w / h;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
glOrtho(0,w,h,0,-100,200);
// Set the clipping volume
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 30 ,0 , 0 ,10 , 0.0f , 1.0f , 0.0f);
}
void display( void )
{
glClearColor(0.0f , 0.0f , 0.6f , 1.0f);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glEnable ( GL_TEXTURE_2D );
drawText(g_UnicodeString,50,50,900,25);
glutSwapBuffers();
}
void keyboard ( unsigned char key, int x, int y ) // Create Keyboard Function
{
switch ( key ) {
case 27: // When Escape Is Pressed...
exit ( 0 ); // Exit The Program
break; // Ready For Next Case
default: // Now Wrap It Up
break;
}
}
void arrow_keys ( int a_keys, int x, int y ) // Create Special Function (required for arrow keys)
{
switch ( a_keys ) {
case GLUT_KEY_UP: // When Up Arrow Is Pressed...
glutFullScreen ( ); // Go Into Full Screen Mode
break;
case GLUT_KEY_DOWN: // When Down Arrow Is Pressed...
glutReshapeWindow ( 500, 500 ); // Go Into A 500 By 500 Window
break;
default:
break;
}
}
int main ( int argc, char** argv ) // Create Main Function For Bringing It All Together
{
glutInit ( &argc, argv ); // Erm Just Write It =)
glutInitDisplayMode ( GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA ); // Display Mode
glutInitWindowPosition (0,0);
glutInitWindowSize ( 500, 500 ); // If glutFullScreen wasn't called this is the window size
glutCreateWindow ( "Chinese - Display" ); // Window Title (argv[0] for current directory as title)
init ();
glutDisplayFunc ( display ); // Matching Earlier Functions To Their Counterparts
glutReshapeFunc ( reshape );
glutKeyboardFunc ( keyboard );
glutSpecialFunc ( arrow_keys );
glutIdleFunc ( display );
glutMainLoop ( ); // Initialize The Main Loop
return 1;
}