Back to index

extremetuxracer  0.5beta
tex_font_metrics.cpp
Go to the documentation of this file.
00001 /* 
00002  * PPRacer 
00003  * Copyright (C) 2004-2005 Volker Stroebel <volker@planetpenguin.de>
00004  *
00005  * Copyright (C) 1999-2001 Jasmin F. Patry
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020  */
00021 
00022 #include "etracer.h"
00023 #include "tex_font_metrics.h"
00024 
00025 #include "ppgltk/ppgltk.h"
00026 
00027 #define MAX_TEX_FONT_CHARS 256
00028 
00029 typedef struct {
00030     pp::Vec2d ll, lr, ul, ur;                 /* geometry coordinates */
00031     pp::Vec2d tex_ll, tex_lr, tex_ul, tex_ur; /* texture coordinates */
00032     double kern_width;  /* distance that this char takes when rendered 
00033                           as part of a string */
00034 } tfm_char_data_t;
00035 
00036 struct tex_font_metrics_ {
00037     int max_ascent;
00038     int max_descent;
00039     tfm_char_data_t *char_data[MAX_TEX_FONT_CHARS];
00040 };
00041 
00042 struct char_dims {
00043     unsigned short ch;
00044     unsigned char w;
00045     unsigned char h;
00046     char x_offset;
00047     char y_offset;
00048     char kern_width;
00049     short x_pixel;
00050     short y_pixel;
00051 };
00052 
00053 
00054 #define READ_BYTES( file, addr, bytes, swap ) \
00055 if ( fread( (addr), (bytes), 1, (file) ) != 1 ) { \
00056     err_msg = "Unexpected end of file"; \
00057     goto bail; \
00058 } else { \
00059     if ((swap)) { \
00060        if ( (bytes) == 4 ) { \
00061            SWAP_WORD(*(addr)); \
00062        } else if ( bytes == 2 ) { \
00063            SWAP_SHORT(*(addr)); \
00064        } else { \
00065            check_assertion( 0, \
00066               "Can't byte-swap storage with size != 2 of 4 bytes" ); \
00067        } \
00068     } \
00069 }
00070 
00071 
00072 tex_font_metrics_t* load_tex_font_metrics( const char *filename )
00073 {
00074     tex_font_metrics_t *tfm = NULL;
00075     FILE *tfm_file = NULL;
00076     int i;
00077     char magic[4];
00078     char *err_msg;
00079     int endian_check;
00080     bool swap_bytes;
00081     struct char_dims ch_dims;
00082     int num_chars;
00083     int texture_width, texture_height;
00084     char dummy;
00085 
00086     check_assertion( sizeof(int) == 4,
00087                    "This architecture's integer size is != 4" );
00088     check_assertion( sizeof(short) == 2,
00089                    "This architecture's short integer size is != 2" );
00090     check_assertion( sizeof(char) == 1,
00091                    "This architecture's char size is != 1" );
00092 
00093     /* Open file */
00094     tfm_file = fopen( filename, "rb" );
00095     if ( tfm_file == NULL ) {
00096        print_warning( MISSING_FILE_WARNING,
00097                      "Couldn't open font metrics file %s", filename );
00098        return NULL;
00099     }
00100 
00101     tfm = (tex_font_metrics_t*)malloc( sizeof(tex_font_metrics_t) );
00102     check_assertion( tfm != NULL, "out of memory" );
00103 
00104     /* Initialize tfm */
00105     for (i=0; i<MAX_TEX_FONT_CHARS; i++) {
00106        tfm->char_data[i] = NULL;
00107     }
00108 
00109     /* Check magic number */
00110     READ_BYTES( tfm_file, magic, sizeof(magic), false );
00111 
00112     if ( strncmp( magic, "\377tfm", 4 ) != 0 ) {
00113        err_msg = "File is not a valid tfm file";
00114        goto bail;
00115     }
00116 
00117     /* Check endian-ness */
00118     READ_BYTES( tfm_file, &endian_check, sizeof(int), false );
00119 
00120     if ( endian_check == 0x12345678 ) {
00121        swap_bytes = false;
00122     } else if ( endian_check == 0x78563412 ) {
00123        swap_bytes = true;
00124     } else {
00125        err_msg = "File is not a valid tfm file";
00126        goto bail;
00127     }
00128 
00129     /* Read in texture_width, texture_height, max_ascent, max_descent */
00130     READ_BYTES( tfm_file, &texture_width, sizeof(int), swap_bytes );
00131     READ_BYTES( tfm_file, &texture_height, sizeof(int), swap_bytes );
00132     READ_BYTES( tfm_file, &tfm->max_ascent, sizeof(int), swap_bytes );
00133     READ_BYTES( tfm_file, &tfm->max_descent, sizeof(int), swap_bytes );
00134 
00135     READ_BYTES( tfm_file, &num_chars, sizeof(int), swap_bytes );
00136 
00137     for (i=0; i<num_chars; i++) {
00138        tfm_char_data_t *cd;
00139        double sstep = 0.5/texture_width;
00140        double tstep = 0.5/texture_height;
00141 
00142        READ_BYTES( tfm_file, &ch_dims.ch, sizeof(unsigned short), swap_bytes );
00143        READ_BYTES( tfm_file, &ch_dims.w, sizeof(unsigned char), false );
00144        READ_BYTES( tfm_file, &ch_dims.h, sizeof(unsigned char), false );
00145        READ_BYTES( tfm_file, &ch_dims.x_offset, sizeof(char), false );
00146        READ_BYTES( tfm_file, &ch_dims.y_offset, sizeof(char), false );
00147        READ_BYTES( tfm_file, &ch_dims.kern_width, sizeof(char), false );
00148        READ_BYTES( tfm_file, &dummy, sizeof(char), false );
00149        READ_BYTES( tfm_file, &ch_dims.x_pixel, sizeof(short), swap_bytes );
00150        READ_BYTES( tfm_file, &ch_dims.y_pixel, sizeof(short), swap_bytes );
00151 
00152        if ( ch_dims.ch >= MAX_TEX_FONT_CHARS ) {
00153            err_msg = "Two-byte characters are not supported";
00154            goto bail;
00155        }
00156 
00157        cd = ( tfm_char_data_t * ) malloc( sizeof( tfm_char_data_t ) );
00158 
00159        check_assertion( cd != NULL, "out of memory" );
00160 
00161        cd->ll = pp::Vec2d( ch_dims.x_offset, ch_dims.y_offset );
00162        cd->lr = pp::Vec2d( cd->ll.x + ch_dims.w, cd->ll.y );
00163        cd->ur = pp::Vec2d( cd->lr.x, cd->lr.y + ch_dims.h );
00164        cd->ul = pp::Vec2d( cd->ur.x - ch_dims.w, cd->ur.y );
00165 
00166        cd->tex_ll = pp::Vec2d( ch_dims.x_pixel / (double)texture_width + 
00167                                sstep,
00168                                ch_dims.y_pixel / (double)texture_height +
00169                                tstep );
00170        cd->tex_lr = pp::Vec2d( cd->tex_ll.x + sstep +
00171                                ch_dims.w / (double)texture_width,
00172                                cd->tex_ll.y + tstep );
00173        cd->tex_ur = pp::Vec2d( cd->tex_lr.x + sstep,
00174                                cd->tex_lr.y + tstep +
00175                                ch_dims.h / (double)texture_height );
00176        cd->tex_ul = pp::Vec2d( cd->tex_ur.x + sstep - 
00177                                ch_dims.w / (double)texture_width,
00178                                cd->tex_ur.y + tstep );
00179 
00180        cd->kern_width = ch_dims.kern_width;
00181 
00182        tfm->char_data[ch_dims.ch] = cd;
00183     }
00184 
00185     fclose( tfm_file );
00186 
00187     return tfm;
00188 
00189 bail:
00190     if ( tfm != NULL ) {
00191        for (i=0; i<MAX_TEX_FONT_CHARS; i++) {
00192            if ( tfm->char_data[i] != NULL ) {
00193               free( tfm->char_data[i] );
00194            }
00195        }
00196        free( tfm );
00197     }
00198 
00199     if ( tfm_file != NULL ) {
00200        fclose( tfm_file );
00201     }
00202 
00203     print_warning( IMPORTANT_WARNING, 
00204                  "Error opening font metrics file `%s': %s\n",
00205                  filename, err_msg );
00206     return NULL;
00207 }
00208 
00209 void delete_tex_font_metrics( tex_font_metrics_t *tfm ) 
00210 {
00211     int i;
00212     if ( tfm != NULL ) {
00213        for (i=0; i<MAX_TEX_FONT_CHARS; i++) {
00214            if ( tfm->char_data[i] != NULL ) {
00215               free( tfm->char_data[i] );
00216            }
00217        }
00218        free( tfm );
00219     }
00220 }
00221 
00222 static tfm_char_data_t* find_char_data( tex_font_metrics_t *tfm, unsigned char c )
00223 {
00224     int i;
00225     if ( tfm->char_data[(int)c] != NULL ) {
00226               return tfm->char_data[(int)c];
00227     } else if ( isupper(c) && tfm->char_data[ tolower(c) ] != NULL ) {
00228               return tfm->char_data[ tolower(c) ];
00229     } else if ( islower(c) && tfm->char_data[ toupper(c) ] != NULL ) {
00230               return tfm->char_data[ toupper(c) ];
00231     } else if ( tfm->char_data[int( ' ') ] != NULL ) {  
00232               print_warning( IMPORTANT_WARNING, 
00233                      "Font does not have a representation of "
00234                      "character `%c'; using space as placeholder", 
00235                      c );
00236               return tfm->char_data[ int(' ' )];
00237     } else {
00238        for (i=0; i<MAX_TEX_FONT_CHARS; i++) {
00239            if ( tfm->char_data[i] != NULL ) {
00240               print_warning( IMPORTANT_WARNING, 
00241                             "Font does not have a representation of "
00242                             "character `%c'; using `%c' as placeholder", 
00243                             c, i );
00244               return tfm->char_data[i];
00245            }
00246        }
00247        check_assertion( 0, "font contains no characters" );
00248     }
00249     
00250     /* Shouldn't get here */
00251     return NULL;
00252 }
00253 
00254 void get_tex_font_string_bbox( tex_font_metrics_t *tfm, 
00255                             const char *string, 
00256                             int *width, int *max_ascent, int *max_descent )
00257 {
00258     int i;
00259     int len;
00260     tfm_char_data_t *cd;
00261     *width = 0;
00262     
00263     len = strlen( string );
00264 
00265     for (i=0; i<len; i++) {
00266               cd = find_char_data( tfm, string[i] );
00267               *width += int(cd->kern_width);
00268     }
00269 
00270     *max_ascent = tfm->max_ascent;
00271     *max_descent = tfm->max_descent;
00272 }
00273 
00274 void draw_tex_font_char( tex_font_metrics_t *tfm, const char c )
00275 {
00276     tfm_char_data_t *cd;
00277 
00278     cd = find_char_data( tfm, c );
00279 
00280     glBegin( GL_QUADS );
00281     {
00282        glTexCoord2dv( (double*) &cd->tex_ll );
00283        glVertex2dv(   (double*) &cd->ll     );
00284        glTexCoord2dv( (double*) &cd->tex_lr );
00285        glVertex2dv(   (double*) &cd->lr     );
00286        glTexCoord2dv( (double*) &cd->tex_ur );
00287        glVertex2dv(   (double*) &cd->ur     );
00288        glTexCoord2dv( (double*) &cd->tex_ul );
00289        glVertex2dv(   (double*) &cd->ul     );
00290     }
00291     glEnd();
00292 
00293     glTranslatef( cd->kern_width, 0., 0. );
00294 }
00295 
00296 void draw_tex_font_string( tex_font_metrics_t *tfm, const char *string )
00297 {
00298     int i;
00299     int len;
00300 
00301     len = strlen( string );
00302 
00303     for (i=0; i<len; i++) {
00304               draw_tex_font_char( tfm, string[i] );
00305     }
00306 }
00307 
00308 bool is_character_in_tex_font( tex_font_metrics_t *tfm, char c ) 
00309 {
00310     return (bool) (tfm->char_data[(int)c] != NULL);
00311 }
00312 
00313 /* EOF */