Redline/source/interfaceutil.cpp
2016-04-02 15:15:38 +02:00

1149 lines
36 KiB
C++

#include <OpenGL/gl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "gamemem.h"
#include "textures.h"
#include "gametime.h"
#include "interface.h"
#include "interfaceutil.h"
#include "vectors.h"
#include "text.h"
#include "controls.h"
#include "screen.h"
#include "carphysics.h"
#include "gamesystem.h"
#include "gamesound.h"
#include "random.h"
#include "interfacemultiplayer.h"
#include "log.h"
#include "initexit.h"
int gJoinFlag=false;
int gInterfaceType=false;
char gJoinHost[256];
char gLastMenuChar;
float gStartIdleTime=0;
/*
#define kNumEasterEggStrings 3
char gEasterEggStrings[kNumEasterEggStrings][256]={
"Easter Egg not yet implemented...",
"Bla Bla",
"Insert Funny Stuff here"
};
/*/
#define kNumEasterEggStrings 10
char gEasterEggStrings[kNumEasterEggStrings][256]={
"You better respect me, 'cos I'm the man with the car with the star",
"It's a long way to the top (if you wanna rock'n'roll!)",
"There's no replacement for displacement",
"echo \"carsOnSpeed 1\" >> ~/Library/Preferences/Redline\ Preferences",
"Moof!",
"All your horsepower are belong to us",
"Frog blast the vent core!",
"\255#w\255Everyone likes \255#r\255c\255#y\255o\255#g\255l\255#c\255o\255#b\255r\255#w\255 tags: \\255#r\\255",
"In Soviet Russia, car drives you!",
"out of errors."
};
#define kEasterEggScrollSpeed 0.8
#define kMenuFPS 75.0
#define kMenuFrameTime (1/kMenuFPS)
#define kMenuSuspendedFPS 0.5
#define kMenuSuspendedFrameTime (1/kMenuSuspendedFPS)
void InterfaceDrawBackgroundFade(float opacity,int showtop)
{
gTexturesQualityModifier=-255;
if(opacity==0)
return;
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_TEXTURE_BIT+GL_CURRENT_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1,1,1,opacity);
TexturesSelectTex(FileGetReference(kInterfaceBackgroundTexture));
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
if(showtop)
{
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch,kBackgroundYStretch);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch,kBackgroundYStretch);
glEnd();
TexturesSelectTex(FileGetReference("menustripe.tif"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch, 0.7*kScreenYPos);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch, 1.0*kScreenYPos);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch,0.7*kScreenYPos);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch,1.0*kScreenYPos);
glEnd();
}
else
{
if(ScreenSupportsBlendColor())
{
glBlendFunc(GL_CONSTANT_ALPHA,GL_ONE_MINUS_CONSTANT_ALPHA);
glBlendColor(1,1,1,opacity);
}
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(1,0.15); glVertex2f(kBackgroundXStretch,kBackgroundYStretch-0.3*kBackgroundXStretch);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(0,0.15); glVertex2f(-kBackgroundXStretch,kBackgroundYStretch-0.3*kBackgroundXStretch);
glEnd();
}
glDisable(GL_TEXTURE_2D);
glColor4f(0,0,0,opacity);
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(-kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glVertex2f(-kBackgroundXStretch,kBackgroundYStretch);
glVertex2f(-2*kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glVertex2f(-2*kBackgroundXStretch,kBackgroundYStretch);
glEnd();
glBegin(GL_TRIANGLE_STRIP);
glVertex2f(2*kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glVertex2f(2*kBackgroundXStretch,kBackgroundYStretch);
glVertex2f(kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glVertex2f(kBackgroundXStretch,kBackgroundYStretch);
glEnd();
glPopAttrib();
gTexturesQualityModifier=0;
}
void InterfaceDrawBackground(tFileRef background,tFileRef image,float imageXScale,float imageYScale,float imageXPos,float imageYPos,float alpha)
{
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
gTexturesQualityModifier=-255;
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glClear(GL_COLOR_BUFFER_BIT);
if(background!=kFileErr)
TexturesSelectTex(background);
else
TexturesSelectTex(FileGetReference(kInterfaceBackgroundTexture));
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
/*
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch,-kBackgroundYStretch);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch,kBackgroundYStretch);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch,-kBackgroundYStretch);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch,kBackgroundYStretch);
glEnd();
*/
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch,kBackgroundYStretch);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch,kBackgroundYStretch-2*kBackgroundXStretch);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch,kBackgroundYStretch);
glEnd();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
TexturesSelectTex(FileGetReference("menustripe.tif"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch, 0.7*kScreenYPos);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch, 1.0*kScreenYPos);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch,0.7*kScreenYPos);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch,1.0*kScreenYPos);
glEnd();
if(image!=kFileErr)
{
glColor4f(1,1,1,alpha);
TexturesSelectTex(image);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(imageXPos+imageXScale,imageYPos-imageYScale);
glTexCoord2d(1,0); glVertex2f(imageXPos+imageXScale,imageYPos+imageYScale);
glTexCoord2d(0,1); glVertex2f(imageXPos-imageXScale,imageYPos-imageYScale);
glTexCoord2d(0,0); glVertex2f(imageXPos-imageXScale,imageYPos+imageYScale);
glEnd();
}
glPopAttrib();
gTexturesQualityModifier=0;
}
void InterfaceFadeInImageFromBlack(float xSize,float ySize,tFileRef image,float maxTime)
{
gTexturesQualityModifier=-255;
TexturesSelectTex(image);
float startTime=TimeGetSeconds();
float time=0;
int exit=false;
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
while(!exit)
{
time=TimeGetSeconds()-startTime;
float alpha=(time/maxTime);
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_COLOR_BUFFER_BIT+GL_LIGHTING_BIT+GL_TEXTURE_BIT+GL_CURRENT_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1,1,1,alpha);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch*xSize,-kBackgroundYStretch*ySize);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch*xSize,kBackgroundYStretch*ySize);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch*xSize,-kBackgroundYStretch*ySize);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch*xSize,kBackgroundYStretch*ySize);
glEnd();
glPopAttrib();
ScreenBlit();
if(time>=maxTime)
exit=true;
}
gTexturesQualityModifier=0;
}
void InterfaceFadeInImageFromImage(float xSize,float ySize,tFileRef image,float xSize2,float ySize2,tFileRef image2,float maxTime)
{
gTexturesQualityModifier=-255;
float startTime=TimeGetSeconds();
float time=0;
int exit=false;
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
while(!exit)
{
time=TimeGetSeconds()-startTime;
float alpha=(time/maxTime);
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_COLOR_BUFFER_BIT+GL_LIGHTING_BIT+GL_TEXTURE_BIT+GL_CURRENT_BIT);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
TexturesSelectTex(image);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch*xSize,-kBackgroundYStretch*ySize);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch*xSize,kBackgroundYStretch*ySize);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch*xSize,-kBackgroundYStretch*ySize);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch*xSize,kBackgroundYStretch*ySize);
glEnd();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1,1,1,alpha);
TexturesSelectTex(image2);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f(kBackgroundXStretch*xSize2,-kBackgroundYStretch*ySize2);
glTexCoord2d(1,0); glVertex2f(kBackgroundXStretch*xSize2,kBackgroundYStretch*ySize2);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch*xSize2,-kBackgroundYStretch*ySize2);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch*xSize2,kBackgroundYStretch*ySize2);
glEnd();
glPopAttrib();
ScreenBlit();
if(time>=maxTime)
exit=true;
}
gTexturesQualityModifier=0;
}
void InterfaceFadeInInterfaceFromImage(tFileRef image,float maxTime)
{
float startTime=TimeGetSeconds();
float time=0;
int exit=false;
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
while(!exit)
{
time=TimeGetSeconds()-startTime;
float alpha=1-(time/maxTime);
InterfaceDrawBackground(-1,image,kBackgroundXStretch,kBackgroundYStretch,0,0,alpha);
ScreenBlit();
if(time>=maxTime)
exit=true;
}
}
void InterfaceDrawStrings(char *stringBuffer,char *secondaryStringBuffer,tFileRef background)
{
InterfaceDrawBackground(background,-1,0,0,0,0,1);
TextPrintfToBufferFormated(Vector(kTitlePosX,kTitlePosY),0.08,kTextAlignLeft,stringBuffer);
TextPrintfToBufferFormated(Vector(-0.9,0.5),0.05,kTextAlignLeft,secondaryStringBuffer);
// TextPrintfToBufferFormated(Vector(-1,0.97),0.03,kTextAlignLeft,gInterfaceMenuPath);
TextPrintBuffer(1,false);
TextClearBuffer();
ScreenBlit();
}
void InterfaceDrawStatusBar(char *stringBuffer,char *secondaryStringBuffer,float status)
{
InterfaceDrawBackground(-1,-1,0,0,0,0,1);
TextPrintfToBufferFormated(Vector(kTitlePosX,kTitlePosY),0.08,kTextAlignLeft,stringBuffer);
TextPrintfToBufferFormated(Vector(-0.9,0.5),0.05,kTextAlignLeft,secondaryStringBuffer);
// TextPrintfToBufferFormated(Vector(-1,0.97),0.03,kTextAlignLeft,gInterfaceMenuPath);
TextPrintBuffer(1,false);
TextClearBuffer();
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
gTexturesQualityModifier=-255;
TexturesSelectTex(FileGetReference("progress.pct"));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(status,1); glVertex2f(-kBackgroundXStretch*0.8+kBackgroundXStretch*1.6*status,-kBackgroundYStretch*0.1);
glTexCoord2d(status,0); glVertex2f(-kBackgroundXStretch*0.8+kBackgroundXStretch*1.6*status,kBackgroundYStretch*0.1);
glTexCoord2d(0,1); glVertex2f(-kBackgroundXStretch*0.8,-kBackgroundYStretch*0.1);
glTexCoord2d(0,0); glVertex2f(-kBackgroundXStretch*0.8,kBackgroundYStretch*0.1);
glEnd();
glPopAttrib();
ScreenBlit();
gTexturesQualityModifier=0;
}
void MenuSubTitleCallback(char *text,int selection,void *menu)
{
TextPrintfToBufferFormated(Vector(-0.85,0.6),0.05,kTextAlignLeft|kTextAutoWrap,text);
}
int InterfaceGetUserConfirmation(char *title,char *text)
{
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,2,title);
menu.RenderCallback=(void(*)(void*,int,void*))MenuSubTitleCallback;
menu.userData=text;
menu.itemsYPos=0.2;
char itemStrings[][32]={"OK","Cancel"};
for(int i=0;i<menu.numItems;i++)
strcpy(menu.items[i].label,itemStrings[i]);
InterfaceMenuZoomAnimation(&menu,0,true);
int result=!InterfaceGetUserMenuSelection(&menu);
InterfaceDisposeMenu(&menu);
return result;
}
int InterfaceGetUserInputString(char *prompt,char *stringBuffer,int bufferSize,int fullCharSet,int hideType)
{
*stringBuffer='\0';
char ch;
int len=0;
tInterfaceMenuDescribtion menu;
InterfaceInitMenu(&menu,0,"");
gInterfaceType=true;
do
{
//InterfaceDrawBackground(-1,-1,0,0,0,0,1);
InterfaceRenderReplay(NULL,0,&menu);
TextPrintfToBufferFormated(Vector(kTitlePosX,kTitlePosY),0.08,kTextAlignLeft,prompt);
if(!hideType)
TextPrintfToBufferFormated(Vector(-0.9,0.5),0.05,kTextAlignLeft,"%s%s",stringBuffer,(int)(TimeGetSeconds()*4.0)%2?"_":"");
else
{
char hiddenType[256];
int ch;
for(ch=0;ch<strlen(stringBuffer);ch++)
hiddenType[ch]='*';
hiddenType[ch]='\0';
TextPrintfToBufferFormated(Vector(-0.9,0.5),0.05,kTextAlignLeft,"%s%s",hiddenType,(int)(TimeGetSeconds()*4.0)%2?"_":"");
}
// TextPrintfToBufferFormated(Vector(-1,0.97),0.03,kTextAlignLeft,gInterfaceMenuPath);
TextPrintBuffer(1,false);
TextClearBuffer();
/* if(!anim)
{
InterfaceTextBufferZoomAnimation(-1,true);
anim=true;
}*/
ScreenBlit();
SystemPoll(false);
SystemYieldTime(TimeGetSeconds()+(gSystemSuspended?1.0:0.05));
ch=GetKeyInput(NULL);
if((ch==0x7f||ch==0x08)&&len>0)
stringBuffer[--len]='\0';
if(ch>=(fullCharSet?' ':'-')&&ch<='z'&&len<bufferSize-1)
{
PlayInterfaceSound(FileGetReference("type.wav"));
stringBuffer[len++]=ch;
stringBuffer[len]='\0';
}
/* if((ch=='\r'||ch==0x1b))
InterfaceTextBufferZoomAnimation(-1,false);*/
TextClearBuffer();
}
while(ch!='\r'&&ch!=0x1b);//wait until return or esc is pressed
gInterfaceType=false;
return(ch=='\r');
}
void InterfaceDisplayMessage(tFileRef background,char *stringBuffer,char *secondaryStringBuffer)
{
while(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)||GetInterfaceKey(kInterfaceKeyEsc));
TextPrintfToBufferFormated(Vector(kTitlePosX,kTitlePosY),0.08,kTextAlignLeft,stringBuffer);
TextPrintfToBufferFormated(Vector(-0.9,0.5),0.05,kTextAlignLeft|kTextAutoWrap,secondaryStringBuffer);
// TextPrintfToBufferFormated(Vector(-1,0.97),0.03,kTextAlignLeft,gInterfaceMenuPath);
InterfaceTextBufferZoomAnimation(background,true);
InterfaceDrawBackground(background,-1,0,0,0,0,1);
TextPrintBuffer(1,false);
ScreenBlit();
int exit=false;
while(!GetKeyInput(NULL)){
SystemPoll(false);
SystemYieldTime(TimeGetSeconds()+(gSystemSuspended?1.0:0.1));
}
InterfaceTextBufferZoomAnimation(background,false);
TextClearBuffer();
FlushKeys();
}
void CashString(int cash, char *str)
{
if(cash>=1000000)
sprintf(str,"$%d,%03d,%03d",cash/1000000,(cash/1000)%1000,cash%1000);
else if(cash>=1000)
sprintf(str,"$%d,%03d",cash/1000,cash%1000);
else
sprintf(str,"$%d",cash);
}
void MakeNumString(int i,char *str)
{
if((i%10)==1&&i!=11)
sprintf(str,"1st");
else if((i%10)==2&&i!=12)
sprintf(str,"2nd");
else if((i%10)==3&&i!=13)
sprintf(str,"3rd");
else
sprintf(str,"%dth",i);
}
void InterfaceInitMenu(tInterfaceMenuDescribtion *menu,int numItems,char *title)
{
menu->items=(tInterfaceMenuItemDescribtion*)MemoryAllocateBlock(sizeof(tInterfaceMenuItemDescribtion)*numItems);
strcpy(menu->title,title);
menu->initialSelection=0;
menu->numItems=numItems;
menu->image=-1;
menu->background=FileGetReference(kInterfaceBackgroundTexture);
menu->scrollEnable=false;
menu->joinDisable=false;
menu->enterAlwaysOK=false;
menu->easterEggEnable=false;
menu->menuTypeable=false;
menu->easterEggScrollPos=-10;
menu->easterEggString=0;
menu->imageXScale=kBackgroundXStretch;
menu->imageYScale=kBackgroundYStretch;
menu->imageAlpha=1.0;
menu->imageXPos=0;
menu->imageYPos=0;
menu->itemsXPos=-0.9;
menu->itemsYPos=0.55;
menu->minScroll=-0.75;
menu->type[0]='\0';
menu->returnOnSpace=false;
menu->cursorShowPos=10000;
menu->cursorPos=0;
menu->descPos=Vector(0.3,0.55);
menu->mousePos=GetMousePos();
menu->RenderCallback=NULL;
menu->TimerCallback=NULL;
menu->userData=NULL;
for(int i=0;i<numItems;i++)
{
menu->items[i].sel=0;
menu->items[i].label[0]='\0';
menu->items[i].describtion[0]='\0';
menu->items[i].type[0]='\0';
menu->items[i].size=0.05;
menu->items[i].lineSpacing=0.15;
menu->items[i].maxTypeXPos=0.95;
menu->items[i].maxTypeLength=255;
menu->items[i].sliderPos=0;
menu->items[i].sliderTransparency=0;
menu->items[i].r=1;
menu->items[i].g=1;
menu->items[i].b=1;
menu->items[i].flags=0;
}
}
void InterfaceDisposeMenu(tInterfaceMenuDescribtion *menu)
{
MemoryFreeBlock((tInterfaceMenuItemDescribtion*)menu->items);
}
void InterfaceMenuRender(tInterfaceMenuDescribtion *menu,int selection,float backgroundAlpha)
{
static float lt=0;
float t=TimeGetSeconds();
float dt=t-lt;
lt=t;
gTexturesQualityModifier=-255;
if(menu->background!=kFileErr)
InterfaceDrawBackground(menu->background,menu->image,menu->imageXScale,menu->imageYScale,menu->imageXPos,menu->imageYPos,menu->imageAlpha*backgroundAlpha);
gTexturesQualityModifier=0;
if(menu->RenderCallback)
menu->RenderCallback(menu->userData,selection,menu);
gTexturesQualityModifier=-255;
float line=menu->itemsYPos;
float selOffset=line;
if(selection!=-1&&menu->scrollEnable)
{
for(int i=0;i<selection;i++)
if(!(menu->items[i].flags&kInterfaceMenuItemFixedPos))
selOffset-=menu->items[i].lineSpacing;
float lastOffset=selOffset;
for(int i=selection;i<menu->numItems;i++)
if(!(menu->items[i].flags&kInterfaceMenuItemFixedPos))
lastOffset-=menu->items[i].lineSpacing;
if(lastOffset<menu->minScroll)
line+=((menu->itemsYPos-selOffset)/(menu->itemsYPos-lastOffset))*((menu->itemsYPos-lastOffset)-(menu->itemsYPos-menu->minScroll));
}
for(int i=0;i<menu->numItems;i++)
{
if((line<=menu->itemsYPos+menu->items[i].lineSpacing*0.5&&line>=menu->minScroll)||(!menu->scrollEnable)||menu->items[i].flags&kInterfaceMenuItemFixedPos)
{
char hiddenType[256];
int ch;
for(ch=0;ch<strlen(menu->items[i].type);ch++)
hiddenType[ch]='*';
hiddenType[ch]='\0';
char str[256];
int j=0;
int img=false;
if(menu->items[i].flags&kInterfaceMenuItemTypeable)
do
{
char *type=(menu->items[i].flags&kInterfaceMenuItemTypeHidden?hiddenType:menu->items[i].type)+j;
sprintf(str,"%s\255#a\255%s",menu->items[i].label,type);
if(j)
if(type[-1]=='\255')
img=!img;
j++;
}
while((TextWidth(str,menu->items[i].size*(1+0.1*menu->items[i].sel))+menu->itemsXPos*kTextXPos>kTextXPos*menu->items[i].maxTypeXPos||img)&&j!=strlen(menu->items[i].type));
else
strcpy(str,menu->items[i].label);
float fullLength=TextWidth(str,menu->items[i].size*(1+0.1*menu->items[i].sel));
float visRatio=fullLength/(kTextXPos*(menu->items[i].maxTypeXPos-menu->itemsXPos));
float textshift=0;
if(visRatio>1)
{
float scroll=menu->items[i].scroll/1.5f;
if(selection==i)
menu->items[i].scroll+=dt;
else if(menu->items[i].scroll>2)
menu->items[i].scroll=0;
else if(menu->items[i].scroll>1)
menu->items[i].scroll=2-menu->items[i].scroll;
else
menu->items[i].scroll-=dt;
float scrollsize;
if(scroll<1)
scrollsize=fullLength*(1-(1-(1/(visRatio+0.1)))*scroll);
else if(scroll<2)
scrollsize=fullLength*(1-(1-(1/(visRatio+0.1)))*(2-scroll));
else
scrollsize=fullLength;
char tmp[256];
strcpy(tmp,str);
j=0;
img=false;
char color=-1;
do
{
strcpy(str,tmp+j);
if(j)
if(tmp[j-1]=='\255')
{
img=!img;
if(img&&tmp[j]=='#')
color=tmp[j+1];
}
j++;
}
while((TextWidth(str,menu->items[i].size*(1+0.1*menu->items[i].sel))>scrollsize||img)&&j!=strlen(tmp));
textshift=scrollsize-TextWidth(str,menu->items[i].size*(1+0.1*menu->items[i].sel));
if(color!=-1)
{
strcpy(tmp,str);
sprintf(str,"\255#%c\255%s",color,tmp);
}
/* int scrollpos=0;
if(scroll<1)
scrollpos=(1-(1/visRatio))*strlen(str)*scroll;
else if(scroll<2)
scrollpos=(1-(1/visRatio))*strlen(str)*(2-scroll);
memmove(str,str+scrollpos,strlen(str+scrollpos)+1);*/
}
if(menu->items[i].scroll<0)
menu->items[i].scroll=0;
img=false;
int l=strlen(str);
while((TextWidth(str,menu->items[i].size*(1+0.1*menu->items[i].sel))+menu->itemsXPos*kTextXPos>kTextXPos*menu->items[i].maxTypeXPos||img)&&*str)
{
if(str[l-1]=='\255')
img=!img;
str[l-1]='\0';
l--;
}
if(menu->items[i].flags&kInterfaceMenuItemTypeable&&selection==i&&(int)(TimeGetSeconds()*4)%2)
sprintf(str,"%s%s",str,"_");
float a=(menu->items[i].flags&kInterfaceMenuItemDisabled?0.5:1)*(0.8+(0.2*menu->items[i].sel*0.5*(sin(TimeGetSeconds()*8)+1) ));
if(menu->items[i].flags&kInterfaceMenuItemFixedPos)
TextPrintfToBufferFormatedColored(Vector(menu->items[i].fixedX,menu->items[i].fixedY+menu->items[i].size*0.1*menu->items[i].sel)
,menu->items[i].size*(1+0.1*menu->items[i].sel)
,kTextAlignLeft
,menu->items[i].r
,menu->items[i].g
,menu->items[i].b
,a
,str
);
else
TextPrintfToBufferFormatedColored(Vector(menu->itemsXPos+textshift,line+menu->items[i].size*0.1*menu->items[i].sel)
,menu->items[i].size*(1+0.1*menu->items[i].sel)
,kTextAlignLeft
,menu->items[i].r
,menu->items[i].g
,menu->items[i].b
,a
,str
);
if(selection==i)
if(menu->items[i].flags&kInterfaceMenuItemFixedPos)
menu->cursorPos=(menu->items[i].fixedY-menu->items[i].size*1.3)*kScreenYPos;
else
menu->cursorPos=(line-menu->items[i].size*1.3)*kScreenYPos;
if(menu->items[i].flags&kInterfaceMenuItemSlider)
{
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
float y=(line-0.05)*kScreenYPos;
glColor4f(1,1,1,(1-menu->items[i].sliderTransparency)*backgroundAlpha);
TexturesSelectTex(FileGetReference(kInterfaceMenuSlideBarTexture));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+kInterfaceMenuSlideBarStart+kInterfaceMenuSlideBarWidth, y-kInterfaceMenuSlideBarHeight);
glTexCoord2d(1,0); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+kInterfaceMenuSlideBarStart+kInterfaceMenuSlideBarWidth, y+kInterfaceMenuSlideBarHeight);
glTexCoord2d(0,1); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+kInterfaceMenuSlideBarStart, y-kInterfaceMenuSlideBarHeight);
glTexCoord2d(0,0); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+kInterfaceMenuSlideBarStart, y+kInterfaceMenuSlideBarHeight);
glEnd();
TexturesSelectTex(FileGetReference(kInterfaceMenuSliderTexture));
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+menu->items[i].sliderPos*kInterfaceMenuSlideBarWidth+kInterfaceMenuSlideBarStart+kInterfaceMenuSliderSize, y-kInterfaceMenuSliderSize);
glTexCoord2d(1,0); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+menu->items[i].sliderPos*kInterfaceMenuSlideBarWidth+kInterfaceMenuSlideBarStart+kInterfaceMenuSliderSize, y+kInterfaceMenuSliderSize);
glTexCoord2d(0,1); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+menu->items[i].sliderPos*kInterfaceMenuSlideBarWidth+kInterfaceMenuSlideBarStart-kInterfaceMenuSliderSize, y-kInterfaceMenuSliderSize);
glTexCoord2d(0,0); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+menu->items[i].sliderPos*kInterfaceMenuSlideBarWidth+kInterfaceMenuSlideBarStart-kInterfaceMenuSliderSize, y+kInterfaceMenuSliderSize);
glEnd();
glPopAttrib();
}
}
if(!(menu->items[i].flags&kInterfaceMenuItemFixedPos))
line-=menu->items[i].lineSpacing;
}
TextPrintfToBufferFormated(Vector(kTitlePosX,kTitlePosY),0.08,kTextAlignLeft,menu->title);
float a=2-(TimeGetSeconds()-giTunesLastStatusUpdate)*0.4;
if(a>0)
{
char str[1024];
if(giTunesPlaying==kITunesPlaying)
sprintf(str,"%s - %s",giTunesArtist,giTunesSong);
else if(giTunesPlaying==kITunesPaused)
strcpy(str,"Paused");
else
strcpy(str,"Stopped");
float screenRatio=(float)gConfig->screenXSize/(float)gConfig->screenYSize;
float maxWidth=(0.1+screenRatio/(4.0/3.0))*kTextXPos;
float scale=1;
while(TextWidth(str,0.04*scale)>maxWidth)
scale*=0.9;
//printf("%f,%f/%f\n",size,TextWidth(str,size),maxWidth);
TextPrintfToBufferFormatedColored(Vector(-0.1,0.95+0.05*scale),0.04*scale,kTextAlignLeft,1,1,1,a,str);
}
glLoadIdentity();
glTranslatef(0.0f,0.0f,-1.0f);
glPushAttrib(GL_DEPTH_BUFFER_BIT+GL_LIGHTING_BIT+GL_COLOR_BUFFER_BIT+GL_CURRENT_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1,1,1,backgroundAlpha*(menu->menuTypeable&&*menu->type)?0.5:1);
TexturesSelectTex(FileGetReference(kInterfaceMenuPointerTexture));
glBegin(GL_TRIANGLE_STRIP);
float y=menu->cursorShowPos;
glTexCoord2d(1,1); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+kInterfaceMenuPointerSize,y-kInterfaceMenuPointerSize);
glTexCoord2d(1,0); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos+kInterfaceMenuPointerSize,y+kInterfaceMenuPointerSize);
glTexCoord2d(0,1); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos-kInterfaceMenuPointerSize,y-kInterfaceMenuPointerSize);
glTexCoord2d(0,0); glVertex2f((menu->itemsXPos-0.05)*kScreenXPos-kInterfaceMenuPointerSize,y+kInterfaceMenuPointerSize);
glEnd();
glPopAttrib();
if(selection!=-1)
TextPrintfToBufferFormatedColored(menu->descPos,0.03,kTextAlignLeft|kTextAutoWrap
,1,1,1,menu->items[selection].flags&kInterfaceMenuItemDisabled?0.45:1
,menu->items[selection].describtion);
TextPrintfToBufferFormatedColoredTilted(Vector(0+sin(menu->easterEggScrollPos*5)*0.1,-menu->easterEggScrollPos),0.05,kTextAlignMiddle,-cos(menu->easterEggScrollPos*5)*0.3,1,0.5,0,1,gEasterEggStrings[menu->easterEggString]);
TextPrintBuffer(backgroundAlpha,false);
TextClearBuffer();
ScreenBlit();
gTexturesQualityModifier=0;
}
#define kMenuAnimationTime 0.2
#define kMenuAnimationMaxXZoom 2.5
#define kMenuAnimationMaxYZoom 0.5
void InterfaceTextBufferZoomAnimation(tFileRef background,int in)
{
float startTime=TimeGetSeconds();
float time=0;
while(time<kMenuAnimationTime)
{
time=TimeGetSeconds()-startTime;
float f=time/kMenuAnimationTime;
gTextBufferScale.x=1+(in?1-f:f)*kMenuAnimationMaxXZoom;
gTextBufferScale.y=1+(in?1-f:f)*kMenuAnimationMaxYZoom;
InterfaceDrawBackground(background,-1,0,0,0,0,1);
TextPrintBuffer(0.5+0.5*(in?1-f:f),false);
SystemPoll(false);
ScreenBlit();
}
gTextBufferScale=Vector(1,1);
ScreenBlit();
}
void InterfaceMenuZoomAnimation(tInterfaceMenuDescribtion *menu,int selection,int in)
{
InterfaceMenuRender(menu,selection,(in?0:1));
float startTime=TimeGetSeconds();
float time=0;
while(time<kMenuAnimationTime)
{
time=TimeGetSeconds()-startTime;
float f=time/kMenuAnimationTime;
// gTextBufferScale.x=1+(in?1-f:f)*kMenuAnimationMaxXZoom;
// gTextBufferScale.y=1+(in?1-f:f)*kMenuAnimationMaxYZoom;
SystemPoll(false);
InterfaceMenuRender(menu,selection,(in?f:1-f));
}
gTextBufferScale=Vector(1,1);
ScreenBlit();
}
extern int gReggieConnected;
int InterfaceMenuInput(tInterfaceMenuDescribtion *menu,int *selection)
{
if(gSystemSuspended)
return false;
/*
tVector2 mousePos=GetMousePos();
int mouseSel=false;
float mouseBar=-1;
float y=menu->itemsYPos;
float minDist=1000;
for(int i=0;i<menu->numItems;i++)
{
float dist=fabs(y-menu->items[i].size-mousePos.y);
if(mousePos.x<menu->itemsXPos)
dist+=fabs(mousePos.x-menu->itemsXPos);
if(menu->items[i].flags&kInterfaceMenuItemSlider)
{
if(mousePos.x>menu->itemsXPos+(kInterfaceMenuSlideBarStart+kInterfaceMenuSlideBarWidth)/kScreenXPos)
dist+=fabs(mousePos.x-(menu->itemsXPos+(kInterfaceMenuSlideBarStart+kInterfaceMenuSlideBarWidth)/kScreenXPos));
}
else
if(mousePos.x>menu->itemsXPos+TextWidth(menu->items[i].label,menu->items[i].size)/kScreenXPos)
dist+=fabs(mousePos.x-(menu->itemsXPos+TextWidth(menu->items[i].label,menu->items[i].size)/kScreenXPos));
if(dist<minDist)
{
minDist=dist;
if(dist<0.2)
{
if(!VectorEqual(mousePos,menu->mousePos))
*selection=i;
mouseSel=true;
}
}
y-=menu->items[i].lineSpacing;
}
if(mousePos.x>menu->itemsXPos+kInterfaceMenuSlideBarStart/kScreenXPos&&mousePos.x<menu->itemsXPos+(kInterfaceMenuSlideBarStart+kInterfaceMenuSlideBarWidth)/kScreenXPos)
mouseBar=(mousePos.x-(menu->itemsXPos+kInterfaceMenuSlideBarStart/kScreenXPos))/(kInterfaceMenuSlideBarWidth/kScreenXPos)+0.08;
menu->mousePos=mousePos;
*/
int key;
char ch=GetKeyInput(&key);
gLastMenuChar=ch;
if(ch||key)
gStartIdleTime=TimeGetSeconds();
/* if(key==kInterfaceMouseDown&&mouseSel)
if(menu->items[*selection].flags&kInterfaceMenuItemSlider)
{
if(mouseBar>menu->items[*selection].sliderPos)
key=kInterfaceKeyRight;
else
key=kInterfaceKeyLeft;
}
else if(menu->items[*selection].flags&kInterfaceMenuItemArrowInput)
key=kInterfaceKeyRight;
else if(!(menu->items[*selection].flags&kInterfaceMenuItemTypeable))
key=kInterfaceKeyEnter;
*/
switch(key)
{
//cursor up/down movement
case kInterfaceKeyDown:
PlayInterfaceSound(FileGetReference("menu.wav"));
(*selection)++;
if(*selection>=menu->numItems)
*selection=0;
break;
case kInterfaceKeyUp:
PlayInterfaceSound(FileGetReference("menu.wav"));
(*selection)--;
if(*selection<0)
*selection=menu->numItems-1;
break;
//cursor left/right movement (if enabled)
case kInterfaceKeyLeft:
if(menu->items[*selection].flags&kInterfaceMenuItemArrowInput&&!(menu->items[*selection].flags&kInterfaceMenuItemDisabled))
{
PlayInterfaceSound(FileGetReference("toggle.wav"));
*selection|=kInterfaceMenuLeftArrow;
if(GetInterfaceKey(kInterfaceKeyEasterEgg))
*selection|=kInterfaceMenuEasterEgg;
return true;
}
break;
case kInterfaceKeyRight:
if(menu->items[*selection].flags&kInterfaceMenuItemArrowInput&&!(menu->items[*selection].flags&kInterfaceMenuItemDisabled))
{
PlayInterfaceSound(FileGetReference("toggle.wav"));
*selection|=kInterfaceMenuRightArrow;
if(GetInterfaceKey(kInterfaceKeyEasterEgg))
*selection|=kInterfaceMenuEasterEgg;
return true;
}
break;
//esc key
case kInterfaceKeyDelete:
if((menu->items[*selection].flags&kInterfaceMenuItemTypeable)||(menu->menuTypeable))
break;
case kInterfaceKeyEsc:
PlayInterfaceSound(FileGetReference("esc.wav"));
if(menu->menuTypeable&&*menu->type)
{
*menu->type='\0';
break;
}
InterfaceMenuZoomAnimation(menu,*selection,false);
*selection=kInterfaceMenuEsc;
return true;
case kInterfaceKeyEasterEgg:
if(menu->easterEggEnable)
menu->easterEggScrollPos=1.0;
menu->easterEggString=RandomInt(0,kNumEasterEggStrings);
break;
case kInterfaceKeyR:
if(menu->easterEggEnable)
{
InterfaceMenuZoomAnimation(menu,*selection,false);
*selection=kInterfaceMenuReplayKey;
return true;
}
break;
//enter key
case kInterfaceKeyReturn:
case kInterfaceKeyEnter:
if(menu->menuTypeable&&*menu->type)
return true;
PlayInterfaceSound(FileGetReference("select.wav"));
if(menu->enterAlwaysOK)
{
InterfaceMenuZoomAnimation(menu,*selection,false);
*selection=kInterfaceMenuOK;
return true;
}
if(!(menu->items[*selection].flags&(kInterfaceMenuItemTypeable|kInterfaceMenuItemDisabled|kInterfaceMenuItemArrowInput)))
InterfaceMenuZoomAnimation(menu,*selection,false);
if(!(menu->items[*selection].flags&kInterfaceMenuItemDisabled))
return true;
case kInterfaceKeySpace:
if(menu->returnOnSpace)
{
InterfaceMenuZoomAnimation(menu,*selection,false);
*selection|=kInterfaceMenuSpaceFlag;
return true;
}
break;
}
if(menu->items[*selection].flags&kInterfaceMenuItemTypeable||menu->menuTypeable&&!(menu->menuTypeable==kMenuTypeableReggie&&!gReggieConnected))
{
gInterfaceType=true;
if(ch)
{
int len=strlen((menu->items[*selection].flags&kInterfaceMenuItemTypeable)?menu->items[*selection].type:menu->type);
if((ch==0x7f||ch==0x08)&&len>0)
if(menu->items[*selection].flags&kInterfaceMenuItemTypeable)
menu->items[*selection].type[--len]='\0';
else
menu->type[--len]='\0';
if(ch>=' '&&ch<='z'&&ch!='%'&&len<menu->items[*selection].maxTypeLength)
{
PlayInterfaceSound(FileGetReference("type.wav"));
if(menu->items[*selection].flags&kInterfaceMenuItemTypeable)
{
menu->items[*selection].type[len++]=ch;
menu->items[*selection].type[len]='\0';
}
else
{
menu->type[len++]=ch;
menu->type[len]='\0';
}
}
}
}
else
gInterfaceType=menu->items[*selection].flags&kInterfaceMenuItemTypeable;
return false;
}
#define kMenuSelFadeTime 0.2
void InterfaceFadeMenuSelection(tInterfaceMenuDescribtion *menu,float dt,int selection)
{
for(int i=0;i<menu->numItems;i++)
{
menu->items[i].sel-=dt/kMenuSelFadeTime;
if(menu->items[i].sel<0)
menu->items[i].sel=0;
}
if( menu->items[selection].sel<1)
menu->items[selection].sel=1;
if(menu->cursorShowPos>10)
menu->cursorShowPos=menu->cursorPos;
if(menu->cursorShowPos>menu->cursorPos)
{
menu->cursorShowPos-=dt+dt*10*fabs(menu->cursorShowPos-menu->cursorPos);
if(menu->cursorShowPos<menu->cursorPos)
menu->cursorShowPos=menu->cursorPos;
}
else
{
menu->cursorShowPos+=dt+dt*10*fabs(menu->cursorShowPos-menu->cursorPos);
if(menu->cursorShowPos>menu->cursorPos)
menu->cursorShowPos=menu->cursorPos;
}
}
int InterfaceGetUserMenuSelection(tInterfaceMenuDescribtion *menu)
{
float lastTime=TimeGetSeconds();
int selection=menu->initialSelection;
int count=0;
do{
if(selection>=menu->numItems||selection<0)
selection=0;
if(gJoinFlag)
if(!menu->joinDisable)
{
gJoinFlag=false;
DirectJoinGame(gJoinHost);
}
else
return kInterfaceMenuEsc;
if(!gSystemSuspended||(count++%100==0))
InterfaceMenuRender(menu,selection,1);
SystemPoll(false);
SystemYieldTime(kMenuFrameTime+lastTime);
float time=TimeGetSeconds();
InterfaceFadeMenuSelection(menu,time-lastTime,selection);
menu->easterEggScrollPos-=kEasterEggScrollSpeed*(time-lastTime);
lastTime=time;
if(menu->TimerCallback)
{
int val=menu->TimerCallback(menu->userData);
if(val!=-1)
return val;
}
}while(!InterfaceMenuInput(menu,&selection));
return selection;
}
#define kScrollTextSize 0.05
int TextPrintFile(tFileRef fileId,float yStart)
{
float y=yStart;
char *fileData=(char*)FileGetDataPtr(fileId);
char *filePos=fileData;
int fileLenght=FileGetSize(fileId);
int linedrawn=false;
while(filePos<fileData+fileLenght)
{
char line[128];
GetLine(line,&filePos,fileData+fileLenght,128);
float a=1-((fabs(y)-0.55)/0.45);
if(a<0)a=0;
if(a>1)a=1;
if(y<=1+3*kScrollTextSize&&y>=-1-3*kScrollTextSize)
{
if(line[0]=='\255'&&line[1]!='#')
TextPrintfToBufferFormatedColored(Vector(0,y),kScrollTextSize*5,kTextAlignMiddle,1,1,1,a,line);
else
TextPrintfToBufferFormatedColored(Vector(0,y),kScrollTextSize,kTextAlignMiddle,1,1,1,a,line);
linedrawn=true;
}
y-=kScrollTextSize*3;
}
// InterfaceDrawBackground(-1,-1,0,0,0,0,1);
InterfaceRenderReplay(NULL,0,NULL);
TextPrintBuffer(1,false);
TextClearBuffer();
ScreenBlit();
return linedrawn;
}
void TextScrollFile(tFileRef fileId)
{
while(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)||GetInterfaceKey(kInterfaceKeyEsc));
float startTime=TimeGetSeconds();
int start=false;
int done=false;
while(!(GetInterfaceKey(kInterfaceKeyReturn)||GetInterfaceKey(kInterfaceKeyEnter)||GetInterfaceKey(kInterfaceKeyEsc)||GetInterfaceKey(kInterfaceKeyDelete)||done))
{
SystemPoll(false);
float time=TimeGetSeconds()-startTime;
float y=-1.2+time*0.2;
if(!TextPrintFile(fileId,y)){
if(start)
done=true;
}
else
start=true;
SystemPoll(false);
}
FlushKeys();
}