2013-04-22 22:42:11 +02:00
/* Copyright 2013 Jeremie Roy. All rights reserved.
* License : http : //www.opensource.org/licenses/BSD-2-Clause
*/
# include "font_manager.h"
# include "../cube_atlas.h"
# pragma warning( push )
# pragma warning( disable: 4146 )
# pragma warning( disable: 4700 )
# pragma warning( disable: 4100 )
# pragma warning( disable: 4701 )
# include "../../../3rdparty/freetype/freetype.h"
# pragma warning( pop )
# include "../../../3rdparty/edtaa3/edtaa3func.h"
# include "../../../3rdparty/edtaa3/edtaa3func.cpp"
# include <math.h>
2013-04-23 23:14:32 +02:00
# include <bx/bx.h>
2013-04-22 22:42:11 +02:00
# if BGFX_CONFIG_USE_TINYSTL
namespace tinystl
{
//struct bgfx_allocator
//{
//static void* static_allocate(size_t _bytes);
//static void static_deallocate(void* _ptr, size_t /*_bytes*/);
//};
} // namespace tinystl
//# define TINYSTL_ALLOCATOR tinystl::bgfx_allocator
# include <TINYSTL / unordered_map.h>
//# include <TINYSTL/unordered_set.h>
namespace stl = tinystl ;
# else
# include <unordered_map>
namespace std { namespace tr1 { } }
namespace stl {
using namespace std ;
using namespace std : : tr1 ;
}
# endif // BGFX_CONFIG_USE_TINYSTL
class FontManager : : TrueTypeFont
{
public :
TrueTypeFont ( ) ;
~ TrueTypeFont ( ) ;
/// Initialize from an external buffer
/// @remark The ownership of the buffer is external, and you must ensure it stays valid up to this object lifetime
/// @return true if the initialization succeed
2013-04-23 20:58:57 +02:00
bool init ( const uint8_t * _buffer , uint32_t _bufferSize , int32_t _fontIndex , uint32_t _pixelHeight ) ;
2013-04-22 22:42:11 +02:00
/// return the font descriptor of the current font
FontInfo getFontInfo ( ) ;
/// raster a glyph as 8bit alpha to a memory buffer
/// update the GlyphInfo according to the raster strategy
2013-04-23 20:58:57 +02:00
/// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char)
bool bakeGlyphAlpha ( CodePoint_t _codePoint , GlyphInfo & _outGlyphInfo , uint8_t * _outBuffer ) ;
2013-04-22 22:42:11 +02:00
/// raster a glyph as 32bit subpixel rgba to a memory buffer
/// update the GlyphInfo according to the raster strategy
2013-04-23 20:58:57 +02:00
/// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(uint32_t)
bool bakeGlyphSubpixel ( CodePoint_t _codePoint , GlyphInfo & _outGlyphInfo , uint8_t * _outBuffer ) ;
2013-04-22 22:42:11 +02:00
/// raster a glyph as 8bit signed distance to a memory buffer
/// update the GlyphInfo according to the raster strategy
2013-04-23 20:58:57 +02:00
/// @ remark buffer min size: glyphInfo.m_width * glyphInfo * height * sizeof(char)
bool bakeGlyphDistance ( CodePoint_t _codePoint , GlyphInfo & _outGlyphInfo , uint8_t * _outBuffer ) ;
2013-04-22 22:42:11 +02:00
private :
void * m_font ;
} ;
struct FTHolder
{
2013-04-23 20:58:57 +02:00
FT_Library m_library ;
FT_Face m_face ;
2013-04-22 22:42:11 +02:00
} ;
FontManager : : TrueTypeFont : : TrueTypeFont ( ) : m_font ( NULL )
{
}
FontManager : : TrueTypeFont : : ~ TrueTypeFont ( )
{
if ( m_font ! = NULL )
{
FTHolder * holder = ( FTHolder * ) m_font ;
2013-04-23 20:58:57 +02:00
FT_Done_Face ( holder - > m_face ) ;
FT_Done_FreeType ( holder - > m_library ) ;
2013-04-22 22:42:11 +02:00
delete m_font ;
m_font = NULL ;
}
}
2013-04-23 20:58:57 +02:00
bool FontManager : : TrueTypeFont : : init ( const uint8_t * _buffer , uint32_t _bufferSize , int32_t _fontIndex , uint32_t _pixelHeight )
2013-04-22 22:42:11 +02:00
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( ( _bufferSize > 256 & & _bufferSize < 100000000 ) , " TrueType buffer size is suspicious " ) ;
BX_CHECK ( ( _pixelHeight > 4 & & _pixelHeight < 128 ) , " TrueType buffer size is suspicious " ) ;
2013-04-22 22:42:11 +02:00
2013-04-23 23:14:32 +02:00
BX_CHECK ( m_font = = NULL , " TrueTypeFont already initialized " ) ;
2013-04-22 22:42:11 +02:00
FTHolder * holder = new FTHolder ( ) ;
// Initialize Freetype library
2013-04-23 20:58:57 +02:00
FT_Error error = FT_Init_FreeType ( & holder - > m_library ) ;
2013-04-22 22:42:11 +02:00
if ( error )
{
delete holder ;
return false ;
}
2013-04-23 20:58:57 +02:00
error = FT_New_Memory_Face ( holder - > m_library , _buffer , _bufferSize , _fontIndex , & holder - > m_face ) ;
2013-04-22 22:42:11 +02:00
if ( error = = FT_Err_Unknown_File_Format )
{
// the font file could be opened and read, but it appears
//that its font format is unsupported
2013-04-23 20:58:57 +02:00
FT_Done_FreeType ( holder - > m_library ) ;
2013-04-22 22:42:11 +02:00
delete holder ;
return false ;
}
else if ( error )
{
// another error code means that the font file could not
// be opened or read, or simply that it is broken...
2013-04-23 20:58:57 +02:00
FT_Done_FreeType ( holder - > m_library ) ;
2013-04-22 22:42:11 +02:00
delete holder ;
return false ;
}
// Select unicode charmap
2013-04-23 20:58:57 +02:00
error = FT_Select_Charmap ( holder - > m_face , FT_ENCODING_UNICODE ) ;
2013-04-22 22:42:11 +02:00
if ( error )
{
2013-04-23 20:58:57 +02:00
FT_Done_Face ( holder - > m_face ) ;
FT_Done_FreeType ( holder - > m_library ) ;
2013-04-22 22:42:11 +02:00
return false ;
}
//set size in pixels
2013-04-23 20:58:57 +02:00
error = FT_Set_Pixel_Sizes ( holder - > m_face , 0 , _pixelHeight ) ;
2013-04-22 22:42:11 +02:00
if ( error )
{
2013-04-23 20:58:57 +02:00
FT_Done_Face ( holder - > m_face ) ;
FT_Done_FreeType ( holder - > m_library ) ;
2013-04-22 22:42:11 +02:00
return false ;
}
m_font = holder ;
return true ;
}
FontInfo FontManager : : TrueTypeFont : : getFontInfo ( )
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( m_font ! = NULL , " TrueTypeFont not initialized " ) ;
2013-04-22 22:42:11 +02:00
FTHolder * holder = ( FTHolder * ) m_font ;
2013-04-23 23:14:32 +02:00
//todo manage unscalable font
BX_CHECK ( FT_IS_SCALABLE ( holder - > m_face ) , " Font is unscalable " ) ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
FT_Size_Metrics metrics = holder - > m_face - > size - > metrics ;
2013-04-22 22:42:11 +02:00
2013-04-23 23:14:32 +02:00
2013-04-22 22:42:11 +02:00
FontInfo outFontInfo ;
2013-04-23 20:58:57 +02:00
outFontInfo . m_scale = 1.0f ;
outFontInfo . m_ascender = metrics . ascender / 64.0f ;
outFontInfo . m_descender = metrics . descender / 64.0f ;
outFontInfo . m_lineGap = ( metrics . height - metrics . ascender + metrics . descender ) / 64.0f ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
outFontInfo . m_underline_position = FT_MulFix ( holder - > m_face - > underline_position , metrics . y_scale ) / 64.0f ;
outFontInfo . m_underline_thickness = FT_MulFix ( holder - > m_face - > underline_thickness , metrics . y_scale ) / 64.0f ;
2013-04-22 22:42:11 +02:00
return outFontInfo ;
}
2013-04-23 20:58:57 +02:00
bool FontManager : : TrueTypeFont : : bakeGlyphAlpha ( CodePoint_t _codePoint , GlyphInfo & _glyphInfo , uint8_t * _outBuffer )
2013-04-22 22:42:11 +02:00
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( m_font ! = NULL , " TrueTypeFont not initialized " ) ;
2013-04-22 22:42:11 +02:00
FTHolder * holder = ( FTHolder * ) m_font ;
2013-04-23 20:58:57 +02:00
_glyphInfo . m_glyphIndex = FT_Get_Char_Index ( holder - > m_face , _codePoint ) ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
FT_GlyphSlot slot = holder - > m_face - > glyph ;
FT_Error error = FT_Load_Glyph ( holder - > m_face , _glyphInfo . m_glyphIndex , FT_LOAD_DEFAULT ) ;
2013-04-22 22:42:11 +02:00
if ( error ) { return false ; }
FT_Glyph glyph ;
error = FT_Get_Glyph ( slot , & glyph ) ;
if ( error ) { return false ; }
error = FT_Glyph_To_Bitmap ( & glyph , FT_RENDER_MODE_NORMAL , 0 , 1 ) ;
if ( error ) { return false ; }
FT_BitmapGlyph bitmap = ( FT_BitmapGlyph ) glyph ;
2013-04-23 22:32:39 +02:00
int32_t x = bitmap - > left ;
int32_t y = - bitmap - > top ;
int32_t w = bitmap - > bitmap . width ;
int32_t h = bitmap - > bitmap . rows ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
_glyphInfo . m_offset_x = ( float ) x ;
_glyphInfo . m_offset_y = ( float ) y ;
_glyphInfo . m_width = ( float ) w ;
_glyphInfo . m_height = ( float ) h ;
_glyphInfo . m_advance_x = ( float ) slot - > advance . x / 64.0f ;
_glyphInfo . m_advance_y = ( float ) slot - > advance . y / 64.0f ;
2013-04-22 22:42:11 +02:00
2013-04-23 22:32:39 +02:00
int32_t charsize = 1 ;
int32_t depth = 1 ;
int32_t stride = bitmap - > bitmap . pitch ;
2013-04-23 22:48:34 +02:00
for ( int32_t ii = 0 ; ii < h ; + + ii )
2013-04-22 22:42:11 +02:00
{
2013-04-23 22:48:34 +02:00
memcpy ( _outBuffer + ( ii * w ) * charsize * depth ,
bitmap - > bitmap . buffer + ( ii * stride ) * charsize , w * charsize * depth ) ;
2013-04-22 22:42:11 +02:00
}
FT_Done_Glyph ( glyph ) ;
return true ;
}
2013-04-23 20:58:57 +02:00
bool FontManager : : TrueTypeFont : : bakeGlyphSubpixel ( CodePoint_t _codePoint , GlyphInfo & _glyphInfo , uint8_t * _outBuffer )
2013-04-22 22:42:11 +02:00
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( m_font ! = NULL , " TrueTypeFont not initialized " ) ;
2013-04-22 22:42:11 +02:00
FTHolder * holder = ( FTHolder * ) m_font ;
2013-04-23 20:58:57 +02:00
_glyphInfo . m_glyphIndex = FT_Get_Char_Index ( holder - > m_face , _codePoint ) ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
FT_GlyphSlot slot = holder - > m_face - > glyph ;
FT_Error error = FT_Load_Glyph ( holder - > m_face , _glyphInfo . m_glyphIndex , FT_LOAD_DEFAULT ) ;
2013-04-22 22:42:11 +02:00
if ( error ) { return false ; }
FT_Glyph glyph ;
error = FT_Get_Glyph ( slot , & glyph ) ;
if ( error ) { return false ; }
error = FT_Glyph_To_Bitmap ( & glyph , FT_RENDER_MODE_LCD , 0 , 1 ) ;
if ( error ) { return false ; }
FT_BitmapGlyph bitmap = ( FT_BitmapGlyph ) glyph ;
2013-04-23 22:32:39 +02:00
int32_t x = bitmap - > left ;
int32_t y = - bitmap - > top ;
int32_t w = bitmap - > bitmap . width ;
int32_t h = bitmap - > bitmap . rows ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
_glyphInfo . m_offset_x = ( float ) x ;
_glyphInfo . m_offset_y = ( float ) y ;
_glyphInfo . m_width = ( float ) w ;
_glyphInfo . m_height = ( float ) h ;
_glyphInfo . m_advance_x = ( float ) slot - > advance . x / 64.0f ;
_glyphInfo . m_advance_y = ( float ) slot - > advance . y / 64.0f ;
2013-04-23 22:32:39 +02:00
int32_t charsize = 1 ;
int32_t depth = 3 ;
int32_t stride = bitmap - > bitmap . pitch ;
2013-04-23 22:48:34 +02:00
for ( int32_t ii = 0 ; ii < h ; + + ii )
2013-04-22 22:42:11 +02:00
{
2013-04-23 22:48:34 +02:00
memcpy ( _outBuffer + ( ii * w ) * charsize * depth ,
bitmap - > bitmap . buffer + ( ii * stride ) * charsize , w * charsize * depth ) ;
2013-04-22 22:42:11 +02:00
}
FT_Done_Glyph ( glyph ) ;
return true ;
}
//TODO optimize: remove dynamic allocation and convert double to float
void make_distance_map ( unsigned char * img , unsigned char * outImg , unsigned int width , unsigned int height )
{
short * xdist = ( short * ) malloc ( width * height * sizeof ( short ) ) ;
short * ydist = ( short * ) malloc ( width * height * sizeof ( short ) ) ;
double * gx = ( double * ) calloc ( width * height , sizeof ( double ) ) ;
double * gy = ( double * ) calloc ( width * height , sizeof ( double ) ) ;
double * data = ( double * ) calloc ( width * height , sizeof ( double ) ) ;
double * outside = ( double * ) calloc ( width * height , sizeof ( double ) ) ;
double * inside = ( double * ) calloc ( width * height , sizeof ( double ) ) ;
2013-04-23 22:48:34 +02:00
uint32_t ii ;
2013-04-22 22:42:11 +02:00
// Convert img into double (data)
double img_min = 255 , img_max = - 255 ;
2013-04-23 22:48:34 +02:00
for ( ii = 0 ; ii < width * height ; + + ii )
2013-04-22 22:42:11 +02:00
{
2013-04-23 22:48:34 +02:00
double v = img [ ii ] ;
data [ ii ] = v ;
2013-04-22 22:42:11 +02:00
if ( v > img_max ) img_max = v ;
if ( v < img_min ) img_min = v ;
}
// Rescale image levels between 0 and 1
2013-04-23 22:48:34 +02:00
for ( ii = 0 ; ii < width * height ; + + ii )
2013-04-22 22:42:11 +02:00
{
2013-04-23 22:48:34 +02:00
data [ ii ] = ( img [ ii ] - img_min ) / ( img_max - img_min ) ;
2013-04-22 22:42:11 +02:00
}
// Compute outside = edtaa3(bitmap); % Transform background (0's)
computegradient ( data , width , height , gx , gy ) ;
edtaa3 ( data , gx , gy , width , height , xdist , ydist , outside ) ;
2013-04-23 22:48:34 +02:00
for ( ii = 0 ; ii < width * height ; + + ii )
if ( outside [ ii ] < 0 )
outside [ ii ] = 0.0 ;
2013-04-22 22:42:11 +02:00
// Compute inside = edtaa3(1-bitmap); % Transform foreground (1's)
memset ( gx , 0 , sizeof ( double ) * width * height ) ;
memset ( gy , 0 , sizeof ( double ) * width * height ) ;
2013-04-23 22:48:34 +02:00
for ( ii = 0 ; ii < width * height ; + + ii )
data [ ii ] = 1.0 - data [ ii ] ;
2013-04-22 22:42:11 +02:00
computegradient ( data , width , height , gx , gy ) ;
edtaa3 ( data , gx , gy , width , height , xdist , ydist , inside ) ;
2013-04-23 22:48:34 +02:00
for ( ii = 0 ; ii < width * height ; + + ii )
if ( inside [ ii ] < 0 )
inside [ ii ] = 0.0 ;
2013-04-22 22:42:11 +02:00
// distmap = outside - inside; % Bipolar distance field
unsigned char * out = outImg ; //(unsigned char *) malloc( width * height * sizeof(unsigned char) );
2013-04-23 22:48:34 +02:00
for ( ii = 0 ; ii < width * height ; + + ii )
2013-04-22 22:42:11 +02:00
{
//out[i] = 127 - outside[i]*8;
//if(out[i]<0) out[i] = 0;
//out[i] += inside[i]*16;
//if(out[i]>255) out[i] = 255;
2013-04-23 22:48:34 +02:00
outside [ ii ] - = inside [ ii ] ;
outside [ ii ] = 128 + outside [ ii ] * 16 ;
2013-04-22 22:42:11 +02:00
//if(outside[i] > 8) outside[i] = 8;
//if(inside[i] > 8) outside[i] = 8;
//outside[i] = 128 - inside[i]*8 + outside[i]*8;
2013-04-23 22:48:34 +02:00
if ( outside [ ii ] < 0 ) outside [ ii ] = 0 ;
if ( outside [ ii ] > 255 ) outside [ ii ] = 255 ;
out [ ii ] = 255 - ( unsigned char ) outside [ ii ] ;
2013-04-22 22:42:11 +02:00
//out[i] = (unsigned char) outside[i];
}
free ( xdist ) ;
free ( ydist ) ;
free ( gx ) ;
free ( gy ) ;
free ( data ) ;
free ( outside ) ;
free ( inside ) ;
}
2013-04-23 20:58:57 +02:00
bool FontManager : : TrueTypeFont : : bakeGlyphDistance ( CodePoint_t _codePoint , GlyphInfo & _glyphInfo , uint8_t * _outBuffer )
2013-04-22 22:42:11 +02:00
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( m_font ! = NULL , " TrueTypeFont not initialized " ) ;
2013-04-22 22:42:11 +02:00
FTHolder * holder = ( FTHolder * ) m_font ;
2013-04-23 20:58:57 +02:00
_glyphInfo . m_glyphIndex = FT_Get_Char_Index ( holder - > m_face , _codePoint ) ;
2013-04-22 22:42:11 +02:00
FT_Int32 loadMode = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING ;
FT_Render_Mode renderMode = FT_RENDER_MODE_NORMAL ;
2013-04-23 20:58:57 +02:00
FT_GlyphSlot slot = holder - > m_face - > glyph ;
FT_Error error = FT_Load_Glyph ( holder - > m_face , _glyphInfo . m_glyphIndex , loadMode ) ;
2013-04-22 22:42:11 +02:00
if ( error ) { return false ; }
FT_Glyph glyph ;
error = FT_Get_Glyph ( slot , & glyph ) ;
if ( error ) { return false ; }
error = FT_Glyph_To_Bitmap ( & glyph , renderMode , 0 , 1 ) ;
if ( error ) { return false ; }
FT_BitmapGlyph bitmap = ( FT_BitmapGlyph ) glyph ;
2013-04-23 22:32:39 +02:00
int32_t x = bitmap - > left ;
int32_t y = - bitmap - > top ;
int32_t w = bitmap - > bitmap . width ;
int32_t h = bitmap - > bitmap . rows ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
_glyphInfo . m_offset_x = ( float ) x ;
_glyphInfo . m_offset_y = ( float ) y ;
_glyphInfo . m_width = ( float ) w ;
_glyphInfo . m_height = ( float ) h ;
_glyphInfo . m_advance_x = ( float ) slot - > advance . x / 64.0f ;
_glyphInfo . m_advance_y = ( float ) slot - > advance . y / 64.0f ;
2013-04-22 22:42:11 +02:00
2013-04-23 22:32:39 +02:00
int32_t charsize = 1 ;
int32_t depth = 1 ;
int32_t stride = bitmap - > bitmap . pitch ;
2013-04-22 22:42:11 +02:00
2013-04-23 22:48:34 +02:00
for ( int32_t ii = 0 ; ii < h ; + + ii )
2013-04-22 22:42:11 +02:00
{
2013-04-23 22:48:34 +02:00
memcpy ( _outBuffer + ( ii * w ) * charsize * depth ,
bitmap - > bitmap . buffer + ( ii * stride ) * charsize , w * charsize * depth ) ;
2013-04-22 22:42:11 +02:00
}
FT_Done_Glyph ( glyph ) ;
if ( w * h > 0 )
{
uint32_t dw = 6 ;
uint32_t dh = 6 ;
if ( dw < 2 ) dw = 2 ;
if ( dh < 2 ) dh = 2 ;
uint32_t nw = w + dw * 2 ;
uint32_t nh = h + dh * 2 ;
2013-04-23 23:14:32 +02:00
BX_CHECK ( nw * nh < 128 * 128 , " buffer overflow " ) ;
2013-04-22 22:42:11 +02:00
uint32_t buffSize = nw * nh * sizeof ( uint8_t ) ;
uint8_t * alphaImg = ( uint8_t * ) malloc ( buffSize ) ;
memset ( alphaImg , 0 , nw * nh * sizeof ( uint8_t ) ) ;
//copy the original buffer to the temp one
2013-04-23 22:48:34 +02:00
for ( uint32_t ii = dh ; ii < nh - dh ; + + ii )
2013-04-22 22:42:11 +02:00
{
2013-04-23 22:48:34 +02:00
memcpy ( alphaImg + ii * nw + dw , _outBuffer + ( ii - dh ) * w , w ) ;
2013-04-22 22:42:11 +02:00
}
2013-04-23 20:58:57 +02:00
make_distance_map ( alphaImg , _outBuffer , nw , nh ) ;
2013-04-22 22:42:11 +02:00
free ( alphaImg ) ;
2013-04-23 20:58:57 +02:00
_glyphInfo . m_offset_x - = ( float ) dw ;
_glyphInfo . m_offset_y - = ( float ) dh ;
_glyphInfo . m_width = ( float ) nw ;
_glyphInfo . m_height = ( float ) nh ;
2013-04-22 22:42:11 +02:00
}
return true ;
}
//*************************************************************
typedef stl : : unordered_map < CodePoint_t , GlyphInfo > GlyphHash_t ;
// cache font data
struct FontManager : : CachedFont
{
2013-04-23 20:58:57 +02:00
CachedFont ( ) { m_trueTypeFont = NULL ; m_masterFontHandle . idx = - 1 ; }
FontInfo m_fontInfo ;
GlyphHash_t m_cachedGlyphs ;
FontManager : : TrueTypeFont * m_trueTypeFont ;
2013-04-22 22:42:11 +02:00
// an handle to a master font in case of sub distance field font
2013-04-23 20:58:57 +02:00
FontHandle m_masterFontHandle ;
int16_t m_padding ;
2013-04-22 22:42:11 +02:00
} ;
const uint16_t MAX_OPENED_FILES = 64 ;
const uint16_t MAX_OPENED_FONT = 64 ;
const uint32_t MAX_FONT_BUFFER_SIZE = 512 * 512 * 4 ;
2013-04-23 20:58:57 +02:00
FontManager : : FontManager ( Atlas * _atlas ) : m_filesHandles ( MAX_OPENED_FILES ) , m_fontHandles ( MAX_OPENED_FONT )
2013-04-22 22:42:11 +02:00
{
2013-04-23 20:58:57 +02:00
m_atlas = _atlas ;
2013-04-22 22:42:11 +02:00
m_ownAtlas = false ;
init ( ) ;
}
2013-04-23 20:58:57 +02:00
FontManager : : FontManager ( uint32_t _textureSideWidth ) : m_filesHandles ( MAX_OPENED_FILES ) , m_fontHandles ( MAX_OPENED_FONT )
2013-04-22 22:42:11 +02:00
{
2013-04-23 20:58:57 +02:00
m_atlas = new Atlas ( _textureSideWidth ) ;
2013-04-22 22:42:11 +02:00
m_ownAtlas = true ;
init ( ) ;
}
void FontManager : : init ( )
{
m_cachedFiles = new CachedFile [ MAX_OPENED_FILES ] ;
m_cachedFonts = new CachedFont [ MAX_OPENED_FONT ] ;
m_buffer = new uint8_t [ MAX_FONT_BUFFER_SIZE ] ;
// Create filler rectangle
uint8_t buffer [ 4 * 4 * 4 ] ;
memset ( buffer , 255 , 4 * 4 * 4 ) ;
2013-04-23 20:58:57 +02:00
m_blackGlyph . m_width = 3 ;
m_blackGlyph . m_height = 3 ;
2013-04-23 23:14:32 +02:00
BX_CHECK ( addBitmap ( m_blackGlyph , buffer ) , " unable to add white glyph " ) ;
2013-04-22 22:42:11 +02:00
//make sure the black glyph doesn't bleed
/*int16_t texUnit = 65535 / m_textureWidth;
m_blackGlyph . texture_x0 + = texUnit ;
m_blackGlyph . texture_y0 + = texUnit ;
m_blackGlyph . texture_x1 - = texUnit ;
m_blackGlyph . texture_y1 - = texUnit ; */
}
FontManager : : ~ FontManager ( )
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( m_fontHandles . getNumHandles ( ) = = 0 , " All the fonts must be destroyed before destroying the manager " ) ;
2013-04-22 22:42:11 +02:00
delete [ ] m_cachedFonts ;
2013-04-23 23:14:32 +02:00
BX_CHECK ( m_filesHandles . getNumHandles ( ) = = 0 , " All the font files must be destroyed before destroying the manager " ) ;
2013-04-22 22:42:11 +02:00
delete [ ] m_cachedFiles ;
delete [ ] m_buffer ;
if ( m_ownAtlas )
{
delete m_atlas ;
}
}
2013-04-23 20:58:57 +02:00
TrueTypeHandle FontManager : : loadTrueTypeFromFile ( const char * _fontPath )
2013-04-22 22:42:11 +02:00
{
FILE * pFile ;
2013-04-23 20:58:57 +02:00
pFile = fopen ( _fontPath , " rb " ) ;
2013-04-22 22:42:11 +02:00
if ( pFile = = NULL )
{
TrueTypeHandle invalid = BGFX_INVALID_HANDLE ;
return invalid ;
}
// Go to the end of the file.
if ( fseek ( pFile , 0L , SEEK_END ) = = 0 )
{
// Get the size of the file.
long bufsize = ftell ( pFile ) ;
if ( bufsize = = - 1 )
{
fclose ( pFile ) ;
TrueTypeHandle invalid = BGFX_INVALID_HANDLE ;
return invalid ;
}
uint8_t * buffer = new uint8_t [ bufsize ] ;
// Go back to the start of the file.
fseek ( pFile , 0L , SEEK_SET ) ;
// Read the entire file into memory.
2013-04-23 22:32:39 +02:00
uint32_t newLen = fread ( ( void * ) buffer , sizeof ( char ) , bufsize , pFile ) ;
2013-04-22 22:42:11 +02:00
if ( newLen = = 0 )
{
fclose ( pFile ) ;
delete [ ] buffer ;
TrueTypeHandle invalid = BGFX_INVALID_HANDLE ;
return invalid ;
}
fclose ( pFile ) ;
uint16_t id = m_filesHandles . alloc ( ) ;
2013-04-23 23:14:32 +02:00
BX_CHECK ( id ! = bx : : HandleAlloc : : invalid , " No more room for files " ) ;
2013-04-22 22:42:11 +02:00
m_cachedFiles [ id ] . buffer = buffer ;
m_cachedFiles [ id ] . bufferSize = bufsize ;
TrueTypeHandle ret = { id } ;
return ret ;
}
//TODO validate font
TrueTypeHandle invalid = BGFX_INVALID_HANDLE ;
return invalid ;
}
2013-04-23 20:58:57 +02:00
TrueTypeHandle FontManager : : loadTrueTypeFromMemory ( const uint8_t * _buffer , uint32_t _size )
2013-04-22 22:42:11 +02:00
{
2013-04-23 23:14:32 +02:00
uint16_t id = m_filesHandles . alloc ( ) ;
BX_CHECK ( id ! = bx : : HandleAlloc : : invalid , " Invalid handle used " ) ;
2013-04-23 20:58:57 +02:00
m_cachedFiles [ id ] . buffer = new uint8_t [ _size ] ;
m_cachedFiles [ id ] . bufferSize = _size ;
memcpy ( m_cachedFiles [ id ] . buffer , _buffer , _size ) ;
2013-04-22 22:42:11 +02:00
//TODO validate font
TrueTypeHandle ret = { id } ;
return ret ;
}
2013-04-23 20:58:57 +02:00
void FontManager : : unloadTrueType ( TrueTypeHandle _handle )
2013-04-22 22:42:11 +02:00
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( bgfx : : invalidHandle ! = _handle . idx , " Invalid handle used " ) ;
2013-04-23 20:58:57 +02:00
delete m_cachedFiles [ _handle . idx ] . buffer ;
m_cachedFiles [ _handle . idx ] . bufferSize = 0 ;
m_cachedFiles [ _handle . idx ] . buffer = NULL ;
m_filesHandles . free ( _handle . idx ) ;
2013-04-22 22:42:11 +02:00
}
2013-04-23 20:58:57 +02:00
FontHandle FontManager : : createFontByPixelSize ( TrueTypeHandle _tt_handle , uint32_t _typefaceIndex , uint32_t _pixelSize , FontType _fontType )
2013-04-22 22:42:11 +02:00
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( bgfx : : invalidHandle ! = _tt_handle . idx , " Invalid handle used " ) ;
2013-04-22 22:42:11 +02:00
TrueTypeFont * ttf = new TrueTypeFont ( ) ;
2013-04-23 20:58:57 +02:00
if ( ! ttf - > init ( m_cachedFiles [ _tt_handle . idx ] . buffer , m_cachedFiles [ _tt_handle . idx ] . bufferSize , _typefaceIndex , _pixelSize ) )
2013-04-22 22:42:11 +02:00
{
delete ttf ;
FontHandle invalid = BGFX_INVALID_HANDLE ;
return invalid ;
}
uint16_t fontIdx = m_fontHandles . alloc ( ) ;
2013-04-23 23:14:32 +02:00
BX_CHECK ( fontIdx ! = bx : : HandleAlloc : : invalid , " Invalid handle used " ) ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
m_cachedFonts [ fontIdx ] . m_trueTypeFont = ttf ;
m_cachedFonts [ fontIdx ] . m_fontInfo = ttf - > getFontInfo ( ) ;
m_cachedFonts [ fontIdx ] . m_fontInfo . m_fontType = _fontType ;
m_cachedFonts [ fontIdx ] . m_fontInfo . m_pixelSize = _pixelSize ;
m_cachedFonts [ fontIdx ] . m_cachedGlyphs . clear ( ) ;
m_cachedFonts [ fontIdx ] . m_masterFontHandle . idx = - 1 ;
2013-04-22 22:42:11 +02:00
FontHandle ret = { fontIdx } ;
return ret ;
}
FontHandle FontManager : : createScaledFontToPixelSize ( FontHandle _baseFontHandle , uint32_t _pixelSize )
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( bgfx : : invalidHandle ! = _baseFontHandle . idx , " Invalid handle used " ) ;
2013-04-22 22:42:11 +02:00
CachedFont & font = m_cachedFonts [ _baseFontHandle . idx ] ;
2013-04-23 20:58:57 +02:00
FontInfo & fontInfo = font . m_fontInfo ;
2013-04-22 22:42:11 +02:00
FontInfo newFontInfo = fontInfo ;
2013-04-23 20:58:57 +02:00
newFontInfo . m_pixelSize = _pixelSize ;
newFontInfo . m_scale = ( float ) _pixelSize / ( float ) fontInfo . m_pixelSize ;
newFontInfo . m_ascender = ( newFontInfo . m_ascender * newFontInfo . m_scale ) ;
newFontInfo . m_descender = ( newFontInfo . m_descender * newFontInfo . m_scale ) ;
newFontInfo . m_lineGap = ( newFontInfo . m_lineGap * newFontInfo . m_scale ) ;
newFontInfo . m_underline_thickness = ( newFontInfo . m_underline_thickness * newFontInfo . m_scale ) ;
newFontInfo . m_underline_position = ( newFontInfo . m_underline_position * newFontInfo . m_scale ) ;
2013-04-22 22:42:11 +02:00
uint16_t fontIdx = m_fontHandles . alloc ( ) ;
2013-04-23 23:14:32 +02:00
BX_CHECK ( fontIdx ! = bx : : HandleAlloc : : invalid , " Invalid handle used " ) ;
2013-04-23 20:58:57 +02:00
m_cachedFonts [ fontIdx ] . m_cachedGlyphs . clear ( ) ;
m_cachedFonts [ fontIdx ] . m_fontInfo = newFontInfo ;
m_cachedFonts [ fontIdx ] . m_trueTypeFont = NULL ;
m_cachedFonts [ fontIdx ] . m_masterFontHandle = _baseFontHandle ;
2013-04-22 22:42:11 +02:00
FontHandle ret = { fontIdx } ;
return ret ;
}
FontHandle FontManager : : loadBakedFontFromFile ( const char * /*fontPath*/ , const char * /*descriptorPath*/ )
{
2013-04-23 23:14:32 +02:00
//assert(false); //TODO implement
2013-04-22 22:42:11 +02:00
FontHandle invalid = BGFX_INVALID_HANDLE ;
return invalid ;
}
FontHandle FontManager : : loadBakedFontFromMemory ( const uint8_t * /*imageBuffer*/ , uint32_t /*imageSize*/ , const uint8_t * /*descriptorBuffer*/ , uint32_t /*descriptorSize*/ )
{
2013-04-23 23:14:32 +02:00
//assert(false); //TODO implement
2013-04-22 22:42:11 +02:00
FontHandle invalid = BGFX_INVALID_HANDLE ;
return invalid ;
}
void FontManager : : destroyFont ( FontHandle _handle )
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( bgfx : : invalidHandle ! = _handle . idx , " Invalid handle used " ) ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
if ( m_cachedFonts [ _handle . idx ] . m_trueTypeFont ! = NULL )
2013-04-22 22:42:11 +02:00
{
2013-04-23 20:58:57 +02:00
delete m_cachedFonts [ _handle . idx ] . m_trueTypeFont ;
m_cachedFonts [ _handle . idx ] . m_trueTypeFont = NULL ;
2013-04-22 22:42:11 +02:00
}
2013-04-23 20:58:57 +02:00
m_cachedFonts [ _handle . idx ] . m_cachedGlyphs . clear ( ) ;
2013-04-22 22:42:11 +02:00
m_fontHandles . free ( _handle . idx ) ;
}
2013-04-23 20:58:57 +02:00
bool FontManager : : preloadGlyph ( FontHandle _handle , const wchar_t * _string )
2013-04-23 23:14:32 +02:00
{
BX_CHECK ( bgfx : : invalidHandle ! = _handle . idx , " Invalid handle used " ) ;
2013-04-23 20:58:57 +02:00
CachedFont & font = m_cachedFonts [ _handle . idx ] ;
2013-04-22 22:42:11 +02:00
//if truetype present
2013-04-23 20:58:57 +02:00
if ( font . m_trueTypeFont ! = NULL )
2013-04-22 22:42:11 +02:00
{
//parse string
2013-04-23 22:48:34 +02:00
for ( uint32_t ii = 0 , end = wcslen ( _string ) ; ii < end ; + + ii )
2013-04-22 22:42:11 +02:00
{
//if glyph cached, continue
2013-04-23 22:48:34 +02:00
CodePoint_t codePoint = _string [ ii ] ;
2013-04-23 20:58:57 +02:00
if ( ! preloadGlyph ( _handle , codePoint ) )
2013-04-22 22:42:11 +02:00
{
return false ;
}
}
return true ;
}
return false ;
}
2013-04-23 20:58:57 +02:00
bool FontManager : : preloadGlyph ( FontHandle _handle , CodePoint_t _codePoint )
2013-04-22 22:42:11 +02:00
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( bgfx : : invalidHandle ! = _handle . idx , " Invalid handle used " ) ;
2013-04-23 20:58:57 +02:00
CachedFont & font = m_cachedFonts [ _handle . idx ] ;
FontInfo & fontInfo = font . m_fontInfo ;
2013-04-22 22:42:11 +02:00
//check if glyph not already present
2013-04-23 20:58:57 +02:00
GlyphHash_t : : iterator iter = font . m_cachedGlyphs . find ( _codePoint ) ;
if ( iter ! = font . m_cachedGlyphs . end ( ) )
2013-04-22 22:42:11 +02:00
{
return true ;
}
//if truetype present
2013-04-23 20:58:57 +02:00
if ( font . m_trueTypeFont ! = NULL )
2013-04-22 22:42:11 +02:00
{
GlyphInfo glyphInfo ;
//bake glyph as bitmap to buffer
2013-04-23 20:58:57 +02:00
switch ( font . m_fontInfo . m_fontType )
2013-04-22 22:42:11 +02:00
{
case FONT_TYPE_ALPHA :
2013-04-23 20:58:57 +02:00
font . m_trueTypeFont - > bakeGlyphAlpha ( _codePoint , glyphInfo , m_buffer ) ;
2013-04-22 22:42:11 +02:00
break ;
//case FONT_TYPE_LCD:
2013-04-23 20:58:57 +02:00
//font.m_trueTypeFont->bakeGlyphSubpixel(codePoint, glyphInfo, m_buffer);
2013-04-22 22:42:11 +02:00
//break;
case FONT_TYPE_DISTANCE :
2013-04-23 20:58:57 +02:00
font . m_trueTypeFont - > bakeGlyphDistance ( _codePoint , glyphInfo , m_buffer ) ;
2013-04-22 22:42:11 +02:00
break ;
case FONT_TYPE_DISTANCE_SUBPIXEL :
2013-04-23 20:58:57 +02:00
font . m_trueTypeFont - > bakeGlyphDistance ( _codePoint , glyphInfo , m_buffer ) ;
2013-04-22 22:42:11 +02:00
break ;
default :
2013-04-23 23:14:32 +02:00
BX_CHECK ( false , " TextureType not supported yet " ) ;
2013-04-22 22:42:11 +02:00
} ;
//copy bitmap to texture
if ( ! addBitmap ( glyphInfo , m_buffer ) )
{
return false ;
}
2013-04-23 20:58:57 +02:00
glyphInfo . m_advance_x = ( glyphInfo . m_advance_x * fontInfo . m_scale ) ;
glyphInfo . m_advance_y = ( glyphInfo . m_advance_y * fontInfo . m_scale ) ;
glyphInfo . m_offset_x = ( glyphInfo . m_offset_x * fontInfo . m_scale ) ;
glyphInfo . m_offset_y = ( glyphInfo . m_offset_y * fontInfo . m_scale ) ;
glyphInfo . m_height = ( glyphInfo . m_height * fontInfo . m_scale ) ;
glyphInfo . m_width = ( glyphInfo . m_width * fontInfo . m_scale ) ;
2013-04-22 22:42:11 +02:00
// store cached glyph
2013-04-23 20:58:57 +02:00
font . m_cachedGlyphs [ _codePoint ] = glyphInfo ;
2013-04-22 22:42:11 +02:00
return true ;
} else
{
//retrieve glyph from parent font if any
2013-04-23 20:58:57 +02:00
if ( font . m_masterFontHandle . idx ! = bgfx : : invalidHandle )
2013-04-22 22:42:11 +02:00
{
2013-04-23 20:58:57 +02:00
if ( preloadGlyph ( font . m_masterFontHandle , _codePoint ) )
2013-04-22 22:42:11 +02:00
{
GlyphInfo glyphInfo ;
2013-04-23 20:58:57 +02:00
getGlyphInfo ( font . m_masterFontHandle , _codePoint , glyphInfo ) ;
2013-04-22 22:42:11 +02:00
2013-04-23 20:58:57 +02:00
glyphInfo . m_advance_x = ( glyphInfo . m_advance_x * fontInfo . m_scale ) ;
glyphInfo . m_advance_y = ( glyphInfo . m_advance_y * fontInfo . m_scale ) ;
glyphInfo . m_offset_x = ( glyphInfo . m_offset_x * fontInfo . m_scale ) ;
glyphInfo . m_offset_y = ( glyphInfo . m_offset_y * fontInfo . m_scale ) ;
glyphInfo . m_height = ( glyphInfo . m_height * fontInfo . m_scale ) ;
glyphInfo . m_width = ( glyphInfo . m_width * fontInfo . m_scale ) ;
2013-04-22 22:42:11 +02:00
// store cached glyph
2013-04-23 20:58:57 +02:00
font . m_cachedGlyphs [ _codePoint ] = glyphInfo ;
2013-04-22 22:42:11 +02:00
return true ;
}
}
}
return false ;
}
2013-04-23 20:58:57 +02:00
const FontInfo & FontManager : : getFontInfo ( FontHandle _handle )
2013-04-22 22:42:11 +02:00
{
2013-04-23 23:14:32 +02:00
BX_CHECK ( bgfx : : invalidHandle ! = _handle . idx , " Invalid handle used " ) ;
2013-04-23 20:58:57 +02:00
return m_cachedFonts [ _handle . idx ] . m_fontInfo ;
2013-04-22 22:42:11 +02:00
}
2013-04-23 20:58:57 +02:00
bool FontManager : : getGlyphInfo ( FontHandle _handle , CodePoint_t _codePoint , GlyphInfo & _outInfo )
2013-04-22 22:42:11 +02:00
{
2013-04-23 20:58:57 +02:00
GlyphHash_t : : iterator iter = m_cachedFonts [ _handle . idx ] . m_cachedGlyphs . find ( _codePoint ) ;
if ( iter = = m_cachedFonts [ _handle . idx ] . m_cachedGlyphs . end ( ) )
2013-04-22 22:42:11 +02:00
{
2013-04-23 20:58:57 +02:00
if ( preloadGlyph ( _handle , _codePoint ) )
2013-04-22 22:42:11 +02:00
{
2013-04-23 20:58:57 +02:00
iter = m_cachedFonts [ _handle . idx ] . m_cachedGlyphs . find ( _codePoint ) ;
2013-04-22 22:42:11 +02:00
} else
{
return false ;
}
}
2013-04-23 20:58:57 +02:00
_outInfo = iter - > second ;
2013-04-22 22:42:11 +02:00
return true ;
}
// ****************************************************************************
2013-04-23 20:58:57 +02:00
bool FontManager : : addBitmap ( GlyphInfo & _glyphInfo , const uint8_t * _data )
2013-04-22 22:42:11 +02:00
{
2013-04-23 20:58:57 +02:00
_glyphInfo . m_regionIndex = m_atlas - > addRegion ( ( uint16_t ) ceil ( _glyphInfo . m_width ) , ( uint16_t ) ceil ( _glyphInfo . m_height ) , _data , AtlasRegion : : TYPE_GRAY ) ;
2013-04-22 22:42:11 +02:00
return true ;
}