// ----------------------------------------------------- console_add_glyph --- void console_add_glyph( console_t *self, wchar_t current, wchar_t previous, markup_t *markup ) { texture_glyph_t *glyph = texture_font_get_glyph( markup->font, current ); if( previous != L'\0' ) { self->pen.x += texture_glyph_get_kerning( glyph, previous ); } float r = markup->foreground_color.r; float g = markup->foreground_color.g; float b = markup->foreground_color.b; float a = markup->foreground_color.a; int x0 = self->pen.x + glyph->offset_x; int y0 = self->pen.y + glyph->offset_y; int x1 = x0 + glyph->width; int y1 = y0 - glyph->height; float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; GLuint indices[] = {0,1,2, 0,2,3}; vertex_t vertices[] = { { x0,y0,0, s0,t0, r,g,b,a }, { x0,y1,0, s0,t1, r,g,b,a }, { x1,y1,0, s1,t1, r,g,b,a }, { x1,y0,0, s1,t0, r,g,b,a } }; vertex_buffer_push_back( self->buffer, vertices, 4, indices, 6 ); self->pen.x += glyph->advance_x; self->pen.y += glyph->advance_y; }
// --------------------------------------------------------------- add_text --- void add_text( vertex_buffer_t * buffer, texture_font_t * font, wchar_t * text, vec4 * color, vec2 * pen ) { size_t i; float r = color->red, g = color->green, b = color->blue, a = color->alpha; for( i=0; i<wcslen(text); ++i ) { texture_glyph_t *glyph = texture_font_get_glyph( font, text[i] ); if( glyph != NULL ) { int kerning = 0; if( i > 0) { kerning = texture_glyph_get_kerning( glyph, text[i-1] ); } pen->x += kerning; int x0 = (int)( pen->x + glyph->offset_x ); int y0 = (int)( pen->y + glyph->offset_y ); int x1 = (int)( x0 + glyph->width ); int y1 = (int)( y0 - glyph->height ); float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; GLuint indices[] = {0,1,2,0,2,3}; vertex_t vertices[] = { { x0,y0,0, s0,t0, r,g,b,a }, { x0,y1,0, s0,t1, r,g,b,a }, { x1,y1,0, s1,t1, r,g,b,a }, { x1,y0,0, s1,t0, r,g,b,a } }; vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); pen->x += glyph->advance_x; } } }
// ------------------------------------------------------------------- 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 ); }
void add_text( vertex_buffer_t * buffer, texture_font_t * font, char* fileBuffer, int bufferSizeBytes, const char* text, vec2 * pen, int currentSize ) { vec2 startPos = *pen; size_t length = strlen(text); Color vertColor = Color::White; for(size_t i=0; i < length; ++i) { if(text[i] == '\n') { pen->x = startPos.x; pen->y -= currentSize; continue; } if(text[i] == '<') { if(i + 1 < length && text[i + 1] == '#') { vertColor = ParseColor(text, i); i += 11; } } float r = vertColor.r; float g = vertColor.g; float b = vertColor.b; float a = vertColor.a; texture_glyph_t *glyph = texture_font_get_glyph( font, fileBuffer, bufferSizeBytes, text[i] ); if( glyph != NULL ) { float kerning = 0; if( i > 0) { kerning = texture_glyph_get_kerning( glyph, text[i-1] ); } pen->x += kerning; int x0 = (int)( pen->x + glyph->offset_x ); int y0 = (int)( pen->y + glyph->offset_y ); int x1 = (int)( x0 + glyph->width ); int y1 = (int)( y0 - glyph->height ); float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; GLuint indices[6] = {0,1,2, 0,2,3}; vertex_t vertices[4] = { {(float)x0, (float)y0, 1.0f, s0, t0, r, g, b, a}, {(float)x0, (float)y1, 1.0f, s0, t1, r, g, b, a}, {(float)x1, (float)y1, 1.0f, s1, t1, r, g, b, a}, {(float)x1, (float)y0, 1.0f, s1, t0, r, g, b, a} }; vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); pen->x += glyph->advance_x; } } }
static void coors_push_to_vector( struct coordinates *coors, vertex_buffer_t * buffer ) { vertex_buffer_push_back( buffer, coors->start_vertex, coors->cur_vertex - coors->start_vertex, coors->start_index, coors->cur_index - coors->start_index ); }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { glutInit( &argc, argv ); glutInitWindowSize( 400, 400 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( argv[0] ); glutReshapeFunc( reshape ); glutDisplayFunc( display ); glutKeyboardFunc( keyboard ); //glutTimerFunc( 1000/60, timer, 1000/60 ); // not working on some systems (bug in GLUT) glutIdleFunc(display); 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) ); typedef struct { float x,y,z;} xyz; typedef struct { float r,g,b,a;} rgba; typedef struct { xyz position, normal; rgba color;} vertex; xyz v[] = { { 1, 1, 1}, {-1, 1, 1}, {-1,-1, 1}, { 1,-1, 1}, { 1,-1,-1}, { 1, 1,-1}, {-1, 1,-1}, {-1,-1,-1} }; xyz n[] = { { 0, 0, 1}, { 1, 0, 0}, { 0, 1, 0} , {-1, 0, 1}, { 0,-1, 0}, { 0, 0,-1} }; rgba c[] = { {1, 1, 1, 1}, {1, 1, 0, 1}, {1, 0, 1, 1}, {0, 1, 1, 1}, {1, 0, 0, 1}, {0, 0, 1, 1}, {0, 1, 0, 1}, {0, 0, 0, 1} }; vertex vertices[24] = { {v[0],n[0],c[0]}, {v[1],n[0],c[1]}, {v[2],n[0],c[2]}, {v[3],n[0],c[3]}, {v[0],n[1],c[0]}, {v[3],n[1],c[3]}, {v[4],n[1],c[4]}, {v[5],n[1],c[5]}, {v[0],n[2],c[0]}, {v[5],n[2],c[5]}, {v[6],n[2],c[6]}, {v[1],n[2],c[1]}, {v[1],n[3],c[1]}, {v[6],n[3],c[6]}, {v[7],n[3],c[7]}, {v[2],n[3],c[2]}, {v[7],n[4],c[7]}, {v[4],n[4],c[4]}, {v[3],n[4],c[3]}, {v[2],n[4],c[2]}, {v[4],n[5],c[4]}, {v[7],n[5],c[7]}, {v[6],n[5],c[6]}, {v[5],n[5],c[5]} }; GLuint indices[24] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11, 12,13,14,15, 16,17,18,19, 20,21,22,23 }; cube = vertex_buffer_new( "vertex:3f,normal:3f,color:4f" ); vertex_buffer_push_back( cube, vertices, 24, indices, 24 ); shader = shader_load("shaders/cube.vert","shaders/cube.frag"); init( ); glutMainLoop( ); return EXIT_SUCCESS; }
void sen_render_push_buffer(vertex_buffer_t* buff, const texture_t* tex, const font_t* font, const shader_t* program, blend_func blend) { vertex_buffer_t* gb = get_group_buffer(buff, tex, font, program, blend); size_t ivsize = buff->vertices->item_size; //size_t iisize = buff->indices->item_size; size_t i; for (i = 0; i < buff->items->size; ++i) { ivec4* item = (ivec4*) vector_get(buff->items, i); /* size_t j; size_t index = 0; for (j = 0; j < gb->items->size; ++j) { ivec4* gb_item = (ivec4*) vector_get(gb->items, j); // FIXME vec4* vz1 = ( vec4*) (buff->vertices->items + ivsize*item->x); vec4* vz2 = ( vec4*) (gb->vertices->items + ivsize*gb_item->x); if (vz1->z < vz2->z ) { //_logfi(""); break; } index++; } */ // vertex_buffer_push_back_vertices(gb, buff->vertices->items, buff->vertices->size ); // vertex_buffer_push_back_indicies(gb, buff->indicies->items, buff->indicies->size ); vertex_buffer_push_back( gb, (char*)(buff->vertices->items) + ivsize*item->x, item->y, indices, 6); //vertex_buffer_insert( gb, 0, // buff->vertices->items + ivsize*item->x, item->y, // indices, 6); /* vertex_buffer_insert( gb, index, buff->vertices->items + ivsize*item->x, item->y, buff->indices->items + iisize*item->z, item->w); */ } //vertex_buffer_push_back_vertices(gb, buff->vertices->items, buff->vertices->size ); //vertex_buffer_push_back_indices(gb, buff->indices->items, buff->indices->size ); }
void FontBufferCache::Add(const std::string &text, const Point3 &position, const GameColor &color, texture_font_t *font) { HashedString hash(text.c_str()); vertex_buffer_t *buffer = 0; if(Contains(text)) { buffer = m_vertexBufferMap.find(hash.getHashValue())->second; vertex_buffer_clear(buffer); } else { buffer = vertex_buffer_new("vertex:3f,tex_coord:2f,color:4f"); m_vertexBufferMap[hash.getHashValue()] = buffer; } F32 r = color.GetX(), g = color.GetY(), b = color.GetZ(), a = color.GetW(); F32 x = 0.0f; U32 size = (U32)text.size(); for(U32 i = 0; i < size; ++i) { texture_glyph_t *glyph = texture_font_get_glyph(font, text[i]); if(glyph != NULL) { I32 kerning = 0; if(i > 0) { kerning = texture_glyph_get_kerning(glyph, text[i - 1]); } x += (float)kerning; F32 x0 = (F32)(position.GetX() + x + glyph->offset_x); F32 y0 = (F32)(position.GetY() + glyph->offset_y); F32 x1 = (F32)(x0 + glyph->width); F32 y1 = (F32)(y0 - glyph->height); F32 s0 = glyph->s0; F32 t0 = glyph->t0; F32 s1 = glyph->s1; F32 t1 = glyph->t1; GLuint indices[6] = {0, 1, 2, 0, 2, 3}; vertex_t vertices[4] = { { x0, y0, 0.0f, s0, t0, r, g, b, a }, { x0, y1, 0.0f, s0, t1, r, g, b, a }, { x1, y1, 0.0f, s1, t1, r, g, b, a }, { x1, y0, 0.0f, s1, t0, r, g, b, a } }; vertex_buffer_push_back(buffer, vertices, 4, indices, 6); x += glyph->advance_x; } } }
// --------------------------------------------------------------- add_text --- vec4 add_text( vertex_buffer_t * buffer, texture_font_t * font, char *text, vec4 * color, vec2 * pen ) { vec4 bbox = {{0,0,0,0}}; size_t i; float r = color->red, g = color->green, b = color->blue, a = color->alpha; for( i = 0; i < strlen(text); ++i ) { texture_glyph_t *glyph = texture_font_get_glyph( font, text + i ); if( glyph != NULL ) { float kerning = 0.0f; if( i > 0) { kerning = texture_glyph_get_kerning( glyph, text + i - 1 ); } pen->x += kerning; int x0 = (int)( pen->x + glyph->offset_x ); int y0 = (int)( pen->y + glyph->offset_y ); int x1 = (int)( x0 + glyph->width ); int y1 = (int)( y0 - glyph->height ); float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; GLuint indices[6] = {0,1,2, 0,2,3}; vertex_t vertices[4] = { { x0,y0,0, s0,t0, r,g,b,a }, { x0,y1,0, s0,t1, r,g,b,a }, { x1,y1,0, s1,t1, r,g,b,a }, { x1,y0,0, s1,t0, r,g,b,a } }; vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); pen->x += glyph->advance_x; if (x0 < bbox.x) bbox.x = x0; if (y1 < bbox.y) bbox.y = y1; if ((x1 - bbox.x) > bbox.width) bbox.width = x1-bbox.x; if ((y0 - bbox.y) > bbox.height) bbox.height = y0-bbox.y; } } return bbox; }
// --------------------------------------------------------------- add_text --- vec4 add_text( vertex_buffer_t * buffer, texture_font_t * font, const char *text, vec4 * color, vec2 * pen ) { auto bbox = vec4{0,0,0,0}; size_t i; auto r = color->red, g = color->green, b = color->blue, a = color->alpha; for( i = 0; i < strlen(text); ++i ) { glfwSetTime(total_time); auto glyph = texture_font_get_glyph( font, text + i ); total_time += glfwGetTime(); if( glyph ) { float kerning = 0.0f; if( i > 0) { kerning = texture_glyph_get_kerning( glyph, text + i - 1 ); } pen->x += kerning; auto x0 = (float)( pen->x + glyph->offset_x ); auto y0 = (float)( pen->y + glyph->offset_y ); auto x1 = (float)( x0 + glyph->width ); auto y1 = (float)( y0 - glyph->height ); auto s0 = glyph->s0; auto t0 = glyph->t0; auto s1 = glyph->s1; auto t1 = glyph->t1; GLuint indices[6] = {0,1,2, 0,2,3}; vertex vertices[4] = { { x0,y0,0, s0,t0, r,g,b,a }, { x0,y1,0, s0,t1, r,g,b,a }, { x1,y1,0, s1,t1, r,g,b,a }, { x1,y0,0, s1,t0, r,g,b,a } }; vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); pen->x += glyph->advance_x; if (x0 < bbox.x) bbox.x = x0; if (y1 < bbox.y) bbox.y = y1; if ((x1 - bbox.x) > bbox.width) bbox.width = x1-bbox.x; if ((y0 - bbox.y) > bbox.height) bbox.height = y0-bbox.y; } } return bbox; }
// ------------------------------------------------------------------- init --- void init( void ) { typedef struct { float x,y,z;} xyz; typedef struct { float r,g,b,a;} rgba; typedef struct { xyz position, normal; rgba color;} vertex; xyz v[] = { { 1, 1, 1}, {-1, 1, 1}, {-1,-1, 1}, { 1,-1, 1}, { 1,-1,-1}, { 1, 1,-1}, {-1, 1,-1}, {-1,-1,-1} }; xyz n[] = { { 0, 0, 1}, { 1, 0, 0}, { 0, 1, 0} , {-1, 0, 1}, { 0,-1, 0}, { 0, 0,-1} }; rgba c[] = { {1, 1, 1, 1}, {1, 1, 0, 1}, {1, 0, 1, 1}, {0, 1, 1, 1}, {1, 0, 0, 1}, {0, 0, 1, 1}, {0, 1, 0, 1}, {0, 0, 0, 1} }; vertex vertices[24] = { {v[0],n[0],c[0]}, {v[1],n[0],c[1]}, {v[2],n[0],c[2]}, {v[3],n[0],c[3]}, {v[0],n[1],c[0]}, {v[3],n[1],c[3]}, {v[4],n[1],c[4]}, {v[5],n[1],c[5]}, {v[0],n[2],c[0]}, {v[5],n[2],c[5]}, {v[6],n[2],c[6]}, {v[1],n[2],c[1]}, {v[1],n[3],c[1]}, {v[6],n[3],c[6]}, {v[7],n[3],c[7]}, {v[2],n[3],c[2]}, {v[7],n[4],c[7]}, {v[4],n[4],c[4]}, {v[3],n[4],c[3]}, {v[2],n[4],c[2]}, {v[4],n[5],c[4]}, {v[7],n[5],c[7]}, {v[6],n[5],c[6]}, {v[5],n[5],c[5]} }; GLuint indices[24] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11, 12,13,14,15, 16,17,18,19, 20,21,22,23 }; cube = vertex_buffer_new( "vertex:3f,normal:3f,color:4f" ); vertex_buffer_push_back( cube, vertices, 24, indices, 24 ); shader = shader_load("../media/shaders/cube.vert","../media/shaders/cube.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glPolygonOffset( 1, 1 ); glClearColor( 1.0, 1.0, 1.0, 1.0 ); glEnable( GL_DEPTH_TEST ); glEnable( GL_COLOR_MATERIAL ); glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_LINE_SMOOTH ); }
void init() { text_shader = shader_load( "text.vert", "text.frag" ); font_manager = font_manager_new( 512, 512, LCD_FILTERING_ON ); buffer = text_buffer_new( ); vec4 black = {{0.0, 0.0, 0.0, 1.0}}; vec4 white = {{1.0, 1.0, 1.0, 1.0}}; vec4 yellow = {{1.0, 1.0, 0.0, 1.0}}; vec4 grey = {{0.5, 0.5, 0.5, 1.0}}; vec4 none = {{1.0, 1.0, 1.0, 0.0}}; //char *f_normal = match_description("Vera:size=50"); char *f_normal = match_description("Arial"); char *f_bold = match_description("Arial", true); //char *f_bold = match_description("sans\\-serif:size=24"); char *f_italic = match_description("sans\\-serif", false, true); //char *f_italic = match_description("SimSun", false, true); //char *f_japanese = match_description("Droid Sans:size=18:lang=ja"); //char *f_japanese = match_description("sans-serif:size=18:lang=zh"); //char *f_japanese = match_description("sans\\-serif:size=18:lang=zh\\-CN"); //char *f_japanese = match_description("FZLanTingHeiS\\-UL\\-GB:size=18:lang=zh\\-CN"); //ok //char *f_japanese = match_description("FZLanTingHeiS\\-UL\\-GB"); //ok //char *f_japanese = match_description("Yu Gothic UI Semibold"); //ok //char *f_japanese = match_description("jj:size=18"); //ok //char *f_japanese = match_description("Brush Script MT"); //ok char *f_japanese = match_description("Microsoft JhengHei UI"); //ok //char *f_japanese = match_description("华文隶书:size=28:lang=zh\\-CN"); //no char *f_math = match_description("DejaVu Sans"); printf("init. f_normal: %s f_bold: %s f_italic: %s f_japanese: %s f_math: %s\n" , f_normal, f_bold, f_italic, f_japanese, f_math); //printf("init. f_japanese: %s\n" , f_japanese); //exit(0); markup_t normal = { .family = f_normal, .size = 20.0, .bold = 0, .italic = 0, .spacing = 0.0, .gamma = 2., .foreground_color = white, .background_color = none, .outline = 0, .outline_color = white, .underline = 0, .underline_color = white, .overline = 0, .overline_color = white, .strikethrough = 0, .strikethrough_color = white, .font = 0, }; markup_t highlight = normal; highlight.background_color = grey; markup_t reverse = normal; reverse.foreground_color = black; reverse.background_color = white; reverse.gamma = 1.0; markup_t overline = normal; overline.overline = 1; markup_t underline = normal; underline.underline = 1; markup_t small = normal; small.size = 10.0; markup_t big = normal; big.size = 48.0; big.italic = 1; big.foreground_color = yellow; markup_t bold = normal; bold.bold = 1; bold.family = f_bold; markup_t italic = normal; italic.italic = 1; italic.family = f_italic; markup_t japanese = normal; japanese.family = f_japanese; //markup_t japanese = normal; japanese.family = "C:/Windows/Fonts/simsun.ttc"; //markup_t japanese = normal; japanese.family = "c:/qtproject/opengl/freetype-gl/fonts/fireflysung.ttf"; japanese.size = 25.0; markup_t math = normal; math.family = f_math; #if 1 normal.font = font_manager_get_from_markup( font_manager, &normal ); highlight.font = font_manager_get_from_markup( font_manager, &highlight ); reverse.font = font_manager_get_from_markup( font_manager, &reverse ); overline.font = font_manager_get_from_markup( font_manager, &overline ); underline.font = font_manager_get_from_markup( font_manager, &underline ); small.font = font_manager_get_from_markup( font_manager, &small ); big.font = font_manager_get_from_markup( font_manager, &big ); bold.font = font_manager_get_from_markup( font_manager, &bold ); italic.font = font_manager_get_from_markup( font_manager, &italic ); japanese.font = font_manager_get_from_markup( font_manager, &japanese ); math.font = font_manager_get_from_markup( font_manager, &math ); #else japanese.font = font_manager_get_from_markup( font_manager, &japanese ); #endif vec2 pen = {{20, 200}}; #if 1 text_buffer_printf( buffer, &pen, &underline, "The", &normal, " Quick", &big, " brown ", &reverse, " fox \n", &italic, "jumps over ", &bold, "the lazy ", &normal, "dog.\n", &small, "Now is the time for all good men " "to come to the aid of the party.\n", &italic, "Ég get etið gler án þess að meiða mig.\n", &japanese, "aaa张私はガラスを食べられます。 それは私を傷つけません\n", &math, "ℕ ⊆ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ", NULL ); #else text_buffer_printf( buffer, &pen, &japanese, "Brush Script MT张私はガラスを食べられます。 それは私を傷つけません\n", NULL ); #endif glGenTextures( 1, &font_manager->atlas->id ); glBindTexture( GL_TEXTURE_2D, font_manager->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, font_manager->atlas->width, font_manager->atlas->height, 0, GL_RGB, GL_UNSIGNED_BYTE, font_manager->atlas->data ); printf("init font_manager->atlas->width: %d font_manager->atlas->height: %d\n" , font_manager->atlas->width, font_manager->atlas->height); text_buffer_align( buffer, &pen, ALIGN_CENTER ); vec4 bounds = text_buffer_get_bounds( buffer, &pen ); float left = bounds.left; float right = bounds.left + bounds.width; float top = bounds.top; float bottom = bounds.top - bounds.height; bounds_shader = shader_load( "v3f-c4f.vert", "v3f-c4f.frag" ); lines_buffer = vertex_buffer_new( "vertex:3f,color:4f" ); vertex_t vertices[] = { { left - 10, top, 0, 0,0,0,1}, // top {right + 10, top, 0, 0,0,0,1}, { left - 10, bottom, 0, 0,0,0,1}, // bottom {right + 10, bottom, 0, 0,0,0,1}, { left, top + 10, 0, 0,0,0,1}, // left { left, bottom - 10, 0, 0,0,0,1}, { right, top + 10, 0, 0,0,0,1}, // right { right, bottom - 10, 0, 0,0,0,1} }; GLuint indices[] = { 0,1,2,3,4,5,6,7 }; vertex_buffer_push_back( lines_buffer, vertices, 8, indices, 8); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); } // ---------------------------------------------------------------- display --- void display( GLFWwindow* window ) { glClearColor(0.40,0.40,0.45,1.00); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glColor4f(1.00,1.00,1.00,1.00); glUseProgram( text_shader ); { glUniformMatrix4fv( glGetUniformLocation( text_shader, "model" ), 1, 0, model.data); glUniformMatrix4fv( glGetUniformLocation( text_shader, "view" ), 1, 0, view.data); glUniformMatrix4fv( glGetUniformLocation( text_shader, "projection" ), 1, 0, projection.data); glUniform1i( glGetUniformLocation( text_shader, "tex" ), 0 ); glUniform3f( glGetUniformLocation( text_shader, "pixel" ), 1.0f/font_manager->atlas->width, 1.0f/font_manager->atlas->height, (float)font_manager->atlas->depth ); glEnable( GL_BLEND ); glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, font_manager->atlas->id ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glBlendColor( 1, 1, 1, 1 ); vertex_buffer_render( buffer->buffer, GL_TRIANGLES ); glBindTexture( GL_TEXTURE_2D, 0 ); glBlendColor( 0, 0, 0, 0 ); glUseProgram( 0 ); } glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA ); glBlendColor( 1.0, 1.0, 1.0, 1.0 ); glUseProgram( bounds_shader ); { glUniformMatrix4fv( glGetUniformLocation( bounds_shader, "model" ), 1, 0, model.data); glUniformMatrix4fv( glGetUniformLocation( bounds_shader, "view" ), 1, 0, view.data); glUniformMatrix4fv( glGetUniformLocation( bounds_shader, "projection" ), 1, 0, projection.data); vertex_buffer_render( lines_buffer, GL_LINES ); } glfwSwapBuffers( window ); }
// ---------------------------------------------------------------------------- void text_buffer_add_wchar( text_buffer_t * self, vec2 * pen, markup_t * markup, wchar_t current, wchar_t previous ) { size_t vcount = 0; size_t icount = 0; vertex_buffer_t * buffer = self->buffer; texture_font_t * font = markup->font; float gamma = markup->gamma; // Maximum number of vertices is 20 (= 5x2 triangles) per glyph: // - 2 triangles for background // - 2 triangles for overline // - 2 triangles for underline // - 2 triangles for strikethrough // - 2 triangles for glyph glyph_vertex_t vertices[4*5]; GLuint indices[6*5]; texture_glyph_t *glyph; texture_glyph_t *black; float kerning = 0; if( current == L'\n' ) { pen->x = self->origin.x; pen->y += self->line_descender; self->line_descender = 0; self->line_ascender = 0; self->line_start = vector_size( self->buffer->items ); return; } if( markup->font->ascender > self->line_ascender ) { float y = pen->y; pen->y -= (markup->font->ascender - self->line_ascender); text_buffer_move_last_line( self, (int)(y-pen->y) ); self->line_ascender = markup->font->ascender; } if( markup->font->descender < self->line_descender ) { self->line_descender = markup->font->descender; } glyph = texture_font_get_glyph( font, current ); black = texture_font_get_glyph( font, -1 ); if( glyph == NULL ) { return; } if( previous && markup->font->kerning ) { kerning = texture_glyph_get_kerning( glyph, previous ); } pen->x += kerning; // Background if( markup->background_color.alpha > 0 ) { float r = markup->background_color.r; float g = markup->background_color.g; float b = markup->background_color.b; float a = markup->background_color.a; float x0 = ( pen->x -kerning ); float y0 = (int)( pen->y + font->descender ); float x1 = ( x0 + glyph->advance_x ); float y1 = (int)( y0 + font->height + font->linegap ); float s0 = black->s0; float t0 = black->t0; float s1 = black->s1; float t1 = black->t1; SET_GLYPH_VERTEX(vertices[vcount+0], (int)x0,y0,0, s0,t0, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+1], (int)x0,y1,0, s0,t1, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+2], (int)x1,y1,0, s1,t1, r,g,b,a, x1-((int)x1), gamma ); SET_GLYPH_VERTEX(vertices[vcount+3], (int)x1,y0,0, s1,t0, r,g,b,a, x1-((int)x1), gamma ); indices[icount + 0] = vcount+0; indices[icount + 1] = vcount+1; indices[icount + 2] = vcount+2; indices[icount + 3] = vcount+0; indices[icount + 4] = vcount+2; indices[icount + 5] = vcount+3; vcount += 4; icount += 6; } // Underline if( markup->underline ) { float r = markup->underline_color.r; float g = markup->underline_color.g; float b = markup->underline_color.b; float a = markup->underline_color.a; float x0 = ( pen->x - kerning ); float y0 = (int)( pen->y + font->underline_position ); float x1 = ( x0 + glyph->advance_x ); float y1 = (int)( y0 + font->underline_thickness ); float s0 = black->s0; float t0 = black->t0; float s1 = black->s1; float t1 = black->t1; SET_GLYPH_VERTEX(vertices[vcount+0], (int)x0,y0,0, s0,t0, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+1], (int)x0,y1,0, s0,t1, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+2], (int)x1,y1,0, s1,t1, r,g,b,a, x1-((int)x1), gamma ); SET_GLYPH_VERTEX(vertices[vcount+3], (int)x1,y0,0, s1,t0, r,g,b,a, x1-((int)x1), gamma ); indices[icount + 0] = vcount+0; indices[icount + 1] = vcount+1; indices[icount + 2] = vcount+2; indices[icount + 3] = vcount+0; indices[icount + 4] = vcount+2; indices[icount + 5] = vcount+3; vcount += 4; icount += 6; } // Overline if( markup->overline ) { float r = markup->overline_color.r; float g = markup->overline_color.g; float b = markup->overline_color.b; float a = markup->overline_color.a; float x0 = ( pen->x -kerning ); float y0 = (int)( pen->y + (int)font->ascender ); float x1 = ( x0 + glyph->advance_x ); float y1 = (int)( y0 + (int)font->underline_thickness ); float s0 = black->s0; float t0 = black->t0; float s1 = black->s1; float t1 = black->t1; SET_GLYPH_VERTEX(vertices[vcount+0], (int)x0,y0,0, s0,t0, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+1], (int)x0,y1,0, s0,t1, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+2], (int)x1,y1,0, s1,t1, r,g,b,a, x1-((int)x1), gamma ); SET_GLYPH_VERTEX(vertices[vcount+3], (int)x1,y0,0, s1,t0, r,g,b,a, x1-((int)x1), gamma ); indices[icount + 0] = vcount+0; indices[icount + 1] = vcount+1; indices[icount + 2] = vcount+2; indices[icount + 3] = vcount+0; indices[icount + 4] = vcount+2; indices[icount + 5] = vcount+3; vcount += 4; icount += 6; } /* Strikethrough */ if( markup->strikethrough ) { float r = markup->strikethrough_color.r; float g = markup->strikethrough_color.g; float b = markup->strikethrough_color.b; float a = markup->strikethrough_color.a; float x0 = ( pen->x -kerning ); float y0 = (int)( pen->y + (int)font->ascender*.33); float x1 = ( x0 + glyph->advance_x ); float y1 = (int)( y0 + (int)font->underline_thickness ); float s0 = black->s0; float t0 = black->t0; float s1 = black->s1; float t1 = black->t1; SET_GLYPH_VERTEX(vertices[vcount+0], (int)x0,y0,0, s0,t0, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+1], (int)x0,y1,0, s0,t1, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+2], (int)x1,y1,0, s1,t1, r,g,b,a, x1-((int)x1), gamma ); SET_GLYPH_VERTEX(vertices[vcount+3], (int)x1,y0,0, s1,t0, r,g,b,a, x1-((int)x1), gamma ); indices[icount + 0] = vcount+0; indices[icount + 1] = vcount+1; indices[icount + 2] = vcount+2; indices[icount + 3] = vcount+0; indices[icount + 4] = vcount+2; indices[icount + 5] = vcount+3; vcount += 4; icount += 6; } { // Actual glyph float r = markup->foreground_color.red; float g = markup->foreground_color.green; float b = markup->foreground_color.blue; float a = markup->foreground_color.alpha; float x0 = ( pen->x + glyph->offset_x ); float y0 = (int)( pen->y + glyph->offset_y ); float x1 = ( x0 + glyph->width ); float y1 = (int)( y0 - glyph->height ); float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; SET_GLYPH_VERTEX(vertices[vcount+0], (int)x0,y0,0, s0,t0, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+1], (int)x0,y1,0, s0,t1, r,g,b,a, x0-((int)x0), gamma ); SET_GLYPH_VERTEX(vertices[vcount+2], (int)x1,y1,0, s1,t1, r,g,b,a, x1-((int)x1), gamma ); SET_GLYPH_VERTEX(vertices[vcount+3], (int)x1,y0,0, s1,t0, r,g,b,a, x1-((int)x1), gamma ); indices[icount + 0] = vcount+0; indices[icount + 1] = vcount+1; indices[icount + 2] = vcount+2; indices[icount + 3] = vcount+0; indices[icount + 4] = vcount+2; indices[icount + 5] = vcount+3; vcount += 4; icount += 6; vertex_buffer_push_back( buffer, vertices, vcount, indices, icount ); pen->x += glyph->advance_x * (1.0 + markup->spacing); } }
// -------------------------------------------------------- console_render --- void console_render( console_t *self ) { char* cur_char; char* prev_char; int viewport[4]; glGetIntegerv( GL_VIEWPORT, viewport ); size_t i, index; self->pen.x = 0; self->pen.y = viewport[3]; vertex_buffer_clear( console->buffer ); int cursor_x = self->pen.x; int cursor_y = self->pen.y; markup_t markup; // console_t buffer markup = self->markup[MARKUP_FAINT]; self->pen.y -= markup.font->height; for( i=0; i<self->lines->size; ++i ) { char *text = * (char **) vector_get( self->lines, i ) ; if( strlen(text) > 0 ) { cur_char = text; prev_char = NULL; console_add_glyph( console, cur_char, prev_char, &markup ); prev_char = cur_char; for( index=1; index < strlen(text)-1; ++index ) { cur_char = text + index; console_add_glyph( console, cur_char, prev_char, &markup ); prev_char = cur_char; } } self->pen.y -= markup.font->height - markup.font->linegap; self->pen.x = 0; cursor_x = self->pen.x; cursor_y = self->pen.y; } // Prompt markup = self->markup[MARKUP_BOLD]; if( strlen( self->prompt ) > 0 ) { cur_char = self->prompt; prev_char = NULL; console_add_glyph( console, cur_char, prev_char, &markup ); prev_char = cur_char; for( index=1; index < strlen(self->prompt); ++index ) { cur_char = self->prompt + index; console_add_glyph( console, cur_char, prev_char, &markup ); prev_char = cur_char; } } cursor_x = (int) self->pen.x; // Input markup = self->markup[MARKUP_NORMAL]; if( strlen(self->input) > 0 ) { cur_char = self->input; prev_char = NULL; console_add_glyph( console, cur_char, prev_char, &markup ); prev_char = cur_char; if( self->cursor > 0) { cursor_x = (int) self->pen.x; } for( index=1; index < strlen(self->input); ++index ) { cur_char = self->input + index; console_add_glyph( console, cur_char, prev_char, &markup ); prev_char = cur_char; if( index < self->cursor ) { cursor_x = (int) self->pen.x; } } } if( self->lines->size || self->prompt[0] != '\0' || self->input[0] != '\0' ) { glBindTexture( GL_TEXTURE_2D, self->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, self->atlas->width, self->atlas->height, 0, GL_RED, GL_UNSIGNED_BYTE, self->atlas->data ); } // Cursor (we use the black character (NULL) as texture ) texture_glyph_t *glyph = texture_font_get_glyph( markup.font, NULL ); float r = markup.foreground_color.r; float g = markup.foreground_color.g; float b = markup.foreground_color.b; float a = markup.foreground_color.a; int x0 = cursor_x+1; int y0 = cursor_y + markup.font->descender; int x1 = cursor_x+2; int y1 = y0 + markup.font->height - markup.font->linegap; float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; GLuint indices[] = {0,1,2, 0,2,3}; vertex_t vertices[] = { { x0,y0,0, s0,t0, r,g,b,a }, { x0,y1,0, s0,t1, r,g,b,a }, { x1,y1,0, s1,t1, r,g,b,a }, { x1,y0,0, s1,t0, r,g,b,a } }; vertex_buffer_push_back( self->buffer, vertices, 4, indices, 6 ); glEnable( GL_TEXTURE_2D ); glUseProgram( shader ); { glUniform1i( glGetUniformLocation( shader, "texture" ), 0 ); glUniformMatrix4fv( glGetUniformLocation( shader, "model" ), 1, 0, model.data); glUniformMatrix4fv( glGetUniformLocation( shader, "view" ), 1, 0, view.data); glUniformMatrix4fv( glGetUniformLocation( shader, "projection" ), 1, 0, projection.data); vertex_buffer_render( console->buffer, GL_TRIANGLES ); } }
// -------------------------------------------------------- console_render --- void console_render( console_t *self ) { int viewport[4]; glGetIntegerv( GL_VIEWPORT, viewport ); size_t i, index; self->pen.x = 0; self->pen.y = viewport[3]; vertex_buffer_clear( console->buffer ); int cursor_x = self->pen.x; int cursor_y = self->pen.y; markup_t markup; // console_t buffer markup = self->markup[MARKUP_FAINT]; self->pen.y -= markup.font->height; for( i=0; i<self->lines->size; ++i ) { wchar_t *text = * (wchar_t **) vector_get( self->lines, i ) ; if( wcslen(text) > 0 ) { console_add_glyph( console, text[0], L'\0', &markup ); for( index=1; index < wcslen(text)-1; ++index ) { console_add_glyph( console, text[index], text[index-1], &markup ); } } self->pen.y -= markup.font->height - markup.font->linegap; self->pen.x = 0; cursor_x = self->pen.x; cursor_y = self->pen.y; } // Prompt markup = self->markup[MARKUP_BOLD]; if( wcslen( self->prompt ) > 0 ) { console_add_glyph( console, self->prompt[0], L'\0', &markup ); for( index=1; index < wcslen(self->prompt); ++index ) { console_add_glyph( console, self->prompt[index], self->prompt[index-1], &markup ); } } cursor_x = (int) self->pen.x; // Input markup = self->markup[MARKUP_NORMAL]; if( wcslen(self->input) > 0 ) { console_add_glyph( console, self->input[0], L'\0', &markup ); if( self->cursor > 0) { cursor_x = (int) self->pen.x; } for( index=1; index < wcslen(self->input); ++index ) { console_add_glyph( console, self->input[index], self->input[index-1], &markup ); if( index < self->cursor ) { cursor_x = (int) self->pen.x; } } } // Cursor (we use the black character (-1) as texture ) texture_glyph_t *glyph = texture_font_get_glyph( markup.font, -1 ); float r = markup.foreground_color.r; float g = markup.foreground_color.g; float b = markup.foreground_color.b; float a = markup.foreground_color.a; int x0 = cursor_x+1; int y0 = cursor_y + markup.font->descender; int x1 = cursor_x+2; int y1 = y0 + markup.font->height - markup.font->linegap; float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; GLuint indices[] = {0,1,2, 0,2,3}; vertex_t vertices[] = { { x0,y0,0, s0,t0, r,g,b,a }, { x0,y1,0, s0,t1, r,g,b,a }, { x1,y1,0, s1,t1, r,g,b,a }, { x1,y0,0, s1,t0, r,g,b,a } }; vertex_buffer_push_back( self->buffer, vertices, 4, indices, 6 ); glEnable( GL_TEXTURE_2D ); glUseProgram( shader ); { glUniform1i( glGetUniformLocation( shader, "texture" ), 0 ); glUniformMatrix4fv( glGetUniformLocation( shader, "model" ), 1, 0, model.data); glUniformMatrix4fv( glGetUniformLocation( shader, "view" ), 1, 0, view.data); glUniformMatrix4fv( glGetUniformLocation( shader, "projection" ), 1, 0, projection.data); vertex_buffer_render( console->buffer, GL_TRIANGLES ); } }
// ------------------------------------------------------------------- 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( atlas, "fonts/Vera.ttf", 400); texture_font_t * small = texture_font_new( atlas, "fonts/Vera.ttf", 18); texture_font_t * title = texture_font_new( atlas, "fonts/Vera.ttf", 32); 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; }
// ------------------------------------------------------------------- init --- void init( void ) { size_t i, j; int ptSize = 50*64; int device_hdpi = 72; int device_vdpi = 72; atlas = texture_atlas_new( 512, 512, 3 ); /* Init freetype */ FT_Library ft_library; assert(!FT_Init_FreeType(&ft_library)); /* Load our fonts */ FT_Face ft_face[NUM_EXAMPLES]; assert(!FT_New_Face( ft_library, fonts[ENGLISH], 0, &ft_face[ENGLISH]) ); assert(!FT_Set_Char_Size( ft_face[ENGLISH], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[ENGLISH] ); // wonderful world of encodings ... force_ucs2_charmap( ft_face[ENGLISH] ); // which we ignore. assert( !FT_New_Face(ft_library, fonts[ARABIC], 0, &ft_face[ARABIC]) ); assert( !FT_Set_Char_Size(ft_face[ARABIC], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[ARABIC] ); force_ucs2_charmap( ft_face[ARABIC] ); assert(!FT_New_Face( ft_library, fonts[CHINESE], 0, &ft_face[CHINESE]) ); assert(!FT_Set_Char_Size( ft_face[CHINESE], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[CHINESE] ); force_ucs2_charmap( ft_face[CHINESE] ); /* Get our harfbuzz font structs */ hb_font_t *hb_ft_font[NUM_EXAMPLES]; hb_ft_font[ENGLISH] = hb_ft_font_create( ft_face[ENGLISH], NULL ); hb_ft_font[ARABIC] = hb_ft_font_create( ft_face[ARABIC] , NULL ); hb_ft_font[CHINESE] = hb_ft_font_create( ft_face[CHINESE], NULL ); /* Create a buffer for harfbuzz to use */ hb_buffer_t *buf = hb_buffer_create(); for (i=0; i < NUM_EXAMPLES; ++i) { hb_buffer_set_direction( buf, text_directions[i] ); /* or LTR */ hb_buffer_set_script( buf, scripts[i] ); /* see hb-unicode.h */ hb_buffer_set_language( buf, hb_language_from_string(languages[i], strlen(languages[i])) ); /* Layout the text */ hb_buffer_add_utf8( buf, texts[i], strlen(texts[i]), 0, strlen(texts[i]) ); hb_shape( hb_ft_font[i], buf, NULL, 0 ); unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); FT_GlyphSlot slot; FT_Bitmap ft_bitmap; float size = 24; size_t hres = 64; FT_Error error; FT_Int32 flags = 0; flags |= FT_LOAD_RENDER; flags |= FT_LOAD_TARGET_LCD; FT_Library_SetLcdFilter( ft_library, FT_LCD_FILTER_LIGHT ); FT_Matrix matrix = { (int)((1.0/hres) * 0x10000L), (int)((0.0) * 0x10000L), (int)((0.0) * 0x10000L), (int)((1.0) * 0x10000L) }; /* Set char size */ error = FT_Set_Char_Size( ft_face[i], (int)(ptSize), 0, 72*hres, 72 ); if( error ) { //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", // __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( ft_face[i] ); break; } /* Set transform matrix */ FT_Set_Transform( ft_face[i], &matrix, NULL ); for (j = 0; j < glyph_count; ++j) { /* Load glyph */ error = FT_Load_Glyph( ft_face[i], glyph_info[j].codepoint, flags ); if( error ) { //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", // __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( ft_face[i] ); break; } slot = ft_face[i]->glyph; ft_bitmap = slot->bitmap; int ft_bitmap_width = slot->bitmap.width; int ft_bitmap_rows = slot->bitmap.rows; int ft_bitmap_pitch = slot->bitmap.pitch; int ft_glyph_top = slot->bitmap_top; int ft_glyph_left = slot->bitmap_left; int w = ft_bitmap_width/3; // 3 because of LCD/RGB encoding int h = ft_bitmap_rows; ivec4 region = texture_atlas_get_region( atlas, w+1, h+1 ); if ( region.x < 0 ) { fprintf( stderr, "Texture atlas is full (line %d)\n", __LINE__ ); continue; } int x = region.x, y = region.y; texture_atlas_set_region( atlas, region.x, region.y, w, h, ft_bitmap.buffer, ft_bitmap.pitch ); printf("%d: %dx%d %f %f\n", glyph_info[j].codepoint, ft_bitmap_width, ft_bitmap_rows, glyph_pos[j].x_advance/64., glyph_pos[j].y_advance/64.); } /* clean up the buffer, but don't kill it just yet */ hb_buffer_reset(buf); } /* Cleanup */ hb_buffer_destroy( buf ); for( i=0; i < NUM_EXAMPLES; ++i ) hb_font_destroy( hb_ft_font[i] ); FT_Done_FreeType( ft_library ); glClearColor(1,1,1,1); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); 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 ); typedef struct { float x,y,z, u,v, r,g,b,a, shift, gamma; } vertex_t; vertex_t vertices[4] = { { 0, 0,0, 0,1, 0,0,0,1, 0, 1}, { 0,512,0, 0,0, 0,0,0,1, 0, 1}, {512,512,0, 1,0, 0,0,0,1, 0, 1}, {512, 0,0, 1,1, 0,0,0,1, 0, 1} }; GLuint indices[6] = { 0, 1, 2, 0,2,3 }; buffer = vertex_buffer_new( "vertex:3f," "tex_coord:2f," "color:4f," "ashift:1f," "agamma:1f" ); vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); 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 ) { 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; }
// ------------------------------------------------------------------- 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, "Distance fields demo", 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 typedef struct { float x,y,z; } xyz; typedef struct { float r,g,b,a; } rgba; typedef struct { xyz position, normal; rgba color; } vertex; xyz v[] = { { 1, 1, 1}, {-1, 1, 1}, {-1,-1, 1}, { 1,-1, 1}, { 1,-1,-1}, { 1, 1,-1}, {-1, 1,-1}, {-1,-1,-1} }; xyz n[] = { { 0, 0, 1}, { 1, 0, 0}, { 0, 1, 0} , {-1, 0, 1}, { 0,-1, 0}, { 0, 0,-1} }; rgba c[] = { {1, 1, 1, 1}, {1, 1, 0, 1}, {1, 0, 1, 1}, {0, 1, 1, 1}, {1, 0, 0, 1}, {0, 0, 1, 1}, {0, 1, 0, 1}, {0, 0, 0, 1} }; vertex vertices[24] = { {v[0],n[0],c[0]}, {v[1],n[0],c[1]}, {v[2],n[0],c[2]}, {v[3],n[0],c[3]}, {v[0],n[1],c[0]}, {v[3],n[1],c[3]}, {v[4],n[1],c[4]}, {v[5],n[1],c[5]}, {v[0],n[2],c[0]}, {v[5],n[2],c[5]}, {v[6],n[2],c[6]}, {v[1],n[2],c[1]}, {v[1],n[3],c[1]}, {v[6],n[3],c[6]}, {v[7],n[3],c[7]}, {v[2],n[3],c[2]}, {v[7],n[4],c[7]}, {v[4],n[4],c[4]}, {v[3],n[4],c[3]}, {v[2],n[4],c[2]}, {v[4],n[5],c[4]}, {v[7],n[5],c[7]}, {v[6],n[5],c[6]}, {v[5],n[5],c[5]} }; GLuint indices[24] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11, 12,13,14,15, 16,17,18,19, 20,21,22,23 }; cube = vertex_buffer_new( "vertex:3f,normal:3f,color:4f" ); vertex_buffer_push_back( cube, vertices, 24, indices, 24 ); shader = shader_load("shaders/cube.vert","shaders/cube.frag"); init( ); glfwSetWindowSize( window, 400, 400 ); glfwShowWindow( window ); glfwSetTime(0.0); while(!glfwWindowShouldClose( window )) { display( window ); glfwPollEvents( ); } glfwDestroyWindow( window ); glfwTerminate( ); return EXIT_SUCCESS; }
static void update_buffer(sprite_t* self) { int status = ((node_t*)self)->updated; const vec4* col = &(((node_t*)self)->color); float r = col->r; float g = col->g; float b = col->b; float a = col->a; vec4* bbox = & ( ((node_t*) self)->bbox ); vec2* size = & ( ((node_t*) self)->size ); const vec4* coords; float sw, sh; float x0,y0,x1,y1,s0,s1,t0,t1; V4F_T2F_C4F vertices[4]; int update_model; if (status & SEN_NODE_UPDATE_INVALIDATE_BUFFER) { vertex_buffer_invalidate(self->quad); status &= ~SEN_NODE_UPDATE_INVALIDATE_BUFFER; } if (status & SEN_NODE_UPDATE_BBOX) { vertex_buffer_clear(self->quad); sw = self->tex->img_width / 2.0f; sh = self->tex->img_height / 2.0f; x0 = -sw; x1 = sw; y0 = -sh; y1 = sh; coords = &(self->tex->coords); s0 = coords->s0; t0 = coords->t0; s1 = coords->s1; t1 = coords->t1; /* V4F_T2F_C4F vertices[4] = {{ -sw,-sh,0,1, coords->s0,coords->t1, col->r,col->g,col->b,col->a,}, { -sw, sh,0,1, coords->s0,coords->t0, col->r,col->g,col->b,col->a,}, { sw, sh,0,1, coords->s1,coords->t0, col->r,col->g,col->b,col->a,}, { sw,-sh,0,1, coords->s1,coords->t1, col->r,col->g,col->b,col->a,}};*/ vertices[0].x = (float)x0; vertices[0].y = (float)y0; vertices[0].z = 0.0f; vertices[0].w = 1.0f; vertices[0].s = s0; vertices[0].t = t1; vertices[0].r = r; vertices[0].g = g; vertices[0].b = b; vertices[0].a = a; vertices[1].x = (float)x0; vertices[1].y = (float)y1; vertices[1].z = 0.0f; vertices[1].w = 1.0f; vertices[1].s = s0; vertices[1].t = t0; vertices[1].r = r; vertices[1].g = g; vertices[1].b = b; vertices[1].a = a; vertices[2].x = (float)x1; vertices[2].y = (float)y1; vertices[2].z = 0.0f; vertices[2].w = 1.0f; vertices[2].s = s1; vertices[2].t = t0; vertices[2].r = r; vertices[2].g = g; vertices[2].b = b; vertices[2].a = a; vertices[3].x = (float)x1; vertices[3].y = (float)y0; vertices[3].z = 0.0f; vertices[3].w = 1.0f; vertices[3].s = s1; vertices[3].t = t1; vertices[3].r = r; vertices[3].g = g; vertices[3].b = b; vertices[3].a = a; bbox->x = -sw; bbox->y = -sh; bbox->z = sw; bbox->w = sh; size->x = (float) (self->tex->img_width); size->y = (float) (self->tex->img_height); vertex_buffer_push_back( self->quad, vertices, 4, indices, 6 ); // vertex_buffer_push_back_vertices( self->quad, vertices, 4); memcpy(self->vertices, vertices, sizeof(vertices)); status &= ~SEN_NODE_UPDATE_BBOX; status |= SEN_NODE_UPDATE_MODEL; } update_model = status & SEN_NODE_UPDATE_MODEL; if ( status & (SEN_NODE_UPDATE_MODEL | SEN_NODE_UPDATE_COLOR)) { //V4F_T2F_C4F vertices[4]; // memcpy(vertices, self->vertices, 4*sizeof(V4F_T2F_C4F)); const mat4* model = sen_node_model(self); int i; for (i=0; i<4; ++i) { if (update_model) { // vec4* v = (vec4*) ( i*sizeof(V4F_T2F_C4F )+(self->quad->vertices->items)); //vec4* v = (vec4*) ( i*sizeof(V4F_T2F_C4F )+(vertices)); //vec4* v = (vec4*) (& vertices[i]);// ( i*sizeof(V4F_T2F_C4F )+(vertices)); vec4* vp = (vec4*) (& (self->vertices[i]) ); vec4* v = (vec4*) ( (char*)(self->quad->vertices->items) + i*sizeof(V4F_T2F_C4F ) ); //v4_transform(model->data, v->data,v->data); v4_transform(model->data, vp->data,v->data); if ( i ) { if (v->x < bbox->x) bbox->x = v->x; else if (v->x > bbox->z) bbox->z = v->x; if (v->y < bbox->y) bbox->y = v->y; else if (v->y > bbox->w) bbox->w = v->y; } else { bbox->x = bbox->z = v->x; bbox->y = bbox->w = v->y; } } if (status & SEN_NODE_UPDATE_COLOR) { vec4* c = (vec4*) ( (char*)(self->quad->vertices->items)+ i*sizeof(V4F_T2F_C4F )+ sizeof(float)*6); // vec4* c = (vec4*) ( i*sizeof(V4F_T2F_C4F )+sizeof(float)*6+(vertices)); //vec4* c = (vec4*) (& (vertices[i].r) );// i*sizeof(V4F_T2F_C4F )+sizeof(float)*6+(vertices)); // vec4* c = (vec4*) (& (self->vertices[i].r) );// i*sizeof(V4F_T2F_C4F )+sizeof(float)*6+(vertices)); memcpy(c,col,sizeof(vec4)); } } //self->quad->state = 1; status &= ~(SEN_NODE_UPDATE_COLOR|SEN_NODE_UPDATE_MODEL|SEN_NODE_UPDATE_PARENT_MODEL); } ((node_t*)self)->updated = status; }
// ------------------------------------------------------------------- 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 ) { size_t i, j; int ptSize = 50*64; int device_hdpi = 72; int device_vdpi = 72; glutInit( &argc, argv ); glutInitWindowSize( 512, 512 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( argv[0] ); 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_atlas_t * atlas = texture_atlas_new( 512, 512, 3 ); /* Init freetype */ FT_Library ft_library; assert(!FT_Init_FreeType(&ft_library)); /* Load our fonts */ FT_Face ft_face[NUM_EXAMPLES]; assert(!FT_New_Face( ft_library, fonts[ENGLISH], 0, &ft_face[ENGLISH]) ); assert(!FT_Set_Char_Size( ft_face[ENGLISH], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[ENGLISH] ); // wonderful world of encodings ... force_ucs2_charmap( ft_face[ENGLISH] ); // which we ignore. assert( !FT_New_Face(ft_library, fonts[ARABIC], 0, &ft_face[ARABIC]) ); assert( !FT_Set_Char_Size(ft_face[ARABIC], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[ARABIC] ); force_ucs2_charmap( ft_face[ARABIC] ); assert(!FT_New_Face( ft_library, fonts[CHINESE], 0, &ft_face[CHINESE]) ); assert(!FT_Set_Char_Size( ft_face[CHINESE], 0, ptSize, device_hdpi, device_vdpi ) ); // ftfdump( ft_face[CHINESE] ); force_ucs2_charmap( ft_face[CHINESE] ); /* Get our harfbuzz font structs */ hb_font_t *hb_ft_font[NUM_EXAMPLES]; hb_ft_font[ENGLISH] = hb_ft_font_create( ft_face[ENGLISH], NULL ); hb_ft_font[ARABIC] = hb_ft_font_create( ft_face[ARABIC] , NULL ); hb_ft_font[CHINESE] = hb_ft_font_create( ft_face[CHINESE], NULL ); /* Create a buffer for harfbuzz to use */ hb_buffer_t *buf = hb_buffer_create(); for (i=0; i < NUM_EXAMPLES; ++i) { hb_buffer_set_direction( buf, text_directions[i] ); /* or LTR */ hb_buffer_set_script( buf, scripts[i] ); /* see hb-unicode.h */ hb_buffer_set_language( buf, hb_language_from_string(languages[i], strlen(languages[i])) ); /* Layout the text */ hb_buffer_add_utf8( buf, texts[i], strlen(texts[i]), 0, strlen(texts[i]) ); hb_shape( hb_ft_font[i], buf, NULL, 0 ); unsigned int glyph_count; hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); FT_GlyphSlot slot; FT_Bitmap ft_bitmap; float size = 24; size_t hres = 64; FT_Error error; FT_Int32 flags = 0; flags |= FT_LOAD_RENDER; flags |= FT_LOAD_TARGET_LCD; FT_Library_SetLcdFilter( ft_library, FT_LCD_FILTER_LIGHT ); FT_Matrix matrix = { (int)((1.0/hres) * 0x10000L), (int)((0.0) * 0x10000L), (int)((0.0) * 0x10000L), (int)((1.0) * 0x10000L) }; /* Set char size */ error = FT_Set_Char_Size( ft_face[i], (int)(ptSize), 0, 72*hres, 72 ); if( error ) { //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", // __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( ft_face[i] ); break; } /* Set transform matrix */ FT_Set_Transform( ft_face[i], &matrix, NULL ); for (j = 0; j < glyph_count; ++j) { /* Load glyph */ error = FT_Load_Glyph( ft_face[i], glyph_info[j].codepoint, flags ); if( error ) { //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n", // __LINE__, FT_Errors[error].code, FT_Errors[error].message ); FT_Done_Face( ft_face[i] ); break; } slot = ft_face[i]->glyph; ft_bitmap = slot->bitmap; int ft_bitmap_width = slot->bitmap.width; int ft_bitmap_rows = slot->bitmap.rows; int ft_bitmap_pitch = slot->bitmap.pitch; int ft_glyph_top = slot->bitmap_top; int ft_glyph_left = slot->bitmap_left; int w = ft_bitmap_width/3; // 3 because of LCD/RGB encoding int h = ft_bitmap_rows; ivec4 region = texture_atlas_get_region( atlas, w+1, h+1 ); if ( region.x < 0 ) { fprintf( stderr, "Texture atlas is full (line %d)\n", __LINE__ ); continue; } int x = region.x, y = region.y; texture_atlas_set_region( atlas, region.x, region.y, w, h, ft_bitmap.buffer, ft_bitmap.pitch ); printf("%d: %dx%d %f %f\n", glyph_info[j].codepoint, ft_bitmap_width, ft_bitmap_rows, glyph_pos[j].x_advance/64., glyph_pos[j].y_advance/64.); } /* clean up the buffer, but don't kill it just yet */ hb_buffer_reset(buf); } /* Cleanup */ hb_buffer_destroy( buf ); for( i=0; i < NUM_EXAMPLES; ++i ) hb_font_destroy( hb_ft_font[i] ); FT_Done_FreeType( ft_library ); 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 ); typedef struct { float x,y,z, u,v, r,g,b,a, shift, gamma; } vertex_t; vertex_t vertices[4] = { { 0, 0,0, 0,1, 0,0,0,1, 0, 1}, { 0,512,0, 0,0, 0,0,0,1, 0, 1}, {512,512,0, 1,0, 0,0,0,1, 0, 1}, {512, 0,0, 1,1, 0,0,0,1, 0, 1} }; GLuint indices[6] = { 0, 1, 2, 0,2,3 }; buffer = vertex_buffer_new( "vertex:3f," "tex_coord:2f," "color:4f," "ashift:1f," "agamma:1f" ); vertex_buffer_push_back( buffer, vertices, 4, indices, 6 ); shader = shader_load("shaders/text.vert", "shaders/text.frag"); mat4_set_identity( &projection ); mat4_set_identity( &model ); mat4_set_identity( &view ); glutMainLoop( ); return 0; }
// ------------------------------------------------------------------- main --- int main( int argc, char **argv ) { #ifndef FT_CONFIG_OPTION_SUBPIXEL_RENDERING fprintf(stderr, "This demo requires freetype to be compiled " "with subpixel rendering.\n"); exit( EXIT_FAILURE) ; #endif glutInit( &argc, argv ); glutInitWindowSize( 260, 330 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); glutCreateWindow( argv[0] ); 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 buffer = vertex_buffer_new( "vertex:3f,color:4f" ); vertex_t vertices[4*2] = { { 15, 0,0, 0,0,0,1}, { 15,330,0, 0,0,0,1}, {245, 0,0, 0,0,0,1}, {245,330,0, 0,0,0,1} }; GLuint indices[4*3] = { 0,1,2,3, }; vertex_buffer_push_back( buffer, vertices, 4, indices, 4 ); text_buffer = text_buffer_new( LCD_FILTERING_ON ); vec4 black = {{0.0, 0.0, 0.0, 1.0}}; text_buffer->base_color = black; vec4 none = {{1.0, 1.0, 1.0, 0.0}}; markup_t markup; markup.family = "fonts/Vera.ttf"; markup.size = 9.0; markup.bold = 0; markup.italic = 0; markup.rise = 0.0; markup.spacing = 0.0; markup.gamma = 1.0; markup.foreground_color = black; markup.background_color = none; markup.underline = 0; markup.underline_color = black; markup.overline = 0; markup.overline_color = black; markup.strikethrough = 0; markup.strikethrough_color = black; markup.font = 0; size_t i; vec2 pen = {{20, 320}}; wchar_t *text = L"| A Quick Brown Fox Jumps Over The Lazy Dog\n"; for( i=0; i < 30; ++i) { text_buffer_add_text( text_buffer, &pen, &markup, text, wcslen(text) ); pen.x += i*0.1; } 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; }
// ------------------------------------------------------------------- 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_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; }
// ------------------------------------------------------------------- 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 ); }