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 *data, int rowsize )
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 offset = 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 + offset;
351 new_char->byte_width = w;
352 new_char->spacing = real_w;
353 new_char->offset = offset;
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 = data[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 void fonttool_read( char *filename, font *fnt )
430 char tmp_name[128], *p;
432 strcpy( tmp_name, filename );
433 p = strchr( tmp_name, '.' );
435 strcat( tmp_name, ".vf" );
437 fp = fopen( tmp_name, "rb" );
439 printf( "Couldn't open font file '%s' for reading!\n", tmp_name );
443 fread( &fnt->id, 4, 1, fp );
444 fread( &fnt->version, sizeof(int), 1, fp );
445 fread( &fnt->num_chars, sizeof(int), 1, fp );
446 fread( &fnt->first_ascii, sizeof(int), 1, fp );
447 fread( &fnt->w, sizeof(int), 1, fp );
448 fread( &fnt->h, sizeof(int), 1, fp );
449 fread( &fnt->num_kern_pairs, sizeof(int), 1, fp );
450 fread( &fnt->kern_data_size, sizeof(int), 1, fp );
451 fread( &fnt->char_data_size, sizeof(int), 1, fp );
452 fread( &fnt->pixel_data_size, sizeof(int), 1, fp );
454 fnt->version = INTEL_INT( fnt->version );
455 fnt->num_chars = INTEL_INT( fnt->num_chars );
456 fnt->first_ascii = INTEL_INT( fnt->first_ascii );
457 fnt->w = INTEL_INT( fnt->w );
458 fnt->h = INTEL_INT( fnt->h );
459 fnt->num_kern_pairs = INTEL_INT( fnt->num_kern_pairs );
460 fnt->kern_data_size = INTEL_INT( fnt->kern_data_size );
461 fnt->char_data_size = INTEL_INT( fnt->char_data_size );
462 fnt->pixel_data_size = INTEL_INT( fnt->pixel_data_size );
464 if ( fnt->kern_data_size ) {
465 fnt->kern_data = (font_kernpair *)malloc( fnt->kern_data_size );
466 if (!fnt->kern_data) {
467 mprintf(( "Out of memory reading %d bytes of font data from %s\n", tmp_name ));
470 fread( fnt->kern_data, fnt->kern_data_size, 1, fp );
472 fnt->kern_data = NULL;
474 if ( fnt->char_data_size ) {
475 fnt->char_data = (font_char *)malloc( fnt->char_data_size );
476 if (!fnt->char_data) {
477 mprintf(( "Out of memory reading %d bytes of font data from %s\n", tmp_name ));
480 fread( fnt->char_data, fnt->char_data_size, 1, fp );
482 fnt->char_data = NULL;
484 if ( fnt->pixel_data_size ) {
485 fnt->pixel_data = (ubyte *)malloc( fnt->pixel_data_size );
486 if (!fnt->pixel_data) {
487 mprintf(( "Out of memory reading %d bytes of font data from %s\n", tmp_name ));
490 fread( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
492 fnt->pixel_data = NULL;
497 // Create a bitmap for hardware cards.
498 // JAS: Try to squeeze this into the smallest square power of two texture.
499 // This should probably be done at font generation time, not here.
501 if ( fnt->pixel_data_size < 64*64 ) {
503 } else if ( fnt->pixel_data_size < 128*128 ) {
511 fnt->bm_data = (ubyte *)malloc(fnt->bm_w*fnt->bm_h);
512 fnt->bm_u = (int *)malloc(sizeof(int)*fnt->num_chars);
513 fnt->bm_v = (int *)malloc(sizeof(int)*fnt->num_chars);
517 for (i=0; i<fnt->num_chars; i++ ) {
520 fp = &fnt->pixel_data[fnt->char_data[i].offset];
521 if ( x + fnt->char_data[i].byte_width >= fnt->bm_w ) {
524 if ( y+fnt->h > fnt->bm_h ) {
525 Error( LOCATION, "Font too big!\n" );
531 for( y1=0; y1<fnt->h; y1++ ) {
532 for (x1=0; x1<fnt->char_data[i].byte_width; x1++ ) {
534 if ( c > 14 ) c = 14;
535 fnt->bm_data[(x+x1)+(y+y1)*fnt->bm_w] = (unsigned char)(c);
538 x += fnt->char_data[i].byte_width;
541 fnt->bitmap_id = bm_create( 8, fnt->bm_w, fnt->bm_h, fnt->bm_data, BMP_AABITMAP );
544 void fonttool_copy_kern( font *src, font *dst )
546 if ( dst->kern_data ) {
547 free( dst->kern_data );
548 dst->kern_data = NULL;
550 if ( (src->kern_data_size < 1) || (!src->kern_data) ) {
551 dst->num_kern_pairs = 0;
552 dst->kern_data_size = 0;
553 dst->kern_data = NULL;
554 fonttool_resync_kerning(dst);
557 dst->kern_data = (font_kernpair *)malloc( src->kern_data_size );
558 if (!dst->kern_data) {
559 mprintf(( "Out of memory copying %d bytes of font data.\n" ));
562 memcpy( dst->kern_data, src->kern_data, src->kern_data_size );
564 dst->kern_data_size = src->kern_data_size;
565 dst->num_kern_pairs = src->num_kern_pairs;
566 fonttool_resync_kerning(dst);
570 void found_box( font *fnt, int x, int y, int w, int h )
572 fonttool_add_char( fnt, x, y, w, h, &data[x+y*offset], offset );
576 void fonttool_create_font(char *pcx_filename, char *font_filename)
579 printf( "Creating font file from '%s' \n", pcx_filename );
580 if ( font_filename ) {
584 int pcx_error = pcx_read_header( pcx_filename, &w, &h, NULL );
585 if ( pcx_error != PCX_ERROR_NONE ) {
586 printf( "Error reading PCX file, '%s'\n", pcx_filename );
592 bmp.data = (ptr_u)malloc( w*h + 768 );
593 bmp.palette = (ubyte *)(bmp.data +w*h );
595 printf( "Error mallocing PCX data, '%s'\n", pcx_filename );
599 pcx_error = pcx_read_bitmap_8bpp( pcx_filename, (ubyte *)bmp.data, pal );
600 if ( pcx_error != PCX_ERROR_NONE ) {
601 printf( "Error reading PCX file, '%s'\n", pcx_filename );
605 fonttool_create_new( &fnt1 );
607 find_all_boxes(&fnt1);
610 printf( "Using kern data from font '%s'\n", font_filename );
611 fonttool_read( font_filename, &fnt2 );
612 fonttool_copy_kern( &fnt2, &fnt1 );
615 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 );
616 if ( num_bad_pixels > 0 )
617 printf( "It had %d bad pixel(s) in it.\n(Bad means the pixel index was greater than 15).\n" , num_bad_pixels );
619 fonttool_dump( pcx_filename, &fnt1 );