// ---------------------------------------------------------------------------- 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); } }
int xpl_text_buffer_add_wchar(xpl_text_buffer_t *self, xvec2 *pen, xpl_markup_t *markup, wchar_t current, wchar_t previous) { assert(self); assert(pen); assert(markup); assert(current); // indices moved forward by this because all share the same vbo size_t voffset = self->vertex_count; size_t vcount = 0; size_t icount = 0; xpl_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]; GLushort indices[6 * 5]; // two shared vertices per triangle if (current == L'\n') { pen->x = self->pen_origin.x; if (previous == L'\n') { // No line descender for this line, so make something up pen->y -= markup->font->height * 1.1f; } else { pen->y -= self->line_descender + markup->font->height; } self->line_descender = 0.0f; self->line_ascender = 0.0f; self->line_start = self->vertex_count; return FALSE; } 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 = xmin(markup->font->descender, self->line_descender); } xpl_glyph_t *glyph = xpl_font_get_glyph(font, current); if (! glyph) { LOG_WARN("Glyph %c not found", current); return FALSE; } xpl_glyph_t *empty = xpl_font_get_glyph(font, -1); float kerning = 0.0f; if (previous > 0) { kerning = xpl_font_glyph_get_kerning(glyph, previous); pen->x += kerning; } 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 = (float)(int)(pen->y + font->descender); float x1 = x0 + glyph->advance_x; float y1 = (float)(int)(y0 + font->height + font->linegap); float s0 = empty->tex_s0; float t0 = empty->tex_t0; float s1 = empty->tex_s1; float t1 = empty->tex_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] = voffset + vcount + 0; indices[icount + 1] = voffset + vcount + 1; indices[icount + 2] = voffset + vcount + 2; indices[icount + 3] = voffset + vcount + 0; indices[icount + 4] = voffset + vcount + 2; indices[icount + 5] = voffset + vcount + 3; vcount += 4; icount += 6; } 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 = (float)(int)(pen->y + font->underscore_position); float x1 = x0 + glyph->advance_x; float y1 = (float)(int)(y0 + font->underscore_thickness); float s0 = empty->tex_s0; float t0 = empty->tex_t0; float s1 = empty->tex_s1; float t1 = empty->tex_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] = voffset + vcount + 0; indices[icount + 1] = voffset + vcount + 1; indices[icount + 2] = voffset + vcount + 2; indices[icount + 3] = voffset + vcount + 0; indices[icount + 4] = voffset + vcount + 2; indices[icount + 5] = voffset + vcount + 3; vcount += 4; icount += 6; } 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 = (float)(int)(pen->y + (int)font->ascender); float x1 = x0 + glyph->advance_x; float y1 = (float)(int)(y0 + (int)font->underscore_thickness); float s0 = empty->tex_s0; float t0 = empty->tex_t0; float s1 = empty->tex_s1; float t1 = empty->tex_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] = voffset + vcount + 0; indices[icount + 1] = voffset + vcount + 1; indices[icount + 2] = voffset + vcount + 2; indices[icount + 3] = voffset + vcount + 0; indices[icount + 4] = voffset + vcount + 2; indices[icount + 5] = voffset + vcount + 3; vcount += 4; icount += 6; } 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 = (float)(int)(pen->y + (int)(0.33f * font->ascender)); float x1 = x0 + glyph->advance_x; float y1 = (float)(int)(y0 + (int)font->underscore_thickness); float s0 = empty->tex_s0; float t0 = empty->tex_t0; float s1 = empty->tex_s1; float t1 = empty->tex_t1; SET_GLYPH_VERTEX(vertices[vcount + 0], x0, y0, 0, s0, t0, r, g, b, a, x0 - ((int)x0), gamma); SET_GLYPH_VERTEX(vertices[vcount + 1], x0, y1, 0, s0, t1, r, g, b, a, x0 - ((int)x0), gamma); SET_GLYPH_VERTEX(vertices[vcount + 2], x1, y1, 0, s1, t1, r, g, b, a, x1 - ((int)x1), gamma); SET_GLYPH_VERTEX(vertices[vcount + 3], x1, y0, 0, s1, t0, r, g, b, a, x1 - ((int)x1), gamma); indices[icount + 0] = voffset + vcount + 0; indices[icount + 1] = voffset + vcount + 1; indices[icount + 2] = voffset + vcount + 2; indices[icount + 3] = voffset + vcount + 0; indices[icount + 4] = voffset + vcount + 2; indices[icount + 5] = voffset + vcount + 3; vcount += 4; icount += 6; } // HOOORAY, IT'S THE GLYPH! // Watch, I'll never use strikeline or overthrough { float r = markup->foreground_color.r; float g = markup->foreground_color.g; float b = markup->foreground_color.b; float a = markup->foreground_color.a; float x0 = pen->x + glyph->offset_x; float y0 = (float)(int)(pen->y + glyph->offset_y); float x1 = x0 + glyph->width; float y1 = (float)(int)(y0 - glyph->height); float s0 = glyph->tex_s0; float t0 = glyph->tex_t0; float s1 = glyph->tex_s1; float t1 = glyph->tex_t1; SET_GLYPH_VERTEX(vertices[vcount + 0], x0, y0, 0, s0, t0, r, g, b, a, x0 - ((int)x0), gamma); SET_GLYPH_VERTEX(vertices[vcount + 1], x0, y1, 0, s0, t1, r, g, b, a, x0 - ((int)x0), gamma); SET_GLYPH_VERTEX(vertices[vcount + 2], x1, y1, 0, s1, t1, r, g, b, a, x1 - ((int)x1), gamma); SET_GLYPH_VERTEX(vertices[vcount + 3], x1, y0, 0, s1, t0, r, g, b, a, x1 - ((int)x1), gamma); indices[icount + 0] = voffset + vcount + 0; indices[icount + 1] = voffset + vcount + 1; indices[icount + 2] = voffset + vcount + 2; indices[icount + 3] = voffset + vcount + 0; indices[icount + 4] = voffset + vcount + 2; indices[icount + 5] = voffset + vcount + 3; vcount += 4; icount += 6; LOG_TRACE("Adding character %lc: (%f,%f):(%f,%f)", current, x0, y0, x1, y1); } xpl_bo_append(self->vertices, vertices, vcount * sizeof (glyph_vertex_t)); xpl_bo_append(self->vao->index_bos[0], indices, icount * sizeof (GLushort)); # if 0 LOG_DEBUG("Index buffer content: ") GLushort *val; size_t elements = self->vao->index_bos[0]->client_data->length / sizeof (GLushort); for (size_t i = 0; i < elements; i++) { val = ((GLushort *)self->vao->index_bos[0]->client_data->content) + i; LOG_DEBUG("%hu", *val); } # endif self->vertex_count += vcount; self->index_count += icount; pen->x += glyph->advance_x * (1.0f + markup->spacing); return TRUE; }