Back to index

supertuxkart  0.5+dfsg1
Classes | Public Types | Public Member Functions | Public Attributes | Static Public Attributes | Private Member Functions | Private Attributes
Track Class Reference

#include <track.hpp>

Collaboration diagram for Track:
Collaboration graph
[legend]

List of all members.

Classes

struct  SegmentTriangle
class  sgVec3Wrapper
 sgVec3 is a float[3] array, so unfortunately we can't put it in a std::vector because it lacks a copy-constructor, this hack should help... More...

Public Types

enum  RoadSide { RS_DONT_KNOW = -1, RS_LEFT = 0, RS_RIGHT = 1 }

Public Member Functions

 Track (std::string filename, float w=100, float h=100, bool stretch=1)
 ~Track ()
void cleanup ()
 Removes the physical body from the world.
void addDebugToScene (int type) const
void draw2Dview (float x_offset, float y_offset) const
void drawScaled2D (float x, float y, float w, float h) const
 It's not the nicest solution to have two very similar version of a function, i.e.
void findRoadSector (const sgVec3 XYZ, int *sector) const
 findRoadSector returns in which sector on the road the position xyz is.
int findOutOfRoadSector (const sgVec3 XYZ, const RoadSide SIDE, const int CURR_SECTOR) const
 findOutOfRoadSector finds the sector where XYZ is, but as it name implies, it is more accurate for the outside of the track than the inside, and for STK's needs the accuracy on top of the track is unacceptable; but if this was a 2D function, the accuracy for out of road sectors would be perfect.
int spatialToTrack (sgVec3 dst, const sgVec2 POS, const int SECTOR) const
 spatialToTrack() takes absolute coordinates (coordinates in OpenGL space) and transforms them into coordinates based on the track.
void trackToSpatial (sgVec3 xyz, const int SECTOR) const
void loadTrackModel ()
bool isShortcut (const int OLDSEC, const int NEWSEC) const
 Determines if a kart moving from sector OLDSEC to sector NEWSEC would be taking a shortcut, i.e.
void addMusic (MusicInformation *mi)
ssgBranch * getModel () const
float getGravity () const
float getTrackLength () const
const std::string & getIdent () const
const char * getName () const
void startMusic () const
const std::string & getFilename () const
const sgVec3 & getSunPos () const
const sgVec4 & getAmbientCol () const
const sgVec4 & getDiffuseCol () const
const sgVec4 & getSpecularCol () const
const bool & useFog () const
const sgVec4 & getFogColor () const
const float & getFogDensity () const
const float & getFogStart () const
const float & getFogEnd () const
const float & getAIAngleAdjustment () const
const float & getAICurveSpeedAdjustment () const
const sgVec4 & getSkyColor () const
const std::string & getDescription () const
const std::string & getDesigner () const
const std::string & getTopviewFile () const
const std::string & getScreenshotFile () const
const std::vector< SGfloat > & getWidth () const
const std::string & getHerringStyle () const
void getStartCoords (unsigned int pos, sgCoord *coords) const
 Returns the start coordinates for a kart on a given position pos (with 0<=pos).
void getTerrainInfo (const btVector3 &pos, float *hot, btVector3 *normal, const Material **material) const
void createPhysicsModel ()
void glVtx (sgVec2 v, float x_offset, float y_offset) const

Public Attributes

std::string m_name
sgVec4 m_sky_color
bool m_use_fog
sgVec4 m_fog_color
float m_fog_density
float m_fog_start
float m_fog_end
sgVec3 m_sun_position
sgVec4 m_ambient_col
 Position of the sun.
sgVec4 m_specular_col
sgVec4 m_diffuse_col
std::vector< sgVec3Wrapperm_driveline
std::vector< SGfloat > m_distance_from_start
std::vector< SGfloat > m_path_width
std::vector< SGfloat > m_angle
std::vector< sgVec3Wrapperm_left_driveline
std::vector< sgVec3Wrapperm_right_driveline
sgVec2 m_driveline_min
sgVec2 m_driveline_max
float m_total_distance
float m_track_2d_width
float m_track_2d_height
float m_scale_x
float m_scale_y
bool m_do_stretch

Static Public Attributes

static const int QUAD_TRI_NONE = -1
static const int QUAD_TRI_FIRST = 1
static const int QUAD_TRI_SECOND = 2
static const int UNKNOWN_SECTOR = -1
static const float NOHIT = -99999.9f

Private Member Functions

void loadTrack (std::string filename)
void herring_command (sgVec3 *xyz, char htype, int bNeedHeight)
void loadDriveline ()
void readDrivelineFromFile (std::vector< sgVec3Wrapper > &line, const std::string &file_ext)
void convertTrackToBullet (ssgEntity *track, sgMat4 m)
float pointSideToLine (const sgVec2 L1, const sgVec2 L2, const sgVec2 P) const
 Finds on which side of the line segment a given point is.
int pointInQuad (const sgVec2 A, const sgVec2 B, const sgVec2 C, const sgVec2 D, const sgVec2 POINT) const
 pointInQuad() works by checking if the given point is 'to the right' in clock-wise direction (which would be to look towards the inside of the quad) of each line segment that forms the quad.
void getMusicInformation (std::vector< std::string > &filenames, std::vector< MusicInformation * > &m_music)

Private Attributes

float m_gravity
std::string m_ident
std::string m_screenshot
std::string m_top_view
std::vector< MusicInformation * > m_music
std::vector< float > m_start_x
std::vector< float > m_start_y
std::vector< float > m_start_z
std::vector< float > m_start_heading
std::string m_herring_style
std::string m_description
std::string m_designer
std::string m_filename
ssgBranch * m_model
TriangleMeshm_track_mesh
TriangleMeshm_non_collision_mesh
float m_AI_angle_adjustment
float m_AI_curve_speed_adjustment

Detailed Description

Definition at line 41 of file track.hpp.


Member Enumeration Documentation

Enumerator:
RS_DONT_KNOW 
RS_LEFT 
RS_RIGHT 

Definition at line 63 of file track.hpp.

{ RS_DONT_KNOW = -1, RS_LEFT = 0, RS_RIGHT = 1 };

Constructor & Destructor Documentation

Track::Track ( std::string  filename,
float  w = 100,
float  h = 100,
bool  stretch = 1 
)

Definition at line 55 of file track.cpp.

Here is the call graph for this function:

Definition at line 73 of file track.cpp.

{
}   // ~Track

Member Function Documentation

void Track::addDebugToScene ( int  type) const

type ==1

Definition at line 459 of file track.cpp.

{
    if(type&1)
    {
        ssgaSphere *sphere;
        sgVec3 center;
        sgVec4 colour;
        for(unsigned int i = 0; i < m_driveline.size(); ++i)
        {
            sphere = new ssgaSphere;
            sgCopyVec3(center, m_driveline[i]);
            sphere->setCenter(center);
            sphere->setSize(getWidth()[i] / 4.0f);
        
            if(i == 0)
            {
                colour[0] = colour[2] = colour[3] = 255;
                colour[1] = 0;
            }
            else
            {
                colour[0] = colour[1] = colour[3] = 255;
                colour[2] = 0;
            }
            sphere->setColour(colour);
            scene->add(sphere);
        }   // for i
    }  
    if(type&2)
    {
        ssgVertexArray* v_array = new ssgVertexArray();
        ssgColourArray* c_array = new ssgColourArray();
        for(unsigned int i = 0; i < m_driveline.size(); i++)
        {
            int ip1 = i==m_driveline.size()-1 ? 0 : i+1;
            // The segment display must be slightly higher than the
            // track, otherwise it's not clearly visible.
            sgVec3 v;
            sgCopyVec3(v,m_left_driveline [i  ]); v[2]+=0.1f; v_array->add(v);
            sgCopyVec3(v,m_right_driveline[i  ]); v[2]+=0.1f; v_array->add(v);
            sgCopyVec3(v,m_right_driveline[ip1]); v[2]+=0.1f; v_array->add(v);
            sgCopyVec3(v,m_left_driveline [ip1]); v[2]+=0.1f; v_array->add(v);
            sgVec4 vc;
            vc[0] = i%2==0 ? 1.0f : 0.0f;
            vc[1] = 1.0f-v[0];
            vc[2] = 0.0f;
            vc[3] = 0.1f;
            c_array->add(vc);c_array->add(vc);c_array->add(vc);c_array->add(vc);
        }   // for i
        // if GL_QUAD_STRIP is used, the colours are smoothed, so the changes
        // from one segment to the next are not visible.
        ssgVtxTable* l = new ssgVtxTable(GL_QUADS, v_array,
                                         (ssgNormalArray*)NULL,
                                         (ssgTexCoordArray*)NULL,
                                         c_array);
        scene->add(l);
    }
}   // addDebugToScene

Here is the call graph for this function:

Here is the caller graph for this function:

void Track::addMusic ( MusicInformation mi) [inline]

Definition at line 168 of file track.hpp.

                                                  {m_music.push_back(mi);       }

Here is the caller graph for this function:

void Track::cleanup ( )

Removes the physical body from the world.

Called at the end of a race.

Definition at line 80 of file track.cpp.

{
    delete m_non_collision_mesh;
    delete m_track_mesh;

    // remove temporary materials loaded by the material manager
    material_manager->popTempMaterial();
}   // cleanup

Here is the call graph for this function:

Here is the caller graph for this function:

void Track::convertTrackToBullet ( ssgEntity *  track,
sgMat4  m 
) [private]

Definition at line 1075 of file track.cpp.

{
    if(!track) return;
    MovingPhysics *mp = dynamic_cast<MovingPhysics*>(track);
    if(mp)
    {
        // If the track contains obect of type MovingPhysics,
        // these objects will be real rigid body and are already
        // part of the world. So these objects must not be converted
        // to triangle meshes.
    } 
    else if(track->isAKindOf(ssgTypeLeaf()))
    {
        ssgLeaf  *leaf     = (ssgLeaf*)(track);
        Material *material = material_manager->getMaterial(leaf);
        // Don't convert triangles with material that is ignored (e.g. fuzzy_sand)
        if(!material || material->isIgnore()) return;

        for(int i=0; i<leaf->getNumTriangles(); i++) 
        {
            short v1,v2,v3;
            sgVec3 vv1, vv2, vv3;
            
            leaf->getTriangle(i, &v1, &v2, &v3);
            sgXformPnt3 ( vv1, leaf->getVertex(v1), m );
            sgXformPnt3 ( vv2, leaf->getVertex(v2), m );
            sgXformPnt3 ( vv3, leaf->getVertex(v3), m );
            btVector3 vb1(vv1[0],vv1[1],vv1[2]);
            btVector3 vb2(vv2[0],vv2[1],vv2[2]);
            btVector3 vb3(vv3[0],vv3[1],vv3[2]);
            if(material->isZipper()) 
            {
                m_non_collision_mesh->addTriangle(vb1, vb2, vb3, material);
            }
            else
            {
                m_track_mesh->addTriangle(vb1, vb2, vb3, material);
            }
        }
        
    }   // if(track isAKindOf leaf)
    else if(track->isAKindOf(ssgTypeTransform()))
    {
        ssgBaseTransform *t = (ssgBaseTransform*)(track);
        sgMat4 tmpT, tmpM;
        t->getTransform(tmpT);
        sgCopyMat4(tmpM, m);
        sgPreMultMat4(tmpM,tmpT);
        for(ssgEntity *e = t->getKid(0); e!=NULL; e=t->getNextKid())
        {
            convertTrackToBullet(e, tmpM);
        }   // for i
    }
    else if (track->isAKindOf(ssgTypeBranch())) 
    {
        ssgBranch *b =(ssgBranch*)track;
        for(ssgEntity* e=b->getKid(0); e!=NULL; e=b->getNextKid()) {
            convertTrackToBullet(e, m);
        }   // for i<getNumKids
    }
    else
    {
        assert(!"Unkown ssg type in convertTrackToBullet");
    }
}   // convertTrackToBullet

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1057 of file track.cpp.

{
    if(!m_model) return;

    m_track_mesh         = new TriangleMesh();
    m_non_collision_mesh = new TriangleMesh();
    
    // Collect all triangles in the track_mesh
    sgMat4 mat;
    sgMakeIdentMat4(mat);
    convertTrackToBullet(m_model, mat);
    m_track_mesh->createBody();
    m_non_collision_mesh->createBody(btCollisionObject::CF_NO_CONTACT_RESPONSE);
    
}   // createPhysicsModel

Here is the call graph for this function:

Here is the caller graph for this function:

void Track::draw2Dview ( float  x_offset,
float  y_offset 
) const

Definition at line 657 of file track.cpp.

{

    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, 0.4f) ;


/*FIXME: Too much calculations here, we should be generating scaled driveline arrays
 * in Track::loadDriveline 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][0] - m_driveline_min[0] ) * m_scale_x,
          y_offset + ( m_left_driveline[i][1] - m_driveline_min[1] ) * m_scale_y) ;
      glVertex2f ( x_offset + ( m_right_driveline[i][0] - m_driveline_min[0] ) * m_scale_x,
          y_offset + ( m_right_driveline[i][1] - m_driveline_min[1] ) * m_scale_y ) ;
    }
    glVertex2f ( x_offset + ( m_left_driveline[0][0] - m_driveline_min[0] ) * m_scale_x,
        y_offset + ( m_left_driveline[0][1] - m_driveline_min[1] ) * m_scale_y ) ;
    glVertex2f ( x_offset + ( m_right_driveline[0][0] - m_driveline_min[0] ) * m_scale_x,
        y_offset + ( m_right_driveline[0][1] - m_driveline_min[1] ) * 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][0] - m_driveline_min[0] ) * m_scale_x,
            y_offset + ( m_left_driveline[i][1] - m_driveline_min[1] ) * m_scale_y ) ;

        glVertex2f ( x_offset + ( m_left_driveline[i+1][0] - m_driveline_min[0] ) * m_scale_x,
            y_offset + ( m_left_driveline[i+1][1] - m_driveline_min[1] ) * m_scale_y ) ;


        /*Draw left driveline of the map*/
        glVertex2f ( x_offset + ( m_right_driveline[i][0] - m_driveline_min[0] ) * m_scale_x,
               y_offset + ( m_right_driveline[i][1] - m_driveline_min[1] ) * m_scale_y ) ;

        glVertex2f ( x_offset + ( m_right_driveline[i+1][0] - m_driveline_min[0] ) * m_scale_x,
               y_offset + ( m_right_driveline[i+1][1] - m_driveline_min[1] ) * m_scale_y ) ;
    }

    //Close the left driveline
    glVertex2f ( x_offset + ( m_left_driveline[DRIVELINE_SIZE - 1][0] - m_driveline_min[0] ) * m_scale_x,
        y_offset + ( m_left_driveline[DRIVELINE_SIZE - 1][1] - m_driveline_min[1] ) * m_scale_y ) ;

    glVertex2f ( x_offset + ( m_left_driveline[0][0] - m_driveline_min[0] ) * m_scale_x,
        y_offset + ( m_left_driveline[0][1] - m_driveline_min[1] ) * m_scale_y ) ;


    //Close the right driveline
    glVertex2f ( x_offset + ( m_right_driveline[DRIVELINE_SIZE - 1][0] - m_driveline_min[0] ) * m_scale_x,
        y_offset + ( m_right_driveline[DRIVELINE_SIZE - 1][1] - m_driveline_min[1] ) * m_scale_y ) ;

    glVertex2f ( x_offset + ( m_right_driveline[0][0] - m_driveline_min[0] ) * m_scale_x,
        y_offset + ( m_right_driveline[0][1] - m_driveline_min[1] ) * 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][0] - m_driveline_min[0] ) * m_scale_x,
            y_offset + ( m_left_driveline[i][1] - m_driveline_min[1] ) * m_scale_y ) ;
    }
    glEnd () ;

    glBegin ( GL_LINE_LOOP ) ;
    for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
    {
        glVertex2f ( x_offset + ( m_right_driveline[i][0] - m_driveline_min[0] ) * m_scale_x,
               y_offset + ( m_right_driveline[i][1] - m_driveline_min[1] ) * 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][0] - m_driveline_min[0] ) * m_scale_x,
            y_offset + ( m_left_driveline[i][1] - m_driveline_min[1] ) * m_scale_y ) ;

        glVertex2f ( x_offset + ( m_right_driveline[i][0] - m_driveline_min[0] ) * m_scale_x,
             y_offset + ( m_right_driveline[i][1] - m_driveline_min[1] ) * m_scale_y ) ;
    }
    glEnd () ;

    glPopAttrib();

}   // draw2Dview
void Track::drawScaled2D ( float  x,
float  y,
float  w,
float  h 
) const

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/loadDriveline)

  • which saves a bit of time at runtime as well. drawScaled2D is called from gui/TrackSel, draw2Dview from RaceGUI.

Definition at line 528 of file track.cpp.

{
    sgVec2 sc;
    sgSubVec2 ( sc, m_driveline_max, m_driveline_min );

    float sx = w / sc[0];
    float sy = h / sc[1];

    if( sx > sy )
    {
        sx = sy;
        x += w/2 - sc[0]*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][0] - m_driveline_min[0] ) * sx,
          y + ( m_left_driveline[i][1] - m_driveline_min[1] ) * sy) ;

      glVertex2f ( x + ( m_right_driveline[i][0] - m_driveline_min[0] ) * sx,
          y + ( m_right_driveline[i][1] - m_driveline_min[1] ) * sy ) ;
    }
    glVertex2f ( x + ( m_left_driveline[0][0] - m_driveline_min[0] ) * sx,
        y + ( m_left_driveline[0][1] - m_driveline_min[1] ) * sy) ;
    glVertex2f ( x + ( m_right_driveline[0][0] - m_driveline_min[0] ) * sx,
        y + ( m_right_driveline[0][1] - m_driveline_min[1] ) * 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][0] - m_driveline_min[0] ) * sx,
            y + ( m_left_driveline[i][1] - m_driveline_min[1] ) * sy ) ;

        glVertex2f ( x + ( m_left_driveline[i+1][0] - m_driveline_min[0] ) * sx,
            y + ( m_left_driveline[i+1][1] - m_driveline_min[1] ) * sy ) ;


        /*Draw left driveline of the map*/
        glVertex2f ( x + ( m_right_driveline[i][0] - m_driveline_min[0] ) * sx,
               y + ( m_right_driveline[i][1] - m_driveline_min[1] ) * sy ) ;

        glVertex2f ( x + ( m_right_driveline[i+1][0] - m_driveline_min[0] ) * sx,
               y + ( m_right_driveline[i+1][1] - m_driveline_min[1] ) * sy ) ;
    }

    //Close the left driveline
    glVertex2f ( x + ( m_left_driveline[DRIVELINE_SIZE - 1][0] - m_driveline_min[0] ) * sx,
        y + ( m_left_driveline[DRIVELINE_SIZE - 1][1] - m_driveline_min[1] ) * sy ) ;

    glVertex2f ( x + ( m_left_driveline[0][0] - m_driveline_min[0] ) * sx,
        y + ( m_left_driveline[0][1] - m_driveline_min[1] ) * sy ) ;


    //Close the right driveline
    glVertex2f ( x + ( m_right_driveline[DRIVELINE_SIZE - 1][0] - m_driveline_min[0] ) * sx,
        y + ( m_right_driveline[DRIVELINE_SIZE - 1][1] - m_driveline_min[1] ) * sy ) ;

    glVertex2f ( x + ( m_right_driveline[0][0] - m_driveline_min[0] ) * sx,
        y + ( m_right_driveline[0][1] - m_driveline_min[1] ) * 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][0] - m_driveline_min[0] ) * sx,
            y + ( m_left_driveline[i][1] - m_driveline_min[1] ) * sy ) ;
    }
    glEnd () ;

    glBegin ( GL_LINE_LOOP ) ;
    for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
    {
        glVertex2f ( x + ( m_right_driveline[i][0] - m_driveline_min[0] ) * sx,
               y + ( m_right_driveline[i][1] - m_driveline_min[1] ) * sy ) ;
    }
    glEnd () ;
#endif


    glBegin ( GL_POINTS ) ;
    for ( size_t i = 0 ; i < DRIVELINE_SIZE ; ++i )
    {
      glVertex2f ( x + ( m_left_driveline[i][0] - m_driveline_min[0] ) * sx,
          y + ( m_left_driveline[i][1] - m_driveline_min[1] ) * sy ) ;

      glVertex2f ( x + ( m_right_driveline[i][0] - m_driveline_min[0] ) * sx,
          y + ( m_right_driveline[i][1] - m_driveline_min[1] ) * sy ) ;
    }
    glEnd () ;

    glPopAttrib();

}   // drawScaled2D

Here is the caller graph for this function:

int Track::findOutOfRoadSector ( const sgVec3  XYZ,
const RoadSide  SIDE,
const int  CURR_SECTOR 
) const

findOutOfRoadSector finds the sector where XYZ is, but as it name implies, it is more accurate for the outside of the track than the inside, and for STK's needs the accuracy on top of the track is unacceptable; but if this was a 2D function, the accuracy for out of road sectors would be perfect.

To find the sector we look for the closest line segment from the right and left drivelines, and the number of that segment will be the sector.

The SIDE argument is used to speed up the function only; if we know that XYZ is on the left or right side of the track, we know that the closest driveline must be the one that matches that condition. In reality, the side used in STK is the one from the previous frame, but in order to move from one side to another a point would go through the middle, that is handled by findRoadSector() which doesn't has speed ups based on the side.

NOTE: This method of finding the sector outside of the road is not perfect: if two line segments have a similar altitude (but enough to let a kart get through) and they are very close on a 2D system, if a kart is on the air it could be closer to the top line segment even if it is supposed to be on the sector of the lower line segment. Probably the best solution would be to construct a quad that reaches until the next higher overlapping line segment, and find the closest one to XYZ.

Definition at line 265 of file track.cpp.

{
    int sector = UNKNOWN_SECTOR;
    float dist;
    //FIXME: it can happen that dist is bigger than nearest_dist for all the
    //the points we check (currently a limit of +/- 10), and if so, the
    //function will return UNKNOWN_SECTOR, and if the AI get this, it will
    //trigger an assertion. I increased the nearest_dist default value from
    //99999 to 9999999, which is a lot more than the situation that caused
    //the discovery of this problem, but the best way to solve this, is to
    //find a better way of handling the shortcuts, and maybe a better way of
    //calculating the distance.
    float nearest_dist = 9999999;
    const unsigned int DRIVELINE_SIZE = (unsigned int)m_left_driveline.size();

    int begin_sector = 0;
    int end_sector = DRIVELINE_SIZE - 1;

    if(CURR_SECTOR != UNKNOWN_SECTOR )
    {
        const int LIMIT = 10; //The limit prevents shortcuts
        if( CURR_SECTOR - LIMIT < 0 )
        {
            begin_sector = DRIVELINE_SIZE - 1 + CURR_SECTOR - LIMIT;
        }
        else begin_sector = CURR_SECTOR - LIMIT;

        if( CURR_SECTOR + LIMIT > (int)DRIVELINE_SIZE - 1 )
        {
            end_sector = CURR_SECTOR + LIMIT - DRIVELINE_SIZE;
        }
        else end_sector = CURR_SECTOR + LIMIT;
    }

    sgLineSegment3 line_seg;
    int next_sector;
    for (int i = begin_sector ; i != end_sector ; i = next_sector )
    {
        next_sector = i + 1 == (int)DRIVELINE_SIZE ? 0 : i + 1;

        if( SIDE != RS_RIGHT)
        {
            sgCopyVec3( line_seg.a, m_left_driveline[i] );
            sgCopyVec3( line_seg.b, m_left_driveline[next_sector] );

            dist = sgDistSquaredToLineSegmentVec3( line_seg, XYZ );

            if ( dist < nearest_dist )
            {
                nearest_dist = dist;
                sector = i ;
            }
        }

        if( SIDE != RS_LEFT )
        {
            sgCopyVec3( line_seg.a, m_right_driveline[i] );
            sgCopyVec3( line_seg.b, m_right_driveline[next_sector] );

            dist = sgDistSquaredToLineSegmentVec3( line_seg, XYZ );

            if ( dist < nearest_dist )
            {
                nearest_dist = dist;
                sector = i ;
            }
        }
    }   // for i

    if(sector==UNKNOWN_SECTOR)
    {
        printf("unknown sector found.\n");
    }
    return sector;
}   // findOutOfRoadSector

Here is the caller graph for this function:

void Track::findRoadSector ( const sgVec3  XYZ,
int *  sector 
) const

findRoadSector returns in which sector on the road the position xyz is.

If xyz is not on top of the road, it returns UNKNOWN_SECTOR.

The 'sector' could be defined as the number of the closest track segment to XYZ.

Definition at line 141 of file track.cpp.

{
    if(*sector!=UNKNOWN_SECTOR)
    {
        int next = (unsigned)(*sector) + 1 <  m_left_driveline.size() ? *sector + 1 : 0;
        if(pointInQuad( m_left_driveline[*sector], m_right_driveline[*sector],
                        m_right_driveline[next],   m_left_driveline[next], 
                        XYZ ) != QUAD_TRI_NONE)
            // Still in the same sector, no changes
            return;
    }
    /* To find in which 'sector' of the track the kart is, we use a
       'point in triangle' algorithm for each triangle in the quad
       that forms each track segment.
     */
    std::vector <SegmentTriangle> possible_segment_tris;
    const unsigned int DRIVELINE_SIZE = (unsigned int)m_left_driveline.size();
    int triangle;
    int next;

    for( size_t i = 0; i < DRIVELINE_SIZE ; ++i )
    {
        next = (unsigned int)i + 1 <  DRIVELINE_SIZE ? (int)i + 1 : 0;
        triangle = pointInQuad( m_left_driveline[i],     m_right_driveline[i],
                                m_right_driveline[next], m_left_driveline[next], 
                                XYZ );

        if (triangle != QUAD_TRI_NONE && ((XYZ[2]-m_left_driveline[i][2]) < 1.0f))
        {
            possible_segment_tris.push_back(SegmentTriangle((int)i, triangle));
        }
    }

    /* Since xyz can be on more than one 2D track segment, we have to
       find on top of which one of the possible track segments it is.
     */
    const int POS_SEG_SIZE = (int)possible_segment_tris.size();
    if( POS_SEG_SIZE == 0 )
    {
        //xyz is not on the road
        *sector = UNKNOWN_SECTOR;
        return;
    }

    //POS_SEG_SIZE > 1
    /* To find on top of which track segment the variable xyz is,
       we get which of the possible triangles that are under xyz
       has the lower distance on the height(Y or Z) axis.
    */
    float dist;
    float near_dist = 99999;
    int nearest = QUAD_TRI_NONE;
    size_t segment;
    sgVec4 plane;
    
    for( int i = 0; i < POS_SEG_SIZE; ++i )
    {
        segment = possible_segment_tris[i].segment;
        next = segment + 1 < DRIVELINE_SIZE ? (int)segment + 1 : 0;
        
        if( possible_segment_tris[i].triangle == QUAD_TRI_FIRST )
        {
            sgMakePlane( plane, m_left_driveline[segment],
                         m_right_driveline[segment], m_right_driveline[next] );
        }
        else //possible_segment_tris[i].triangle == QUAD_TRI_SECOND
        {
            sgMakePlane( plane, m_right_driveline[next],
                         m_left_driveline[next], m_left_driveline[segment] );
        }
        
        dist = sgHeightAbovePlaneVec3( plane, XYZ );
        
        /* sgHeightAbovePlaneVec3 gives a negative dist if the plane
           is on top, so we have to rule it out.
           
           However, for some reason there are cases where we get
           negative values for the track segment we should be on.
        */
        if( dist > -2.0 && dist < near_dist)
        {
            near_dist = dist;
            nearest = i;
        }
    }
    
    if( nearest != QUAD_TRI_NONE )
    {
        *sector=possible_segment_tris[nearest].segment;
        return;
    }
    *sector = UNKNOWN_SECTOR;
    return;                         // This only happens if the position is
                                    // under all the possible sectors
}   // findRoadSector

Here is the call graph for this function:

Here is the caller graph for this function:

const float& Track::getAIAngleAdjustment ( ) const [inline]

Definition at line 186 of file track.hpp.

Here is the caller graph for this function:

const float& Track::getAICurveSpeedAdjustment ( ) const [inline]

Definition at line 187 of file track.hpp.

Here is the caller graph for this function:

const sgVec4& Track::getAmbientCol ( ) const [inline]

Definition at line 178 of file track.hpp.

{return m_ambient_col;        }

Here is the caller graph for this function:

const std::string& Track::getDescription ( ) const [inline]

Definition at line 189 of file track.hpp.

{return m_description;        }

Here is the caller graph for this function:

const std::string& Track::getDesigner ( ) const [inline]

Definition at line 190 of file track.hpp.

{return m_designer;           }

Here is the caller graph for this function:

const sgVec4& Track::getDiffuseCol ( ) const [inline]

Definition at line 179 of file track.hpp.

{return m_diffuse_col;        }

Here is the caller graph for this function:

const std::string& Track::getFilename ( ) const [inline]

Definition at line 176 of file track.hpp.

{return m_filename;           }

Here is the caller graph for this function:

const sgVec4& Track::getFogColor ( ) const [inline]

Definition at line 182 of file track.hpp.

{return m_fog_color;          }

Here is the caller graph for this function:

const float& Track::getFogDensity ( ) const [inline]

Definition at line 183 of file track.hpp.

{return m_fog_density;        }

Here is the caller graph for this function:

const float& Track::getFogEnd ( ) const [inline]

Definition at line 185 of file track.hpp.

{return m_fog_end;            }

Here is the caller graph for this function:

const float& Track::getFogStart ( ) const [inline]

Definition at line 184 of file track.hpp.

{return m_fog_start;          }

Here is the caller graph for this function:

float Track::getGravity ( ) const [inline]

Definition at line 171 of file track.hpp.

{return m_gravity;            }

Here is the caller graph for this function:

const std::string& Track::getHerringStyle ( ) const [inline]

Definition at line 194 of file track.hpp.

{return m_herring_style;      }

Here is the caller graph for this function:

const std::string& Track::getIdent ( ) const [inline]

Definition at line 173 of file track.hpp.

{return m_ident;              }

Here is the caller graph for this function:

ssgBranch* Track::getModel ( ) const [inline]

Definition at line 170 of file track.hpp.

{return m_model;              }
void Track::getMusicInformation ( std::vector< std::string > &  filenames,
std::vector< MusicInformation * > &  m_music 
) [private]

Definition at line 854 of file track.cpp.

{
    for(int i=0; i<(int)filenames.size(); i++)
    {
        std::string full_path = file_manager->getTrackFile(filenames[i], getIdent());
        MusicInformation* mi;
        try
        {
            mi = sound_manager->getMusicInformation(full_path);
        }
        catch(std::runtime_error)
        {
            mi = sound_manager->getMusicInformation(file_manager->getMusicFile(filenames[i]));
        }
        if(!mi)
        {
            fprintf(stderr, "Music information file '%s' not found - ignored.\n",
                    filenames[i].c_str());
            continue;
        }
        m_music.push_back(mi);
    }   // for i in filenames
}   // getMusicInformation

Here is the call graph for this function:

Here is the caller graph for this function:

const char* Track::getName ( ) const [inline]

Definition at line 174 of file track.hpp.

{return m_name.c_str();       }

Here is the caller graph for this function:

const std::string& Track::getScreenshotFile ( ) const [inline]

Definition at line 192 of file track.hpp.

{return m_screenshot;         }

Here is the caller graph for this function:

const sgVec4& Track::getSkyColor ( ) const [inline]

Definition at line 188 of file track.hpp.

{return m_sky_color;          }

Here is the caller graph for this function:

const sgVec4& Track::getSpecularCol ( ) const [inline]

Definition at line 180 of file track.hpp.

{return m_specular_col;       }

Here is the caller graph for this function:

void Track::getStartCoords ( unsigned int  pos,
sgCoord *  coords 
) const

Returns the start coordinates for a kart on a given position pos (with 0<=pos).

Definition at line 418 of file track.cpp.

                                                                  {
  // Bug fix/workaround: 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! Therefor -1.5 is subtracted from the y position - which
  // is a somewhat arbitrary value.
  coords->xyz[0] = pos<m_start_x.size() ? m_start_x[pos] : ((pos%2==0)?1.5f:-1.5f);
  coords->xyz[1] = pos<m_start_y.size() ? m_start_y[pos] : -1.5f*pos-1.5f;
   // height must be larger than the actual hight for which hot is computed.
  coords->xyz[2] = pos<m_start_z.size() ? m_start_z[pos] : 1.0f;

  coords->hpr[0] = pos<m_start_heading.size() ? m_start_heading[pos] : 0.0f;
  coords->hpr[1] = 0.0f;
  coords->hpr[2] = 0.0f;

  btVector3 tmp_pos(coords->xyz[0],coords->xyz[1],coords->xyz[2]);

  btVector3 normal;
  const Material *material=NULL;
  getTerrainInfo(tmp_pos, &(coords->xyz[2]), &normal, &material);

}   // getStartCoords

Here is the call graph for this function:

const sgVec3& Track::getSunPos ( ) const [inline]

Definition at line 177 of file track.hpp.

{return m_sun_position;       }

Here is the caller graph for this function:

void Track::getTerrainInfo ( const btVector3 pos,
float *  hot,
btVector3 normal,
const Material **  material 
) const

Definition at line 1356 of file track.cpp.

{
    btVector3 to_pos(pos);
    to_pos.setZ(-100000.f);

    class MaterialCollision : public btCollisionWorld::ClosestRayResultCallback
    {
    public:
        const Material* m_material;
        MaterialCollision(btVector3 p1, btVector3 p2) : 
            btCollisionWorld::ClosestRayResultCallback(p1,p2) {m_material=NULL;}
        virtual btScalar AddSingleResult(btCollisionWorld::LocalRayResult& rayResult,
                                         bool normalInWorldSpace) {
             if(rayResult.m_localShapeInfo && rayResult.m_localShapeInfo->m_shapePart>=0 )
             {
                 m_material = ((TriangleMesh*)rayResult.m_collisionObject->getUserPointer())->getMaterial(rayResult.m_localShapeInfo->m_triangleIndex);
             }
             return btCollisionWorld::ClosestRayResultCallback::AddSingleResult(rayResult, 
                                                                                normalInWorldSpace);
        }   // AddSingleResult
    };   // myCollision
    MaterialCollision rayCallback(pos, to_pos);
    world->getPhysics()->getPhysicsWorld()->rayTest(pos, to_pos, rayCallback);

    if(!rayCallback.HasHit()) 
    {
        *hot      = NOHIT;
        *material = NULL;
        return;
    }

    *hot      = rayCallback.m_hitPointWorld.getZ();
    *normal   = rayCallback.m_hitNormalWorld;
    *material = rayCallback.m_material;
    // Note: material might be NULL. This happens if the ray cast does not
    // hit the track, but anoterh rigid body (kart, moving_physics) - e.g.
    // assume two karts falling down, one over the other. Bullet does not
    // have any triangle/material information in this case!
}   // getTerrainInfo

Here is the call graph for this function:

Here is the caller graph for this function:

const std::string& Track::getTopviewFile ( ) const [inline]

Definition at line 191 of file track.hpp.

{return m_top_view;           }

Here is the caller graph for this function:

float Track::getTrackLength ( ) const [inline]

Definition at line 172 of file track.hpp.

{return m_total_distance;     }

Here is the caller graph for this function:

const std::vector<SGfloat>& Track::getWidth ( ) const [inline]

Definition at line 193 of file track.hpp.

{return m_path_width;         }

Here is the caller graph for this function:

void Track::glVtx ( sgVec2  v,
float  x_offset,
float  y_offset 
) const [inline]

Definition at line 199 of file track.hpp.

    {
        glVertex2f(
            x_offset+(v[0]-m_driveline_min[0])*m_scale_x,
            y_offset+(v[1]-m_driveline_min[1])*m_scale_y);
    }
void Track::herring_command ( sgVec3 *  xyz,
char  htype,
int  bNeedHeight 
) [private]

Definition at line 1335 of file track.cpp.

{

    // if only 2d coordinates are given, let the herring fall from very heigh
    if(bNeedHeight) (*xyz)[2] = 1000000.0f;

    // Even if 3d data are given, make sure that the herring is on the ground
    (*xyz)[2] = getHeight ( m_model, *xyz ) + 0.06f;
    herringType type=HE_GREEN;
    if ( htype=='Y' || htype=='y' ) { type = HE_GOLD   ;}
    if ( htype=='G' || htype=='g' ) { type = HE_GREEN  ;}
    if ( htype=='R' || htype=='r' ) { type = HE_RED    ;}
    if ( htype=='S' || htype=='s' ) { type = HE_SILVER ;}

    // Time trial does not have any red herrings
    if(type==HE_RED && race_manager->getRaceMode()==RaceManager::RM_TIME_TRIAL) 
        return;
    herring_manager->newHerring(type, xyz);
}   // herring_command

Here is the call graph for this function:

Here is the caller graph for this function:

bool Track::isShortcut ( const int  OLDSEC,
const int  NEWSEC 
) const

Determines if a kart moving from sector OLDSEC to sector NEWSEC would be taking a shortcut, i.e.

if the distance is larger than a certain detla

Definition at line 446 of file track.cpp.

{
    // If the kart was off the road, don't do any shortcuts
    if(OLDSEC==UNKNOWN_SECTOR || NEWSEC==UNKNOWN_SECTOR) return false;
    unsigned int distance_sectors = abs(OLDSEC-NEWSEC);
    // Handle 'wrap around': if the distance is more than half the 
    // number of driveline poins, assume it's a 'wrap around'
    if(2*distance_sectors > (unsigned int)m_driveline.size())
        distance_sectors = (unsigned int)m_driveline.size() - distance_sectors;
    return (distance_sectors>stk_config->m_shortcut_segments);
}   // isShortcut

Here is the caller graph for this function:

void Track::loadDriveline ( ) [private]

Definition at line 886 of file track.cpp.

{
    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;

    SGfloat width;
    sgVec3 center_point, width_vector;
    m_driveline.reserve(DRIVELINE_SIZE);
    m_path_width.reserve(DRIVELINE_SIZE);
    m_angle.reserve(DRIVELINE_SIZE);
    for(unsigned int i = 0; i < DRIVELINE_SIZE; ++i)
    {
        sgAddVec3(center_point, m_left_driveline[i], m_right_driveline[i]);
        sgScaleVec3(center_point, 0.5f);
        m_driveline.push_back(center_point);

        sgSubVec3(width_vector, m_right_driveline[i], center_point);
        width = sgLengthVec3(width_vector);
        if(width > 0.0f) m_path_width.push_back(width);
        else m_path_width.push_back(-width);
    }

    size_t next;
    float adjacent_line, opposite_line;
    SGfloat theta;

    for(unsigned int i = 0; i < DRIVELINE_SIZE; ++i)
    {
        next = i + 1 >= DRIVELINE_SIZE ? 0 : i + 1;
        adjacent_line = m_driveline[next][0] - m_driveline[i][0];
        opposite_line = m_driveline[next][1] - m_driveline[i][1];

        theta = sgATan(opposite_line/adjacent_line);
        theta += adjacent_line < 0.0f ? 90.0f : -90.0f;

        m_angle.push_back(theta);
    }

    sgSetVec2 ( m_driveline_min,  SG_MAX/2.0f,  SG_MAX/2.0f ) ;
    sgSetVec2 ( m_driveline_max, -SG_MAX/2.0f, -SG_MAX/2.0f ) ;


    m_distance_from_start.reserve(DRIVELINE_SIZE);
    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.
        if ( m_right_driveline[i][0] < m_driveline_min[0] )
            m_driveline_min[0] = m_right_driveline[i][0] ;
        if ( m_right_driveline[i][1] < m_driveline_min[1] )
            m_driveline_min[1] = m_right_driveline[i][1] ;
        if ( m_right_driveline[i][0] > m_driveline_max[0] )
            m_driveline_max[0] = m_right_driveline[i][0] ;
        if ( m_right_driveline[i][1] > m_driveline_max[1] )
            m_driveline_max[1] = m_right_driveline[i][1] ;

        if ( m_left_driveline[i][0] < m_driveline_min[0] )
            m_driveline_min[0] = m_left_driveline[i][0] ;
        if ( m_left_driveline[i][1] < m_driveline_min[1] )
            m_driveline_min[1] = m_left_driveline[i][1] ;
        if ( m_left_driveline[i][0] > m_driveline_max[0] )
            m_driveline_max[0] = m_left_driveline[i][0] ;
        if ( m_left_driveline[i][1] > m_driveline_max[1] )
            m_driveline_max[1] = m_left_driveline[i][1] ;


        m_distance_from_start.push_back(d);  // dfs[i] is not valid in windows here!

        if ( i == DRIVELINE_SIZE - 1 )
            d += sgDistanceVec2 ( m_driveline[i], m_driveline[0] ) ;
        else
            d += sgDistanceVec2 ( m_driveline[i], m_driveline[i+1] ) ;
    }

    m_total_distance = d;

    sgVec2 sc ;
    sgSubVec2 ( sc, m_driveline_max, m_driveline_min ) ;

    m_scale_x = m_track_2d_width  / sc[0] ;
    m_scale_y = m_track_2d_height / sc[1] ;

    if(!m_do_stretch) m_scale_x = m_scale_y = std::min(m_scale_x, m_scale_y);
    
}   // loadDriveline

Here is the call graph for this function:

Here is the caller graph for this function:

void Track::loadTrack ( std::string  filename) [private]

Definition at line 781 of file track.cpp.

{
    m_filename      = filename_;

    m_ident = StringUtils::basename(StringUtils::without_extension(m_filename));
    std::string path = StringUtils::without_extension(m_filename);

    // Default values
    m_use_fog = false;
    sgSetVec4 ( m_fog_color  , 0.3f, 0.7f, 0.9f, 1.0f ) ;
    m_fog_density               = 1.0f/100.0f;
    m_fog_start                 = 0.0f;
    m_fog_end                   = 1000.0f;
    m_gravity                   = 9.80665f;
    m_AI_angle_adjustment       = 1.0f;
    m_AI_curve_speed_adjustment = 1.0f;

    sgSetVec3 ( m_sun_position,  0.4f, 0.4f, 0.4f      );
    sgSetVec4 ( m_sky_color,     0.3f, 0.7f, 0.9f, 1.0f );
    sgSetVec4 ( m_fog_color,     0.3f, 0.7f, 0.9f, 1.0f );
    sgSetVec4 ( m_ambient_col,   0.5f, 0.5f, 0.5f, 1.0f );
    sgSetVec4 ( m_specular_col,  1.0f, 1.0f, 1.0f, 1.0f );
    sgSetVec4 ( m_diffuse_col,   1.0f, 1.0f, 1.0f, 1.0f );

    lisp::Parser parser;
    const lisp::Lisp* const ROOT = parser.parse(m_filename);

    const lisp::Lisp* const LISP = ROOT->getLisp("tuxkart-track");
    if(!LISP)
    {
        delete ROOT;
        char msg[MAX_ERROR_MESSAGE_LENGTH];
        snprintf(msg, sizeof(msg), 
                 "Couldn't load map '%s': no tuxkart-track node.",
                 m_filename.c_str());
        throw std::runtime_error(msg);
    }

    LISP->get      ("name",                  m_name);
    LISP->get      ("description",           m_description);
    LISP->get      ("designer",              m_designer);
    std::vector<std::string> filenames;
    LISP->getVector("music",                 filenames);
    getMusicInformation(filenames, m_music);
    LISP->get      ("herring",               m_herring_style);
    LISP->get      ("screenshot",            m_screenshot);
    LISP->get      ("topview",               m_top_view);
    LISP->get      ("sky-color",             m_sky_color);
    LISP->getVector("start-x",               m_start_x);
    LISP->getVector("start-y",               m_start_y);
    LISP->getVector("start-z",               m_start_z);
    LISP->getVector("start-heading",         m_start_heading);
    LISP->get      ("use-fog",               m_use_fog);
    LISP->get      ("fog-color",             m_fog_color);
    LISP->get      ("fog-density",           m_fog_density);
    LISP->get      ("fog-start",             m_fog_start);
    LISP->get      ("fog-end",               m_fog_end);
    LISP->get      ("sun-position",          m_sun_position);
    LISP->get      ("sun-ambient",           m_ambient_col);
    LISP->get      ("sun-specular",          m_specular_col);
    LISP->get      ("sun-diffuse",           m_diffuse_col);
    LISP->get      ("gravity",               m_gravity);
    LISP->get      ("AI-angle-adjust",       m_AI_angle_adjustment);
    LISP->get      ("AI-curve-speed-adjust", m_AI_curve_speed_adjustment);

    // Set the correct paths
    m_screenshot = file_manager->getTrackFile(m_screenshot, getIdent());
    m_top_view   = file_manager->getTrackFile(m_top_view,   getIdent());
    
    delete ROOT;
}   // loadTrack

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1142 of file track.cpp.

{
    // Add the track directory to the texture search path
    file_manager->pushTextureSearchPath(file_manager->getTrackFile("",getIdent()));
    file_manager->pushModelSearchPath  (file_manager->getTrackFile("",getIdent()));
    // First read the temporary materials.dat file if it exists
    try
    {
        std::string materials_file = file_manager->getTrackFile("materials.dat",getIdent());
        material_manager->pushTempMaterial(materials_file);
    }
    catch (std::exception& e)
    {
        // no temporary materials.dat file, ignore
        (void)e;
    }
    std::string path = file_manager->getTrackFile(getIdent()+".loc");

    FILE *fd = fopen (path.c_str(), "r" );
    if ( fd == NULL )
    {
        char msg[MAX_ERROR_MESSAGE_LENGTH];
        snprintf(msg, sizeof(msg),"Can't open track location file '%s'.\n",
                 path.c_str());
        throw std::runtime_error(msg);
    }

    // Start building the scene graph
    m_model = new ssgBranch ;
    scene->add(m_model);

    char s [ 1024 ] ;

    while ( fgets ( s, 1023, fd ) != NULL )
    {
        if ( *s == '#' || *s < ' ' )
            continue ;

        int need_hat = false ;
        int fit_skin = false ;
        char fname [ 1024 ] ;
        sgCoord loc ;
        sgZeroVec3 ( loc.xyz ) ;
        sgZeroVec3 ( loc.hpr ) ;

        char htype = '\0' ;

        if ( sscanf ( s, "%cHERRING,%f,%f,%f", &htype,
                      &(loc.xyz[0]), &(loc.xyz[1]), &(loc.xyz[2]) ) == 4 )
        {
            herring_command(&loc.xyz, htype, false) ;
        }
        else if ( sscanf ( s, "%cHERRING,%f,%f", &htype,
                           &(loc.xyz[0]), &(loc.xyz[1]) ) == 3 )
        {
            herring_command (&loc.xyz, htype, true) ;
        }
        else if ( s[0] == '\"' )
        {
            if ( sscanf ( s, "\"%[^\"]\",%f,%f,%f,%f,%f,%f",
                          fname, &(loc.xyz[0]), &(loc.xyz[1]), &(loc.xyz[2]),
                          &(loc.hpr[0]), &(loc.hpr[1]), &(loc.hpr[2]) ) == 7 )
            {
                /* All 6 DOF specified */
                need_hat = false;
            }
            else if ( sscanf ( s, "\"%[^\"]\",%f,%f,{},%f,%f,%f",
                               fname, &(loc.xyz[0]), &(loc.xyz[1]),
                               &(loc.hpr[0]), &(loc.hpr[1]), &(loc.hpr[2])) == 6 )
            {
                /* All 6 DOF specified - but need height */
                need_hat = true ;
            }
            else if ( sscanf ( s, "\"%[^\"]\",%f,%f,%f,%f",
                               fname, &(loc.xyz[0]), &(loc.xyz[1]), &(loc.xyz[2]),
                               &(loc.hpr[0]) ) == 5 )
            {
                /* No Roll/Pitch specified - assumed zero */
                need_hat = false ;
            }
            else if ( sscanf ( s, "\"%[^\"]\",%f,%f,{},%f,{},{}",
                               fname, &(loc.xyz[0]), &(loc.xyz[1]),
                               &(loc.hpr[0]) ) == 4 )
            {
                /* All 6 DOF specified - but need height, roll, pitch */
                need_hat = true ;
                fit_skin = true ;
            }
            else if ( sscanf ( s, "\"%[^\"]\",%f,%f,{},%f",
                               fname, &(loc.xyz[0]), &(loc.xyz[1]),
                               &(loc.hpr[0]) ) == 4 )
            {
                /* No Roll/Pitch specified - but need height */
                need_hat = true ;
            }
            else if ( sscanf ( s, "\"%[^\"]\",%f,%f,%f",
                               fname, &(loc.xyz[0]), &(loc.xyz[1]),
                               &(loc.xyz[2]) ) == 4 )
            {
                /* No Heading/Roll/Pitch specified - but need height */
                need_hat = false ;
            }
            else if ( sscanf ( s, "\"%[^\"]\",%f,%f,{}",
                               fname, &(loc.xyz[0]), &(loc.xyz[1]) ) == 3 )
            {
                /* No Roll/Pitch specified - but need height */
                need_hat = true ;
            }
            else if ( sscanf ( s, "\"%[^\"]\",%f,%f",
                               fname, &(loc.xyz[0]), &(loc.xyz[1]) ) == 3 )
            {
                /* No Z/Heading/Roll/Pitch specified */
                need_hat = false ;
            }
            else if ( sscanf ( s, "\"%[^\"]\"", fname ) == 1 )
            {
                /* Nothing specified */
                need_hat = false ;
            }
            else
            {
                fclose(fd);
                char msg[MAX_ERROR_MESSAGE_LENGTH];
                snprintf(msg, sizeof(msg), "Syntax error in '%s': %s",
                         path.c_str(), s);
                throw std::runtime_error(msg);
            }

            if ( need_hat )
            {
                sgVec3 nrm ;

                loc.xyz[2] = 1000.0f ;
                loc.xyz[2] = getHeightAndNormal ( m_model, loc.xyz, nrm ) ;

                if ( fit_skin )
                {
                    float sy = sin ( -loc.hpr [ 0 ] * SG_DEGREES_TO_RADIANS ) ;
                    float cy = cos ( -loc.hpr [ 0 ] * SG_DEGREES_TO_RADIANS ) ;

                    loc.hpr[2] =  SG_RADIANS_TO_DEGREES * atan2 ( nrm[0] * cy -
                                  nrm[1] * sy, nrm[2] ) ;
                    loc.hpr[1] = -SG_RADIANS_TO_DEGREES * atan2 ( nrm[1] * cy +
                                 nrm[0] * sy, nrm[2] ) ;
                }
            }   // if need_hat

            ssgEntity        *obj   = loader->load(file_manager->getModelFile(fname),
                                                   CB_TRACK,
                                                   /* optimise   */  true,
                                                   /*is_full_path*/  true);
            if(!obj)
            {
                fclose(fd);
                char msg[MAX_ERROR_MESSAGE_LENGTH];
                snprintf(msg, sizeof(msg), "Can't open track model '%s'",fname);
                file_manager->popTextureSearchPath();
                file_manager->popModelSearchPath  ();
                throw std::runtime_error(msg);
            }
            createDisplayLists(obj);
            ssgRangeSelector *lod   = new ssgRangeSelector ;
            ssgTransform     *trans = new ssgTransform ( & loc ) ;

            float r [ 2 ] = { -10.0f, 2000.0f } ;

            lod    -> addKid(obj   );
            trans  -> addKid(lod   );
            m_model-> addKid(trans );
            lod    -> setRanges(r, 2);
            if(user_config->m_track_debug)
                addDebugToScene(user_config->m_track_debug);

        }
        else
        {
//            fclose(fd);
//            char msg[MAX_ERROR_MESSAGE_LENGTH];
//            snprintf(msg, sizeof(msg), "Syntax error in '%s': %s",
            fprintf(stderr, "Warning: Syntax error in '%s': %s",
                     path.c_str(), s);
//            throw std::runtime_error(msg);
        }
    }   // while fgets

    fclose ( fd ) ;
    file_manager->popTextureSearchPath();
    file_manager->popModelSearchPath  ();

    createPhysicsModel();
}   // loadTrack

Here is the call graph for this function:

Here is the caller graph for this function:

int Track::pointInQuad ( const sgVec2  A,
const sgVec2  B,
const sgVec2  C,
const sgVec2  D,
const sgVec2  POINT 
) const [private]

pointInQuad() works by checking if the given point is 'to the right' in clock-wise direction (which would be to look towards the inside of the quad) of each line segment that forms the quad.

If it is to the left of all the segments, then the point is inside. This idea works for convex polygons, so we have to test it for the two triangles that compose the quad, in case that the quad is concave, not for the quad itself.

Definition at line 108 of file track.cpp.

{
    if(pointSideToLine( C, A, POINT ) >= 0.0 )
    {
        //Test the first triangle
        if( pointSideToLine( A, B, POINT ) >  0.0 &&
            pointSideToLine( B, C, POINT ) >= 0.0    )
            return QUAD_TRI_FIRST;
        return QUAD_TRI_NONE;
    }

    //Test the second triangle
    if( pointSideToLine( C, D, POINT ) > 0.0 &&
        pointSideToLine( D, A, POINT ) > 0.0     )
        return QUAD_TRI_SECOND;

    return QUAD_TRI_NONE;
}   // pointInQuad

Here is the caller graph for this function:

float Track::pointSideToLine ( const sgVec2  L1,
const sgVec2  L2,
const sgVec2  P 
) const [inline, private]

Finds on which side of the line segment a given point is.

Definition at line 92 of file track.cpp.

{
    return ( L2[0]-L1[0] )*( P[1]-L1[1] )-( L2[1]-L1[1] )*( P[0]-L1[0] );
}   // pointSideToLine
void Track::readDrivelineFromFile ( std::vector< sgVec3Wrapper > &  line,
const std::string &  file_ext 
) [private]

Definition at line 985 of file track.cpp.

{
    std::string path = file_manager->getTrackFile(m_ident+file_ext);
    FILE *fd = fopen ( path.c_str(), "r" ) ;

    if ( fd == NULL )
    {
        char msg[MAX_ERROR_MESSAGE_LENGTH];
        snprintf (msg, sizeof(msg), "Can't open '%s' for reading.\n", path.c_str() ) ;
        throw std::runtime_error(msg);
    }

    int prev_sector = UNKNOWN_SECTOR;
    SGfloat 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 )
        {
            char msg[MAX_ERROR_MESSAGE_LENGTH];
            snprintf (msg, sizeof(msg), "Syntax error in '%s'\n", path.c_str() ) ;
            throw std::runtime_error(msg);
        }

        sgVec3 point;
        point[0] = x;
        point[1] = y;
        point[2] = z;

        if(prev_sector != UNKNOWN_SECTOR) prev_distance = sgDistanceVec2(
            point, line[prev_sector] );

        //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

Here is the call graph for this function:

Here is the caller graph for this function:

int Track::spatialToTrack ( sgVec3  dst,
const sgVec2  POS,
const int  SECTOR 
) const

spatialToTrack() takes absolute coordinates (coordinates in OpenGL space) and transforms them into coordinates based on the track.

It is for 2D coordinates, thought it can be used on 3D vectors. The y-axis of the returned vector is how much of the track the point has gone through, the x-axis is on which side of the road it is, and the z-axis contains half the width of the track at this point. The return value is p1, i.e. the first of the two driveline points between which the kart is currently located.

Definition at line 356 of file track.cpp.

{
    if( SECTOR == UNKNOWN_SECTOR )
    {
        std::cerr << "WARNING: UNKNOWN_SECTOR in spatialToTrack().\n";
        return -1;
    }

    const unsigned int DRIVELINE_SIZE = (unsigned int)m_driveline.size();
    const size_t PREV = SECTOR == 0 ? DRIVELINE_SIZE - 1 : SECTOR - 1;
    const size_t NEXT = (size_t)SECTOR+1 >= DRIVELINE_SIZE ? 0 : SECTOR + 1;

    const float DIST_PREV = sgDistanceVec2 ( m_driveline[PREV], POS );
    const float DIST_NEXT = sgDistanceVec2 ( m_driveline[NEXT], POS );

    size_t p1, p2;
    if ( DIST_NEXT < DIST_PREV )
    {
        p1 = SECTOR; p2 = NEXT;
    }
    else
    {
        p1 = PREV; p2 = SECTOR;
    }

    sgVec3 line_eqn;
    sgVec2 tmp;

    sgMake2DLine ( line_eqn, m_driveline[p1], m_driveline[p2] );

    dst[0] = sgDistToLineVec2 ( line_eqn, POS );

    sgAddScaledVec2 ( tmp, POS, line_eqn, -dst [0] );

    float dist_from_driveline_p1 = sgDistanceVec2 ( tmp, m_driveline[p1] );
    dst[1] = dist_from_driveline_p1 + m_distance_from_start[p1];
    // Set z-axis to half the width (linear interpolation between the
    // width at p1 and p2) - m_path_width is actually already half the width
    // of the track. This is used to determine if a kart is too far
    // away from the road and is therefore considered taking a shortcut.

    float fraction = dist_from_driveline_p1
                   / (m_distance_from_start[p2]-m_distance_from_start[p1]);
    dst[2] = m_path_width[p1]*(1-fraction)+fraction*m_path_width[p2];

    return (int)p1;
}   // spatialToTrack

Here is the caller graph for this function:

void Track::startMusic ( ) const

Definition at line 880 of file track.cpp.

                             {
    sound_manager->startMusic(m_music[rand()% m_music.size()]);
}   // startMusic

Here is the call graph for this function:

Here is the caller graph for this function:

void Track::trackToSpatial ( sgVec3  xyz,
const int  SECTOR 
) const

Definition at line 409 of file track.cpp.

{
    sgCopyVec3 ( xyz, m_driveline [ SECTOR ] ) ;
}   // trackToSpatial
const bool& Track::useFog ( ) const [inline]

Definition at line 181 of file track.hpp.

{return m_use_fog;            }

Here is the caller graph for this function:


Member Data Documentation

Definition at line 60 of file track.hpp.

Definition at line 61 of file track.hpp.

Position of the sun.

Definition at line 93 of file track.hpp.

std::vector<SGfloat> Track::m_angle

Definition at line 127 of file track.hpp.

std::string Track::m_description [private]

Definition at line 51 of file track.hpp.

std::string Track::m_designer [private]

Definition at line 52 of file track.hpp.

Definition at line 95 of file track.hpp.

std::vector<SGfloat> Track::m_distance_from_start

Definition at line 125 of file track.hpp.

Definition at line 145 of file track.hpp.

Definition at line 124 of file track.hpp.

Definition at line 135 of file track.hpp.

Definition at line 134 of file track.hpp.

std::string Track::m_filename [private]

Definition at line 53 of file track.hpp.

Definition at line 88 of file track.hpp.

Definition at line 89 of file track.hpp.

Definition at line 91 of file track.hpp.

Definition at line 90 of file track.hpp.

float Track::m_gravity [private]

Definition at line 44 of file track.hpp.

std::string Track::m_herring_style [private]

Definition at line 50 of file track.hpp.

std::string Track::m_ident [private]

Definition at line 45 of file track.hpp.

Definition at line 131 of file track.hpp.

ssgBranch* Track::m_model [private]

Definition at line 54 of file track.hpp.

std::vector<MusicInformation*> Track::m_music [private]

Definition at line 48 of file track.hpp.

std::string Track::m_name

Definition at line 85 of file track.hpp.

Definition at line 56 of file track.hpp.

std::vector<SGfloat> Track::m_path_width

Definition at line 126 of file track.hpp.

Definition at line 132 of file track.hpp.

Definition at line 143 of file track.hpp.

Definition at line 143 of file track.hpp.

std::string Track::m_screenshot [private]

Definition at line 46 of file track.hpp.

Definition at line 86 of file track.hpp.

Definition at line 94 of file track.hpp.

std::vector<float> Track::m_start_heading [private]

Definition at line 49 of file track.hpp.

std::vector<float> Track::m_start_x [private]

Definition at line 49 of file track.hpp.

std::vector<float> Track::m_start_y [private]

Definition at line 49 of file track.hpp.

std::vector<float> Track::m_start_z [private]

Definition at line 49 of file track.hpp.

Definition at line 92 of file track.hpp.

std::string Track::m_top_view [private]

Definition at line 47 of file track.hpp.

Definition at line 138 of file track.hpp.

Definition at line 141 of file track.hpp.

Definition at line 141 of file track.hpp.

Definition at line 55 of file track.hpp.

Definition at line 87 of file track.hpp.

const float Track::NOHIT = -99999.9f [static]

Definition at line 139 of file track.hpp.

const int Track::QUAD_TRI_FIRST = 1 [static]

Definition at line 68 of file track.hpp.

const int Track::QUAD_TRI_NONE = -1 [static]

Definition at line 67 of file track.hpp.

const int Track::QUAD_TRI_SECOND = 2 [static]

Definition at line 69 of file track.hpp.

const int Track::UNKNOWN_SECTOR = -1 [static]

Definition at line 71 of file track.hpp.


The documentation for this class was generated from the following files: