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