Added first version of track mini map to race gui.

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@3784 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2009-07-30 02:40:30 +00:00
parent 519dc6426d
commit 89b2eea124
9 changed files with 223 additions and 601 deletions

View File

@ -104,7 +104,7 @@ const std::string Challenge::getUnlockedMessage() const
Track* track = track_manager->getTrack( m_feature[n].name );
message = StringUtils::insert_values(
_("New track '%s'\nnow available"),
_(track->getName()) );
_(track->getName().c_str()) );
break;
}
case UNLOCK_MODE:

View File

@ -69,22 +69,11 @@ void Scene::reset()
//-----------------------------------------------------------------------------
void Scene::draw(float dt)
{
glEnable ( GL_DEPTH_TEST ) ;
const Track* TRACK = RaceManager::getTrack();
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
for (Cameras::iterator i = m_cameras.begin(); i != m_cameras.end(); ++i)
{
(*i)->update(dt);
(*i)->apply ();
} // for cameras
if (TRACK->useFog())
{
glDisable ( GL_FOG ) ;
}
glViewport ( 0, 0, UserConfigParams::m_width, UserConfigParams::m_height ) ;
}

View File

@ -74,8 +74,9 @@ void World::init()
TimedRace::setClockMode( CHRONO );
m_use_highscores = true;
// Create the race gui before anything else is attached to the scene node.
// This allows the race gui to do any rendering on texture.
// Create the race gui before anything else is attached to the scene node
// (which happens when the track is loaded). This allows the race gui to
// do any rendering on texture.
m_race_gui = new RaceGUI();
// Grab the track file
@ -161,7 +162,6 @@ void World::init()
// objects need to allocate data structures depending on the number
// of karts.
m_track->reset();
m_track->startMusic();
if(!history->replayHistory()) history->initRecording();

View File

@ -42,26 +42,15 @@ using namespace irr;
*/
RaceGUI::RaceGUI()
{
// FIXME: translation problem
m_pos_string[0] = "?!?";
m_pos_string[1] = "1st";
m_pos_string[2] = "2nd";
m_pos_string[3] = "3rd";
m_pos_string[4] = "4th";
m_pos_string[5] = "5th";
m_pos_string[6] = "6th";
m_pos_string[7] = "7th";
m_pos_string[8] = "8th";
m_pos_string[9] = "9th";
m_pos_string[10] = "10th";
int icon_width=40;
int icon_player_width=50;
if(UserConfigParams::m_height<600)
{
icon_width = 27;
icon_player_width = 35;
}
m_marker_rendered_size = 32;
m_marker_ai_size = 14;
m_marker_player_size = 16;
m_map_rendered_width = 128;
m_map_rendered_height = 128;
m_map_width = 100;
m_map_height = 100;
m_map_left = 10;
m_map_bottom = 10;
m_speed_meter_icon = material_manager->getMaterial("speedback.png");
m_speed_bar_icon = material_manager->getMaterial("speedfore.png");
@ -87,16 +76,16 @@ void RaceGUI::createMarkerTexture()
// Textures must be power of 2, so
while(npower2<n) npower2*=2;
int marker_size = 64; // must be a power of 2
int radius = (marker_size>>1)-1;
irr_driver->beginRenderToTexture(core::dimension2di(marker_size * npower2, marker_size),
int radius = (m_marker_rendered_size>>1)-1;
irr_driver->beginRenderToTexture(core::dimension2di(m_marker_rendered_size * npower2,
m_marker_rendered_size),
"RaceGUI::markers");
for(unsigned int i=0; i<race_manager->getNumKarts(); i++)
{
const std::string& kart_name = race_manager->getKartName(i);
const KartProperties *kp = kart_properties_manager->getKart(kart_name);
core::vector2df center((float)((marker_size>>1)+i*marker_size),
(float)(marker_size>>1));
core::vector2df center((float)((m_marker_rendered_size>>1)+i*m_marker_rendered_size),
(float)(m_marker_rendered_size>>1) );
int count = kp->getShape();
core::array<core::vector2df> vertices;
createRegularPolygon(count, (float)radius, center,&vertices);
@ -109,7 +98,6 @@ void RaceGUI::createMarkerTexture()
#endif
}
m_marker = irr_driver->endRenderToTexture();
core::dimension2di X = m_marker->getOriginalSize();
} // createMarkerTexture
//-----------------------------------------------------------------------------
@ -171,64 +159,40 @@ void RaceGUI::drawTimer ()
} // drawTimer
//-----------------------------------------------------------------------------
#define TRACKVIEW_SIZE 100
void RaceGUI::drawMap()
/** Draws the mini map and the position of all karts on it.
*/
void RaceGUI::drawMiniMap()
{
// arenas currently don't have a map.
if(RaceManager::getTrack()->isArena()) return;
const video::ITexture *mini_map=RaceManager::getTrack()->getMiniMap();
core::rect<s32> dest(10, UserConfigParams::m_height-60,
60, UserConfigParams::m_height-10);
int upper_y = UserConfigParams::m_height-m_map_bottom-m_map_height;
int lower_y = UserConfigParams::m_height-m_map_bottom;
core::rect<s32> dest(m_map_left, upper_y,
m_map_left + m_map_width, lower_y);
core::rect<s32> source(core::position2di(0, 0), mini_map->getOriginalSize());
//FIXME irr_driver->getVideoDriver()->draw2DImage(mini_map, dest, source, 0, 0, true);
core::rect<s32> dest1( 10, UserConfigParams::m_height-10,
100, UserConfigParams::m_height-110);
core::rect<s32> source1(core::position2di(0, 0), m_marker->getOriginalSize());
irr_driver->getVideoDriver()->draw2DImage(m_marker, dest, source1, 0, 0, true);
irr_driver->getVideoDriver()->draw2DImage(mini_map, dest, source, 0, 0, true);
return;
glDisable ( GL_TEXTURE_2D ) ;
assert(RaceManager::getWorld() != NULL);
int xLeft = 10;
int yTop = 10;
RaceManager::getTrack() -> draw2Dview ( (float)xLeft, (float)yTop );
glBegin ( GL_QUADS ) ;
for ( unsigned int i = 0 ; i < race_manager->getNumKarts() ; i++ )
for(unsigned int i=0; i<race_manager->getNumKarts(); i++)
{
Kart* kart = RaceManager::getKart(i);
const Kart *kart = RaceManager::getKart(i);
if(kart->isEliminated()) continue; // don't draw eliminated kart
//glColor3fv ( kart->getColor().toFloat());
const Vec3& xyz = kart->getXYZ();
/* If it's a player, draw a bigger sign */
// TODO
/*
if (kart -> isPlayerKart ())
{
RaceManager::getTrack() -> glVtx ( xyz.toFloat(), (float)xLeft+3, (float)yTop+3);
RaceManager::getTrack() -> glVtx ( xyz.toFloat(), (float)xLeft-2, (float)yTop+3);
RaceManager::getTrack() -> glVtx ( xyz.toFloat(), (float)xLeft-2, (float)yTop-2);
RaceManager::getTrack() -> glVtx ( xyz.toFloat(), (float)xLeft+3, (float)yTop-2);
}
else
{
RaceManager::getTrack() -> glVtx ( xyz.toFloat(), (float)xLeft+2, (float)yTop+2);
RaceManager::getTrack() -> glVtx ( xyz.toFloat(), (float)xLeft-1, (float)yTop+2);
RaceManager::getTrack() -> glVtx ( xyz.toFloat(), (float)xLeft-1, (float)yTop-1);
RaceManager::getTrack() -> glVtx ( xyz.toFloat(), (float)xLeft+2, (float)yTop-1);
}
*/
}
glEnd () ;
glEnable ( GL_TEXTURE_2D ) ;
const Vec3& xyz = kart->getXYZ();
Vec3 draw_at;
RaceManager::getTrack()->mapPoint2MiniMap(xyz, &draw_at);
int marker_height = m_marker->getOriginalSize().Height;
core::rect<s32> source(i *m_marker_rendered_size, 0,
(i+1)*m_marker_rendered_size, m_marker_rendered_size);
int marker_half_size = (kart->isPlayerKart() ? m_marker_player_size
: m_marker_ai_size )>>1;
core::rect<s32> position(m_map_left+(int)(draw_at.getX()-marker_half_size),
lower_y -(int)(draw_at.getY()+marker_half_size),
m_map_left+(int)(draw_at.getX()+marker_half_size),
lower_y -(int)(draw_at.getY()-marker_half_size));
irr_driver->getVideoDriver()->draw2DImage(m_marker, position, source, NULL, NULL, true);
} // for i<getNumKarts
} // drawMap
//-----------------------------------------------------------------------------
@ -737,7 +701,7 @@ void RaceGUI::drawStatusText()
drawMusicDescription();
}
//drawMap();
drawMiniMap();
drawPlayerIcons(info);
} // drawStatusText

View File

@ -84,14 +84,47 @@ private:
}
};
const char *m_pos_string [11];
Material *m_speed_meter_icon;
Material *m_speed_bar_icon;
Material *m_plunger_face;
typedef std::vector<TimedMessage> AllMessageType;
AllMessageType m_messages;
/** A texture with all mini dots to be displayed in the minimap for all karts. */
video::ITexture *m_marker;
/** The mini map of the track. */
video::ITexture *m_mini_map;
/** The size of a single marker in pixels, must be a power of 2. */
int m_marker_rendered_size;
/** The size of a single marker on the screen for AI karts,
* need not be a power of 2. */
int m_marker_ai_size;
/** The size of a single marker on the screen or player karts,
* need not be a power of 2. */
int m_marker_player_size;
/** The width of the rendered mini map in pixels, must be a power of 2. */
int m_map_rendered_width;
/** The height of the rendered mini map in pixels, must be a power of 2. */
int m_map_rendered_height;
/** Width of the map in pixels on the screen, need not be a power of 2. */
int m_map_width;
/** Height of the map in pixels on the screen, need not be a power of 2. */
int m_map_height;
/** Distance of map from left side of screen. */
int m_map_left;
/** Distance of map from bottom of screen. */
int m_map_bottom;
void createMarkerTexture();
void createRegularPolygon(unsigned int n, float radius,
const core::vector2df &center,
@ -110,7 +143,7 @@ private:
float ratio_x, float ratio_y );
void drawPlayerIcons (const KartIconDisplayInfo* info);
void oldDrawPlayerIcons ();
void drawMap ();
void drawMiniMap ();
void drawTimer ();
void drawMusicDescription ();
void cleanupMessages (const float dt);
@ -127,6 +160,10 @@ public:
void addMessage(const std::string &m, const Kart *kart, float time,
int fonst_size,
const video::SColor &color=video::SColor(255, 255, 0, 255));
/** Returns the size of the texture on which to render the minimap to. */
const core::dimension2di getMiniMapSize() const
{ return core::dimension2di(m_map_width, m_map_height); }
};
#endif

View File

@ -38,6 +38,7 @@ QuadGraph::QuadGraph(const std::string &quad_file_name,
m_node = NULL;
m_mesh = NULL;
m_mesh_buffer = NULL;
m_lap_length = 0;
m_all_quads = new QuadSet(quad_file_name);
GraphNode::m_all_quads = m_all_quads;
GraphNode::m_all_nodes = this;
@ -132,6 +133,15 @@ void QuadGraph::load(const std::string &filename)
}
delete xml;
for(unsigned int i=0; i<m_all_nodes.size(); i++)
{
if(m_all_nodes[i]->getSuccessor(0)==0)
{
m_lap_length = m_all_nodes[i]->getDistanceFromStart()
+ m_all_nodes[i]->getDistanceToSuccessor(0);
break;
}
}
setDefaultSuccessors();
} // load
@ -406,11 +416,6 @@ video::ITexture *QuadGraph::makeMiniMap(const core::dimension2di &dimension,
const video::SColor &fill_color)
{
irr_driver->beginRenderToTexture(dimension, name);
for(unsigned int i=0; i<m_all_quads->getNumberOfQuads(); i++)
{
// core::array<core::vector2df> vertices;
// vertices.push_back(core::vertices
}
createMesh();
video::S3DVertex *v = (video::S3DVertex*)m_mesh_buffer->getVertices();
for(unsigned int i=0; i<m_mesh_buffer->getVertexCount(); i++)
@ -420,16 +425,38 @@ video::ITexture *QuadGraph::makeMiniMap(const core::dimension2di &dimension,
m_node = irr_driver->addMesh(m_mesh); // add Debug Mesh
m_node->setMaterialFlag(video::EMF_LIGHTING, false);
// Add the camera:
// ---------------
scene::ICameraSceneNode *camera = irr_driver->addCamera();
Vec3 bb_min, bb_max;
m_all_quads->getBoundingBox(&bb_min, &bb_max);
Vec3 center = (bb_max+bb_min)*0.5f;
scene::ICameraSceneNode *camera = irr_driver->addCamera();
camera->setPosition(core::vector3df(center.getX(), 120, center.getY()));
core::matrix4 projection;
projection.buildProjectionMatrixOrthoLH(bb_max.getX()-bb_min.getX(),
bb_max.getY()-bb_min.getY(),
-1, bb_max.getZ()-bb_min.getZ()+1);
camera->setProjectionMatrix(projection, true);
camera->setPosition(core::vector3df(center.getX(), bb_max.getZ(), center.getY()));
camera->setUpVector(core::vector3df(0,0,1));
camera->setTarget(core::vector3df(center.getX(),0,center.getY()));
video::ITexture *texture=irr_driver->endRenderToTexture();
cleanupDebugMesh();
m_min_coord = bb_min;
m_scaling = dimension.Width/(bb_max.getX()-bb_min.getX());
return texture;
} // drawMiniMap
//-----------------------------------------------------------------------------
/** Returns the 2d coordinates of a point when drawn on the mini map
* texture.
* \param xyz Coordinates of the point to map.
* \param draw_at The coordinates in pixel on the mini map of the point,
* only the first two coordinates will be used.
*/
void QuadGraph::mapPoint2MiniMap(const Vec3 &xyz,Vec3 *draw_at) const
{
draw_at->setX((xyz.getX()-m_min_coord.getX())*m_scaling.getX());
draw_at->setY((xyz.getY()-m_min_coord.getY())*m_scaling.getY());
} // mapPoint

View File

@ -41,6 +41,15 @@ private:
/** For debug only: the actual mesh buffer storing the quads. */
scene::IMeshBuffer *m_mesh_buffer;
/** The length of the first loop. */
float m_lap_length;
/** The minimum coordinates of the quad graph. */
Vec3 m_min_coord;
/** Scaling for mini map, only x and y components are used. */
Vec3 m_scaling;
void setDefaultSuccessors();
void load (const std::string &filename);
void createMesh();
@ -66,33 +75,37 @@ public:
const std::string &name,
const video::SColor &fill_color
=video::SColor(127, 255, 255, 255) );
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
/** Returns the number of nodes in the graph. */
unsigned int getNumNodes() const { return m_all_nodes.size(); }
unsigned int getNumNodes() const { return m_all_nodes.size(); }
// ----------------------------------------------------------------------
/** Return the distance to the j-th successor of node n. */
float getDistanceToNext(int n, int j) const
float getDistanceToNext(int n, int j) const
{ return m_all_nodes[n]->getDistanceToSuccessor(j);}
// ----------------------------------------------------------------------
/** Returns the angle of the line between node n and its j-th.
* successor. */
float getAngleToNext(int n, int j) const
float getAngleToNext(int n, int j) const
{ return m_all_nodes[n]->getAngleToSuccessor(j); }
// ----------------------------------------------------------------------
/** Returns the number of successors of a node n. */
int getNumberOfSuccessors(int n) const
int getNumberOfSuccessors(int n) const
{ return m_all_nodes[n]->getNumberOfSuccessors(); }
// ----------------------------------------------------------------------
/** Returns the quad that belongs to a graph node. */
const Quad& getQuad(unsigned int j) const
const Quad& getQuad(unsigned int j) const
{ return m_all_quads->getQuad(m_all_nodes[j]->getIndex()); }
// ----------------------------------------------------------------------
/** Returns the quad that belongs to a graph node. */
GraphNode& getNode(unsigned int j) const{ return *m_all_nodes[j]; }
GraphNode& getNode(unsigned int j) const{ return *m_all_nodes[j]; }
// ----------------------------------------------------------------------
/** Returns the distance from the start to the beginning of a quad. */
float getDistanceFromStart(int j) const
float getDistanceFromStart(int j) const
{ return m_all_nodes[j]->getDistanceFromStart(); }
// ----------------------------------------------------------------------
/** Returns the length of the main driveline. */
float getLapLength() const {return m_lap_length; }
}; // QuadGraph
#endif

View File

@ -45,6 +45,7 @@ using namespace irr;
#include "physics/physical_object.hpp"
#include "physics/triangle_mesh.hpp"
#include "race/race_manager.hpp"
#include "states_screens/race_gui.hpp"
#include "tracks/bezier_curve.hpp"
#include "tracks/check_manager.hpp"
#include "tracks/quad_graph.hpp"
@ -54,28 +55,24 @@ using namespace irr;
const float Track::NOHIT = -99999.9f;
// ----------------------------------------------------------------------------
Track::Track( std::string filename_, float w, float h, bool stretch )
Track::Track( std::string filename)
{
m_filename = filename_;
m_item_style = "";
m_track_2d_width = w;
m_track_2d_height = h;
m_do_stretch = stretch;
m_description = "";
m_designer = "";
m_screenshot = "";
m_version = 0;
m_track_mesh = new TriangleMesh();
m_non_collision_mesh = new TriangleMesh();
m_filename = filename;
m_item_style = "";
m_description = "";
m_designer = "";
m_screenshot = "";
m_version = 0;
m_track_mesh = new TriangleMesh();
m_non_collision_mesh = new TriangleMesh();
m_all_nodes.clear();
m_all_meshes.clear();
m_has_final_camera = false;
m_is_arena = false;
m_quad_graph = NULL;
m_animation_manager = NULL;
m_check_manager = NULL;
m_has_final_camera = false;
m_is_arena = false;
m_quad_graph = NULL;
m_animation_manager = NULL;
m_check_manager = NULL;
loadTrack(m_filename);
loadQuadGraph();
} // Track
//-----------------------------------------------------------------------------
@ -85,6 +82,7 @@ Track::~Track()
if(m_quad_graph) delete m_quad_graph;
if(m_animation_manager) delete m_animation_manager;
if(m_check_manager) delete m_check_manager;
if(m_mini_map) irr_driver->removeTexture(m_mini_map);
} // ~Track
//-----------------------------------------------------------------------------
@ -153,18 +151,9 @@ btTransform Track::getStartTransform(unsigned int pos) const
orig.setZ( m_start_positions[pos][2] );
}
else
{
// sometimes the first kart would be too close
// to the first driveline point and not to the last one -->
// This kart would not get any lap counting done in the first
// lap! Therefore an offset is substracted from its Y location,
// and this offset is calculated based on the drivelines
float offset = 1.5f;
if(m_left_driveline[0].getY() > 0 || m_right_driveline[0].getY() > 0)
offset += std::max(m_left_driveline[0].getY(), m_left_driveline[0].getY());
{
orig.setX( pos<m_start_x.size() ? m_start_x[pos] : ((pos%2==0)?1.5f:-1.5f) );
orig.setY( pos<m_start_y.size() ? m_start_y[pos] : -1.5f*pos-offset );
orig.setY( pos<m_start_y.size() ? m_start_y[pos] : -1.5f*pos-1.5f );
orig.setZ( pos<m_start_z.size() ? m_start_z[pos] : 1.0f );
}
btTransform start;
@ -176,267 +165,6 @@ btTransform Track::getStartTransform(unsigned int pos) const
return start;
} // getStartTransform
//-----------------------------------------------------------------------------
/** It's not the nicest solution to have two very similar version of a function,
* i.e. drawScaled2D and draw2Dview - but to keep both versions const, the
* values m_scale_x/m_scale_y can not be changed, but they are needed in glVtx.
* So two functions are provided: one which uses temporary variables, and one
* which uses the pre-computed attributes (see constructor/loadQuadGraph)
* - which saves a bit of time at runtime as well.
* drawScaled2D is called from gui/TrackSel, draw2Dview from RaceGUI.
*/
void Track::drawScaled2D(float x, float y, float w, float h) const
{
float width = m_driveline_max.getX() - m_driveline_min.getX();
float sx = w / width;
float sy = h / ( m_driveline_max.getY()-m_driveline_min.getY() );
if( sx > sy )
{
sx = sy;
x += w/2 - width*sx/2;
}
else
{
sy = sx;
}
const unsigned int DRIVELINE_SIZE = (unsigned int)m_driveline.size();
glPushAttrib ( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT );
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable (GL_TEXTURE_2D);
glColor4f ( 1, 1, 1, 0.5) ;
glBegin ( GL_QUAD_STRIP ) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
{
glVertex2f ( x + ( m_left_driveline[i].getX() - m_driveline_min.getX() ) * sx,
y + ( m_left_driveline[i].getY() - m_driveline_min.getY() ) * sy) ;
glVertex2f ( x + ( m_right_driveline[i].getX() - m_driveline_min.getX() ) * sx,
y + ( m_right_driveline[i].getY() - m_driveline_min.getY() ) * sy ) ;
}
glVertex2f ( x + ( m_left_driveline[0].getX() - m_driveline_min.getX() ) * sx,
y + ( m_left_driveline[0].getY() - m_driveline_min.getY() ) * sy) ;
glVertex2f ( x + ( m_right_driveline[0].getX() - m_driveline_min.getX() ) * sx,
y + ( m_right_driveline[0].getY() - m_driveline_min.getY() ) * sy ) ;
glEnd () ;
glEnable( GL_LINE_SMOOTH );
glEnable( GL_POINT_SMOOTH );
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glLineWidth(1);
glPointSize(1);
glColor4f ( 0, 0, 0, 1 ) ;
glBegin ( GL_LINES ) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE - 1 ; ++i )
{
/*Draw left driveline of the map*/
glVertex2f ( x + ( m_left_driveline[i].getX() - m_driveline_min.getX() ) * sx,
y + ( m_left_driveline[i].getY() - m_driveline_min.getY() ) * sy ) ;
glVertex2f ( x + ( m_left_driveline[i+1].getX() - m_driveline_min.getX() ) * sx,
y + ( m_left_driveline[i+1].getY() - m_driveline_min.getY() ) * sy ) ;
/*Draw left driveline of the map*/
glVertex2f ( x + ( m_right_driveline[i].getX() - m_driveline_min.getX() ) * sx,
y + ( m_right_driveline[i].getY() - m_driveline_min.getY() ) * sy ) ;
glVertex2f ( x + ( m_right_driveline[i+1].getX() - m_driveline_min.getX() ) * sx,
y + ( m_right_driveline[i+1].getY() - m_driveline_min.getY() ) * sy ) ;
}
//Close the left driveline
glVertex2f ( x + ( m_left_driveline[DRIVELINE_SIZE - 1].getX() - m_driveline_min.getX() ) * sx,
y + ( m_left_driveline[DRIVELINE_SIZE - 1].getY() - m_driveline_min.getY() ) * sy ) ;
glVertex2f ( x + ( m_left_driveline[0].getX() - m_driveline_min.getX() ) * sx,
y + ( m_left_driveline[0].getY() - m_driveline_min.getY() ) * sy ) ;
//Close the right driveline
glVertex2f ( x + ( m_right_driveline[DRIVELINE_SIZE - 1].getX() - m_driveline_min.getX() ) * sx,
y + ( m_right_driveline[DRIVELINE_SIZE - 1].getY() - m_driveline_min.getY() ) * sy ) ;
glVertex2f ( x + ( m_right_driveline[0].getX() - m_driveline_min.getX() ) * sx,
y + ( m_right_driveline[0].getY() - m_driveline_min.getY() ) * sy ) ;
glEnd () ;
#if 0
//FIXME: We are not sure if it's a videocard problem, but on Linux with a
//Nvidia Geforce4 mx 440, we get problems with GL_LINE_LOOP;
//If this issue is solved, using GL_LINE_LOOP is a better solution than
//GL_LINES
glBegin ( GL_LINE_LOOP ) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
{
glVertex2f ( x + ( m_left_driveline[i].getX() - m_driveline_min.getX() ) * sx,
y + ( m_left_driveline[i].getY() - m_driveline_min.getY() ) * sy ) ;
}
glEnd () ;
glBegin ( GL_LINE_LOOP ) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
{
glVertex2f ( x + ( m_right_driveline[i].getX() - m_driveline_min.getX() ) * sx,
y + ( m_right_driveline[i].getY() - m_driveline_min.getY() ) * sy ) ;
}
glEnd () ;
#endif
glBegin ( GL_POINTS ) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
{
glVertex2f ( x + ( m_left_driveline[i].getX() - m_driveline_min.getX() ) * sx,
y + ( m_left_driveline[i].getY() - m_driveline_min.getY() ) * sy ) ;
glVertex2f ( x + ( m_right_driveline[i].getX() - m_driveline_min.getX() ) * sx,
y + ( m_right_driveline[i].getY() - m_driveline_min.getY() ) * sy ) ;
}
glEnd () ;
glPopAttrib();
} // drawScaled2D
//-----------------------------------------------------------------------------
void Track::draw2Dview (float x_offset, float y_offset) const
{
const unsigned int DRIVELINE_SIZE = (unsigned int)m_driveline.size();
glPushAttrib ( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_LINE_BIT );
glEnable ( GL_BLEND );
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable (GL_TEXTURE_2D);
//TODO: maybe colors should be configurable, or at least the alpha value
glColor4f ( 1.0f, 1.0f, 1.0f, 0.4f) ;
/*FIXME: Too much calculations here, we should be generating scaled driveline arrays
* in Track::loadQuadGraph so all we'd be doing is pumping out predefined
* vertexes in-game.
*/
/*Draw white filling of the map*/
glBegin ( GL_QUAD_STRIP ) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i ) {
glVertex2f ( x_offset + ( m_left_driveline[i].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_left_driveline[i].getY() - m_driveline_min.getY() ) * m_scale_y) ;
glVertex2f ( x_offset + ( m_right_driveline[i].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_right_driveline[i].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
}
glVertex2f ( x_offset + ( m_left_driveline[0].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_left_driveline[0].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
glVertex2f ( x_offset + ( m_right_driveline[0].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_right_driveline[0].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
glEnd () ;
glEnable( GL_LINE_SMOOTH );
glEnable( GL_POINT_SMOOTH );
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glLineWidth(2);
glPointSize(2);
glColor4f ( 0,0,0,1) ;
glBegin ( GL_LINES ) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE - 1 ; ++i )
{
/*Draw left driveline of the map*/
glVertex2f ( x_offset + ( m_left_driveline[i].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_left_driveline[i].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
glVertex2f ( x_offset + ( m_left_driveline[i+1].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_left_driveline[i+1].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
/*Draw left driveline of the map*/
glVertex2f ( x_offset + ( m_right_driveline[i].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_right_driveline[i].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
glVertex2f ( x_offset + ( m_right_driveline[i+1].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_right_driveline[i+1].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
}
//Close the left driveline
glVertex2f ( x_offset + ( m_left_driveline[DRIVELINE_SIZE - 1].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_left_driveline[DRIVELINE_SIZE - 1].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
glVertex2f ( x_offset + ( m_left_driveline[0].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_left_driveline[0].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
//Close the right driveline
glVertex2f ( x_offset + ( m_right_driveline[DRIVELINE_SIZE - 1].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_right_driveline[DRIVELINE_SIZE - 1].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
glVertex2f ( x_offset + ( m_right_driveline[0].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_right_driveline[0].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
glEnd () ;
#if 0
//FIXME: We are not sure if it's a videocard problem, but on Linux with a
//Nvidia Geforce4 mx 440, we get problems with GL_LINE_LOOP;
//If this issue is solved, using GL_LINE_LOOP is a better solution than
//GL_LINES
glBegin ( GL_LINE_LOOP ) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
{
glVertex2f ( x_offset + ( m_left_driveline[i].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_left_driveline[i].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
}
glEnd () ;
glBegin ( GL_LINE_LOOP ) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
{
glVertex2f ( x_offset + ( m_right_driveline[i].get() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_right_driveline[i].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
}
glEnd () ;
#endif
/*Because of the way OpenGL draws lines of widths higher than 1,
*we have to draw the joints too, in order to fill small spaces
*between lines
*/
glBegin ( GL_POINTS) ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
{
glVertex2f ( x_offset + ( m_left_driveline[i].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_left_driveline[i].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
glVertex2f ( x_offset + ( m_right_driveline[i].getX() - m_driveline_min.getX() ) * m_scale_x,
y_offset + ( m_right_driveline[i].getY() - m_driveline_min.getY() ) * m_scale_y ) ;
}
glEnd () ;
glPopAttrib();
} // draw2Dview
//-----------------------------------------------------------------------------
void Track::loadTrack(const std::string &filename)
{
@ -453,7 +181,7 @@ void Track::loadTrack(const std::string &filename)
m_gravity = 9.80665f;
m_sun_position = core::vector3df(0.4f, 0.4f, 0.4f);
m_sky_color = video::SColorf(0.3f, 0.7f, 0.9f, 1.0f);
m_fog_color = video::SColorf(0.3f, 0.7f, 0.9f, 1.0f);
m_fog_color = video::SColorf(0.3f, 0.7f, 0.9f, 1.0f).toSColor();
m_ambient_color = video::SColorf(0.5f, 0.5f, 0.5f, 1.0f);
m_specular_color = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
m_diffuse_color = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
@ -600,136 +328,16 @@ void Track::loadQuadGraph()
{
m_quad_graph = new QuadGraph(file_manager->getTrackFile(m_ident+".quads"),
file_manager->getTrackFile(m_ident+".graph"));
m_mini_map = m_quad_graph->makeMiniMap(core::dimension2di(128,128), m_ident);
m_mini_map = m_quad_graph->makeMiniMap(RaceManager::getWorld()->getRaceGUI()->getMiniMapSize(),
"minimap::"+m_ident);
if(m_quad_graph->getNumNodes()==0)
{
fprintf(stderr, "No graph nodes defined for track '%s'\n",
m_filename.c_str());
exit(-1);
}
readDrivelineFromFile(m_left_driveline, ".drvl");
const unsigned int DRIVELINE_SIZE = (unsigned int)m_left_driveline.size();
m_right_driveline.reserve(DRIVELINE_SIZE);
readDrivelineFromFile(m_right_driveline, ".drvr");
if(m_right_driveline.size() != m_left_driveline.size())
std::cout << "Error: driveline's sizes do not match, right " <<
"driveline is " << m_right_driveline.size() << " vertex long " <<
"and the left driveline is " << m_left_driveline.size()
<< " vertex long. Track is " << m_name << " ." << std::endl;
m_driveline.reserve(DRIVELINE_SIZE);
for(unsigned int i = 0; i < DRIVELINE_SIZE; ++i)
{
Vec3 center_point = (m_left_driveline[i]+m_right_driveline[i])*0.5;
m_driveline.push_back(center_point);
}
for(unsigned int i = 0; i < DRIVELINE_SIZE; ++i)
{
unsigned int next = i + 1 >= DRIVELINE_SIZE ? 0 : i + 1;
float dx = m_driveline[next].getX() - m_driveline[i].getX();
float dy = m_driveline[next].getY() - m_driveline[i].getY();
float theta = -atan2(dx, dy);
}
m_driveline_min = Vec3( 9999999.9f);
m_driveline_max = Vec3(-9999999.9f);
float d = 0.0f ;
for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
{
//Both drivelines must be checked to get the true size of
//the drivelines, and using the center driveline is not
//good enough.
m_driveline_min.min(m_right_driveline[i]);
m_driveline_min.min(m_left_driveline[i] );
m_driveline_max.max(m_right_driveline[i]);
m_driveline_max.max(m_left_driveline[i] );
d += (m_driveline[i]-m_driveline[ i==DRIVELINE_SIZE-1 ? 0 : i+1 ]).length();
}
m_total_distance = d;
Vec3 sc = m_driveline_max - m_driveline_min;
m_scale_x = m_track_2d_width / sc.getX();
m_scale_y = m_track_2d_height / sc.getY();
if(!m_do_stretch) m_scale_x = m_scale_y = std::min(m_scale_x, m_scale_y);
} // loadQuadGraph
//-----------------------------------------------------------------------------
void
Track::readDrivelineFromFile(std::vector<Vec3>& line, const std::string& file_ext)
{
std::string path = file_manager->getTrackFile(m_ident+file_ext);
FILE *fd = fopen ( path.c_str(), "r" ) ;
if ( fd == NULL )
{
std::ostringstream msg;
msg<<"Can't open '"<<path<<"' for reading.\n";
throw std::runtime_error(msg.str());
}
int prev_sector = QuadGraph::UNKNOWN_SECTOR;
float prev_distance = 1.51f;
while(!feof(fd))
{
char s [ 1024 ] ;
if ( fgets ( s, 1023, fd ) == NULL )
break ;
if ( *s == '#' || *s < ' ' )
continue ;
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
if (sscanf ( s, "%f,%f,%f", &x, &y, &z ) != 3 )
{
std::ostringstream msg;
msg<<"Syntax error in '"<<path<<"'\n";
throw std::runtime_error(msg.str());
}
Vec3 point(x,y,z);
if(prev_sector != QuadGraph::UNKNOWN_SECTOR)
prev_distance = (point-line[prev_sector]).length2_2d();
//1.5f was choosen because it's more or less the length of the tuxkart
if(prev_distance < 0.0000001)
{
fprintf(stderr, "File %s point %d is duplicated!.\n",
path.c_str(), prev_sector+1);
}
#if 0
else if(prev_distance < 1.5f)
{
fprintf(stderr,"File %s point %d is too close(<1.5) to previous point.\n",
path.c_str(), prev_sector + 1);
}
if(prev_distance > 15.0f)
{
fprintf(stderr,"In file %s point %d is too far(>15.0) from next point at %d.\n",
path, prev_sector, prev_distance);
}
#endif
line.push_back(point);
++prev_sector;
prev_distance -= 1.5f;
}
fclose ( fd ) ;
} // readDrivelineFromFile
// -----------------------------------------------------------------------------
//* Convert the ssg track tree into its physics equivalents.
void Track::createPhysicsModel()
@ -965,6 +573,11 @@ void Track::createWater(const XMLNode &node)
*/
void Track::loadTrackModel()
{
// Load the graph only now: this function is called from world, after
// the race gui was created. The race gui is needed since it stores
// the information about the size of the texture to render the mini
// map to.
loadQuadGraph();
// Add the track directory to the texture search path
file_manager->pushTextureSearchPath(file_manager->getTrackFile("",getIdent()));
file_manager->pushModelSearchPath (file_manager->getTrackFile("",getIdent()));
@ -1106,11 +719,10 @@ void Track::loadTrackModel()
file_manager->popTextureSearchPath();
file_manager->popModelSearchPath ();
const core::vector3df &sun_pos = getSunPos();
irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 120, 120, 120));
m_light = irr_driver->getSceneManager()->addLightSceneNode(NULL, sun_pos, video::SColorf(1.0f,1.0f,1.0f));
m_light = irr_driver->getSceneManager()->addLightSceneNode(NULL, m_sun_position,
video::SColorf(1.0f,1.0f,1.0f));
m_light->setLightType(video::ELT_DIRECTIONAL);
m_light->setRotation( core::vector3df(180, 45, 45) );
@ -1118,13 +730,17 @@ void Track::loadTrackModel()
m_light->getLightData().SpecularColor = irr::video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
/*
m_light = irr_driver->getSceneManager()->addLightSceneNode(0, sun_pos);
m_light = irr_driver->getSceneManager()->addLightSceneNode(0, m_sun_position);
video::SLight light;
// HACK & TEST: checking how ambient looks for some things, must be properly done once we reach an agreement
light.AmbientColor = irr::video::SColorf(0.666666f, 0.666666f, 0.666666f, 0.0f);
m_light->setLightData(light);
*/
if(m_use_fog)
{
irr_driver->getVideoDriver()->setFog(m_fog_color, true, m_fog_start, m_fog_end, m_fog_density);
}
// Note: the physics world for irrlicht is created in loadMainTrack
createPhysicsModel();

View File

@ -72,13 +72,14 @@ private:
Vec3 m_camera_final_hpr;
bool m_is_arena;
int m_version;
bool loadMainTrack(const XMLNode &node);
void createWater(const XMLNode &node);
/** The graph used to connect the quads. */
QuadGraph *m_quad_graph;
/** The type of sky to be used for the track. */
enum {SKY_NONE, SKY_BOX,
SKY_DOME} m_sky_type;
/** A list of the textures for the sky to use. It contains one texture
* in case of a dome, and 6 textures for a box. */
std::vector<std::string> m_sky_textures;
@ -100,6 +101,18 @@ private:
/** If a sky dome is used, percentage of the texture to be used. */
float m_sky_texture_percent;
std::string m_name;
bool m_use_fog;
float m_fog_density;
float m_fog_start;
float m_fog_end;
core::vector3df m_sun_position;
video::SColorf m_ambient_color;
video::SColorf m_specular_color;
video::SColorf m_diffuse_color;
video::SColorf m_sky_color;
video::SColor m_fog_color;
/** The texture for the mini map, which is displayed in the race gui. */
video::ITexture *m_mini_map;
@ -112,86 +125,60 @@ private:
/** Checkline manager. */
CheckManager *m_check_manager;
void loadTrack(const std::string &filename);
void itemCommand(const Vec3 &xyz, Item::ItemType item_type,
int bNeedHeight);
void loadQuadGraph();
void convertTrackToBullet(const scene::IMesh *mesh);
bool loadMainTrack(const XMLNode &node);
void createWater(const XMLNode &node);
void getMusicInformation(std::vector<std::string>& filenames,
std::vector<MusicInformation*>& m_music );
void loadCurves(const XMLNode &node);
void handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml);
public:
std::string m_name;
bool m_use_fog;
float m_fog_density;
float m_fog_start;
float m_fog_end;
core::vector3df m_sun_position;
video::SColorf m_ambient_color;
video::SColorf m_specular_color;
video::SColorf m_diffuse_color;
video::SColorf m_sky_color;
video::SColorf m_fog_color;
//FIXME: Maybe the next 4 vectors should be inside an struct and be used
//from a vector of structs?
//FIXME: should the driveline be set as a sgVec2?
private:
std::vector<Vec3> m_driveline;
//Left and Right drivelines for overhead map rendering.
std::vector<Vec3> m_left_driveline;
std::vector<Vec3> m_right_driveline;
public:
/** Start positions for arenas (unused in linear races) */
std::vector<Vec3> m_start_positions;
Vec3 m_driveline_min;
Vec3 m_driveline_max;
float m_total_distance;
static const float NOHIT;
float m_track_2d_width, // Width and heigth of the 2d display of the track
m_track_2d_height;
float m_scale_x, // Scaling to fit track into the size determined by
m_scale_y; // track2dWidth/Heightheigth
bool m_do_stretch; // 2d track display might be stretched to fit better
Track (std::string filename,float w=100,
float h=100, bool stretch=1);
Track (std::string filename);
~Track ();
bool isArena () const { return m_is_arena; }
void cleanup ();
/** Returns the texture with the mini map for this track. */
const video::ITexture*getMiniMap () const { return m_mini_map; }
void draw2Dview (float x_offset,
float y_offset ) const;
void drawScaled2D (float x, float y, float w,
float h ) const;
const Vec3& trackToSpatial (const int SECTOR) const;
void loadTrackModel ();
void addMusic (MusicInformation* mi)
{m_music.push_back(mi); }
float getGravity () const {return m_gravity; }
/** Returns the version of the .track file. */
int getVersion () const {return m_version; }
float getTrackLength () const {return m_total_distance; }
/** Returns the length of the main driveline. */
float getTrackLength () const {return m_quad_graph->getLapLength(); }
/** Returns a unique identifier for this track (the directory name). */
const std::string& getIdent () const {return m_ident; }
const char* getName () const {return m_name.c_str(); }
/** Returns the name of the track, which is e.g. displayed on the screen. */
const std::string& getName () const {return m_name; }
/** Returns all groups this track belongs to. */
const std::vector<std::string>
getGroups () const {return m_groups; }
/** Starts the music for this track. */
void startMusic () const;
/** Returns the filename of this track. */
const std::string& getFilename () const {return m_filename; }
const core::vector3df& getSunPos () const {return m_sun_position; }
const video::SColorf& getAmbientCol () const {return m_ambient_color; }
const video::SColorf& getDiffuseCol () const {return m_diffuse_color; }
const video::SColorf& getSpecularCol () const {return m_specular_color; }
const video::SColorf& getFogColor () const {return m_fog_color; }
const video::SColorf& getSkyColor () const {return m_sky_color; }
const bool& useFog () const {return m_use_fog; }
const float& getFogDensity () const {return m_fog_density; }
const float& getFogStart () const {return m_fog_start; }
const float& getFogEnd () const {return m_fog_end; }
const std::string& getDescription () const {return m_description; }
const std::string& getDesigner () const {return m_designer; }
const std::string& getScreenshotFile () const {return m_screenshot; }
@ -218,26 +205,15 @@ public:
* \param n Number of the quad for which the angle is asked.
*/
float getAngle(int n) const
{ return m_quad_graph->getAngleToNext(n, 0); }
/*
void glVtx (sgVec2 v, float x_offset, float y_offset) const
{
glVertex2f(
x_offset+(v[0]-m_driveline_min[0])*m_scale_x,
y_offset+(v[1]-m_driveline_min[1])*m_scale_y);
}*/
private:
void loadTrack(const std::string &filename);
void itemCommand(const Vec3 &xyz, Item::ItemType item_type,
int bNeedHeight);
void loadQuadGraph();
void readDrivelineFromFile(std::vector<Vec3>& line,
const std::string& file_ext);
void convertTrackToBullet(const scene::IMesh *mesh);
void getMusicInformation(std::vector<std::string>& filenames,
std::vector<MusicInformation*>& m_music );
}
; // class Track
{ return m_quad_graph->getAngleToNext(n, 0); }
/** Returns the 2d coordinates of a point when drawn on the mini map
* texture.
* \param xyz Coordinates of the point to map.
* \param draw_at The coordinates in pixel on the mini map of the point,
* only the first two coordinates will be used.
*/
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *draw_at) const
{ m_quad_graph->mapPoint2MiniMap(xyz, draw_at); }
}; // class Track
#endif