From 2251a7b2dc1f7fa36bad1a98e2b7062a0dff7706 Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Thu, 17 Nov 2011 09:56:25 +0000 Subject: [PATCH] - added freetype-gl rendered and set as default font renderer (see: http://code.google.com/p/freetype-gl/) --- source/shared_lib/CMakeLists.txt | 6 + .../include/graphics/freetype-gl/edtaa3func.h | 96 +++ .../graphics/freetype-gl/font-manager.h | 131 ++++ .../include/graphics/freetype-gl/markup.h | 128 ++++ .../graphics/freetype-gl/texture-atlas.h | 156 ++++ .../graphics/freetype-gl/texture-font.h | 120 +++ .../graphics/freetype-gl/texture-glyph.h | 131 ++++ .../include/graphics/freetype-gl/vector.h | 289 +++++++ .../graphics/freetype-gl/vertex-buffer.h | 477 ++++++++++++ .../graphics/gl/font_text_freetypegl.h | 280 +++++++ source/shared_lib/sources/graphics/font.cpp | 15 +- .../sources/graphics/freetype-gl/edtaa3func.c | 577 ++++++++++++++ .../graphics/freetype-gl/font-manager.c | 222 ++++++ .../sources/graphics/freetype-gl/makefont.c | 349 +++++++++ .../sources/graphics/freetype-gl/markup.c | 294 +++++++ .../graphics/freetype-gl/texture-atlas.c | 324 ++++++++ .../graphics/freetype-gl/texture-font.c | 422 ++++++++++ .../graphics/freetype-gl/texture-glyph.c | 225 ++++++ .../sources/graphics/freetype-gl/vector.c | 362 +++++++++ .../graphics/freetype-gl/vertex-buffer.c | 722 ++++++++++++++++++ .../graphics/gl/font_text_freetypegl.cpp | 336 ++++++++ 21 files changed, 5660 insertions(+), 2 deletions(-) create mode 100644 source/shared_lib/include/graphics/freetype-gl/edtaa3func.h create mode 100644 source/shared_lib/include/graphics/freetype-gl/font-manager.h create mode 100644 source/shared_lib/include/graphics/freetype-gl/markup.h create mode 100644 source/shared_lib/include/graphics/freetype-gl/texture-atlas.h create mode 100644 source/shared_lib/include/graphics/freetype-gl/texture-font.h create mode 100644 source/shared_lib/include/graphics/freetype-gl/texture-glyph.h create mode 100644 source/shared_lib/include/graphics/freetype-gl/vector.h create mode 100644 source/shared_lib/include/graphics/freetype-gl/vertex-buffer.h create mode 100644 source/shared_lib/include/graphics/gl/font_text_freetypegl.h create mode 100644 source/shared_lib/sources/graphics/freetype-gl/edtaa3func.c create mode 100644 source/shared_lib/sources/graphics/freetype-gl/font-manager.c create mode 100644 source/shared_lib/sources/graphics/freetype-gl/makefont.c create mode 100644 source/shared_lib/sources/graphics/freetype-gl/markup.c create mode 100644 source/shared_lib/sources/graphics/freetype-gl/texture-atlas.c create mode 100644 source/shared_lib/sources/graphics/freetype-gl/texture-font.c create mode 100644 source/shared_lib/sources/graphics/freetype-gl/texture-glyph.c create mode 100644 source/shared_lib/sources/graphics/freetype-gl/vector.c create mode 100644 source/shared_lib/sources/graphics/freetype-gl/vertex-buffer.c create mode 100644 source/shared_lib/sources/graphics/gl/font_text_freetypegl.cpp diff --git a/source/shared_lib/CMakeLists.txt b/source/shared_lib/CMakeLists.txt index c39117212..91a60c8df 100644 --- a/source/shared_lib/CMakeLists.txt +++ b/source/shared_lib/CMakeLists.txt @@ -188,6 +188,11 @@ IF(BUILD_MEGAGLEST_MODEL_VIEWER OR BUILD_MEGAGLEST_MAP_EDITOR OR BUILD_MEGAGLEST ADD_DEFINITIONS(-DMINIUPNPC_VERSION_PRE1_6) ENDIF() + OPTION(USE_FREETYPEGL "Use Freetype-GL for on-screen fonts" ON) + if(USE_FREETYPEGL) + ADD_DEFINITIONS(-DUSE_FREETYPEGL) + endif(USE_FREETYPEGL) + ######################################################################################### # megaglest lib @@ -195,6 +200,7 @@ IF(BUILD_MEGAGLEST_MODEL_VIEWER OR BUILD_MEGAGLEST_MAP_EDITOR OR BUILD_MEGAGLEST feathery_ftp glew graphics + graphics/freetype-gl graphics/gl graphics/md5 lua diff --git a/source/shared_lib/include/graphics/freetype-gl/edtaa3func.h b/source/shared_lib/include/graphics/freetype-gl/edtaa3func.h new file mode 100644 index 000000000..bfe61ea2f --- /dev/null +++ b/source/shared_lib/include/graphics/freetype-gl/edtaa3func.h @@ -0,0 +1,96 @@ +/* + * Copyright 2009 Stefan Gustavson (stefan.gustavson@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY STEFAN GUSTAVSON ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL STEFAN GUSTAVSON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Stefan Gustavson. + * + * + * edtaa3() + * + * Sweep-and-update Euclidean distance transform of an + * image. Positive pixels are treated as object pixels, + * zero or negative pixels are treated as background. + * An attempt is made to treat antialiased edges correctly. + * The input image must have pixels in the range [0,1], + * and the antialiased image should be a box-filter + * sampling of the ideal, crisp edge. + * If the antialias region is more than 1 pixel wide, + * the result from this transform will be inaccurate. + * + * By Stefan Gustavson (stefan.gustavson@gmail.com). + * + * Originally written in 1994, based on a verbal + * description of the SSED8 algorithm published in the + * PhD dissertation of Ingemar Ragnemalm. This is his + * algorithm, I only implemented it in C. + * + * Updated in 2004 to treat border pixels correctly, + * and cleaned up the code to improve readability. + * + * Updated in 2009 to handle anti-aliased edges. + * + * Updated in 2011 to avoid a corner case infinite loop. + * + */ + + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Compute the local gradient at edge pixels using convolution filters. + * The gradient is computed only at edge pixels. At other places in the + * image, it is never used, and it's mostly zero anyway. + */ +void computegradient(double *img, int w, int h, double *gx, double *gy); + +/* + * A somewhat tricky function to approximate the distance to an edge in a + * certain pixel, with consideration to either the local gradient (gx,gy) + * or the direction to the pixel (dx,dy) and the pixel greyscale value a. + * The latter alternative, using (dx,dy), is the metric used by edtaa2(). + * Using a local estimate of the edge gradient (gx,gy) yields much better + * accuracy at and near edges, and reduces the error even at distant pixels + * provided that the gradient direction is accurately estimated. + */ +double edgedf(double gx, double gy, double a); + + +double distaa3(double *img, double *gximg, double *gyimg, int w, int c, int xc, int yc, int xi, int yi); + +// Shorthand macro: add ubiquitous parameters dist, gx, gy, img and w and call distaa3() +#define DISTAA(c,xc,yc,xi,yi) (distaa3(img, gx, gy, w, c, xc, yc, xi, yi)) + +void edtaa3(double *img, double *gx, double *gy, int w, int h, short *distx, short *disty, double *dist); + +#ifdef __cplusplus +} +#endif diff --git a/source/shared_lib/include/graphics/freetype-gl/font-manager.h b/source/shared_lib/include/graphics/freetype-gl/font-manager.h new file mode 100644 index 000000000..3e32765c4 --- /dev/null +++ b/source/shared_lib/include/graphics/freetype-gl/font-manager.h @@ -0,0 +1,131 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#pragma once +#ifndef __FONT_MANAGER_H__ +#define __FONT_MANAGER_H__ + +#include "vector.h" +#include "markup.h" +#include "texture-font.h" +#include "texture-atlas.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * + */ +typedef struct { + TextureAtlas * atlas; + Vector * fonts; + wchar_t * cache; + Region black; +} FontManager; + + + +/** + * + */ + FontManager * + font_manager_new( size_t width, size_t height, size_t depth ); + + +/** + * + */ + void + font_manager_delete( FontManager *self ); + + +/** + * + */ + TextureFont * + font_manager_get_from_filename( FontManager * self, + const char * filename, + const float size ); + + +/** + * + */ + TextureFont * + font_manager_get_from_description( FontManager * self, + const char * family, + const float size, + const int bold, + const int italic ); + + +/** + * + */ + TextureFont * + font_manager_get_from_markup( FontManager *self, + const Markup *markup ); + + +/** + * + */ + char * + font_manager_match_description( FontManager * self, + const char * family, + const float size, + const int bold, + const int italic ); + + +/** + * + */ + const wchar_t * + font_manager_get_cache( FontManager * self ); + + +/** + * + */ + void + font_manager_set_cache( FontManager * self, + const wchar_t * cache ); + +#ifdef __cplusplus +} +#endif + +#endif /* __FONT_MANAGER_H__ */ + diff --git a/source/shared_lib/include/graphics/freetype-gl/markup.h b/source/shared_lib/include/graphics/freetype-gl/markup.h new file mode 100644 index 000000000..442880031 --- /dev/null +++ b/source/shared_lib/include/graphics/freetype-gl/markup.h @@ -0,0 +1,128 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#pragma once +#ifndef __MARKUP_H__ +#define __MARKUP_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + float r,g,b,a; +} Color; + +typedef struct +{ + char * family; + float size; + int bold; + int italic; + float rise; + float spacing; + Color foreground_color; + Color background_color; + int outline; + Color outline_color; + int underline; + Color underline_color; + int overline; + Color overline_color; + int strikethrough; + Color strikethrough_color; + struct TextureFont_ * font; +} Markup; + + +Markup * markup_new( void ); +Markup * markup_copy( const Markup *other ); + + +int markup_cmp( const Markup *self, + const Markup *other ); + +void markup_delete( Markup *self ); +const char * markup_get_family( Markup *self ); +void markup_set_family( Markup *self, + const char *family ); +int markup_get_italic( Markup *self ); +void markup_set_italic( Markup *self, + const int italic ); +int markup_get_bold( Markup *self ); +void markup_set_bold( Markup *self, + const int bold ); +float markup_get_size( Markup *self ); +void markup_set_size( Markup *self, + const float size ); +float markup_get_rise( Markup *self ); +void markup_set_rise( Markup *self, + const float rise ); +float markup_get_spacing( Markup *self ); +void markup_set_spacing( Markup *self, + const float spacing ); +Color markup_get_foreground_color( Markup *self ); +void markup_set_foreground_color( Markup *self, + const Color * color ); +Color markup_get_background_color( Markup *self ); +void markup_set_background_color( Markup *self, + const Color * color ); +int markup_get_outline( Markup *self ); +void markup_set_outline( Markup *self, + const int outline ); +Color markup_get_outline_color( Markup *self ); +void markup_set_outline_color( Markup *self, + const Color * color ); +int markup_get_underline( Markup *self ); +void markup_set_underline( Markup *self, + const int underline ); +Color markup_get_underline_color( Markup *self ); +void markup_set_underline_color( Markup *self, + const Color * color ); +int markup_get_overline( Markup *self ); +void markup_set_overline( Markup *self, + const int overline ); +Color markup_get_overline_color( Markup *self ); +void markup_set_overline_color( Markup *self, + const Color * color ); +int markup_get_strikethrough( Markup *self ); +void markup_set_strikethrough( Markup *self, + const int strikethrough ); +Color markup_get_strikethrough_color( Markup *self ); +void markup_set_strikethrough_color( Markup *self, + const Color * color ); + +#ifdef __cplusplus +} +#endif + +#endif /* __MARKUP_H__ */ diff --git a/source/shared_lib/include/graphics/freetype-gl/texture-atlas.h b/source/shared_lib/include/graphics/freetype-gl/texture-atlas.h new file mode 100644 index 000000000..717a96b0a --- /dev/null +++ b/source/shared_lib/include/graphics/freetype-gl/texture-atlas.h @@ -0,0 +1,156 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= + + This source is based on the article by Jukka Jylänki : + "A Thousand Ways to Pack the Bin - A Practical Approach to + Two-Dimensional Rectangle Bin Packing", February 27, 2010. + + More precisely, this is an implementation of the Skyline Bottom-Left + algorithm based on C++ sources provided by Jukka Jylänki at: + http://clb.demon.fi/files/RectangleBinPack/ + + ========================================================================= */ +#pragma once +#ifndef __TEXTURE_ATLAS_H__ +#define __TEXTURE_ATLAS_H__ +#include "vector.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A Region describes + * + * + */ +typedef struct +{ + int x; + int y; + int width; + int height; +} Region; + + +typedef struct { float x,y,z,w; } vec4; +typedef struct { float x,y,z; } vec3; +typedef struct { float x,y; } vec2; +typedef struct { int x,y,z,w; } ivec4; +typedef struct { int x,y,z; } ivec3; +typedef struct { int x,y; } ivec2; + + +typedef struct +{ + /** Current allocated nodes */ + Vector *nodes; + + /** Width (in pixels) of the underlying texture */ + size_t width; + + /** Height (in pixels) of the underlying texture */ + size_t height; + + /** Texture format (1, 3 or 4) */ + size_t depth; + + /** Allocated surface */ + size_t used; + + /** Texture identity (OpenGL) */ + unsigned int texid; + + unsigned char *data; + + /** A special region */ + Region black; + +} TextureAtlas; + + +/** + * + */ + TextureAtlas * + texture_atlas_new( size_t width, + size_t height, + size_t depth ); + + +/** + * + */ + void + texture_atlas_delete( TextureAtlas *self ); + + +/** + * + */ + void + texture_atlas_upload( TextureAtlas *self ); + + +/** + * + */ + Region + texture_atlas_get_region( TextureAtlas *self, + size_t width, + size_t height ); + + +/** + * + */ + void + texture_atlas_set_region( TextureAtlas *self, + size_t x, + size_t y, + size_t width, + size_t height, + unsigned char *data, + size_t stride ); + +/** + * + */ + void + texture_atlas_clear( TextureAtlas *self ); + +#ifdef __cplusplus +} +#endif + +#endif /* __TEXTURE_ATLAS_H__ */ diff --git a/source/shared_lib/include/graphics/freetype-gl/texture-font.h b/source/shared_lib/include/graphics/freetype-gl/texture-font.h new file mode 100644 index 000000000..8cc178c7b --- /dev/null +++ b/source/shared_lib/include/graphics/freetype-gl/texture-font.h @@ -0,0 +1,120 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#pragma once +#ifndef __TEXTURE_FONT_H__ +#define __TEXTURE_FONT_H__ + +#include +#include FT_FREETYPE_H +#include "vector.h" +#include "texture-atlas.h" +#include "texture-glyph.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * + */ +struct TextureFont_ +{ + Vector * glyphs; + TextureAtlas * atlas; + char * filename; + int bold; + int italic; + float size; + float gamma; + Region black; + int antialias; + int subpixel; + int hinting; + float height; + float linegap; + float ascender; + float descender; + int lcd_filter; + unsigned char lcd_weights[5]; +}; +typedef struct TextureFont_ TextureFont; + + + +/** + * + */ + TextureFont * + texture_font_new( TextureAtlas * atlas, + const char * filename, + const float size ); + + +/** + * + */ + void + texture_font_delete( TextureFont * self ); + + +/** + * + */ + TextureGlyph * + texture_font_get_glyph( TextureFont * self, + wchar_t charcode ); + + +/** + * + */ + size_t + texture_font_cache_glyphs( TextureFont * self, + const wchar_t * charcodes ); + + +/** + * + */ + int + texture_font_load_face( FT_Library * library, + const char * filename, + const float size, + FT_Face * face ); + +#ifdef __cplusplus +} +#endif + +#endif /* __TEXTURE_FONT_H__ */ + diff --git a/source/shared_lib/include/graphics/freetype-gl/texture-glyph.h b/source/shared_lib/include/graphics/freetype-gl/texture-glyph.h new file mode 100644 index 000000000..d293785ce --- /dev/null +++ b/source/shared_lib/include/graphics/freetype-gl/texture-glyph.h @@ -0,0 +1,131 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#pragma once +#ifndef __TEXTURE_GLYPH_H__ +#define __TEXTURE_GLYPH_H__ + +#include +#include "markup.h" +#include "vertex-buffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * + */ +typedef struct { + wchar_t charcode; + float kerning; +} KerningPair; + + +/** + * + */ +typedef struct { + float x,y; +} Pen; + + +/** + * + */ +typedef struct { + wchar_t charcode; + int width, height; + int offset_x, offset_y; + float advance_x, advance_y; + float u0, v0, u1, v1; + KerningPair * kerning; + size_t kerning_count; + struct TextureFont_ *font; +} TextureGlyph; + + +/** + * + */ +typedef struct { + float x, y, z; + float u, v; + float r, g, b, a; +} TextureGlyphVertex; + + +/** + * + */ + TextureGlyph * + texture_glyph_new( void ); + + +/** + * + */ + void + texture_glyph_delete( TextureGlyph * self ); + + +/** + * + */ + void + texture_glyph_render( TextureGlyph * self, + Markup * markup, + Pen * pen ); + + +/** + * + */ + void + texture_glyph_add_to_vertex_buffer( const TextureGlyph * self, + VertexBuffer * buffer, + const Markup * markup, + Pen * pen, int kerning ); + + +/** + * + */ + float + texture_glyph_get_kerning( TextureGlyph * self, + wchar_t charcode ); + +#ifdef __cplusplus +} +#endif + +#endif /* __TEXTURE_GLYPH_H__ */ diff --git a/source/shared_lib/include/graphics/freetype-gl/vector.h b/source/shared_lib/include/graphics/freetype-gl/vector.h new file mode 100644 index 000000000..aafddccef --- /dev/null +++ b/source/shared_lib/include/graphics/freetype-gl/vector.h @@ -0,0 +1,289 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#ifndef __VECTOR_H__ +#define __VECTOR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Generic vector structure. + */ +typedef struct + { + /** Pointer to dynamically allocated items. */ + void * items; + + /** Number of items that can be held in currently allocated storage. */ + size_t capacity; + + /** Number of items. */ + size_t size; + + /** Size (in bytes) of a single item. */ + size_t item_size; +} Vector; + +/** + * Creates a vector. + * + * @param item_size item size in bytes + * @return a new empty vector + */ + Vector * + vector_new( size_t item_size ); + +/** + * Deletes a vector. + * + * @param self a vector structure + */ + void + vector_delete( Vector *self ); + +/** + * Returns a pointer to the item located at specified index. + * + * @param self a vector structure + * @param index the index of the item to be returned + * @return pointer on the specified item + */ + const void * + vector_get( const Vector *self, + size_t index ); + +/** + * Returns a pointer to the first item. + * + * @param self a vector structure + * @return pointer on the first item + */ + const void * + vector_front( const Vector *self ); + +/** + * Returns a pointer to the last item + * + * @param self a vector structure + * @return pointer on the last item + */ + const void * + vector_back( const Vector *self ); + +/** + * Check if an item is contained within the vector. + * + * @param self a vector structure + * @param item item to be searched in the vector + * @param cmp a pointer a comparison function + * @return 1 if item is contained within the vector, 0 otherwise + */ + int + vector_contains( const Vector *self, + const void *item, + int (*cmp)(const void *, const void *) ); + +/** + * Checks whether the vector is empty. + * + * @param self a vector structure + * @return 1 if the vector is empty, 0 otherwise + */ + int + vector_empty( const Vector *self ); + +/** + * Returns the number of items + * + * @param self a vector structure + * @return number of items + */ + size_t + vector_size( const Vector *self ); + +/** + * Reserve storage such that it can hold at last size items. + * + * @param self a vector structure + * @param size the new storage capacity + */ + void + vector_reserve( Vector *self, + const size_t size ); + +/** + * Returns current storage capacity + * + * @param self a vector structure + * @return storage capacity + */ + size_t + vector_capacity( const Vector *self ); + +/** + * Decrease capacity to fit actual size. + * + * @param self a vector structure + */ + void + vector_shrink( Vector *self ); + +/** + * Removes all items. + * + * @param self a vector structure + */ + void + vector_clear( Vector *self ); + +/** + * Replace an item. + * + * @param self a vector structure + * @param index the index of the item to be replaced + * @param item the new item + */ + void + vector_set( Vector *self, + const size_t index, + const void *item ); + +/** + * Erase an item. + * + * @param self a vector structure + * @param index the index of the item to be erased + */ + void + vector_erase( Vector *self, + const size_t index ); + +/** + * Erase a range of items. + * + * @param self a vector structure + * @param first the index of the first item to be erased + * @param last the index of the last item to be erased + */ + void + vector_erase_range( Vector *self, + const size_t first, + const size_t last ); + +/** + * Appends given item to the end of the vector. + * + * @param self a vector structure + * @param item the item to be inserted + */ + void + vector_push_back( Vector *self, + const void *item ); + +/** + * Removes the last item of the vector. + * + * @param self a vector structure + */ + void + vector_pop_back( Vector *self ); + +/** + * Resizes the vector to contain size items + * + * If the current size is less than size, additional items are appended and + * initialized with value. If the current size is greater than size, the + * vector is reduced to its first size elements. + * + * @param self a vector structure + * @param size the new size + */ + void + vector_resize( Vector *self, + const size_t size ); + +/** + * Insert a single item at specified index. + * + * @param self a vector structure + * @param index location before which to insert item + * @param item the item to be inserted + */ + void + vector_insert( Vector *self, + const size_t index, + const void *item ); + +/** + * Insert raw data at specified index. + * + * @param self a vector structure + * @param index location before which to insert item + * @param data a pointer to the items to be inserted + * @param count the number of items to be inserted + */ + void + vector_insert_data( Vector *self, + const size_t index, + const void * data, + const size_t count ); + +/** + * Append raw data to the end of the vector. + * + * @param self a vector structure + * @param data a pointer to the items to be inserted + * @param count the number of items to be inserted + */ + void + vector_push_back_data( Vector *self, + const void * data, + const size_t count ); + +/** + * Sort vector items according to cmp function. + * + * @param self a vector structure + * @param cmp a pointer a comparison function + */ + void + vector_sort( Vector *self, + int (*cmp)(const void *, const void *) ); + +#ifdef __cplusplus +} +#endif + +#endif /* __VECTOR_H__ */ diff --git a/source/shared_lib/include/graphics/freetype-gl/vertex-buffer.h b/source/shared_lib/include/graphics/freetype-gl/vertex-buffer.h new file mode 100644 index 000000000..cf99cb670 --- /dev/null +++ b/source/shared_lib/include/graphics/freetype-gl/vertex-buffer.h @@ -0,0 +1,477 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#ifndef __VERTEX_BUFFER_H__ +#define __VERTEX_BUFFER_H__ +#if defined(__APPLE__) + #include +#else + #include +#endif +#include "vector.h" + +#define MAX_VERTEX_ATTRIBUTE 64 + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Generic vertex attribute. + */ +typedef struct +{ + /** + * a client-side capability. + */ + GLenum target; + + /** + * a translated client-side capability. + */ + GLchar ctarget; + + /** + * index of the generic vertex attribute to be modified. + */ + GLuint index; + + /** + * Number of components per generic vertex attribute. Must be 1, 2, 3, or + * 4. The initial value is 4. + */ + GLint size; + + /** + * Data type of each component in the array. Symbolic constants GL_BYTE, + * GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, + * GL_FLOAT, or GL_DOUBLE are accepted. The initial value is GL_FLOAT. + */ + GLenum type; + + /** + * Whether fixed-point data values should be normalized (GL_TRUE) or + * converted directly as fixed-point values (GL_FALSE) when they are + * accessed. + */ + GLboolean normalized; + + /** + * Byte offset between consecutive generic vertex attributes. If stride is + * 0, the generic vertex attributes are understood to be tightly packed in + * the array. The initial value is 0. + */ + GLsizei stride; + + /** + * Pointer to the first component of the first attribute element in the + * array. + */ + GLvoid * pointer; + + /** Pointer to the function that enable this attribute. */ + void ( * enable )(void *); + +} VertexAttribute; + + + +/** + * Generic vertex buffer. + */ +typedef struct +{ + /** Format of the vertex buffer. */ + char * format; + + /** Vector of vertices. */ + Vector * vertices; + + /** GL identity of the vertices buffer. */ + GLuint vertices_id; + + /** Vector of indices. */ + Vector * indices; + + /** GL identity of the indices buffer. */ + GLuint indices_id; + + /** Whether the vertex buffer needs to be uploaded to GPU memory. */ + char dirty; + + /** Array of attributes. */ + VertexAttribute *attributes[MAX_VERTEX_ATTRIBUTE]; +} VertexBuffer; + + + +/** + * Creates an empty vertex buffer. + * + * @param format a string describing vertex format. + * @return an empty vertex buffer. + */ + VertexBuffer * + vertex_buffer_new( const char *format ); + + +/** + * Creates a vertex buffer from data. + * + * @param format a string describing vertex format. + * @param vcount number of vertices + * @param vertices raw vertices data + * @param icount number of vertices + * @param indices raw indices data + * @return an empty vertex buffer. + */ + VertexBuffer * + vertex_buffer_new_from_data( char *format, + size_t vcount, + void * vertices, + size_t icount, + GLuint * indices ); + + +/** + * Deletes vertex buffer and releases GPU memory. + * + * @param self a vertex buffer + */ + void + vertex_buffer_delete( VertexBuffer * self ); + + + +/** + * Print information about a vertex buffer + * + * @param self a vertex buffer + */ + void + vertex_buffer_print( VertexBuffer * self ); + + +/** + * Immediate draw + * + * @param self a vertex buffer + * @param mode render mode + * @param what attributes to be rendered + */ + void + vertex_buffer_draw ( const char * format, + const GLenum mode, + const void * vertices, + const size_t count ); + + +/** + * Immediate draw with indexed vertices + * + * @param self a vertex buffer + * @param mode render mode + * @param what attributes to be rendered + */ + void + vertex_buffer_draw_indexed ( const char * format, + const GLenum mode, + const void * vertices, + const size_t vcount, + const GLuint * indices, + const size_t icount ); + + +/** + * Render vertex buffer. + * + * @param self a vertex buffer + * @param mode render mode + * @param what attributes to be rendered + */ + void + vertex_buffer_render ( VertexBuffer *self, + GLenum mode, + const char *what ); + + +/** + * Upload buffer to GPU memory. + * + * @param self a vertex buffer + */ + void + vertex_buffer_upload( VertexBuffer *self ); + + +/** + * Clear all vertices and indices + * + * @param self a vertex buffer + */ + void + vertex_buffer_clear( VertexBuffer *self ); + + +/** + * Appends a single index at the end of the buffer. + * + * @param self a vertex buffer + * @param index index to be appended + */ + void + vertex_buffer_push_back_index ( VertexBuffer *self, + GLuint index ); + + +/** + * Appends a single vertex at the end of the buffer. + * + * @param self a vertex buffer + * @param vertex vertex to be appended + */ + void + vertex_buffer_push_back_vertex ( VertexBuffer *self, + void *vertex ); + + +/** + * Appends indices at the end of the buffer. + * + * @param self a vertex buffer + * @param indices indices to be appended + * @param count number of indices to be appended + */ + void + vertex_buffer_push_back_indices ( VertexBuffer *self, + GLuint *indices, + size_t count ); + + +/** + * Appends vertices at the end of the buffer. + * + * @param self a vertex buffer + * @param vertices vertices to be appended + * @param count number of vertices to be appended + */ + void + vertex_buffer_push_back_vertices ( VertexBuffer *self, + void *vertices, + size_t count ); + + +/** + * Appends indices at the end of the buffer. + * + * @param self a vertex buffer + * @param index location before which to insert indices + * @param indices indices to be appended + * @param count number of indices to be appended + */ + void + vertex_buffer_insert_indices ( VertexBuffer *self, + size_t index, + GLuint *indices, + size_t count ); + + +/** + * Appends indices at the end of the buffer. + * + * @param self a vertex buffer + * @param index location before which to insert vertices + * @param vertices vertices to be appended + * @param count number of vertices to be appended + * + * @note + * Indices after index will be increased by count. + */ + void + vertex_buffer_add_vertices ( VertexBuffer *self, + size_t index, + void *vertices, + size_t count ); + + +/** + * Create an attribute from the given parameters. + * + * @param target client-side capability + * @param index index of the generic vertex attribute to be modified. + * @param size number of component + * @param type data type + * @param normalized Whether fixed-point data values should be normalized + (GL_TRUE) or converted directly as fixed-point values + (GL_FALSE) when they are accessed. + * @param stride byte offset between consecutive attributes. + * @param pointer pointer to the first component of the first attribute + * element in the array. + * @return a new initialized vertex attribute. + */ +VertexAttribute * +vertex_attribute_new( GLenum target, + GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + GLvoid *pointer ); + + +/** + * Create an attribute from the given description. + * + * @param format Format string specifies the format of a vertex attribute. + * @return an initialized vertex attribute + * + */ + VertexAttribute * + vertex_attribute_parse( char *format ); + + +/** + * Enable the position vertex attribute. + * + * @param attr a vertex attribute + */ + void + vertex_attribute_position_enable( VertexAttribute *attr ); + + +/** + * Enable the normal vertex attribute. + * + * @param attr a vertex attribute + */ + void + vertex_attribute_normal_enable( VertexAttribute *attr ); + + +/** + * Enable the color vertex attribute. + * + * @param attr a vertex attribute + */ + void + vertex_attribute_color_enable( VertexAttribute *attr ); + + +/** + * Enable the texture vertex attribute. + * + * @param attr a vertex attribute + */ + void + vertex_attribute_tex_coord_enable( VertexAttribute *attr ); + + +/** + * Enable the fog vertex attribute. + * + * @param attr a vertex attribute + */ + void + vertex_attribute_fog_coord_enable( VertexAttribute *attr ); + + +/** + * Enable the edge flag vertex attribute. + * + * @param attr a vertex attribute + */ + void + vertex_attribute_edge_flag_enable( VertexAttribute *attr ); + + +/** + * Enable the secondary color vertex attribute. + * + * @param attr a vertex attribute + */ + void + vertex_attribute_secondary_color_enable( VertexAttribute *attr ); + +/** + * Enable a generic vertex attribute. + * + * @param attr a vertex attribute + */ + void + vertex_attribute_generic_attribute_enable( VertexAttribute *attr ); + + +/** + * Returns the GL enum type correspond to given character. + * + * @param ctype character type + * @return GL enum type + */ + GLenum + GL_TYPE( char ctype ); + + +/** + * Get the GL name of the given target. + * + * @param ctarget a char describing target ( one of v,c,e,f,n,s,t) + * @return the associated GL target + */ + GLenum + GL_VERTEX_ATTRIBUTE_TARGET( char ctarget ); + + +/** + * Returns the size of a given GL enum type. + * + * @param gtype a GL enum type + * @return the size of the given type + */ + GLuint + GL_TYPE_SIZE( GLenum gtype ); + + +/** + * Returns the literal string of given GL enum type. + * + * @param gtype a GL enum type + * @return the literal string describing the type + */ + char * + GL_TYPE_STRING( GLenum gtype ); + +#ifdef __cplusplus +} +#endif + +#endif /* __VERTEX_BUFFER_H__ */ diff --git a/source/shared_lib/include/graphics/gl/font_text_freetypegl.h b/source/shared_lib/include/graphics/gl/font_text_freetypegl.h new file mode 100644 index 000000000..6826fc201 --- /dev/null +++ b/source/shared_lib/include/graphics/gl/font_text_freetypegl.h @@ -0,0 +1,280 @@ +// ============================================================== +// This file is part of the MegaGlest Shared Library (www.megaglest.org) +// +// Copyright (C) 2011 Mark Vejvoda and others +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 3 of the +// License, or (at your option) any later version +// ============================================================== + +#ifndef TextFreetypeGL_h +#define TextFreetypeGL_h + +#ifdef USE_FREETYPEGL + +//#include +#include + +//#include "vector.h" +#include "texture-font.h" +#include "texture-atlas.h" +#include "vertex-buffer.h" +#include "font-manager.h" + +#include "font_text.h" + +namespace Shared { namespace Graphics { namespace Gl { + +/** + * Use Freetype-GL for rendering text in OpenGL + */ +//==================================================================== +class TextFreetypeGL : public Text +{ +public: + + static string langHeightText; + static int faceResolution; + + TextFreetypeGL(FontTextHandlerType type); + virtual ~TextFreetypeGL(); + virtual void init(string fontName, int fontSize); + + virtual void SetFaceSize(int); + virtual int GetFaceSize(); + + virtual void Render(const char*, const int = -1); + virtual float Advance(const char*, const int = -1); + virtual float LineHeight(const char*, const int = -1); + + virtual void Render(const wchar_t*, const int = -1); + virtual float Advance(const wchar_t*, const int = -1); + virtual float LineHeight(const wchar_t* = L" ", const int = -1); + +private: + //FTFont *ftFont; + VertexBuffer *buffer; + TextureAtlas *atlas; + TextureFont *font; + //TextureGlyph *glyph; + FontManager *manager; + //Markup markup; + int fontFaceSize; + + string fontName; + const char* fontFile; + + const char* findFont(const char *firstFontToTry=NULL); + + void cleanupFont(); +}; + +}}}//end namespace + +/** + * Provides a way to easily walk multibyte unicode strings in the various + * Unicode encodings (UTF-8, UTF-16, UTF-32, UCS-2, and UCS-4). Encodings + * with elements larger than one byte must already be in the correct endian + * order for the current architecture. + */ +template +class FreetypeGLUnicodeStringItr +{ +public: + /** + * Constructor. Also reads the first character and stores it. + * + * @param string The buffer to iterate. No copy is made. + */ + FreetypeGLUnicodeStringItr(const T* string) : curPos(string), nextPos(string) + { + (*this)++; + }; + + /** + * Pre-increment operator. Reads the next unicode character and sets + * the state appropriately. + * Note - not protected against overruns. + */ + FreetypeGLUnicodeStringItr& operator++() + { + curPos = nextPos; + // unicode handling + switch (sizeof(T)) + { + case 1: // UTF-8 + // get this character + readUTF8(); break; + case 2: // UTF-16 + readUTF16(); break; + case 4: // UTF-32 + // fall through + default: // error condition really, but give it a shot anyway + curChar = *nextPos++; + } + return *this; + } + + /** + * Post-increment operator. Reads the next character and sets + * the state appropriately. + * Note - not protected against overruns. + */ + FreetypeGLUnicodeStringItr operator++(int) + { + FreetypeGLUnicodeStringItr temp = *this; + ++*this; + return temp; + } + + /** + * Equality operator. Two FreetypeGLUnicodeStringItrs are considered equal + * if they have the same current buffer and buffer position. + */ + bool operator==(const FreetypeGLUnicodeStringItr& right) const + { + if (curPos == right.getBufferFromHere()) + return true; + return false; + } + + /** + * Dereference operator. + * + * @return The unicode codepoint of the character currently pointed + * to by the FreetypeGLUnicodeStringItr. + */ + unsigned int operator*() const + { + return curChar; + } + + /** + * Buffer-fetching getter. You can use this to retreive the buffer + * starting at the currently-iterated character for functions which + * require a Unicode string as input. + */ + const T* getBufferFromHere() const { return curPos; } + +private: + /** + * Helper function for reading a single UTF8 character from the string. + * Updates internal state appropriately. + */ + void readUTF8(); + + /** + * Helper function for reading a single UTF16 character from the string. + * Updates internal state appropriately. + */ + void readUTF16(); + + /** + * The buffer position of the first element in the current character. + */ + const T* curPos; + + /** + * The character stored at the current buffer position (prefetched on + * increment, so there's no penalty for dereferencing more than once). + */ + unsigned int curChar; + + /** + * The buffer position of the first element in the next character. + */ + const T* nextPos; + + // unicode magic numbers + static const unsigned char utf8bytes[256]; + static const unsigned long offsetsFromUTF8[6]; + static const unsigned long highSurrogateStart; + static const unsigned long highSurrogateEnd; + static const unsigned long lowSurrogateStart; + static const unsigned long lowSurrogateEnd; + static const unsigned long highSurrogateShift; + static const unsigned long lowSurrogateBase; +}; + +/* The first character in a UTF8 sequence indicates how many bytes + * to read (among other things) */ +template +const unsigned char FreetypeGLUnicodeStringItr::utf8bytes[256] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6 +}; + +/* Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. */ +template +const unsigned long FreetypeGLUnicodeStringItr::offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +// get a UTF8 character; leave the tracking pointer at the start of the +// next character +// not protected against invalid UTF8 +template +inline void FreetypeGLUnicodeStringItr::readUTF8() +{ + unsigned int ch = 0; + unsigned int extraBytesToRead = utf8bytes[(unsigned char)(*nextPos)]; + // falls through + switch (extraBytesToRead) + { + case 6: ch += *nextPos++; ch <<= 6; /* remember, illegal UTF-8 */ + case 5: ch += *nextPos++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *nextPos++; ch <<= 6; + case 3: ch += *nextPos++; ch <<= 6; + case 2: ch += *nextPos++; ch <<= 6; + case 1: ch += *nextPos++; + } + ch -= offsetsFromUTF8[extraBytesToRead-1]; + curChar = ch; +} + +// Magic numbers for UTF-16 conversions +template +const unsigned long FreetypeGLUnicodeStringItr::highSurrogateStart = 0xD800; +template +const unsigned long FreetypeGLUnicodeStringItr::highSurrogateEnd = 0xDBFF; +template +const unsigned long FreetypeGLUnicodeStringItr::lowSurrogateStart = 0xDC00; +template +const unsigned long FreetypeGLUnicodeStringItr::lowSurrogateEnd = 0xDFFF; +template +const unsigned long FreetypeGLUnicodeStringItr::highSurrogateShift = 10; +template +const unsigned long FreetypeGLUnicodeStringItr::lowSurrogateBase = 0x0010000UL; + +template +inline void FreetypeGLUnicodeStringItr::readUTF16() +{ + unsigned int ch = *nextPos++; + // if we have the first half of the surrogate pair + if (ch >= highSurrogateStart && ch <= highSurrogateEnd) + { + unsigned int ch2 = *curPos; + // complete the surrogate pair + if (ch2 >= lowSurrogateStart && ch2 <= lowSurrogateEnd) + { + ch = ((ch - highSurrogateStart) << highSurrogateShift) + + (ch2 - lowSurrogateStart) + lowSurrogateBase; + ++nextPos; + } + } + curChar = ch; +} + + +#endif // USE_FREETYPEGL + +#endif // TextFreetypeGL_h diff --git a/source/shared_lib/sources/graphics/font.cpp b/source/shared_lib/sources/graphics/font.cpp index fc78fd1c1..f31891998 100644 --- a/source/shared_lib/sources/graphics/font.cpp +++ b/source/shared_lib/sources/graphics/font.cpp @@ -23,6 +23,12 @@ using namespace Shared::Graphics::Gl; #endif +#ifdef USE_FREETYPEGL + +#include "font_text_freetypegl.h" + +#endif + #include "util.h" #include "leak_dumper.h" @@ -153,10 +159,15 @@ Font::Font(FontTextHandlerType type) { size = 10; textHandler = NULL; -#ifdef USE_FTGL +#if defined(USE_FTGL) || defined(USE_FREETYPEGL) if(Font::forceLegacyFonts == false) { try { +#if defined(USE_FREETYPEGL) + textHandler = NULL; + textHandler = new TextFreetypeGL(type); + +#else TextFTGL::faceResolution = Font::faceResolution; TextFTGL::langHeightText = Font::langHeightText; @@ -164,7 +175,7 @@ Font::Font(FontTextHandlerType type) { textHandler = new TextFTGL(type); TextFTGL::faceResolution = Font::faceResolution; TextFTGL::langHeightText = Font::langHeightText; - +#endif metrics.setTextHandler(this->textHandler); } catch(exception &ex) { diff --git a/source/shared_lib/sources/graphics/freetype-gl/edtaa3func.c b/source/shared_lib/sources/graphics/freetype-gl/edtaa3func.c new file mode 100644 index 000000000..3bec8688b --- /dev/null +++ b/source/shared_lib/sources/graphics/freetype-gl/edtaa3func.c @@ -0,0 +1,577 @@ +/* + * Copyright 2009 Stefan Gustavson (stefan.gustavson@gmail.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY STEFAN GUSTAVSON ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL STEFAN GUSTAVSON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Stefan Gustavson. + * + * + * edtaa3() + * + * Sweep-and-update Euclidean distance transform of an + * image. Positive pixels are treated as object pixels, + * zero or negative pixels are treated as background. + * An attempt is made to treat antialiased edges correctly. + * The input image must have pixels in the range [0,1], + * and the antialiased image should be a box-filter + * sampling of the ideal, crisp edge. + * If the antialias region is more than 1 pixel wide, + * the result from this transform will be inaccurate. + * + * By Stefan Gustavson (stefan.gustavson@gmail.com). + * + * Originally written in 1994, based on a verbal + * description of the SSED8 algorithm published in the + * PhD dissertation of Ingemar Ragnemalm. This is his + * algorithm, I only implemented it in C. + * + * Updated in 2004 to treat border pixels correctly, + * and cleaned up the code to improve readability. + * + * Updated in 2009 to handle anti-aliased edges. + * + * Updated in 2011 to avoid a corner case infinite loop. + * +*/ +#include + + +/* + * Compute the local gradient at edge pixels using convolution filters. + * The gradient is computed only at edge pixels. At other places in the + * image, it is never used, and it's mostly zero anyway. + */ +void computegradient(double *img, int w, int h, double *gx, double *gy) +{ + int i,j,k; + double glength; +#define SQRT2 1.4142136 + for(i = 1; i < h-1; i++) { // Avoid edges where the kernels would spill over + for(j = 1; j < w-1; j++) { + k = i*w + j; + if((img[k]>0.0) && (img[k]<1.0)) { // Compute gradient for edge pixels only + gx[k] = -img[k-w-1] - SQRT2*img[k-1] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+1] + img[k+w+1]; + gy[k] = -img[k-w-1] - SQRT2*img[k-w] - img[k+w-1] + img[k-w+1] + SQRT2*img[k+w] + img[k+w+1]; + glength = gx[k]*gx[k] + gy[k]*gy[k]; + if(glength > 0.0) { // Avoid division by zero + glength = sqrt(glength); + gx[k]=gx[k]/glength; + gy[k]=gy[k]/glength; + } + } + } + } + // TODO: Compute reasonable values for gx, gy also around the image edges. + // (These are zero now, which reduces the accuracy for a 1-pixel wide region + // around the image edge.) 2x2 kernels would be suitable for this. +} + +/* + * A somewhat tricky function to approximate the distance to an edge in a + * certain pixel, with consideration to either the local gradient (gx,gy) + * or the direction to the pixel (dx,dy) and the pixel greyscale value a. + * The latter alternative, using (dx,dy), is the metric used by edtaa2(). + * Using a local estimate of the edge gradient (gx,gy) yields much better + * accuracy at and near edges, and reduces the error even at distant pixels + * provided that the gradient direction is accurately estimated. + */ +double edgedf(double gx, double gy, double a) +{ + double df, glength, temp, a1; + + if ((gx == 0) || (gy == 0)) { // Either A) gu or gv are zero, or B) both + df = 0.5-a; // Linear approximation is A) correct or B) a fair guess + } else { + glength = sqrt(gx*gx + gy*gy); + if(glength>0) { + gx = gx/glength; + gy = gy/glength; + } + /* Everything is symmetric wrt sign and transposition, + * so move to first octant (gx>=0, gy>=0, gx>=gy) to + * avoid handling all possible edge directions. + */ + gx = fabs(gx); + gy = fabs(gy); + if(gx 1.0) a = 1.0; + if(a < 0.0) a = 0.0; // Clip grayscale values outside the range [0,1] + if(a == 0.0) return 1000000.0; // Not an object pixel, return "very far" ("don't know yet") + + dx = (double)xi; + dy = (double)yi; + di = sqrt(dx*dx + dy*dy); // Length of integer vector, like a traditional EDT + if(di==0) { // Use local gradient only at edges + // Estimate based on local gradient only + df = edgedf(gx, gy, a); + } else { + // Estimate gradient based on direction to edge (accurate for large di) + df = edgedf(dx, dy, a); + } + return di + df; // Same metric as edtaa2, except at edges (where di=0) +} + +// Shorthand macro: add ubiquitous parameters dist, gx, gy, img and w and call distaa3() +#define DISTAA(c,xc,yc,xi,yi) (distaa3(img, gx, gy, w, c, xc, yc, xi, yi)) + +void edtaa3(double *img, double *gx, double *gy, int w, int h, short *distx, short *disty, double *dist) +{ + int x, y, i, c; + int offset_u, offset_ur, offset_r, offset_rd, + offset_d, offset_dl, offset_l, offset_lu; + double olddist, newdist; + int cdistx, cdisty, newdistx, newdisty; + int changed; + double epsilon = 1e-3; + + /* Initialize index offsets for the current image width */ + offset_u = -w; + offset_ur = -w+1; + offset_r = 1; + offset_rd = w+1; + offset_d = w; + offset_dl = w-1; + offset_l = -1; + offset_lu = -w-1; + + /* Initialize the distance images */ + for(i=0; i 0) // If non-zero distance or not set yet + { + c = i + offset_u; // Index of candidate for testing + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty+1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_ur; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty+1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + i++; + + /* Middle pixels have all neighbors */ + for(x=1; x 0) // If not already zero distance + { + c = i+offset_l; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx+1; + newdisty = cdisty; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_lu; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx+1; + newdisty = cdisty+1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_u; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty+1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + + /* Move index to second rightmost pixel of current row. */ + /* Rightmost pixel is skipped, it has no right neighbor. */ + i = y*w + w-2; + + /* scan left, propagate distance from right */ + for(x=w-2; x>=0; x--, i--) + { + olddist = dist[i]; + if(olddist <= 0) continue; // Already zero distance + + c = i+offset_r; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + } + + /* Scan rows in reverse order, except last row */ + for(y=h-2; y>=0; y--) + { + /* move index to rightmost pixel of current row */ + i = y*w + w-1; + + /* Scan left, propagate distances from below & right */ + + /* Rightmost pixel is special, has no right neighbors */ + olddist = dist[i]; + if(olddist > 0) // If not already zero distance + { + c = i+offset_d; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_dl; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx+1; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + i--; + + /* Middle pixels have all neighbors */ + for(x=w-2; x>0; x--, i--) + { + olddist = dist[i]; + if(olddist <= 0) continue; // Already zero distance + + c = i+offset_r; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_rd; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_d; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_dl; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx+1; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + /* Leftmost pixel is special, has no left neighbors */ + olddist = dist[i]; + if(olddist > 0) // If not already zero distance + { + c = i+offset_r; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_rd; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx-1; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + olddist=newdist; + changed = 1; + } + + c = i+offset_d; + cdistx = distx[c]; + cdisty = disty[c]; + newdistx = cdistx; + newdisty = cdisty-1; + newdist = DISTAA(c, cdistx, cdisty, newdistx, newdisty); + if(newdist < olddist-epsilon) + { + distx[i]=newdistx; + disty[i]=newdisty; + dist[i]=newdist; + changed = 1; + } + } + + /* Move index to second leftmost pixel of current row. */ + /* Leftmost pixel is skipped, it has no left neighbor. */ + i = y*w + 1; + for(x=1; x +#include +#include +#include +#include "font-manager.h" + + +wchar_t * +wcsdup( const wchar_t *string ) +{ + wchar_t * result; + assert( string ); + result = (wchar_t *) malloc( (wcslen(string) + 1) * sizeof(wchar_t) ); + wcscpy( result, string ); + return result; +} + + +FontManager * +font_manager_new( size_t width, size_t height, size_t depth ) +{ + static FontManager *self = 0; + if( !self ) + { + TextureAtlas *atlas = texture_atlas_new( width, height, depth ); + self = (FontManager *) malloc( sizeof(FontManager) ); + if( !self ) + { + return 0; + } + self->atlas = atlas; + self->fonts = vector_new( sizeof(TextureFont) ); + self->cache = wcsdup( L" " ); +/* + self->cache = wcsdup( L" !\"#$%&'()*+,-./0123456789:;<=>?" + L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + L"`abcdefghijklmnopqrstuvwxyz{|}~" ); +*/ + } + return self; +} + +void +font_manager_delete( FontManager *self ) +{ + assert( self ); + vector_delete( self->fonts ); + texture_atlas_delete( self->atlas ); + if( self->cache ) + { + free( self->cache ); + } + free( self ); +} + +TextureFont * +font_manager_get_from_filename( FontManager *self, + const char * filename, + const float size ) +{ + size_t i; + TextureFont *font; + + assert( self ); + + for( i=0; ifonts->size;++i ) + { + font = (TextureFont *) vector_get( self->fonts, i ); + if( (strcmp(font->filename, filename) == 0) && ( font->size == size) ) + { + return font; + } + } + font = texture_font_new( self->atlas, filename, size ); + texture_font_cache_glyphs( font, self->cache ); + if( font ) + { + vector_push_back( self->fonts, font ); + } + return font; +} + + +TextureFont * +font_manager_get_from_description( FontManager *self, + const char * family, + const float size, + const int bold, + const int italic ) +{ + assert( self ); + + TextureFont *font; + char *filename = font_manager_match_description( self, family, size, bold, italic ); + // fprintf(stderr, "Matched filename for %s: %s\n", family, filename); + if( !filename ) + { + return 0; + } + font = font_manager_get_from_filename( self, filename, size ); + free( filename ); + return font; +} + +TextureFont * +font_manager_get_from_markup( FontManager *self, + const Markup *markup ) +{ + assert( self ); + assert( markup ); + TextureFont *font = + font_manager_get_from_description( self, markup->family, markup->size, + markup->bold, markup->italic ); + return font; +} + + +char * +font_manager_match_description( FontManager *self, + const char * family, + const float size, + const int bold, + const int italic ) +{ + char *filename = 0; + int weight = FC_WEIGHT_REGULAR; + int slant = FC_SLANT_ROMAN; + if ( bold ) + { + weight = FC_WEIGHT_BOLD; + } + if( italic ) + { + slant = FC_SLANT_ITALIC; + } + FcInit(); + FcPattern *pattern = FcPatternCreate(); + FcPatternAddDouble( pattern, FC_SIZE, size ); + FcPatternAddInteger( pattern, FC_WEIGHT, weight ); + FcPatternAddInteger( pattern, FC_SLANT, slant ); + FcPatternAddString( pattern, FC_FAMILY, (FcChar8*) family ); + FcConfigSubstitute( 0, pattern, FcMatchPattern ); + FcDefaultSubstitute( pattern ); + FcResult result; + FcPattern *match = FcFontMatch( 0, pattern, &result ); + FcPatternDestroy( pattern ); + + if ( !match ) + { + fprintf( stderr, "fontconfig error: could not match family '%s'", family ); + return 0; + } + else + { + FcValue value; + FcResult result = FcPatternGet( match, FC_FILE, 0, &value ); + if ( result ) + { + fprintf( stderr, "fontconfig error: could not match family '%s'", family ); + } + else + { + filename = strdup( (char *)(value.u.s) ); + } + } + FcPatternDestroy( match ); + return filename; +} + + +const wchar_t * +font_manager_get_cache( FontManager *self ) +{ + assert( self ); + return self->cache; +} + +void +font_manager_set_cache( FontManager *self, + const wchar_t * cache ) +{ + assert( self ); + assert( cache ); + + if( self->cache ) + { + free( self->cache ); + } + self->cache = wcsdup( cache ); +} diff --git a/source/shared_lib/sources/graphics/freetype-gl/makefont.c b/source/shared_lib/sources/graphics/freetype-gl/makefont.c new file mode 100644 index 000000000..4e0f70bec --- /dev/null +++ b/source/shared_lib/sources/graphics/freetype-gl/makefont.c @@ -0,0 +1,349 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#if defined(__APPLE__) + #include +#else + #include +#endif +#include +#include +#include +#include "vector.h" +#include "texture-font.h" +#include "texture-glyph.h" +#include "texture-atlas.h" +#include "font-manager.h" + + +void display( void ) +{ + int viewport[4]; + glGetIntegerv( GL_VIEWPORT, viewport ); + GLuint width = viewport[2]; + GLuint height = viewport[3]; + + glClearColor(1,1,1,1); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glEnable( GL_TEXTURE_2D ); + glColor4f(0,0,0,1); + glBegin(GL_QUADS); + glTexCoord2f( 0, 1 ); glVertex2i( 0, 0 ); + glTexCoord2f( 0, 0 ); glVertex2i( 0, height ); + glTexCoord2f( 1, 0 ); glVertex2i( width, height ); + glTexCoord2f( 1, 1 ); glVertex2i( width, 0 ); + glEnd(); + glutSwapBuffers( ); +} + +void reshape(int width, int height) +{ + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, 0, height, -1, 1); + glMatrixMode(GL_MODELVIEW); + glutPostRedisplay(); +} + +void keyboard( unsigned char key, int x, int y ) +{ + if ( key == 27 ) + { + exit( 1 ); + } +} + +int main( int argc, char **argv ) +{ + size_t i, j; + + wchar_t * font_cache = + L" !\"#$%&'()*+,-./0123456789:;<=>?" + L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + L"`abcdefghijklmnopqrstuvwxyz{|}~"; + + char * font_family = "arial"; + float font_size = 16.0; + char * font_filename = "arial.ttf"; + char * header_filename = "arial-16.h"; + + TextureAtlas * atlas = texture_atlas_new( 128, 128, 1 ); + TextureFont * font = texture_font_new( atlas, font_filename, font_size ); + + + glutInit( &argc, argv ); + glutInitWindowSize( atlas->width, atlas->height ); + glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH ); + glutCreateWindow( "Freetype OpenGL" ); + glutReshapeFunc( reshape ); + glutDisplayFunc( display ); + glutKeyboardFunc( keyboard ); + glBindTexture( GL_TEXTURE_2D, atlas->texid ); + + size_t missed = texture_font_cache_glyphs( font, font_cache ); + + wprintf( L"Font filename : %s\n", font_filename ); + wprintf( L"Font size : %.1f\n", font_size ); + wprintf( L"Number of glyphs : %ld\n", wcslen(font_cache) ); + wprintf( L"Number of missed glyphs : %ld\n", missed ); + wprintf( L"Texture size : %ldx%ldx%ld\n", atlas->width, atlas->height, atlas->depth ); + wprintf( L"Texture occupancy : %.2f%%\n", + 100.0*atlas->used/(float)(atlas->width*atlas->height) ); + wprintf( L"\n" ); + wprintf( L"Header filename : %s\n", header_filename ); + + + + +// glutMainLoop(); + + + size_t texture_size = atlas->width * atlas->height *atlas->depth; + size_t glyph_count = font->glyphs->size; + size_t max_kerning_count = 1; + for( i=0; i < glyph_count; ++i ) + { + TextureGlyph *glyph = (TextureGlyph *) vector_get( font->glyphs, i ); + if( glyph->kerning_count > max_kerning_count ) + { + max_kerning_count = glyph->kerning_count; + } + } + + FILE *file = fopen( header_filename, "w" ); + + + // ------------- + // Header + // ------------- + fwprintf( file, + L"/* =========================================================================\n" + L" * Freetype GL - A C OpenGL Freetype engine\n" + L" * Platform: Any\n" + L" * WWW: http://code.google.com/p/freetype-gl/\n" + L" * -------------------------------------------------------------------------\n" + L" * Copyright 2011 Nicolas P. Rougier. All rights reserved.\n" + L" *\n" + L" * Redistribution and use in source and binary forms, with or without\n" + L" * modification, are permitted provided that the following conditions are met:\n" + L" *\n" + L" * 1. Redistributions of source code must retain the above copyright notice,\n" + L" * this list of conditions and the following disclaimer.\n" + L" *\n" + L" * 2. Redistributions in binary form must reproduce the above copyright\n" + L" * notice, this list of conditions and the following disclaimer in the\n" + L" * documentation and/or other materials provided with the distribution.\n" + L" *\n" + L" * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR\n" + L" * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n" + L" * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n" + L" * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n" + L" * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n" + L" * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n" + L" * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n" + L" * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" + L" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n" + L" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + L" *\n" + L" * The views and conclusions contained in the software and documentation are\n" + L" * those of the authors and should not be interpreted as representing official\n" + L" * policies, either expressed or implied, of Nicolas P. Rougier.\n" + L" * ========================================================================= */\n" ); + + + + // ---------------------- + // Structure declarations + // ---------------------- + fwprintf( file, + L"typedef struct\n" + L"{\n" + L" wchar_t charcode;\n" + L" float kerning;\n" + L"} Kerning;\n\n" ); + + fwprintf( file, + L"typedef struct\n" + L"{\n" + L" wchar_t charcode;\n" + L" int width, height;\n" + L" int offset_x, offset_y;\n" + L" float advance_x, advance_y;\n" + L" float u0, v0, u1, v1;\n" + L" size_t kerning_count;\n" + L" Kerning kerning[%d];\n" + L"} TextureGlyph;\n\n", max_kerning_count ); + + fwprintf( file, + L"typedef struct\n" + L"{\n" + L" size_t tex_width;\n" + L" size_t tex_height;\n" + L" size_t tex_depth;\n" + L" char tex_data[%d];\n" + L" float size;\n" + L" float height;\n" + L" float linegap;\n" + L" float ascender;\n" + L" float descender;\n" + L" size_t glyphs_count;\n" + L" TextureGlyph glyphs[%d];\n" + L"} TextureFont;\n\n", texture_size, glyph_count ); + + + + fwprintf( file, L"TextureFont font = {\n" ); + + + // ------------ + // Texture data + // ------------ + fwprintf( file, L" %d, %d, %d, \n", atlas->width, atlas->height, atlas->depth ); + fwprintf( file, L" {" ); + for( i=0; i < texture_size; i+= 32 ) + { + for( j=0; j < 32 && (j+i) < texture_size ; ++ j) + { + if( (j+i) < (texture_size-1) ) + { + fwprintf( file, L"%d,", atlas->data[i+j] ); + } + else + { + fwprintf( file, L"%d", atlas->data[i+j] ); + } + } + if( (j+i) < texture_size ) + { + fwprintf( file, L"\n " ); + } + } + fwprintf( file, L"}, \n" ); + + + // ------------------- + // Texture information + // ------------------- + fwprintf( file, L" %f, %f, %f, %f, %f, %d, \n", + font->size, font->height, + font->linegap,font->ascender, font->descender, + glyph_count ); + + // -------------- + // Texture glyphs + // -------------- + fwprintf( file, L" {\n" ); + for( i=0; i < glyph_count; ++i ) + { + TextureGlyph *glyph = (TextureGlyph *) vector_get( font->glyphs, i ); + +/* + // Debugging information + wprintf( L"glyph : '%lc'\n", + glyph->charcode ); + wprintf( L" size : %dx%d\n", + glyph->width, glyph->height ); + wprintf( L" offset : %+d%+d\n", + glyph->offset_x, glyph->offset_y ); + wprintf( L" advance : %f, %f\n", + glyph->advance_x, glyph->advance_y ); + wprintf( L" tex coords.: %f, %f, %f, %f\n", + glyph->u0, glyph->v0, glyph->u1, glyph->v1 ); + + wprintf( L" kerning : " ); + if( glyph->kerning_count ) + { + for( j=0; j < glyph->kerning_count; ++j ) + { + wprintf( L"('%lc', %f)", + glyph->kerning[j].charcode, glyph->kerning[j].kerning ); + if( j < (glyph->kerning_count-1) ) + { + wprintf( L", " ); + } + } + } + else + { + wprintf( L"None" ); + } + wprintf( L"\n\n" ); +*/ + + // TextureFont + if( (glyph->charcode == L'\'' ) || (glyph->charcode == L'\\' ) ) + { + fwprintf( file, L" {L'\\%lc', ", glyph->charcode ); + } + else + { + fwprintf( file, L" {L'%lc', ", glyph->charcode ); + } + fwprintf( file, L"%d, %d, ", glyph->width, glyph->height ); + fwprintf( file, L"%d, %d, ", glyph->offset_x, glyph->offset_y ); + fwprintf( file, L"%f, %f, ", glyph->advance_x, glyph->advance_y ); + fwprintf( file, L"%f, %f, %f, %f, ", glyph->u0, glyph->v0, glyph->u1, glyph->v1 ); + fwprintf( file, L"%d, ", max_kerning_count ); + fwprintf( file, L"{ " ); + for( j=0; j < glyph->kerning_count; ++j ) + { + wchar_t charcode = glyph->kerning[j].charcode; + + if( (charcode == L'\'' ) || (charcode == L'\\') ) + { + fwprintf( file, L"{L'\\%lc', %f}", charcode, glyph->kerning[j].kerning ); + } + else + { + fwprintf( file, L"{L'%lc', %f}", charcode, glyph->kerning[j].kerning ); + } + if( j < (glyph->kerning_count-1) ) + { + fwprintf( file, L", " ); + } + } + if( i < (glyph_count-1) ) + { + fwprintf( file, L"} },\n" ); + } + else + { + fwprintf( file, L"} }\n" ); + } + } + fwprintf( file, L" }\n};\n" ); + + return 0; +} diff --git a/source/shared_lib/sources/graphics/freetype-gl/markup.c b/source/shared_lib/sources/graphics/freetype-gl/markup.c new file mode 100644 index 000000000..76cfb854b --- /dev/null +++ b/source/shared_lib/sources/graphics/freetype-gl/markup.c @@ -0,0 +1,294 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#include +#include +#include +#include "font-manager.h" +#include "markup.h" + +Markup * +markup_new( void ) +{ + Color black = {0,0,0,1}; + Color white = {1,1,1,1}; + + Markup *self = (Markup *) malloc( sizeof(Markup) ); + if( !self ) + { + return NULL; + } + + self->family = strdup("monotype"); + self->italic = 0; + self->bold = 0; + self->size = 16; + self->rise = 0; + self->spacing= 0; + + self->foreground_color = black; + self->background_color = white; + self->underline = 0; + self->underline_color = black; + self->overline = 0; + self->overline_color = black; + self->strikethrough = 0; + self->strikethrough_color = black; + + self->font = 0; + + return self; +} + +void +markup_delete( Markup *self ) +{ + assert( self ); + + free( self->family ); + free( self ); +} + + +int +markup_cmp( const Markup *self, + const Markup *other ) +{ + size_t n = sizeof( Markup ) - sizeof( TextureFont * ); + return memcmp( self, other, n ); +} + + +const char * +markup_get_family( Markup *self ) +{ + assert( self ); + return self->family; +} + +void +markup_set_family( Markup *self, + const char *family ) +{ +} + +int +markup_get_italic( Markup *self ) +{ + assert( self ); + return self->italic; +} + +void +markup_set_italic( Markup *self, + const int italic ) +{ +} + +int +markup_get_bold( Markup *self ) +{ + assert( self ); + return self->bold; +} + +void +markup_set_bold( Markup *self, + const int bold ) +{ +} + +float +markup_get_size( Markup *self ) +{ + assert( self ); + + return self->size; +} + +void +markup_set_size( Markup *self, + const float size ) +{ +} + +float +markup_get_rise( Markup *self ) +{ + assert( self ); + return self->rise; +} + +void +markup_set_rise( Markup *self, const float rise ) +{ +} + +float +markup_get_spacing( Markup *self ) +{ + assert( self ); + return self->spacing; +} + +void +markup_set_spacing( Markup *self, const float spacing ) +{ +} + +Color +markup_get_foreground_color( Markup *self ) +{ + assert( self ); + return self->foreground_color; +} + +void +markup_set_foreground_color( Markup *self, const Color * color ) +{ +} + +Color +markup_get_background_color( Markup *self ) +{ + assert( self ); + return self->background_color; +} + +void +markup_set_background_color( Markup *self, const Color * color ) +{ +} + +int +markup_get_outline( Markup *self ) +{ + assert( self ); + return self->outline; +} + +void +markup_set_outline( Markup *self, + const int outline ) +{ +} + +Color +markup_get_outline_color( Markup *self ) +{ + assert( self ); + return self->outline_color; +} + +void +markup_set_outline_color( Markup *self, + const Color * color ) +{ +} + +int +markup_get_underline( Markup *self ) +{ + assert( self ); + return self->underline; +} + +void +markup_set_underline( Markup *self, + const int underline ) +{ +} + +Color +markup_get_underline_color( Markup *self ) +{ + assert( self ); + return self->underline_color; +} + +void +markup_set_underline_color( Markup *self, + const Color * color ) +{ +} + +int +markup_get_overline( Markup *self ) +{ + assert( self ); + return self->overline; +} + +void +markup_set_overline( Markup *self, + const int overline ) +{ +} + +Color +markup_get_overline_color( Markup *self ) +{ + assert( self ); + return self->overline_color; +} + +void +markup_set_overline_color( Markup *self, + const Color * color ) +{ +} + +int +markup_get_strikethrough( Markup *self ) +{ + assert( self ); + return self->strikethrough; +} + +void +markup_set_strikethrough( Markup *self, + const int strikethrough ) +{ +} + +Color +markup_get_strikethrough_color( Markup *self ) +{ + assert( self ); + return self->strikethrough_color; +} + +void +markup_set_strikethrough_color( Markup *self, + const Color * color ) +{ +} diff --git a/source/shared_lib/sources/graphics/freetype-gl/texture-atlas.c b/source/shared_lib/sources/graphics/freetype-gl/texture-atlas.c new file mode 100644 index 000000000..be7f3148c --- /dev/null +++ b/source/shared_lib/sources/graphics/freetype-gl/texture-atlas.c @@ -0,0 +1,324 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#if defined(__APPLE__) + #include +#else + #include +#endif +#include +#include +#include +#include +#include "texture-atlas.h" + +#define max(a,b) (a)>(b)?(a):(b) +#define min(a,b) (a)<(b)?(a):(b) + +typedef struct { int x, y, width; } Node; + + + + +/* ------------------------------------------------------------------------- */ +TextureAtlas * +texture_atlas_new( size_t width, size_t height, size_t depth ) +{ + assert( (depth == 1) || (depth == 3) ); + + TextureAtlas *self = (TextureAtlas *) malloc( sizeof(TextureAtlas) ); + if( !self ) + { + return NULL; + } + self->nodes = vector_new( sizeof(Node) ); + self->used = 0; + self->width = width; + self->height = height; + self->depth = depth; + Node node = {0,0,width}; + vector_push_back( self->nodes, &node ); + self->texid = 0; + self->data = (unsigned char *) + calloc( width*height*depth, sizeof(unsigned char) ); + + + // This is a special region that is used for background and underlined + // decorations of glyphs + int n = 4; + unsigned char buffer[n*n]; + memset(buffer, 255, n*n); + Region r = texture_atlas_get_region( self, n, n ); + texture_atlas_set_region( self, r.x, r.y, r.width, r.height, buffer, 1); + self->black.x = r.x + 1; + self->black.y = r.y + 1; + self->black.width = r.width - 2; + self->black.height= r.height - 2; + + return self; +} + + + +/* ------------------------------------------------------------------------- */ +void +texture_atlas_delete( TextureAtlas *self ) +{ + assert( self ); + vector_delete( self->nodes ); + if( self->data ) + { + free( self->data ); + } + if( self->texid ) + { + glDeleteTextures( 1, &self->texid ); + } + free( self ); +} + + + +/* ------------------------------------------------------------------------- */ +void +texture_atlas_upload( TextureAtlas *self ) +{ + assert( self ); + assert( self->data ); + if( !self->texid ) + { + glGenTextures( 1, &self->texid ); + } + glBindTexture( GL_TEXTURE_2D, self->texid ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + if( self->depth == 3 ) + { + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, self->width, self->height, + 0, GL_RGB, GL_UNSIGNED_BYTE, self->data ); + } + else + { + glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, self->width, self->height, + 0, GL_ALPHA, GL_UNSIGNED_BYTE, self->data ); + } +} + + + +/* ------------------------------------------------------------------------- */ +void +texture_atlas_set_region( TextureAtlas *self, + size_t x, size_t y, + size_t width, size_t height, + unsigned char *data, size_t stride ) +{ + assert( self ); + assert( x < self->width); + assert( (x + width) <= self->width); + assert( y < self->height); + assert( (y + height) <= self->height); + size_t i; + size_t depth = self->depth; + size_t charsize = sizeof(char); + for( i=0; idata+((y+i)*self->width + x ) * charsize * depth, + data + (i*stride) * charsize, width * charsize * depth ); + } +} + + + +/* ------------------------------------------------------------------------- */ +int +texture_atlas_fit( TextureAtlas *self, + size_t index, size_t width, size_t height ) +{ + Node *node = (Node *) (vector_get( self->nodes, index )); + int x = node->x, y, width_left = width; + size_t i = index; + + if ( (x + width) > self->width ) + { + return -1; + } + y = node->y; + while( width_left > 0 ) + { + node = (Node *) (vector_get( self->nodes, i )); + y = max( y, node->y ); + if( (y + height) > self->height ) + { + return -1; + } + width_left -= node->width; + ++i; + } + return y; +} + + + +/* ------------------------------------------------------------------------- */ +void +texture_atlas_merge( TextureAtlas *self ) +{ + Node *node, *next; + size_t i; + + for( i=0; i< self->nodes->size-1; ++i ) + { + node = (Node *) (vector_get( self->nodes, i )); + next = (Node *) (vector_get( self->nodes, i+1 )); + + if( node->y == next->y ) + { + node->width += next->width; + vector_erase( self->nodes, i+1 ); + --i; + } + } +} + + + +/* ------------------------------------------------------------------------- */ +Region +texture_atlas_get_region( TextureAtlas *self, + size_t width, size_t height ) +{ + assert( self ); +/* + assert( width ); + assert( height ); +*/ + int y, best_height, best_width, best_index; + Node *node, *prev; + Region region = {0,0,width,height}; + size_t i; + + best_height = INT_MAX; + best_index = -1; + best_width = INT_MAX; + for( i=0; inodes->size; ++i ) + { + y = texture_atlas_fit( self, i, width, height ); + if( y >= 0 ) + { + node = (Node *) vector_get( self->nodes, i ); + if( ( y + height < best_height ) || + ( y + height == best_height && node->width < best_width) ) + { + best_height = y + height; + best_index = i; + best_width = node->width; + region.x = node->x; + region.y = y; + } + } + } + + if( best_index == -1 ) + { + region.x = -1; + region.y = -1; + region.width = 0; + region.height = 0; + return region; + } + + node = (Node *) malloc( sizeof(Node) ); + node->x = region.x; + node->y = region.y + height; + node->width = width; + vector_insert( self->nodes, best_index, node ); + free( node ); + + for(i = best_index+1; i < self->nodes->size; ++i) + { + node = (Node *) vector_get( self->nodes, i ); + prev = (Node *) vector_get( self->nodes, i-1 ); + + if (node->x < (prev->x + prev->width) ) + { + int shrink = prev->x + prev->width - node->x; + node->x += shrink; + node->width -= shrink; + if (node->width <= 0) + { + vector_erase( self->nodes, i ); + --i; + } + else + { + break; + } + } + else + { + break; + } + } + texture_atlas_merge( self ); + self->used += width * height; + return region; +} + + +/* ------------------------------------------------------------------------- */ +void +texture_atlas_clear( TextureAtlas *self ) +{ + + vector_clear( self->nodes ); + self->used = 0; + Node node = {0,0,self->width}; + vector_push_back( self->nodes, &node ); + + memset( self->data, 0, self->width*self->height*self->depth ); + + + // This is a special region that is used for background and underlined + // decorations of glyphs + int n = 4; + unsigned char buffer[n*n]; + memset(buffer, 255, n*n); + Region r = texture_atlas_get_region( self, n, n ); + texture_atlas_set_region( self, r.x, r.y, r.width, r.height, buffer, 1); + self->black.x = r.x + 1; + self->black.y = r.y + 1; + self->black.width = r.width - 2; + self->black.height= r.height - 2; +} diff --git a/source/shared_lib/sources/graphics/freetype-gl/texture-font.c b/source/shared_lib/sources/graphics/freetype-gl/texture-font.c new file mode 100644 index 000000000..ef132e322 --- /dev/null +++ b/source/shared_lib/sources/graphics/freetype-gl/texture-font.c @@ -0,0 +1,422 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#include +#include FT_FREETYPE_H +// #include FT_ADVANCES_H +#include FT_LCD_FILTER_H +#include +#include +#include +#include +#include +#include "texture-font.h" +#include "texture-glyph.h" + +#undef __FTERRORS_H__ +#define FT_ERRORDEF( e, v, s ) { e, s }, +#define FT_ERROR_START_LIST { +#define FT_ERROR_END_LIST { 0, 0 } }; +const struct { + int code; + const char* message; +} FT_Errors[] = +#include FT_ERRORS_H + +#define max(a,b) (a)>(b)?(a):(b) +#define min(a,b) (a)<(b)?(a):(b) + + +/* ------------------------------------------------------------------------- */ +TextureFont * +texture_font_new( TextureAtlas *atlas, + const char *filename, + const float size ) +{ + TextureFont *self = (TextureFont *) malloc( sizeof(TextureFont) ); + if( !self ) + { + return NULL; + } + self->glyphs = vector_new( sizeof(TextureGlyph) ); + self->filename = strdup( filename ); + self->size = size; + self->gamma = 1.; + self->atlas = atlas; + self->height = 0; + self->ascender = 0; + self->descender = 0; + self->hinting = 1; + self->lcd_filter = 0; + self->lcd_weights[0] = 0; + self->lcd_weights[1] = 0; + self->lcd_weights[2] = 255; + self->lcd_weights[3] = 0; + self->lcd_weights[4] = 0; + + /* Get font metrics at high resolution */ + FT_Library library; + FT_Face face; + if( !texture_font_load_face( &library, self->filename, self->size*100, &face ) ) + { + return self; + } + + FT_Size_Metrics metrics = face->size->metrics; + self->ascender = (metrics.ascender >> 6) / 100.0; + self->descender = (metrics.descender >> 6) / 100.0; + self->height = (metrics.height >> 6) / 100.0; + self->linegap = self->height - self->ascender + self->descender; + + return self; +} + + + +/* ------------------------------------------------------------------------- */ +void +texture_font_delete( TextureFont *self ) +{ + assert( self ); + if( self->filename ) + { + free( self->filename ); + } + vector_delete( self->glyphs ); + free( self ); +} + + + +/* ------------------------------------------------------------------------- */ +void +texture_font_generate_kerning( TextureFont *self ) +{ + size_t i, j, k, count; + FT_Library library; + FT_Face face; + FT_UInt glyph_index, prev_index; + TextureGlyph *glyph, *prev_glyph; + FT_Vector kerning; + + + /* Load font */ + if( !texture_font_load_face( &library, self->filename, self->size, &face ) ) + { + return; + } + + /* For each glyph couple combination, check if kerning is necessary */ + for( i=0; iglyphs->size; ++i ) + { + + glyph = (TextureGlyph *) vector_get( self->glyphs, i ); + + /* Remove any old kerning information */ + if( glyph->kerning ) + { + free( glyph->kerning ); + glyph->kerning = 0; + glyph->kerning_count = 0; + } + + /* Count how many kerning pairs we need */ + count = 0; + glyph_index = FT_Get_Char_Index( face, glyph->charcode ); + for( j=0; jglyphs->size; ++j ) + { + prev_glyph = (TextureGlyph *) vector_get( self->glyphs, j ); + prev_index = FT_Get_Char_Index( face, prev_glyph->charcode ); + FT_Get_Kerning( face, prev_index, glyph_index, FT_KERNING_UNFITTED, &kerning ); + if( kerning.x != 0.0 ) + { + count++; + } + } + + /* No kerning at all */ + if( !count ) + { + continue; + } + + /* Store kerning pairs */ + glyph->kerning = (KerningPair *) malloc( count * sizeof(KerningPair) ); + glyph->kerning_count = count; + k = 0; + for( j=0; jglyphs->size; ++j ) + { + prev_glyph = (TextureGlyph *) vector_get( self->glyphs, j ); + prev_index = FT_Get_Char_Index( face, prev_glyph->charcode ); + FT_Get_Kerning( face, prev_index, glyph_index, FT_KERNING_UNFITTED, &kerning ); + if( kerning.x != 0.0 ) + { + glyph->kerning[k].charcode = prev_glyph->charcode; + // 64 * 64 because of 26.6 encoding AND the transform matrix used + // in texture_font_load_face (hres = 64) + glyph->kerning[k].kerning = kerning.x/ (float)(64.0f*64.0f); + ++k; + } + } + } + + FT_Done_Face( face ); + FT_Done_FreeType( library ); +} + + + +/* ------------------------------------------------------------------------- */ +size_t +texture_font_cache_glyphs( TextureFont *self, + const wchar_t * charcodes ) +{ + size_t i, x, y, width, height, depth, w, h; + FT_Library library; + FT_Error error; + FT_Face face; + FT_GlyphSlot slot; + FT_UInt glyph_index; + TextureGlyph *glyph; + Region region; + unsigned char c; + size_t missed = 0; + width = self->atlas->width; + height = self->atlas->height; + depth = self->atlas->depth; + + if( !texture_font_load_face( &library, self->filename, self->size, &face ) ) + { + return wcslen(charcodes); + } + + /* Load each glyph */ + for( i=0; ihinting ) + { + flags |= FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT; + } + else + { + flags |= FT_LOAD_FORCE_AUTOHINT; + } + + if( depth == 3 ) + { + FT_Library_SetLcdFilter( library, FT_LCD_FILTER_LIGHT ); + flags |= FT_LOAD_TARGET_LCD; + if( self->lcd_filter ) + { + FT_Library_SetLcdFilterWeights( library, self->lcd_weights ); + } + } + error = FT_Load_Glyph( face, glyph_index, flags ); + + if( error ) + { + fprintf(stderr, "FT_Error (line %d, code 0x%02x) : %s\n", + __LINE__, FT_Errors[error].code, FT_Errors[error].message); + FT_Done_FreeType( library ); + return wcslen(charcodes)-i; + } + slot = face->glyph; + + /* Gamma correction (sort of) */ + for( x=0; xbitmap.width; ++x ) + { + for( y=0; ybitmap.rows; ++y ) + { + c = *(unsigned char *)(slot->bitmap.buffer + + y*slot->bitmap.pitch + x ); + c = (unsigned char) ( pow(c/255.0, self->gamma) * 255); + *(unsigned char *)(slot->bitmap.buffer + + y*slot->bitmap.pitch + x ) = c; + } + } + + // We want each glyph to be separated by at least one black pixel + // (for example for shader used in demo-subpixel.c) + w = slot->bitmap.width/depth + 1; + h = slot->bitmap.rows + 1; + region = texture_atlas_get_region( self->atlas, w, h ); + if ( region.x < 0 ) + { + missed++; + continue; + } + w = w - 1; + h = h - 1; + x = region.x; + y = region.y; + texture_atlas_set_region( self->atlas, x, y, w, h, + slot->bitmap.buffer, slot->bitmap.pitch ); + + glyph = texture_glyph_new( ); + glyph->font = self; + glyph->charcode = charcodes[i]; + glyph->kerning = 0; + glyph->width = w; + glyph->height = h; + glyph->offset_x = slot->bitmap_left; + glyph->offset_y = slot->bitmap_top; + glyph->u0 = x/(float)width; + glyph->v0 = y/(float)height; + glyph->u1 = (x + glyph->width)/(float)width; + glyph->v1 = (y + glyph->height)/(float)height; + + /* Discard hinting to get advance */ + FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING); + slot = face->glyph; + glyph->advance_x = slot->advance.x/64.0; + glyph->advance_y = slot->advance.y/64.0; + + vector_push_back( self->glyphs, glyph ); + texture_glyph_delete( glyph ); + } + FT_Done_Face( face ); + FT_Done_FreeType( library ); + texture_atlas_upload( self->atlas ); + texture_font_generate_kerning( self ); + return missed; +} + + + +/* ------------------------------------------------------------------------- */ +TextureGlyph * +texture_font_get_glyph( TextureFont *self, + wchar_t charcode ) +{ + size_t i; + static wchar_t *buffer = 0; + TextureGlyph *glyph; + + assert( self ); + assert( self->filename ); + assert( self->atlas ); + + /* Check if charcode has been already loaded */ + for( i=0; iglyphs->size; ++i ) + { + glyph = (TextureGlyph *) vector_get( self->glyphs, i ); + if( glyph->charcode == charcode ) + { + return glyph; + } + } + + /* If not, load it */ + if( !buffer) + { + buffer = (wchar_t *) calloc( 2, sizeof(wchar_t) ); + } + buffer[0] = charcode; + + if( texture_font_cache_glyphs( self, buffer ) == 0 ) + { + return (TextureGlyph *) vector_back( self->glyphs ); + } + return NULL; +} + + + +/* ------------------------------------------------------------------------- */ +int +texture_font_load_face( FT_Library * library, + const char * filename, + const float size, + FT_Face * face ) +{ + size_t hres = 64; + FT_Error error; + FT_Matrix matrix = { (int)((1.0/hres) * 0x10000L), + (int)((0.0) * 0x10000L), + (int)((0.0) * 0x10000L), + (int)((1.0) * 0x10000L) }; + + /* Initialize library */ + error = FT_Init_FreeType( library ); + if( error ) + { + fprintf(stderr, "FT_Error (0x%02x) : %s\n", + FT_Errors[error].code, FT_Errors[error].message); + return 0; + } + + /* Load face */ + error = FT_New_Face( *library, filename, 0, face ); + if( error ) + { + fprintf(stderr, "FT_Error (line %d, code 0x%02x) : %s\n", + __LINE__, FT_Errors[error].code, FT_Errors[error].message); + FT_Done_FreeType( *library ); + return 0; + } + + /* Select charmap */ + error = FT_Select_Charmap( *face, FT_ENCODING_UNICODE ); + if( error ) + { + fprintf(stderr, "FT_Error (line %d, code 0x%02x) : %s\n", + __LINE__, FT_Errors[error].code, FT_Errors[error].message); + FT_Done_Face( *face ); + FT_Done_FreeType( *library ); + return 0; + } + + /* Set char size */ + error = FT_Set_Char_Size( *face, (int)(size*64), 0, 72*hres, 72 ); + + /* error = FT_Set_Char_Size( *face, size*64, 0, 72, 72 ); */ + if( error ) + { + fprintf(stderr, "FT_Error (line %d, code 0x%02x) : %s\n", + __LINE__, FT_Errors[error].code, FT_Errors[error].message); + FT_Done_Face( *face ); + FT_Done_FreeType( *library ); + return 0; + } + + /* Set transform matrix */ + FT_Set_Transform( *face, &matrix, NULL ); + + return 1; +} + diff --git a/source/shared_lib/sources/graphics/freetype-gl/texture-glyph.c b/source/shared_lib/sources/graphics/freetype-gl/texture-glyph.c new file mode 100644 index 000000000..c6dba7e33 --- /dev/null +++ b/source/shared_lib/sources/graphics/freetype-gl/texture-glyph.c @@ -0,0 +1,225 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#if defined(__APPLE__) + #include +#else + #include +#endif +#include +#include +#include "texture-font.h" +#include "texture-glyph.h" + + +/* ------------------------------------------------------------------------- */ +TextureGlyph * +texture_glyph_new( void ) +{ + TextureGlyph *self = (TextureGlyph *) malloc( sizeof(TextureGlyph) ); + if(! self ) + { + return NULL; + } + self->width = 0; + self->height = 0; + self->offset_x = 0; + self->offset_y = 0; + self->advance_x = 0.0; + self->advance_y = 0.0; + self->u0 = 0.0; + self->v0 = 0.0; + self->u1 = 0.0; + self->v1 = 0.0; + self->kerning_count = 0; + return self; +} + + + +/* ------------------------------------------------------------------------- */ +void +texture_glyph_delete( TextureGlyph *self ) +{ + assert( self ); + free( self ); +} + + + +/* ------------------------------------------------------------------------- */ +void +texture_glyph_render( TextureGlyph *self, + Markup *markup, + Pen *pen ) +{ + assert( self ); + + int x = pen->x + self->offset_x; + int y = pen->y + self->offset_y + markup->rise; + int w = self->width; + int h = self->height; + + float u0 = self->u0; + float v0 = self->v0; + float u1 = self->u1; + float v1 = self->v1; + + glBegin( GL_TRIANGLES ); + { + glTexCoord2f( u0, v0 ); glVertex2i( x, y ); + glTexCoord2f( u0, v1 ); glVertex2i( x, y-h ); + glTexCoord2f( u1, v1 ); glVertex2i( x+w, y-h ); + + glTexCoord2f( u0, v0 ); glVertex2i( x, y ); + glTexCoord2f( u1, v1 ); glVertex2i( x+w, y-h ); + glTexCoord2f( u1, v0 ); glVertex2i( x+w, y ); + } + glEnd(); + + pen->x += self->advance_x + markup->spacing; + pen->y += self->advance_y; +} + + + +/* ------------------------------------------------------------------------- */ +void +texture_glyph_add_to_vertex_buffer( const TextureGlyph *self, + VertexBuffer *buffer, + const Markup *markup, + Pen *pen, int kerning ) +{ + TextureFont *font = self->font; + float r = 1; + float g = 1; + float b = 1; + float a = 1; + int rise = 0; + int spacing = 0; + + if( markup ) + { + rise = markup->rise; + spacing = markup->spacing; + } + + pen->x += kerning; + + // Background + if( markup && markup->background_color.a > 0 ) + { + float u0 = font->atlas->black.x / (float) font->atlas->width; + float v0 = font->atlas->black.y / (float) font->atlas->height; + float u1 = u0 + font->atlas->black.width / (float) font->atlas->width; + float v1 = v0 + font->atlas->black.height / (float) font->atlas->height; + int x0 = pen->x - kerning; + int y0 = pen->y + font->descender; + int x1 = x0 + self->advance_x + markup->spacing + kerning; + int y1 = y0 + font->height - font->linegap; + r = markup->background_color.r; + g = markup->background_color.g; + b = markup->background_color.b; + a = markup->background_color.a; + GLuint index = buffer->vertices->size; + GLuint indices[] = {index, index+1, index+2, + index, index+2, index+3}; + TextureGlyphVertex vertices[] = { { x0,y0,0, u0,v0, r,g,b,a }, + { x0,y1,0, u0,v1, r,g,b,a }, + { x1,y1,0, u1,v1, r,g,b,a }, + { x1,y0,0, u1,v0, r,g,b,a } }; + vertex_buffer_push_back_indices( buffer, indices, 6 ); + vertex_buffer_push_back_vertices( buffer, vertices, 4 ); + } + + // Underline + + // Overline + + // Outline + + // Strikethrough + + // Actual glyph + if( markup ) + { + r = markup->foreground_color.r; + g = markup->foreground_color.g; + b = markup->foreground_color.b; + a = markup->foreground_color.a; + } + int x0 = (int)( pen->x + self->offset_x ); + int y0 = (int)( pen->y + self->offset_y + rise ); + int x1 = (int)( x0 + self->width ); + int y1 = (int)( y0 - self->height ); + float u0 = self->u0; + float v0 = self->v0; + float u1 = self->u1; + float v1 = self->v1; + GLuint index = buffer->vertices->size; + GLuint indices[] = {index, index+1, index+2, + index, index+2, index+3}; + TextureGlyphVertex vertices[] = { { x0,y0,0, u0,v0, r,g,b,a }, + { x0,y1,0, u0,v1, r,g,b,a }, + { x1,y1,0, u1,v1, r,g,b,a }, + { x1,y0,0, u1,v0, r,g,b,a } }; + vertex_buffer_push_back_indices( buffer, indices, 6 ); + vertex_buffer_push_back_vertices( buffer, vertices, 4 ); + + pen->x += self->advance_x + spacing; + pen->y += self->advance_y; +} + + + +/* ------------------------------------------------------------------------- */ +float +texture_glyph_get_kerning( TextureGlyph *self, + wchar_t charcode ) +{ + size_t i; + + assert( self ); + if( !self->kerning ) + { + return 0; + } + + for( i=0; ikerning_count; ++i ) + { + if( self->kerning[i].charcode == charcode ) + { + return self->kerning[i].kerning; + } + } + return 0; +} diff --git a/source/shared_lib/sources/graphics/freetype-gl/vector.c b/source/shared_lib/sources/graphics/freetype-gl/vector.c new file mode 100644 index 000000000..204d44169 --- /dev/null +++ b/source/shared_lib/sources/graphics/freetype-gl/vector.c @@ -0,0 +1,362 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#include +#include +#include +#include +#include "vector.h" + + + +/* ------------------------------------------------------------------------- */ +Vector * +vector_new( size_t item_size ) +{ + assert( item_size ); + + Vector *self = (Vector *) malloc( sizeof(Vector) ); + if( !self ) + { + return NULL; + } + self->item_size = item_size; + self->size = 0; + self->capacity = 1; + self->items = malloc( self->item_size * self->capacity ); + return self; +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_delete( Vector *self ) +{ + assert( self ); + free( self->items ); + free( self ); +} + + + +/* ------------------------------------------------------------------------- */ +const void * +vector_get( const Vector *self, + size_t index ) +{ + assert( self ); + assert( self->size ); + assert( index < self->size ); + return self->items + index * self->item_size; +} + + + +/* ------------------------------------------------------------------------- */ +const void * +vector_front( const Vector *self ) +{ + assert( self ); + assert( self->size ); + return vector_get( self, 0 ); +} + + + +/* ------------------------------------------------------------------------- */ +const void * +vector_back( const Vector *self ) +{ + assert( self ); + assert( self->size ); + return vector_get( self, self->size-1 ); +} + + + +/* ------------------------------------------------------------------------- */ +int +vector_contains( const Vector *self, + const void *item, + int (*cmp)(const void *, const void *) ) +{ + size_t i; + assert( self ); + for( i=0; isize; ++i ) + { + if( (*cmp)(item, vector_get(self,i) ) == 0 ) + { + return 1; + } + } + return 0; +} + + + +/* ------------------------------------------------------------------------- */ +int +vector_empty( const Vector *self ) +{ + assert( self ); + return self->size == 0; +} + + + +/* ------------------------------------------------------------------------- */ +size_t +vector_size( const Vector *self ) +{ + assert( self ); + return self->size; +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_reserve( Vector *self, + const size_t size ) +{ + assert( self ); + if( self->capacity < size); + { + self->items = realloc( self->items, size * self->item_size ); + self->capacity = size; + } +} + + + +/* ------------------------------------------------------------------------- */ +size_t +vector_capacity( const Vector *self ) +{ + assert( self ); + return self->capacity; +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_shrink( Vector *self ) +{ + assert( self ); + if( self->capacity > self->size ) + { + self->items = realloc( self->items, self->size * self->item_size ); + } + self->capacity = self->size; +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_clear( Vector *self ) +{ + assert( self ); + self->size = 0; +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_set( Vector *self, + const size_t index, + const void *item ) +{ + assert( self ); + assert( self->size ); + assert( index < self->size ); + memcpy( self->items + index * self->item_size, + item, self->item_size ); +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_insert( Vector *self, + const size_t index, + const void *item ) +{ + assert( self ); + assert( index <= self->size); + + if( self->capacity <= self->size ) + { + vector_reserve(self, 2 * self->capacity ); + } + if( index < self->size ) + { + memmove( self->items + (index + 1) * self->item_size, + self->items + (index + 0) * self->item_size, + (self->size - index) * self->item_size); + } + self->size++; + vector_set( self, index, item ); +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_erase_range( Vector *self, + const size_t first, + const size_t last ) +{ + assert( self ); + assert( first < self->size ); + assert( last < self->size+1 ); + assert( first < last ); + memmove( self->items + first * self->item_size, + self->items + last * self->item_size, + (self->size - last) * self->item_size); + self->size -= (last-first); +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_erase( Vector *self, + const size_t index ) +{ + assert( self ); + assert( index < self->size ); + + vector_erase_range( self, index, index+1 ); +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_push_back( Vector *self, + const void *item ) +{ + vector_insert( self, self->size, item ); +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_pop_back( Vector *self ) +{ + assert( self ); + assert( self->size ); + self->size--; +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_resize( Vector *self, + const size_t size ) +{ + assert( self ); + if( size > self->capacity) + { + vector_reserve( self, size ); + self->size = self->capacity; + } + else + { + self->size = size; + } +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_push_back_data( Vector *self, + const void * data, + const size_t count ) +{ + assert( self ); + assert( data ); + assert( count ); + + if( self->capacity < (self->size+count) ) + { + vector_reserve(self, self->size+count); + } + memmove( self->items + self->size * self->item_size, data, + count*self->item_size ); + self->size += count; +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_insert_data( Vector *self, + const size_t index, + const void * data, + const size_t count ) +{ + assert( self ); + assert( index < self->size ); + assert( data ); + assert( count ); + + if( self->capacity < (self->size+count) ) + { + vector_reserve(self, self->size+count); + } + memmove( self->items + (index + count ) * self->item_size, + self->items + (index ) * self->item_size, + count*self->item_size ); + memmove( self->items + index * self->item_size, data, + count*self->item_size ); + self->size += count; +} + + + +/* ------------------------------------------------------------------------- */ +void +vector_sort( Vector *self, + int (*cmp)(const void *, const void *) ) +{ + assert( self ); + assert( self->size ); + qsort(self->items, self->size, self->item_size, cmp); +} diff --git a/source/shared_lib/sources/graphics/freetype-gl/vertex-buffer.c b/source/shared_lib/sources/graphics/freetype-gl/vertex-buffer.c new file mode 100644 index 000000000..320559231 --- /dev/null +++ b/source/shared_lib/sources/graphics/freetype-gl/vertex-buffer.c @@ -0,0 +1,722 @@ +/* ========================================================================= + * Freetype GL - A C OpenGL Freetype engine + * Platform: Any + * WWW: http://code.google.com/p/freetype-gl/ + * ------------------------------------------------------------------------- + * Copyright 2011 Nicolas P. Rougier. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Nicolas P. Rougier. + * ========================================================================= */ +#include +#include +#include +#include +#include "vertex-buffer.h" + + + +// ---------------------------------------------------------------------------- +VertexBuffer * +vertex_buffer_new( const char *format ) +{ + size_t i, index = 0, stride = 0; + const char *start = 0, *end = 0; + GLvoid *pointer = 0; + + VertexBuffer *self = (VertexBuffer *) malloc (sizeof(VertexBuffer)); + if( !self ) + { + return NULL; + } + + self->format = strdup( format ); + + for( i=0; iattributes[i] = 0; + } + + start = format; + do + { + end = (char *) (strchr(start+1, ':')); + char *desc = 0; + if (end == NULL) + { + desc = strdup(start); + } + else + { + desc = strndup(start, end-start); + } + VertexAttribute *attribute = vertex_attribute_parse( desc ); + start = end+1; + free(desc); + attribute->pointer = pointer; + stride += attribute->size*GL_TYPE_SIZE( attribute->type ); + pointer+= attribute->size*GL_TYPE_SIZE( attribute->type ); + self->attributes[index] = attribute; + index++; + } while ( end && (index < MAX_VERTEX_ATTRIBUTE) ); + + for( i=0; iattributes[i]->stride = stride; + } + + self->vertices = vector_new( stride ); + self->vertices_id = 0; + self->indices = vector_new( sizeof(GLuint) ); + self->indices_id = 0; + self->dirty = 1; + return self; +} + + + +// ---------------------------------------------------------------------------- +VertexBuffer * +vertex_buffer_new_from_data( char *format, + size_t vcount, + void *vertices, + size_t icount, + GLuint *indices ) +{ + VertexBuffer *self = vertex_buffer_new( format ); + + vector_resize( self->vertices, vcount ); + assert( self->vertices->size == vcount); + memcpy( self->vertices->items, vertices, vcount*self->vertices->item_size ); + vector_resize( self->indices, icount ); + assert( self->indices->size == icount); + memcpy( self->indices->items, indices, icount*self->indices->item_size ); + self->dirty = 1; + return self; +} + + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_delete( VertexBuffer *self ) +{ + assert( self ); + + vector_delete( self->vertices ); + self->vertices = 0; + if( self->vertices_id ) + { + glDeleteBuffers( 1, &self->vertices_id ); + } + self->vertices_id = 0; + + vector_delete( self->indices ); + self->indices = 0; + if( self->indices_id ) + { + glDeleteBuffers( 1, &self->vertices_id ); + } + self->indices_id = 0; + if( self->format ) + { + free( self->format ); + } + self->format = 0; + self->dirty = 0; + free( self ); +} + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_print( VertexBuffer * self ) +{ + assert(self); + + int i = 0; + + fprintf( stderr, "%ld vertices, %ld indices\n", + vector_size( self->vertices ), vector_size( self->indices ) ); + + while( self->attributes[i] ) + { + if( self->attributes[i]->target > 0 ) + { + switch(self->attributes[i]->target ) + { + case GL_VERTEX_ARRAY: + fprintf( stderr, " -> Position: "); + break; + case GL_NORMAL_ARRAY: + fprintf( stderr, " -> Normal: "); + break; + case GL_COLOR_ARRAY: + fprintf( stderr, " -> Color: "); + break; + case GL_TEXTURE_COORD_ARRAY: + fprintf( stderr, " -> Texture coord: "); + break; + case GL_FOG_COORD_ARRAY: + fprintf( stderr, " -> Fog coord: "); + break; + case GL_SECONDARY_COLOR_ARRAY: + fprintf( stderr, " -> Secondary color: "); + break; + case GL_EDGE_FLAG_ARRAY: + fprintf( stderr, " -> Edge flag: "); + break; + default: + fprintf( stderr, " -> Unknown: "); + break; + } + } + else + { + fprintf( stderr, " -> Generic attribute n°%d: ", + self->attributes[i]->index ); + } + fprintf(stderr, "%dx%s (+%ld)\n", + self->attributes[i]->size, + GL_TYPE_STRING( self->attributes[i]->type ), + (long) self->attributes[i]->pointer); + + i += 1; + } +} + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_upload ( VertexBuffer *self ) +{ + if( !self->vertices_id ) + { + glGenBuffers( 1, &self->vertices_id ); + } + if( !self->indices_id ) + { + glGenBuffers( 1, &self->indices_id ); + } + glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id ); + glBufferData( GL_ARRAY_BUFFER, + self->vertices->size*self->vertices->item_size, + self->vertices->items, GL_DYNAMIC_DRAW ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, + self->indices->size*self->indices->item_size, + self->indices->items, GL_DYNAMIC_DRAW ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_clear( VertexBuffer *self ) +{ + assert( self ); + + vector_clear( self->indices ); + vector_clear( self->vertices ); + self->dirty = 1; +} + + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_render ( VertexBuffer *self, + GLenum mode, + const char *what ) +{ + assert( self ); + + if( !self->vertices->size ) + { + return; + } + + if( self->dirty ) + { + vertex_buffer_upload( self ); + self->dirty = 0; + } + + glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); + glBindBuffer( GL_ARRAY_BUFFER, self->vertices_id ); + + size_t i; + for( i=0; iattributes[i]; + if ( attribute == 0 ) + { + break; + } + else + { + if (attribute->ctarget == 'g') + { + (*(attribute->enable))( attribute ); + } + else if ( strchr(what, attribute->ctarget) ) + { + (*(attribute->enable))( attribute ); + } + } + } + + if( self->indices->size ) + { + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, self->indices_id ); + glDrawElements( mode, self->indices->size, GL_UNSIGNED_INT, 0 ); + } + else + { + glDrawArrays( mode, 0, self->vertices->size ); + } + + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); + glPopClientAttrib( ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_push_back_index ( VertexBuffer *self, + GLuint index ) +{ + assert( self ); + + self->dirty = 1; + vector_push_back( self->indices, &index ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_push_back_vertex ( VertexBuffer *self, + void *vertex ) +{ + assert( self ); + + self->dirty = 1; + vector_push_back( self->vertices, vertex ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_push_back_indices ( VertexBuffer *self, + GLuint *indices, + size_t count ) +{ + assert( self ); + + self->dirty = 1; + vector_push_back_data( self->indices, indices, count ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_push_back_vertices ( VertexBuffer *self, + void *vertices, + size_t count ) +{ + assert( self ); + + self->dirty = 1; + vector_push_back_data( self->vertices, vertices, count ); + +} + + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_insert_indices ( VertexBuffer *self, + size_t index, + GLuint *indices, + size_t count ) +{ + assert( self ); + + self->dirty = 1; + vector_insert_data( self->indices, index, indices, count ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_buffer_insert_vertices ( VertexBuffer *self, + size_t index, + void *vertices, + size_t count ) +{ + size_t i; + + assert( self ); + assert( self->vertices ); + assert( index < self->vertices->size+1 ); + + self->dirty = 1; + for( i=0; iindices->size-index; ++i ) + { + if( *(GLuint *)(vector_get( self->indices, i )) > index ) + { + *(GLuint *)(vector_get( self->indices, i )) += index; + } + } + vector_insert_data( self->vertices, index, vertices, count ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_attribute_position_enable( VertexAttribute *attr ) +{ + glEnableClientState( attr->target ); + glVertexPointer( attr->size, attr->type, attr->stride, attr->pointer ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_attribute_normal_enable( VertexAttribute *attr ) +{ + glEnableClientState( attr->target ); + glNormalPointer( attr->type, attr->stride, attr->pointer ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_attribute_color_enable( VertexAttribute *attr ) +{ + glEnableClientState( attr->target ); + glColorPointer( attr->size, attr->type, attr->stride, attr->pointer ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_attribute_tex_coord_enable( VertexAttribute *attr ) +{ + glEnableClientState( attr->target ); + glTexCoordPointer( attr->size, attr->type, attr->stride, attr->pointer ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_attribute_fog_coord_enable( VertexAttribute *attr ) +{ + glEnableClientState( attr->target ); + glFogCoordPointer( attr->type, attr->stride, attr->pointer ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_attribute_edge_flag_enable( VertexAttribute *attr ) +{ + glEnableClientState( attr->target ); + glEdgeFlagPointer( attr->stride, attr->pointer ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_attribute_secondary_color_enable( VertexAttribute *attr ) +{ + glEnableClientState( attr->target ); + glSecondaryColorPointer( attr->size, attr->type, attr->stride, attr->pointer ); +} + + + +// ---------------------------------------------------------------------------- +void +vertex_attribute_generic_enable( VertexAttribute *attr ) +{ + glEnableVertexAttribArray( attr->index ); + glVertexAttribPointer( attr->index, attr->size, attr->type, + attr->normalized, attr->stride, attr->pointer ); +} + + + +// ---------------------------------------------------------------------------- +VertexAttribute * +vertex_attribute_parse( char *format ) +{ + // Generic attribute + char *p = strpbrk ( format, "0123456789" ); + if (p == format) + { + // Normalized + p = strpbrk ( format, "n" ); + if ( p != NULL ) + { + int size, index; + char ctype; + sscanf( format, "%dgn%d%c", &index, &size, &ctype ); + GLenum type = GL_TYPE( ctype ); + return vertex_attribute_new( 0, index, size, type, GL_TRUE, 0, 0 ); + } + else + { + int size, index; + char ctype; + sscanf( format, "%dg%d%c", &index, &size, &ctype ); + GLenum type = GL_TYPE( ctype ); + return vertex_attribute_new( 0, index, size, type, GL_FALSE, 0, 0 ); + } + } + + // Known attribute + p = strpbrk ( format, "vcntfse" ); + if ( p != 0 ) + { + int size; + char ctarget, ctype; + sscanf( format, "%c%d%c", &ctarget, &size, &ctype ); + GLenum type = GL_TYPE( ctype ); + GLenum target = GL_VERTEX_ATTRIBUTE_TARGET( ctarget ); + return vertex_attribute_new( target, 0, size, type, GL_FALSE, 0, 0 ); + } + + fprintf(stderr, "Vertex attribute format not understood\n"); + return 0; +} + + + +// ---------------------------------------------------------------------------- +VertexAttribute * +vertex_attribute_new( GLenum target, + GLuint index, + GLint size, + GLenum type, + GLboolean normalized, + GLsizei stride, + GLvoid *pointer ) +{ + VertexAttribute *attribute = (VertexAttribute *) malloc (sizeof(VertexAttribute)); + assert( size > 0 ); + + // Generic attribute + if (target == 0) + { + attribute->ctarget = 'g'; + assert( (size < 4) ); + assert( (type == GL_BYTE) || (type == GL_UNSIGNED_BYTE) || + (type == GL_SHORT) || (type == GL_UNSIGNED_SHORT) || + (type == GL_INT) || (type == GL_UNSIGNED_INT) || + (type == GL_FLOAT) || (type == GL_DOUBLE) ); + attribute->enable = + (void(*)(void *)) vertex_attribute_generic_enable; + } + else + { + // Standard attribute + switch( target ) + { + case GL_VERTEX_ARRAY: + attribute->ctarget = 'v'; + assert( size > 1 ); + attribute->enable = + (void(*)(void *)) vertex_attribute_position_enable; + break; + + case GL_NORMAL_ARRAY: + attribute->ctarget = 'n'; + assert (size == 3); + assert( (type == GL_BYTE) || (type == GL_SHORT) || + (type == GL_INT) || (type == GL_FLOAT) || + (type == GL_DOUBLE) ); + attribute->enable = + (void(*)(void *)) vertex_attribute_normal_enable; + break; + + case GL_COLOR_ARRAY: + attribute->ctarget = 'c'; + assert( (size == 3) || (size == 4) ); + assert( (type == GL_BYTE) || (type == GL_UNSIGNED_BYTE) || + (type == GL_SHORT) || (type == GL_UNSIGNED_SHORT) || + (type == GL_INT) || (type == GL_UNSIGNED_INT) || + (type == GL_FLOAT) || (type == GL_DOUBLE) ); + attribute->enable = + (void(*)(void *)) vertex_attribute_color_enable; + break; + + case GL_TEXTURE_COORD_ARRAY: + attribute->ctarget = 't'; + assert( (type == GL_SHORT) || (type == GL_INT) || + (type == GL_FLOAT) || (type == GL_DOUBLE) ); + attribute->enable = + (void(*)(void *)) vertex_attribute_tex_coord_enable; + break; + + case GL_FOG_COORD_ARRAY: + attribute->ctarget = 'f'; + assert( size == 2 ); + assert( (type == GL_FLOAT) || (type == GL_DOUBLE) ); + attribute->enable = + (void(*)(void *)) vertex_attribute_fog_coord_enable; + break; + + case GL_EDGE_FLAG_ARRAY: + attribute->ctarget = 'e'; + assert( size == 1 ); + assert( type == GL_BOOL ); + attribute->enable = + (void(*)(void *)) vertex_attribute_edge_flag_enable; + break; + + case GL_SECONDARY_COLOR_ARRAY: + attribute->ctarget = 's'; + assert( size == 3 ); + assert( (type == GL_BYTE) || (type == GL_UNSIGNED_BYTE) || + (type == GL_SHORT) || (type == GL_UNSIGNED_SHORT) || + (type == GL_INT) || (type == GL_UNSIGNED_INT) || + (type == GL_FLOAT) || (type == GL_DOUBLE) ); + attribute->enable = + (void(*)(void *)) vertex_attribute_secondary_color_enable; + break; + + default: + fprintf(stderr, "Vertex attribute format not understood\n"); + attribute->enable = 0; + break; + } + } + + attribute->target = target; + attribute->index = index; + attribute->size = size; + attribute->type = type; + attribute->normalized = normalized; + attribute->stride = stride; + attribute->pointer = pointer; + + return attribute; +} + + + +// ---------------------------------------------------------------------------- +GLenum +GL_TYPE( char ctype ) +{ + switch( ctype ) + { + case 'b': return GL_BYTE; + case 'B': return GL_UNSIGNED_BYTE; + case 's': return GL_SHORT; + case 'S': return GL_UNSIGNED_SHORT; + case 'i': return GL_INT; + case 'I': return GL_UNSIGNED_INT; + case 'f': return GL_FLOAT; + case 'd': return GL_DOUBLE; + default: return 0; + } +} + + + +// ---------------------------------------------------------------------------- +GLenum +GL_VERTEX_ATTRIBUTE_TARGET( char ctarget ) +{ + switch( ctarget ) + { + case 'v': return GL_VERTEX_ARRAY; + case 'n': return GL_NORMAL_ARRAY; + case 'c': return GL_COLOR_ARRAY; + case 't': return GL_TEXTURE_COORD_ARRAY; + case 'f': return GL_FOG_COORD_ARRAY; + case 's': return GL_SECONDARY_COLOR_ARRAY; + case 'e': return GL_EDGE_FLAG_ARRAY; + default: return 0; + } +} + + + +// ---------------------------------------------------------------------------- +GLuint +GL_TYPE_SIZE( GLenum gtype ) +{ + switch( gtype ) + { + case GL_BOOL: return sizeof(GLboolean); + case GL_BYTE: return sizeof(GLbyte); + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_SHORT: return sizeof(GLshort); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_INT: return sizeof(GLint); + case GL_UNSIGNED_INT: return sizeof(GLuint); + case GL_FLOAT: return sizeof(GLfloat); + case GL_DOUBLE: return sizeof(GLdouble); + default: return 0; + } +} + + + +char * +GL_TYPE_STRING( GLenum gtype ) +{ + switch( gtype ) + { + case GL_BOOL: return "GL_BOOL"; + case GL_BYTE: return "GL_BYTE"; + case GL_UNSIGNED_BYTE: return "GL_UNSIGNED_BYTE"; + case GL_SHORT: return "GL_SHORT"; + case GL_UNSIGNED_SHORT: return "GL_UNSIGNED_SHORT"; + case GL_INT: return "GL_INT"; + case GL_UNSIGNED_INT: return "GL_UNSIGNED_INT"; + case GL_FLOAT: return "GL_FLOAT"; + case GL_DOUBLE: return "GL_DOUBLE"; + default: return "GL_VOID"; + } +} diff --git a/source/shared_lib/sources/graphics/gl/font_text_freetypegl.cpp b/source/shared_lib/sources/graphics/gl/font_text_freetypegl.cpp new file mode 100644 index 000000000..7d6d34c6d --- /dev/null +++ b/source/shared_lib/sources/graphics/gl/font_text_freetypegl.cpp @@ -0,0 +1,336 @@ +// ============================================================== +// This file is part of the MegaGlest Shared Library (www.megaglest.org) +// +// Copyright (C) 2011 Mark Vejvoda and others +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 3 of the +// License, or (at your option) any later version +// ============================================================== + +#ifdef USE_FREETYPEGL + +#include "font_text_freetypegl.h" +#include "vector.h" + +//#include "opengl.h" +#include +#include + +#ifdef HAVE_FONTCONFIG +#include +#endif + +#include "util.h" + +using namespace std; +using namespace Shared::Util; + +namespace Shared { namespace Graphics { namespace Gl { + + +//string TextFreetypeGL::langHeightText = "yW"; +//int TextFreetypeGL::faceResolution = 72; + +//==================================================================== +TextFreetypeGL::TextFreetypeGL(FontTextHandlerType type) : Text(type) { + buffer=NULL; + atlas=NULL; + font=NULL; + manager=NULL; + + init("", 24); +} + +TextFreetypeGL::~TextFreetypeGL() { + cleanupFont(); +} + +void TextFreetypeGL::cleanupFont() { + if(font) { + texture_font_delete(font); + font = NULL; + } +} + +void TextFreetypeGL::init(string fontName, int fontSize) { + cleanupFont(); + this->fontName = fontName; + this->fontFile = findFont(this->fontName.c_str()); + this->fontFaceSize = fontSize; + + const wchar_t *cache = L" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + + this->manager = font_manager_new( 512, 512, 1 ); + this->atlas = texture_atlas_new( 512, 512, 1 ); + this->buffer = vertex_buffer_new( "v3f:t2f:c4f" ); + + //font = texture_font_new( atlas, "Verdana", minsize ); + this->font = texture_font_new( atlas, fontFile, fontFaceSize ); + //font = texture_font_new( atlas, font_manager_match_description( 0, "Verdana", minsize, bold, italic ), minsize ); + + int missed = texture_font_cache_glyphs( font, cache ); + + free((void*)this->fontFile); + this->fontFile = NULL; +} + +void TextFreetypeGL::SetFaceSize(int value) { + this->fontFaceSize = value; + init(this->fontName,this->fontFaceSize); +} + +int TextFreetypeGL::GetFaceSize() { + return this->fontFaceSize; +} + +void TextFreetypeGL::Render(const char* str, const int len) { + if(str == NULL) { + return; + } + + Pen pen ; + pen.x = 0; pen.y = 0; + + vertex_buffer_clear( this->buffer ); + + float currentColor[4]; + glGetFloatv(GL_CURRENT_COLOR,currentColor); + + Markup markup = { 0, this->fontFaceSize, 0, 0, 0.0, 0.0, + {currentColor[0],currentColor[1],currentColor[2],currentColor[3]}, {0,0,0,0}, + 0, {0,0,0,1}, 0, {0,0,0,1}, + 0, {0,0,0,1}, 0, {0,0,0,1}, 0 }; + + // Add glyph one by one to the vertex buffer + // Expand totalBox by each glyph in string + + // for multibyte - we can't rely on sizeof(T) == character + FreetypeGLUnicodeStringItr ustr((const unsigned char *)str); + + for(int i = 0; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { + unsigned int prevChar = (i > 0 ? *ustr-1 : 0); + unsigned int thisChar = *ustr++; + unsigned int nextChar = *ustr; + + // Get glyph (build it if needed + TextureGlyph *glyph = texture_font_get_glyph( this->font, thisChar ); + + // Take kerning into account if necessary + int kx = texture_glyph_get_kerning( glyph, prevChar ); + + // Add glyph to the vertex buffer + texture_glyph_add_to_vertex_buffer( glyph, this->buffer, &markup, &pen, kx ); + } + + //glBindTexture( GL_TEXTURE_2D, manager->atlas->texid ); + glBindTexture( GL_TEXTURE_2D, this->atlas->texid ); + + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glEnable( GL_TEXTURE_2D ); + vertex_buffer_render( this->buffer, GL_TRIANGLES, "vtc" ); +} + +void TextFreetypeGL::Render(const wchar_t* str, const int len) { + if(str == NULL) { + return; + } + + const wchar_t *text = str; + Pen pen ; + pen.x = 0; pen.y = 0; + + vertex_buffer_clear( this->buffer ); + + float currentColor[4]; + glGetFloatv(GL_CURRENT_COLOR,currentColor); + + Markup markup = { 0, this->fontFaceSize, 0, 0, 0.0, 0.0, + {currentColor[0],currentColor[1],currentColor[2],currentColor[3]}, {0,0,0,0}, + 0, {0,0,0,1}, 0, {0,0,0,1}, + 0, {0,0,0,1}, 0, {0,0,0,1}, 0 }; + + // Add glyph one by one to the vertex buffer + for( size_t i = 0; i < wcslen(text); ++i ) { + // Get glyph (build it if needed + TextureGlyph *glyph = texture_font_get_glyph( this->font, text[i] ); + + // Take kerning into account if necessary + int kx = texture_glyph_get_kerning( glyph, text[i-1] ); + + // Add glyph to the vertex buffer + texture_glyph_add_to_vertex_buffer( glyph, this->buffer, &markup, &pen, kx ); + } + + //glBindTexture( GL_TEXTURE_2D, manager->atlas->texid ); + glBindTexture( GL_TEXTURE_2D, this->atlas->texid ); + + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glEnable( GL_TEXTURE_2D ); + vertex_buffer_render( this->buffer, GL_TRIANGLES, "vtc" ); +} + +float TextFreetypeGL::Advance(const wchar_t* str, const int len) { + float result = 0; + + for(unsigned int i = 0; i < wcslen(str); ++i) { + TextureGlyph *glyph = texture_font_get_glyph( font, str[i] ); + result += glyph->width; + } + return result; +} + +float TextFreetypeGL::Advance(const char* str, const int len) { + float result = 0; + + for(unsigned int i = 0; i < strlen(str); ++i) { + TextureGlyph *glyph = texture_font_get_glyph( font, str[i] ); + result += glyph->width; + } + return result; +} + +float TextFreetypeGL::LineHeight(const char* str, const int len) { + float result = 0; + if(strlen(str) > 0) { + TextureGlyph *glyph = texture_font_get_glyph( font, str[0] ); + result = glyph->height; + } + return result; +} + +float TextFreetypeGL::LineHeight(const wchar_t* str, const int len) { + float result = 0; + if(wcslen(str) > 0) { + TextureGlyph *glyph = texture_font_get_glyph( font, str[0] ); + result = glyph->height; + } + return result; +} + +const char* TextFreetypeGL::findFont(const char *firstFontToTry) { + const char* font = NULL; + const char* path = NULL; + + #define CHECK_FONT_PATH(filename) \ + { \ + path = filename; \ + if( !font && path && fileExists(path) == true ) \ + font = strdup(path); \ + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Found font file [%s]\n",font); \ + } + + string tryFont = ""; + if(firstFontToTry) { + tryFont = firstFontToTry; + #ifdef WIN32 + replaceAll(tryFont, "/", "\\"); + #endif + + CHECK_FONT_PATH(tryFont.c_str()) + } + + // Get user-specified font path + if(getenv("MEGAGLEST_FONT") != NULL) { + tryFont = getenv("MEGAGLEST_FONT"); + #ifdef WIN32 + replaceAll(tryFont, "/", "\\"); + #endif + + CHECK_FONT_PATH(tryFont.c_str()) + } + + string data_path = Text::DEFAULT_FONT_PATH; + string defaultFont = data_path + "data/core/fonts/LinBiolinum_RB.ttf";//LinBiolinum_Re-0.6.4.ttf + tryFont = defaultFont; + #ifdef WIN32 + replaceAll(tryFont, "/", "\\"); + #endif + CHECK_FONT_PATH(tryFont.c_str()) + +#ifdef FONT_PATH + // Get distro-specified font path + CHECK_FONT_PATH(FONT_PATH) +#endif + +#ifdef HAVE_FONTCONFIG + // Get default font via fontconfig + if( !font && FcInit() ) { + FcResult result; + FcFontSet *fs; + FcPattern* pat; + FcPattern *match; + + /* + TRANSLATORS: If using the FTGL backend, this should be the font + name of a font that contains all the Unicode characters in use in + your translation. + */ + pat = FcNameParse((FcChar8 *)"Gothic Uralic"); + FcConfigSubstitute(0, pat, FcMatchPattern); + + FcPatternDel(pat, FC_WEIGHT); + FcPatternAddInteger(pat, FC_WEIGHT, FC_WEIGHT_BOLD); + + FcDefaultSubstitute(pat); + fs = FcFontSetCreate(); + match = FcFontMatch(0, pat, &result); + + if (match) FcFontSetAdd(fs, match); + if (pat) FcPatternDestroy(pat); + if(fs) { + FcChar8* file; + if( FcPatternGetString (fs->fonts[0], FC_FILE, 0, &file) == FcResultMatch ) { + CHECK_FONT_PATH((const char*)file) + } + FcFontSetDestroy(fs); + } + FcFini(); + } +#endif + + CHECK_FONT_PATH("/usr/share/fonts/truetype/uralic/gothub__.ttf") + + // Check a couple of common paths for Gothic Uralic/bold as a last resort + // Debian + /* + TRANSLATORS: If using the FTGL backend, this should be the path of a bold + font that contains all the Unicode characters in use in your translation. + If the font is available in Debian it should be the Debian path. + */ + CHECK_FONT_PATH("/usr/share/fonts/truetype/uralic/gothub__.ttf") + /* + TRANSLATORS: If using the FTGL backend, this should be the path of a + font that contains all the Unicode characters in use in your translation. + If the font is available in Debian it should be the Debian path. + */ + CHECK_FONT_PATH("/usr/share/fonts/truetype/uralic/gothu___.ttf") + // Mandrake + /* + TRANSLATORS: If using the FTGL backend, this should be the path of a bold + font that contains all the Unicode characters in use in your translation. + If the font is available in Mandrake it should be the Mandrake path. + */ + CHECK_FONT_PATH("/usr/share/fonts/TTF/uralic/GOTHUB__.TTF") + /* + TRANSLATORS: If using the FTGL backend, this should be the path of a + font that contains all the Unicode characters in use in your translation. + If the font is available in Mandrake it should be the Mandrake path. + */ + CHECK_FONT_PATH("/usr/share/fonts/TTF/uralic/GOTHU___.TTF") + + // Check the non-translated versions of the above + CHECK_FONT_PATH("/usr/share/fonts/truetype/uralic/gothub__.ttf") + CHECK_FONT_PATH("/usr/share/fonts/truetype/uralic/gothu___.ttf") + CHECK_FONT_PATH("/usr/share/fonts/TTF/uralic/GOTHUB__.TTF") + CHECK_FONT_PATH("/usr/share/fonts/TTF/uralic/GOTHU___.TTF") + + return font; +} + +}}}//end namespace + +#endif // USE_FTGL