diff options
author | Luo Jinghua <sunmoon1997@gmail.com> | 2011-06-12 13:05:22 +0800 |
---|---|---|
committer | Luo Jinghua <sunmoon1997@gmail.com> | 2011-06-12 13:05:22 +0800 |
commit | 71768e8d8bb1fd2aaaff5481485c046f78d96e56 (patch) | |
tree | e045626c516409f6c9abef440d56b2db42812a6c | |
parent | 4d1a3848f246666f03cef9eca095fb04d82e10b3 (diff) |
opengles: fix the renderer to draw glyphs at correct positions
-rw-r--r-- | src/sdl-freetype-opengles.c | 245 |
1 files changed, 137 insertions, 108 deletions
diff --git a/src/sdl-freetype-opengles.c b/src/sdl-freetype-opengles.c index b1425b5..c20e463 100644 --- a/src/sdl-freetype-opengles.c +++ b/src/sdl-freetype-opengles.c @@ -37,6 +37,7 @@ #include "sdl-freetype-opengles.h" #include "sdl-freetype-utils.h" +#include <assert.h> #include <stdlib.h> #include <stdio.h> @@ -67,8 +68,10 @@ typedef struct { } sdl_freetype_opengles_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_opengles_coord_t uv[2]; } sdl_freetype_opengles_user_data_t; @@ -90,9 +93,9 @@ sdl_freetype_opengles_user_data_destroy (sdl_freetype_opengles_user_data_t * dat static sdl_freetype_error_t sdl_freetype_opengles_glyph_user_data_init (sdl_freetype_font_t * font, - sdl_freetype_glyph_render_t * render, - sdl_freetype_glyph_info_t * info, - FT_UInt index) + sdl_freetype_glyph_render_t * render, + sdl_freetype_glyph_info_t * info, + FT_UInt index) { sdl_freetype_opengles_render_t * opengles_render = (sdl_freetype_opengles_render_t *) render; @@ -159,7 +162,7 @@ sdl_freetype_opengles_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,11 +178,11 @@ sdl_freetype_opengles_glyph_user_data_init (sdl_freetype_font_t * font, } } } else if (bitmap->pixel_mode == FT_PIXEL_MODE_LCD || - bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V) { + bitmap->pixel_mode == FT_PIXEL_MODE_LCD_V) { 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; @@ -188,17 +191,17 @@ sdl_freetype_opengles_glyph_user_data_init (sdl_freetype_font_t * font, dst = data; for (h = bitmap->rows; h > 0; h--, src += bitmap->pitch, dst += pitch) { int x; - unsigned int *s = (unsigned int*)src; + unsigned int *s = (unsigned int*)src; for (x = 0; x < bitmap->width; x++) - dst[x] = s[x] >> 24; + dst[x] = s[x] >> 24; } } 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_opengles_user_data_create (); if (!user_data) @@ -246,8 +249,10 @@ sdl_freetype_opengles_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->font = font; + user_data->index = index; + user_data->uv[0].x = (float)area->x / opengles_render->width; + user_data->uv[0].y = (float)area->y / opengles_render->height; user_data->uv[1].x = (float)(area->x + bitmap->width) / opengles_render->width; user_data->uv[1].y = (float)(area->y + bitmap->rows) / opengles_render->height; info->data = user_data; @@ -291,7 +296,8 @@ sdl_freetype_opengles_glyphs_render (sdl_freetype_font_t * font, sdl_freetype_opengles_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) { @@ -316,123 +322,145 @@ sdl_freetype_opengles_glyphs_render (sdl_freetype_font_t * font, blend_enabled = glIsEnabled(GL_BLEND); - 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; - } + start = 0; + while (start < num_glyphs) { + int end; + + 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 (num_cached) { + GLfloat *vertex_buffer = render->vertex_buffer; + GLfloat *texcoord_buffer = render->texcoord_buffer; + int left = num_cached; - glMatrixMode (GL_TEXTURE); - glPushMatrix (); - glLoadIdentity (); + if (!dirty) { + dirty = SDL_FREETYPE_TRUE; - glMatrixMode (GL_MODELVIEW); - glPushMatrix (); + glMatrixMode (GL_TEXTURE); + glPushMatrix (); + glLoadIdentity (); - glEnable (GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); - glEnable (GL_TEXTURE_2D); - glBindTexture (GL_TEXTURE_2D, render->texture); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glTranslatef (x * render->usx, y * render->usy, 0.0f); + glEnable (GL_TEXTURE_2D); + glBindTexture (GL_TEXTURE_2D, render->texture); - glColor4ub (r, g, b, a); + glTranslatef (x * render->usx, y * render->usy, 0.0f); - glEnableClientState (GL_VERTEX_ARRAY); - glEnableClientState (GL_TEXTURE_COORD_ARRAY); + glColor4ub (r, g, b, a); - glVertexPointer (2, GL_FLOAT, 0, vertex_buffer); - glTexCoordPointer (2, GL_FLOAT, 0, texcoord_buffer); + glEnableClientState (GL_VERTEX_ARRAY); + glEnableClientState (GL_TEXTURE_COORD_ARRAY); - i = 0; - while (left) { - int num_quads = VERTEX_BUFFER_SIZE; - int max_index; - int j = 0; + glVertexPointer (2, GL_FLOAT, 0, vertex_buffer); + glTexCoordPointer (2, GL_FLOAT, 0, texcoord_buffer); + } - if (left < num_quads) - num_quads = left; + i = 0; + while (left) { + int num_quads = VERTEX_BUFFER_SIZE; + int max_index; + int j; - max_index = i + num_quads; - for (j = 0; i < max_index; i++, j += 12) { - user_data = cached[i].info->data; + if (left < num_quads) + num_quads = left; - 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; + max_index = i + num_quads; - x1 *= render->usx; - y1 *= render->usy; - x2 *= render->usx; - y2 *= render->usy; + for (j = 0; i < max_index; i++, j += 12) { + user_data = cached[i].info->data; - 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; + assert (user_data->locked != 0); - 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; + 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; - 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; + x1 *= render->usx; + y1 *= render->usy; + x2 *= render->usx; + y2 *= render->usy; - 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 + 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 + 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 + 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 + 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; + 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; - user_data->locked = SDL_FREETYPE_FALSE; - } + 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; - glDrawArrays (GL_TRIANGLES, 0, num_quads * 6); + 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; - left -= num_quads; + user_data->locked--; + } + + glDrawArrays (GL_TRIANGLES, 0, num_quads * 6); + + left -= num_quads; + } } + start = end; + } + if (dirty) { glDisableClientState (GL_VERTEX_ARRAY); glDisableClientState (GL_TEXTURE_COORD_ARRAY); - glPopMatrix (); + glPopMatrix (); - glMatrixMode (GL_TEXTURE); - glPopMatrix (); - } + glMatrixMode (GL_TEXTURE); + glPopMatrix (); - if (!blend_enabled) - glDisable (GL_BLEND); + if (!blend_enabled) + glDisable (GL_BLEND); - glBindTexture (GL_TEXTURE_2D, 0); + glBindTexture (GL_TEXTURE_2D, 0); + } if (cached != stack_cached) free (cached); @@ -471,17 +499,18 @@ sdl_freetype_opengles_glyph_move_in (sdl_freetype_area_manager_t * manager, static void sdl_freetype_opengles_glyph_move_out (sdl_freetype_area_manager_t * manager, - sdl_freetype_area_t * area, void * closure) + sdl_freetype_area_t * area, void * closure) { sdl_freetype_opengles_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 sdl_freetype_opengles_glyph_compare_score (sdl_freetype_area_manager_t * manager, - sdl_freetype_area_t * area, - void * closure1, void * closure2) + sdl_freetype_area_t * area, + void * closure1, void * closure2) { sdl_freetype_opengles_user_data_t * user_data = closure1; @@ -511,10 +540,10 @@ sdl_freetype_opengles_render_create (void) render->usx = render->usy = 1.0; render->width = render->height = GLYPH_CACHE_SIZE; render->manager = - sdl_freetype_area_manager_create (render->width, - render->height, - GLYPH_CACHE_LEVEL, - &sdl_freetype_opengles_glyph_ops); + sdl_freetype_area_manager_create (render->width, + render->height, + GLYPH_CACHE_LEVEL, + &sdl_freetype_opengles_glyph_ops); if (!render->manager) goto errquit1; @@ -534,7 +563,7 @@ sdl_freetype_opengles_render_create (void) sdl_freetype_error_t sdl_freetype_opengles_render_set_unit_scale (sdl_freetype_glyph_render_t * render, - float sx, float sy) + float sx, float sy) { sdl_freetype_opengles_render_t * opengles_render = (sdl_freetype_opengles_render_t *) render; |