00001 /* 00002 font.cpp 00003 Cone3D SDL font routines. 00004 Made by Marius Andra 2002 00005 http://cone3d.gamedev.net 00006 00007 You can use the code for anything you like. 00008 Even in a commercial project. 00009 But please let me know where it ends up. 00010 I'm just curious. That's all. 00011 */ 00012 00013 #include <stdio.h> 00014 #include <stdlib.h> 00015 #include <stdarg.h> 00016 #include <string.h> 00017 00018 #include <SDL/SDL.h> 00019 00020 #include "font.h" 00021 00022 // this function draws one part of an image to some other part of an other image 00023 // it's only to be used inside the font.cpp file, so it's not available to any 00024 // other source files (no prototype in font.h) 00025 void fontDrawIMG(SDL_Surface *screen, SDL_Surface *img, int x, int y, int w, 00026 int h, int x2, int y2) 00027 { 00028 SDL_Rect dest; 00029 dest.x = x; 00030 dest.y = y; 00031 SDL_Rect src; 00032 src.x = x2; 00033 src.y = y2; 00034 src.w = w; 00035 src.h = h; 00036 SDL_BlitSurface(img, &src, screen, &dest); 00037 } 00038 00039 // this function loads in our font file 00040 SDLFont *initFont(char *fontdir, float r, float g, float b, float a) 00041 { 00042 // some variables 00043 SDLFont *tempFont; // a temporary font 00044 FILE *fp; // file pointer - used when reading files 00045 char tempString[100]; // temporary string 00046 unsigned char tmp; // temporary unsigned char 00047 int width; // the width of the font 00048 SDL_Surface *tempSurface; // temporary surface 00049 00050 // find out about the size of a font from the ini file 00051 sprintf(tempString,"%s/%s",fontdir,"font.ini"); 00052 fp = fopen(tempString, "rb"); 00053 if( fp == NULL ) 00054 { 00055 return 0; 00056 } 00057 fscanf(fp, "%d", &width); 00058 fclose(fp); 00059 00060 // let's create our font structure now 00061 tempFont = new SDLFont; 00062 tempFont->data = new unsigned char[width*width*4]; 00063 tempFont->width = width; 00064 tempFont->charWidth = width/16; 00065 00066 // open the font raw data file and read everything in 00067 sprintf(tempString,"%s/%s",fontdir,"font.raw"); 00068 fp = fopen(tempString, "rb"); 00069 if( fp != NULL ) 00070 { 00071 for(int i=0;i<width*width;i++) 00072 { 00073 tmp = fgetc(fp); 00074 tempFont->data[i*4] = (unsigned char)255*(unsigned char)r; 00075 tempFont->data[i*4+1] = (unsigned char)255*(unsigned char)g; 00076 tempFont->data[i*4+2] = (unsigned char)255*(unsigned char)b; 00077 tempFont->data[i*4+3] = (unsigned char)(((float)tmp)*a); 00078 } 00079 } else { 00080 return 0; 00081 } 00082 fclose(fp); 00083 // now let's create a SDL surface for the font 00084 Uint32 rmask,gmask,bmask,amask; 00085 #if SDL_BYTEORDER == SDL_BIG_ENDIAN 00086 rmask = 0xff000000; 00087 gmask = 0x00ff0000; 00088 bmask = 0x0000ff00; 00089 amask = 0x000000ff; 00090 #else 00091 rmask = 0x000000ff; 00092 gmask = 0x0000ff00; 00093 bmask = 0x00ff0000; 00094 amask = 0xff000000; 00095 #endif 00096 tempSurface = SDL_CreateRGBSurfaceFrom(tempFont->data, width, width, 00097 32, width*4, rmask, gmask, bmask, amask); 00098 tempFont->font = SDL_DisplayFormatAlpha(tempSurface); 00099 SDL_FreeSurface(tempSurface); 00100 00101 // let's create a variable to hold all the widths of the font 00102 tempFont->widths = new int[256]; 00103 00104 // now read in the information about the width of each character 00105 sprintf(tempString,"%s/%s",fontdir,"font.dat"); 00106 fp = fopen(tempString, "rb"); 00107 if( fp != NULL ) 00108 { 00109 for(int i=0;i<256;i++) 00110 { 00111 tmp = fgetc(fp); 00112 tempFont->widths[i]=tmp; 00113 } 00114 } 00115 fclose(fp); 00116 00118 return tempFont; 00119 } 00120 00121 // here we draw the string 00122 void drawString(SDL_Surface *screen, SDLFont *font, int x, int y, char *str, ...) 00123 { 00124 char string[1024]; // Temporary string 00125 00126 va_list ap; // Pointer To List Of Arguments 00127 va_start(ap, str); // Parses The String For Variables 00128 vsprintf(string, str, ap); // And Converts Symbols To Actual Numbers 00129 va_end(ap); // Results Are Stored In Text 00130 00131 int len=strlen(string); // Get the number of chars in the string 00132 int xx=0; // This will hold the place where to draw the next char 00133 for(int i=0;i<len;i++) // Loop through all the chars in the string 00134 { 00135 // This may look scary, but it's really not. 00136 // We only draw one character with this code. 00137 // At the next run of the loop we draw the next character. 00138 00139 // Remember, the fontDrawIMG function looks like this: 00140 // void fontDrawIMG(SDL_Surface *screen, SDL_Surface *img, int x, int y, 00141 // int w, int h, int x2, int y2) 00142 00143 // We draw onto the screen SDL_Surface a part of the font SDL_Surface. 00144 fontDrawIMG( 00145 screen, 00146 font->font, 00147 // We draw the char at pos [x+xx,y]. 00148 // x+xx: this function's parameter x + the width of all the characters before 00149 // this one, so we wouldn't overlap any of the previous characters in the string 00150 // y: this function's y parameter 00151 xx+x, 00152 y, 00153 // For the width of the to-be-drawn character we take it's real width + 2 00154 font->widths[string[i]]+2, 00155 // And for the height we take the height of the character (height of the font/16) 00156 font->charWidth, 00157 // Now comes the tricky part 00158 // The font image DOES consist of 16x16 grid of characters. From left to 00159 // right in the image, the ascii values of the characters increase: 00160 // The character at block 0x0 in the font image is the character with the 00161 // ascii code 0, the character at the pos 1x0 has the ascii code 1, the char 00162 // at the pos 15x0 has the ascii code 15. And that's the end of the first row 00163 // Now in the second row on the image, the first character (0x1) has the ascii 00164 // value 16, the fourth character on the second row of the image (3x1) has the ascii 00165 // value 19. To calculate the ascii value of the character 3x1, we use the 00166 // really simple equation: row*[number of thing in one row (=16)]+column pos. 00167 // So the position 3x1 has the ascii value 1*16+3 = 19. The character in the 00168 // image at the position 8x12 has the ascii value 12*16+8=200, and so on. 00169 // But this isn't much of use to us since we KNOW the ascii value of a character, 00170 // but we NEED to find out it's position on the image. 00171 // First we'll get the column on the image. For that we'll divide the ascii value 00172 // with 16 (the number of columns) and get it's remainder (we'll use the modulus 00173 // operator). We'll do this equation to get the column: [ascii value]%16. 00174 // Now to get to the position of the column in pixels, we multiply the ascii 00175 // value by the width of one column ([font image width]/16) 00176 // And so the equation to get the first pixel of the block becomes: 00177 // [font image width]%16*[1/16th of the font image width] 00178 // Now, since all the letters are centered in each cell (1/16th of the image), 00179 // we need to get the center of the cell. This is done by adding half the width 00180 // of the cell to the number we got before. And the only thing left to do is to 00181 // subtract half of the character's real width and we get the x position from where 00182 // to draw our character on the font map :) 00183 (string[i]%16*font->charWidth)+((font->charWidth/2)-(font->widths[string[i]])/2), 00184 // To get the row of the character in the image, we divide the ascii value of 00185 // the character by 16 and get rid of all the numbers after the point (.) 00186 // (if we get the number 7.125257.., we remove the .125157... and end up with 7) 00187 // We then multiply the result with the height of one cell and voila - we get 00188 // the y position! 00189 (((int)string[i]/16)*font->charWidth) 00190 ); 00191 00192 // Now we increase the xx printed string width counter by the width of the 00193 // drawn character 00194 xx+=font->widths[string[i]]; 00195 } 00196 } 00197 00198 // This function returns the width of a string 00199 int stringWidth(SDLFont *font,char *str,...) 00200 { 00201 char string[1024]; // Temporary string 00202 00203 va_list ap; // Pointer To List Of Arguments 00204 va_start(ap, str); // Parses The String For Variables 00205 vsprintf(string, str, ap); // And Converts Symbols To Actual Numbers 00206 va_end(ap); // Results Are Stored In Text 00207 00208 // Now we just count up the width of all the characters 00209 int xx=0; 00210 int len=strlen(string); 00211 for(int i=0;i<len;i++) 00212 { 00213 // Add their widths together 00214 xx+=font->widths[string[i]]; 00215 } 00216 00217 // and then return the sum 00218 return xx; 00219 } 00220 00221 // Clear up 00222 void freeFont(SDLFont *font) 00223 { 00224 delete [] font->widths; 00225 delete [] font->data; 00226 SDL_FreeSurface(font->font); 00227 delete font; 00228 } 00229 00230 00231 00232