Removed glib dependancy
[freeglut] / genfonts / genfonts.c
1 /*
2  * main.c
3  *
4  * A simple utility to generate the bitmap fonts to be used in freeglut.
5  *
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
9  *
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:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Sotware.
19  *
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.
26  */
27
28 #ifdef HAVE_CONFIG_H
29     #include <config.h>
30 #endif
31
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <assert.h>
39
40 /*
41  * Define the log domain
42  */
43 #undef   G_LOG_DOMAIN
44 #define  G_LOG_DOMAIN  "genfonts"
45
46 /*
47  * The alphabet we want to export.
48  */
49 char* g_Alphabet = " abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789`~!@#$%^&*()-_=+[{}];:,.<>/?\\\"";
50 int   g_AlphabetLength = 0;
51
52 /*
53  * All undefined characters will get replaced by this one:
54  */
55 char  g_NoChar = '*';
56
57 /*
58  * The stream we want to redirect our output to
59  */
60 FILE*  g_Output = NULL;
61
62 /*
63  * The display we're getting the fonts from
64  */
65 Display* g_Display;
66
67 /*
68  * Our argv[0]
69  */
70 char *g_ProgName = "";
71
72 /*
73  * This function outputs the font file prologue
74  */
75 void OutputPrologue( char* fileName )
76 {
77     /*
78      * Output the copyright and permission notices:
79      */
80     fprintf( g_Output, "/*\n * %s\n *\n * This file has been automatically generated by the genfonts utility.\n *\n", fileName );
81     fprintf( g_Output, " * Copyright (c) 1999-2000 by Pawel W. Olszta\n * Written by Pawel W. Olszta, <olszta@sourceforge.net>\n * \n" );
82     fprintf( g_Output, " * Permission is hereby granted, free of charge, to any person obtaining a\n" );
83     fprintf( g_Output, " * copy of this software and associated documentation files (the \"Software\"),\n" );
84     fprintf( g_Output, " * to deal in the Software without restriction, including without limitation\n" );
85     fprintf( g_Output, " * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n" );
86     fprintf( g_Output, " * and/or sell copies of the Software, and to permit persons to whom the\n" );
87     fprintf( g_Output, " * Software is furnished to do so, subject to the following conditions:\n *\n" );
88     fprintf( g_Output, " * The above copyright notice and this permission notice shall be included\n" );
89     fprintf( g_Output, " * in all copies or substantial portions of the Sotware.\n *\n" );
90     fprintf( g_Output, " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n" );
91     fprintf( g_Output, " * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n" );
92     fprintf( g_Output, " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n" );
93     fprintf( g_Output, " * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\n" );
94     fprintf( g_Output, " * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n" );
95     fprintf( g_Output, " * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n" );
96
97     /*
98      * The obvious include headers
99      */
100     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" );
101 }
102
103 /*
104  * This function outputs a font set
105  */
106 void OutputFont( char* freeglutFontName, char* fontName )
107 {
108     int character, lineWidth, maxWidth = 0, maxHeight = 0;
109     XFontStruct* fontStruct = NULL;
110     XGCValues contextValues;
111     XImage* image = NULL;
112     unsigned char* lineBuffer;
113     Pixmap buffer;
114     GC context;
115
116     /*
117      * Check if there is a font that meets our requirements
118      */
119     fontStruct = XLoadQueryFont( g_Display, fontName );
120
121     if( fontStruct == NULL )
122     {
123         /*
124          * Whoops, the font was not found
125          */
126         fprintf( stderr, "%s: couldn't get font `%s' using local display\n",
127                 g_ProgName, fontName );
128         exit( 1 );
129     }
130
131     /*
132      * Get the maximum size of the font characters
133      */
134     maxWidth  = fontStruct->max_bounds.rbearing - fontStruct->min_bounds.lbearing;
135     maxHeight = fontStruct->max_bounds.ascent   + fontStruct->max_bounds.descent;
136
137     /*
138      * Allocate the line buffer for storing the font bitmap lines
139      */
140     lineBuffer = malloc( maxWidth );
141
142     /*
143      * Create a pixmap buffer where we'll be rendering our fonts to.
144      */
145     buffer = XCreatePixmap(
146         g_Display,
147         RootWindow( g_Display, DefaultScreen( g_Display ) ),
148         maxWidth,
149         maxHeight,
150         1
151     );
152
153     /*
154      * We'll need a graphics context to handle the font writes and buffer clears
155      */
156     context = XCreateGC(
157         g_Display,
158         buffer,
159         0,
160         &contextValues
161     );
162
163     /*
164      * Have the font assigned to the graphics context
165      */
166     XSetFont( g_Display, context, fontStruct->fid );
167
168     /*
169      * For every character we want to have outputted...
170      */
171     for( character=0; character<g_AlphabetLength; character++ )
172     {
173         int x, y, start_x, stop_x;
174
175         /*
176          * Clear the context black (0 is black in our case)...
177          */
178         XSetForeground( g_Display, context, 0x00 );
179         XFillRectangle( g_Display, buffer, context, 0, 0, maxWidth, maxHeight );
180
181         /*
182          * Be kind and draw the characters white (which is 1 for us)
183          */
184         XSetForeground( g_Display, context, 0xff );
185
186         /*
187          * Draw the n-th character of the alphabet
188          */
189         XDrawString(
190             g_Display,
191             buffer,
192             context,
193             -fontStruct->min_bounds.lbearing,
194             fontStruct->max_bounds.ascent,
195             (g_Alphabet + character),
196             1
197         );
198
199         /*
200          * We need some a way to access the font we've just drawn:
201          */
202         image = XGetImage(
203             g_Display,
204             buffer,
205             0, 0,
206             maxWidth, maxHeight,
207             1, XYPixmap
208         );
209
210         /*
211          * Find the first non-empty column:
212          */
213         start_x = -1; stop_x = -1;
214
215         for( x=0; x<maxWidth; x++ )
216             for( y=0; y<maxHeight; y++ )
217                 if( (XGetPixel( image, x, y ) == 1) && (start_x == -1) )
218                     start_x = x;
219
220         /*
221          * Find the last empty column
222          */
223         for( x=maxWidth-1; x>=0; x-- )
224             for( y=0; y<maxHeight; y++ )
225                 if( (XGetPixel( image, x, y) == 1) && (stop_x == -1) )
226                     stop_x = x + 1;
227
228         /*
229          * If the size is too little, enhance it a bit
230          */
231         if( stop_x - start_x < 1 )
232         {
233             start_x = 0; stop_x = maxWidth - 1;
234         }
235          
236         /*
237          * Output the character we have just grabbed
238          */
239         fprintf( g_Output, "static const GLubyte %s_Character_%03i[] = {%3i",
240             freeglutFontName, (int) g_Alphabet[ character ], stop_x-start_x
241         );
242
243         for( y=maxHeight-1; y>=0; y-- )
244         {
245             /*
246              * Prepare the line buffer for being used again
247              */
248             memset( lineBuffer, 0, maxWidth );
249
250             /*
251              * Grab the rasterized character face into the line buffer
252              */
253             for( x=start_x, lineWidth=0; x<stop_x; x++, lineWidth++ )
254                 if( XGetPixel( image, x, y ) )
255                     lineBuffer[ lineWidth / 8 ] |= 1 << (7 - (lineWidth % 8));
256
257             /*
258              * Feel free to output the final line bitmap now
259              */
260             for( x=0; x<(stop_x - start_x + 7) / 8; x++ )
261                 fprintf( g_Output, ",%3i", lineBuffer[ x ] );
262         }
263
264         fprintf( g_Output, "};\n" );
265
266         /*
267          * Free the image, and get to the next character...
268          */
269         XDestroyImage( image );
270     }
271
272     /*
273      * Now we are ready to output the final data concerning the font charset
274      */
275     fprintf( g_Output, "\n/* The font characters mapping: */\n" );
276     fprintf( g_Output, "static const GLubyte* %s_Character_Map[] = {", freeglutFontName );
277
278     /*
279      * I have decided to change the characters mapping a bit...
280      */
281     for( character=1; character<256; character++ )
282     {
283         char ourCharacter[ 2 ] = { 0, 0 };
284         
285         /*
286          * Do we have the character defined or not?
287          */
288         ourCharacter[ 0 ] = (char) character;
289          
290         if( strstr( g_Alphabet, ourCharacter ) == NULL )
291         {
292             /*
293              * Nope, output the g_NoChar character instead:
294              */
295             fprintf( g_Output, "%s_Character_%03i,", freeglutFontName, (int) g_NoChar );        
296         }
297         else
298         {
299             /*
300              * Otherwise we're welcome to output the character:
301              */
302             fprintf( g_Output, "%s_Character_%03i,", freeglutFontName, (int) ourCharacter[ 0 ] );
303         }
304     }
305         
306     fprintf( g_Output, "NULL};\n\n" );
307
308     /*
309      * And finally have the font structure written to the output stream
310      */
311     fprintf( g_Output, "/* The font structure: */\n" );
312     fprintf( g_Output, "const SFG_Font fgFont%s = { \"%s\", %i, %i, %s_Character_Map };\n\n",
313         freeglutFontName, fontName, g_AlphabetLength, maxHeight, freeglutFontName
314     );
315
316     /*
317      * Done, clean up behind...
318      */
319     XFreeGC( g_Display, context );
320     XFreePixmap( g_Display, buffer );
321     free( lineBuffer );
322 }
323
324 /*
325  * This function outputs the font file epilogue
326  */
327 void OutputEpilogue( void )
328 {
329     fprintf( g_Output, "/*** END OF FILE ***/\n" );
330 }
331
332 /*
333  * The main function processes the command line arguments
334  * and outputs all the fonts we need to have rasterized.
335  */
336 int main( int argc, char** argv )
337 {
338     char ourCharacter[ 2 ] = { 0, 0 };
339     char* outputFileName = NULL;
340     char* displayName = NULL;
341     int i = 1;
342
343     /*
344      * The fonts that are going to be rasterized and added to the output file:
345      */
346     int   fontsQuantity = 7;
347     char* fontsList[] = {
348         "Fixed8x13",    "-misc-fixed-medium-r-normal--13-120-75-75-C-80-iso8859-1",
349         "Fixed9x15",    "-misc-fixed-medium-r-normal--15-140-75-75-C-90-iso8859-1",
350         "Helvetica10",  "-adobe-helvetica-medium-r-normal--10-100-75-75-p-56-iso8859-1",
351         "Helvetica12",  "-adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1",
352         "Helvetica18",  "-adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1",
353         "TimesRoman10", "-adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1",
354         "TimesRoman24", "-adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1"
355     };
356
357     g_ProgName = argv[0];
358
359     /*
360      * Initialize the alphabet's length
361      */
362     g_AlphabetLength = strlen( g_Alphabet );
363
364     /*
365      * Make sure that the no-character character is in the alphabet
366      */
367     ourCharacter[ 0 ] = g_NoChar;
368          
369     if( strstr( g_Alphabet, ourCharacter ) == NULL )
370     {
371         fprintf( stderr, "%s the g_NoChar `%c' character not found in the alphabet `%s'\n",
372                  g_ProgName, g_NoChar, g_Alphabet );
373         exit( 1 );
374     }
375  
376     /*
377      * Grab the display name to be used
378      */
379     displayName = strdup( getenv( "DISPLAY" ) );
380
381     /*
382      * Define the default output file name
383      */
384     outputFileName = strdup( "freeglut_font_data.c" );
385
386     /*
387      * Process the command line arguments now. Command line arguments expected:
388      *
389      *      -display <DISPLAYNAME>      -- the display to connect to
390      *      -file    <FILENAME>         -- the destination file name
391      */
392     while( i < argc )
393     {
394         /*
395          * See what the current token is
396          */
397         if( strcasecmp( argv[ i ], "-display" ) == 0 )
398         {
399             assert( (i + 1) < argc );
400             free( displayName );
401
402             /*
403              * The next token is expected to contain the X display name to use
404              */
405             displayName = strdup( argv[ ++i ] );
406         }
407         else if( strcasecmp( argv[ i ], "-file" ) == 0 )
408         {
409             assert( (i + 1) < argc );
410             free( outputFileName );
411
412             /*
413              * The next token is expected to contain the destination file name
414              */
415             outputFileName = strdup( argv[ ++i ] );
416         }
417
418         /*
419          * Get to the next argument
420          */
421         i++;
422     }
423
424     /*
425      * Connect to the X display
426      */
427     g_Display = XOpenDisplay( displayName );
428     assert( g_Display != NULL );
429
430     /*
431      * Have the destination file opened
432      */
433     g_Output = fopen( outputFileName, "wt" );
434     assert( g_Output != NULL );
435
436     /*
437      * Output the file header first
438      */
439     OutputPrologue( outputFileName );
440
441     /*
442      * In the file header, have the list of the fonts written:
443      */
444     fprintf( g_Output, "\n/*\n * Following fonts are defined in this file:\n * \n" );
445
446     for( i=0; i<fontsQuantity; i++ )
447         fprintf( g_Output, " * %i. fgFont%s <%s>\n",
448             i + 1, fontsList[ i*2 + 0 ], fontsList[ i*2 + 1 ]
449         );
450
451     fprintf( g_Output, " */\n\n" );
452
453     /*
454      * Output all of the fonts we want to output
455      */
456     for( i=0; i<fontsQuantity; i++ )
457         OutputFont( fontsList[ i*2 + 0 ], fontsList[ i*2 + 1 ] );
458
459     /*
460      * Finally, have the file epilogue outputted
461      */
462     OutputEpilogue();
463
464     /*
465      * Close the output stream
466      */
467     fclose( g_Output );
468
469     /*
470      * Close the X display
471      */
472     XCloseDisplay( g_Display );
473
474     /*
475      * Clean up all the rest of the mess
476      */
477     free( outputFileName );
478     free( displayName );
479
480     /*
481      * Return successful!
482      */
483     return( EXIT_SUCCESS );
484 }
485
486 /*** END OF FILE ***/