403 lines
11 KiB
C++
403 lines
11 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"
|
|
#include "game_ctrl.h"
|
|
#include <algorithm>
|
|
|
|
|
|
#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 GLubyte energy_background_color[] = { 51, 51, 51, 0 };
|
|
static const GLubyte energy_foreground_color[] = { 138, 150, 255, 128 };
|
|
static const GLubyte speedbar_background_color[] = { 51, 51, 51, 0 };
|
|
static const GLubyte hud_white[] = { 255, 255, 255, 255 };
|
|
|
|
static void draw_time(double time, sf::Color color) {
|
|
Tex.Draw(T_TIME, 10, 10, 1);
|
|
|
|
int min, sec, hundr;
|
|
GetTimeComponents(time, &min, &sec, &hundr);
|
|
std::string timestr = Int_StrN(min, 2);
|
|
std::string secstr = Int_StrN(sec, 2);
|
|
std::string hundrstr = Int_StrN(hundr, 2);
|
|
|
|
timestr += ':';
|
|
timestr += secstr;
|
|
|
|
if (param.use_papercut_font < 2) {
|
|
Tex.DrawNumStr(timestr, 50, 12, 1, color);
|
|
Tex.DrawNumStr(hundrstr, 170, 12, 0.7f, color);
|
|
} else {
|
|
Winsys.beginSFML();
|
|
FT.SetColor(color);
|
|
FT.SetSize(30);
|
|
FT.DrawString(138, 3, hundrstr);
|
|
FT.SetSize(42);
|
|
FT.DrawString(53, 3, timestr);
|
|
Winsys.endSFML();
|
|
}
|
|
}
|
|
|
|
static void draw_herring_count(int herring_count, sf::Color color) {
|
|
Tex.Draw(HERRING_ICON, Winsys.resolution.width - 59, 12, 1);
|
|
|
|
std::string hcountstr = Int_StrN(herring_count, 3);
|
|
if (param.use_papercut_font < 2) {
|
|
Tex.DrawNumStr(hcountstr, Winsys.resolution.width - 130, 12, 1, color);
|
|
} else {
|
|
Winsys.beginSFML();
|
|
FT.SetColor(color);
|
|
FT.DrawString(Winsys.resolution.width - 125, 3, hcountstr);
|
|
Winsys.endSFML();
|
|
}
|
|
}
|
|
|
|
TVector2d calc_new_fan_pt(double angle) {
|
|
return TVector2d(
|
|
ENERGY_GAUGE_CENTER_X + std::cos(ANGLES_TO_RADIANS(angle)) * SPEEDBAR_OUTER_RADIUS,
|
|
ENERGY_GAUGE_CENTER_Y + std::sin(ANGLES_TO_RADIANS(angle)) * SPEEDBAR_OUTER_RADIUS);
|
|
}
|
|
|
|
void draw_partial_tri_fan(double fraction) {
|
|
double angle = SPEEDBAR_BASE_ANGLE +
|
|
(SPEEDBAR_MAX_ANGLE - SPEEDBAR_BASE_ANGLE) * fraction;
|
|
|
|
int divs = (int)((SPEEDBAR_BASE_ANGLE - angle) * CIRCLE_DIVISIONS / 360.0) + 1;
|
|
double cur_angle = SPEEDBAR_BASE_ANGLE;
|
|
double angle_incr = 360.0 / CIRCLE_DIVISIONS;
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
glVertex2f(ENERGY_GAUGE_CENTER_X,
|
|
ENERGY_GAUGE_CENTER_Y);
|
|
|
|
for (int i=0; i<divs; i++) {
|
|
TVector2d pt = calc_new_fan_pt(cur_angle);
|
|
glVertex2f(pt.x, pt.y);
|
|
cur_angle -= angle_incr;
|
|
}
|
|
|
|
if (cur_angle+angle_incr > angle + EPS) {
|
|
cur_angle = angle;
|
|
TVector2d pt = calc_new_fan_pt(cur_angle);
|
|
glVertex2f(pt.x, pt.y);
|
|
}
|
|
|
|
glEnd();
|
|
}
|
|
|
|
void draw_gauge(double speed, double energy) {
|
|
static const GLfloat xplane[4] = {1.f / GAUGE_IMG_SIZE, 0.f, 0.f, 0.f };
|
|
static const GLfloat yplane[4] = {0.f, 1.f / GAUGE_IMG_SIZE, 0.f, 0.f };
|
|
|
|
ScopedRenderMode rm(GAUGE_BARS);
|
|
|
|
if (Tex.GetTexture(GAUGE_ENERGY) == nullptr) return;
|
|
if (Tex.GetTexture(GAUGE_SPEED) == nullptr) return;
|
|
if (Tex.GetTexture(GAUGE_OUTLINE) == nullptr) 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);
|
|
float y = ENERGY_GAUGE_BOTTOM + energy * ENERGY_GAUGE_HEIGHT;
|
|
|
|
const GLfloat vtx1 [] = {
|
|
0.f, y,
|
|
GAUGE_IMG_SIZE, y,
|
|
GAUGE_IMG_SIZE, GAUGE_IMG_SIZE,
|
|
0.f, GAUGE_IMG_SIZE
|
|
};
|
|
const GLfloat vtx2 [] = {
|
|
0.f, 0.f,
|
|
GAUGE_IMG_SIZE, 0.f,
|
|
GAUGE_IMG_SIZE, y,
|
|
0.f, y
|
|
};
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
|
|
glColor4ubv(energy_background_color);
|
|
glVertexPointer(2, GL_FLOAT, 0, vtx1);
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
glColor4ubv(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;
|
|
}
|
|
|
|
glColor4ubv(speedbar_background_color);
|
|
Tex.BindTex(GAUGE_SPEED);
|
|
draw_partial_tri_fan(1.0);
|
|
glColor4ubv(hud_white);
|
|
draw_partial_tri_fan(std::min(1.0, speedbar_frac));
|
|
|
|
glColor4ubv(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) {
|
|
std::string speedstr = Int_StrN((int)speed, 3);
|
|
if (param.use_papercut_font < 2) {
|
|
Tex.DrawNumStr(speedstr,
|
|
Winsys.resolution.width - 87, Winsys.resolution.height-73, 1, colWhite);
|
|
} else {
|
|
Winsys.beginSFML();
|
|
FT.SetColor(colDDYell);
|
|
FT.DrawString(Winsys.resolution.width - 82, Winsys.resolution.height - 80, speedstr);
|
|
Winsys.endSFML();
|
|
}
|
|
}
|
|
|
|
void DrawWind(float dir, float speed, const CControl *ctrl) {
|
|
if (g_game.wind_id < 1) return;
|
|
|
|
static const int texHeight = Tex.GetSFTexture(SPEEDMETER).getSize().y;
|
|
static const int texWidth = Tex.GetSFTexture(SPEEDMETER).getSize().x;
|
|
|
|
Tex.Draw(SPEEDMETER, 5, Winsys.resolution.height-5-texHeight, 1.0);
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
|
|
float alpha, red, blue;
|
|
if (speed <= 50) {
|
|
alpha = speed / 50;
|
|
red = 0;
|
|
} else {
|
|
alpha = 1.f;
|
|
red = (speed - 50) / 50;
|
|
}
|
|
blue = 1.f - red;
|
|
|
|
glPushMatrix();
|
|
glColor4f(red, 0, blue, alpha);
|
|
glTranslatef(5 + texWidth / 2, 5 + texHeight / 2, 0);
|
|
glRotatef(dir, 0, 0, 1);
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
static const int len = 45;
|
|
static const GLshort vtx1 [] = {
|
|
-5, 0,
|
|
5, 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(std::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, 5 + texWidth / 2 - 8, Winsys.resolution.height - 5 - texWidth / 2 - 8, 1.0);
|
|
std::string windstr = Int_StrN((int)speed, 3);
|
|
if (param.use_papercut_font < 2) {
|
|
Tex.DrawNumStr(windstr, 120, Winsys.resolution.height - 45, 1, colWhite);
|
|
} else {
|
|
Winsys.beginSFML();
|
|
FT.SetColor(colDDYell);
|
|
FT.DrawString(120, Winsys.resolution.height - 50, windstr);
|
|
Winsys.endSFML();
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
std::string fpsstr = Int_StrN((int)averagefps);
|
|
if (param.use_papercut_font < 2) {
|
|
Tex.DrawNumStr(fpsstr, (Winsys.resolution.width - 60) / 2, 10, 1, colWhite);
|
|
} else {
|
|
Winsys.beginSFML();
|
|
if (averagefps >= 35)
|
|
FT.SetColor(colWhite);
|
|
else
|
|
FT.SetColor(colRed);
|
|
FT.DrawString(-1, 3, fpsstr);
|
|
Winsys.endSFML();
|
|
}
|
|
}
|
|
|
|
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, 1,
|
|
1, 1,
|
|
1, 1 - fact,
|
|
0, 1 - 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();
|
|
Setup2dScene();
|
|
|
|
draw_gauge(speed * 3.6, ctrl->jump_amt);
|
|
ScopedRenderMode rm(TEXFONT);
|
|
|
|
if (g_game.game_type == CUPRACING) {
|
|
if (g_game.time < g_game.race->time.z)
|
|
draw_time(g_game.race->time.z - g_game.time, colGold);
|
|
else if (g_game.time < g_game.race->time.y)
|
|
draw_time(g_game.race->time.y - g_game.time, colSilver);
|
|
else if (g_game.time < g_game.race->time.x)
|
|
draw_time(g_game.race->time.x - g_game.time, colBronze);
|
|
else
|
|
draw_time(g_game.time, colDRed);
|
|
|
|
if (g_game.herring < g_game.race->herrings.x)
|
|
draw_herring_count(g_game.race->herrings.x - g_game.herring, colBronze);
|
|
else if (g_game.herring < g_game.race->herrings.y)
|
|
draw_herring_count(g_game.race->herrings.y - g_game.herring, colSilver);
|
|
else if (g_game.herring < g_game.race->herrings.z)
|
|
draw_herring_count(g_game.race->herrings.z - g_game.herring, colGold);
|
|
else
|
|
draw_herring_count(g_game.herring, colGreen);
|
|
} else {
|
|
draw_time(g_game.time, param.use_papercut_font < 2 ? colWhite : colDYell);
|
|
draw_herring_count(g_game.herring, param.use_papercut_font < 2 ? colWhite : colDYell);
|
|
}
|
|
|
|
DrawSpeed(speed * 3.6);
|
|
DrawFps();
|
|
DrawCoursePosition(ctrl);
|
|
DrawWind(Wind.Angle(), Wind.Speed(), ctrl);
|
|
}
|