diff options
author | Luo Jinghua <sunmoon1997@gmail.com> | 2011-06-12 13:07:39 +0800 |
---|---|---|
committer | Luo Jinghua <sunmoon1997@gmail.com> | 2011-06-12 13:07:39 +0800 |
commit | ba5bd0a69af94ddcf3c5f19f2c3efb1ca5885c8f (patch) | |
tree | b0eafdb68cc8ddbc50f5e1a14202b72677716487 | |
parent | 71768e8d8bb1fd2aaaff5481485c046f78d96e56 (diff) |
opengl: fix the renderer to draw glyphs at correct positions
-rw-r--r-- | src/sdl-freetype-opengl.c | 234 |
1 files changed, 153 insertions, 81 deletions
diff --git a/src/sdl-freetype-opengl.c b/src/sdl-freetype-opengl.c index b29e8a3..d7fefe6 100644 --- a/src/sdl-freetype-opengl.c +++ b/src/sdl-freetype-opengl.c @@ -37,14 +37,17 @@ #include "sdl-freetype-opengl.h" #include "sdl-freetype-utils.h" +#include <assert.h> #include <stdlib.h> #include <stdio.h> + #include <GL/gl.h> #define FIXEDTOD(f) (sdl_freetype_fixed_to_double (f)) #define GLYPH_CACHE_SIZE 512 #define GLYPH_CACHE_LEVEL 64 +#define VERTEX_BUFFER_SIZE 128 typedef struct sdl_freetype_opengl_render_s { sdl_freetype_glyph_render_t base; @@ -56,6 +59,8 @@ typedef struct sdl_freetype_opengl_render_s { int width, height; float usx, usy; GLuint texture; + GLfloat vertex_buffer[VERTEX_BUFFER_SIZE * 6 * 2]; + GLfloat texcoord_buffer[VERTEX_BUFFER_SIZE * 6 * 2]; } sdl_freetype_opengl_render_t; typedef struct { @@ -63,8 +68,10 @@ typedef struct { } sdl_freetype_opengl_coord_t; typedef struct { + sdl_freetype_font_t * font; + FT_UInt index; sdl_freetype_area_t * area; - sdl_freetype_bool_t locked; + int locked; sdl_freetype_opengl_coord_t uv[2]; } sdl_freetype_opengl_user_data_t; @@ -155,7 +162,7 @@ sdl_freetype_opengl_glyph_user_data_init (sdl_freetype_font_t * font, unsigned char * src, * dst; int h; - width = pitch = (bitmap->width + 3) & ~3; + width = pitch = (bitmap->width + 1 + 3) & ~3; data = calloc (pitch * info->bitmap.rows, 1); if (!data) return SDL_FREETYPE_ERR_OUT_OF_MEMORY; @@ -175,7 +182,7 @@ sdl_freetype_opengl_glyph_user_data_init (sdl_freetype_font_t * font, unsigned char * src, * dst; int h; - width = pitch = (bitmap->width + 3) & ~3; + width = pitch = (bitmap->width + 1 + 3) & ~3; data = calloc (pitch * info->bitmap.rows, 1); if (!data) return SDL_FREETYPE_ERR_OUT_OF_MEMORY; @@ -192,9 +199,9 @@ sdl_freetype_opengl_glyph_user_data_init (sdl_freetype_font_t * font, } else { data = NULL; pitch = bitmap->pitch; - width = (bitmap->width + 3) & ~3; + width = (bitmap->width + 1 + 3) & ~3; } - height = (bitmap->rows + 3) & ~3; + height = (bitmap->rows + 1 + 3) & ~3; user_data = sdl_freetype_opengl_user_data_create (); if (!user_data) @@ -247,10 +254,12 @@ sdl_freetype_opengl_glyph_user_data_init (sdl_freetype_font_t * font, if (data) free (data); - user_data->uv[0].x = (float)area->x; - user_data->uv[0].y = (float)area->y; - user_data->uv[1].x = (float)(area->x + bitmap->width); - user_data->uv[1].y = (float)(area->y + bitmap->rows); + user_data->font = font; + user_data->index = index; + user_data->uv[0].x = (float)area->x / opengl_render->width; + user_data->uv[0].y = (float)area->y / opengl_render->height; + user_data->uv[1].x = (float)(area->x + bitmap->width) / opengl_render->width; + user_data->uv[1].y = (float)(area->y + bitmap->rows) / opengl_render->height; info->data = user_data; return SDL_FREETYPE_ERR_OK; } @@ -292,7 +301,9 @@ sdl_freetype_opengl_glyphs_render (sdl_freetype_font_t * font, sdl_freetype_opengl_glyph_info_t * cached, stack_cached[LOCAL_BUF]; sdl_freetype_glyph_info_t * info; double x1, y1, x2, y2; - int i, num_cached; + int i, start, num_cached; + sdl_freetype_bool_t dirty = SDL_FREETYPE_FALSE; + GLboolean blend_enabled; if (!render->valid) { for (i = 0; i < num_glyphs && !render->valid; i++) @@ -304,12 +315,6 @@ sdl_freetype_opengl_glyphs_render (sdl_freetype_font_t * font, return SDL_FREETYPE_ERR_UNKNOWN; } - /* FIXME: only use alpha channel for supixel rendering */ -#if 0 - if (render->subpixel) - return SDL_FREETYPE_ERR_NOT_IMPLEMENTED; -#endif - if (!render->width || !render->height) return SDL_FREETYPE_ERR_OK; @@ -320,82 +325,148 @@ sdl_freetype_opengl_glyphs_render (sdl_freetype_font_t * font, if (!cached) return SDL_FREETYPE_ERR_OUT_OF_MEMORY; - glPushAttrib (GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT); - - num_cached = 0; - for (i = 0; i < num_glyphs; i++) { - info = sdl_freetype_font_glyph_info_lookup (font, glyphs[i].index, - SDL_FREETYPE_GLYPH_SURFACE | - SDL_FREETYPE_GLYPH_USER_DATA); - if (!info) - continue; - user_data = info->data; - if (!user_data || !user_data->area) - continue; - user_data->locked = SDL_FREETYPE_TRUE; - cached[num_cached].index = i; - cached[num_cached++].info = info; - } - - if (num_cached) { - glMatrixMode (GL_TEXTURE); - glPushMatrix (); - glLoadIdentity (); - glScalef (1.0f / render->width, 1.0f / render->height, 1.0f); - - glMatrixMode (GL_MODELVIEW); - glPushMatrix (); - - glEnable (GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glEnable (GL_TEXTURE_2D); - glBindTexture (GL_TEXTURE_2D, render->texture); + blend_enabled = glIsEnabled(GL_BLEND); - glTranslatef (x * render->usx, y * render->usy, 0.0f); + start = 0; + while (start < num_glyphs) { + int end; - glColor4ub (r, g, b, a); + num_cached = 0; + for (i = start; i < num_glyphs; i++) { + info = sdl_freetype_font_glyph_info_lookup (font, glyphs[i].index, + SDL_FREETYPE_GLYPH_SURFACE | + SDL_FREETYPE_GLYPH_USER_DATA); + if (!info || info->flags & SDL_FREETYPE_GLYPH_EMPTY) + continue; + + user_data = info->data; + if (!user_data) { + if (num_cached) + i--; + break; + } + if (!user_data->area) + continue; + user_data->locked++; + cached[num_cached].index = i; + cached[num_cached++].info = info; + } + end = i + 1; + + if (num_cached) { + GLfloat *vertex_buffer = render->vertex_buffer; + GLfloat *texcoord_buffer = render->texcoord_buffer; + int left = num_cached; + + if (!dirty) { + dirty = SDL_FREETYPE_TRUE; + + glMatrixMode (GL_TEXTURE); + glPushMatrix (); + glLoadIdentity (); + + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glEnable (GL_TEXTURE_2D); + glBindTexture (GL_TEXTURE_2D, render->texture); + + glTranslatef (x * render->usx, y * render->usy, 0.0f); + + glColor4ub (r, g, b, a); + + glEnableClientState (GL_VERTEX_ARRAY); + glEnableClientState (GL_TEXTURE_COORD_ARRAY); + + glVertexPointer (2, GL_FLOAT, 0, vertex_buffer); + glTexCoordPointer (2, GL_FLOAT, 0, texcoord_buffer); + } + + i = 0; + while (left) { + int num_quads = VERTEX_BUFFER_SIZE; + int max_index; + int j; + + if (left < num_quads) + num_quads = left; + + max_index = i + num_quads; + + for (j = 0; i < max_index; i++, j += 12) { + user_data = cached[i].info->data; + + assert (user_data->locked != 0); + + x1 = FIXEDTOD (glyphs[cached[i].index].x) + cached[i].info->x_offset; + y1 = FIXEDTOD (glyphs[cached[i].index].y) + cached[i].info->y_offset; + x2 = x1 + cached[i].info->bitmap.width; + y2 = y1 + cached[i].info->bitmap.rows; + + x1 *= render->usx; + y1 *= render->usy; + x2 *= render->usx; + y2 *= render->usy; + + texcoord_buffer[j + 0] = user_data->uv[0].x; + texcoord_buffer[j + 1] = user_data->uv[0].y; + vertex_buffer[j + 0] = x1; + vertex_buffer[j + 1] = y1; + + texcoord_buffer[j + 2] = user_data->uv[0].x; + texcoord_buffer[j + 3] = user_data->uv[1].y; + vertex_buffer[j + 2] = x1; + vertex_buffer[j + 3] = y2; + + texcoord_buffer[j + 4] = user_data->uv[1].x; + texcoord_buffer[j + 5] = user_data->uv[1].y; + vertex_buffer[j + 4] = x2; + vertex_buffer[j + 5] = y2; + + texcoord_buffer[j + 6] = user_data->uv[1].x; + texcoord_buffer[j + 7] = user_data->uv[1].y; + vertex_buffer[j + 6] = x2; + vertex_buffer[j + 7] = y2; + + texcoord_buffer[j + 8] = user_data->uv[1].x; + texcoord_buffer[j + 9] = user_data->uv[0].y; + vertex_buffer[j + 8] = x2; + vertex_buffer[j + 9] = y1; + + texcoord_buffer[j + 10] = user_data->uv[0].x; + texcoord_buffer[j + 11] = user_data->uv[0].y; + vertex_buffer[j + 10] = x1; + vertex_buffer[j + 11] = y1; + + user_data->locked--; + } - glBegin (GL_QUADS); + glDrawArrays (GL_TRIANGLES, 0, num_quads * 6); - for (i = 0; i < num_cached; i++) { - user_data = cached[i].info->data; - - x1 = FIXEDTOD (glyphs[cached[i].index].x) + cached[i].info->x_offset; - y2 = -FIXEDTOD (glyphs[cached[i].index].y) - cached[i].info->y_offset; - x2 = x1 + cached[i].info->bitmap.width; - y1 = y2 - cached[i].info->bitmap.rows; - - x1 *= render->usx; - y1 *= render->usy; - x2 *= render->usx; - y2 *= render->usy; - - glTexCoord2f (user_data->uv[0].x, user_data->uv[1].y); - glVertex2f (x1, y1); - - glTexCoord2f (user_data->uv[0].x, user_data->uv[0].y); - glVertex2f (x1, y2); - - glTexCoord2f (user_data->uv[1].x, user_data->uv[0].y); - glVertex2f (x2, y2); + left -= num_quads; + } + } + start = end; + } - glTexCoord2f (user_data->uv[1].x, user_data->uv[1].y); - glVertex2f (x2, y1); + if (dirty) { + glDisableClientState (GL_VERTEX_ARRAY); + glDisableClientState (GL_TEXTURE_COORD_ARRAY); - user_data->locked = SDL_FREETYPE_FALSE; - } + glPopMatrix (); - glEnd (); + glMatrixMode (GL_TEXTURE); + glPopMatrix (); - glPopMatrix (); + if (!blend_enabled) + glDisable (GL_BLEND); - glMatrixMode (GL_TEXTURE); - glPopMatrix (); + glBindTexture (GL_TEXTURE_2D, 0); } - glPopAttrib (); - if (cached != stack_cached) free (cached); @@ -438,6 +509,7 @@ sdl_freetype_opengl_glyph_move_out (sdl_freetype_area_manager_t * manager, sdl_freetype_opengl_user_data_t * user_data = closure; user_data->area = NULL; + sdl_freetype_font_glyph_clear_user_data(user_data->font, user_data->index); } static int |