2 * $Logfile: /Freespace2/code/fonttool/FontCreate.cpp $
7 * Tool for creating new fonts
10 * Revision 1.1 2002/05/03 03:28:08 root
14 * 4 1/06/99 2:25p Dave
15 * Stubs and release build fixes.
17 * 3 12/02/98 9:58a Dave
18 * Got fonttool working under glide/direct3d.
20 * 2 10/24/98 5:15p Dave
22 * 1 10/24/98 4:58p Dave
24 * 4 10/31/97 10:30a Adam
25 * fixed a bug passing wrong pointer to pcx_read trashing memory.
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.
31 * 2 6/05/97 4:53p John
32 * First rev of new antialiased font stuff.
34 * 1 6/02/97 4:04p John
62 static ubyte pal[768];
69 static void myexit(int value)
75 ubyte PIX(int x,int y)
77 if ( x<0 || x >= bmp.w ) return bkg;
78 if ( y<0 || y >= bmp.h ) return bkg;
80 return data[x+y*offset];
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 )
90 if ( PIX(x,y) != border ) return 0;
95 // printf( "--------- Finding box at %d, %d ----------\n", x1, y1 );
97 //======================= FIND LEFT EDGE ======================
99 while ( PIX(x,y)==border ) {
100 if ( PIX(x+1,y)==border) {
105 printf( "Box at (%d,%d) goes off bottom of screen.\n", x1, y1 );
109 // printf( "Box at (%d,%d) doesn't have bottom border.\n", x1, y1 );
115 // printf( "Has a left height of %d\n", h1 );
117 //======================= FIND BOTTOM EDGE ======================
119 while ( PIX(x,y)==border ) {
120 if ( PIX(x,y-1)==border) {
121 goto BottomSideFound;
125 printf( "Box at (%d,%d) goes off left of screen.\n", x1, y1 );
129 printf( "Box at (%d,%d) doesn't have right border connected to bottom.\n", x1, y1 );
134 // printf( "Has a bottom width of %d\n", w1 );
136 //======================= FIND RIGHT EDGE ======================
139 while ( PIX(x,y)==border ) {
140 if ( PIX(x-1,y)==border) {
145 printf( "Box at (%d,%d) goes off top of screen.\n", x1, y1 );
149 printf( "Box at (%d,%d) doesn't have top border connected to right border.\n", x1, y1 );
154 // printf( "Has a right height of %d\n", h2 );
157 //======================= FIND TOP EDGE ======================
160 while ( PIX(x,y)==border ) {
161 if ( PIX(x,y+1)==border) {
166 printf( "Box at (%d,%d) goes off left of screen.\n", x1, y1 );
170 printf( "Box at (%d,%d) doesn't have left border connected to top border.\n", x1, y1 );
175 // printf( "Has a top width of %d\n", w2 );
177 //====================
179 printf( "Box at (%d,%d) has unequal top/bottom .\n", x1, y1 );
183 printf( "Box at (%d,%d) has unequal left/right.\n", x1, y1 );
188 printf( "Box at (%d,%d) is less than 1 pixel wide.\n", x1, y1 );
193 printf( "Box at (%d,%d) is less than 1 pixel tall.\n", x1, y1 );
205 void found_box( font *fnt, int x, int y, int w, int h );
207 void find_all_boxes(font *fnt)
212 data = (ubyte *)bmp.data;
216 printf( "Background color = %d\n", bkg );
218 for ( y=0; y<bmp.h; y++ ) {
219 for ( x=0; x<bmp.w; x++ ) {
220 if ( PIX(x,y) != bkg ) {
226 printf( "Couldn't find anything but background pixels\n" );
230 printf( "Border color = %d, starts at %d,%d\n", border, x, y );
236 if ( find_box( x, y, &w, &h ) ) {
237 found_box( fnt, x+1, y+1, w, h );
239 if ( row_height < 1 ) {
242 // if ( row_height != h ) {
243 // printf( "Uneven row height!\n" );
252 //printf( "Moving down %d pixels\n", row_height+2);
267 void fonttool_create_new( font *fnt )
269 strncpy( (char *)&fnt->id, "VFNT", 4 );
270 fnt->version = FONT_VERSION;
272 fnt->first_ascii = ' ';
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;
285 void fonttool_add_char( font *fnt, int x1, int y1, int real_w, int h, ubyte *data, int rowsize )
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 );
297 // add new character data
298 font_char * new_char;
299 new_char = (font_char *)malloc( fnt->char_data_size + sizeof(font_char) );
301 printf( "Not enough memory to create a new character\n" );
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;
309 fnt->char_data = new_char;
310 fnt->char_data_size += sizeof(font_char);
311 new_char = fnt->char_data + fnt->num_chars;
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);
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;
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;
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;
336 for ( y=0; y<h; y++ ) {
337 for (x=0; x<w; x++ ) {
342 c = data[x+y*rowsize];
347 *new_pixel_data++ = c;
356 for (i=0; i<fnt->num_chars; i++ ) {
357 wtotal += fnt->char_data[i].spacing;
360 fnt->w = wtotal / fnt->num_chars;
366 void fonttool_dump( char *filename, font *fnt )
369 char tmp_name[128], *p;
371 strcpy( tmp_name, filename );
372 p = strchr( tmp_name, '.' );
374 strcat( tmp_name, ".vf" );
376 fp = fopen( tmp_name, "wb" );
378 printf( "Couldn't open font file '%s' for writing!\n", tmp_name );
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 );
393 if ( fnt->kern_data_size ) {
394 fwrite( fnt->kern_data, fnt->kern_data_size, 1, fp );
396 if ( fnt->char_data_size ) {
397 fwrite( fnt->char_data, fnt->char_data_size, 1, fp );
399 if ( fnt->pixel_data_size ) {
400 fwrite( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
406 void fonttool_read( char *filename, font *fnt )
409 char tmp_name[128], *p;
411 strcpy( tmp_name, filename );
412 p = strchr( tmp_name, '.' );
414 strcat( tmp_name, ".vf" );
416 fp = fopen( tmp_name, "rb" );
418 printf( "Couldn't open font file '%s' for reading!\n", tmp_name );
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 );
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 );
439 fread( fnt->kern_data, fnt->kern_data_size, 1, fp );
441 fnt->kern_data = NULL;
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 );
449 fread( fnt->char_data, fnt->char_data_size, 1, fp );
451 fnt->char_data = NULL;
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 );
459 fread( fnt->pixel_data, fnt->pixel_data_size, 1, fp );
461 fnt->pixel_data = NULL;
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.
470 if ( fnt->pixel_data_size < 64*64 ) {
472 } else if ( fnt->pixel_data_size < 128*128 ) {
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);
486 for (i=0; i<fnt->num_chars; i++ ) {
489 fp = &fnt->pixel_data[fnt->char_data[i].offset];
490 if ( x + fnt->char_data[i].byte_width >= fnt->bm_w ) {
493 if ( y+fnt->h > fnt->bm_h ) {
494 Error( LOCATION, "Font too big!\n" );
500 for( y1=0; y1<fnt->h; y1++ ) {
501 for (x1=0; x1<fnt->char_data[i].byte_width; x1++ ) {
503 if ( c > 14 ) c = 14;
504 fnt->bm_data[(x+x1)+(y+y1)*fnt->bm_w] = unsigned char(c);
507 x += fnt->char_data[i].byte_width;
510 fnt->bitmap_id = bm_create( 8, fnt->bm_w, fnt->bm_h, fnt->bm_data, BMP_AABITMAP );
513 void fonttool_copy_kern( font *src, font *dst )
515 if ( dst->kern_data ) {
516 free( dst->kern_data );
517 dst->kern_data = NULL;
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);
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" );
531 memcpy( dst->kern_data, src->kern_data, src->kern_data_size );
533 dst->kern_data_size = src->kern_data_size;
534 dst->num_kern_pairs = src->num_kern_pairs;
535 fonttool_resync_kerning(dst);
539 void found_box( font *fnt, int x, int y, int w, int h )
541 fonttool_add_char( fnt, x, y, w, h, &data[x+y*offset], offset );
545 void fonttool_create_font(char *pcx_filename, char *font_filename)
548 printf( "Creating font file from '%s' \n", pcx_filename );
549 if ( font_filename ) {
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 );
561 bmp.data = (uint)malloc( w*h + 768 );
562 bmp.palette = (ubyte *)(bmp.data +w*h );
564 printf( "Error mallocing PCX data, '%s'\n", pcx_filename );
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 );
574 fonttool_create_new( &fnt1 );
576 find_all_boxes(&fnt1);
579 printf( "Using kern data from font '%s'\n", font_filename );
580 fonttool_read( font_filename, &fnt2 );
581 fonttool_copy_kern( &fnt2, &fnt1 );
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 );
588 fonttool_dump( pcx_filename, &fnt1 );