// ----------------------------------------------------- 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; } } }
Vector2 Render::GetTextSize(const Font& font, const std::string& text) { float totalW = 0; float totalH = 0; float cx = 0; float cy = 0; unsigned long len = text.size(); for (unsigned long i = 0; i < len; i++) { char l = text[i]; texture_glyph_t* glyph = texture_font_get_glyph(font.FontHandle, (wchar_t)text[i]); if (glyph == null) { TL_ASSERT(false); return Vector2::Zero; } if (i > 0) { cx += texture_glyph_get_kerning(glyph, text[i - 1]); } if (l == '\n') { cy += font.FontHandle->height; cx = 0; continue; } cx += glyph->advance_x; if (cx > totalW) totalW = cx; if (cy + font.FontHandle->height > totalH) totalH = cy + font.FontHandle->height; } return Vector2(totalW, totalH); }
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; } } }
void FontRenderer::RenderText(unsigned int x, unsigned int y, const char* pText) { bool IsCullEnabled = glIsEnabled(GL_CULL_FACE); glDisable(GL_CULL_FACE); assert(strlen(pText) < MAX_STRING_LEN); wchar_t text[MAX_STRING_LEN] = { 0 }; int len = mbstowcs(text, pText, strlen(pText)); assert(len > 0); vertex_buffer_clear( m_pTextBuffer ); TextureGlyph* pGlyph = texture_font_get_glyph( m_pFont, text[0] ); assert(pGlyph); Pen pen = {(float)x, (float)y}; texture_glyph_add_to_vertex_buffer( pGlyph, m_pTextBuffer, &markup, &pen, 0 ); for( size_t i=1; i<wcslen(text); ++i ) { pGlyph = texture_font_get_glyph( m_pFont, text[i] ); assert(pGlyph); int kerning = texture_glyph_get_kerning( pGlyph, text[i-1] ); texture_glyph_add_to_vertex_buffer( pGlyph, m_pTextBuffer, &markup, &pen, kerning ); } glActiveTexture(GL_TEXTURE0); glBindTexture( GL_TEXTURE_2D, m_pManager->atlas->texid ); m_fontShader.Enable(); int viewport[4]; glGetIntegerv( GL_VIEWPORT, viewport ); float xScale = 2.0f / (float)viewport[2]; float yScale = 2.0f / (float)viewport[3]; GLfloat Trans[] = { xScale, 0.0f, 0.0f, -1.0f, 0.0f, yScale, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; m_fontShader.SetTransformation(Trans); vertex_buffer_render( m_pTextBuffer, GL_TRIANGLES, "vtc" ); if (IsCullEnabled) { glEnable(GL_CULL_FACE); } }
/** * @text * @floatarray [advance,kerning...] * @start optional * @end optional */ METHOD_BEGIN(measure, info) { HandleScope scope; Font* font = internalPtr<Font>(info, CLASS_Font); if(font == 0) { return; } // text v8::Local<v8::String> tmp = info[0]->ToString(); int length = tmp->Length(); uint16_t uchars[length + 1]; tmp->Write(uchars); // Float32Array ClassBase* ptr = internalArg<ClassBase>(info[1], CLASS_Float32Array); if(ptr == 0) { ThrowException(String::New("Font.measure Float32Array not found")); return; } ByteBuffer buf; ptr->getUnderlying(&buf); // start and end int start = 0; int end = length; if(info.Length() >= 3) { start = info[2]->Uint32Value(); } if(info.Length() >= 4) { end = info[3]->Uint32Value(); } // setup for(int i = start; i < end; i++) { texture_glyph_t *glyph = texture_font_get_glyph(font->font, uchars[i] ); if(glyph != NULL) { if(i > 0) { float values[2] = { glyph->advance_x, texture_glyph_get_kerning(glyph, uchars[i - 1]) }; buf.set_value<float>((i - start) * 2, values, 2); } else { float values[2] = { glyph->advance_x, 0 }; buf.set_value<float>((i - start) * 2, values, 2); } } else { float values[2] = { 0, 0 }; buf.set_value<float>((i - start) * 2, values, 2); } } }
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; }
float OLabel::getWordWidth(const std::string& word) { float width = 0; const maths::vec2& scale = m_Font->GetScale(); ftgl::texture_font_t* ftFont = m_Font->GetFTFont(); for (uint i = 0; i < word.length(); i++) { char c = word[i]; ftgl::texture_glyph_t* glyph = texture_font_get_glyph(ftFont, c); if (glyph != nullptr) { if (i > 0) { float kerning = texture_glyph_get_kerning(glyph, m_Text[i - 1]); width += kerning / scale.x; } float gwidth = glyph->advance_x / scale.x; width += gwidth; } } return width; }
// --------------------------------------------------------------- add_text --- void add_text( vertex_buffer_t * buffer, texture_font_t * font, char * 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 < 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 index = buffer->vertices->size; GLuint indices[] = {index, index+1, index+2, index, index+2, index+3}; vertex_t vertices[] = { { x0,y0,0, s0,t0, r,g,b,a, 0,1 }, { x0,y1,0, s0,t1, r,g,b,a, 0,1 }, { x1,y1,0, s1,t1, r,g,b,a, 0,1 }, { x1,y0,0, s1,t0, r,g,b,a, 0,1 } }; vertex_buffer_push_back_indices( buffer, indices, 6 ); vertex_buffer_push_back_vertices( buffer, vertices, 4 ); pen->x += glyph->advance_x; } } }
// --------------------------------------------------------------- add_text --- void add_text( vertex_buffer_t * buffer, texture_font_t * font, char *text, vec2 pen, vec4 fg_color_1, vec4 fg_color_2 ) { size_t i; for( i = 0; i < strlen(text); ++i ) { texture_glyph_t *glyph = texture_font_get_glyph( font, text + i ); float kerning = 0.0f; if( i > 0) { kerning = texture_glyph_get_kerning( glyph, text + i - 1 ); } pen.x += kerning; /* Actual glyph */ 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; GLuint index = buffer->vertices->size; GLuint indices[] = {index, index+1, index+2, index, index+2, index+3}; vertex_t vertices[] = { { (int)x0,y0,0, s0,t0, fg_color_1 }, { (int)x0,y1,0, s0,t1, fg_color_2 }, { (int)x1,y1,0, s1,t1, fg_color_2 }, { (int)x1,y0,0, s1,t0, fg_color_1 } }; vertex_buffer_push_back_indices( buffer, indices, 6 ); vertex_buffer_push_back_vertices( buffer, vertices, 4 ); pen.x += glyph->advance_x; } }
void mesh_init_vertices_text() { int i,j,k, kerning = 0; float x0,y0,x1,y1; float s0,t0,s1,t1; float base_x = m_text.base_1_x; float base_y = m_text.base_1_y; texture_glyph_t *glyph; m_text.char_len_1 = swprintf(m_text.text_1, 8, L"%d/%d", m_info.next_image, m_info.image_count); if(m_text.char_len_1 > 0) { for(i=0;i<m_text.char_len_1;i++) { glyph = texture_font_get_glyph(m_texture.text_font, m_text.text_1[i]); if( glyph != NULL ) { kerning = 0; if( i > 0) //test if needed {kerning = texture_glyph_get_kerning( glyph, m_text.text_1[i-1] );} base_x += kerning; /* x0 = ( base_x + (float)glyph->offset_x ); y0 = ( base_y + (float)glyph->offset_y ); x1 = ( x0 + (float)glyph->width ); y1 = ( y0 - (float)glyph->height ); */ x0 = ( base_x + (((float)glyph->offset_x)*4/3) ); y0 = ( base_y + (float)glyph->offset_y ); x1 = ( x0 + (((float)glyph->width)*4/3) ); y1 = ( y0 - (float)glyph->height ); x0 = (2*x0)/m_display.scr_width; x1 = (2*x1)/m_display.scr_width; y0 = (2*y0)/m_display.scr_height; y1 = (2*y1)/m_display.scr_height; s0 = glyph->s0; t0 = glyph->t0; s1 = glyph->s1; t1 = glyph->t1; j=18*i; k=12*i; m_mesh.m_attribute.pos_text[j]=x0; m_mesh.m_attribute.pos_text[j+1]=y0; m_mesh.m_attribute.pos_text[j+2]=0.0; m_mesh.m_attribute.texCoord_text[k]=s0; m_mesh.m_attribute.texCoord_text[k+1]=t0; m_mesh.m_attribute.pos_text[j+3]=x0; m_mesh.m_attribute.pos_text[j+4]=y1; m_mesh.m_attribute.pos_text[j+5]=0.0; m_mesh.m_attribute.texCoord_text[k+2]=s0; m_mesh.m_attribute.texCoord_text[k+3]=t1; m_mesh.m_attribute.pos_text[j+6]=x1; m_mesh.m_attribute.pos_text[j+7]=y1; m_mesh.m_attribute.pos_text[j+8]=0.0; m_mesh.m_attribute.texCoord_text[k+4]=s1; m_mesh.m_attribute.texCoord_text[k+5]=t1; m_mesh.m_attribute.pos_text[j+9]=x0; m_mesh.m_attribute.pos_text[j+10]=y0; m_mesh.m_attribute.pos_text[j+11]=0.0; m_mesh.m_attribute.texCoord_text[k+6]=s0; m_mesh.m_attribute.texCoord_text[k+7]=t0; m_mesh.m_attribute.pos_text[j+12]=x1; m_mesh.m_attribute.pos_text[j+13]=y1; m_mesh.m_attribute.pos_text[j+14]=0.0; m_mesh.m_attribute.texCoord_text[k+8]=s1; m_mesh.m_attribute.texCoord_text[k+9]=t1; m_mesh.m_attribute.pos_text[j+15]=x1; m_mesh.m_attribute.pos_text[j+16]=y0; m_mesh.m_attribute.pos_text[j+17]=0.0; m_mesh.m_attribute.texCoord_text[k+10]=s1; m_mesh.m_attribute.texCoord_text[k+11]=t0; //base_x += glyph->advance_x; base_x += (((float)glyph->advance_x)*4/3); } } } }
// --------------------------------------------------------------- add_text --- void add_text( vertex_buffer_t * buffer, vec2 * pen, ... ) { markup_t *markup; char *text; va_list args; va_start ( args, pen ); do { markup = va_arg( args, markup_t * ); if( markup == NULL ) { break; } text = va_arg( args, char * ); size_t i; texture_font_t * font = markup->font; float r = markup->foreground_color.red; float g = markup->foreground_color.green; float b = markup->foreground_color.blue; float a = markup->foreground_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; /* Actual glyph */ 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; GLuint index = buffer->vertices->size; GLuint indices[] = {index, index+1, index+2, index, index+2, index+3 }; vertex_t vertices[] = { { (int)x0,y0,0, s0,t0, r,g,b,a }, { (int)x0,y1,0, s0,t1, r,g,b,a }, { (int)x1,y1,0, s1,t1, r,g,b,a }, { (int)x1,y0,0, s1,t0, r,g,b,a } }; vertex_buffer_push_back_indices( buffer, indices, 6 ); vertex_buffer_push_back_vertices( buffer, vertices, 4 ); pen->x += glyph->advance_x; } } } while( markup != 0 ); va_end ( args ); }
// ---------------------------------------------------------------------------- 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); } }
void BatchRenderer2D::drawString(const std::string& text, const vec3& position, const Font& font, unsigned int color) { float samplerIndex = 0.0f; bool found = false; for (size_t i = 0; i < m_Textures.size(); i++) { if (m_Textures[i] == font.getID()) { found = true; samplerIndex = (float)(i + 1); break; } } if (!found) { if (m_Textures.size() >= MAX_TEXTURES) { end(); begin(); } m_Textures.push_back(font.getID()); samplerIndex = (float)m_Textures.size(); } float x = position.x; const vec2& scale = font.getScale(); for (size_t i = 0; i < text.length(); i++) { const char& c = text[i]; ftgl::texture_glyph_t* glyph = ftgl::texture_font_get_glyph(font.getFont(), c); if (glyph) { if (i > 0) { float kerning = texture_glyph_get_kerning(glyph, text[i - 1]); x += kerning / scale.x; } float x0 = x + glyph->offset_x / scale.x; float y0 = position.y + glyph->offset_y / scale.y; float x1 = x0 + glyph->width / scale.x; float y1 = y0 - glyph->height / scale.y; float u0 = glyph->s0; float v0 = glyph->t0; float u1 = glyph->s1; float v1 = glyph->t1; m_Buffer->position = *m_TransformationBack * vec3(x0, y0, 0.0f); m_Buffer->uv = vec2(u0, v0); m_Buffer->sampler = samplerIndex; m_Buffer->color = color; m_Buffer++; m_Buffer->position = *m_TransformationBack * vec3(x0, y1, 0.0f); m_Buffer->uv = vec2(u0, v1); m_Buffer->sampler = samplerIndex; m_Buffer->color = color; m_Buffer++; m_Buffer->position = *m_TransformationBack * vec3(x1, y1, 0.0f); m_Buffer->uv = vec2(u1, v1); m_Buffer->sampler = samplerIndex; m_Buffer->color = color; m_Buffer++; m_Buffer->position = *m_TransformationBack * vec3(x1, y0, 0.0f); m_Buffer->uv = vec2(u1, v0); m_Buffer->sampler = samplerIndex; m_Buffer->color = color; m_Buffer++; m_IndexCount += 6; x += glyph->advance_x / scale.x; } } /*m_Buffer->position = vec3(-8, -8, 0); m_Buffer->uv = vec2(0, 1); m_Buffer->sampler = samplerIndex; m_Buffer->color = color; m_Buffer++; m_Buffer->position = vec3(8, -8, 0); m_Buffer->uv = vec2(1, 1); m_Buffer->sampler = samplerIndex; m_Buffer->color = color; m_Buffer++; m_Buffer->position = vec3(8, 8, 0); m_Buffer->uv = vec2(1, 0); m_Buffer->sampler = samplerIndex; m_Buffer->color = color; m_Buffer++; m_Buffer->position = vec3(-8, 8, 0); m_Buffer->uv = vec2(0, 0); m_Buffer->sampler = samplerIndex; m_Buffer->color = color; m_Buffer++; m_IndexCount += 6;*/ }
// ----------------------------------------------------------- build_buffer --- void build_buffer( void ) { vec2 pen; size_t i; texture_font_t *font; texture_glyph_t *glyph; vec4 white = {{1.0, 1.0, 1.0, 1.0}}; vec4 none = {{1.0, 1.0, 1.0, 0.0}}; markup_t markup = { .family = "Arial", .size = 10.0, .bold = 0, .italic = 0, .rise = 0.0, .spacing = 0.0, .gamma = 2.2, .foreground_color = white, .background_color = none, .underline = 0, .underline_color = white, .overline = 0, .overline_color = white, .strikethrough = 0, .strikethrough_color = white, .font = 0, }; vertex_buffer_clear( buffer ); texture_atlas_clear( atlas ); if( p_family == VERA) { font = texture_font_new( atlas, "fonts/Vera.ttf", p_size ); } else if( p_family == VERA_MONO) { font = texture_font_new( atlas, "fonts/VeraMono.ttf", p_size ); } else if( p_family == GEORGIA) { font = texture_font_new( atlas, "fonts/Georgia.ttf", p_size ); } else if( p_family == TIMES ) { font = texture_font_new( atlas, "fonts/Times.ttf", p_size ); } else if( p_family == TAHOMA ) { font = texture_font_new( atlas, "fonts/Tahoma.ttf", p_size ); } else if( p_family == ARIAL ) { font = texture_font_new( atlas, "fonts/Arial.ttf", p_size ); } else if( p_family == VERDANA ) { font = texture_font_new( atlas, "fonts/Verdana.ttf", p_size ); } else { fprintf( stderr, "Error : Unknown family type\n" ); return; } font->hinting = p_hinting; font->filtering = 1; float norm = 1.0/(p_primary + 2*p_secondary + 2*p_tertiary); font->lcd_weights[0] = (unsigned char)(p_tertiary*norm*256); font->lcd_weights[1] = (unsigned char)(p_secondary*norm*256); font->lcd_weights[2] = (unsigned char)(p_primary*norm*256); font->lcd_weights[3] = (unsigned char)(p_secondary*norm*256); font->lcd_weights[4] = (unsigned char)(p_tertiary*norm*256); texture_font_load_glyphs( font, L" !\"#$%&'()*+,-./0123456789:;<=>?" L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" L"`abcdefghijklmnopqrstuvwxyz{|}~" ); pen.x = 10; pen.y = 600 - font->height - 10; glyph = texture_font_get_glyph( font, text[0] ); add_glyph( glyph, buffer, &markup, &pen, 0 ); for( i=1; i<wcslen(text); ++i ) { if( text[i] == '\n' ) { pen.x = 10; pen.y -= font->height; // + 0.01*(size - (int)size)*font->height; } else { glyph = texture_font_get_glyph( font, text[i] ); float kerning = 0.0; if( p_kerning ) { kerning = texture_glyph_get_kerning( glyph, text[i-1] ); } add_glyph( glyph, buffer, &markup, &pen, kerning ); } } texture_font_delete (font ); } // ---------------------------------------------------------------- display --- void display(void) { if( p_invert ) { glClearColor( 0, 0, 0, 1 ); } else { glClearColor( 1, 1, 1, 1 ); } glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, atlas->id ); if( !p_lcd_filtering ) { glEnable( GL_COLOR_MATERIAL ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); if( p_invert ) { glColor4f(1,1,1,1); } else { glColor4f(0,0,0,1); } } else { glEnable( GL_COLOR_MATERIAL ); glBlendFunc( GL_CONSTANT_COLOR_EXT, GL_ONE_MINUS_SRC_COLOR ); glEnable( GL_BLEND ); glColor3f( 1,1,1 ); if( p_invert ) { glBlendColor( 1, 1, 1, 1 ); } else { glBlendColor( 0, 0, 0, 1 ); } } if( !p_lcd_filtering ) { vertex_buffer_render( buffer, GL_TRIANGLES, "vt" ); } else { glUseProgram( program ); glUniform1i( texture_location, 0 ); glUniform1f( gamma_location, p_gamma ); float norm = 1.0/(p_primary+2*p_secondary+2*p_tertiary); glUniform1f( primary_location, p_primary*norm ); glUniform1f( secondary_location, p_secondary*norm ); glUniform1f( tertiary_location, p_tertiary*norm ); glUniform2f( pixel_location, 1.0/atlas->width, 1.0/atlas->height ); vertex_buffer_render( buffer, GL_TRIANGLES, "vtc" ); glUseProgram( 0 ); } TwDraw( ); glutSwapBuffers( ); } // ---------------------------------------------------------------- reshape --- void reshape( int width, int height ) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, width, 0, height, -1, 1); glMatrixMode(GL_MODELVIEW); TwWindowSize( width, height ); }
void Render::Text(Font* font, const std::string& text, float x, float y, const Color& color) { if (color.A == 0) return; this->SetTexture(font->Atlas->id); this->SetShader(this->DefaultShaderText.ProgramHandle); x += this->_DrawOffset.X; y += this->_DrawOffset.Y; y -= font->FontHandle->height / 4; float cx = x; float cy = y; int len = (int)text.size(); this->CheckSpace(len * 4, len * 6); // per square, 4 vertices and 6 indices float currentMaxLineHeight = 0; for (int i = 0; i < len; i++) { char l = text[i]; texture_glyph_t* glyph = texture_font_get_glyph(font->FontHandle, (wchar_t)text[i]); if (glyph == null) { TL_ASSERT(false); return; } if (i > 0) { cx += texture_glyph_get_kerning(glyph, text[i - 1]); } if (l == '\n') { cy += font->FontHandle->height; cx = x; continue; } float w = (float)glyph->width; float h = (float)font->FontHandle->height; _vertexData a, b, c, d; float lw = cx + glyph->offset_x; float lh = cy + h - glyph->offset_y; float x1 = glyph->s0; float x2 = glyph->s1; float y1 = glyph->t0; float y2 = glyph->t1; float pixelWidth = 1.0f / this->DefaultFont->Atlas->width; float pixelHeight = 1.0f / this->DefaultFont->Atlas->height; a.Location.X = lw; a.Location.Y = lh; b.Location.X = lw + w; b.Location.Y = lh; c.Location.X = lw; c.Location.Y = lh + glyph->height; d.Location.X = lw + w; d.Location.Y = lh + glyph->height; a.TextureLocation.X = x1; a.TextureLocation.Y = y1; b.TextureLocation.X = x2; b.TextureLocation.Y = y1; c.TextureLocation.X = x1; c.TextureLocation.Y = y2; d.TextureLocation.X = x2; d.TextureLocation.Y = y2; if (this->ClippingEnabled) { if (lw < this->_ClippingPos.X) { // if the sign is fully outside of the clipping, then just skip it. if (lw + w < this->_ClippingPos.X) { cx += glyph->advance_x; continue; } else { // calculate the new screen and texture location float offset = this->_ClippingPos.X - lw; a.Location.X += offset; c.Location.X += offset; a.TextureLocation.X += offset * pixelWidth; c.TextureLocation.X += offset * pixelWidth; } } if (lw + w > this->_ClippingPos.X + this->_ClippingSize.X) { if (cx > this->_ClippingPos.X + this->_ClippingSize.X) { cx += glyph->advance_x; continue; } else { float offset = lw + w - this->_ClippingPos.X - this->_ClippingSize.X; b.Location.X -= offset; d.Location.X -= offset; b.TextureLocation.X -= offset * pixelWidth; d.TextureLocation.X -= offset * pixelWidth; } } if (a.Location.Y < this->_ClippingPos.Y) { if (d.Location.Y < this->_ClippingPos.Y) { cx += glyph->advance_x; continue; } else { float offset = this->_ClippingPos.Y - a.Location.Y; a.Location.Y += offset; b.Location.Y += offset; a.TextureLocation.Y += offset * pixelHeight; b.TextureLocation.Y += offset * pixelHeight; } } if (d.Location.Y > this->_ClippingPos.Y + this->_ClippingSize.Y) { if (b.Location.Y > this->_ClippingPos.Y + this->_ClippingSize.Y) { cx += glyph->advance_x; continue; } else { float offset = d.Location.Y - this->_ClippingPos.Y - this->_ClippingSize.Y; c.Location.Y -= offset; d.Location.Y -= offset; c.TextureLocation.Y -= offset * pixelHeight; d.TextureLocation.Y -= offset * pixelHeight; } } } a.Color = color; b.Color = color; c.Color = color; d.Color = color; unsigned int curVertices = this->VerticeDataCount; VERTICE_PUSH(a); VERTICE_PUSH(b); VERTICE_PUSH(c); VERTICE_PUSH(d); INDICE_PUSH(curVertices + 0); INDICE_PUSH(curVertices + 1); INDICE_PUSH(curVertices + 2); INDICE_PUSH(curVertices + 1); INDICE_PUSH(curVertices + 3); INDICE_PUSH(curVertices + 2); cx += glyph->advance_x; } }
void opengl_font_print( mFloat px, mFloat py, const wchar_t* msg, mFloat r, mFloat g, mFloat b, mFloat a) { GLfloat colors[] = { r, g, b, a }; GLfloat use_texture[] = { 1.0f, 0.0f }; size_t i, len = wcslen(msg); float dx = 0.0f; mFloat cwidth = (mFloat)0.0; GLfloat matrix_copy[16]; opengl_font_t* font = (opengl_font_t*)current_font->data; fontSize(L"M", &cwidth, NULL); opengl_view_copy(matrix_copy); opengl_setup_view( px * window_zoom, py * window_zoom, 1.0f, - 1.0f); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, font->atlas->id); for(i = 0 ; i < len ; i++) { texture_glyph_t *glyph; if(msg[i] == L'\t') { dx += 8.0f * cwidth * window_zoom; continue; } glyph = texture_font_get_glyph(font->font, msg[i]); if(glyph != NULL) { GLfloat x0 = dx + (GLfloat)glyph->offset_x; GLfloat y0 = (GLfloat)glyph->offset_y; GLfloat x1 = x0 + (GLfloat)glyph->width; GLfloat y1 = y0 - (GLfloat)glyph->height - 1.25f; GLfloat s0 = glyph->s0; GLfloat t0 = glyph->t0; GLfloat s1 = glyph->s1; GLfloat t1 = glyph->t1 + 0.00125f; GLfloat vertices[] = { x0, y0, x0, y1, x1, y0, x1, y1 }; GLfloat tex_indices[] = { s0, t0, s0, t1, s1, t0, s1, t1 }; opengl_draw_data(vertices, tex_indices, colors, use_texture); dx += glyph->advance_x + texture_glyph_get_kerning(glyph, msg[i]); } } glDisable(GL_TEXTURE_2D); opengl_view_set(matrix_copy); }
float TextureGlyph::GetKerning(const wchar_t charcode) { return texture_glyph_get_kerning(static_cast<const texture_glyph_t*>(self_), charcode); }
void Stats::update_text() { // Destroy any old vertex buffers. glDeleteBuffers(1, &position_vbo); glDeleteBuffers(1, &texcoord_vbo); glDeleteVertexArrays(1, &vao); vertex_count = 0; // Bail out if we do not have any text. if (lines.size() == 0) return; // Count the number of vertices. for (int i = 0; i < lines.size(); ++i) { vertex_count += lines[i].text.size() * 6; } // Generate the new vertices. glm::vec2 pen; std::vector<glm::vec2> positions(vertex_count); std::vector<glm::vec2> texcoords(vertex_count); int offset = 0; for (int i = 0; i < lines.size(); ++i) { const std::string& text = lines[i].text; int text_length = text.size(); pen.x = 0; for (int k = 0; k < text_length; ++k) { wchar_t c = (wchar_t) text[k]; texture_glyph_t* glyph = texture_font_get_glyph(texture_font, c); float kerning = 0.0f; if (k > 0) { kerning = texture_glyph_get_kerning(glyph, text[k - 1]); } pen.x += kerning; float x0 = pen.x + glyph->offset_x; float y0 = pen.y + glyph->offset_y; float x1 = x0 + glyph->width; float y1 = y0 - glyph->height; positions[offset + k * 6 + 0] = glm::vec2(x0, y0); positions[offset + k * 6 + 1] = glm::vec2(x0, y1); positions[offset + k * 6 + 2] = glm::vec2(x1, y1); positions[offset + k * 6 + 3] = glm::vec2(x0, y0); positions[offset + k * 6 + 4] = glm::vec2(x1, y1); positions[offset + k * 6 + 5] = glm::vec2(x1, y0); float s0 = glyph->s0; float t0 = glyph->t0; float s1 = glyph->s1; float t1 = glyph->t1; texcoords[offset + k * 6 + 0] = glm::vec2(s0, t0); texcoords[offset + k * 6 + 1] = glm::vec2(s0, t1); texcoords[offset + k * 6 + 2] = glm::vec2(s1, t1); texcoords[offset + k * 6 + 3] = glm::vec2(s0, t0); texcoords[offset + k * 6 + 4] = glm::vec2(s1, t1); texcoords[offset + k * 6 + 5] = glm::vec2(s1, t0); pen.x += glyph->advance_x; } pen.y -= (texture_font->ascender - texture_font->descender) + texture_font->linegap; offset += text_length * 6; } // Generate new vertex buffers. glGenVertexArrays(1, &vao); glBindVertexArray(vao); glGenBuffers(1, &position_vbo); glBindBuffer(GL_ARRAY_BUFFER, position_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * vertex_count, &positions[0], GL_STATIC_DRAW); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); glGenBuffers(1, &texcoord_vbo); glBindBuffer(GL_ARRAY_BUFFER, texcoord_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * vertex_count, &texcoords[0], GL_STATIC_DRAW); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(1); }
// Text functions // Create text string with specified font // Begin at [0,0] // Store data to modelText[modelIndex] int modelEngine::createText(int modelIndex, texture_font_t * font, wchar_t * text, vec4 * color, vec2 * pen, vec3 * offset, vec2 * scale) { size_t i; vec2 startPen = *pen; //Zoffset = Zoffset * 400; // Make room to store vertices and texture coordinates for 50 characters GLfloat vertices[3600]; int verticesIndex = 0; GLfloat texCoordinates[2400]; int texIndex = 0; // Return -1 if model index is invalid if(modelIndex == -1) { return -1; } float r = color->red, g = color->green, b = color->blue, a = color->alpha; for( i=0; i<wcslen(text); ++i ) { // Check for special character wchar_t currentChar = text[i]; wchar_t* currentCharPointer = text + i; //wchar_t newLineChar = L"\n"; //if((text + i) == L"\n") int result = wcsncmp(currentCharPointer, L"\n", 1); if(result == 0) { // New line found pen->x = startPen.x; pen->y = startPen.y - font->height; startPen.y = pen->y; } 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; GLfloat vertexCoordinates[] = { x0,y0,0, x0,y1,0, x1,y1,0, x0,y0,0, x1,y1,0, x1,y0,0, }; for(int i = 0; i < 18; i++) { vertexCoordinates[i] = vertexCoordinates[i] / 400; } GLfloat textureCoordinates[] = { s0,t0, s0,t1, s1,t1, s0,t0, s1,t1, s1,t0, }; // Copy vertex data memcpy (vertices + verticesIndex, vertexCoordinates, 18 * sizeof(GLfloat)); // Increase pointer verticesIndex += 18; // Copy texture data memcpy (texCoordinates + texIndex, textureCoordinates, 12 * sizeof(GLfloat)); // Increase pointer texIndex += 12; // Increase pen position pen->x += glyph->advance_x; } } // Scale all data in X and Y direction for(int i = 0; i < verticesIndex; i+=3) { vertices[i] = vertices[i] * scale->x; vertices[i+1] = vertices[i+1] * scale->y; } // Store data to buffers // First, orphan GL buffers // Check if text has been enabled if(modelText[modelIndex].textReady != 0) { glDeleteBuffers(1, &modelText[modelIndex].vertexBuffer); glDeleteBuffers(1, &modelText[modelIndex].texBuffer); //orphanArrayBuffer(modelText[modelIndex].vertexBuffer, modelText[modelIndex].vertexBufferSize); //orphanArrayBuffer(modelText[modelIndex].texBuffer, modelText[modelIndex].texBufferSize); } // Generate vertex buffer glGenBuffers(1, &modelText[modelIndex].vertexBuffer); // Bind buffer glBindBuffer(GL_ARRAY_BUFFER, modelText[modelIndex].vertexBuffer); // Create buffer data glBufferData(GL_ARRAY_BUFFER, verticesIndex * sizeof(GLfloat), &vertices, GL_STATIC_DRAW); checkGLError(); // Unbind buffer glBindBuffer(GL_ARRAY_BUFFER, 0); // Store number of vertices modelText[modelIndex].vertexBufferSize = verticesIndex; // Generate texture buffer glGenBuffers(1, &modelText[modelIndex].texBuffer); // Bind buffer glBindBuffer(GL_ARRAY_BUFFER, modelText[modelIndex].texBuffer); // Create buffer data glBufferData(GL_ARRAY_BUFFER, texIndex * sizeof(GLfloat), &texCoordinates, GL_STATIC_DRAW); checkGLError(); // Unbind buffer glBindBuffer(GL_ARRAY_BUFFER, 0); // Store number of vertices modelText[modelIndex].texBufferSize = texIndex; // Store number of characters modelText[modelIndex].characters = wcslen(text); // Store font color modelText[modelIndex].fontColor.r = color->r; modelText[modelIndex].fontColor.g = color->g; modelText[modelIndex].fontColor.b = color->b; modelText[modelIndex].fontColor.a = color->a; // Store font offset on model modelText[modelIndex].offset = *offset; modelText[modelIndex].textReady = 1; return 0; }
void modelEngine::add_text(texture_font_t * font, wchar_t * text, vec4 * color, vec2 * pen, GLuint vertexBuffer, GLfloat Zoffset) { 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; GLfloat indices[6] = {0,1,2, 0,2,3}; GLfloat vertexCoordinates[] = { x0,y0,Zoffset, x0,y1,Zoffset, x1,y1,Zoffset, x0,y0,Zoffset, x1,y1,Zoffset, x1,y0,Zoffset, }; for(int i = 0; i < 18; i++) { vertexCoordinates[i] = vertexCoordinates[i] / 1000; } GLfloat textureCoordinates[] = { s0,t0, s0,t1, s1,t1, s0,t0, s1,t1, s1,t0, }; GLfloat colors[] = { r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, r, g, b, a, }; GLfloat 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, x0,y0,0, s0,t0, 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; // Store vertices to buffer // Generate buffer GLuint verticeBuffer = 0; GLuint textureBuffer = 0; GLuint colorBuffer = 0; // Generate vertex buffer glGenBuffers(1, &verticeBuffer); // Bind buffer glBindBuffer(GL_ARRAY_BUFFER, verticeBuffer); // Create buffer data glBufferData(GL_ARRAY_BUFFER, 216, &vertexCoordinates, GL_STATIC_DRAW); // Unbind buffer glBindBuffer(GL_ARRAY_BUFFER, 0); // Generate texture buffer glGenBuffers(1, &textureBuffer); // Bind buffer glBindBuffer(GL_ARRAY_BUFFER, textureBuffer); // Create buffer data glBufferData(GL_ARRAY_BUFFER, 48, &textureCoordinates, GL_STATIC_DRAW); // Unbind buffer glBindBuffer(GL_ARRAY_BUFFER, 0); // Generate color buffer glGenBuffers(1, &colorBuffer); // Bind buffer glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); // Create buffer data glBufferData(GL_ARRAY_BUFFER, 48, &colors, GL_STATIC_DRAW); // Unbind buffer glBindBuffer(GL_ARRAY_BUFFER, 0); // Enabling color array makes font dissapear //glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState( GL_VERTEX_ARRAY ); //glDisable(GL_TEXTURE_2D); //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); // Start with a clear screen glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Draw on screen // Bind texture glBindTexture(GL_TEXTURE_2D, atlas->id); // Bind buffers // Bind vertex buffer glBindBuffer(GL_ARRAY_BUFFER, verticeBuffer); glVertexPointer(3, GL_FLOAT, 0, NULL); // Bind texture buffer glBindBuffer(GL_ARRAY_BUFFER, textureBuffer); glTexCoordPointer(2, GL_FLOAT, 0, NULL); // Bind color buffer glBindBuffer(GL_ARRAY_BUFFER, colorBuffer); glColorPointer(4, GL_FLOAT, 0, NULL); glPushMatrix(); // Move model glTranslatef(0.0f,0.0f,20.0f); // Rotate model glRotatef(0.0f, 1.0, 0.0, 0.0); glRotatef(0.0f, 0.0, 1.0, 0.0); glRotatef(0.0f, 0.0, 0.0, 1.0); // Scale model glScalef(15.0f,15.0f,15.0f); glColor4f(0.0f, 0.6f, 1.0f, 0.5f); glDrawArrays(GL_TRIANGLES, 0, 6); // Display eglSwapBuffers(state.display, state.surface); glBindBuffer(GL_ARRAY_BUFFER, 0); glEnableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); //glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glPopMatrix(); } } }
TextInfo FontRenderer::RenderText(std::string text, float xPos, float yPos, float pixelWidthLimit, const glm::vec4 color, FontShader* shader, bool wordFormat) { TextInfo result; result.start_position = glm::vec2(0, 0); result.end_position = glm::vec2(0, 0); float scaleX = ContextWindow::getCurrent().getWidth(); float scaleY = ContextWindow::getCurrent().getHeight(); float x = xPos / scaleX; float firstPos = (float)xPos; float limitX = (pixelWidthLimit + xPos) / scaleX; int yAdvance = 0; auto fit = [&text, pixelWidthLimit](int index, float xPos, float headStart, ftgl::texture_glyph_t* glyph) { float x = (float)xPos; for (; text[index + 1] != ' ' && text[index + 1] != 0; ++index) { unsigned char c = text[index]; x += glyph->advance_x; if ((xPos + pixelWidthLimit) < x + headStart) return false; } return true; }; glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); shader->useShader(); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, atlas->id); for (int i = 0; i < text.size(); i++) { unsigned char c = text[i]; ftgl::texture_glyph_t* glyph = ftgl::texture_font_get_glyph(font, c); if (glyph != NULL) { IndexedModel * im = fontMesh->getQuad()->getIndexedModel(); if (i > 0) { float kerning = texture_glyph_get_kerning(glyph, text[i - 1]); x += kerning / scaleX; } if (i > 0) { if (text[i - 1] == ' ' && text[i] != ' ') { if (!fit(i, firstPos, x * scaleX, glyph) && c != ' ') { x = xPos / scaleX; yPos -= font->ascender - font->descender; // highest glyph height - lowest glyph height yAdvance++; } } } float x0 = x + glyph->offset_x / scaleX; float y0 = (yPos + glyph->offset_y) / scaleY; float x1 = x0 + glyph->width / scaleX; float y1 = y0 - glyph->height / scaleY; if (i == 0) { result.start_position.x = x0; result.start_position.y = y0; result.end_position.x = x1; } if (x1 > result.end_position.x) result.end_position.x = x1; result.end_position.y = y1; im->positions[0] = glm::vec3(x0, y1, 0.0f); im->positions[1] = glm::vec3(x0, y0, 0.0f); im->positions[2] = glm::vec3(x1, y1, 0.0f); im->positions[3] = glm::vec3(x1, y0, 0.0f); #if 0 // Font debug glUseProgram(0); glLineWidth(1.0); glBegin(GL_LINES); glColor3f(1, 0, 0); glVertex3f(x0, y1, -1.0f); // Vertical left debug line glVertex3f(x0, y0, -1.0f); glVertex3f(x1, y1, -1.0f); // Vertical right glVertex3f(x1, y0, -1.0f); glVertex3f(x0, y1, -1.0f); // Horizontal bottom glVertex3f(x1, y1, -1.0f); glVertex3f(x0, y0, -1.0f); // Horizontal top glVertex3f(x1, y0, -1.0f); glEnd(); shader->useShader(); #endif im->texCoords[0] = glm::vec2(glyph->s0, glyph->t1); im->texCoords[1] = glm::vec2(glyph->s0, glyph->t0); im->texCoords[2] = glm::vec2(glyph->s1, glyph->t1); im->texCoords[3] = glm::vec2(glyph->s1, glyph->t0); glBindVertexArray(fontMesh->getVertexArrayID()); glBindBuffer(GL_ARRAY_BUFFER, fontMesh->getVertexBufferID()); glBufferSubData(GL_ARRAY_BUFFER, 0, im->positions.size() * sizeof(float) * 3, &im->positions[0]); glBindBuffer(GL_ARRAY_BUFFER, fontMesh->getTextureBufferID()); glBufferSubData(GL_ARRAY_BUFFER, 0, im->texCoords.size() * sizeof(float) * 2, &im->texCoords[0]); shader->setTextColor(color); shader->update(); fontMesh->render(); x += glyph->advance_x / scaleX; } } glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); glUseProgram(0); result.num_rows = yAdvance + 1; result.height = (font->ascender - font->descender) * (float)yAdvance; result.width = result.end_position.x - result.start_position.x; #if 1 // Font debug glUseProgram(0); glLineWidth(1.0); glBegin(GL_LINES); glColor3f(1, 0, 0); glVertex3f(result.start_position.x, result.start_position.y, -1.0f); // Vertical left debug line glVertex3f(result.end_position.x, result.end_position.y, -1.0f); glEnd(); shader->useShader(); #endif return result; }