//text.cpp //texture-based OpenGL font drawing code #include #include #include #include #include "fileio.h" #include "gamemem.h" #include "text.h" #include "config.h" #include "parser.h" #include "textures.h" #include "renderframe.h" #include "gameframe.h" #include "environment.h" #include "screen.h" #include "gameinitexit.h" #define kMessageBufferSize 128 #define kMessageSize 512 //one element of the Message Buffer, which will be drawn to the screen //when TextPrintBuffer is called typedef struct{ char text[kMessageSize];//the actual string float r,g,b,a; //color to draw text in tVector3 pos; //position on screen float size; //size of text int startFadeIn; int startFade,endFade; // int align; //alignment of text float tilt; } tMessage; tMessage gMessageBuffer[kMessageBufferSize]; int gMessagePos=0; tFontInfo *gTextFont; float gTextSize=0.03; float gTextLineSpacing=0; tVector2 gTextBufferScale=Vector(1,1); float gTextOpacity=1; //loads the font described by the file referenced to by fontRef void TextLoadFont(int fontRef) { gTextFont=(tFontInfo*)FileGetParsedDataPtr(fontRef,kParserTypeFontInfoDesc,sizeof(tFontInfo)); static int s=false; if(!s){ for(int i=0;inumChars;i++) { gTextFont->chars[i].x1+=0.003; gTextFont->chars[i].x2-=0.003; }s=true;} } void TextDrawSimple(char *text,float maxWidth,float size,int align) { TexturesSelectTex(gTextFont->fontTexture); //glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glPushAttrib(GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); int l=0; float xPos=0; float yPos=0; char *printPos=text; float totalWidth=0; while(*printPos!='\0') { if(*printPos=='\255') { do{ printPos++; l++; }while(*printPos!='\255'&&*printPos!='\0'); if(*printPos=='\0') { printPos--; } else l++; } if(*printPos>=gTextFont->startChar&&*printPosstartChar+gTextFont->numChars) { char ch=*printPos; if(ch>='a'&&ch<='z')ch+='A'-'a'; tFontCharInfo *cInfo=gTextFont->chars+(ch-gTextFont->startChar); if(cInfo->y2-cInfo->y1>0) if(totalWidth+(cInfo->x2-cInfo->x1)/(cInfo->y2-cInfo->y1)*sizex2-cInfo->x1)/(cInfo->y2-cInfo->y1)*size; l++; } } printPos++; } printPos=text; if(align==kTextAlignRight) xPos-=totalWidth; else if(align==kTextAlignMiddle) xPos-=totalWidth/2; int i=0; while(printPos=gTextFont->startChar&&*printPosstartChar+gTextFont->numChars) { char ch=*printPos; if(ch>='a'&&ch<='z')ch+='A'-'a'; tFontCharInfo *cInfo=gTextFont->chars+(ch-gTextFont->startChar); if(cInfo->y2-cInfo->y1>0) { float width=(cInfo->x2-cInfo->x1)/(cInfo->y2-cInfo->y1)*size; glBegin(GL_TRIANGLE_STRIP); glTexCoord2d(cInfo->x2,cInfo->y2); glVertex2f(xPos+width,yPos-size); glTexCoord2d(cInfo->x2,cInfo->y1); glVertex2f(xPos+width,yPos); glTexCoord2d(cInfo->x1,cInfo->y2); glVertex2f(xPos,yPos-size); glTexCoord2d(cInfo->x1,cInfo->y1); glVertex2f(xPos,yPos); glEnd(); #ifdef __POLYCOUNT gPolyCount+=2; #endif xPos+=width; } } printPos++; } glPopAttrib(); } float TextWidth(char *str,float size) { float width=0; while(*str!='\0') { if(*str>=gTextFont->startChar&&*strstartChar+gTextFont->numChars) { tFontCharInfo *cInfo=gTextFont->chars+(*str-gTextFont->startChar); if(cInfo->y2-cInfo->y1>0) width+=(cInfo->x2-cInfo->x1)/(cInfo->y2-cInfo->y1)*size; } if(*str=='\255') { str++; char iconFile[256]; int chi=0; while(*str!='\255'&&*str!='\0') iconFile[chi++]=*(str++); iconFile[chi]='\0'; if(iconFile[0]!='#') width+=size; } str++; } return width; } //#include "error.h" #define kTabSpaces 10 //draws all the messages in the text buffer to the screen void TextPrintBuffer(float opacity,int useInstrumentColor) { gTexturesQualityModifier=-255; int tmpFileError=gFileErrorReporting; gFileErrorReporting=false; glLoadIdentity(); glTranslatef(0.0f,0.0f,0.0f); glScalef(gTextBufferScale.x,gTextBufferScale.y,1); TexturesSelectTex(gTextFont->fontTexture); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); glPushAttrib(GL_LIGHTING_BIT+GL_DEPTH_BUFFER_BIT+GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); for(int i=gMessagePos-1;i>=0;i--) if(gMessageBuffer[i].a>0) { float xPos=gMessageBuffer[i].pos.x; float yPos=gMessageBuffer[i].pos.y; float zPos=gMessageBuffer[i].pos.z; if(fabs(zPos)>10) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); if(zPos!=-1.0) SetupAspect(1.0+~gCameraEntity->velo*0.0015*((gGameInfo->arcade!=3&&gGameInfo->arcade!=0)?(gGameInfo->arcade+1):0)); else SetupAspect(kNormalFOVY); float size=gMessageBuffer[i].size; char *printPos=gMessageBuffer[i].text; float totalWidth=TextWidth(printPos,size); printPos=gMessageBuffer[i].text; if((gMessageBuffer[i].align&kTextAlignMask)==kTextAlignRight) xPos-=totalWidth; else if((gMessageBuffer[i].align&kTextAlignMask)==kTextAlignMiddle) xPos-=totalWidth/2; float fade=1; if(gMessageBuffer[i].startFade!=-1) { if(gFrameCount>gMessageBuffer[i].startFade) fade=1-(gFrameCount-gMessageBuffer[i].startFade)/(float)(gMessageBuffer[i].endFade-gMessageBuffer[i].startFade); else if(gFrameCountinstrumentColor.x*gMessageBuffer[i].r ,gEnvironment->instrumentColor.y*gMessageBuffer[i].g ,gEnvironment->instrumentColor.z*gMessageBuffer[i].b ,fade*gMessageBuffer[i].a*opacity); else glColor4f(gMessageBuffer[i].r ,gMessageBuffer[i].g ,gMessageBuffer[i].b ,fade*gMessageBuffer[i].a*opacity); // PrintConsoleString(gMessageBuffer[i].text); while(*printPos!='\0') { if(*printPos>=gTextFont->startChar&&*printPosstartChar+gTextFont->numChars) { tFontCharInfo *cInfo=gTextFont->chars+(*printPos-gTextFont->startChar); if(cInfo->y2-cInfo->y1>0) { float width=(cInfo->x2-cInfo->x1)/(cInfo->y2-cInfo->y1)*size; glBegin(GL_TRIANGLE_STRIP); glTexCoord2d(cInfo->x2,cInfo->y2); glVertex3f(xPos+width,yPos-size,zPos); glTexCoord2d(cInfo->x2,cInfo->y1); glVertex3f(xPos+size*gMessageBuffer[i].tilt+width,yPos,zPos); glTexCoord2d(cInfo->x1,cInfo->y2); glVertex3f(xPos,yPos-size,zPos); glTexCoord2d(cInfo->x1,cInfo->y1); glVertex3f(xPos+size*gMessageBuffer[i].tilt,yPos,zPos); glEnd(); #ifdef __POLYCOUNT gPolyCount+=2; #endif xPos+=width; } } else if(*printPos=='\t') xPos=ceil(xPos*kTabSpaces/2)/(kTabSpaces/2); else if(*printPos=='\255') { printPos++; char iconFile[256]; int chi=0; while(*printPos!='\255'&&*printPos!='\0'&&chi<255) iconFile[chi++]=*(printPos++); //printPos++; iconFile[chi]='\0'; if(iconFile[0]=='#') { float r,g,b; switch(iconFile[1]) { case 'w': r=1;g=1;b=1; break; case 'r': r=1;g=0;b=0; break; case 'g': r=0;g=1;b=0; break; case 'b': r=0;g=0;b=1; break; case 'y': r=1;g=1;b=0; break; case 'c': r=0;g=1;b=1; break; case 'm': r=1;g=0;b=1; break; case 'a': r=0.8;g=0.8;b=0.8; break; case 'd': r=0.6;g=0.6;b=0.6; break; case 'l': r=0;g=0;b=0; break; case 'n': r=gMessageBuffer[i].r;g=gMessageBuffer[i].g;b=gMessageBuffer[i].b; break; case '0': r=0;g=0;b=0; break; } if(useInstrumentColor) glColor4f(gEnvironment->instrumentColor.x*r ,gEnvironment->instrumentColor.y*g ,gEnvironment->instrumentColor.z*b ,fade*gMessageBuffer[i].a*opacity); else glColor4f(r,g,b,fade*gMessageBuffer[i].a*opacity); } else { tFileRef icon=FileGetReference(iconFile); if(icon!=kFileErr) { char *extension=FileGetExtension(icon); if(!(_stricmp(extension,".pct")&&_stricmp(extension,".tif")&&_stricmp(extension,".png")&&_stricmp(extension,".txr"))) { glPushAttrib(GL_CURRENT_BIT); glColor4f(1,1,1,fade*gMessageBuffer[i].a*opacity); TexturesSelectTex(icon); GLint width,height; glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&width); glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&height); float ratio=height/(float)width; glBegin(GL_TRIANGLE_STRIP); glTexCoord2d(1,1); glVertex3f(xPos+size,yPos-size*ratio,zPos); glTexCoord2d(1,0); glVertex3f(xPos+size,yPos,zPos); glTexCoord2d(0,1); glVertex3f(xPos,yPos-size*ratio,zPos); glTexCoord2d(0,0); glVertex3f(xPos,yPos,zPos); glEnd(); glPopAttrib(); TexturesSelectTex(gTextFont->fontTexture); xPos+=size; } } } } if(gMessageBuffer[i].align==(kTextAlignLeft|kTextAutoWrap)) if(xPos>0.43&&*printPos==' ') { xPos=gMessageBuffer[i].pos.x; yPos-=size; } if(gMessageBuffer[i].align==(kTextAlignLeft|kTextAutoCut)) if(xPos>0.49) xPos=10; if((*printPos=='\n'||*printPos=='\r')&&(gMessageBuffer[i].align&kTextAlignMask)==kTextAlignLeft) { xPos=gMessageBuffer[i].pos.x; yPos-=size; } if(*printPos!='\0') printPos++; } } glPopAttrib(); gFileErrorReporting=tmpFileError; gTexturesQualityModifier=0; } void TextClearBuffer() { int fadeCount=0; for(int i=0;i=kMessageBufferSize) return; va_list ap; // Pointer To List Of Arguments if (fmt == NULL) // If There's No Text return; // Do Nothing va_start(ap, fmt); // Parses The String For Variables gMessageBuffer[gMessagePos].pos=Vector(0,0,-1); gMessageBuffer[gMessagePos].size=gTextSize; gMessageBuffer[gMessagePos].startFade=-1; gMessageBuffer[gMessagePos].endFade=-1; gMessageBuffer[gMessagePos].r=1; gMessageBuffer[gMessagePos].g=1; gMessageBuffer[gMessagePos].b=1; gMessageBuffer[gMessagePos].a=gTextOpacity; gMessageBuffer[gMessagePos].align=kTextAlignLeft; gMessageBuffer[gMessagePos].tilt=0; vsprintf(gMessageBuffer[gMessagePos++].text,fmt,ap); // And Converts Symbols To Actual Numbers va_end(ap); // Results Are Stored In Text } void TextPrintfToBufferFormated(tVector2 pos,float size,int align,const char *fmt, ...) { if(gMessagePos>=kMessageBufferSize) return; va_list ap; // Pointer To List Of Arguments if (fmt == NULL) // If There's No Text return; // Do Nothing va_start(ap, fmt); // Parses The String For Variables gMessageBuffer[gMessagePos].pos.x=pos.x*kTextXPos; gMessageBuffer[gMessagePos].pos.y=pos.y*kTextYPos; gMessageBuffer[gMessagePos].pos.z=-1; gMessageBuffer[gMessagePos].size=size; gMessageBuffer[gMessagePos].startFade=-1; gMessageBuffer[gMessagePos].endFade=-1; gMessageBuffer[gMessagePos].r=1; gMessageBuffer[gMessagePos].g=1; gMessageBuffer[gMessagePos].b=1; gMessageBuffer[gMessagePos].a=gTextOpacity; gMessageBuffer[gMessagePos].align=align; gMessageBuffer[gMessagePos].tilt=0; vsprintf(gMessageBuffer[gMessagePos++].text,fmt,ap); // And Converts Symbols To Actual Numbers va_end(ap); // Results Are Stored In Text } void TextPrintfToBufferFormatedVector3(tVector3 pos,float size,int align,const char *fmt, ...) { if(gMessagePos>=kMessageBufferSize) return; va_list ap; // Pointer To List Of Arguments if (fmt == NULL) // If There's No Text return; // Do Nothing va_start(ap, fmt); // Parses The String For Variables pos.z=-pos.z; pos.x=-pos.x; gMessageBuffer[gMessagePos].pos=pos; gMessageBuffer[gMessagePos].size=size; gMessageBuffer[gMessagePos].startFade=-1; gMessageBuffer[gMessagePos].endFade=-1; gMessageBuffer[gMessagePos].r=1; gMessageBuffer[gMessagePos].g=1; gMessageBuffer[gMessagePos].b=1; float dist=fabs(pos.z)/20.0; if(dist>1)dist=1; gMessageBuffer[gMessagePos].a=gTextOpacity*dist; gMessageBuffer[gMessagePos].align=align; gMessageBuffer[gMessagePos].tilt=0; vsprintf(gMessageBuffer[gMessagePos++].text,fmt,ap); // And Converts Symbols To Actual Numbers va_end(ap); // Results Are Stored In Text } void TextPrintfToBufferFormatedColored(tVector2 pos,float size,int align,float r,float g,float b,float a,const char *fmt, ...) { if(gMessagePos>=kMessageBufferSize) return; va_list ap; // Pointer To List Of Arguments if (fmt == NULL) // If There's No Text return; // Do Nothing va_start(ap, fmt); // Parses The String For Variables gMessageBuffer[gMessagePos].pos.x=pos.x*kTextXPos; gMessageBuffer[gMessagePos].pos.y=pos.y*kTextYPos; gMessageBuffer[gMessagePos].pos.z=-1; gMessageBuffer[gMessagePos].size=size; gMessageBuffer[gMessagePos].startFade=-1; gMessageBuffer[gMessagePos].endFade=-1; gMessageBuffer[gMessagePos].r=r; gMessageBuffer[gMessagePos].g=g; gMessageBuffer[gMessagePos].b=b; gMessageBuffer[gMessagePos].a=a*gTextOpacity; gMessageBuffer[gMessagePos].align=align; gMessageBuffer[gMessagePos].tilt=0; vsprintf(gMessageBuffer[gMessagePos++].text,fmt,ap); // And Converts Symbols To Actual Numbers va_end(ap); // Results Are Stored In Text } void TextPrintfToBufferFormatedColoredTilted(tVector2 pos,float size,int align,float tilt,float r,float g,float b,float a,const char *fmt, ...) { if(gMessagePos>=kMessageBufferSize) return; va_list ap; // Pointer To List Of Arguments if (fmt == NULL) // If There's No Text return; // Do Nothing va_start(ap, fmt); // Parses The String For Variables gMessageBuffer[gMessagePos].pos.x=pos.x*kTextXPos; gMessageBuffer[gMessagePos].pos.y=pos.y*kTextYPos; gMessageBuffer[gMessagePos].pos.z=-1; gMessageBuffer[gMessagePos].size=size; gMessageBuffer[gMessagePos].startFade=-1; gMessageBuffer[gMessagePos].endFade=-1; gMessageBuffer[gMessagePos].r=r; gMessageBuffer[gMessagePos].g=g; gMessageBuffer[gMessagePos].b=b; gMessageBuffer[gMessagePos].a=a*gTextOpacity; gMessageBuffer[gMessagePos].align=align; gMessageBuffer[gMessagePos].tilt=tilt; vsprintf(gMessageBuffer[gMessagePos++].text,fmt,ap); // And Converts Symbols To Actual Numbers va_end(ap); // Results Are Stored In Text } void TextPrintfToBufferFormatedFading(tVector2 pos,float size,int align,float startFade,float endFade,const char *fmt, ...) { if(gMessagePos>=kMessageBufferSize) return; va_list ap; // Pointer To List Of Arguments if (fmt == NULL) // If There's No Text return; // Do Nothing va_start(ap, fmt); // Parses The String For Variables gMessageBuffer[gMessagePos].pos.x=pos.x*kTextXPos; gMessageBuffer[gMessagePos].pos.y=pos.y*kTextYPos; gMessageBuffer[gMessagePos].pos.z=-1; gMessageBuffer[gMessagePos].size=size; gMessageBuffer[gMessagePos].startFade=gFrameCount+startFade*kFPS; gMessageBuffer[gMessagePos].endFade=gFrameCount+endFade*kFPS; gMessageBuffer[gMessagePos].startFadeIn=gFrameCount; gMessageBuffer[gMessagePos].r=1; gMessageBuffer[gMessagePos].g=1; gMessageBuffer[gMessagePos].b=1; gMessageBuffer[gMessagePos].a=gTextOpacity*0.7; gMessageBuffer[gMessagePos].align=align; gMessageBuffer[gMessagePos].tilt=0; vsprintf(gMessageBuffer[gMessagePos++].text,fmt,ap); // And Converts Symbols To Actual Numbers va_end(ap); // Results Are Stored In Text }