// ------------------------------------------------------------------- init --- void init( void ) { size_t i; vec2 pen = {{0,0}}; vec4 color = {{0,0,0,1}}; atlas = texture_atlas_new( 512, 512, 1 ); font = texture_font_new_from_file( atlas, 12, "../media/fonts/VeraMono.ttf" ); buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); pen.y = -font->descender; for( i=0; i<line_count; ++i ) { pen.x = 10.0; add_text( buffer, font, text, &color, &pen ); pen.y += font->height - font->linegap; } glClearColor( 1.0, 1.0, 1.0, 1.0 ); glDisable( GL_DEPTH_TEST ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_TEXTURE_2D ); glEnable( GL_BLEND ); shader = shader_load("../media/shaders/v3f-t2f-c4f.vert", "../media/shaders/v3f-t2f-c4f.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }
TextureFont::TextureFont(TextureAtlas* atlas, const std::string& filename, const float size ) : self_(texture_font_new_from_file(static_cast<texture_atlas_t*>(atlas->RawGet()), size, filename.c_str())), atlas_(atlas) {}
// ------------------------------------------------------------------- init --- void init( void ) { atlas = texture_atlas_new( 512, 512, 1 ); auto filename = "fonts/Vera.ttf"; auto text = "A Quick Brown Fox Jumps Over The Lazy Dog 0123456789"; buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); vec2 pen = {0,0}; auto black = vec4{1,1,1,1}; auto font = texture_font_new_from_file( atlas, 48, filename ); font->rendermode = RENDER_SIGNED_DISTANCE_FIELD; auto bbox = add_text( buffer, font, text, &black, &pen ); size_t i; auto vertices = buffer->vertices; for( i=0; i< vector_size(vertices); ++i ) { auto vert = (vertex *) vector_get(vertices,i); vert->x -= (int)(bbox.x + bbox.width/2); vert->y -= (int)(bbox.y + bbox.height/2); } 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_RED, atlas->width, atlas->height, 0, GL_RED, GL_UNSIGNED_BYTE, atlas->data ); shader = shader_load( "shaders/distance-field-2v5.vert", "shaders/distance-field-2v5.frag" ); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }
// ------------------------------------------------------------------- init --- void init( void ) { atlas = texture_atlas_new( 512, 512, 1 ); font = texture_font_new_from_file( atlas, 32, "../media/fonts/Vera.ttf" ); texture_glyph_t *glyph; // Generate the glyp at 512 points, compute distance field and scale it // back to 32 points // Just load another glyph if you want to see difference (draw render a '@') glyph = load_glyph( "../media/fonts/Vera.ttf", "@", 512, 64, 0.1); vector_push_back( font->glyphs, &glyph ); texture_atlas_upload( atlas ); glyph = texture_font_get_glyph( font, "@"); GLuint indices[6] = {0,1,2, 0,2,3}; vertex_t vertices[4] = { { -.5,-.5,0, glyph->s0,glyph->t1, 0,0,0,1 }, { -.5, .5,0, glyph->s0,glyph->t0, 0,0,0,1 }, { .5, .5,0, glyph->s1,glyph->t0, 0,0,0,1 }, { .5,-.5,0, glyph->s1,glyph->t1, 0,0,0,1 } }; buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); program = shader_load( "../media/shaders/distance-field.vert", "../media/shaders/distance-field-2.frag" ); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }
// ----------------------------------------- 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; }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitWindowSize( 800, 600 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( "Signed Distance Field" ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutKeyboardFunc( 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_font_t *font = 0; texture_atlas_t *atlas = texture_atlas_new( 512, 512, 1 ); 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" ); vec2 pen = {{0,0}}; vec4 black = {{1,1,1,1}}; font = texture_font_new_from_file( atlas, 48, filename ); vec4 bbox = add_text( buffer, font, text, &black, &pen ); size_t i; vector_t * vertices = buffer->vertices; for( i=0; i< vector_size(vertices); ++i ) { vertex_t * vertex = (vertex_t *) vector_get(vertices,i); vertex->x -= (int)(bbox.x + bbox.width/2); vertex->y -= (int)(bbox.y + bbox.height/2); } glBindTexture( GL_TEXTURE_2D, atlas->id ); fprintf( stderr, "Generating distance map...\n" ); unsigned char *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 ); shader = shader_load( "shaders/distance-field-2.vert", "shaders/distance-field-2.frag" ); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glutMainLoop( ); return 0; }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { size_t width = 800, height = 200; glutInit( &argc, argv ); glutInitWindowSize( width, height ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( "Glyph Cartoon" ); 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) ); atlas = texture_atlas_new( 1024, 1024, 1 ); buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); texture_font_t *font = texture_font_new_from_file( atlas, 128, "fonts/ObelixPro.ttf" ); vec2 pen = {{50, 50}}; vec4 black = {{0.0, 0.0, 0.0, 1.0}}; vec4 yellow = {{1.0, 1.0, 0.0, 1.0}}; vec4 orange1 = {{1.0, 0.9, 0.0, 1.0}}; vec4 orange2 = {{1.0, 0.6, 0.0, 1.0}}; font->outline_type = 2; font->outline_thickness = 7; add_text( buffer, font, L"Freetype GL", pen, black, black ); font->outline_type = 2; font->outline_thickness = 5; add_text( buffer, font, L"Freetype GL", pen, yellow, yellow ); font->outline_type = 1; font->outline_thickness = 3; add_text( buffer, font, L"Freetype GL", pen, black, black ); font->outline_type = 0; font->outline_thickness = 0; add_text( buffer, font, L"Freetype GL", pen, orange1, orange2 ); shader = shader_load("shaders/v3f-t2f-c4f.vert", "shaders/v3f-t2f-c4f.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); 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; }
// ------------------------------------------------------------------- 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; }
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); }
// ------------------------------------------------------------------- init --- void init( void ) { atlas = texture_atlas_new( 1024, 1024, 1 ); buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); texture_font_t *font = texture_font_new_from_file( atlas, 128, "fonts/LuckiestGuy.ttf" ); vec2 pen = {{50, 50}}; vec4 black = {{0.0, 0.0, 0.0, 1.0}}; vec4 yellow = {{1.0, 1.0, 0.0, 1.0}}; vec4 orange1 = {{1.0, 0.9, 0.0, 1.0}}; vec4 orange2 = {{1.0, 0.6, 0.0, 1.0}}; font->rendermode = RENDER_OUTLINE_POSITIVE; font->outline_thickness = 7; add_text( buffer, font, "Freetype GL", pen, black, black ); font->rendermode = RENDER_OUTLINE_POSITIVE; font->outline_thickness = 5; add_text( buffer, font, "Freetype GL", pen, yellow, yellow ); font->rendermode = RENDER_OUTLINE_EDGE; font->outline_thickness = 3; add_text( buffer, font, "Freetype GL", pen, black, black ); font->rendermode = RENDER_NORMAL; font->outline_thickness = 0; add_text( buffer, font, "Freetype GL", pen, orange1, orange2 ); 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_RED, atlas->width, atlas->height, 0, GL_RED, GL_UNSIGNED_BYTE, atlas->data ); shader = shader_load("shaders/v3f-t2f-c4f.vert", "shaders/v3f-t2f-c4f.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitWindowSize( 512, 512 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( "Distance fields demo" ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); glutTimerFunc( 1000.0/60, timer, 60 ); 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) ); program = shader_load( "shaders/distance-field.vert", "shaders/distance-field-3.frag" ); glUseProgram( program ); atlas = texture_atlas_new( 512, 512, 1 ); font = texture_font_new_from_file( atlas, 32, "fonts/Vera.ttf" ); texture_glyph_t *glyph; // Generate the glyp at 512 points, compute distance field and scale it // back to 32 points // Just load another glyph if you want to see difference (draw render a '@') glyph = load_glyph( "fonts/Vera.ttf", L'@', 512, 64, 0.1); vector_push_back( font->glyphs, &glyph ); texture_atlas_upload( atlas ); glutMainLoop( ); return 0; }
// ------------------------------------------------------------------- init --- void init( void ) { texture_font_t *font = 0; texture_atlas_t *atlas = texture_atlas_new( 512, 512, 1 ); 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" ); vec2 pen = {{0,0}}; vec4 black = {{1,1,1,1}}; font = texture_font_new_from_file( atlas, 48, filename ); vec4 bbox = add_text( buffer, font, text, &black, &pen ); texture_atlas_upload( font->atlas ); size_t i; vector_t * vertices = buffer->vertices; for( i=0; i< vector_size(vertices); ++i ) { vertex_t * vertex = (vertex_t *) vector_get(vertices,i); vertex->x -= (int)(bbox.x + bbox.width/2); vertex->y -= (int)(bbox.y + bbox.height/2); } glBindTexture( GL_TEXTURE_2D, atlas->id ); fprintf( stderr, "Generating distance map...\n" ); unsigned char *map = make_distance_mapb(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 ); shader = shader_load( "shaders/distance-field.vert", "shaders/distance-field-2.frag" ); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }
// ------------------------------------------------------------------- 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 ); }
// ------------------------------------------------------------------- init --- void init( void ) { size_t i; atlas = texture_atlas_new( 512, 512, 1 ); buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); vec4 white = {{1.0, 1.0, 1.0, 1.0}}; vec4 none = {{1.0, 1.0, 1.0, 0.0}}; markup_t markup; markup.family = "../media/fonts/Vera.ttf"; markup.size = 80.0; markup.bold = 0; markup.italic = 0; markup.rise = 0.0; markup.spacing = 0.0; markup.gamma = 1.5; markup.foreground_color = white; markup.background_color = none; markup.underline = 0; markup.underline_color = white; markup.overline = 0; markup.overline_color = white; markup.strikethrough = 0; markup.strikethrough_color = white; markup.font = 0; markup.font = texture_font_new_from_file( atlas, markup.size, "../media/fonts/Vera.ttf" ); markup.font->outline_type = 1; vec2 pen; pen.x = 40; pen.y = 190; for( i=0; i< 10; ++i) { markup.font->outline_thickness = 2*((i+1)/10.0); add_text( buffer, &pen, &markup, "g", NULL ); } pen.x = 40; pen.y = 110; markup.font->outline_type = 2; for( i=0; i< 10; ++i) { markup.font->outline_thickness = 2*((i+1)/10.0); add_text( buffer, &pen, &markup, "g", NULL ); } pen.x = 40; pen.y = 30; markup.font->outline_type = 3; for( i=0; i< 10; ++i) { markup.font->outline_thickness = 1*((i+1)/10.0); add_text( buffer, &pen, &markup, "g", NULL ); } shader = shader_load("../media/shaders/v3f-t2f-c4f.vert", "../media/shaders/v3f-t2f-c4f.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); }
// ------------------------------------------------------------------- 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, "Glyph Cartoon", NULL, NULL ); if (!window) { glfwTerminate( ); exit( EXIT_FAILURE ); } glfwMakeContextCurrent( window ); glfwSwapInterval( 1 ); glfwSetFramebufferSizeCallback( window, reshape ); glfwSetWindowRefreshCallback( window, display ); glfwSetKeyCallback( window, keyboard ); #ifndef __APPLE__ 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 atlas = texture_atlas_new( 1024, 1024, 1 ); buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); texture_font_t *font = texture_font_new_from_file( atlas, 128, "fonts/LuckiestGuy.ttf" ); vec2 pen = {{50, 50}}; vec4 black = {{0.0, 0.0, 0.0, 1.0}}; vec4 yellow = {{1.0, 1.0, 0.0, 1.0}}; vec4 orange1 = {{1.0, 0.9, 0.0, 1.0}}; vec4 orange2 = {{1.0, 0.6, 0.0, 1.0}}; font->outline_type = 2; font->outline_thickness = 7; add_text( buffer, font, L"Freetype GL", pen, black, black ); font->outline_type = 2; font->outline_thickness = 5; add_text( buffer, font, L"Freetype GL", pen, yellow, yellow ); font->outline_type = 1; font->outline_thickness = 3; add_text( buffer, font, L"Freetype GL", pen, black, black ); font->outline_type = 0; font->outline_thickness = 0; add_text( buffer, font, L"Freetype GL", pen, orange1, orange2 ); shader = shader_load("shaders/v3f-t2f-c4f.vert", "shaders/v3f-t2f-c4f.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glfwSetWindowSize( window, 850, 200 ); glfwShowWindow( window ); while(!glfwWindowShouldClose( window )) { display( window ); glfwPollEvents( ); } glfwDestroyWindow( window ); glfwTerminate( ); return 0; }
// ----------------------------------------------------------- build_buffer --- void build_buffer( void ) { vec2 pen; texture_font_t *font; vec4 black = {{0.0, 0.0, 0.0, 1.0}}; vec4 white = {{1.0, 1.0, 1.0, 1.0}}; vec4 none = {{1.0, 1.0, 1.0, 0.0}}; vec4 color = white; if( p_invert ) { color = black; } markup_t markup = { .family = "Source Sans Pro", .size = 10.0, .bold = 0, .italic = 0, .spacing = p_interval, .gamma = p_gamma, .foreground_color = color, .background_color = none, .underline = 0, .underline_color = color, .overline = 0, .overline_color = color, .strikethrough = 0, .strikethrough_color = color, .font = 0, }; text_buffer_clear( text_buffer ); texture_atlas_t * atlas = font_manager->atlas; texture_atlas_clear( atlas ); if( p_family == VERA) { font = texture_font_new_from_file( atlas, p_size, "fonts/Vera.ttf" ); } else if( p_family == VERA_MONO) { font = texture_font_new_from_file( atlas, p_size, "fonts/VeraMono.ttf" ); } else if( p_family == LUCKIEST_GUY) { font = texture_font_new_from_file( atlas, p_size, "fonts/LuckiestGuy.ttf" ); } else if( p_family == SOURCE_SANS ) { font = texture_font_new_from_file( atlas, p_size, "fonts/SourceSansPro-Regular.ttf" ); } else if( p_family == SOURCE_CODE ) { font = texture_font_new_from_file( atlas, p_size, "fonts/SourceCodePro-Regular.ttf" ); } else if( p_family == OLD_STANDARD ) { font = texture_font_new_from_file( atlas, p_size, "fonts/OldStandard-Regular.ttf" ); } else if( p_family == LOBSTER ) { font = texture_font_new_from_file( atlas, p_size, "fonts/Lobster-Regular.ttf" ); } else { fprintf( stderr, "Error : Unknown family type\n" ); return; } if (!font) return; markup.font = font; font->hinting = p_hinting; font->kerning = p_kerning; font->filtering = 1; float norm = 1.0/(p_primary + 2*p_secondary + 2*p_tertiary); font->lcd_weights[0] = (unsigned char)(p_tertiary*norm*255); font->lcd_weights[1] = (unsigned char)(p_secondary*norm*255); font->lcd_weights[2] = (unsigned char)(p_primary*norm*255); font->lcd_weights[3] = (unsigned char)(p_secondary*norm*255); font->lcd_weights[4] = (unsigned char)(p_tertiary*norm*255); pen.x = 10; pen.y = 600 - font->height - 10; text_buffer_printf( text_buffer, &pen, &markup, text, NULL ); // Post-processing for width and orientation vertex_buffer_t * vbuffer = text_buffer->buffer; size_t i; for( i=0; i < vector_size( vbuffer->items ); ++i ) { ivec4 *item = (ivec4 *) vector_get( vbuffer->items, i); glyph_vertex_t * v0 = /* x0,y0 */ (glyph_vertex_t *) vector_get( vbuffer->vertices, item->vstart+0 ); //glyph_vertex_t * v1 = /* x0,y1 */ // (glyph_vertex_t *) vector_get( vbuffer->vertices, item->vstart+1 ); glyph_vertex_t * v2 = /* x1,y1 */ (glyph_vertex_t *) vector_get( vbuffer->vertices, item->vstart+2 ); glyph_vertex_t * v3 = /* x1,y0 */ (glyph_vertex_t *) vector_get( vbuffer->vertices, item->vstart+3 ); float x0 = v0->x, y0 = v0->y; float x1 = v2->x, y1 = v2->y; v2->x = v3->x = x0 + (x1-x0)*p_width; float dy = fabs(y1-y0); float dx = tan(p_faux_italic/180.0 * M_PI) * dy; v0->x += dx; v0->shift = fmod(v0->shift + dx-(int)(dx),1.0); v3->x += dx; v3->shift = fmod(v3->shift + dx-(int)(dx),1.0); } glBindTexture( GL_TEXTURE_2D, font_manager->atlas->id ); GLenum gl_format = (font_manager->atlas->depth == LCD_FILTERING_OFF) ? GL_RED : GL_RGB; glTexImage2D( GL_TEXTURE_2D, 0, gl_format, font_manager->atlas->width, font_manager->atlas->height, 0, gl_format, GL_UNSIGNED_BYTE, font_manager->atlas->data ); texture_font_delete( font ); } // ------------------------------------------------------------------- quit --- void reset( void ) { p_family = VERA; p_size = 12.0; p_invert = 0; p_kerning = 1; p_hinting = 1; p_lcd_filtering = 1; p_gamma = 1.75; p_interval = 0.0; p_weight = 0.33; p_width = 1.0; p_faux_weight = 0.0; p_faux_italic = 0.0; // FT_LCD_FILTER_LIGHT p_primary = 1.0/3.0; p_secondary = 1.0/3.0; p_tertiary = 0.0/3.0; // FT_LCD_FILTER_DEFAULT // p_primary = 3.0/9.0; // p_secondary = 2.0/9.0; // p_tertiary = 1.0/9.0; build_buffer(); }
// ----------------------------------------------------------- build_buffer --- void build_buffer( void ) { vec2 pen; texture_font_t *font; vec4 black = {{0.0, 0.0, 0.0, 1.0}}; vec4 white = {{1.0, 1.0, 1.0, 1.0}}; vec4 none = {{1.0, 1.0, 1.0, 0.0}}; vec4 color = white; if( p_invert ) { color = black; } markup_t markup = { .family = "Source Sans Pro", .size = 10.0, .bold = 0, .italic = 0, .rise = 0.0, .spacing = p_interval, .gamma = p_gamma, .foreground_color = color, .background_color = none, .underline = 0, .underline_color = color, .overline = 0, .overline_color = color, .strikethrough = 0, .strikethrough_color = color, .font = 0, }; text_buffer_clear( buffer ); texture_atlas_t * atlas = buffer->manager->atlas; texture_atlas_clear( atlas ); if( p_family == VERA) { font = texture_font_new_from_file( atlas, p_size, "fonts/Vera.ttf" ); } else if( p_family == VERA_MONO) { font = texture_font_new_from_file( atlas, p_size, "fonts/VeraMono.ttf" ); } else if( p_family == LUCKIEST_GUY) { font = texture_font_new_from_file( atlas, p_size, "fonts/LuckiestGuy.ttf" ); } else if( p_family == SOURCE_SANS ) { font = texture_font_new_from_file( atlas, p_size, "fonts/SourceSansPro-Regular.ttf" ); } else if( p_family == SOURCE_CODE ) { font = texture_font_new_from_file( atlas, p_size, "fonts/SourceCodePro-Regular.ttf" ); } else if( p_family == OLD_STANDARD ) { font = texture_font_new_from_file( atlas, p_size, "fonts/OldStandard-Regular.ttf" ); } else if( p_family == LOBSTER ) { font = texture_font_new_from_file( atlas, p_size, "fonts/Lobster-Regular.ttf" ); } else { fprintf( stderr, "Error : Unknown family type\n" ); return; } if (!font) return; markup.font = font; font->hinting = p_hinting; font->kerning = p_kerning; 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); pen.x = 10; pen.y = 600 - font->height - 10; text_buffer_printf( buffer, &pen, &markup, text, NULL ); // Post-processing for width and orientation vertex_buffer_t * vbuffer = buffer->buffer; size_t i; for( i=0; i < vector_size( vbuffer->items ); ++i ) { ivec4 *item = (ivec4 *) vector_get( vbuffer->items, i); glyph_vertex_t * v0 = /* x0,y0 */ (glyph_vertex_t *) vector_get( vbuffer->vertices, item->vstart+0 ); //glyph_vertex_t * v1 = /* x0,y1 */ // (glyph_vertex_t *) vector_get( vbuffer->vertices, item->vstart+1 ); glyph_vertex_t * v2 = /* x1,y1 */ (glyph_vertex_t *) vector_get( vbuffer->vertices, item->vstart+2 ); glyph_vertex_t * v3 = /* x1,y0 */ (glyph_vertex_t *) vector_get( vbuffer->vertices, item->vstart+3 ); float x0 = v0->x, y0 = v0->y; float x1 = v2->x, y1 = v2->y; v2->x = v3->x = x0 + (x1-x0)*p_width; float dy = abs(y1-y0); float dx = tan(p_faux_italic/180.0 * M_PI) * dy; v0->x += dx; v0->shift = fmod(v0->shift + dx-(int)(dx),1.0); v3->x += dx; v3->shift = fmod(v3->shift + dx-(int)(dx),1.0); } texture_font_delete( font ); } // ---------------------------------------------------------------- display --- void display( GLFWwindow* window ) { vec4 black = {{0.0, 0.0, 0.0, 1.0}}; vec4 white = {{1.0, 1.0, 1.0, 1.0}}; if( !p_invert ) { glClearColor( 0, 0, 0, 1 ); buffer->base_color = white; } else { glClearColor( 1, 1, 1, 1 ); buffer->base_color = black; } glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glUseProgram( buffer->shader ); { glUniformMatrix4fv( glGetUniformLocation( buffer->shader, "model" ), 1, 0, model.data); glUniformMatrix4fv( glGetUniformLocation( buffer->shader, "view" ), 1, 0, view.data); glUniformMatrix4fv( glGetUniformLocation( buffer->shader, "projection" ), 1, 0, projection.data); text_buffer_render( buffer ); } TwDraw( ); glfwSwapBuffers( window ); }
// ------------------------------------------------------------------- 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; }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { int width = 600; int height = 600; glutInit( &argc, argv ); glutInitWindowSize( width, height ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( "Freetype OpenGL" ); 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) ); vec4 blue = {{0,0,1,1}}; vec4 black = {{0,0,0,1}}; texture_atlas_t * atlas = texture_atlas_new( 512, 512, 1); texture_font_t * big = texture_font_new_from_file( atlas, 400, "fonts/Vera.ttf"); texture_font_t * small = texture_font_new_from_file( atlas, 18, "fonts/Vera.ttf"); texture_font_t * title = texture_font_new_from_file( atlas, 32, "fonts/Vera.ttf"); text_buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); line_buffer = vertex_buffer_new( "vertex:3f,color:4f" ); point_buffer = vertex_buffer_new( "vertex:3f,color:4f" ); vec2 pen, origin; texture_glyph_t *glyph = texture_font_get_glyph( big, L'g' ); origin.x = width/2 - glyph->offset_x - glyph->width/2; origin.y = height/2 - glyph->offset_y + glyph->height/2; add_text( text_buffer, big, L"g", &black, &origin ); // title pen.x = 50; pen.y = 560; add_text( text_buffer, title, L"Glyph metrics", &black, &pen ); point_t vertices[] = { // Baseline {0.1*width, origin.y, 0, black}, {0.9*width, origin.y, 0, black}, // Top line {0.1*width, origin.y + glyph->offset_y, 0, black}, {0.9*width, origin.y + glyph->offset_y, 0, black}, // Bottom line {0.1*width, origin.y + glyph->offset_y - glyph->height, 0, black}, {0.9*width, origin.y + glyph->offset_y - glyph->height, 0, black}, // Left line at origin {width/2-glyph->offset_x-glyph->width/2, 0.1*height, 0, black}, {width/2-glyph->offset_x-glyph->width/2, 0.9*height, 0, black}, // Left line {width/2 - glyph->width/2, .3*height, 0, black}, {width/2 - glyph->width/2, .9*height, 0, black}, // Right line {width/2 + glyph->width/2, .3*height, 0, black}, {width/2 + glyph->width/2, .9*height, 0, black}, // Right line at origin {width/2-glyph->offset_x-glyph->width/2+glyph->advance_x, 0.1*height, 0, black}, {width/2-glyph->offset_x-glyph->width/2+glyph->advance_x, 0.7*height, 0, black}, // Width {width/2 - glyph->width/2, 0.8*height, 0, blue}, {width/2 + glyph->width/2, 0.8*height, 0, blue}, // Advance_x {width/2-glyph->width/2-glyph->offset_x, 0.2*height, 0, blue}, {width/2-glyph->width/2-glyph->offset_x+glyph->advance_x, 0.2*height, 0, blue}, // Offset_x {width/2-glyph->width/2-glyph->offset_x, 0.85*height, 0, blue}, {width/2-glyph->width/2, 0.85*height, 0, blue}, // Height {0.3*width/2, origin.y + glyph->offset_y - glyph->height, 0, blue}, {0.3*width/2, origin.y + glyph->offset_y, 0, blue}, // Offset y {0.8*width, origin.y + glyph->offset_y, 0, blue}, {0.8*width, origin.y , 0, blue}, }; GLuint indices [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12, 13,14,15,16,17,18,19,20,21,22,23,24,25}; vertex_buffer_push_back( line_buffer, vertices, 26, indices, 26 ); pen.x = width/2 - 48; pen.y = .2*height - 18; add_text( text_buffer, small, L"advance_x", &blue, &pen ); pen.x = width/2 - 20; pen.y = .8*height + 3; add_text( text_buffer, small, L"width", &blue, &pen ); pen.x = width/2 - glyph->width/2 + 5; pen.y = .85*height-8; add_text( text_buffer, small, L"offset_x", &blue, &pen ); pen.x = 0.2*width/2-30; pen.y = origin.y + glyph->offset_y - glyph->height/2; add_text( text_buffer, small, L"height", &blue, &pen ); pen.x = 0.8*width+3; pen.y = origin.y + glyph->offset_y/2 -6; add_text( text_buffer, small, L"offset_y", &blue, &pen ); pen.x = width/2 - glyph->offset_x - glyph->width/2 - 58; pen.y = height/2 - glyph->offset_y + glyph->height/2 - 20; add_text( text_buffer, small, L"Origin", &black, &pen ); GLuint i = 0; point_t p; p.color = black; // Origin point p.x = width/2 - glyph->offset_x - glyph->width/2; p.y = height/2 - glyph->offset_y + glyph->height/2; vertex_buffer_push_back( point_buffer, &p, 1, &i, 1 ); // Advance point p.x = width/2 - glyph->offset_x - glyph->width/2 + glyph->advance_x; p.y = height/2 - glyph->offset_y + glyph->height/2; vertex_buffer_push_back( point_buffer, &p, 1, &i, 1 ); text_shader = shader_load( "shaders/v3f-t2f-c4f.vert", "shaders/v3f-t2f-c4f.frag" ); shader = shader_load( "shaders/v3f-c4f.vert", "shaders/v3f-c4f.frag" ); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glutMainLoop( ); return 0; }
// ------------------------------------------------------------ console_new --- console_t * console_new( void ) { console_t *self = (console_t *) malloc( sizeof(console_t) ); if( !self ) { return self; } self->lines = vector_new( sizeof(wchar_t *) ); self->prompt = (wchar_t *) wcsdup( L">>> " ); self->cursor = 0; self->buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); self->input[0] = L'\0'; self->killring[0] = L'\0'; self->handlers[__SIGNAL_ACTIVATE__] = 0; self->handlers[__SIGNAL_COMPLETE__] = 0; self->handlers[__SIGNAL_HISTORY_NEXT__] = 0; self->handlers[__SIGNAL_HISTORY_PREV__] = 0; self->pen.x = self->pen.y = 0; texture_atlas_t * atlas = texture_atlas_new( 512, 512, 1 ); vec4 white = {{1,1,1,1}}; vec4 black = {{0,0,0,1}}; vec4 none = {{0,0,1,0}}; markup_t normal; normal.family = "fonts/VeraMono.ttf"; normal.size = 13.0; normal.bold = 0; normal.italic = 0; normal.rise = 0.0; normal.spacing = 0.0; normal.gamma = 1.0; normal.foreground_color = black; normal.background_color = none; normal.underline = 0; normal.underline_color = white; normal.overline = 0; normal.overline_color = white; normal.strikethrough = 0; normal.strikethrough_color = white; normal.font = texture_font_new_from_file( atlas, 13, "fonts/VeraMono.ttf" ); markup_t bold = normal; bold.bold = 1; bold.font = texture_font_new_from_file( atlas, 13, "fonts/VeraMoBd.ttf" ); markup_t italic = normal; italic.italic = 1; bold.font = texture_font_new_from_file( atlas, 13, "fonts/VeraMoIt.ttf" ); markup_t bold_italic = normal; bold.bold = 1; italic.italic = 1; italic.font = texture_font_new_from_file( atlas, 13, "fonts/VeraMoBI.ttf" ); markup_t faint = normal; faint.foreground_color.r = 0.35; faint.foreground_color.g = 0.35; faint.foreground_color.b = 0.35; markup_t error = normal; error.foreground_color.r = 1.00; error.foreground_color.g = 0.00; error.foreground_color.b = 0.00; markup_t warning = normal; warning.foreground_color.r = 1.00; warning.foreground_color.g = 0.50; warning.foreground_color.b = 0.50; markup_t output = normal; output.foreground_color.r = 0.00; output.foreground_color.g = 0.00; output.foreground_color.b = 1.00; self->markup[MARKUP_NORMAL] = normal; self->markup[MARKUP_ERROR] = error; self->markup[MARKUP_WARNING] = warning; self->markup[MARKUP_OUTPUT] = output; self->markup[MARKUP_FAINT] = faint; self->markup[MARKUP_BOLD] = bold; self->markup[MARKUP_ITALIC] = italic; self->markup[MARKUP_BOLD_ITALIC] = bold_italic; return self; }
// ------------------------------------------------------------------- init --- void init( void ) { vec4 blue = {{0,0,1,1}}; vec4 black = {{0,0,0,1}}; texture_atlas_t * atlas = texture_atlas_new( 512, 512, 1); texture_font_t * big = texture_font_new_from_file( atlas, 400, "fonts/Vera.ttf"); texture_font_t * small = texture_font_new_from_file( atlas, 18, "fonts/Vera.ttf"); texture_font_t * title = texture_font_new_from_file( atlas, 32, "fonts/Vera.ttf"); text_buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); line_buffer = vertex_buffer_new( "vertex:3f,color:4f" ); point_buffer = vertex_buffer_new( "vertex:3f,color:4f" ); vec2 pen, origin; texture_glyph_t *glyph = texture_font_get_glyph( big, "g" ); origin.x = width/2 - glyph->offset_x - glyph->width/2; origin.y = height/2 - glyph->offset_y + glyph->height/2; add_text( text_buffer, big, "g", &black, &origin ); // title pen.x = 50; pen.y = 560; add_text( text_buffer, title, "Glyph metrics", &black, &pen ); point_t vertices[] = { // Baseline {0.1*width, origin.y, 0, black}, {0.9*width, origin.y, 0, black}, // Top line {0.1*width, origin.y + glyph->offset_y, 0, black}, {0.9*width, origin.y + glyph->offset_y, 0, black}, // Bottom line {0.1*width, origin.y + glyph->offset_y - glyph->height, 0, black}, {0.9*width, origin.y + glyph->offset_y - glyph->height, 0, black}, // Left line at origin {width/2-glyph->offset_x-glyph->width/2, 0.1*height, 0, black}, {width/2-glyph->offset_x-glyph->width/2, 0.9*height, 0, black}, // Left line {width/2 - glyph->width/2, .3*height, 0, black}, {width/2 - glyph->width/2, .9*height, 0, black}, // Right line {width/2 + glyph->width/2, .3*height, 0, black}, {width/2 + glyph->width/2, .9*height, 0, black}, // Right line at origin {width/2-glyph->offset_x-glyph->width/2+glyph->advance_x, 0.1*height, 0, black}, {width/2-glyph->offset_x-glyph->width/2+glyph->advance_x, 0.7*height, 0, black}, // Width {width/2 - glyph->width/2, 0.8*height, 0, blue}, {width/2 + glyph->width/2, 0.8*height, 0, blue}, // Advance_x {width/2-glyph->width/2-glyph->offset_x, 0.2*height, 0, blue}, {width/2-glyph->width/2-glyph->offset_x+glyph->advance_x, 0.2*height, 0, blue}, // Offset_x {width/2-glyph->width/2-glyph->offset_x, 0.85*height, 0, blue}, {width/2-glyph->width/2, 0.85*height, 0, blue}, // Height {0.3*width/2, origin.y + glyph->offset_y - glyph->height, 0, blue}, {0.3*width/2, origin.y + glyph->offset_y, 0, blue}, // Offset y {0.8*width, origin.y + glyph->offset_y, 0, blue}, {0.8*width, origin.y , 0, blue}, }; GLuint indices [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12, 13,14,15,16,17,18,19,20,21,22,23,24,25}; vertex_buffer_push_back( line_buffer, vertices, 26, indices, 26 ); pen.x = width/2 - 48; pen.y = .2*height - 18; add_text( text_buffer, small, "advance_x", &blue, &pen ); pen.x = width/2 - 20; pen.y = .8*height + 3; add_text( text_buffer, small, "width", &blue, &pen ); pen.x = width/2 - glyph->width/2 + 5; pen.y = .85*height-8; add_text( text_buffer, small, "offset_x", &blue, &pen ); pen.x = 0.2*width/2-30; pen.y = origin.y + glyph->offset_y - glyph->height/2; add_text( text_buffer, small, "height", &blue, &pen ); pen.x = 0.8*width+3; pen.y = origin.y + glyph->offset_y/2 -6; add_text( text_buffer, small, "offset_y", &blue, &pen ); pen.x = width/2 - glyph->offset_x - glyph->width/2 - 58; pen.y = height/2 - glyph->offset_y + glyph->height/2 - 20; add_text( text_buffer, small, "Origin", &black, &pen ); GLuint i = 0; point_t p; p.color = black; // Origin point p.x = width/2 - glyph->offset_x - glyph->width/2; p.y = height/2 - glyph->offset_y + glyph->height/2; vertex_buffer_push_back( point_buffer, &p, 1, &i, 1 ); // Advance point p.x = width/2 - glyph->offset_x - glyph->width/2 + glyph->advance_x; p.y = height/2 - glyph->offset_y + glyph->height/2; vertex_buffer_push_back( point_buffer, &p, 1, &i, 1 ); text_shader = shader_load( "shaders/v3f-t2f-c4f.vert", "shaders/v3f-t2f-c4f.frag" ); shader = shader_load( "shaders/v3f-c4f.vert", "shaders/v3f-c4f.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( 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; }
// ------------------------------------------------------------------- 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 ); 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) ); texture_atlas_t * atlas = texture_atlas_new( 512, 512, 1 ); 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_from_file( atlas, i, filename ); 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("shaders/v3f-t2f-c4f.vert", "shaders/v3f-t2f-c4f.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glutMainLoop( ); return 0; }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { int width = 600; int height = 600; 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", 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 vec4 blue = {{0,0,1,1}}; vec4 black = {{0,0,0,1}}; texture_atlas_t * atlas = texture_atlas_new( 512, 512, 1); texture_font_t * big = texture_font_new_from_file( atlas, 400, "fonts/Vera.ttf"); texture_font_t * small = texture_font_new_from_file( atlas, 18, "fonts/Vera.ttf"); texture_font_t * title = texture_font_new_from_file( atlas, 32, "fonts/Vera.ttf"); text_buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" ); line_buffer = vertex_buffer_new( "vertex:3f,color:4f" ); point_buffer = vertex_buffer_new( "vertex:3f,color:4f" ); vec2 pen, origin; texture_glyph_t *glyph = texture_font_get_glyph( big, L'g' ); origin.x = width/2 - glyph->offset_x - glyph->width/2; origin.y = height/2 - glyph->offset_y + glyph->height/2; add_text( text_buffer, big, L"g", &black, &origin ); // title pen.x = 50; pen.y = 560; add_text( text_buffer, title, L"Glyph metrics", &black, &pen ); point_t vertices[] = { // Baseline {0.1*width, origin.y, 0, black}, {0.9*width, origin.y, 0, black}, // Top line {0.1*width, origin.y + glyph->offset_y, 0, black}, {0.9*width, origin.y + glyph->offset_y, 0, black}, // Bottom line {0.1*width, origin.y + glyph->offset_y - glyph->height, 0, black}, {0.9*width, origin.y + glyph->offset_y - glyph->height, 0, black}, // Left line at origin {width/2-glyph->offset_x-glyph->width/2, 0.1*height, 0, black}, {width/2-glyph->offset_x-glyph->width/2, 0.9*height, 0, black}, // Left line {width/2 - glyph->width/2, .3*height, 0, black}, {width/2 - glyph->width/2, .9*height, 0, black}, // Right line {width/2 + glyph->width/2, .3*height, 0, black}, {width/2 + glyph->width/2, .9*height, 0, black}, // Right line at origin {width/2-glyph->offset_x-glyph->width/2+glyph->advance_x, 0.1*height, 0, black}, {width/2-glyph->offset_x-glyph->width/2+glyph->advance_x, 0.7*height, 0, black}, // Width {width/2 - glyph->width/2, 0.8*height, 0, blue}, {width/2 + glyph->width/2, 0.8*height, 0, blue}, // Advance_x {width/2-glyph->width/2-glyph->offset_x, 0.2*height, 0, blue}, {width/2-glyph->width/2-glyph->offset_x+glyph->advance_x, 0.2*height, 0, blue}, // Offset_x {width/2-glyph->width/2-glyph->offset_x, 0.85*height, 0, blue}, {width/2-glyph->width/2, 0.85*height, 0, blue}, // Height {0.3*width/2, origin.y + glyph->offset_y - glyph->height, 0, blue}, {0.3*width/2, origin.y + glyph->offset_y, 0, blue}, // Offset y {0.8*width, origin.y + glyph->offset_y, 0, blue}, {0.8*width, origin.y , 0, blue}, }; GLuint indices [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12, 13,14,15,16,17,18,19,20,21,22,23,24,25}; vertex_buffer_push_back( line_buffer, vertices, 26, indices, 26 ); pen.x = width/2 - 48; pen.y = .2*height - 18; add_text( text_buffer, small, L"advance_x", &blue, &pen ); pen.x = width/2 - 20; pen.y = .8*height + 3; add_text( text_buffer, small, L"width", &blue, &pen ); pen.x = width/2 - glyph->width/2 + 5; pen.y = .85*height-8; add_text( text_buffer, small, L"offset_x", &blue, &pen ); pen.x = 0.2*width/2-30; pen.y = origin.y + glyph->offset_y - glyph->height/2; add_text( text_buffer, small, L"height", &blue, &pen ); pen.x = 0.8*width+3; pen.y = origin.y + glyph->offset_y/2 -6; add_text( text_buffer, small, L"offset_y", &blue, &pen ); pen.x = width/2 - glyph->offset_x - glyph->width/2 - 58; pen.y = height/2 - glyph->offset_y + glyph->height/2 - 20; add_text( text_buffer, small, L"Origin", &black, &pen ); GLuint i = 0; point_t p; p.color = black; // Origin point p.x = width/2 - glyph->offset_x - glyph->width/2; p.y = height/2 - glyph->offset_y + glyph->height/2; vertex_buffer_push_back( point_buffer, &p, 1, &i, 1 ); // Advance point p.x = width/2 - glyph->offset_x - glyph->width/2 + glyph->advance_x; p.y = height/2 - glyph->offset_y + glyph->height/2; vertex_buffer_push_back( point_buffer, &p, 1, &i, 1 ); text_shader = shader_load( "shaders/v3f-t2f-c4f.vert", "shaders/v3f-t2f-c4f.frag" ); shader = shader_load( "shaders/v3f-c4f.vert", "shaders/v3f-c4f.frag" ); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glfwSetWindowSize( window, width, height ); 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 ); }