Redline/source/text.cpp

533 lines
16 KiB
C++
Raw Permalink Normal View History

//text.cpp
//texture-based OpenGL font drawing code
#include <OpenGL/gl.h>
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#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;i<gTextFont->numChars;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&&*printPos<gTextFont->startChar+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)*size<maxWidth)
{
totalWidth+=(cInfo->x2-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<text+l)
{
if(*printPos=='\255')
{
do{
printPos++;
}while(*printPos!='\255'&&printPos<text+l);
}
if(*printPos>=gTextFont->startChar&&*printPos<gTextFont->startChar+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&&*str<gTextFont->startChar+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(gFrameCount<gMessageBuffer[i].startFadeIn+0.2*kFPS)
fade=(gFrameCount-gMessageBuffer[i].startFadeIn)/(float)(0.2*kFPS);
}
if(useInstrumentColor)
glColor4f(gEnvironment->instrumentColor.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&&*printPos<gTextFont->startChar+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<gMessagePos;i++)
if(gMessageBuffer[i].startFade!=-1&&gFrameCount<=gMessageBuffer[i].endFade)
{
gMessageBuffer[fadeCount]=gMessageBuffer[i];
fadeCount++;
}
gMessagePos=fadeCount;
}
void TextClearBufferFading()
{
gMessagePos=0;
}
void TextPrintfToBuffer(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=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
}