2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/fonttool/FontCreate.cpp $
15 * Tool for creating new fonts
18 * Revision 1.5 2006/04/26 19:38:36 taylor
19 * fix some minor fonttool compile errors
21 * Revision 1.4 2004/06/11 00:50:40 tigital
22 * byte-swapping changes for bigendian systems
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)
27 * Revision 1.2 2002/06/09 04:41:16 relnev
28 * added copyright header
30 * Revision 1.1.1.1 2002/05/03 03:28:08 root
34 * 4 1/06/99 2:25p Dave
35 * Stubs and release build fixes.
37 * 3 12/02/98 9:58a Dave
38 * Got fonttool working under glide/direct3d.
40 * 2 10/24/98 5:15p Dave
42 * 1 10/24/98 4:58p Dave
44 * 4 10/31/97 10:30a Adam
45 * fixed a bug passing wrong pointer to pcx_read trashing memory.
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.
51 * 2 6/05/97 4:53p John
52 * First rev of new antialiased font stuff.
54 * 1 6/02/97 4:04p John
83 static ubyte pal[768];
90 static void myexit(int value)
96 ubyte PIX(int x,int y)
98 if ( x<0 || x >= bmp.w ) return bkg;
99 if ( y<0 || y >= bmp.h ) return bkg;
101 return data[x+y*offset];
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 )
111 if ( PIX(x,y) != border ) return 0;
116 // printf( "--------- Finding box at %d, %d ----------\n", x1, y1 );
118 //======================= FIND LEFT EDGE ======================
120 while ( PIX(x,y)==border ) {
121 if ( PIX(x+1,y)==border) {
126 printf( "Box at (%d,%d) goes off bottom of screen.\n", x1, y1 );
130 // printf( "Box at (%d,%d) doesn't have bottom border.\n", x1, y1 );
136 // printf( "Has a left height of %d\n", h1 );
138 //======================= FIND BOTTOM EDGE ======================
140 while ( PIX(x,y)==border ) {
141 if ( PIX(x,y-1)==border) {
142 goto BottomSideFound;
146 printf( "Box at (%d,%d) goes off left of screen.\n", x1, y1 );
150 printf( "Box at (%d,%d) doesn't have right border connected to bottom.\n", x1, y1 );
155 // printf( "Has a bottom width of %d\n", w1 );
157 //======================= FIND RIGHT EDGE ======================
160 while ( PIX(x,y)==border ) {
161 if ( PIX(x-1,y)==border) {
166 printf( "Box at (%d,%d) goes off top of screen.\n", x1, y1 );
170 printf( "Box at (%d,%d) doesn't have top border connected to right border.\n", x1, y1 );
175 // printf( "Has a right height of %d\n", h2 );
178 //======================= FIND TOP EDGE ======================
181 while ( PIX(x,y)==border ) {
182 if ( PIX(x,y+1)==border) {
187 printf( "Box at (%d,%d) goes off left of screen.\n", x1, y1 );
191 printf( "Box at (%d,%d) doesn't have left border connected to top border.\n", x1, y1 );
196 // printf( "Has a top width of %d\n", w2 );
198 //====================
200 printf( "Box at (%d,%d) has unequal top/bottom .\n", x1, y1 );
204 printf( "Box at (%d,%d) has unequal left/right.\n", x1, y1 );
209 printf( "Box at (%d,%d) is less than 1 pixel wide.\n", x1, y1 );
214 printf( "Box at (%d,%d) is less than 1 pixel tall.\n", x1, y1 );
226 void found_box( font *fnt, int x, int y, int w, int h );
228 void find_all_boxes(font *fnt)
233 data = (ubyte *)bmp.data;
237 printf( "Background color = %d\n", bkg );
239 for ( y=0; y<bmp.h; y++ ) {
240 for ( x=0; x<bmp.w; x++ ) {
241 if ( PIX(x,y) != bkg ) {
247 printf( "Couldn't find anything but background pixels\n" );
251 printf( "Border color = %d, starts at %d,%d\n", border, x, y );
257 if ( find_box( x, y, &w, &h ) ) {
258 found_box( fnt, x+1, y+1, w, h );
260 if ( row_height < 1 ) {
263 // if ( row_height != h ) {
264 // printf( "Uneven row height!\n" );
273 //printf( "Moving down %d pixels\n", row_height+2);
288 void fonttool_create_new( font *fnt )
290 strncpy( (char *)&fnt->id, "VFNT", 4 );
291 fnt->version = FONT_VERSION;
293 fnt->first_ascii = ' ';
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;
306 void fonttool_add_char( font *fnt, int x1, int y1, int real_w, int h, ubyte *cdata, int rowsize )
308 int x, y, n, coffset;
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 );
318 // add new character data
319 font_char * new_char;
320 new_char = (font_char *)malloc( fnt->char_data_size + sizeof(font_char) );
322 printf( "Not enough memory to create a new character\n" );
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;
330 fnt->char_data = new_char;
331 fnt->char_data_size += sizeof(font_char);
332 new_char = fnt->char_data + fnt->num_chars;
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);
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;
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;
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;
357 for ( y=0; y<h; y++ ) {
358 for (x=0; x<w; x++ ) {
363 c = cdata[x+y*rowsize];
368 *new_pixel_data++ = c;
377 for (i=0; i<fnt->num_chars; i++ ) {
378 wtotal += fnt->char_data[i].spacing;
381 fnt->w = wtotal / fnt->num_chars;
387 void fonttool_dump( char *filename, font *fnt )
390 char tmp_name[128], *p;
392 strcpy( tmp_name, filename );
393 p = strchr( tmp_name, '.' );
395 strcat( tmp_name, ".vf" );
397 fp = fopen( tmp_name, "wb" );
399 printf( "Couldn't open font file '%s' for writing!\n", tmp_name );
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 );
414 if ( fnt->kern_data_size ) {
415 fwrite( fnt->kern_data, fnt->kern_data_size, 1, fp );
417 if ( fnt->char_data_size ) {
418 fwrite( fnt->char_data, fnt->char_data_size, 1, fp );
420 if ( fnt->pixel_data_size ) {
421 fwrite( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
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); \
438 void fonttool_read( char *filename, font *fnt )
441 char tmp_name[128], *p;
443 strcpy( tmp_name, filename );
444 p = strchr( tmp_name, '.' );
446 strcat( tmp_name, ".vf" );
448 fp = fopen( tmp_name, "rb" );
450 printf( "Couldn't open font file '%s' for reading!\n", tmp_name );
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 );
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 );
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 ));
481 FREAD( fnt->kern_data, fnt->kern_data_size, 1, fp );
483 fnt->kern_data = NULL;
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 ));
491 FREAD( fnt->char_data, fnt->char_data_size, 1, fp );
493 fnt->char_data = NULL;
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 ));
501 FREAD( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
503 fnt->pixel_data = NULL;
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.
512 if ( fnt->pixel_data_size < 64*64 ) {
514 } else if ( fnt->pixel_data_size < 128*128 ) {
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);
528 for (i=0; i<fnt->num_chars; i++ ) {
531 pd = &fnt->pixel_data[fnt->char_data[i].offset];
532 if ( x + fnt->char_data[i].byte_width >= fnt->bm_w ) {
535 if ( y+fnt->h > fnt->bm_h ) {
536 Error( LOCATION, "Font too big!\n" );
542 for( y1=0; y1<fnt->h; y1++ ) {
543 for (x1=0; x1<fnt->char_data[i].byte_width; x1++ ) {
545 if ( c > 14 ) c = 14;
546 fnt->bm_data[(x+x1)+(y+y1)*fnt->bm_w] = (unsigned char)(c);
549 x += fnt->char_data[i].byte_width;
552 fnt->bitmap_id = bm_create( 8, fnt->bm_w, fnt->bm_h, fnt->bm_data, BMP_AABITMAP );
555 void fonttool_copy_kern( font *src, font *dst )
557 if ( dst->kern_data ) {
558 free( dst->kern_data );
559 dst->kern_data = NULL;
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);
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" ));
573 memcpy( dst->kern_data, src->kern_data, src->kern_data_size );
575 dst->kern_data_size = src->kern_data_size;
576 dst->num_kern_pairs = src->num_kern_pairs;
577 fonttool_resync_kerning(dst);
581 void found_box( font *fnt, int x, int y, int w, int h )
583 fonttool_add_char( fnt, x, y, w, h, &data[x+y*offset], offset );
587 void fonttool_create_font(char *pcx_filename, char *font_filename)
590 printf( "Creating font file from '%s' \n", pcx_filename );
591 if ( font_filename ) {
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 );
603 bmp.data = (ptr_u)malloc( w*h + 768 );
604 bmp.palette = (ubyte *)(bmp.data +w*h );
606 printf( "Error mallocing PCX data, '%s'\n", pcx_filename );
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 );
616 fonttool_create_new( &fnt1 );
618 find_all_boxes(&fnt1);
621 printf( "Using kern data from font '%s'\n", font_filename );
622 fonttool_read( font_filename, &fnt2 );
623 fonttool_copy_kern( &fnt2, &fnt1 );
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 );
630 fonttool_dump( pcx_filename, &fnt1 );