extremetuxracer/src/hud.cpp

394 lines
10 KiB
C++

/* --------------------------------------------------------------------
EXTREME TUXRACER
Copyright (C) 1999-2001 Jasmin F. Patry (Tuxracer)
Copyright (C) 2010 Extreme Tuxracer Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
---------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include <etr_config.h>
#endif
#include "hud.h"
#include "ogl.h"
#include "textures.h"
#include "spx.h"
#include "particles.h"
#include "font.h"
#include "course.h"
#include "physics.h"
#include "winsys.h"
#define GAUGE_IMG_SIZE 128
#define ENERGY_GAUGE_BOTTOM 3.0
#define ENERGY_GAUGE_HEIGHT 103.0
#define ENERGY_GAUGE_CENTER_X 71.0
#define ENERGY_GAUGE_CENTER_Y 55.0
#define GAUGE_WIDTH 128.0
#define SPEEDBAR_OUTER_RADIUS (ENERGY_GAUGE_CENTER_X)
#define SPEEDBAR_BASE_ANGLE 225
#define SPEEDBAR_MAX_ANGLE 45
#define SPEEDBAR_GREEN_MAX_SPEED (MAX_PADDLING_SPEED * 3.6)
#define SPEEDBAR_YELLOW_MAX_SPEED 100
#define SPEEDBAR_RED_MAX_SPEED 160
#define SPEEDBAR_GREEN_FRACTION 0.5
#define SPEEDBAR_YELLOW_FRACTION 0.25
#define SPEEDBAR_RED_FRACTION 0.25
#define CIRCLE_DIVISIONS 10
static const GLfloat energy_background_color[] = { 0.2, 0.2, 0.2, 0.0 };
static const GLfloat energy_foreground_color[] = { 0.54, 0.59, 1.00, 0.5 };
static const GLfloat speedbar_background_color[] = { 0.2, 0.2, 0.2, 0.0 };
static const GLfloat hud_white[] = { 1.0, 1.0, 1.0, 1.0 };
static const TColor text_colour(0, 0, 0, 1);
static void draw_time() {
int min, sec, hundr;
GetTimeComponents(g_game.time, &min, &sec, &hundr);
string timestr = Int_StrN(min, 2);
string secstr = Int_StrN(sec, 2);
string hundrstr = Int_StrN(hundr, 2);
timestr += ":";
timestr += secstr;
if (param.use_papercut_font < 2) {
Tex.DrawNumStr(timestr, 50, 12, 1, colWhite);
Tex.DrawNumStr(hundrstr, 170, 12, 0.7, colWhite);
} else {
/*
glEnable (GL_LINE_SMOOTH);
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
glLineWidth (1.5);
*/
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
Tex.Draw(T_TIME, 16, 20, 1);
FT.SetColor(colDYell);
FT.SetSize(32);
FT.DrawString(160, 6, hundrstr);
FT.SetSize(42);
FT.DrawString(70, 10, timestr);
}
}
static void draw_herring_count(int herring_count) {
string hcountstr = Int_StrN(herring_count, 3);
if (param.use_papercut_font < 2) {
Tex.DrawNumStr(hcountstr, Winsys.resolution.width - 90, 10, 1, colWhite);
Tex.Draw(HERRING_ICON, Winsys.resolution.width-160, -20, 1);
} else {
FT.SetColor(colDYell);
FT.DrawString(Winsys.resolution.width - 90, 10, hcountstr);
Tex.Draw(T_YELLHERRING, Winsys.resolution.width-160, 12, 1);
}
}
TVector2d calc_new_fan_pt(double angle) {
TVector2d pt;
pt.x = ENERGY_GAUGE_CENTER_X + cos(ANGLES_TO_RADIANS(angle)) * SPEEDBAR_OUTER_RADIUS;
pt.y = ENERGY_GAUGE_CENTER_Y + sin(ANGLES_TO_RADIANS(angle)) * SPEEDBAR_OUTER_RADIUS;
return pt;
}
void start_tri_fan() {
glBegin(GL_TRIANGLE_FAN);
glVertex2f(ENERGY_GAUGE_CENTER_X,
ENERGY_GAUGE_CENTER_Y);
TVector2d pt = calc_new_fan_pt(SPEEDBAR_BASE_ANGLE);
glVertex2f(pt.x, pt.y);
}
void draw_partial_tri_fan(double fraction) {
bool trifan = false;
double angle = SPEEDBAR_BASE_ANGLE +
(SPEEDBAR_MAX_ANGLE - SPEEDBAR_BASE_ANGLE) * fraction;
int divs = (int)((SPEEDBAR_BASE_ANGLE - angle) * CIRCLE_DIVISIONS / 360.0);
double cur_angle = SPEEDBAR_BASE_ANGLE;
double angle_incr = 360.0 / CIRCLE_DIVISIONS;
for (int i=0; i<divs; i++) {
if (!trifan) {
start_tri_fan();
trifan = true;
}
cur_angle -= angle_incr;
TVector2d pt = calc_new_fan_pt(cur_angle);
glVertex2f(pt.x, pt.y);
}
if (cur_angle > angle + EPS) {
cur_angle = angle;
if (!trifan) {
start_tri_fan();
trifan = true;
}
TVector2d pt = calc_new_fan_pt(cur_angle);
glVertex2f(pt.x, pt.y);
}
if (trifan) {
glEnd();
}
}
void draw_gauge(double speed, double energy) {
static const GLfloat xplane[4] = {1.0 / GAUGE_IMG_SIZE, 0.0, 0.0, 0.0 };
static const GLfloat yplane[4] = {0.0, 1.0 / GAUGE_IMG_SIZE, 0.0, 0.0 };
ScopedRenderMode rm(GAUGE_BARS);
if (Tex.GetTexture(GAUGE_ENERGY) == NULL) return;
if (Tex.GetTexture(GAUGE_SPEED) == NULL) return;
if (Tex.GetTexture(GAUGE_OUTLINE) == NULL) return;
Tex.BindTex(GAUGE_ENERGY);
glTexGenfv(GL_S, GL_OBJECT_PLANE, xplane);
glTexGenfv(GL_T, GL_OBJECT_PLANE, yplane);
glPushMatrix();
glTranslatef(Winsys.resolution.width - GAUGE_WIDTH, 0, 0);
Tex.BindTex(GAUGE_ENERGY);
double y = ENERGY_GAUGE_BOTTOM + energy * ENERGY_GAUGE_HEIGHT;
const GLfloat vtx1 [] = {
0.0, y,
GAUGE_IMG_SIZE, y,
GAUGE_IMG_SIZE, GAUGE_IMG_SIZE,
0.0, GAUGE_IMG_SIZE
};
const GLfloat vtx2 [] = {
0.0, 0.0,
GAUGE_IMG_SIZE, 0.0,
GAUGE_IMG_SIZE, y,
0.0, y
};
glEnableClientState(GL_VERTEX_ARRAY);
glColor4fv(energy_background_color);
glVertexPointer(2, GL_FLOAT, 0, vtx1);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glColor4fv(energy_foreground_color);
glVertexPointer(2, GL_FLOAT, 0, vtx2);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
double speedbar_frac = 0.0;
if (speed > SPEEDBAR_GREEN_MAX_SPEED) {
speedbar_frac = SPEEDBAR_GREEN_FRACTION;
if (speed > SPEEDBAR_YELLOW_MAX_SPEED) {
speedbar_frac += SPEEDBAR_YELLOW_FRACTION;
if (speed > SPEEDBAR_RED_MAX_SPEED) {
speedbar_frac += SPEEDBAR_RED_FRACTION;
} else {
speedbar_frac += (speed - SPEEDBAR_YELLOW_MAX_SPEED) /
(SPEEDBAR_RED_MAX_SPEED - SPEEDBAR_YELLOW_MAX_SPEED) * SPEEDBAR_RED_FRACTION;
}
} else {
speedbar_frac += (speed - SPEEDBAR_GREEN_MAX_SPEED) /
(SPEEDBAR_YELLOW_MAX_SPEED - SPEEDBAR_GREEN_MAX_SPEED) * SPEEDBAR_YELLOW_FRACTION;
}
} else {
speedbar_frac += speed/SPEEDBAR_GREEN_MAX_SPEED * SPEEDBAR_GREEN_FRACTION;
}
glColor4fv(speedbar_background_color);
Tex.BindTex(GAUGE_SPEED);
draw_partial_tri_fan(1.0);
glColor4fv(hud_white);
draw_partial_tri_fan(min(1.0, speedbar_frac));
glColor4fv(hud_white);
Tex.BindTex(GAUGE_OUTLINE);
static const GLshort vtx3 [] = {
0, 0,
GAUGE_IMG_SIZE, 0,
GAUGE_IMG_SIZE, GAUGE_IMG_SIZE,
0, GAUGE_IMG_SIZE
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_SHORT, 0, vtx3);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
}
void DrawSpeed(double speed) {
string speedstr = Int_StrN((int)speed, 3);
if (param.use_papercut_font < 2) {
Tex.DrawNumStr(speedstr,
Winsys.resolution.width - 85, Winsys.resolution.height-74, 1, colWhite);
} else {
FT.SetColor(colDDYell);
FT.DrawString(Winsys.resolution.width-82, Winsys.resolution.height-80, speedstr);
}
}
void DrawWind(float dir, float speed, const CControl *ctrl) {
if (g_game.wind_id < 1) return;
Tex.Draw(SPEEDMETER, 0, Winsys.resolution.height-140, 1.0);
glDisable(GL_TEXTURE_2D);
float alpha, red, blue;
if (speed <= 50) {
alpha = speed / 50;
red = 0;
} else {
alpha = 1.0;
red = (speed - 50) / 50;
}
blue = 1.0 - red;
glPushMatrix();
glColor4f(red, 0, blue, alpha);
glTranslatef(72, 66, 0);
glRotatef(dir, 0, 0, 1);
glEnableClientState(GL_VERTEX_ARRAY);
static const int len = 45;
static const GLshort vtx1 [] = {
-5, 0.0,
5, 0.0,
5, -len,
- 5, -len
};
glVertexPointer(2, GL_SHORT, 0, vtx1);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// direction indicator
float dir_angle = RADIANS_TO_ANGLES(atan2(ctrl->cvel.x, ctrl->cvel.z));
glColor4f(0, 0.5, 0, 1.0);
glRotatef(dir_angle - dir, 0, 0, 1);
static const GLshort vtx2 [] = {
-2, 0,
2, 0,
2, -50,
-2, -50
};
glVertexPointer(2, GL_SHORT, 0, vtx2);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glPopMatrix();
glEnable(GL_TEXTURE_2D);
Tex.Draw(SPEED_KNOB, 64, Winsys.resolution.height - 74, 1.0);
string windstr = Int_StrN((int)speed, 3);
if (param.use_papercut_font < 2) {
Tex.DrawNumStr(windstr, 130, Winsys.resolution.height - 55, 1, colWhite);
} else {
FT.SetColor(colBlue);
FT.DrawString(130, Winsys.resolution.height - 55, windstr);
}
}
void DrawFps() {
const int maxFrames = 50;
static int numFrames = 0;
static float averagefps = 0;
static float sumTime = 0;
if (!param.display_fps)
return;
if (numFrames >= maxFrames) {
averagefps = 1 / sumTime * maxFrames;
numFrames = 0;
sumTime = 0;
} else {
sumTime += g_game.time_step;
numFrames++;
}
if (averagefps < 1) return;
string fpsstr = Int_StrN((int)averagefps);
if (param.use_papercut_font < 2) {
Tex.DrawNumStr(fpsstr, (Winsys.resolution.width - 60) / 2, 10, 1, colWhite);
} else {
if (averagefps >= 35)
FT.SetColor(colWhite);
else
FT.SetColor(colRed);
FT.DrawString((Winsys.resolution.width - 60) / 2, 10, fpsstr);
}
}
void DrawPercentBar(float fact, float x, float y) {
Tex.BindTex(T_ENERGY_MASK);
glColor4f(1.0, 1.0, 1.0, 1.0);
const GLfloat tex[] = {
0, 0,
1, 0,
1, fact,
0, fact
};
const GLfloat vtx[] = {
x, y,
x + 32, y,
x + 32, y + fact * 128,
x, y + fact * 128
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vtx);
glTexCoordPointer(2, GL_FLOAT, 0, tex);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
void DrawCoursePosition(const CControl *ctrl) {
double fact = ctrl->cpos.z / Course.GetPlayDimensions().y;
if (fact > 1.0) fact = 1.0;
glEnable(GL_TEXTURE_2D);
DrawPercentBar(-fact, Winsys.resolution.width - 48, 280-128);
Tex.Draw(T_MASK_OUTLINE, Winsys.resolution.width - 48, Winsys.resolution.height - 280, 1.0);
}
// -------------------------------------------------------
void DrawHud(const CControl *ctrl) {
if (!param.show_hud)
return;
double speed = ctrl->cvel.Length();
SetupGuiDisplay();
draw_gauge(speed * 3.6, ctrl->jump_amt);
ScopedRenderMode rm(TEXFONT);
draw_time();
draw_herring_count(g_game.herring);
DrawSpeed(speed * 3.6);
DrawFps();
DrawCoursePosition(ctrl);
DrawWind(Wind.Angle(), Wind.Speed(), ctrl);
}