/* Copyright (C) <2011> Luo Jinghua * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #ifdef HAVE_FONTCONFIG #include #endif #include #include enum TextFormat { TF_NONE = 0, TF_CALCRECT = 1 << 0, TF_CENTER = 1 << 1, TF_LEFT = 1 << 2, TF_RIGHT = 1 << 3, TF_SINGLELINE = 1 << 4, TF_NOCLIP = 1 << 5 }; struct TextRect { int x; int y; int width; int height; }; struct TextColor { unsigned char r; unsigned char g; unsigned char b; unsigned char a; }; typedef std::vector GlyphVector; struct TextLine { GlyphVector glyphs; sdl_freetype_text_fixed_extents_t exts; }; typedef std::vector TextLineVector; static int DrawText(sdl_freetype_font_t * font, FT_Int32 *text, int len, TextRect *rect, TextFormat format, TextColor color) { if (!font || !text) return 0; if (len < 0) { FT_Int32 *s = text; len = 0; while (*s++) len++; } TextLineVector lines; sdl_freetype_font_fixed_extents_t exts; sdl_freetype_font_fixed_extents(font, &exts); sdl_freetype_fixed_t x = 0; sdl_freetype_fixed_t y = 0; sdl_freetype_fixed_t adv_x = 0; sdl_freetype_fixed_t adv_y = 0; sdl_freetype_fixed_t width = rect->width << 16; sdl_freetype_fixed_t maxwidth = 0; bool clip = (format & TF_NOCLIP) == 0; lines.push_back(TextLine()); TextLine *line = &lines.back(); memset(&line->exts, 0, sizeof(line->exts)); for (int i = 0; i < len; i++) { sdl_freetype_glyph_t g; sdl_freetype_text_fixed_extents_t metrics; if (text[i] == '\r') continue; if (clip && (y + exts.height) >> 16 > rect->height) break; if (text[i] == '\n') { if (format & TF_SINGLELINE) continue; y += exts.height; sdl_freetype_font_glyphs_fixed_extents(font, &line->exts, &line->glyphs[0], line->glyphs.size()); if (line->exts.width > maxwidth) maxwidth = line->exts.width; lines.push_back(TextLine()); line = &lines.back(); memset(&line->exts, 0, sizeof(line->exts)); adv_x = 0; adv_y = 0; x = 0; } x += adv_x; y += adv_y; g.x = x; g.y = y; g.index = sdl_freetype_font_glyph_index(font, text[i]); if (!g.index || sdl_freetype_font_glyph_fixed_metrics(font, g.index, &metrics)) { adv_x = 0; adv_y = 0; continue; } else { adv_x = metrics.x_advance; adv_y = metrics.y_advance; } if (format & TF_SINGLELINE) { if (!clip || x + metrics.width <= width) line->glyphs.push_back(g); else break; } else { if (clip && x + metrics.width > width) { sdl_freetype_font_glyphs_fixed_extents(font, &line->exts, &line->glyphs[0], line->glyphs.size()); if (line->exts.width > maxwidth) maxwidth = line->exts.width; lines.push_back(TextLine()); line = &lines.back(); memset(&line->exts, 0, sizeof(line->exts)); x = 0; y += exts.height; g.y = y; g.x = x; } line->glyphs.push_back(g); } } if (line->glyphs.size() && !line->exts.width) sdl_freetype_font_glyphs_fixed_extents(font, &line->exts, &line->glyphs[0], line->glyphs.size()); if (!(format & TF_CALCRECT)) { int xoffset; int yoffset; if (lines.size()) yoffset = (exts.height - exts.descent) >> 16; for (size_t i = 0; i < lines.size(); i++) { TextLine &line = lines[i]; xoffset = -line.exts.x_bearing >> 16; if (format & TF_RIGHT) xoffset += rect->width - (line.exts.width >> 16); else if (format & TF_CENTER) xoffset += (rect->width - (line.exts.width >> 16)) / 2; sdl_freetype_font_show_glyphs(font, 0, color.r, color.g, color.b, color.a, rect->x + xoffset, rect->y + yoffset, &line.glyphs[0], line.glyphs.size()); } } if (!lines[0].glyphs.size()) return 0; rect->width = maxwidth >> 16; return (lines.size() * exts.height) >> 16; } static void DrawLine(float x0, float y0, float x1, float y1) { GLfloat verts[4]; verts[0] = x0; verts[1] = y0; verts[2] = x1; verts[3] = y1; glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (2, GL_FLOAT, 0, verts); glDrawArrays (GL_LINES, 0, 2); glDisableClientState (GL_VERTEX_ARRAY); } static void DrawRect(float x, float y, float w, float h) { DrawLine(x, y, x + w, y); DrawLine(x + w, y, x + w, y + h); DrawLine(x + w, y + h, x, y + h); DrawLine(x, y + h, x, y); } int main(int argc, char *argv[]) { SDL_Surface * screen; Uint8 video_bpp; Uint32 videoflags; int done; SDL_Event event; float alpha, step; sdl_freetype_font_t * font; sdl_freetype_glyph_render_t * render; FT_Int32 text[] = { 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.', ' ', 0x4f60, 0x597d, ',', ' ', 0x5927, 0x4e16, 0x754c, 0xff01, 0x0000 }; /* Initialize SDL */ if (SDL_Init (SDL_INIT_VIDEO) < 0) goto errquit0; videoflags = SDL_HWSURFACE; videoflags |= SDL_OPENGL; video_bpp = 32; /* Set 640x480 video mode */ screen = SDL_SetVideoMode (640, 480, video_bpp, videoflags); if (!screen) goto errquit0; //use following code to create a font if fontconfig isn't //available. //font = sdl_freetype_font_create("/path/to/font.ttf", // pixel_size); #ifdef HAVE_FONTCONFIG font = sdl_ft_create_font ("sans", 18, SDL_FT_WEIGHT_NORMAL, SDL_FT_SLANT_NORMAL, 96); #else if (argc < 2) goto errquit0; font = sdl_freetype_font_create(argv[1], 18 * 96 / 72.0); #endif if (!font) goto errquit0; //create a opengl font renderer render = sdl_freetype_opengl_render_create (); if (!render) goto errquit1; //replace the default font renderer with opengl one sdl_freetype_font_set_render (font, render); glMatrixMode (GL_PROJECTION) ; glLoadIdentity (); glOrtho (0, 640, 480, 0, -1.0, 1.0); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glEnable (GL_TEXTURE_2D); glClearColor (0.8f, 0.8f, 0.8f, 0.0f); alpha = 1.0f; step = -0.01; /* Wait for a keystroke */ done = 0; while (!done) { /* Check for events */ while (SDL_PollEvent (&event)) { switch (event.type) { case SDL_MOUSEBUTTONDOWN: break; case SDL_KEYDOWN: case SDL_QUIT: done = 1; break; default: break; } } glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glScalef (alpha + 1.0, alpha + 1.0, 1.0); TextColor color; color.r = 255; color.g = 0; color.b = 0; color.a = alpha * 255; TextRect rect; rect.x = 400; rect.y = 100; rect.width = 200; rect.height = 100; int h; // draw a single line and left aligned text h = DrawText(font, text, -1, &rect, TextFormat(TF_SINGLELINE | TF_LEFT), color); DrawRect(400, 100, 200, 100); DrawLine(400, 100 + h, 400 + 200, 100 + h); // draw a multiple lines and left aligned text rect.x = 100; rect.y = 100; rect.width = 100; rect.height = 100; h = DrawText(font, text, -1, &rect, TF_LEFT, color); DrawRect(100, 100, 200, 100); DrawLine(100, 100 + h, 100 + 200, 100 + h); // draw a multiple lines and right aligned text rect.x = 100; rect.y = 200; rect.width = 200; rect.height = 100; h = DrawText(font, text, -1, &rect, TF_RIGHT, color); DrawRect(100, 200, 200, 100); DrawLine(100, 200 + h, 100 + 200, 200 + h); // draw a multiple lines and center aligned text rect.x = 100; rect.y = 300; rect.width = 200; rect.height = 100; h = DrawText(font, text, -1, &rect, TF_CENTER, color); DrawRect(100, 300, 200, 100); DrawLine(100, 300 + h, 100 + 200, 300 + h); SDL_GL_SwapBuffers(); alpha += step; if (alpha < 0.0f) { alpha = 0.0f; step = -step; } else if (alpha > 1.0f) { alpha = 1.0f; step = -step; } SDL_Delay(20); } errquit1: sdl_freetype_font_destroy (font); sdl_freetype_fini (); errquit0: SDL_Quit(); return 0; }