/* * PlanetPenguin Racer * Copyright (C) 2004-2005 Volker Stroebel * * Copyright (C) 1999-2001 Jasmin F. Patry * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gl_util.h" #include "fps.h" #include "phys_sim.h" #include "course_mgr.h" #include "hud.h" #include "stuff.h" #include "game_mgr.h" #include "gameconfig.h" #include "ppogl/base/defs.h" HUD HUD1; HUD HUD2; HUD::Element::Element() : type(-1), x(0), y(0), font(NULL), texture(0), width(0), height(0), size(0), angle(0) { } HUD::HUD() { m_numElements=0; } void HUD::reset() { m_numElements=0; initGauge(); } bool HUD::add(Element newElement){ if( m_numElements < HUD_MAX_ITEMS){ m_element[m_numElements] = newElement; m_numElements++; return true; }else{ return false; } } bool HUD::update(const int i, Element newElement){ if( m_numElements > i ){ m_element[i] = newElement; return true; }else{ //element i not available return false; } } void HUD::draw(Player& plyr, int width, int height) { m_width=width; m_height = height; gl::PushMatrix(); { gl::MatrixMode(GL_PROJECTION); gl::LoadIdentity(); gl::Ortho(0.0, m_width, 0.0, m_height, -1.0, 1.0); gl::MatrixMode(GL_MODELVIEW); gl::LoadIdentity(); gl::Translate(0.0, 0.0, -1.0); gl::Color(ppogl::Color::white); set_gl_options( TEXFONT ); for(int i=0; idraw(m_element[i].string, m_element[i].x, m_element[i].y); } } void HUD::fps(const int i) { if(m_element[i].font){ char string[BUFF_LEN]; sprintf( string, m_element[i].string.c_str(), fpsCounter.get() ); ppogl::Font::utf8ToUnicode(m_element[i].u_string,string); int width = int(m_element[i].font->advance(m_element[i].u_string)); fix_xy(m_element[i].x,m_element[i].y,m_element[i].height,width); m_element[i].font->draw(m_element[i].u_string, m_element[i].x, m_element[i].y); } } void HUD::herring(const int i, const int herring_count) { if(m_element[i].font){ char string[BUFF_LEN]; sprintf( string, m_element[i].string.c_str(), herring_count ); ppogl::Font::utf8ToUnicode(m_element[i].u_string,string); int width = int(m_element[i].font->advance(m_element[i].u_string)); fix_xy(m_element[i].x,m_element[i].y,m_element[i].height,width); m_element[i].font->draw(m_element[i].u_string, m_element[i].x, m_element[i].y); } } void HUD::image(const int i) { if(!m_element[i].texture) return; gl::Color(ppogl::Color::white); gl::BindTexture(GL_TEXTURE_2D, m_element[i].texture); fix_xy( m_element[i].x, m_element[i].y, m_element[i].height, m_element[i].width); gl::PushMatrix(); { gl::Translate(m_element[i].x, m_element[i].y); gl::Begin( GL_QUADS ); { gl::TexCoord(0, 0); gl::Vertex(0, 0); gl::TexCoord(double(m_element[i].width) / m_element[i].size,0.0); gl::Vertex(m_element[i].width, 0); gl::TexCoord( double(m_element[i].width) / m_element[i].size, double(m_element[i].height) / m_element[i].size ); gl::Vertex(m_element[i].width, m_element[i].height); gl::TexCoord(0.0, double(m_element[i].height) / m_element[i].size ); gl::Vertex(0.0, m_element[i].height); } gl::End(); } gl::PopMatrix(); } void HUD::time(const int i) { if(m_element[i].font){ char string[BUFF_LEN]; int minutes, seconds, hundredths; getTimeComponents( GameMgr::getInstance().time, minutes, seconds, hundredths ); sprintf( string, m_element[i].string.c_str(), minutes, seconds, hundredths); ppogl::Font::utf8ToUnicode(m_element[i].u_string,string); int width = int(m_element[i].font->advance(m_element[i].u_string)); fix_xy(m_element[i].x,m_element[i].y,m_element[i].height,width); m_element[i].font->draw(m_element[i].u_string, m_element[i].x, m_element[i].y); } } void HUD::speed(const int i, const double speed) { if(m_element[i].font){ char string[BUFF_LEN]; sprintf( string, m_element[i].string.c_str(), speed ); ppogl::Font::utf8ToUnicode(m_element[i].u_string,string); int width = int(m_element[i].font->advance(m_element[i].u_string)); fix_xy(m_element[i].x,m_element[i].y,m_element[i].height,width); m_element[i].font->draw(m_element[i].u_string, m_element[i].x-(width/2), m_element[i].y); } } void HUD::bar(const int i, double percentage) { if(!m_element[i].texture) return; if(percentage>1)percentage=1; double temp_sin=sin(double(m_element[i].angle)/180.0*M_PI); double temp_cos=cos(double(m_element[i].angle)/180.0*M_PI); gl::BindTexture(GL_TEXTURE_2D, m_element[i].texture); fix_xy(m_element[i].x,m_element[i].y,int(m_element[i].height)); gl::PushMatrix(); { gl::Translate(m_element[i].x, m_element[i].y,0); gl::Begin(GL_QUADS); { gl::TexCoord(0,0); gl::Vertex(0,0); gl::TexCoord(1,0); gl::Vertex(temp_cos*m_element[i].width,temp_sin*m_element[i].width); gl::TexCoord(1.0,percentage); gl::Vertex(temp_cos*m_element[i].width+temp_sin*m_element[i].height*percentage, temp_sin*m_element[i].width-temp_cos*m_element[i].height*percentage); gl::TexCoord(0.0,percentage); gl::Vertex(temp_sin*m_element[i].height*percentage, (-1)*temp_cos*m_element[i].height*percentage); } gl::End(); } gl::PopMatrix(); } //Sollte man bei Gelegenheit noch konfigurierbar machen #define ENERGY_GAUGE_BOTTOM 3.0 #define ENERGY_GAUGE_CENTER_X 71.0 #define ENERGY_GAUGE_CENTER_Y 55.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 * M_PER_SEC_TO_KM_PER_H ) #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 SPEED_UNITS_Y_OFFSET 4.0 static ppogl::Color energy_background_color(0.2, 0.2, 0.2, 0.5); static ppogl::Color energy_foreground_color(0.54, 0.59, 1.00, 0.5); static ppogl::Color speedbar_background_color(0.2, 0.2, 0.2, 0.5); void HUD::initGauge() { m_energymaskTex = ppogl::TextureMgr::getInstance().get("gauge_energy_mask"); m_speedmaskTex = ppogl::TextureMgr::getInstance().get("gauge_speed_mask"); m_outlineTex = ppogl::TextureMgr::getInstance().get("gauge_outline"); } void HUD::gauge(const int i, const double speed, const double energy) { GLfloat xplane[4] = { 1.0/m_element[i].size, 0.0, 0.0, 0.0 }; GLfloat yplane[4] = { 0.0, 1.0/m_element[i].size, 0.0, 0.0 }; double y; double speedbar_frac; //the gauge bar needs it's own mode //we reset the mode at the end of the function set_gl_options( GAUGE_BARS ); gl::TexGen(GL_S, GL_OBJECT_PLANE, xplane); gl::TexGen(GL_T, GL_OBJECT_PLANE, yplane); gl::PushMatrix(); { gl::Translate(m_width - m_element[i].width,0); gl::Color(energy_background_color); gl::BindTexture(GL_TEXTURE_2D, m_energymaskTex); y = ENERGY_GAUGE_BOTTOM + energy * m_element[i].height; gl::Begin( GL_QUADS ); { gl::Vertex(0.0, y); gl::Vertex(m_element[i].size, y); gl::Vertex(m_element[i].size, m_element[i].size); gl::Vertex(0.0, m_element[i].size); } gl::End(); gl::Color(energy_foreground_color); gl::Begin(GL_QUADS); { gl::Vertex(0.0, 0.0); gl::Vertex(m_element[i].size, 0.0); gl::Vertex(m_element[i].size, y); gl::Vertex(0.0, y); } gl::End(); /* Calculate the fraction of the speed bar to fill */ 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; } gl::Color(speedbar_background_color); gl::BindTexture(GL_TEXTURE_2D, m_speedmaskTex); draw_partial_tri_fan(1.0); gl::Color(ppogl::Color::white); draw_partial_tri_fan( MIN( 1.0, speedbar_frac ) ); gl::Color(ppogl::Color::white); gl::BindTexture(GL_TEXTURE_2D, m_outlineTex); gl::Begin(GL_QUADS); { gl::Vertex(0.0, 0.0); gl::Vertex(m_element[i].size, 0.0); gl::Vertex(m_element[i].size, m_element[i].size); gl::Vertex(0.0, m_element[i].size); } gl::End(); } gl::PopMatrix(); //we reset this because all other elements need TEXFONT set_gl_options( TEXFONT ); } #define CIRCLE_DIVISIONS 10 void HUD::draw_partial_tri_fan(const double fraction) { int divs; double angle, angle_incr, cur_angle; int i; bool trifan = false; ppogl::Vec2d pt; angle = SPEEDBAR_BASE_ANGLE + ( SPEEDBAR_MAX_ANGLE - SPEEDBAR_BASE_ANGLE ) * fraction; divs = int(( SPEEDBAR_BASE_ANGLE - angle ) * CIRCLE_DIVISIONS / 360.0); cur_angle = SPEEDBAR_BASE_ANGLE; angle_incr = 360.0 / CIRCLE_DIVISIONS; for (i=0; i angle + EPS ) { cur_angle = angle; if ( !trifan ) { start_tri_fan(); trifan = true; } pt = calc_new_fan_pt( cur_angle ); gl::Vertex(pt.x(), pt.y()); } if ( trifan ) { gl::End(); trifan = false; } } ppogl::Vec2d HUD::calc_new_fan_pt(const double angle ) { ppogl::Vec2d 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 HUD::start_tri_fan(void) { ppogl::Vec2d pt; gl::Begin(GL_TRIANGLE_FAN); gl::Vertex(ENERGY_GAUGE_CENTER_X, ENERGY_GAUGE_CENTER_Y); pt = calc_new_fan_pt( SPEEDBAR_BASE_ANGLE ); gl::Vertex(pt); } void HUD::fix_xy(int &x, int &y, const int asc, const int width) { if(x<0){ x=m_width+x-width+1; } if(y<0){ y=m_height+y-asc+1; } } void HUD::coursePercentage(const int i, const Player& plyr) { if(m_element[i].font){ char string[BUFF_LEN]; sprintf( string, m_element[i].string.c_str(), plyr.getCoursePercentage() ); ppogl::Font::utf8ToUnicode(m_element[i].u_string,string); int width = int(m_element[i].font->advance(m_element[i].u_string)); fix_xy(m_element[i].x,m_element[i].y,m_element[i].height,width); m_element[i].font->draw(m_element[i].u_string, m_element[i].x, m_element[i].y); } }