// ----------------------------------------- font_manager_get_from_filename --- texture_font_t * font_manager_get_from_filename( font_manager_t *self, const char * filename, const float size ) { size_t i; texture_font_t *font; assert( self ); for( i=0; i<vector_size(self->fonts); ++i ) { font = * (texture_font_t **) vector_get( self->fonts, i ); if( (strcmp(font->filename, filename) == 0) && ( font->size == size) ) { return font; } } font = texture_font_new_from_file( self->atlas, size, filename ); if( font ) { vector_push_back( self->fonts, &font ); texture_font_load_glyphs( font, self->cache ); return font; } fprintf( stderr, "Unable to load \"%s\" (size=%.1f)\n", filename, size ); return 0; }
//texture int init_texture() { memset( &m_texture, 0, sizeof(texture) ); glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 ); //global m_texture.data = (unsigned char *)malloc( IMAGE_W * IMAGE_H * 1 ); glActiveTexture(GL_TEXTURE0); m_texture.text_atlas = texture_atlas_new( 1024, 1024, 1 ); m_texture.text_font = texture_font_new( m_texture.text_atlas, "./fonts/Vera.ttf", 60/*size*/ ); texture_font_load_glyphs( m_texture.text_font, L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~"); texture_atlas_upload(m_texture.text_atlas); //uploads data to gpu memory using glTexImage2D(). glActiveTexture(GL_TEXTURE1); glGenTextures(1, &m_texture.m_texture); glBindTexture(GL_TEXTURE_2D, m_texture.m_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // only for Active texture glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); return (0); }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitWindowSize( 800, 400 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( "Freetype OpenGL / vertex arrays" ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); size_t i; texture_font_t *font = 0; texture_atlas_t *atlas = texture_atlas_new( 512, 512, 1 ); const char * filename = "./Vera.ttf"; wchar_t *text = L"A Quick Brown Fox Jumps Over The Lazy Dog 0123456789"; buffer = vertex_buffer_new( "v3f:t2f:c4f" ); vec2 pen = {{0,0}}; vec4 black = {{0,0,0,1}}; for( i=7; i < 27; ++i) { font = texture_font_new( atlas, filename, i ); pen.x = 0; pen.y -= font->height; texture_font_load_glyphs( font, text ); add_text( buffer, font, text, &black, &pen ); texture_font_delete( font ); } glBindTexture( GL_TEXTURE_2D, atlas->id ); glutMainLoop( ); return 0; }
bool Font::Load(const std::string &file, float size) { if (Font::Atlas == null) { Font::Atlas = texture_atlas_new(1024, 1024, 1); } this->FontHandle = texture_font_new_from_file(Font::Atlas, size, file.c_str()); if (this->FontHandle == nullptr) return false; texture_font_load_glyphs(this->FontHandle, L"~!@#$%^&*()_+`1234567890-=QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm|\\<>?,./:;\"'}{][”“’\n"); return true; }
void opengl_font_reload(font_t* f) { opengl_font_t* o = (opengl_font_t*)f->data; texture_font_delete(o->font); texture_atlas_delete(o->atlas); o->atlas = texture_atlas_new(512, 512, 1); o->font = texture_font_new(o->atlas, o->name, f->size * window_zoom); texture_font_load_glyphs(o->font, cache); }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitWindowSize( 512, 512 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( "Freetype OpenGL width shaders" ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutMotionFunc( mouse_drag ); glutPassiveMotionFunc( mouse_motion ); glutKeyboardFunc( keyboard ); glewExperimental = GL_TRUE; GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ fprintf( stderr, "Error: %s\n", glewGetErrorString(err) ); exit( EXIT_FAILURE ); } fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) ); unsigned char *map; texture_font_t * font; const char *filename = "fonts/Vera.ttf"; const wchar_t *cache = L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~"; atlas = texture_atlas_new( 512, 512, 1 ); font = texture_font_new_from_file( atlas, 72, filename ); texture_font_load_glyphs( font, cache ); texture_font_delete( font ); fprintf( stderr, "Generating distance map...\n" ); map = make_distance_map(atlas->data, atlas->width, atlas->height); fprintf( stderr, "done !\n"); memcpy( atlas->data, map, atlas->width*atlas->height*sizeof(unsigned char) ); free(map); texture_atlas_upload( atlas ); // Create the GLSL program program = shader_load( "shaders/distance-field.vert", "shaders/distance-field.frag" ); glUseProgram( program ); glutMainLoop( ); return 0; }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitWindowSize( 800, 400 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( "Freetype OpenGL / LCD filtering" ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); glewExperimental = GL_TRUE; GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ fprintf( stderr, "Error: %s\n", glewGetErrorString(err) ); exit( EXIT_FAILURE ); } fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) ); size_t i; texture_font_t *font = 0; atlas = texture_atlas_new( 512, 512, 3 ); const char * filename = "fonts/Vera.ttf"; wchar_t *text = L"A Quick Brown Fox Jumps Over The Lazy Dog 0123456789"; buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f,ashift:1f,agamma:1f" ); vec2 pen = {{0,0}}; vec4 color = {{0,0,0,1}}; for( i=7; i < 27; ++i) { font = texture_font_new_from_file( atlas, i, filename ); pen.x = 0; pen.y -= font->height; texture_font_load_glyphs( font, text ); add_text( buffer, font, text, &color, &pen ); texture_font_delete( font ); } glBindTexture( GL_TEXTURE_2D, atlas->id ); shader = shader_load( "shaders/text.vert", "shaders/text.frag" ); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glutMainLoop( ); return 0; }
int modelEngine::initFonts() { /* Texture atlas to store individual glyphs */ atlas = texture_atlas_new( 1024, 1024, 1 ); font1 = texture_font_new( atlas, "./fonts/fonts/custom.ttf", 50 ); font2 = texture_font_new( atlas, "./fonts/fonts/ObelixPro.ttf", 70 ); /* Cache some glyphs to speed things up */ texture_font_load_glyphs( font1, L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~"); texture_font_load_glyphs( font2, L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~"); texture_atlas_upload(atlas); vec2 pen = {-400,150}; vec4 color = {0.5,0.5,0.5,0.5}; GLuint bufIndex = atlas->id; }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitWindowSize( 512, 512 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( argv[0] ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); atlas = texture_atlas_new( 512, 512, 1 ); assert(atlas); const char *filename = "../fonts/Vera.ttf"; const wchar_t *cache = L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~"; size_t minsize = 8, maxsize = 27; size_t count = maxsize - minsize; size_t i, missed = 0; for( i=minsize; i < maxsize; ++i ) { texture_font_t * font = texture_font_new( atlas, filename, i ); if(!font) { fprintf(stderr, "Failed to load font: \"%s\"\n", filename); return -1; } if(!texture_font_load_glyphs( font, cache )) { missed++; } texture_font_delete( font ); } printf( "Matched font : %s\n", filename ); printf( "Number of fonts : %zd\n", count ); printf( "Number of glyphs per font : %zd\n", wcslen(cache) ); printf( "Number of missed glyphs : %zd\n", missed ); printf( "Total number of glyphs : %zd/%zd\n", wcslen(cache)*count - missed, wcslen(cache)*count ); printf( "Texture size : %zdx%zd\n", atlas->width, atlas->height ); printf( "Texture occupancy : %.2f%%\n", 100.0*atlas->used/(float)(atlas->width*atlas->height) ); glutMainLoop( ); return 0; }
Stats::Stats(int viewport_width, int viewport_height) : texture_atlas(0) , texture_font(0) , vertex_count(0) , position_vbo(0) , texcoord_vbo(0) , vao(0) , sampler(0) , text_vs(0) , text_fs(0) , text_program(0) , uniform_instance_buffer(0) { texture_atlas = texture_atlas_new(512, 512, 1); texture_font = texture_font_new_from_file(texture_atlas, 11, (DIRECTORY_FONTS + FILE_DEFAULT_FONT).c_str()); texture_font_load_glyphs(texture_font, FONT_CHARSET_CACHE); // Create a sampler object for the font. glGenSamplers(1, &sampler); glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Load the shader program. text_vs = compile_shader_from_file(DIRECTORY_SHADERS + FILE_TEXT_VS, GL_VERTEX_SHADER); text_fs = compile_shader_from_file(DIRECTORY_SHADERS + FILE_TEXT_FS, GL_FRAGMENT_SHADER); text_program = glCreateProgram(); glAttachShader(text_program, text_vs); glAttachShader(text_program, text_fs); link_program(text_program); // Setup a scale matrix to go from screen space to normalized device space. glm::mat3 scale(2.0f / viewport_width, 0.0f, 0.0f, 0.0f, 2.0f / viewport_height, 0.0f, 0.0f, 0.0f, 1.0f); glm::mat3 translation(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, MARGIN_X, MARGIN_Y, 1.0f); uniform_instance_data.model_matrix = glm::mat3x4(translation * scale); uniform_instance_data.color = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f); glGenBuffers(1, &uniform_instance_buffer); glBindBufferBase(GL_UNIFORM_BUFFER, UNIFORM_INSTANCE_BINDING, uniform_instance_buffer); glBufferData(GL_UNIFORM_BUFFER, sizeof(TextPerInstance), &uniform_instance_data, GL_DYNAMIC_DRAW); }
void Font::ResizeFont(int size) { if(m_font) texture_font_delete(m_font); if(m_atlas) texture_atlas_delete(m_atlas); delete m_textureAtlas; m_atlas = texture_atlas_new(512, 512, 1); m_font = texture_font_new(m_atlas, m_fontFile->m_buffer, m_fontFile->m_bufLength, (float)size); texture_font_load_glyphs(m_font, L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~", m_fontFile->m_buffer, m_fontFile->m_bufLength); m_textureAtlas = new GLTexture(m_atlas->id, 512, 512); }
ofxFreeTypeGL::ofxFreeTypeGL(){ texture_atlas_t * atlas = texture_atlas_new( ofGetWidth(), ofGetHeight(), 1 ); texture.allocate(1024, 1024, GL_LUMINANCE_ALPHA); const char *filename = "../../../data/fonts/hiraginoKakugoW6.otf"; const wchar_t *cache = L"Wow,これは面白い!!夜露死苦〠"; size_t minsize = 4, maxsize = 80; size_t count = maxsize - minsize; size_t i, missed = 0; for( i=minsize; i < maxsize; ++i ){ texture_font_t * font = texture_font_new( atlas, filename, i ); missed += texture_font_load_glyphs( font, cache ); texture_font_delete( font ); } printf( "Matched font : %s\n", filename ); printf( "Number of fonts : %ld\n", count ); printf( "Number of glyphs per font : %ld\n", wcslen(cache) ); printf( "Number of missed glyphs : %ld\n", missed ); printf( "Total number of glyphs : %ld/%ld\n", wcslen(cache)*count - missed, wcslen(cache)*count ); printf( "Texture size : %ldx%ld\n", atlas->width, atlas->height ); printf( "Texture occupancy : %.2f%%\n", 100.0*atlas->used/(float)(atlas->width*atlas->height) ); const int SIZE = atlas->width * atlas->height; vector<unsigned char> temp; temp.resize(SIZE * 2); unsigned char *src = atlas->data; unsigned char *dst = temp.data(); for (int i = 0; i < SIZE; i++){ dst[0] = 255; dst[1] = *src; src++; dst += 2; } texture.loadData(temp.data(), 1024, 1024, GL_LUMINANCE_ALPHA); }
/** * @text */ METHOD_BEGIN(load, info) { HandleScope scope; Font* font = internalPtr<Font>(info, CLASS_Font); if(font == 0) { return; } v8::Local<v8::String> tmp = info[0]->ToString(); int length = tmp->Length(); uint16_t uchars[length + 1]; wchar_t wchars[length + 1]; tmp->Write(uchars); for (int i=0; i<length; i++) { wchars[i] = uchars[i]; } wchars[length] = 0; texture_font_load_glyphs(font->font, wchars); }
int opengl_font_build( font_t* font, const char* file, int size) { opengl_font_t* o; if((o = (opengl_font_t*)malloc(sizeof(opengl_font_t))) == NULL) return 0; font->size = size; font->data = (void*)o; m_sprintf(o->name, MAX_BUFFER, DATA_PATH "/" FONTS "/%s", file); o->atlas = texture_atlas_new(512, 512, 1); o->font = texture_font_new(o->atlas, o->name, size * window_zoom); texture_font_load_glyphs(o->font, cache); current_font = font; // Set last build to current one. return 1; }
// ------------------------------------------------------------------- init --- void init( void ) { size_t i; texture_font_t *font = 0; atlas = texture_atlas_new( 512, 512, 3 ); const char * filename = "fonts/Vera.ttf"; char * text = "A Quick Brown Fox Jumps Over The Lazy Dog 0123456789"; buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f,ashift:1f,agamma:1f" ); vec2 pen = {{0,0}}; vec4 color = {{0,0,0,1}}; for( i=7; i < 27; ++i) { font = texture_font_new_from_file( atlas, i, filename ); pen.x = 0; pen.y -= font->height; texture_font_load_glyphs( font, text ); add_text( buffer, font, text, &color, &pen ); texture_font_delete( font ); } glGenTextures( 1, &atlas->id ); glBindTexture( GL_TEXTURE_2D, atlas->id ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, atlas->width, atlas->height, 0, GL_RGB, GL_UNSIGNED_BYTE, atlas->data ); shader = shader_load( "shaders/text.vert", "shaders/text.frag" ); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { size_t i, j; GLFWwindow* window; glfwSetErrorCallback( error_callback ); if (!glfwInit( )) { exit( EXIT_FAILURE ); } glfwWindowHint( GLFW_VISIBLE, GL_TRUE ); glfwWindowHint( GLFW_RESIZABLE, GL_FALSE ); window = glfwCreateWindow( 1, 1, argv[0], NULL, NULL ); if (!window) { glfwTerminate( ); exit( EXIT_FAILURE ); } glfwMakeContextCurrent( window ); glfwSwapInterval( 1 ); glfwSetFramebufferSizeCallback( window, reshape ); glfwSetWindowRefreshCallback( window, display ); glfwSetKeyCallback( window, keyboard ); #ifndef __APPLE__ glewExperimental = GL_TRUE; GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ fprintf( stderr, "Error: %s\n", glewGetErrorString(err) ); exit( EXIT_FAILURE ); } fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) ); #endif texture_atlas_t * atlas = texture_atlas_new( 512, 512, 3 ); texture_font_t *fonts[20]; for ( i=0; i< 20; ++i ) { fonts[i] = texture_font_new_from_file(atlas, 12+i, font_filename), texture_font_load_glyphs(fonts[i], text, direction, language, script ); } typedef struct { float x,y,z, u,v, r,g,b,a, shift, gamma; } vertex_t; vbuffer = vertex_buffer_new( "vertex:3f,tex_coord:2f," "color:4f,ashift:1f,agamma:1f" ); /* Create a buffer for harfbuzz to use */ hb_buffer_t *buffer = hb_buffer_create(); for (i=0; i < 20; ++i) { hb_buffer_set_direction( buffer, direction ); hb_buffer_set_script( buffer, script ); hb_buffer_set_language( buffer, hb_language_from_string(language, strlen(language)) ); hb_buffer_add_utf8( buffer, text, strlen(text), 0, strlen(text) ); hb_shape( fonts[i]->hb_ft_font, buffer, NULL, 0 ); unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buffer, &glyph_count); texture_font_load_glyphs( fonts[i], text, direction, language, script ); float gamma = 1.0; float shift = 0.0; float x = 0; float y = 600 - i * (10+i) - 15; float width = 0.0; float hres = fonts[i]->hres; for (j = 0; j < glyph_count; ++j) { int codepoint = glyph_info[j].codepoint; float x_advance = glyph_pos[j].x_advance/(float)(hres*64); float x_offset = glyph_pos[j].x_offset/(float)(hres*64); texture_glyph_t *glyph = texture_font_get_glyph(fonts[i], codepoint); if( i < (glyph_count-1) ) width += x_advance + x_offset; else width += glyph->offset_x + glyph->width; } x = 800 - width - 10 ; for (j = 0; j < glyph_count; ++j) { int codepoint = glyph_info[j].codepoint; // because of vhinting trick we need the extra 64 (hres) float x_advance = glyph_pos[j].x_advance/(float)(hres*64); float x_offset = glyph_pos[j].x_offset/(float)(hres*64); float y_advance = glyph_pos[j].y_advance/(float)(64); float y_offset = glyph_pos[j].y_offset/(float)(64); texture_glyph_t *glyph = texture_font_get_glyph(fonts[i], codepoint); float r = 0.0; float g = 0.0; float b = 0.0; float a = 1.0; float x0 = x + x_offset + glyph->offset_x; float x1 = x0 + glyph->width; float y0 = floor(y + y_offset + glyph->offset_y); float y1 = floor(y0 - glyph->height); float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; vertex_t vertices[4] = { {x0,y0,0, s0,t0, r,g,b,a, shift, gamma}, {x0,y1,0, s0,t1, r,g,b,a, shift, gamma}, {x1,y1,0, s1,t1, r,g,b,a, shift, gamma}, {x1,y0,0, s1,t0, r,g,b,a, shift, gamma} }; GLushort indices[6] = { 0,1,2, 0,2,3 }; vertex_buffer_push_back( vbuffer, vertices, 4, indices, 6 ); x += x_advance; y += y_advance; } /* clean up the buffer, but don't kill it just yet */ hb_buffer_reset(buffer); } glClearColor(1,1,1,1); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glBindTexture( GL_TEXTURE_2D, atlas->id ); texture_atlas_upload( atlas ); vertex_buffer_upload( vbuffer ); shader = shader_load("shaders/text.vert", "shaders/text.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glfwSetWindowSize( window, 800, 600 ); glfwShowWindow( window ); while(!glfwWindowShouldClose( window )) { display( window ); glfwPollEvents( ); } glfwDestroyWindow( window ); glfwTerminate( ); return 0; }
// ------------------------------------------------------------------- main --- int main_texture( int argc, char **argv ) { glutInit( &argc, argv ); glutInitWindowSize( 512, 512 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( argv[0] ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); // GLenum err = glewInit(); // if (GLEW_OK != err) // { // /* Problem: glewInit failed, something is seriously wrong. */ // fprintf( stderr, "Error: %s\n", glewGetErrorString(err) ); // exit( EXIT_FAILURE ); // } // fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) ); texture_atlas_t * atlas = texture_atlas_new( 512, 512, 1 ); // const char *filename = "/Users/jie/svn/v8/deps/freetype-gl-read-only/fonts/Vera.ttf"; const char *filename = "/Users/jie/svn/v8/deps/freetype-gl-read-only/fonts/fat.ttf"; // const wchar_t *cache = L" !\"#$%&'()*+,-./0123456789:;<=>?" // L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" // L"`abcdefghijklmnopqrstuvwxyz{|}~"; wchar_t unicode[6]; unicode[0] = 22909; unicode[1] = 20320; unicode[2] = 25438; unicode[3] = 28156; unicode[4] = 48; unicode[5] = 0; wchar_t* cache = (wchar_t*)unicode; printf("%d %d\n", cache[0], wcslen(cache)); size_t minsize = 20, maxsize = 40; size_t count = maxsize - minsize; size_t i, missed = 0; for( i=minsize; i < maxsize; ++i ) { texture_font_t * font = texture_font_new( atlas, filename, i ); missed += texture_font_load_glyphs( font, cache ); texture_font_delete( font ); } printf( "Matched font : %s\n", filename ); printf( "Number of fonts : %ld\n", count ); printf( "Number of glyphs per font : %ld\n", wcslen(cache) ); printf( "Number of missed glyphs : %ld\n", missed ); printf( "Total number of glyphs : %ld/%ld\n", wcslen(cache)*count - missed, wcslen(cache)*count ); printf( "Texture size : %ldx%ld\n", atlas->width, atlas->height ); printf( "Texture occupancy : %.2f%%\n", 100.0*atlas->used/(float)(atlas->width*atlas->height) ); glClearColor(1,1,1,1); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, atlas->id ); typedef struct { float x,y,z, u,v, r,g,b,a; } vertex_t; vertex_t vertices[4] = { { 0, 0, 0, 0,1, 0,0,0,1}, { 0, 512,0, 0,0, 0,0,0,1}, { 512,512,0, 1,0, 0,0,0,1}, { 512, 0,0, 1,1, 0,0,0,1} }; GLuint indices[6] = { 0,1,2, 0,2,3 }; buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); shader = shader_load("/Users/jie/svn/v8/deps/freetype-gl-read-only/shaders/v3f-t2f-c4f.vert", "/Users/jie/svn/v8/deps/freetype-gl-read-only/shaders/v3f-t2f-c4f.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glutMainLoop( ); return 0; }
// ------------------------------------------------- texture_font_get_glyph --- texture_glyph_t * texture_font_get_glyph( texture_font_t * self, wchar_t charcode ) { assert( self ); size_t i; static wchar_t *buffer = 0; texture_glyph_t *glyph; assert( self ); assert( self->filename ); assert( self->atlas ); /* Check if charcode has been already loaded */ for( i=0; i<self->glyphs->size; ++i ) { glyph = *(texture_glyph_t **) vector_get( self->glyphs, i ); if( (glyph->charcode == charcode) && (glyph->outline_type == self->outline_type) && (glyph->outline_thickness == self->outline_thickness) ) { return glyph; } } /* charcode -1 is special : it is used for line drawing (overline, * underline, strikethrough) and background. */ if( charcode == (wchar_t)(-1) ) { size_t width = self->atlas->width; size_t height = self->atlas->height; ivec4 region = texture_atlas_get_region( self->atlas, 5, 5 ); texture_glyph_t * glyph = texture_glyph_new( ); static unsigned char data[4*4*3] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; if ( region.x < 0 ) { // fprintf( stderr, "Texture atlas is full (line %d)\n", __LINE__ ); return NULL; } #ifndef RENDERSTRING texture_atlas_set_region( self->atlas, region.x, region.y, 4, 4, data, 0 ); #else data[0]=0; #endif glyph->charcode = (wchar_t)(-1); glyph->s0 = (region.x+2)/(float)width; glyph->t0 = (region.y+2)/(float)height; glyph->s1 = (region.x+3)/(float)width; glyph->t1 = (region.y+3)/(float)height; vector_push_back( self->glyphs, &glyph ); return glyph; //*(texture_glyph_t **) vector_back( self->glyphs ); } /* Glyph has not been already loaded */ if( !buffer) { buffer = (wchar_t *) calloc( 2, sizeof(wchar_t) ); } buffer[0] = charcode; if( texture_font_load_glyphs( self, buffer ) == 0 ) { return *(texture_glyph_t **) vector_back( self->glyphs ); } return NULL; }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { FILE* test; size_t i, j; int arg; char * font_cache = " !\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~"; float font_size = 0.0; const char * font_filename = NULL; const char * header_filename = NULL; const char * variable_name = "font"; int show_help = 0; size_t texture_width = 128; for ( arg = 1; arg < argc; ++arg ) { if ( 0 == strcmp( "--font", argv[arg] ) || 0 == strcmp( "-f", argv[arg] ) ) { ++arg; if ( font_filename ) { fprintf( stderr, "Multiple --font parameters.\n" ); print_help(); exit( 1 ); } if ( arg >= argc ) { fprintf( stderr, "No font file given.\n" ); print_help(); exit( 1 ); } font_filename = argv[arg]; continue; } if ( 0 == strcmp( "--header", argv[arg] ) || 0 == strcmp( "-o", argv[arg] ) ) { ++arg; if ( header_filename ) { fprintf( stderr, "Multiple --header parameters.\n" ); print_help(); exit( 1 ); } if ( arg >= argc ) { fprintf( stderr, "No header file given.\n" ); print_help(); exit( 1 ); } header_filename = argv[arg]; continue; } if ( 0 == strcmp( "--help", argv[arg] ) || 0 == strcmp( "-h", argv[arg] ) ) { show_help = 1; break; } if ( 0 == strcmp( "--size", argv[arg] ) || 0 == strcmp( "-s", argv[arg] ) ) { ++arg; if ( 0.0 != font_size ) { fprintf( stderr, "Multiple --size parameters.\n" ); print_help(); exit( 1 ); } if ( arg >= argc ) { fprintf( stderr, "No font size given.\n" ); print_help(); exit( 1 ); } errno = 0; font_size = atof( argv[arg] ); if ( errno ) { fprintf( stderr, "No valid font size given.\n" ); print_help(); exit( 1 ); } continue; } if ( 0 == strcmp( "--variable", argv[arg] ) || 0 == strcmp( "-arg", argv[arg] ) ) { ++arg; if ( 0 != strcmp( "font", variable_name ) ) { fprintf( stderr, "Multiple --variable parameters.\n" ); print_help(); exit( 1 ); } if ( arg >= argc ) { fprintf( stderr, "No variable name given.\n" ); print_help(); exit( 1 ); } variable_name = argv[arg]; continue; } if ( 0 == strcmp( "--texture", argv[arg] ) || 0 == strcmp( "-t", argv[arg] ) ) { ++arg; if ( 128.0 != texture_width ) { fprintf( stderr, "Multiple --texture parameters.\n" ); print_help(); exit( 1 ); } if ( arg >= argc ) { fprintf( stderr, "No texture size given.\n" ); print_help(); exit( 1 ); } errno = 0; texture_width = atof( argv[arg] ); if ( errno ) { fprintf( stderr, "No valid texture size given.\n" ); print_help(); exit( 1 ); } continue; } fprintf( stderr, "Unknown parameter %s\n", argv[arg] ); print_help(); exit( 1 ); } if ( show_help ) { print_help(); exit( 1 ); } if ( !font_filename ) { fprintf( stderr, "No font file given.\n" ); print_help(); exit( 1 ); } if ( !( test = fopen( font_filename, "r" ) ) ) { fprintf( stderr, "Font file \"%s\" does not exist.\n", font_filename ); } fclose( test ); if ( 4.0 > font_size ) { fprintf( stderr, "Font size too small, expected at least 4 pt.\n" ); print_help(); exit( 1 ); } if ( !header_filename ) { fprintf( stderr, "No header file given.\n" ); print_help(); exit( 1 ); } texture_atlas_t * atlas = texture_atlas_new( texture_width, texture_width, 1 ); texture_font_t * font = texture_font_new_from_file( atlas, font_size, font_filename ); size_t missed = texture_font_load_glyphs( font, font_cache ); printf( "Font filename : %s\n" "Font size : %.1f\n" "Number of glyphs : %ld\n" "Number of missed glyphs : %ld\n" "Texture size : %ldx%ldx%ld\n" "Texture occupancy : %.2f%%\n" "\n" "Header filename : %s\n" "Variable name : %s\n", font_filename, font_size, strlen(font_cache), missed, atlas->width, atlas->height, atlas->depth, 100.0 * atlas->used / (float)(atlas->width * atlas->height), header_filename, variable_name ); size_t texture_size = atlas->width * atlas->height *atlas->depth; size_t glyph_count = font->glyphs->size; size_t max_kerning_count = 1; for( i=0; i < glyph_count; ++i ) { texture_glyph_t *glyph = *(texture_glyph_t **) vector_get( font->glyphs, i ); if( vector_size(glyph->kerning) > max_kerning_count ) { max_kerning_count = vector_size(glyph->kerning); } } FILE *file = fopen( header_filename, "w" ); // ------------- // Header // ------------- fprintf( file, "/* ============================================================================\n" " * Freetype GL - A C OpenGL Freetype engine\n" " * Platform: Any\n" " * WWW: https://github.com/rougier/freetype-gl\n" " * ----------------------------------------------------------------------------\n" " * Copyright 2011,2012 Nicolas P. Rougier. All rights reserved.\n" " *\n" " * Redistribution and use in source and binary forms, with or without\n" " * modification, are permitted provided that the following conditions are met:\n" " *\n" " * 1. Redistributions of source code must retain the above copyright notice,\n" " * this list of conditions and the following disclaimer.\n" " *\n" " * 2. Redistributions in binary form must reproduce the above copyright\n" " * notice, this list of conditions and the following disclaimer in the\n" " * documentation and/or other materials provided with the distribution.\n" " *\n" " * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR\n" " * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n" " * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n" " * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n" " * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n" " * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" " * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n" " * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" " * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n" " * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" " *\n" " * The views and conclusions contained in the software and documentation are\n" " * those of the authors and should not be interpreted as representing official\n" " * policies, either expressed or implied, of Nicolas P. Rougier.\n" " * ============================================================================\n" " */\n"); // ---------------------- // Structure declarations // ---------------------- fprintf( file, "#include <stddef.h>\n" "#include <stdint.h>\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n" "\n" "typedef struct\n" "{\n" " uint32_t codepoint;\n" " float kerning;\n" "} kerning_t;\n\n" ); fprintf( file, "typedef struct\n" "{\n" " uint32_t codepoint;\n" " int width, height;\n" " int offset_x, offset_y;\n" " float advance_x, advance_y;\n" " float s0, t0, s1, t1;\n" " size_t kerning_count;\n" " kerning_t kerning[%zu];\n" "} texture_glyph_t;\n\n", max_kerning_count ); fprintf( file, "typedef struct\n" "{\n" " size_t tex_width;\n" " size_t tex_height;\n" " size_t tex_depth;\n" " char tex_data[%zu];\n" " float size;\n" " float height;\n" " float linegap;\n" " float ascender;\n" " float descender;\n" " size_t glyphs_count;\n" " texture_glyph_t glyphs[%zu];\n" "} texture_font_t;\n\n", texture_size, glyph_count ); fprintf( file, "texture_font_t %s = {\n", variable_name ); // ------------ // Texture data // ------------ fprintf( file, " %zu, %zu, %zu, \n", atlas->width, atlas->height, atlas->depth ); fprintf( file, " {" ); for( i=0; i < texture_size; i+= 32 ) { for( j=0; j < 32 && (j+i) < texture_size ; ++ j) { if( (j+i) < (texture_size-1) ) { fprintf( file, "%d,", atlas->data[i+j] ); } else { fprintf( file, "%d", atlas->data[i+j] ); } } if( (j+i) < texture_size ) { fprintf( file, "\n " ); } } fprintf( file, "}, \n" ); // ------------------- // Texture information // ------------------- fprintf( file, " %ff, %ff, %ff, %ff, %ff, %zu, \n", font->size, font->height, font->linegap,font->ascender, font->descender, glyph_count ); // -------------- // Texture glyphs // -------------- fprintf( file, " {\n" ); for( i=0; i < glyph_count; ++i ) { texture_glyph_t * glyph = *(texture_glyph_t **) vector_get( font->glyphs, i ); /* // Debugging information printf( "glyph : '%lc'\n", glyph->codepoint ); printf( " size : %dx%d\n", glyph->width, glyph->height ); printf( " offset : %+d%+d\n", glyph->offset_x, glyph->offset_y ); printf( " advance : %ff, %ff\n", glyph->advance_x, glyph->advance_y ); printf( " tex coords.: %ff, %ff, %ff, %ff\n", glyph->u0, glyph->v0, glyph->u1, glyph->v1 ); printf( " kerning : " ); if( glyph->kerning_count ) { for( j=0; j < glyph->kerning_count; ++j ) { printf( "('%lc', %ff)", glyph->kerning[j].codepoint, glyph->kerning[j].kerning ); if( j < (glyph->kerning_count-1) ) { printf( ", " ); } } } else { printf( "None" ); } printf( "\n\n" ); */ // TextureFont fprintf( file, " {%u, ", glyph->codepoint ); fprintf( file, "%zu, %zu, ", glyph->width, glyph->height ); fprintf( file, "%d, %d, ", glyph->offset_x, glyph->offset_y ); fprintf( file, "%ff, %ff, ", glyph->advance_x, glyph->advance_y ); fprintf( file, "%ff, %ff, %ff, %ff, ", glyph->s0, glyph->t0, glyph->s1, glyph->t1 ); fprintf( file, "%zu, ", vector_size(glyph->kerning) ); if (vector_size(glyph->kerning) == 0) { fprintf( file, "0" ); } else { fprintf( file, "{ " ); for( j=0; j < vector_size(glyph->kerning); ++j ) { kerning_t *kerning = (kerning_t *) vector_get( glyph->kerning, j); fprintf( file, "{%u, %ff}", kerning->codepoint, kerning->kerning ); if( j < (vector_size(glyph->kerning)-1)) { fprintf( file, ", " ); } } fprintf( file, "}" ); } fprintf( file, " },\n" ); } fprintf( file, " }\n};\n" ); fprintf( file, "#ifdef __cplusplus\n" "}\n" "#endif\n" ); return 0; }
// ----------------------------------------------------------- build_buffer --- void build_buffer( void ) { vec2 pen; size_t i; texture_font_t *font; texture_glyph_t *glyph; vec4 white = {{1.0, 1.0, 1.0, 1.0}}; vec4 none = {{1.0, 1.0, 1.0, 0.0}}; markup_t markup = { .family = "Arial", .size = 10.0, .bold = 0, .italic = 0, .rise = 0.0, .spacing = 0.0, .gamma = 2.2, .foreground_color = white, .background_color = none, .underline = 0, .underline_color = white, .overline = 0, .overline_color = white, .strikethrough = 0, .strikethrough_color = white, .font = 0, }; vertex_buffer_clear( buffer ); texture_atlas_clear( atlas ); if( p_family == VERA) { font = texture_font_new( atlas, "fonts/Vera.ttf", p_size ); } else if( p_family == VERA_MONO) { font = texture_font_new( atlas, "fonts/VeraMono.ttf", p_size ); } else if( p_family == GEORGIA) { font = texture_font_new( atlas, "fonts/Georgia.ttf", p_size ); } else if( p_family == TIMES ) { font = texture_font_new( atlas, "fonts/Times.ttf", p_size ); } else if( p_family == TAHOMA ) { font = texture_font_new( atlas, "fonts/Tahoma.ttf", p_size ); } else if( p_family == ARIAL ) { font = texture_font_new( atlas, "fonts/Arial.ttf", p_size ); } else if( p_family == VERDANA ) { font = texture_font_new( atlas, "fonts/Verdana.ttf", p_size ); } else { fprintf( stderr, "Error : Unknown family type\n" ); return; } font->hinting = p_hinting; font->filtering = 1; float norm = 1.0/(p_primary + 2*p_secondary + 2*p_tertiary); font->lcd_weights[0] = (unsigned char)(p_tertiary*norm*256); font->lcd_weights[1] = (unsigned char)(p_secondary*norm*256); font->lcd_weights[2] = (unsigned char)(p_primary*norm*256); font->lcd_weights[3] = (unsigned char)(p_secondary*norm*256); font->lcd_weights[4] = (unsigned char)(p_tertiary*norm*256); texture_font_load_glyphs( font, L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~" ); pen.x = 10; pen.y = 600 - font->height - 10; glyph = texture_font_get_glyph( font, text[0] ); add_glyph( glyph, buffer, &markup, &pen, 0 ); for( i=1; i<wcslen(text); ++i ) { if( text[i] == '\n' ) { pen.x = 10; pen.y -= font->height; // + 0.01*(size - (int)size)*font->height; } else { glyph = texture_font_get_glyph( font, text[i] ); float kerning = 0.0; if( p_kerning ) { kerning = texture_glyph_get_kerning( glyph, text[i-1] ); } add_glyph( glyph, buffer, &markup, &pen, kerning ); } } texture_font_delete (font ); } // ---------------------------------------------------------------- display --- void display(void) { if( p_invert ) { glClearColor( 0, 0, 0, 1 ); } else { glClearColor( 1, 1, 1, 1 ); } glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, atlas->id ); if( !p_lcd_filtering ) { glEnable( GL_COLOR_MATERIAL ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); if( p_invert ) { glColor4f(1,1,1,1); } else { glColor4f(0,0,0,1); } } else { glEnable( GL_COLOR_MATERIAL ); glBlendFunc( GL_CONSTANT_COLOR_EXT, GL_ONE_MINUS_SRC_COLOR ); glEnable( GL_BLEND ); glColor3f( 1,1,1 ); if( p_invert ) { glBlendColor( 1, 1, 1, 1 ); } else { glBlendColor( 0, 0, 0, 1 ); } } if( !p_lcd_filtering ) { vertex_buffer_render( buffer, GL_TRIANGLES, "vt" ); } else { glUseProgram( program ); glUniform1i( texture_location, 0 ); glUniform1f( gamma_location, p_gamma ); float norm = 1.0/(p_primary+2*p_secondary+2*p_tertiary); glUniform1f( primary_location, p_primary*norm ); glUniform1f( secondary_location, p_secondary*norm ); glUniform1f( tertiary_location, p_tertiary*norm ); glUniform2f( pixel_location, 1.0/atlas->width, 1.0/atlas->height ); vertex_buffer_render( buffer, GL_TRIANGLES, "vtc" ); glUseProgram( 0 ); } TwDraw( ); glutSwapBuffers( ); } // ---------------------------------------------------------------- reshape --- void reshape( int width, int height ) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, width, 0, height, -1, 1); glMatrixMode(GL_MODELVIEW); TwWindowSize( width, height ); }
size_t TextureFont::LoadGlyphs(const wchar_t* charcodes) { return texture_font_load_glyphs(static_cast<texture_font_t*>(self_), charcodes); }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { GLFWwindow* window; glfwSetErrorCallback( error_callback ); if (!glfwInit( )) { exit( EXIT_FAILURE ); } glfwWindowHint( GLFW_VISIBLE, GL_TRUE ); glfwWindowHint( GLFW_RESIZABLE, GL_FALSE ); window = glfwCreateWindow( 1, 1, "Freetype OpenGL / LCD filtering", NULL, NULL ); if (!window) { glfwTerminate( ); exit( EXIT_FAILURE ); } glfwMakeContextCurrent( window ); glfwSwapInterval( 1 ); glfwSetFramebufferSizeCallback( window, reshape ); glfwSetWindowRefreshCallback( window, display ); glfwSetKeyCallback( window, keyboard ); #ifndef __APPLE__ glewExperimental = GL_TRUE; GLenum err = glewInit(); if (GLEW_OK != err) { /* Problem: glewInit failed, something is seriously wrong. */ fprintf( stderr, "Error: %s\n", glewGetErrorString(err) ); exit( EXIT_FAILURE ); } fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) ); #endif size_t i; texture_font_t *font = 0; atlas = texture_atlas_new( 512, 512, 3 ); const char * filename = "fonts/Vera.ttf"; wchar_t *text = L"A Quick Brown Fox Jumps Over The Lazy Dog 0123456789"; buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f,ashift:1f,agamma:1f" ); vec2 pen = {{0,0}}; vec4 color = {{0,0,0,1}}; for( i=7; i < 27; ++i) { font = texture_font_new_from_file( atlas, i, filename ); pen.x = 0; pen.y -= font->height; texture_font_load_glyphs( font, text ); add_text( buffer, font, text, &color, &pen ); texture_font_delete( font ); } glBindTexture( GL_TEXTURE_2D, atlas->id ); shader = shader_load( "shaders/text.vert", "shaders/text.frag" ); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glfwSetWindowSize( window, 800, 500 ); glfwShowWindow( window ); while(!glfwWindowShouldClose( window )) { display( window ); glfwPollEvents( ); } glfwDestroyWindow( window ); glfwTerminate( ); return 0; }
// ------------------------------------------------------------------- init --- void init( void ) { size_t i, j; texture_atlas_t * atlas = texture_atlas_new( 512, 512, 3 ); texture_font_t *fonts[20]; for ( i=0; i< 20; ++i ) { fonts[i] = texture_font_new_from_file(atlas, 12+i, font_filename), texture_font_load_glyphs(fonts[i], text, direction, language, script ); } typedef struct { float x,y,z, u,v, r,g,b,a, shift, gamma; } vertex_t; vbuffer = vertex_buffer_new( "vertex:3f,tex_coord:2f," "color:4f,ashift:1f,agamma:1f" ); /* Create a buffer for harfbuzz to use */ hb_buffer_t *buffer = hb_buffer_create(); for (i=0; i < 20; ++i) { hb_buffer_set_direction( buffer, direction ); hb_buffer_set_script( buffer, script ); hb_buffer_set_language( buffer, hb_language_from_string(language, strlen(language)) ); hb_buffer_add_utf8( buffer, text, strlen(text), 0, strlen(text) ); hb_shape( fonts[i]->hb_ft_font, buffer, NULL, 0 ); unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buffer, &glyph_count); texture_font_load_glyphs( fonts[i], text, direction, language, script ); float gamma = 1.0; float shift = 0.0; float x = 0; float y = 600 - i * (10+i) - 15; float width = 0.0; float hres = fonts[i]->hres; for (j = 0; j < glyph_count; ++j) { int codepoint = glyph_info[j].codepoint; float x_advance = glyph_pos[j].x_advance/(float)(hres*64); float x_offset = glyph_pos[j].x_offset/(float)(hres*64); texture_glyph_t *glyph = texture_font_get_glyph(fonts[i], codepoint); if( i < (glyph_count-1) ) width += x_advance + x_offset; else width += glyph->offset_x + glyph->width; } x = 800 - width - 10 ; for (j = 0; j < glyph_count; ++j) { int codepoint = glyph_info[j].codepoint; // because of vhinting trick we need the extra 64 (hres) float x_advance = glyph_pos[j].x_advance/(float)(hres*64); float x_offset = glyph_pos[j].x_offset/(float)(hres*64); float y_advance = glyph_pos[j].y_advance/(float)(64); float y_offset = glyph_pos[j].y_offset/(float)(64); texture_glyph_t *glyph = texture_font_get_glyph(fonts[i], codepoint); float r = 0.0; float g = 0.0; float b = 0.0; float a = 1.0; float x0 = x + x_offset + glyph->offset_x; float x1 = x0 + glyph->width; float y0 = floor(y + y_offset + glyph->offset_y); float y1 = floor(y0 - glyph->height); float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; vertex_t vertices[4] = { {x0,y0,0, s0,t0, r,g,b,a, shift, gamma}, {x0,y1,0, s0,t1, r,g,b,a, shift, gamma}, {x1,y1,0, s1,t1, r,g,b,a, shift, gamma}, {x1,y0,0, s1,t0, r,g,b,a, shift, gamma} }; GLuint indices[6] = { 0,1,2, 0,2,3 }; vertex_buffer_push_back( vbuffer, vertices, 4, indices, 6 ); x += x_advance; y += y_advance; } /* clean up the buffer, but don't kill it just yet */ hb_buffer_reset(buffer); } glClearColor(1,1,1,1); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, atlas->id ); texture_atlas_upload( atlas ); vertex_buffer_upload( vbuffer ); shader = shader_load("shaders/text.vert", "shaders/text.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { size_t i, j; wchar_t * font_cache = L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~"; float font_size = 16.0; char * font_filename = "fonts/Arial.ttf"; char * header_filename = "arial-16.h"; texture_atlas_t * atlas = texture_atlas_new( 128, 128, 1 ); texture_font_t * font = texture_font_new( atlas, font_filename, font_size ); glutInit( &argc, argv ); glutInitWindowSize( atlas->width, atlas->height ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( "Freetype OpenGL" ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); size_t missed = texture_font_load_glyphs( font, font_cache ); wprintf( L"Font filename : %s\n", font_filename ); wprintf( L"Font size : %.1f\n", font_size ); wprintf( L"Number of glyphs : %ld\n", wcslen(font_cache) ); wprintf( L"Number of missed glyphs : %ld\n", missed ); wprintf( L"Texture size : %ldx%ldx%ld\n", atlas->width, atlas->height, atlas->depth ); wprintf( L"Texture occupancy : %.2f%%\n", 100.0*atlas->used/(float)(atlas->width*atlas->height) ); wprintf( L"\n" ); wprintf( L"Header filename : %s\n", header_filename ); size_t texture_size = atlas->width * atlas->height *atlas->depth; size_t glyph_count = font->glyphs->size; size_t max_kerning_count = 1; for( i=0; i < glyph_count; ++i ) { texture_glyph_t *glyph = *(texture_glyph_t **) vector_get( font->glyphs, i ); if( vector_size(glyph->kerning) > max_kerning_count ) { max_kerning_count = vector_size(glyph->kerning); } } FILE *file = fopen( header_filename, "w" ); // ------------- // Header // ------------- fwprintf( file, L"/* ============================================================================\n" L" * Freetype GL - A C OpenGL Freetype engine\n" L" * Platform: Any\n" L" * WWW: http://code.google.com/p/freetype-gl/\n" L" * ----------------------------------------------------------------------------\n" L" * Copyright 2011,2012 Nicolas P. Rougier. All rights reserved.\n" L" *\n" L" * Redistribution and use in source and binary forms, with or without\n" L" * modification, are permitted provided that the following conditions are met:\n" L" *\n" L" * 1. Redistributions of source code must retain the above copyright notice,\n" L" * this list of conditions and the following disclaimer.\n" L" *\n" L" * 2. Redistributions in binary form must reproduce the above copyright\n" L" * notice, this list of conditions and the following disclaimer in the\n" L" * documentation and/or other materials provided with the distribution.\n" L" *\n" L" * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR\n" L" * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n" L" * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n" L" * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n" L" * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n" L" * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" L" * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n" L" * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" L" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n" L" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" L" *\n" L" * The views and conclusions contained in the software and documentation are\n" L" * those of the authors and should not be interpreted as representing official\n" L" * policies, either expressed or implied, of Nicolas P. Rougier.\n" L" * ===============================================================================\n" L" */\n"); // ---------------------- // Structure declarations // ---------------------- fwprintf( file, L"#include <stddef.h>\n" L"#ifdef __cplusplus\n" L"extern \"C\" {\n" L"#endif\n" L"\n" L"typedef struct\n" L"{\n" L" wchar_t charcode;\n" L" float kerning;\n" L"} kerning_t;\n\n" ); fwprintf( file, L"typedef struct\n" L"{\n" L" wchar_t charcode;\n" L" int width, height;\n" L" int offset_x, offset_y;\n" L" float advance_x, advance_y;\n" L" float s0, t0, s1, t1;\n" L" size_t kerning_count;\n" L" kerning_t kerning[%d];\n" L"} texture_glyph_t;\n\n", max_kerning_count ); fwprintf( file, L"typedef struct\n" L"{\n" L" size_t tex_width;\n" L" size_t tex_height;\n" L" size_t tex_depth;\n" L" char tex_data[%d];\n" L" float size;\n" L" float height;\n" L" float linegap;\n" L" float ascender;\n" L" float descender;\n" L" size_t glyphs_count;\n" L" texture_glyph_t glyphs[%d];\n" L"} texture_font_t;\n\n", texture_size, glyph_count ); fwprintf( file, L"texture_font_t font = {\n" ); // ------------ // Texture data // ------------ fwprintf( file, L" %d, %d, %d, \n", atlas->width, atlas->height, atlas->depth ); fwprintf( file, L" {" ); for( i=0; i < texture_size; i+= 32 ) { for( j=0; j < 32 && (j+i) < texture_size ; ++ j) { if( (j+i) < (texture_size-1) ) { fwprintf( file, L"%d,", atlas->data[i+j] ); } else { fwprintf( file, L"%d", atlas->data[i+j] ); } } if( (j+i) < texture_size ) { fwprintf( file, L"\n " ); } } fwprintf( file, L"}, \n" ); // ------------------- // Texture information // ------------------- fwprintf( file, L" %ff, %ff, %ff, %ff, %ff, %d, \n", font->size, font->height, font->linegap,font->ascender, font->descender, glyph_count ); // -------------- // Texture glyphs // -------------- fwprintf( file, L" {\n" ); for( i=0; i < glyph_count; ++i ) { texture_glyph_t * glyph = *(texture_glyph_t **) vector_get( font->glyphs, i ); /* // Debugging information wprintf( L"glyph : '%lc'\n", glyph->charcode ); wprintf( L" size : %dx%d\n", glyph->width, glyph->height ); wprintf( L" offset : %+d%+d\n", glyph->offset_x, glyph->offset_y ); wprintf( L" advance : %ff, %ff\n", glyph->advance_x, glyph->advance_y ); wprintf( L" tex coords.: %ff, %ff, %ff, %ff\n", glyph->u0, glyph->v0, glyph->u1, glyph->v1 ); wprintf( L" kerning : " ); if( glyph->kerning_count ) { for( j=0; j < glyph->kerning_count; ++j ) { wprintf( L"('%lc', %ff)", glyph->kerning[j].charcode, glyph->kerning[j].kerning ); if( j < (glyph->kerning_count-1) ) { wprintf( L", " ); } } } else { wprintf( L"None" ); } wprintf( L"\n\n" ); */ // TextureFont if( (glyph->charcode == L'\'' ) || (glyph->charcode == L'\\' ) ) { fwprintf( file, L" {L'\\%lc', ", glyph->charcode ); //wprintf( L" {L'\\%lc', ", glyph->charcode ); } else if( glyph->charcode == (wchar_t)(-1) ) { fwprintf( file, L" {L'\\0', " ); //wprintf( L" {L'\\0', " ); } else { fwprintf( file, L" {L'%lc', ", glyph->charcode ); //wprintf( L" {L'%lc', ", glyph->charcode ); } fwprintf( file, L"%d, %d, ", glyph->width, glyph->height ); fwprintf( file, L"%d, %d, ", glyph->offset_x, glyph->offset_y ); fwprintf( file, L"%ff, %ff, ", glyph->advance_x, glyph->advance_y ); fwprintf( file, L"%ff, %ff, %ff, %ff, ", glyph->s0, glyph->t0, glyph->s1, glyph->t1 ); fwprintf( file, L"%d, ", vector_size(glyph->kerning) ); fwprintf( file, L"{ " ); for( j=0; j < vector_size(glyph->kerning); ++j ) { kerning_t *kerning = (kerning_t *) vector_get( glyph->kerning, j); wchar_t charcode = kerning->charcode; if( (charcode == L'\'' ) || (charcode == L'\\') ) { fwprintf( file, L"{L'\\%lc', %ff}", charcode, kerning->kerning ); } else if( (charcode != (wchar_t)(-1) ) ) { fwprintf( file, L"{L'%lc', %ff}", charcode, kerning->kerning ); } if( j < (vector_size(glyph->kerning)-1)) { fwprintf( file, L", " ); } } fwprintf( file, L"} },\n" ); } fwprintf( file, L" }\n};\n" ); fwprintf( file, L"#ifdef __cplusplus\n" L"}\n" L"#endif\n" ); return 0; }