bool FontRenderer::InitFontRenderer() { m_pManager = font_manager_new( 512, 512, 1 ); if (!m_pManager) { fprintf(stderr, "%s:%d - error initializing the font manager\n", __FILE__, __LINE__); return false; } m_pFont = font_manager_get_from_markup( m_pManager, &markup ); if (!m_pFont) { fprintf(stderr, "%s:%d - error getting the font\n", __FILE__, __LINE__); return false; } m_pTextBuffer = vertex_buffer_new( "v3f:t2f:c4f" ); if (!m_pTextBuffer) { fprintf(stderr, "%s:%d - error creating the text buffer\n", __FILE__, __LINE__); return false; } if (!m_fontShader.InitFontShader()) { fprintf(stderr, "%s:%d - error compiling the shader program\n", __FILE__, __LINE__); return false; } m_fontShader.Enable(); m_fontShader.SetFontMapTextureUnit(0); return true; }
// ---------------------------------------------------------------------------- void text_buffer_add_text( text_buffer_t * self, vec2 * pen, markup_t * markup, const char * text, size_t length ) { font_manager_t * manager = self->manager; size_t i; const char * prev_character = NULL; if( markup == NULL ) { return; } if( !markup->font ) { markup->font = font_manager_get_from_markup( manager, markup ); if( ! markup->font ) { fprintf( stderr, "Houston, we've got a problem !\n" ); exit( EXIT_FAILURE ); } } if( length == 0 ) { length = utf8_strlen(text); } if( vertex_buffer_size( self->buffer ) == 0 ) { self->origin = *pen; self->line_left = pen->x; self->bounds.left = pen->x; self->bounds.top = pen->y; } else { if (pen->x < self->origin.x) { self->origin.x = pen->x; } if (pen->y != self->last_pen_y) { text_buffer_finish_line(self, pen, false); } } for( i = 0; utf8_strlen( text + i ) && length; i += utf8_surrogate_len( text + i ) ) { text_buffer_add_char( self, pen, markup, text + i, prev_character ); prev_character = text + i; length--; } self->last_pen_y = pen->y; }
/* ----------------------------------------------------------------- print - */ void TextRender::print(const std::wstring &_text, const float &_x, const float &_y) { m_mutex.lock(); m_pen = { { _x, _y } }; m_markup.font = font_manager_get_from_markup(m_text_buffer->manager, &m_markup); text_buffer_clear(m_text_buffer); text_buffer_add_text(m_text_buffer, &m_pen, &m_markup, const_cast<wchar_t*>(_text.c_str()), _text.size()); m_mutex.unlock(); }
// ------------------------------------------------------------------ print --- void print( text_buffer_t * buffer, vec2 * pen, char *text, markup_t *markup ) { char *seq_start = text, *seq_end = text; char *p; size_t i; for( p=text; p<(text+strlen(text)); ++p ) { char *start = strstr( p, "\033[" ); char *end = NULL; if( start) { end = strstr( start+1, "m" ); } if( (start == p) && (end > start) ) { seq_start = start+2; seq_end = end; p = end; } else { int seq_size = (seq_end-seq_start)+1; char * text_start = p; int text_size = 0; if( start ) { text_size = start-p; p = start-1; } else { text_size = text+strlen(text)-p; p = text+strlen(text); } ansi_to_markup(seq_start, seq_size, markup ); markup->font = font_manager_get_from_markup( buffer->manager, markup ); text_buffer_add_text( buffer, pen, markup, text_start, text_size ); } } }
// ---------------------------------------------------------------------------- void text_buffer_add_text( text_buffer_t * self, vec2 * pen, markup_t * markup, wchar_t * text, size_t length ) { font_manager_t * manager = self->manager; size_t i; if( markup == NULL ) { return; } if( !markup->font ) { markup->font = font_manager_get_from_markup( manager, markup ); if( ! markup->font ) { fprintf( stderr, "Houston, we've got a problem !\n" ); exit( EXIT_FAILURE ); } } if( length == 0 ) { length = wcslen(text); } if( vertex_buffer_size( self->buffer ) == 0 ) { self->origin = *pen; } text_buffer_add_wchar( self, pen, markup, text[0], 0 ); for( i=1; i<length; ++i ) { text_buffer_add_wchar( self, pen, markup, text[i], text[i-1] ); } }
void CFont::TextAdd(float x, float y, float _size, float rectw, float recth, const char *text, const unsigned length) { bool hasSizeChange = abs(_size - normal.size) > 0.01f; bool hasTextChange = (0 == lasttext.size() || 0 != strcmp(text, lasttext.c_str())); if (hasSizeChange || hasTextChange || nullptr == font_manager) { // DONE: rebuild a font texture and atlas if (nullptr != font_manager) { glDeleteTextures(1, &font_manager->atlas->id); font_manager->atlas->id = 0; font_manager_delete(font_manager); font_manager = nullptr; } normal.size = _size; font_manager = font_manager_new(ATLAS_SIZE, ATLAS_SIZE, LCD_FILTERING_ON); normal.font = font_manager_get_from_markup(font_manager, &normal); normal.font->kerning = 0; text_buffer_clear(buffer); vec2 pen = { { 0, 0 } }; text_buffer_add_text(buffer, &pen, &normal, text, length); //text_buffer_align(buffer, &pen, ALIGN_CENTER); 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); vec4 bounds = text_buffer_get_bounds(buffer, &pen); mBounds[0] = bounds.x; mBounds[1] = bounds.y; mBounds[2] = bounds.z; mBounds[3] = bounds.w; lasttext = text; } // //vec2 pen = { { x, y } }; //text_buffer_add_text(buffer, &pen, &normal, text, length); mat4_set_identity(&model); float stretch = 1.01f; // mBounds[2] / (0.8f * rectw); float xoffset = 0.25f * mBounds[2] / length; float yoffset = recth - 0.5f * (recth - mBounds[3]); mat4_set_scaling(&model, stretch, 1.0f, 1.0f); mat4_translate(&model, x + xoffset, y + yoffset, 0.0f); }
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_text( text_buffer_t * self, vec2 * pen, markup_t * markup, wchar_t * text, size_t length ) { vertex_buffer_t * buffer = self->buffer; font_manager_t * manager = self->manager; if( markup == NULL ) { return; } if( !markup->font ) { markup->font = font_manager_get_from_markup( manager, markup ); if( ! markup->font ) { fprintf( stderr, "Houston, we've got a problem !\n" ); exit( EXIT_FAILURE ); } } if( length == 0 ) { length = wcslen(text); } if( vertex_buffer_size( self->buffer ) == 0 ) { self->origin = *pen; } if( markup->font->ascender > self->line_ascender ) { size_t i, j; float dy = (int)(markup->font->ascender - self->line_ascender); for( i=self->line_start; i < vector_size( buffer->items ); ++i ) { ivec4 *item = (ivec4 *) vector_get( buffer->items, i); for( j=item->vstart; j<item->vstart+item->vcount; ++j) { glyph_vertex_t * vertex = (glyph_vertex_t *) vector_get( buffer->vertices, j ); vertex->y -= dy; } } self->line_ascender = markup->font->ascender; pen->y -= dy; } if( markup->font->descender < self->line_descender ) { self->line_descender = markup->font->descender; } text_buffer_add_wchar( self, pen, markup, text[0], 0 ); size_t i; for( i=1; i<length; ++i ) { text_buffer_add_wchar( self, pen, markup, text[i], text[i-1] ); } }