home *** CD-ROM | disk | FTP | other *** search
Wrap
/*! \file texfont.cpp \author Karsten Schwenk See header for description (font.h). */ #include "texfont.h" #include "Tokenizer.h" #include "TextureHandler.h" #include "File.h" //#include <stdio.h> //#include <stdlib.h> #ifndef WIN32 #include <ctype.h> // fr isdigit #include <stdarg.h> // fr linux va_kram #define _vsnprintf vsnprintf #endif #include "SDL.h" //! The font colors that can be accessed via '^0-9' (see #setFontColor() and detailed description of font.h) static float fontColors[10][4]={ {0.0f, 0.0f, 0.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 1.0f, 1.0f}, {0.75f, 0.75f, 0.75f, 1.0f}, {0.5f, 0.5f, 0.5f, 1.0f}, }; /*! This function loads a texFont into a #texFont_s struct and returns a pointer to it. When the font is no longer needed it can be freed using #freeFont(). The file must be a .font file, see font.h for details. \c NULL is returned on errors. \warning In most situations you should use #FontHandler::getFont() to get pointers to fonts. This prevents multiple loading of the same font. \param filename name of the .font-file that describes this font \return a pointer to the loaded texFont (or \c NULL) */ texFont_t* loadFont(const char* filename){ char buff[256]; Tokenizer t(" \"\t\n\r", "\""); File* f = new File(filename, "rt"); if(!f->isOpen()){ return NULL; } texFont_t* ret=new texFont_t; ret->filename=newString(filename); ret->spacing=0; ret->height=0; ret->tex=NULL; ret->texCoordHeight=0.0; for(int i=0;i<TEX_FONT_MAX_CHARACTERS;i++) ret->chars[i]=NULL; while(f->readLine(256, buff, true) != -1){ // printf("AH!\n"); t.tokenize(buff); if(t.tokc < 2) continue; if(streq(t.tokv[0], "texture")){ ret->tex=TextureHandler::getTexture(t.tokv[1]); }else if(streq(t.tokv[0], "height")){ ret->height=atoi(t.tokv[1]); ret->texCoordHeight=ret->height/(float)ret->tex->height; }else if(streq(t.tokv[0], "spacing")){ ret->spacing=atoi(t.tokv[1]); }else if(streq(t.tokv[0], "character") && t.tokc == 5){ if(*t.tokv[1]>0 && *t.tokv[1]<TEX_FONT_MAX_CHARACTERS){ int c = *t.tokv[1]; if(c=='\'' && strlen(t.tokv[1])>=2 && t.tokv[1][1]=='\''){ // double ' means " c='\"';//t.tokv[1][1]; } // printf("char: %c, %i\n", c, c); ret->chars[c]=new texFontCharacter_t; ret->chars[c]->u=atoi(t.tokv[2])/(float)ret->tex->width; ret->chars[c]->v=atoi(t.tokv[3])/(float)ret->tex->height; ret->chars[c]->width=atoi(t.tokv[4]); ret->chars[c]->texCoordWidth=ret->chars[c]->width/(float)ret->tex->width; } } } return ret; } /*! This function frees a #texFont_s struct allocated by #loadFont(). \warning In most situations you should use the #FontHandler to manage pointers to fonts. \param font a pointer to the loaded texFont */ void freeFont(texFont_t* font){ if(font!=NULL){ for(int i=0;i<TEX_FONT_MAX_CHARACTERS;i++){ if(font->chars[i]!=NULL) delete font->chars[i]; } if(font->tex!=NULL) TextureHandler::releaseTexture(font->tex); if(font->filename!=NULL) delete[] font->filename; delete font; } } /*! This function returns how many pixels \c string is wide in font \c font (\b including the fonts spacing). This is used mainly in the \c drawAlignedString-functions to calculate the correct x-offset. \param font a pointer a #texFont_s struct \param string a NULL-terminated string whoose width should be calculated \return width of the string in pixels \bug color coding chars are not counted correctly -> wrong width */ int getStringWidth(texFont_t* font, const char* string){ if(font==NULL || string==NULL) return 0; char* p=(char*)string; int cx=0; while(*p!='\0'){ if( *p=='^' && isdigit((int)(*(p+1))) ){ // don't count color coding chars p+=2; continue; } if( *p<0 || font->chars[*p]==NULL){ // count as height/2 - oder doch nicht? //cx = (int)( cx + font->height*0.5 + font->spacing ); p++; continue; } cx = cx + font->chars[*p]->width + font->spacing; p++; } return cx-font->spacing; // sub spacing after last character again } /*! This function sets the OpenGl color according to the values in #fontColors. This is used to change color in a string dynamicaly. See file describtion of font.h for details. \param c digit-character to reference the #fontColors array \return \c true if a new color was set, \c false if not (illegal character) */ bool setFontColor(char c){ if(c=='0') glColor4fv(fontColors[0]); else if(c=='1') glColor4fv(fontColors[1]); else if(c=='2') glColor4fv(fontColors[2]); else if(c=='3') glColor4fv(fontColors[3]); else if(c=='4') glColor4fv(fontColors[4]); else if(c=='5') glColor4fv(fontColors[5]); else if(c=='6') glColor4fv(fontColors[6]); else if(c=='7') glColor4fv(fontColors[7]); else if(c=='8') glColor4fv(fontColors[8]); else if(c=='9') glColor4fv(fontColors[9]); else if(c=='b'){ if((SDL_GetTicks()/700)%2) glColor4fv(fontColors[0]);// black else glColor4fv(fontColors[2]);// red }else return false; return true; } /*! This function draws string \c string on he screen at \c (x,y) using font \c font. Other functions have additional arguments for alignment, scaling, etc. and take format strings instead of 'normal' strings - but they are used in exactly the same manner, so I don't think it is neccassary to document them. The string is printed with the currently set OpenGL color (unless not changed by '^0-9'). \c GL_BLEND must be enabled, \c GL_TEXTURE_2D is disabled best (because your texture binding will change!). \param x x screen coordinate where string should be drawed \param y y screen coordinate where string should be drawed \param font font that should be used \param string string that should be drawed */ void drawString(int x, int y, texFont_t* font, const char* string){ if(font==NULL || string==NULL) return; char* p=(char*)string; int cx=x; glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, font->tex->texName); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBegin(GL_QUADS); while(*p!='\0'){ if(*p<0 || font->chars[*p]==NULL){ p++; continue; } if(*p=='^' && setFontColor(*(p+1))){ p+=2; continue; } // printf("char: %c | cx: %i | wi:%i | sp:%i\n", *p, cx,font->chars[*p]->width, font->spacing); // character glTexCoord2f(font->chars[*p]->u, font->chars[*p]->v); // lower left glVertex2i(cx, y); glTexCoord2f(font->chars[*p]->u+font->chars[*p]->texCoordWidth, font->chars[*p]->v); // lower right glVertex2i(cx+font->chars[*p]->width, y); glTexCoord2f(font->chars[*p]->u+font->chars[*p]->texCoordWidth, font->chars[*p]->v+font->texCoordHeight); // upper right glVertex2i(cx+font->chars[*p]->width, y+font->height); glTexCoord2f(font->chars[*p]->u, font->chars[*p]->v+font->texCoordHeight); //upper left glVertex2i(cx, y+font->height); cx = cx + font->chars[*p]->width + font->spacing; p++; } glEnd(); glDisable(GL_TEXTURE_2D); } void drawScaledString(int x, int y, float scaleX, float scaleY, texFont_t* font, const char* string){ if(font==NULL || string==NULL) return; char* p=(char*)string; float cx=(float)(x); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, font->tex->texName); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBegin(GL_QUADS); while(*p!='\0'){ if(*p<0 || font->chars[*p]==NULL){ p++; continue; } if(*p=='^' && setFontColor(*(p+1))){ p+=2; continue; } // printf("char: %c | cx: %i | wi:%i | sp:%i\n", *p, cx,font->chars[*p]->width, font->spacing); // character glTexCoord2f(font->chars[*p]->u, font->chars[*p]->v); // lower left glVertex2f(cx, (float)y); glTexCoord2f(font->chars[*p]->u+font->chars[*p]->texCoordWidth, font->chars[*p]->v); // lower right glVertex2f(cx+font->chars[*p]->width*scaleX, (float)y); glTexCoord2f(font->chars[*p]->u+font->chars[*p]->texCoordWidth, font->chars[*p]->v+font->texCoordHeight); // upper right glVertex2f(cx+font->chars[*p]->width*scaleX, y+font->height*scaleY); glTexCoord2f(font->chars[*p]->u, font->chars[*p]->v+font->texCoordHeight); //upper left glVertex2f(cx, y+font->height*scaleY); cx = cx + (font->chars[*p]->width + font->spacing)*scaleX; p++; } glEnd(); glDisable(GL_TEXTURE_2D); } void drawAlignedString(int x, int y, texFont_t* font, int alignment, const char* string){ if(font==NULL || string==NULL) return; char* p=(char*)string; int cx; // printf("stringWidth;: %i\n", getStringWidth(font, string)); if(alignment==TEXT_ALIGN_RIGHT) cx=x-getStringWidth(font, string); else if(alignment==TEXT_ALIGN_CENTER) cx=x-getStringWidth(font, string)/2; else cx=x; glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, font->tex->texName); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBegin(GL_QUADS); while(*p!='\0'){ if(*p<0 || font->chars[*p]==NULL){ p++; continue; } if(*p=='^' && setFontColor(*(p+1))){ p+=2; continue; } // printf("char: %c | cx: %i | wi:%i | sp:%i\n", *p, cx,font->chars[*p]->width, font->spacing); // character glTexCoord2f(font->chars[*p]->u, font->chars[*p]->v); // lower left glVertex2i(cx, y); glTexCoord2f(font->chars[*p]->u+font->chars[*p]->texCoordWidth, font->chars[*p]->v); // lower right glVertex2i(cx+font->chars[*p]->width, y); glTexCoord2f(font->chars[*p]->u+font->chars[*p]->texCoordWidth, font->chars[*p]->v+font->texCoordHeight); // upper right glVertex2i(cx+font->chars[*p]->width, y+font->height); glTexCoord2f(font->chars[*p]->u, font->chars[*p]->v+font->texCoordHeight); //upper left glVertex2i(cx, y+font->height); cx = cx + font->chars[*p]->width + font->spacing; p++; } glEnd(); glDisable(GL_TEXTURE_2D); } void drawScaledAndAlignedString(int x, int y, float scaleX, float scaleY, texFont_t* font, int alignment, const char* string){ if(font==NULL || string==NULL) return; char* p=(char*)string; float cx; // printf("stringWidth;: %i\n", getStringWidth(font, string)); if(alignment==TEXT_ALIGN_RIGHT) cx=x-(getStringWidth(font, string)*scaleX); else if(alignment==TEXT_ALIGN_CENTER) cx=x-(getStringWidth(font, string)*scaleX)/2; else cx=(float)x; glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, font->tex->texName); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glBegin(GL_QUADS); while(*p!='\0'){ if(*p<0 || font->chars[*p]==NULL){ // THINKABOUTME: alle chars mit ascii>128 ignorieren? oder X ausgeben? //glDisable(GL_TEXTURE_2D); //glBegin(GL_LINE_LOOP); // glVertex2f(cx, (float)y); // glVertex2f(cx+font->height*0.5f*scaleX, (float)y); // glVertex2f(cx+font->height*0.5f*scaleX, y+font->height*scaleY); // glVertex2f(cx, y+font->height*scaleY); //glEnd(); //glEnable(GL_TEXTURE_2D); //glBindTexture(GL_TEXTURE_2D, font->tex->texName); //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //cx = cx + (font->height*0.5f + font->spacing)*scaleX; p++; continue; } if(*p=='^' && setFontColor(*(p+1))){ p+=2; continue; } // printf("char: %c | cx: %i | wi:%i | sp:%i\n", *p, cx,font->chars[*p]->width, font->spacing); // character glTexCoord2f(font->chars[*p]->u, font->chars[*p]->v); // lower left glVertex2f(cx, (float)y); glTexCoord2f(font->chars[*p]->u+font->chars[*p]->texCoordWidth, font->chars[*p]->v); // lower right glVertex2f(cx+font->chars[*p]->width*scaleX, (float)y); glTexCoord2f(font->chars[*p]->u+font->chars[*p]->texCoordWidth, font->chars[*p]->v+font->texCoordHeight); // upper right glVertex2f(cx+font->chars[*p]->width*scaleX, y+font->height*scaleY); glTexCoord2f(font->chars[*p]->u, font->chars[*p]->v+font->texCoordHeight); //upper left glVertex2f(cx, y+font->height*scaleY); cx = cx + (font->chars[*p]->width + font->spacing)*scaleX; p++; } glEnd(); glDisable(GL_TEXTURE_2D); } void drawShadowedString( float x, float y, float scale, int shadowOffset, texFont_t* font, int alignment, const char* string){ float oldColor[4]; glGetFloatv(GL_CURRENT_COLOR, oldColor); glColor4f(0.0f, 0.0f, 0.0f, 0.7f); drawScaledAndAlignedString((int)((x+shadowOffset)), (int)((y-shadowOffset)) , scale, scale, font, alignment, string); glColor4fv(oldColor); drawScaledAndAlignedString((int)(x), (int)(y) , scale, scale, font, alignment, string); } void drawFormatString(int x, int y, texFont_t* font, const char* formatString, ...){ va_list ap; char toStringBuffer[512]; va_start (ap, formatString); _vsnprintf(toStringBuffer, 511, formatString, ap); va_end(ap); toStringBuffer[511]='\0'; drawString(x,y,font,toStringBuffer); } void drawScaledFormatString(int x, int y, float scaleX, float scaleY, texFont_t* font, const char* formatString, ...){ va_list ap; char toStringBuffer[512]; va_start (ap, formatString); _vsnprintf(toStringBuffer, 511, formatString, ap); va_end(ap); toStringBuffer[511]='\0'; drawScaledString(x,y,scaleX, scaleY, font,toStringBuffer); } void drawAlignedFormatString(int x, int y, texFont_t* font, int alignment, const char* formatString, ...){ va_list ap; char toStringBuffer[512]; va_start (ap, formatString); _vsnprintf(toStringBuffer, 511, formatString, ap); va_end(ap); toStringBuffer[511]='\0'; drawAlignedString(x,y,font,alignment,toStringBuffer); } void drawScaledAndAlignedFormatString(int x, int y, float scaleX, float scaleY, texFont_t* font, int alignment, const char* formatString, ...){ va_list ap; char toStringBuffer[512]; va_start (ap, formatString); _vsnprintf(toStringBuffer, 511, formatString, ap); va_end(ap); toStringBuffer[511]='\0'; drawScaledAndAlignedString(x,y,scaleX, scaleY, font,alignment,toStringBuffer); } void drawShadowedFormatString( float x, float y, float scale, int shadowOffset, texFont_t* font, int alignment, const char* formatString, ...){ va_list ap; char toStringBuffer[512]; va_start (ap, formatString); _vsnprintf(toStringBuffer, 511, formatString, ap); va_end(ap); toStringBuffer[511]='\0'; drawShadowedString(x, y ,scale,shadowOffset, font, alignment, toStringBuffer); }