- added freetype-gl rendered and set as default font renderer (see: http://code.google.com/p/freetype-gl/)

This commit is contained in:
Mark Vejvoda
2011-11-17 09:56:25 +00:00
parent d29293d3cf
commit 2251a7b2dc
21 changed files with 5660 additions and 2 deletions

View File

@@ -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

View File

@@ -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 <math.h>
#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

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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 <ft2build.h>
#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__ */

View File

@@ -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 <wchar.h>
#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__ */

View File

@@ -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__ */

View File

@@ -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 <Glut/glut.h>
#else
#include <GL/glut.h>
#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__ */

View File

@@ -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 <stdlib.h>
#include <wchar.h>
//#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 <typename T>
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 <typename T>
const unsigned char FreetypeGLUnicodeStringItr<T>::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 <typename T>
const unsigned long FreetypeGLUnicodeStringItr<T>::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 <typename T>
inline void FreetypeGLUnicodeStringItr<T>::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 <typename T>
const unsigned long FreetypeGLUnicodeStringItr<T>::highSurrogateStart = 0xD800;
template <typename T>
const unsigned long FreetypeGLUnicodeStringItr<T>::highSurrogateEnd = 0xDBFF;
template <typename T>
const unsigned long FreetypeGLUnicodeStringItr<T>::lowSurrogateStart = 0xDC00;
template <typename T>
const unsigned long FreetypeGLUnicodeStringItr<T>::lowSurrogateEnd = 0xDFFF;
template <typename T>
const unsigned long FreetypeGLUnicodeStringItr<T>::highSurrogateShift = 10;
template <typename T>
const unsigned long FreetypeGLUnicodeStringItr<T>::lowSurrogateBase = 0x0010000UL;
template <typename T>
inline void FreetypeGLUnicodeStringItr<T>::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

View File

@@ -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) {

View File

@@ -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 <math.h>
/*
* 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<gy) {
temp = gx;
gx = gy;
gy = temp;
}
a1 = 0.5*gy/gx;
if (a < a1) { // 0 <= a < a1
df = 0.5*(gx + gy) - sqrt(2.0*gx*gy*a);
} else if (a < (1.0-a1)) { // a1 <= a <= 1-a1
df = (0.5-a)*gx;
} else { // 1-a1 < a <= 1
df = -0.5*(gx + gy) + sqrt(2.0*gx*gy*(1.0-a));
}
}
return df;
}
double distaa3(double *img, double *gximg, double *gyimg, int w, int c, int xc, int yc, int xi, int yi)
{
double di, df, dx, dy, gx, gy, a;
int closest;
closest = c-xc-yc*w; // Index to the edge pixel pointed to from c
a = img[closest]; // Grayscale value at the edge pixel
gx = gximg[closest]; // X gradient component at the edge pixel
gy = gyimg[closest]; // Y gradient component at the edge pixel
if(a > 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<w*h; i++) {
distx[i] = 0; // At first, all pixels point to
disty[i] = 0; // themselves as the closest known.
if(img[i] <= 0.0)
{
dist[i]= 1000000.0; // Big value, means "not set yet"
}
else if (img[i]<1.0) {
dist[i] = edgedf(gx[i], gy[i], img[i]); // Gradient-assisted estimate
}
else {
dist[i]= 0.0; // Inside the object
}
}
/* Perform the transformation */
do
{
changed = 0;
/* Scan rows, except first row */
for(y=1; y<h; y++)
{
/* move index to leftmost pixel of current row */
i = y*w;
/* scan right, propagate distances from above & left */
/* Leftmost pixel is special, has no left neighbors */
olddist = dist[i];
if(olddist > 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<w-1; x++, i++)
{
olddist = dist[i];
if(olddist <= 0) continue; // No need to update further
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;
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;
}
}
/* Rightmost pixel of row is special, has no right neighbors */
olddist = dist[i];
if(olddist > 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<w; x++, i++)
{
/* scan right, propagate distance from left */
olddist = dist[i];
if(olddist <= 0) continue; // 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;
changed = 1;
}
}
}
}
while(changed); // Sweep until no more updates are made
/* The transformation is completed. */
}

View File

@@ -0,0 +1,222 @@
/* =========================================================================
* 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 <fontconfig/fontconfig.h>
#include <assert.h>
#include <stdio.h>
#include <wchar.h>
#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; i<self->fonts->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 );
}

View File

@@ -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 <Glut/glut.h>
#else
#include <GL/glut.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#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;
}

View File

@@ -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 <assert.h>
#include <stdlib.h>
#include <string.h>
#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 )
{
}

View File

@@ -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 <Glut/glut.h>
#else
#include <GL/glut.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#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; i<height; ++i )
{
memcpy( self->data+((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; i<self->nodes->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;
}

View File

@@ -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 <ft2build.h>
#include FT_FREETYPE_H
// #include FT_ADVANCES_H
#include FT_LCD_FILTER_H
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#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; i<self->glyphs->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; j<self->glyphs->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; j<self->glyphs->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; i<wcslen(charcodes); ++i )
{
glyph_index = FT_Get_Char_Index( face, charcodes[i] );
// WARNING: We use texture-atlas depth to guess if user wants
// LCD subpixel rendering
FT_Int32 flags = FT_LOAD_RENDER;
if( !self->hinting )
{
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; x<slot->bitmap.width; ++x )
{
for( y=0; y<slot->bitmap.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; i<self->glyphs->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;
}

View File

@@ -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 <Glut/glut.h>
#else
#include <GL/glut.h>
#endif
#include <assert.h>
#include <stdlib.h>
#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; i<self->kerning_count; ++i )
{
if( self->kerning[i].charcode == charcode )
{
return self->kerning[i].kerning;
}
}
return 0;
}

View File

@@ -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 <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#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; i<self->size; ++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);
}

View File

@@ -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 <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#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; i<MAX_VERTEX_ATTRIBUTE; ++i )
{
self->attributes[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; i<index; ++i )
{
self->attributes[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; i<MAX_VERTEX_ATTRIBUTE; ++i )
{
VertexAttribute *attribute = self->attributes[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; i<self->indices->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";
}
}

View File

@@ -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 <stdexcept>
#include <sys/stat.h>
#ifdef HAVE_FONTCONFIG
#include <fontconfig/fontconfig.h>
#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<unsigned char> 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