public void LoadResource( Resource resource )
{
// TODO : Revisit after checking current Imaging support in Mono.
#if !( XBOX || XBOX360 || ANDROID || IPHONE)
string current = Environment.CurrentDirectory;
IntPtr ftLibrary = IntPtr.Zero;
if ( FT.FT_Init_FreeType( out ftLibrary ) != 0 )
throw new AxiomException( "Could not init FreeType library!" );
IntPtr face = IntPtr.Zero;
int char_space = 5;
Stream fileStream = ResourceGroupManager.Instance.OpenResource( Source, Group );
byte[] data = new byte[ fileStream.Length ];
fileStream.Read( data, 0, data.Length );
//Load font
int success = FT.FT_New_Memory_Face( ftLibrary, data, data.Length, 0, out face );
if ( success != 0 )
{
throw new AxiomException( "Could not open font face!" );
}
// Convert our point size to freetype 26.6 fixed point format
int ttfSize = _ttfSize * ( 1 << 6 );
success = FT.FT_Set_Char_Size( face, ttfSize, 0, (uint)_ttfResolution, (uint)_ttfResolution );
if ( success != 0 )
{
{
throw new AxiomException( "Could not set char size!" );
}
}
int max_height = 0, max_width = 0;
List<KeyValuePair<int, int>> codePointRange = new List<KeyValuePair<int, int>>();
// Backwards compatibility - if codepoints not supplied, assume 33-166
if ( codePointRange.Count == 0 )
{
codePointRange.Add( new KeyValuePair<int, int>( 33, 166 ) );
}
int glyphCount = 0;
foreach ( KeyValuePair<int, int> r in codePointRange )
{
KeyValuePair<int, int> range = r;
for ( int cp = range.Key; cp <= range.Value; ++cp, ++glyphCount )
{
FT.FT_Load_Char( face, (uint)cp, 4 ); //4 == FT_LOAD_RENDER
FT_FaceRec rec = (FT_FaceRec)Marshal.PtrToStructure( face, typeof( FT_FaceRec ) );
FT_GlyphSlotRec glyp = (FT_GlyphSlotRec)Marshal.PtrToStructure( rec.glyph, typeof( FT_GlyphSlotRec ) );
if ( ( 2 * ( glyp.bitmap.rows << 6 ) - glyp.metrics.horiBearingY ) > max_height )
max_height = ( 2 * ( glyp.bitmap.rows << 6 ) - glyp.metrics.horiBearingY );
if ( glyp.metrics.horiBearingY > maxBearingY )
maxBearingY = glyp.metrics.horiBearingY;
if ( ( glyp.advance.x >> 6 ) + ( glyp.metrics.horiBearingX >> 6 ) > max_width )
max_width = ( glyp.advance.x >> 6 ) + ( glyp.metrics.horiBearingX >> 6 );
}
}
// Now work out how big our texture needs to be
int rawSize = ( max_width + char_space ) *
( ( max_height >> 6 ) + char_space ) * glyphCount;
int tex_side = (int)System.Math.Sqrt( (Real)rawSize );
// just in case the size might chop a glyph in half, add another glyph width/height
tex_side += System.Math.Max( max_width, ( max_height >> 6 ) );
// Now round up to nearest power of two
int roundUpSize = (int)Bitwise.FirstPO2From( (uint)tex_side );
// Would we benefit from using a non-square texture (2X width(
int finalWidth = 0, finalHeight = 0;
if ( roundUpSize * roundUpSize * 0.5 >= rawSize )
{
finalHeight = (int)( roundUpSize * 0.5 );
}
else
{
finalHeight = roundUpSize;
}
finalWidth = roundUpSize;
Real textureAspec = (Real)finalWidth / (Real)finalHeight;
int pixelBytes = 2;
int dataWidth = finalWidth * pixelBytes;
int data_size = finalWidth * finalHeight * pixelBytes;
LogManager.Instance.Write( "Font " + _name + " using texture size " + finalWidth.ToString() + "x" + finalHeight.ToString() );
byte[] imageData = new byte[ data_size ];
for ( int i = 0; i < data_size; i += pixelBytes )
{
imageData[ i + 0 ] = 0xff;// luminance
imageData[ i + 1 ] = 0x00;// alpha
}
int l = 0, m = 0;
foreach ( KeyValuePair<int, int> r in codePointRange )
{
KeyValuePair<int, int> range = r;
for ( int cp = range.Key; cp <= range.Value; ++cp )
{
int result = FT.FT_Load_Char( face, (uint)cp, 4 );//4 == FT_LOAD_RENDER
if ( result != 0 )
{
// problem loading this glyph, continue
LogManager.Instance.Write( "Info: cannot load character '" + char.ConvertFromUtf32( cp ) + "' in font " + _name + "." );
continue;
}
FT_FaceRec rec = (FT_FaceRec)Marshal.PtrToStructure( face, typeof( FT_FaceRec ) );
FT_GlyphSlotRec glyp = (FT_GlyphSlotRec)Marshal.PtrToStructure( rec.glyph, typeof( FT_GlyphSlotRec ) );
int advance = glyp.advance.x >> 6;
unsafe
{
if ( glyp.bitmap.buffer == IntPtr.Zero )
{
LogManager.Instance.Write( "Info: Freetype returned null for character '" + char.ConvertFromUtf32( cp ) + "' in font " + _name + "." );
continue;
}
byte* buffer = (byte*)glyp.bitmap.buffer;
byte* imageDataPtr = (byte*)Memory.PinObject( imageData );
int y_bearing = ( ( maxBearingY >> 6 ) - ( glyp.metrics.horiBearingY >> 6 ) );
int x_bearing = glyp.metrics.horiBearingX >> 6;
for ( int j = 0; j < glyp.bitmap.rows; j++ )
{
int row = j + m + y_bearing;
byte* pDest = &imageDataPtr[ ( row * dataWidth ) + ( l + x_bearing ) * pixelBytes ];
for ( int k = 0; k < glyp.bitmap.width; k++ )
{
if ( AntialiasColor )
{
// Use the same greyscale pixel for all components RGBA
*pDest++ = *buffer;
}
else
{
// Always white whether 'on' or 'off' pixel, since alpha
// will turn off
*pDest++ = (byte)0xFF;
}
// Always use the greyscale value for alpha
*pDest++ = *buffer++;
}//end k
}//end j
//
this.SetGlyphTexCoords( (uint)cp, (Real)l / (Real)finalWidth,//u1
(Real)m / (Real)finalHeight,//v1
(Real)( l + ( glyp.advance.x >> 6 ) ) / (Real)finalWidth, //u2
( m + ( max_height >> 6 ) ) / (Real)finalHeight, textureAspec ); //v2
// textureAspec );
//SetGlyphTexCoords( c, u1, v1, u2, v2 );
//Glyphs.Add( new KeyValuePair<CodePoint, GlyphInfo>( (uint)cp,
// new GlyphInfo( (uint)cp,
// new UVRect(
// (Real)l / (Real)finalWidth,//u1
// (Real)m / (Real)finalHeight,//v1
// (Real)( l + ( glyp.advance.x >> 6 ) ) / (Real)finalWidth, //u2
// ( m + ( max_height >> 6 ) ) / (Real)finalHeight //v2
// ), textureAspec ) ) );
// Advance a column
l += ( advance + char_space );
// If at end of row
if ( finalWidth - 1 < l + ( advance ) )
{
m += ( max_height >> 6 ) + char_space;
l = 0;
}
}
}
}//end foreach
MemoryStream memStream = new MemoryStream( imageData );
Image img = Image.FromRawStream( memStream, finalWidth, finalHeight, PixelFormat.BYTE_LA );
Texture tex = (Texture)resource;
Image[] images = new Image[ 1 ];
images[ 0 ] = img;
tex.LoadImages( images );
FT.FT_Done_FreeType( ftLibrary );
//img.Save( "C:\\" + Name + ".png" );
//FileStream file = new FileStream( "C:\\" + Name + ".fontdef", FileMode.Create );
//StreamWriter str = new StreamWriter( file );
//str.WriteLine( Name );
//str.WriteLine( "{" );
//str.WriteLine( "\ttype\timage" );
//str.WriteLine( "\tsource\t{0}.png\n", Name );
//for ( uint i = 0; i < (uint)( END_CHAR - START_CHAR ); i++ )
//{
// char c = (char)( i + START_CHAR );
// str.WriteLine( "\tglyph\t{0}\t{1:F6}\t{2:F6}\t{3:F6}\t{4:F6}", c, Glyphs[ c ].uvRect.Top, Glyphs[ c ].uvRect.Left, Glyphs[ c ].uvRect.Bottom, Glyphs[ c ].uvRect.Right );
//}
//str.WriteLine( "}" );
//str.Close();
//file.Close();
#endif
}
#endregion Implementation of IManualResourceLoader