]> icculus.org git repositories - taylor/freespace2.git/blob - src/fonttool/fontcreate.cpp
Initial revision
[taylor/freespace2.git] / src / fonttool / fontcreate.cpp
1 /*
2  * $Logfile: /Freespace2/code/fonttool/FontCreate.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Tool for creating new fonts
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:08  root
11  * Initial revision
12  *
13  * 
14  * 4     1/06/99 2:25p Dave
15  * Stubs and release build fixes.
16  * 
17  * 3     12/02/98 9:58a Dave
18  * Got fonttool working under glide/direct3d.
19  * 
20  * 2     10/24/98 5:15p Dave
21  * 
22  * 1     10/24/98 4:58p Dave
23  * 
24  * 4     10/31/97 10:30a Adam
25  * fixed a bug passing wrong pointer to pcx_read trashing memory.
26  * 
27  * 3     10/30/97 4:56p John
28  * Fixed up font stuff to build.  Fixed bug where it didn't show the last
29  * 3 characters in kerning table.
30  * 
31  * 2     6/05/97 4:53p John
32  * First rev of new antialiased font stuff.
33  * 
34   * 1     6/02/97 4:04p John
35  *
36  * $NoKeywords: $
37  */
38
39 #include <stdlib.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <io.h>
43 #include <conio.h>
44
45 #include "pstypes.h"
46 #include "osapi.h"
47 #include "cfile.h"
48 #include "2d.h"
49 #include "key.h"
50 #include "mouse.h"
51 #include "palman.h"
52 #include "timer.h"
53 #include "pcxutils.h"
54 #include "font.h"
55 #include "bmpman.h"
56
57 #include "fonttool.h"
58
59 static bitmap bmp;
60 static ubyte *data;
61 static int offset;
62 static ubyte pal[768];
63
64 static ubyte bkg;
65 static ubyte border;
66
67 int num_bad_pixels=0;
68
69 static void myexit(int value)
70 {
71 //      getch();
72         exit(value);
73 }
74
75 ubyte PIX(int x,int y)  
76 {
77         if ( x<0 || x >= bmp.w ) return bkg;
78         if ( y<0 || y >= bmp.h ) return bkg;
79
80         return data[x+y*offset];
81 }
82
83 // Attempts to find a box at pixel (x,y) if it can't, then it
84 // returns 0, else returns 1 and w&h are filled in.
85 int find_box( int x, int y, int *w, int *h )
86 {
87         int w1, w2, h1, h2;
88         int y1,x1,tmp;
89
90         if ( PIX(x,y) != border ) return 0;
91
92         x1 = x;
93         y1 = y;
94
95 //      printf( "--------- Finding box at %d, %d ----------\n", x1, y1 );
96
97 //======================= FIND LEFT EDGE ======================
98         y++;
99         while ( PIX(x,y)==border )      {
100                 if ( PIX(x+1,y)==border)        {
101                         goto LeftSideFound;
102                 }
103                 y++;
104                 if ( y > bmp.h )        {
105                         printf( "Box at (%d,%d) goes off bottom of screen.\n", x1, y1 );
106                         myexit(1);
107                 }
108         }
109 //      printf( "Box at (%d,%d) doesn't have bottom border.\n", x1, y1 );
110 //      myexit(1);
111         return 0;
112
113 LeftSideFound:
114         h1 = y - y1 - 1;
115 //      printf( "Has a left height of %d\n", h1 );
116
117 //======================= FIND BOTTOM EDGE ======================
118         x++;
119         while ( PIX(x,y)==border )      {
120                 if ( PIX(x,y-1)==border)        {
121                         goto BottomSideFound;
122                 }
123                 x++;
124                 if ( x > bmp.w )        {
125                         printf( "Box at (%d,%d) goes off left of screen.\n", x1, y1 );
126                         myexit(1);
127                 }
128         }
129         printf( "Box at (%d,%d) doesn't have right border connected to bottom.\n", x1, y1 );
130         myexit(1);
131
132 BottomSideFound:
133         w1 = x - x1 - 1;
134 //      printf( "Has a bottom width of %d\n", w1 );
135
136 //======================= FIND RIGHT EDGE ======================
137         tmp = y;
138         y--;
139         while ( PIX(x,y)==border )      {
140                 if ( PIX(x-1,y)==border)        {
141                         goto RightSideFound;
142                 }
143                 y--;
144                 if ( y < 0 )    {
145                         printf( "Box at (%d,%d) goes off top of screen.\n", x1, y1 );
146                         myexit(1);
147                 }
148         }
149         printf( "Box at (%d,%d) doesn't have top border connected to right border.\n", x1, y1 );
150         myexit(1);
151
152 RightSideFound:
153         h2 = tmp - y - 1;
154 //      printf( "Has a right height of %d\n", h2 );
155
156
157 //======================= FIND TOP EDGE ======================
158         tmp = x;
159         x--;
160         while ( PIX(x,y)==border )      {
161                 if ( PIX(x,y+1)==border)        {
162                         goto TopSideFound;
163                 }
164                 x--;
165                 if ( x < 0 )    {
166                         printf( "Box at (%d,%d) goes off left of screen.\n", x1, y1 );
167                         myexit(1);
168                 }
169         }
170         printf( "Box at (%d,%d) doesn't have left border connected to top border.\n", x1, y1 );
171         myexit(1);
172
173 TopSideFound:
174         w2 = tmp - x - 1;
175 //      printf( "Has a top width of %d\n", w2 );
176
177 //==================== 
178         if ( h1 != h2 ) {
179                 printf( "Box at (%d,%d) has unequal top/bottom .\n", x1, y1 );
180                 myexit(1);
181         }
182         if ( w1 != w2 ) {
183                 printf( "Box at (%d,%d) has unequal left/right.\n", x1, y1 );
184                 myexit(1);
185         }
186
187         if ( w1 < 1 )   {
188                 printf( "Box at (%d,%d) is less than 1 pixel wide.\n", x1, y1 );
189                 myexit(1);
190         }
191                 
192         if ( h1 < 1 )   {
193                 printf( "Box at (%d,%d) is less than 1 pixel tall.\n", x1, y1 );
194                 myexit(1);
195         }
196
197         *w = w1;
198         *h = h1;
199
200         return 1;
201 }
202
203
204
205 void found_box( font *fnt, int x, int y, int w, int h );
206
207 void find_all_boxes(font *fnt)
208 {
209         int x = 0;
210         int y = 0;
211
212         data = (ubyte *)bmp.data;
213         offset = bmp.w;
214
215         bkg = data[0];
216         printf( "Background color = %d\n", bkg );
217
218         for ( y=0; y<bmp.h; y++ )       {
219                 for ( x=0; x<bmp.w; x++ )       {
220                         if ( PIX(x,y) != bkg )  {
221                                 border = PIX(x,y);
222                                 goto FoundBorder;
223                         }
224                 }
225         }
226         printf( "Couldn't find anything but background pixels\n" );
227         myexit(1);
228
229 FoundBorder:
230         printf( "Border color = %d, starts at %d,%d\n", border, x, y );
231
232         int w,h;
233         int row_height = 0;
234
235         while(1)        {
236                 if ( find_box( x, y, &w, &h ) ) {
237                         found_box( fnt, x+1, y+1, w, h );
238                         x = x + w + 1;
239                         if ( row_height < 1 )   {
240                                 row_height = h;
241                         } else {
242 //              if ( row_height != h )  {
243 //                      printf( "Uneven row height!\n" );
244 //                      myexit(1);
245 //              }
246                         }
247                 } else {
248                         x++;
249                         if ( x >= bmp.w )       {
250                                 x = 0;
251                                 if ( row_height )       {
252                                         //printf( "Moving down %d pixels\n", row_height+2);
253                                         y += row_height+2;
254                                         row_height = 0;
255                                 } else {
256                                         y++;
257                                 }
258                                 if ( y >= bmp.h )       {
259                                         break;
260                                 }
261                         }
262                 }
263         }       
264 }
265
266
267 void fonttool_create_new( font *fnt )
268 {
269         strncpy( (char *)&fnt->id, "VFNT", 4 );
270         fnt->version = FONT_VERSION;
271         fnt->num_chars = 0;
272         fnt->first_ascii = ' ';
273         fnt->w = 0;
274         fnt->h = 0;
275         fnt->num_kern_pairs = 0;
276         fnt->pixel_data = NULL;
277         fnt->pixel_data_size = 0;
278         fnt->kern_data = NULL;
279         fnt->kern_data_size = 0;
280         fnt->char_data = NULL;
281         fnt->char_data_size = 0;
282 }
283         
284
285 void fonttool_add_char( font *fnt, int x1, int y1, int real_w, int h, ubyte *data, int rowsize )
286 {
287         int x, y, n, offset;
288         int w;
289         
290         n = fnt->num_chars;
291
292         w = real_w;
293         while ( w & 1)  w++;
294
295         printf( "Adding character %d (%c) from the %dx%d pixels at (%d,%d)\n", n, n + fnt->first_ascii, real_w, h, x1, y1 );
296
297         // add new character data
298         font_char * new_char;
299         new_char = (font_char *)malloc( fnt->char_data_size + sizeof(font_char) );
300         if ( !new_char )        {
301                 printf( "Not enough memory to create a new character\n" );
302                 myexit(1);
303         }
304         if ( fnt->char_data )   {
305                 memcpy( new_char, fnt->char_data, fnt->char_data_size );
306                 free(fnt->char_data);
307                 fnt->char_data = NULL;
308         }
309         fnt->char_data = new_char;
310         fnt->char_data_size += sizeof(font_char);
311         new_char = fnt->char_data + fnt->num_chars;
312         fnt->num_chars++;
313
314         // add new character pixel data
315         ubyte *new_pixel_data = (ubyte *)malloc( fnt->pixel_data_size+w*h );
316         if ( !new_pixel_data )  {
317                 printf( "Not enough memory to create new %dx%d character\n", w, h);
318                 myexit(1);
319         }
320         if ( fnt->pixel_data )  {
321                 memcpy( new_pixel_data, fnt->pixel_data, fnt->pixel_data_size );
322                 free(fnt->pixel_data);
323                 fnt->pixel_data = NULL;
324         }
325         offset = fnt->pixel_data_size;
326         fnt->pixel_data_size += w*h;
327         fnt->pixel_data = new_pixel_data;
328         new_pixel_data = fnt->pixel_data + offset;
329
330         new_char->byte_width = w;
331         new_char->spacing = real_w;
332         new_char->offset = offset;
333         new_char->kerning_entry = -1;
334         new_char->user_data = 0;
335
336         for ( y=0; y<h; y++ )   {
337                 for (x=0; x<w; x++ )    {
338                         ubyte c;
339                         if ( x >= real_w)
340                                 c = 0;
341                         else
342                                 c = data[x+y*rowsize];
343                         if ( c > 15 ) {
344                                 num_bad_pixels++;
345                                 c = 15;
346                         }
347                         *new_pixel_data++ = c;
348                 }
349         }
350
351         if ( fnt->h < 1 )
352                 fnt->h = h;
353
354         int i, wtotal = 0;
355
356         for (i=0; i<fnt->num_chars; i++ )       {
357                 wtotal += fnt->char_data[i].spacing;
358         }
359
360         fnt->w = wtotal / fnt->num_chars;
361         if ( fnt->w < 1 )
362                 fnt->w = 1;
363 }
364
365
366 void fonttool_dump( char *filename, font *fnt )
367 {
368         FILE *fp;
369         char tmp_name[128], *p;
370
371         strcpy( tmp_name, filename );
372         p = strchr( tmp_name, '.' );
373         if ( p ) *p = 0;
374         strcat( tmp_name, ".vf" );
375         
376         fp = fopen( tmp_name, "wb" );
377         if ( fp == NULL )       {
378                 printf( "Couldn't open font file '%s' for writing!\n", tmp_name );
379                 myexit(1);
380         }
381
382         fwrite( &fnt->id, 4, 1, fp );
383         fwrite( &fnt->version, sizeof(int), 1, fp );
384         fwrite( &fnt->num_chars, sizeof(int), 1, fp );
385         fwrite( &fnt->first_ascii, sizeof(int), 1, fp );
386         fwrite( &fnt->w, sizeof(int), 1, fp );
387         fwrite( &fnt->h, sizeof(int), 1, fp );
388         fwrite( &fnt->num_kern_pairs, sizeof(int), 1, fp );
389         fwrite( &fnt->kern_data_size, sizeof(int), 1, fp );
390         fwrite( &fnt->char_data_size, sizeof(int), 1, fp );
391         fwrite( &fnt->pixel_data_size, sizeof(int), 1, fp );
392
393         if ( fnt->kern_data_size )      {
394                 fwrite( fnt->kern_data, fnt->kern_data_size, 1, fp );
395         }       
396         if ( fnt->char_data_size )      {
397                 fwrite( fnt->char_data, fnt->char_data_size, 1, fp );
398         }       
399         if ( fnt->pixel_data_size )     {
400                 fwrite( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
401         }       
402
403         fclose(fp);
404 }
405
406 void fonttool_read( char *filename, font *fnt )
407 {
408         FILE *fp;
409         char tmp_name[128], *p;
410
411         strcpy( tmp_name, filename );
412         p = strchr( tmp_name, '.' );
413         if ( p ) *p = 0;
414         strcat( tmp_name, ".vf" );
415         
416         fp = fopen( tmp_name, "rb" );
417         if ( fp == NULL )       {
418                 printf( "Couldn't open font file '%s' for reading!\n", tmp_name );
419                 myexit(1);
420         }
421
422         fread( &fnt->id, 4, 1, fp );
423         fread( &fnt->version, sizeof(int), 1, fp );
424         fread( &fnt->num_chars, sizeof(int), 1, fp );
425         fread( &fnt->first_ascii, sizeof(int), 1, fp );
426         fread( &fnt->w, sizeof(int), 1, fp );
427         fread( &fnt->h, sizeof(int), 1, fp );
428         fread( &fnt->num_kern_pairs, sizeof(int), 1, fp );
429         fread( &fnt->kern_data_size, sizeof(int), 1, fp );
430         fread( &fnt->char_data_size, sizeof(int), 1, fp );
431         fread( &fnt->pixel_data_size, sizeof(int), 1, fp );
432
433         if ( fnt->kern_data_size )      {
434                 fnt->kern_data = (font_kernpair *)malloc( fnt->kern_data_size );
435                 if (!fnt->kern_data)    {
436                         printf( "Out of memory reading %d bytes of font data from %s\n", tmp_name );
437                         myexit(1);
438                 }
439                 fread( fnt->kern_data, fnt->kern_data_size, 1, fp );
440         } else {
441                 fnt->kern_data = NULL;
442         }
443         if ( fnt->char_data_size )      {
444                 fnt->char_data = (font_char *)malloc( fnt->char_data_size );
445                 if (!fnt->char_data)    {
446                         printf( "Out of memory reading %d bytes of font data from %s\n", tmp_name );
447                         myexit(1);
448                 }
449                 fread( fnt->char_data, fnt->char_data_size, 1, fp );
450         } else {
451                 fnt->char_data = NULL;
452         }
453         if ( fnt->pixel_data_size )     {
454                 fnt->pixel_data = (ubyte *)malloc( fnt->pixel_data_size );
455                 if (!fnt->pixel_data)   {
456                         printf( "Out of memory reading %d bytes of font data from %s\n", tmp_name );
457                         myexit(1);
458                 }
459                 fread( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
460         } else {
461                 fnt->pixel_data = NULL;
462         }
463
464         fclose(fp);
465
466         // Create a bitmap for hardware cards.
467         // JAS:  Try to squeeze this into the smallest square power of two texture.
468         // This should probably be done at font generation time, not here.
469         int w, h;
470         if ( fnt->pixel_data_size < 64*64 )     {
471                 w = h = 64;
472         } else if ( fnt->pixel_data_size < 128*128 )    {
473                 w = h = 128;
474         } else {
475                 w = h = 256;
476         }
477
478         fnt->bm_w = w;
479         fnt->bm_h = h;
480         fnt->bm_data = (ubyte *)malloc(fnt->bm_w*fnt->bm_h);
481         fnt->bm_u = (int *)malloc(sizeof(int)*fnt->num_chars);
482         fnt->bm_v = (int *)malloc(sizeof(int)*fnt->num_chars);
483
484         int i,x,y;
485         x = y = 0;
486         for (i=0; i<fnt->num_chars; i++ )       {
487                 ubyte * fp;
488                 int x1, y1;
489                 fp = &fnt->pixel_data[fnt->char_data[i].offset];
490                 if ( x + fnt->char_data[i].byte_width >= fnt->bm_w )    {
491                         x = 0;
492                         y += fnt->h;
493                         if ( y+fnt->h > fnt->bm_h ) {
494                                 Error( LOCATION, "Font too big!\n" );
495                         }
496                 }
497                 fnt->bm_u[i] = x;
498                 fnt->bm_v[i] = y;
499
500                 for( y1=0; y1<fnt->h; y1++ )    {
501                         for (x1=0; x1<fnt->char_data[i].byte_width; x1++ )      {
502                                 uint c = *fp++;
503                                 if ( c > 14 ) c = 14;
504                                 fnt->bm_data[(x+x1)+(y+y1)*fnt->bm_w] = unsigned char(c);       
505                         }
506                 }
507                 x += fnt->char_data[i].byte_width;
508         }
509
510         fnt->bitmap_id = bm_create( 8, fnt->bm_w, fnt->bm_h, fnt->bm_data, BMP_AABITMAP );
511 }
512
513 void fonttool_copy_kern( font *src, font *dst )
514 {
515         if ( dst->kern_data )   {
516                 free( dst->kern_data );
517                 dst->kern_data = NULL;
518         }
519         if ( (src->kern_data_size < 1) || (!src->kern_data) )   {
520                 dst->num_kern_pairs = 0;
521                 dst->kern_data_size = 0;
522                 dst->kern_data = NULL;
523                 fonttool_resync_kerning(dst);
524                 return;
525         }
526         dst->kern_data = (font_kernpair *)malloc( src->kern_data_size );
527         if (!dst->kern_data)    {
528                 printf( "Out of memory copying %d bytes of font data.\n" );
529                 myexit(1);
530         }
531         memcpy( dst->kern_data, src->kern_data, src->kern_data_size );
532
533         dst->kern_data_size  = src->kern_data_size;
534         dst->num_kern_pairs = src->num_kern_pairs;
535         fonttool_resync_kerning(dst);
536 }
537
538
539 void found_box( font *fnt, int x, int y, int w, int h )
540 {
541         fonttool_add_char( fnt, x, y, w, h, &data[x+y*offset], offset );
542 }
543
544
545 void fonttool_create_font(char *pcx_filename, char *font_filename)
546 {
547         font fnt1, fnt2;
548         printf( "Creating font file from '%s' \n", pcx_filename );
549         if ( font_filename )    {
550         }
551                 
552         int w, h;
553         int pcx_error = pcx_read_header( pcx_filename, &w, &h, NULL );
554         if ( pcx_error != PCX_ERROR_NONE )      {
555                 printf( "Error reading PCX file, '%s'\n", pcx_filename );
556                 myexit(1);
557         }       
558         
559         bmp.w = (short)w;
560         bmp.h = (short)h;
561         bmp.data = (uint)malloc( w*h + 768 );
562         bmp.palette = (ubyte *)(bmp.data +w*h );
563         if ( !bmp.data )        {
564                 printf( "Error mallocing PCX data, '%s'\n", pcx_filename );
565                 myexit(1);
566         }
567
568         pcx_error = pcx_read_bitmap_8bpp( pcx_filename, (ubyte *)bmp.data, pal );
569         if ( pcx_error != PCX_ERROR_NONE )      {
570                 printf( "Error reading PCX file, '%s'\n", pcx_filename );
571                 myexit(1);
572         }       
573
574         fonttool_create_new( &fnt1 );
575
576         find_all_boxes(&fnt1);
577
578         if (font_filename)      {
579                 printf( "Using kern data from font '%s'\n", font_filename );
580                 fonttool_read( font_filename, &fnt2 );
581                 fonttool_copy_kern( &fnt2, &fnt1 );
582         }
583
584         printf( "\nFont is, on average, %dx%d and has %d characters, %d kerning pairs.\n", fnt1.w, fnt1.h, fnt1.num_chars, fnt1.num_kern_pairs );
585         if ( num_bad_pixels > 0 )
586                 printf( "It had %d bad pixel(s) in it.\n(Bad means the pixel index was greater than 15).\n" , num_bad_pixels );
587         
588         fonttool_dump( pcx_filename, &fnt1 );
589
590         myexit(0);
591 }
592