83cd3b3ff62a593f9b1534443a2aef7a08eee15b
[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 #include <glib.h>
35
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdio.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 gchar* g_Alphabet = " abcdefghijklmnopqrstuwvxyzABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789`~!@#$%^&*()-_=+[{}];:,.<>/?\\\"";
50 gint   g_AlphabetLength = 0;
51
52 /*
53  * All undefined characters will get replaced by this one:
54  */
55 gchar  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  * This function outputs the font file prologue
69  */
70 void OutputPrologue( gchar* fileName )
71 {
72     /*
73      * Output the copyright and permission notices:
74      */
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" );
91
92     /*
93      * The obvious include headers
94      */
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" );
96 }
97
98 /*
99  * This function outputs a font set
100  */
101 void OutputFont( gchar* freeglutFontName, gchar* fontName )
102 {
103     gint character, lineWidth, maxWidth = 0, maxHeight = 0;
104     XFontStruct* fontStruct = NULL;
105     XGCValues contextValues;
106     XImage* image = NULL;
107     guchar* lineBuffer;
108     Pixmap buffer;
109     GC context;
110
111     /*
112      * Check if there is a font that meets our requirements
113      */
114     fontStruct = XLoadQueryFont( g_Display, fontName );
115
116     if( fontStruct == NULL )
117     {
118         /*
119          * Whoops, the font was not found
120          */
121         g_error( "couldn't get font `%s' using local display", fontName );
122     }
123
124     /*
125      * Get the maximum size of the font characters
126      */
127     maxWidth  = fontStruct->max_bounds.rbearing - fontStruct->min_bounds.lbearing;
128     maxHeight = fontStruct->max_bounds.ascent   + fontStruct->max_bounds.descent;
129
130     /*
131      * Allocate the line buffer for storing the font bitmap lines
132      */
133     lineBuffer = g_new0( guchar, maxWidth );
134
135     /*
136      * Create a pixmap buffer where we'll be rendering our fonts to.
137      */
138     buffer = XCreatePixmap(
139         g_Display,
140         RootWindow( g_Display, DefaultScreen( g_Display ) ),
141         maxWidth,
142         maxHeight,
143         1
144     );
145
146     /*
147      * We'll need a graphics context to handle the font writes and buffer clears
148      */
149     context = XCreateGC(
150         g_Display,
151         buffer,
152         0,
153         &contextValues
154     );
155
156     /*
157      * Have the font assigned to the graphics context
158      */
159     XSetFont( g_Display, context, fontStruct->fid );
160
161     /*
162      * For every character we want to have outputted...
163      */
164     for( character=0; character<g_AlphabetLength; character++ )
165     {
166         gint x, y, start_x, stop_x;
167
168         /*
169          * Clear the context black (0 is black in our case)...
170          */
171         XSetForeground( g_Display, context, 0x00 );
172         XFillRectangle( g_Display, buffer, context, 0, 0, maxWidth, maxHeight );
173
174         /*
175          * Be kind and draw the characters white (which is 1 for us)
176          */
177         XSetForeground( g_Display, context, 0xff );
178
179         /*
180          * Draw the n-th character of the alphabet
181          */
182         XDrawString(
183             g_Display,
184             buffer,
185             context,
186             -fontStruct->min_bounds.lbearing,
187             fontStruct->max_bounds.ascent,
188             (g_Alphabet + character),
189             1
190         );
191
192         /*
193          * We need some a way to access the font we've just drawn:
194          */
195         image = XGetImage(
196             g_Display,
197             buffer,
198             0, 0,
199             maxWidth, maxHeight,
200             1, XYPixmap
201         );
202
203         /*
204          * Find the first non-empty column:
205          */
206         start_x = -1; stop_x = -1;
207
208         for( x=0; x<maxWidth; x++ )
209             for( y=0; y<maxHeight; y++ )
210                 if( (XGetPixel( image, x, y ) == 1) && (start_x == -1) )
211                     start_x = x;
212
213         /*
214          * Find the last empty column
215          */
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) )
219                     stop_x = x + 1;
220
221         /*
222          * If the size is too little, enhance it a bit
223          */
224         if( stop_x - start_x < 1 )
225         {
226             start_x = 0; stop_x = maxWidth - 1;
227         }
228          
229         /*
230          * Output the character we have just grabbed
231          */
232         fprintf( g_Output, "static const guchar %s_Character_%03i[] = {%3i",
233             freeglutFontName, (gint) g_Alphabet[ character ], stop_x-start_x
234         );
235
236         for( y=maxHeight-1; y>=0; y-- )
237         {
238             /*
239              * Prepare the line buffer for being used again
240              */
241             memset( lineBuffer, 0, maxWidth );
242
243             /*
244              * Grab the rasterized character face into the line buffer
245              */
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));
249
250             /*
251              * Feel free to output the final line bitmap now
252              */
253             for( x=0; x<(stop_x - start_x + 7) / 8; x++ )
254                 fprintf( g_Output, ",%3i", lineBuffer[ x ] );
255         }
256
257         fprintf( g_Output, "};\n" );
258
259         /*
260          * Free the image, and get to the next character...
261          */
262         XDestroyImage( image );
263     }
264
265     /*
266      * Now we are ready to output the final data concerning the font charset
267      */
268     fprintf( g_Output, "\n/* The font characters mapping: */\n" );
269     fprintf( g_Output, "static const guchar* %s_Character_Map[] = {", freeglutFontName );
270
271     /*
272      * I have decided to change the characters mapping a bit...
273      */
274     for( character=1; character<256; character++ )
275     {
276         gchar ourCharacter[ 2 ] = { 0, 0 };
277         
278         /*
279          * Do we have the character defined or not?
280          */
281         ourCharacter[ 0 ] = (gchar) character;
282          
283         if( strstr( g_Alphabet, ourCharacter ) == NULL )
284         {
285             /*
286              * Nope, output the g_NoChar character instead:
287              */
288             fprintf( g_Output, "%s_Character_%03i,", freeglutFontName, (gint) g_NoChar );       
289         }
290         else
291         {
292             /*
293              * Otherwise we're welcome to output the character:
294              */
295             fprintf( g_Output, "%s_Character_%03i,", freeglutFontName, (gint) ourCharacter[ 0 ] );
296         }
297     }
298         
299     fprintf( g_Output, "NULL};\n\n" );
300
301     /*
302      * And finally have the font structure written to the output stream
303      */
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
307     );
308
309     /*
310      * Done, clean up behind...
311      */
312     XFreeGC( g_Display, context );
313     XFreePixmap( g_Display, buffer );
314     g_free( lineBuffer );
315 }
316
317 /*
318  * This function outputs the font file epilogue
319  */
320 void OutputEpilogue( void )
321 {
322     fprintf( g_Output, "/*** END OF FILE ***/\n" );
323 }
324
325 /*
326  * The main function processes the command line arguments
327  * and outputs all the fonts we need to have rasterized.
328  */
329 int main( int argc, char** argv )
330 {
331     gchar ourCharacter[ 2 ] = { 0, 0 };
332     gchar* outputFileName = NULL;
333     gchar* displayName = NULL;
334     gint i = 1;
335
336     /*
337      * The fonts that are going to be rasterized and added to the output file:
338      */
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"
348     };
349
350     /*
351      * Initialize the alphabet's length
352      */
353     g_AlphabetLength = strlen( g_Alphabet );
354
355     /*
356      * Make sure that the no-character character is in the alphabet
357      */
358     ourCharacter[ 0 ] = g_NoChar;
359          
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 );
362  
363     /*
364      * Grab the display name to be used
365      */
366     displayName = g_strdup( (gchar *) g_getenv( "DISPLAY" ) );
367
368     /*
369      * Define the default output file name
370      */
371     outputFileName = g_strdup( "freeglut_font_data.c" );
372
373     /*
374      * Process the command line arguments now. Command line arguments expected:
375      *
376      *      -display <DISPLAYNAME>      -- the display to connect to
377      *      -file    <FILENAME>         -- the destination file name
378      */
379     while( i < argc )
380     {
381         /*
382          * See what the current token is
383          */
384         if( g_strcasecmp( argv[ i ], "-display" ) == 0 )
385         {
386             g_assert( (i + 1) < argc );
387             g_free( displayName );
388
389             /*
390              * The next token is expected to contain the X display name to use
391              */
392             displayName = g_strdup( (gchar *) argv[ ++i ] );
393         }
394         else if( g_strcasecmp( argv[ i ], "-file" ) == 0 )
395         {
396             g_assert( (i + 1) < argc );
397             g_free( outputFileName );
398
399             /*
400              * The next token is expected to contain the destination file name
401              */
402             outputFileName = g_strdup( (gchar *) argv[ ++i ] );
403         }
404
405         /*
406          * Get to the next argument
407          */
408         i++;
409     }
410
411     /*
412      * Connect to the X display
413      */
414     g_Display = XOpenDisplay( displayName );
415     g_assert( g_Display != NULL );
416
417     /*
418      * Have the destination file opened
419      */
420     g_Output = fopen( outputFileName, "wt" );
421     g_assert( g_Output != NULL );
422
423     /*
424      * Output the file header first
425      */
426     OutputPrologue( outputFileName );
427
428     /*
429      * In the file header, have the list of the fonts written:
430      */
431     fprintf( g_Output, "\n/*\n * Following fonts are defined in this file:\n * \n" );
432
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 ]
436         );
437
438     fprintf( g_Output, " */\n\n" );
439
440     /*
441      * Output all of the fonts we want to output
442      */
443     for( i=0; i<fontsQuantity; i++ )
444         OutputFont( fontsList[ i*2 + 0 ], fontsList[ i*2 + 1 ] );
445
446     /*
447      * Finally, have the file epilogue outputted
448      */
449     OutputEpilogue();
450
451     /*
452      * Close the output stream
453      */
454     fclose( g_Output );
455
456     /*
457      * Close the X display
458      */
459     XCloseDisplay( g_Display );
460
461     /*
462      * Clean up all the rest of the mess
463      */
464     g_free( outputFileName );
465     g_free( displayName );
466
467     /*
468      * Return successful!
469      */
470     return( EXIT_SUCCESS );
471 }
472
473 /*** END OF FILE ***/