blob: 5e057db65596c48ff4fbf3cff2f64268362fb679 [file] [log] [blame]
/****************************************************************************/
/* */
/* The FreeType project - a Free and Portable Quality TrueType Renderer. */
/* */
/* Copyright 1996-1998 by */
/* D. Turner, R.Wilhelm, and W. Lemberg */
/* */
/* fttimer: A simple performance benchmark. Now with graylevel rendering */
/* with the '-g' option. */
/* */
/* Be aware that the timer program benchmarks different things */
/* in each release of the FreeType library. Thus, performance */
/* should only be compared between similar release numbers. */
/* */
/* */
/* NOTE: This is just a test program that is used to show off and */
/* debug the current engine. In no way does it shows the final */
/* high-level interface that client applications will use. */
/* */
/****************************************************************************/
#include <freetype/freetype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h> /* for clock() */
#include "graph.h"
#include <freetype/ftgrays.h>
/* SunOS 4.1.* does not define CLOCKS_PER_SEC, so include <sys/param.h> */
/* to get the HZ macro which is the equivalent. */
#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4)
#include <sys/param.h>
#define CLOCKS_PER_SEC HZ
#endif
#define CHARSIZE 400 /* character point size */
#define MAX_GLYPHS 512 /* Maximum number of glyphs rendered at one time */
char Header[128];
FT_Error error;
FT_Library library;
FT_Face face;
FT_Size size;
FT_GlyphSlot glyph;
FT_Outline outline;
FT_Pos* cur_x;
FT_Pos* cur_y;
unsigned short* cur_endContour;
unsigned char* cur_touch;
FT_Outline outlines[MAX_GLYPHS];
int num_glyphs;
int tab_glyphs;
int cur_glyph;
int cur_point;
unsigned short cur_contour;
int pixel_size = CHARSIZE;
int repeat_count = 1;
int use_grays = 0;
FT_Bitmap Bit;
grBitmap bit;
int Fail;
int Num;
int vio_Height, vio_Width;
short visual; /* display glyphs while rendering */
short antialias; /* smooth fonts with gray levels */
short force_low;
#define RASTER_BUFF_SIZE 128000
char raster_buff[ RASTER_BUFF_SIZE ];
static void Clear_Buffer();
static void Panic( const char* message )
{
fprintf( stderr, "%s\n error code = 0x%04x\n", message, error );
}
/*******************************************************************/
/* */
/* Get_Time: */
/* */
/* Returns the current time in milliseconds. */
/* */
/*******************************************************************/
long Get_Time( void )
{
return clock() * 10000 / CLOCKS_PER_SEC;
}
/*******************************************************************/
/* */
/* Init_Engine: */
/* */
/* Allocates bitmap, render pool and other structs... */
/* */
/*******************************************************************/
void Init_Engine( void )
{
Bit.rows = bit.rows;
Bit.width = bit.width;
Bit.pitch = bit.pitch;
Bit.buffer = bit.buffer;
Bit.pixel_mode = antialias ? ft_pixel_mode_grays : ft_pixel_mode_mono;
Bit.num_grays = bit.grays;
Clear_Buffer();
}
/*******************************************************************/
/* */
/* Clear_Buffer: */
/* */
/* Clears current bitmap. */
/* */
/*******************************************************************/
static void Clear_Buffer( void )
{
long size = Bit.rows * Bit.pitch;
memset( Bit.buffer, 0, size );
}
/*******************************************************************/
/* */
/* LoadTrueTypeChar: */
/* */
/* Loads a glyph into memory. */
/* */
/*******************************************************************/
FT_Error LoadChar( int idx )
{
error = FT_Load_Glyph( face, idx, FT_LOAD_DEFAULT );
if ( error )
return error;
glyph->outline.flags |= ft_outline_single_pass |
ft_outline_ignore_dropouts;
if (force_low)
glyph->outline.flags &= ~ft_outline_high_precision;
/* debugging */
#if 0
if ( idx == 0 && !visual )
{
printf( "points = %d\n", outline.points );
for ( j = 0; j < outline.points; j++ )
printf( "%02x (%01hx,%01hx)\n",
j, outline.xCoord[j], outline.yCoord[j] );
printf( "\n" );
}
#endif
/* create a new outline */
FT_Outline_New( library,
glyph->outline.n_points,
glyph->outline.n_contours,
&outlines[cur_glyph] );
/* copy the glyph outline into it */
glyph->outline.flags |= ft_outline_single_pass;
if (force_low)
glyph->outline.flags &= ~ft_outline_high_precision;
FT_Outline_Copy( &glyph->outline, &outlines[cur_glyph] );
/* center outline around 0 */
{
FT_BBox bbox;
FT_Outline_Get_CBox( &glyph->outline, &bbox );
FT_Outline_Translate( &outlines[cur_glyph],
- ( bbox.xMax - bbox.xMin )/2,
- ( bbox.yMax - bbox.yMin )/2 );
}
/* translate it */
FT_Outline_Translate( &outlines[cur_glyph],
Bit.width * 32 ,
Bit.rows * 32 );
cur_glyph++;
return FT_Err_Ok;
}
/*******************************************************************/
/* */
/* ConvertRaster: */
/* */
/* Performs scan conversion. */
/* */
/*******************************************************************/
FT_Error ConvertRaster( int index )
{
outlines[index].flags |= ~ft_outline_single_pass;
return FT_Outline_Get_Bitmap( library, &outlines[index], &Bit );
}
static void Usage()
{
fprintf( stderr, "fttimer: simple performance timer -- part of the FreeType project\n" );
fprintf( stderr, "-----------------------------------------------------------------\n\n" );
fprintf( stderr, "Usage: fttimer [options] fontname[.ttf|.ttc]\n\n" );
fprintf( stderr, "options:\n");
fprintf( stderr, " -r : repeat count to be used (default is 1)\n" );
fprintf( stderr, " -s : character pixel size (default is 600)\n" );
fprintf( stderr, " -v : display results..\n" );
fprintf( stderr, " -g : render anti-aliased glyphs\n" );
fprintf( stderr, " -a : use smooth anti-aliaser\n" );
fprintf( stderr, " -l : force low quality even at small sizes\n" );
exit(1);
}
int main( int argc, char** argv )
{
int i, total, base, rendered_glyphs;
char filename[128 + 4];
char alt_filename[128 + 4];
char* execname;
grSurface* surface = 0;
long t, t0, tz0;
execname = argv[0];
antialias = 0;
visual = 0;
force_low = 0;
while ( argc > 1 && argv[1][0] == '-' )
{
switch ( argv[1][1] )
{
case 'g':
antialias = 1;
break;
case 'a':
use_grays = 1;
break;
case 'l':
force_low = 1;
break;
case 'v':
visual = 1;
break;
case 's':
argc--;
argv++;
if ( argc < 2 ||
sscanf( argv[1], "%d", &pixel_size ) != 1 )
Usage();
break;
case 'r':
argc--;
argv++;
if ( argc < 2 ||
sscanf( argv[1], "%d", &repeat_count ) != 1 )
Usage();
if (repeat_count < 1)
repeat_count = 1;
break;
default:
fprintf( stderr, "Unknown argument '%s'!\n", argv[1] );
Usage();
}
argc--;
argv++;
}
if ( argc != 2 )
Usage();
i = strlen( argv[1] );
while ( i > 0 && argv[1][i] != '\\' )
{
if ( argv[1][i] == '.' )
i = 0;
i--;
}
filename[128] = '\0';
alt_filename[128] = '\0';
strncpy( filename, argv[1], 128 );
strncpy( alt_filename, argv[1], 128 );
if ( i >= 0 )
{
strncpy( filename + strlen( filename ), ".ttf", 4 );
strncpy( alt_filename + strlen( alt_filename ), ".ttc", 4 );
}
/* Initialize engine */
if ( (error = FT_Init_FreeType( &library )) )
Panic( "Error while initializing engine" );
/* set-up smooth anti-aliaser */
if (use_grays)
{
error = FT_Set_Raster( library, &ft_grays_raster );
if (error) Panic( "Could not initialize smooth anti-aliasing renderer" );
}
/* Load face */
error = FT_New_Face( library, filename, 0, &face );
if ( error == FT_Err_Cannot_Open_Stream )
Panic( "Could not find/open font resource" );
else if ( error )
Panic( "Error while opening font resource" );
/* get face properties and allocate preload arrays */
num_glyphs = face->num_glyphs;
glyph = face->glyph;
tab_glyphs = MAX_GLYPHS;
if ( tab_glyphs > num_glyphs )
tab_glyphs = num_glyphs;
/* create size */
error = FT_Set_Pixel_Sizes( face, pixel_size, pixel_size );
if ( error ) Panic( "Could not reset instance" );
bit.mode = antialias ? gr_pixel_mode_gray : gr_pixel_mode_mono;
bit.width = 640;
bit.rows = 480;
bit.grays = 128;
if ( visual )
{
if ( !grInitDevices() )
Panic( "Could not initialize graphics.\n" );
surface = grNewSurface( 0, &bit );
if (!surface)
Panic( "Could not open graphics window/screen.\n" );
}
else
{
if ( grNewBitmap( bit.mode,
bit.grays,
bit.width,
bit.rows,
&bit ) )
Panic( "Could not create rendering buffer.\n" );
}
Init_Engine();
Num = 0;
Fail = 0;
total = num_glyphs;
base = 0;
rendered_glyphs = 0;
t0 = 0; /* Initial time */
tz0 = Get_Time();
while ( total > 0 )
{
int repeat;
/* First, preload 'tab_glyphs' in memory */
cur_glyph = 0;
cur_point = 0;
cur_contour = 0;
printf( "loading %d glyphs", tab_glyphs );
for ( Num = 0; Num < tab_glyphs; Num++ )
{
error = LoadChar( base + Num );
if ( error )
Fail++;
total--;
}
base += tab_glyphs;
if ( tab_glyphs > total )
tab_glyphs = total;
printf( ", rendering... " );
/* Now, render the loaded glyphs */
t = Get_Time();
for ( repeat = 0; repeat < repeat_count; repeat++ )
{
for ( Num = 0; Num < cur_glyph; Num++ )
{
if ( (error = ConvertRaster( Num )) )
Fail++;
else
{
rendered_glyphs ++;
if ( Num == 0 && visual )
{
sprintf( Header, "Glyph: %5d", Num );
grSetTitle( surface, Header );
grRefreshSurface( surface );
Clear_Buffer();
}
}
}
}
t = Get_Time() - t;
if ( t < 0 )
t += 1000 * 60 * 60;
printf( " = %f s\n", (double)t / 10000 );
t0 += t;
/* Now free all loaded outlines */
for ( Num = 0; Num < cur_glyph; Num++ )
FT_Outline_Done( library, &outlines[Num] );
}
tz0 = Get_Time() - tz0;
FT_Done_Face( face );
printf( "\n" );
printf( "rendered glyphs = %d\n", rendered_glyphs );
printf( "render time = %f s\n", (double)t0 / 10000 );
printf( "fails = %d\n", Fail );
printf( "average glyphs/s = %f\n",
(double)rendered_glyphs / t0 * 10000 );
printf( "total timing = %f s\n", (double)tz0 / 10000 );
printf( "Fails = %d\n", Fail );
FT_Done_FreeType( library );
exit( 0 ); /* for safety reasons */
return 0; /* never reached */
}
/* End */