summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuo Jinghua <sunmoon1997@gmail.com>2011-06-12 13:07:39 +0800
committerLuo Jinghua <sunmoon1997@gmail.com>2011-06-12 13:07:39 +0800
commitba5bd0a69af94ddcf3c5f19f2c3efb1ca5885c8f (patch)
treeb0eafdb68cc8ddbc50f5e1a14202b72677716487
parent71768e8d8bb1fd2aaaff5481485c046f78d96e56 (diff)
opengl: fix the renderer to draw glyphs at correct positions
-rw-r--r--src/sdl-freetype-opengl.c234
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