4 * A simple utility to generate the bitmap fonts to be used in freeglut.
6 * Copyright (c) 1999-2000 by Pawel W. Olszta
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Creation date: nie gru 26 21:52:36 CET 1999
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software")
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Sotware.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #include <X11/Xutil.h>
41 * Define the log domain
44 #define G_LOG_DOMAIN "genfonts"
47 * The alphabet we want to export.
49 gchar* g_Alphabet = " abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789`~!@#$%^&*()-_=+[{}];:,.<>/?\\\"";
50 gint g_AlphabetLength = 0;
53 * All undefined characters will get replaced by this one:
58 * The stream we want to redirect our output to
60 FILE* g_Output = NULL;
63 * The display we're getting the fonts from
68 * This function outputs the font file prologue
70 void OutputPrologue( gchar* fileName )
73 * Output the copyright and permission notices:
75 fprintf( g_Output, "/*\n * %s\n *\n * This file has been automatically generated by the genfonts utility.\n *\n", fileName );
76 fprintf( g_Output, " * Copyright (c) 1999-2000 by Pawel W. Olszta\n * Written by Pawel W. Olszta, <olszta@sourceforge.net>\n * \n" );
77 fprintf( g_Output, " * Permission is hereby granted, free of charge, to any person obtaining a\n" );
78 fprintf( g_Output, " * copy of this software and associated documentation files (the \"Software\"),\n" );
79 fprintf( g_Output, " * to deal in the Software without restriction, including without limitation\n" );
80 fprintf( g_Output, " * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n" );
81 fprintf( g_Output, " * and/or sell copies of the Software, and to permit persons to whom the\n" );
82 fprintf( g_Output, " * Software is furnished to do so, subject to the following conditions:\n *\n" );
83 fprintf( g_Output, " * The above copyright notice and this permission notice shall be included\n" );
84 fprintf( g_Output, " * in all copies or substantial portions of the Sotware.\n *\n" );
85 fprintf( g_Output, " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n" );
86 fprintf( g_Output, " * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n" );
87 fprintf( g_Output, " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n" );
88 fprintf( g_Output, " * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n" );
89 fprintf( g_Output, " * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n" );
90 fprintf( g_Output, " * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n" );
93 * The obvious include headers
95 fprintf( g_Output, "\n#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif\n\n#include \"../include/GL/freeglut.h\"\n#include \"../include/GL/freeglut_internal.h\"\n" );
99 * This function outputs a font set
101 void OutputFont( gchar* freeglutFontName, gchar* fontName )
103 gint character, lineWidth, maxWidth = 0, maxHeight = 0;
104 XFontStruct* fontStruct = NULL;
105 XGCValues contextValues;
106 XImage* image = NULL;
112 * Check if there is a font that meets our requirements
114 fontStruct = XLoadQueryFont( g_Display, fontName );
116 if( fontStruct == NULL )
119 * Whoops, the font was not found
121 g_error( "couldn't get font `%s' using local display", fontName );
125 * Get the maximum size of the font characters
127 maxWidth = fontStruct->max_bounds.rbearing - fontStruct->min_bounds.lbearing;
128 maxHeight = fontStruct->max_bounds.ascent + fontStruct->max_bounds.descent;
131 * Allocate the line buffer for storing the font bitmap lines
133 lineBuffer = g_new0( guchar, maxWidth );
136 * Create a pixmap buffer where we'll be rendering our fonts to.
138 buffer = XCreatePixmap(
140 RootWindow( g_Display, DefaultScreen( g_Display ) ),
147 * We'll need a graphics context to handle the font writes and buffer clears
157 * Have the font assigned to the graphics context
159 XSetFont( g_Display, context, fontStruct->fid );
162 * For every character we want to have outputted...
164 for( character=0; character<g_AlphabetLength; character++ )
166 gint x, y, start_x, stop_x;
169 * Clear the context black (0 is black in our case)...
171 XSetForeground( g_Display, context, 0x00 );
172 XFillRectangle( g_Display, buffer, context, 0, 0, maxWidth, maxHeight );
175 * Be kind and draw the characters white (which is 1 for us)
177 XSetForeground( g_Display, context, 0xff );
180 * Draw the n-th character of the alphabet
186 -fontStruct->min_bounds.lbearing,
187 fontStruct->max_bounds.ascent,
188 (g_Alphabet + character),
193 * We need some a way to access the font we've just drawn:
204 * Find the first non-empty column:
206 start_x = -1; stop_x = -1;
208 for( x=0; x<maxWidth; x++ )
209 for( y=0; y<maxHeight; y++ )
210 if( (XGetPixel( image, x, y ) == 1) && (start_x == -1) )
214 * Find the last empty column
216 for( x=maxWidth-1; x>=0; x-- )
217 for( y=0; y<maxHeight; y++ )
218 if( (XGetPixel( image, x, y) == 1) && (stop_x == -1) )
222 * If the size is too little, enhance it a bit
224 if( stop_x - start_x < 1 )
226 start_x = 0; stop_x = maxWidth - 1;
230 * Output the character we have just grabbed
232 fprintf( g_Output, "static const guchar %s_Character_%03i[] = {%3i",
233 freeglutFontName, (gint) g_Alphabet[ character ], stop_x-start_x
236 for( y=maxHeight-1; y>=0; y-- )
239 * Prepare the line buffer for being used again
241 memset( lineBuffer, 0, maxWidth );
244 * Grab the rasterized character face into the line buffer
246 for( x=start_x, lineWidth=0; x<stop_x; x++, lineWidth++ )
247 if( XGetPixel( image, x, y ) )
248 lineBuffer[ lineWidth / 8 ] |= 1 << (7 - (lineWidth % 8));
251 * Feel free to output the final line bitmap now
253 for( x=0; x<(stop_x - start_x + 7) / 8; x++ )
254 fprintf( g_Output, ",%3i", lineBuffer[ x ] );
257 fprintf( g_Output, "};\n" );
260 * Free the image, and get to the next character...
262 XDestroyImage( image );
266 * Now we are ready to output the final data concerning the font charset
268 fprintf( g_Output, "\n/* The font characters mapping: */\n" );
269 fprintf( g_Output, "static const guchar* %s_Character_Map[] = {", freeglutFontName );
272 * I have decided to change the characters mapping a bit...
274 for( character=1; character<256; character++ )
276 gchar ourCharacter[ 2 ] = { 0, 0 };
279 * Do we have the character defined or not?
281 ourCharacter[ 0 ] = (gchar) character;
283 if( strstr( g_Alphabet, ourCharacter ) == NULL )
286 * Nope, output the g_NoChar character instead:
288 fprintf( g_Output, "%s_Character_%03i,", freeglutFontName, (gint) g_NoChar );
293 * Otherwise we're welcome to output the character:
295 fprintf( g_Output, "%s_Character_%03i,", freeglutFontName, (gint) ourCharacter[ 0 ] );
299 fprintf( g_Output, "NULL};\n\n" );
302 * And finally have the font structure written to the output stream
304 fprintf( g_Output, "/* The font structure: */\n" );
305 fprintf( g_Output, "const SFG_Font fgFont%s = { \"%s\", %i, %i, %s_Character_Map };\n\n",
306 freeglutFontName, fontName, g_AlphabetLength, maxHeight, freeglutFontName
310 * Done, clean up behind...
312 XFreeGC( g_Display, context );
313 XFreePixmap( g_Display, buffer );
314 g_free( lineBuffer );
318 * This function outputs the font file epilogue
320 void OutputEpilogue( void )
322 fprintf( g_Output, "/*** END OF FILE ***/\n" );
326 * The main function processes the command line arguments
327 * and outputs all the fonts we need to have rasterized.
329 int main( int argc, char** argv )
331 gchar ourCharacter[ 2 ] = { 0, 0 };
332 gchar* outputFileName = NULL;
333 gchar* displayName = NULL;
337 * The fonts that are going to be rasterized and added to the output file:
339 gint fontsQuantity = 7;
340 gchar* fontsList[] = {
341 "Fixed8x13", "-misc-fixed-medium-r-normal--13-120-75-75-C-80-iso8859-1",
342 "Fixed9x15", "-misc-fixed-medium-r-normal--15-140-75-75-C-90-iso8859-1",
343 "Helvetica10", "-adobe-helvetica-medium-r-normal--10-100-75-75-p-56-iso8859-1",
344 "Helvetica12", "-adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1",
345 "Helvetica18", "-adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1",
346 "TimesRoman10", "-adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1",
347 "TimesRoman24", "-adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1"
351 * Initialize the alphabet's length
353 g_AlphabetLength = strlen( g_Alphabet );
356 * Make sure that the no-character character is in the alphabet
358 ourCharacter[ 0 ] = g_NoChar;
360 if( strstr( g_Alphabet, ourCharacter ) == NULL )
361 g_error( "the g_NoChar `%c' character not found in the alphabet `%s'", g_NoChar, g_Alphabet );
364 * Grab the display name to be used
366 displayName = g_strdup( (gchar *) g_getenv( "DISPLAY" ) );
369 * Define the default output file name
371 outputFileName = g_strdup( "freeglut_font_data.c" );
374 * Process the command line arguments now. Command line arguments expected:
376 * -display <DISPLAYNAME> -- the display to connect to
377 * -file <FILENAME> -- the destination file name
382 * See what the current token is
384 if( g_strcasecmp( argv[ i ], "-display" ) == 0 )
386 g_assert( (i + 1) < argc );
387 g_free( displayName );
390 * The next token is expected to contain the X display name to use
392 displayName = g_strdup( (gchar *) argv[ ++i ] );
394 else if( g_strcasecmp( argv[ i ], "-file" ) == 0 )
396 g_assert( (i + 1) < argc );
397 g_free( outputFileName );
400 * The next token is expected to contain the destination file name
402 outputFileName = g_strdup( (gchar *) argv[ ++i ] );
406 * Get to the next argument
412 * Connect to the X display
414 g_Display = XOpenDisplay( displayName );
415 g_assert( g_Display != NULL );
418 * Have the destination file opened
420 g_Output = fopen( outputFileName, "wt" );
421 g_assert( g_Output != NULL );
424 * Output the file header first
426 OutputPrologue( outputFileName );
429 * In the file header, have the list of the fonts written:
431 fprintf( g_Output, "\n/*\n * Following fonts are defined in this file:\n * \n" );
433 for( i=0; i<fontsQuantity; i++ )
434 fprintf( g_Output, " * %i. fgFont%s <%s>\n",
435 i + 1, fontsList[ i*2 + 0 ], fontsList[ i*2 + 1 ]
438 fprintf( g_Output, " */\n\n" );
441 * Output all of the fonts we want to output
443 for( i=0; i<fontsQuantity; i++ )
444 OutputFont( fontsList[ i*2 + 0 ], fontsList[ i*2 + 1 ] );
447 * Finally, have the file epilogue outputted
452 * Close the output stream
457 * Close the X display
459 XCloseDisplay( g_Display );
462 * Clean up all the rest of the mess
464 g_free( outputFileName );
465 g_free( displayName );
470 return( EXIT_SUCCESS );
473 /*** END OF FILE ***/