Merged reverse-mode branch back into trunk.
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@10867 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
commit
7ad18d4815
@ -42,8 +42,17 @@
|
||||
</div>
|
||||
|
||||
<!-- Right pane -->
|
||||
<placeholder proportion="1" height="100%" id="screenshot_div">
|
||||
</placeholder>
|
||||
<div proportion="1" height="100%" layout="vertical-row">
|
||||
<placeholder proportion="1" width="100%" height="100%" id="screenshot_div">
|
||||
</placeholder>
|
||||
<div width="75%" height="fit" layout="horizontal-row" >
|
||||
<spacer width="40" height="2" />
|
||||
<checkbox id="reverse"/>
|
||||
<spacer width="20" height="2" />
|
||||
<label id="reverse-text" height="100%" I18N="Drive the track reverse" text="Reverse"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<spacer width="1" height="5%"/>
|
||||
|
@ -114,7 +114,12 @@ void Camera::readEndCamera(const XMLNode &root)
|
||||
m_end_cameras.clear();
|
||||
for(unsigned int i=0; i<root.getNumNodes(); i++)
|
||||
{
|
||||
const XMLNode *node = root.getNode(i);
|
||||
unsigned int index = i;
|
||||
// In reverse mode, reverse the order in which the
|
||||
// end cameras are read.
|
||||
if(QuadGraph::get()->isReverse())
|
||||
index = root.getNumNodes() - 1 - i;
|
||||
const XMLNode *node = root.getNode(index);
|
||||
EndCameraInformation eci;
|
||||
if(!eci.readXML(*node)) continue;
|
||||
m_end_cameras.push_back(eci);
|
||||
@ -220,12 +225,8 @@ void Camera::setMode(Mode mode)
|
||||
{
|
||||
m_next_end_camera = m_end_cameras.size()>1 ? 1 : 0;
|
||||
m_current_end_camera = 0;
|
||||
if(m_end_cameras.size()>0 &&
|
||||
m_end_cameras[0].m_type==EndCameraInformation::EC_STATIC_FOLLOW_KART)
|
||||
{
|
||||
m_camera->setPosition(m_end_cameras[0].m_position.toIrrVector());
|
||||
m_camera->setTarget(m_kart->getXYZ().toIrrVector());
|
||||
}
|
||||
m_camera->setFOV(m_fov);
|
||||
handleEndCamera(0);
|
||||
} // mode==CM_FINAL
|
||||
|
||||
m_mode = mode;
|
||||
@ -255,8 +256,9 @@ void Camera::reset()
|
||||
*/
|
||||
void Camera::setInitialTransform()
|
||||
{
|
||||
m_camera->setPosition( m_kart->getXYZ().toIrrVector()
|
||||
+ core::vector3df(0, 25, -50) );
|
||||
Vec3 start_offset(0, 25, -50);
|
||||
Vec3 xx = m_kart->getTrans()(start_offset);
|
||||
m_camera->setPosition( xx.toIrrVector());
|
||||
// Reset the target from the previous target (in case of a restart
|
||||
// of a race) - otherwise the camera will initially point in the wrong
|
||||
// direction till smoothMoveCamera has corrected this. Setting target
|
||||
@ -491,7 +493,8 @@ void Camera::positionCamera(float dt, float above_kart, float cam_angle,
|
||||
|
||||
if (race_manager->getNumLocalPlayers() < 2)
|
||||
{
|
||||
sfx_manager->positionListener(m_camera->getPosition(), wanted_target - m_camera->getPosition());
|
||||
sfx_manager->positionListener(m_camera->getPosition(),
|
||||
wanted_target - m_camera->getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,6 +508,25 @@ void Camera::positionCamera(float dt, float above_kart, float cam_angle,
|
||||
*/
|
||||
void Camera::handleEndCamera(float dt)
|
||||
{
|
||||
// First test if the kart is close enough to the next end camera, and
|
||||
// if so activate it.
|
||||
if( m_end_cameras.size()>0 &&
|
||||
m_end_cameras[m_next_end_camera].isReached(m_kart->getXYZ()))
|
||||
{
|
||||
m_current_end_camera = m_next_end_camera;
|
||||
if(m_end_cameras[m_current_end_camera].m_type
|
||||
==EndCameraInformation::EC_STATIC_FOLLOW_KART)
|
||||
{
|
||||
m_camera->setPosition(
|
||||
m_end_cameras[m_current_end_camera].m_position.toIrrVector()
|
||||
);
|
||||
}
|
||||
m_camera->setFOV(m_fov);
|
||||
m_next_end_camera++;
|
||||
if(m_next_end_camera>=(unsigned)m_end_cameras.size())
|
||||
m_next_end_camera = 0;
|
||||
}
|
||||
|
||||
EndCameraInformation::EndCameraType info
|
||||
= m_end_cameras.size()==0 ? EndCameraInformation::EC_AHEAD_OF_KART
|
||||
: m_end_cameras[m_current_end_camera].m_type;
|
||||
@ -513,7 +535,11 @@ void Camera::handleEndCamera(float dt)
|
||||
{
|
||||
case EndCameraInformation::EC_STATIC_FOLLOW_KART:
|
||||
{
|
||||
const core::vector3df &cp = m_camera->getAbsolutePosition();
|
||||
// Since the camera has no parents, we can use the relative
|
||||
// position here (otherwise we need to call updateAbsolutePosition
|
||||
// after changing the relative position in order to get the right
|
||||
// position here).
|
||||
const core::vector3df &cp = m_camera->getPosition();
|
||||
const Vec3 &kp = m_kart->getXYZ();
|
||||
// Estimate the fov, assuming that the vector from the camera to
|
||||
// the kart and the kart length are orthogonal to each other
|
||||
@ -541,22 +567,7 @@ void Camera::handleEndCamera(float dt)
|
||||
default: break;
|
||||
} // switch
|
||||
|
||||
// Now test if the kart is close enough to the next end camera, and
|
||||
// if so activate it.
|
||||
if( m_end_cameras.size()>0 &&
|
||||
m_end_cameras[m_next_end_camera].isReached(m_kart->getXYZ()))
|
||||
{
|
||||
m_current_end_camera = m_next_end_camera;
|
||||
if(m_end_cameras[m_current_end_camera].m_type
|
||||
==EndCameraInformation::EC_STATIC_FOLLOW_KART)
|
||||
m_camera->setPosition(
|
||||
m_end_cameras[m_current_end_camera].m_position.toIrrVector()
|
||||
);
|
||||
m_camera->setFOV(m_fov);
|
||||
m_next_end_camera++;
|
||||
if(m_next_end_camera>=(unsigned)m_end_cameras.size()) m_next_end_camera = 0;
|
||||
}
|
||||
} // checkForNextEndCamera
|
||||
} // handleEndCamera
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets viewport etc. for this camera. Called from irr_driver just before
|
||||
|
@ -173,6 +173,7 @@ void LODNode::OnRegisterSceneNode()
|
||||
{
|
||||
scene::IMeshBuffer* mb = mesh->getMeshBuffer(n);
|
||||
video::ITexture* t = mb->getMaterial().getTexture(0);
|
||||
if(!t) continue;
|
||||
Material* m = material_manager->getMaterialFor(t, mb);
|
||||
if (m != NULL)
|
||||
{
|
||||
|
@ -225,22 +225,7 @@ void RubberBall::getNextControlPoint()
|
||||
m_length_cp_2_3 = dist;
|
||||
const Quad &quad =
|
||||
QuadGraph::get()->getQuadOfNode(m_last_aimed_graph_node);
|
||||
Vec3 aim = quad.getCenter();
|
||||
// If we are close enough for the ball to hop faster, adjust the position
|
||||
// relative to the center of the track depending on where the target is:
|
||||
|
||||
// if(m_fast_ping)
|
||||
if(0)
|
||||
{
|
||||
LinearWorld *world = dynamic_cast<LinearWorld*>(World::getWorld());
|
||||
float r = world->getTrackSector(m_target->getWorldKartId())
|
||||
.getRelativeDistanceToCenter();
|
||||
aim -= m_st_early_target_factor * r
|
||||
* QuadGraph::get()->getNode(m_last_aimed_graph_node)
|
||||
.getCenterToRightVector();
|
||||
}
|
||||
|
||||
m_control_points[3] = aim;
|
||||
m_control_points[3] = quad.getCenter();
|
||||
} // getNextControlPoint
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -78,6 +78,14 @@ void AIBaseController::computePath()
|
||||
next.clear();
|
||||
// Get all successors the AI is allowed to take.
|
||||
QuadGraph::get()->getSuccessors(i, next, /*for_ai*/true);
|
||||
// In case of short cuts hidden for the AI it can be that a node
|
||||
// might not have a successor (since the first and last edge of
|
||||
// a hidden shortcut is ignored). Since in the case that the AI
|
||||
// ends up on a short cut (e.g. by accident) and doesn't have an
|
||||
// allowed way to drive, it should still be able to drive, so add
|
||||
// the non-AI successors of that node in this case.
|
||||
if(next.size()==0)
|
||||
QuadGraph::get()->getSuccessors(i, next, /*for_ai*/false);
|
||||
// For now pick one part on random, which is not adjusted during the
|
||||
// race. Long term statistics might be gathered to determine the
|
||||
// best way, potentially depending on race position etc.
|
||||
|
@ -134,6 +134,19 @@ void EndController::reset()
|
||||
}
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Callback when a new lap is triggered. It is used to switch to the first
|
||||
* end camera (which is esp. useful in fixing up end cameras in reverse mode,
|
||||
* since otherwise the switch to the first end camera usually happens way too
|
||||
* late)
|
||||
*/
|
||||
void EndController::newLap(int lap)
|
||||
{
|
||||
// This will implicitely trigger setting the first end camera to be active.
|
||||
if(m_kart->getCamera())
|
||||
m_kart->getCamera()->setMode(Camera::CM_FINAL);
|
||||
} // newLap
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** The end controller must forward 'fire' presses to the race gui.
|
||||
*/
|
||||
|
@ -86,6 +86,7 @@ public:
|
||||
* to the right player. */
|
||||
virtual bool isPlayerController () const {return m_player!=NULL;}
|
||||
virtual void action (PlayerAction action, int value);
|
||||
virtual void newLap (int lap);
|
||||
|
||||
}; // EndKart
|
||||
|
||||
|
@ -361,6 +361,7 @@ void cmdLineHelp (char* invocation)
|
||||
" --list-karts Show available karts.\n"
|
||||
" --laps N Define number of laps to N.\n"
|
||||
" --mode N N=1 novice, N=2 driver, N=3 racer.\n"
|
||||
" --reverse Play track in reverse (if allowed)\n"
|
||||
// TODO: add back "--players" switch
|
||||
// " --players n Define number of players to between 1 and 4.\n"
|
||||
" --item STYLE Use STYLE as your item style.\n"
|
||||
@ -766,6 +767,10 @@ int handleCmdLine(int argc, char **argv)
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else if( !strcmp(argv[i], "--reverse"))
|
||||
{
|
||||
race_manager->setReverseTrack(true);
|
||||
}
|
||||
else if( (!strcmp(argv[i], "--track") || !strcmp(argv[i], "-t"))
|
||||
&& i+1<argc )
|
||||
{
|
||||
|
@ -216,10 +216,15 @@ void LinearWorld::newLap(unsigned int kart_index)
|
||||
KartInfo &kart_info = m_kart_info[kart_index];
|
||||
Kart *kart = m_karts[kart_index];
|
||||
|
||||
// Don't do anything if a kart that has already finished the race
|
||||
// crosses the start line again. This avoids 'fastest lap' messages
|
||||
// if the end controller does a fastest lap.
|
||||
if(kart->hasFinishedRace()) return;
|
||||
// Only update the kart controller if a kart that has already finished
|
||||
// the race crosses the start line again. This avoids 'fastest lap'
|
||||
// messages if the end controller does a fastest lap, but especially
|
||||
// allows the end controller to switch end cameras
|
||||
if(kart->hasFinishedRace())
|
||||
{
|
||||
kart->getController()->newLap(kart_info.m_race_lap);
|
||||
return;
|
||||
}
|
||||
|
||||
const int lap_count = race_manager->getNumLaps();
|
||||
|
||||
@ -496,12 +501,10 @@ float LinearWorld::estimateFinishTimeForKart(Kart* kart)
|
||||
// In case that a kart is rescued behind start line, or ...
|
||||
if(distance_covered<0) distance_covered =1.0f;
|
||||
|
||||
const float full_distance = race_manager->getNumLaps()
|
||||
* m_track->getTrackLength();
|
||||
const float average_speed = distance_covered/getTime();
|
||||
|
||||
// Finish time is the time needed for the whole race with
|
||||
// the average speed computed above.
|
||||
float full_distance = race_manager->getNumLaps()
|
||||
* m_track->getTrackLength();
|
||||
if(full_distance == 0)
|
||||
full_distance = 1; // For 0 lap races avoid warning below
|
||||
#ifdef DEBUG
|
||||
if(full_distance < distance_covered)
|
||||
{
|
||||
@ -510,9 +513,17 @@ float LinearWorld::estimateFinishTimeForKart(Kart* kart)
|
||||
printf("%f < %f\n", full_distance, distance_covered);
|
||||
}
|
||||
#endif
|
||||
// Avoid potential problems (floating point issues, coding bug?) if a
|
||||
// kart has driven more than the full distance, but not finished:
|
||||
// Return the current time plus initial position to spread arrival
|
||||
// times a bit. This code should generally not be used at all, it's
|
||||
// just here to avoid invalid finishing times.
|
||||
if(full_distance < distance_covered)
|
||||
return getTime() + kart->getInitialPosition();
|
||||
|
||||
// Finish time is the time needed for the whole race with
|
||||
// the computed average speed computed.
|
||||
const float average_speed = distance_covered/getTime();
|
||||
return getTime() + (full_distance - distance_covered) / average_speed;
|
||||
|
||||
} // estimateFinishTimeForKart
|
||||
|
@ -137,7 +137,7 @@ public:
|
||||
virtual bool haveBonusBoxes(){ return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Override settings from base class */
|
||||
virtual bool computeChecklineRequirements() const { return true; }
|
||||
virtual bool useChecklineRequirements() const { return true; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns true if the kart is on a valid driveline quad.
|
||||
* \param kart_index Index of the kart. */
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
virtual void onFirePressed(Controller* who);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Override settings from base class */
|
||||
virtual bool computeChecklineRequirements() const { return false; }
|
||||
virtual bool useChecklineRequirements() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
void scheduleReturnToGarage() { m_return_to_garage = true; }
|
||||
};
|
||||
|
@ -108,7 +108,7 @@ void World::init()
|
||||
m_eliminated_karts = 0;
|
||||
m_eliminated_players = 0;
|
||||
m_num_players = 0;
|
||||
|
||||
|
||||
// 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.
|
||||
@ -133,7 +133,7 @@ void World::init()
|
||||
|
||||
// Load the track models - this must be done before the karts so that the
|
||||
// karts can be positioned properly on (and not in) the tracks.
|
||||
m_track->loadTrackModel(this);
|
||||
m_track->loadTrackModel(this, race_manager->getReverseTrack());
|
||||
|
||||
for(unsigned int i=0; i<num_karts; i++)
|
||||
{
|
||||
|
@ -284,7 +284,7 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Whether to compute checkline requirements for each world on the
|
||||
* quadgraph. Override to change value. */
|
||||
virtual bool computeChecklineRequirements() const { return false; }
|
||||
virtual bool useChecklineRequirements() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
void delayedSelfDestruct();
|
||||
|
||||
|
@ -55,6 +55,7 @@ RaceManager::RaceManager()
|
||||
m_minor_mode = MINOR_MODE_NORMAL_RACE;
|
||||
m_track_number = 0;
|
||||
m_coin_target = 0;
|
||||
setReverseTrack(false);
|
||||
setTrack("jungle");
|
||||
m_default_ai_list.clear();
|
||||
setNumLocalPlayers(0);
|
||||
@ -351,7 +352,7 @@ void RaceManager::startNextRace()
|
||||
else if(m_minor_mode==MINOR_MODE_FOLLOW_LEADER)
|
||||
World::setWorld(new FollowTheLeaderRace());
|
||||
else if(m_minor_mode==MINOR_MODE_NORMAL_RACE ||
|
||||
m_minor_mode==MINOR_MODE_TIME_TRIAL)
|
||||
m_minor_mode==MINOR_MODE_TIME_TRIAL)
|
||||
World::setWorld(new StandardRace());
|
||||
else if(m_minor_mode==MINOR_MODE_3_STRIKES)
|
||||
World::setWorld(new ThreeStrikesBattle());
|
||||
@ -617,7 +618,8 @@ void RaceManager::startGP(const GrandPrixData* gp)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void RaceManager::startSingleRace(const std::string trackIdent, const int num_laps)
|
||||
void RaceManager::startSingleRace(const std::string trackIdent,
|
||||
const int num_laps)
|
||||
{
|
||||
StateManager::get()->enterGameState();
|
||||
setTrack(trackIdent.c_str());
|
||||
|
@ -250,6 +250,9 @@ private:
|
||||
/** The number of laps for each track of a GP (only one element
|
||||
* is used if only a single track is used. */
|
||||
std::vector<int> m_num_laps;
|
||||
|
||||
/** Whether a track should be reversed */
|
||||
std::vector<bool> m_reverse_track;
|
||||
|
||||
/** The points given to a kart on a given position (index is
|
||||
* 0 based, so using race-position - 1. */
|
||||
@ -315,6 +318,10 @@ public:
|
||||
|
||||
void setNumLaps(int num) { m_num_laps.clear();
|
||||
m_num_laps.push_back(num); }
|
||||
|
||||
void setReverseTrack(bool r_t) { m_reverse_track.clear();
|
||||
m_reverse_track.push_back(r_t); }
|
||||
|
||||
void setMajorMode(MajorRaceModeType mode)
|
||||
{ m_major_mode = mode; }
|
||||
void setMinorMode(MinorRaceModeType mode)
|
||||
@ -358,6 +365,9 @@ public:
|
||||
return 9999;
|
||||
return m_num_laps[m_track_number];
|
||||
} // getNumLaps
|
||||
// ------------------------------------------------------------------------
|
||||
/** \return whether the track should be reversed */
|
||||
bool getReverseTrack() const { return m_reverse_track[m_track_number]; }
|
||||
|
||||
Difficulty getDifficulty() const { return m_difficulty; }
|
||||
const std::string& getTrackName() const { return m_tracks[m_track_number]; }
|
||||
@ -481,9 +491,11 @@ public:
|
||||
void startGP(const GrandPrixData* gp);
|
||||
|
||||
/**
|
||||
* \brief Higher-level method to start a GP without having to care about the exact startup sequence
|
||||
* \brief Higher-level method to start a GP without having to care about
|
||||
* the exact startup sequence.
|
||||
* \param trackIdent Internal name of the track to race on
|
||||
* \param num_laps Number of laps to race, or -1 if number of laps is not relevant in current mode
|
||||
* \param num_laps Number of laps to race, or -1 if number of laps is
|
||||
* not relevant in current mode
|
||||
*/
|
||||
void startSingleRace(const std::string trackIdent, const int num_laps);
|
||||
|
||||
|
@ -116,6 +116,21 @@ TrackInfoDialog::TrackInfoDialog(const std::string& ribbonItem, const std::strin
|
||||
}
|
||||
|
||||
|
||||
// Reverse track
|
||||
const bool reverse_available = track->reverseAvailable();
|
||||
if (reverse_available)
|
||||
{
|
||||
m_checkbox = getWidget<CheckBoxWidget>("reverse");
|
||||
m_checkbox->setState(race_manager->getReverseTrack());
|
||||
}
|
||||
else
|
||||
{
|
||||
getWidget<CheckBoxWidget>("reverse")->setVisible(false);
|
||||
getWidget<LabelWidget>("reverse-text")->setVisible(false);
|
||||
m_checkbox = NULL;
|
||||
race_manager->setReverseTrack(false);
|
||||
}
|
||||
|
||||
// ---- High Scores
|
||||
if (has_highscores)
|
||||
{
|
||||
@ -144,7 +159,7 @@ TrackInfoDialog::TrackInfoDialog(const std::string& ribbonItem, const std::strin
|
||||
|
||||
getWidget<ButtonWidget>("start")->setFocusForPlayer( PLAYER_ID_GAME_MASTER );
|
||||
|
||||
}
|
||||
} // TrackInfoDialog
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -158,7 +173,7 @@ TrackInfoDialog::~TrackInfoDialog()
|
||||
((TracksScreen*)curr_screen)->setFocusOnTrack(m_ribbon_item);
|
||||
}
|
||||
|
||||
}
|
||||
} // ~TrackInfoDialog
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -214,17 +229,23 @@ void TrackInfoDialog::updateHighScores()
|
||||
m_highscore_entries[n]->setText( line.c_str(), false );
|
||||
|
||||
}
|
||||
}
|
||||
} // updateHighScores
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
void TrackInfoDialog::onEnterPressedInternal()
|
||||
{
|
||||
ModalDialog::dismiss();
|
||||
|
||||
// Create a copy of member variables we still need, since they will
|
||||
// not be accessible after dismiss:
|
||||
const int num_laps = (m_spinner == NULL ? -1 : m_spinner->getValue());
|
||||
race_manager->startSingleRace(m_track_ident, num_laps);
|
||||
}
|
||||
const bool reverse_track = m_checkbox == NULL ? false
|
||||
: m_checkbox->getState();
|
||||
race_manager->setReverseTrack(reverse_track);
|
||||
std::string track_ident = m_track_ident;
|
||||
ModalDialog::dismiss();
|
||||
race_manager->startSingleRace(track_ident, num_laps);
|
||||
} // onEnterPressedInternal
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
@ -232,14 +253,13 @@ GUIEngine::EventPropagation TrackInfoDialog::processEvent(const std::string& eve
|
||||
{
|
||||
if (eventSource == "start" )
|
||||
{
|
||||
// Create a copy of member variables we still need, since they will
|
||||
// not be accessible after dismiss:
|
||||
const int num_laps = (m_spinner == NULL ? -1 : m_spinner->getValue());
|
||||
std::string track_ident = m_track_ident;
|
||||
ModalDialog::dismiss();
|
||||
race_manager->startSingleRace(track_ident, num_laps);
|
||||
onEnterPressedInternal();
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
else if (eventSource == "reversecheckbox")
|
||||
{
|
||||
race_manager->setReverseTrack(m_checkbox->getState());
|
||||
}
|
||||
else if (eventSource == "lapcountspinner")
|
||||
{
|
||||
assert(m_spinner != NULL);
|
||||
@ -250,6 +270,6 @@ GUIEngine::EventPropagation TrackInfoDialog::processEvent(const std::string& eve
|
||||
}
|
||||
|
||||
return GUIEngine::EVENT_LET;
|
||||
}
|
||||
} // processEvent
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define HEADER_TRACKINFO_DIALOG_HPP
|
||||
|
||||
#include "guiengine/modaldialog.hpp"
|
||||
#include "guiengine/widgets/check_box_widget.hpp"
|
||||
|
||||
static const int HIGHSCORE_COUNT = 3;
|
||||
|
||||
@ -42,6 +43,7 @@ class TrackInfoDialog : public GUIEngine::ModalDialog
|
||||
// When there is no need to tab through / click on images/labels, we can add directly
|
||||
// irrlicht labels (more complicated uses require the use of our widget set)
|
||||
GUIEngine::SpinnerWidget* m_spinner;
|
||||
GUIEngine::CheckBoxWidget* m_checkbox;
|
||||
GUIEngine::IconButtonWidget* m_kart_icons[HIGHSCORE_COUNT];
|
||||
GUIEngine::LabelWidget* m_highscore_entries[HIGHSCORE_COUNT];
|
||||
|
||||
|
@ -28,14 +28,11 @@
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
/** Constructor for a checksphere.
|
||||
* \param check_manager Pointer to the check manager, which is needed when
|
||||
* resetting e.g. new lap counters.
|
||||
* \param node XML node containing the parameters for this checkline.
|
||||
*/
|
||||
AmbientLightSphere::AmbientLightSphere(CheckManager *check_manager,
|
||||
const XMLNode &node,
|
||||
AmbientLightSphere::AmbientLightSphere(const XMLNode &node,
|
||||
unsigned int index)
|
||||
: CheckSphere(check_manager, node, index)
|
||||
: CheckSphere(node, index)
|
||||
{
|
||||
m_ambient_color = video::SColor(255, 0, 255, 0); // green
|
||||
m_inner_radius2 = 1;
|
||||
|
@ -49,8 +49,7 @@ private:
|
||||
* inner radius. */
|
||||
video::SColor m_ambient_color;
|
||||
public:
|
||||
AmbientLightSphere(CheckManager *check_manager,
|
||||
const XMLNode &node, unsigned int index);
|
||||
AmbientLightSphere(const XMLNode &node, unsigned int index);
|
||||
virtual ~AmbientLightSphere() {};
|
||||
virtual void update(float dt);
|
||||
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "io/xml_node.hpp"
|
||||
#include "modes/linear_world.hpp"
|
||||
#include "race/race_manager.hpp"
|
||||
#include "tracks/check_manager.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
/** Constructor for a lap line.
|
||||
@ -31,9 +30,8 @@
|
||||
* resetting e.g. new lap counters.
|
||||
* \param node XML node containing the parameters for this checkline.
|
||||
*/
|
||||
CheckLap::CheckLap(CheckManager *check_manager, const XMLNode &node,
|
||||
unsigned int index)
|
||||
: CheckStructure(check_manager, node, index)
|
||||
CheckLap::CheckLap(const XMLNode &node, unsigned int index)
|
||||
: CheckStructure(node, index)
|
||||
{
|
||||
// Note that when this is called the karts have not been allocated
|
||||
// in world, so we can't call world->getNumKarts()
|
||||
|
@ -37,8 +37,7 @@ private:
|
||||
std::vector<float> m_previous_distance;
|
||||
|
||||
public:
|
||||
CheckLap(CheckManager *check_manager, const XMLNode &node,
|
||||
unsigned int index);
|
||||
CheckLap(const XMLNode &node, unsigned int index);
|
||||
virtual ~CheckLap() {};
|
||||
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
int indx);
|
||||
|
@ -27,13 +27,11 @@
|
||||
#include "race/race_manager.hpp"
|
||||
|
||||
/** Constructor for a checkline.
|
||||
* \param check_manager Pointer to the check manager, which is needed when
|
||||
* resetting e.g. new lap counters.
|
||||
* \param node XML node containing the parameters for this checkline.
|
||||
* \param index Index of this check structure in the check manager.
|
||||
*/
|
||||
CheckLine::CheckLine(CheckManager *check_manager, const XMLNode &node,
|
||||
unsigned int index)
|
||||
: CheckStructure(check_manager, node, index)
|
||||
CheckLine::CheckLine(const XMLNode &node, unsigned int index)
|
||||
: CheckStructure(node, index)
|
||||
{
|
||||
// Note that when this is called the karts have not been allocated
|
||||
// in world, so we can't call world->getNumKarts()
|
||||
|
@ -64,8 +64,7 @@ private:
|
||||
* quad and still considered to be able to cross it. */
|
||||
static const int m_over_min_height = 4;
|
||||
public:
|
||||
CheckLine(CheckManager *check_manager, const XMLNode &node,
|
||||
unsigned int index);
|
||||
CheckLine(const XMLNode &node, unsigned int index);
|
||||
virtual ~CheckLine();
|
||||
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, int indx);
|
||||
virtual void reset(const Track &track);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "tracks/check_manager.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "io/xml_node.hpp"
|
||||
#include "tracks/ambient_light_sphere.hpp"
|
||||
@ -27,7 +28,11 @@
|
||||
#include "tracks/check_structure.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
CheckManager::CheckManager(const XMLNode &node, Track *track)
|
||||
CheckManager *CheckManager::m_check_manager = NULL;
|
||||
|
||||
/** Loads all check structure informaiton from the specified xml file.
|
||||
*/
|
||||
void CheckManager::load(const XMLNode &node)
|
||||
{
|
||||
for(unsigned int i=0; i<node.getNumNodes(); i++)
|
||||
{
|
||||
@ -35,31 +40,61 @@ CheckManager::CheckManager(const XMLNode &node, Track *track)
|
||||
const std::string &type = check_node->getName();
|
||||
if(type=="check-line")
|
||||
{
|
||||
CheckLine *cl = new CheckLine(this, *check_node, i);
|
||||
CheckLine *cl = new CheckLine(*check_node, i);
|
||||
m_all_checks.push_back(cl);
|
||||
} // checkline
|
||||
else if(type=="check-lap")
|
||||
{
|
||||
m_all_checks.push_back(new CheckLap(this, *check_node, i));
|
||||
m_all_checks.push_back(new CheckLap(*check_node, i));
|
||||
}
|
||||
else if(type=="check-sphere")
|
||||
{
|
||||
AmbientLightSphere *cs = new AmbientLightSphere(this, *check_node,
|
||||
AmbientLightSphere *cs = new AmbientLightSphere(*check_node,
|
||||
i);
|
||||
m_all_checks.push_back(cs);
|
||||
} // checksphere
|
||||
else
|
||||
printf("Unknown check structure '%s' - ignored.\n", type.c_str());
|
||||
} // for i<node.getNumNodes
|
||||
} // CheckManager
|
||||
|
||||
// Now set all 'successors', i.e. check structures that need to get a
|
||||
// state change when a check structure is triggered. This can't be
|
||||
// done in the CheckStructures easily, since reversing a track changes
|
||||
// the direction of the dependencies.
|
||||
for(unsigned int i=0; i<node.getNumNodes(); i++)
|
||||
{
|
||||
const XMLNode *check_node = node.getNode(i);
|
||||
std::vector<int> check_structures_to_change_state;
|
||||
|
||||
check_node->get("other-ids", &check_structures_to_change_state);
|
||||
// Backwards compatibility to tracks exported with older versions of
|
||||
// the track exporter
|
||||
if(check_structures_to_change_state.size()==0)
|
||||
check_node->get("other-id", &check_structures_to_change_state);
|
||||
std::vector<int>::iterator it;
|
||||
for(it=check_structures_to_change_state.begin();
|
||||
it != check_structures_to_change_state.end(); it++)
|
||||
{
|
||||
if(QuadGraph::get()->isReverse())
|
||||
m_all_checks[*it]->addSuccessor(i);
|
||||
else
|
||||
m_all_checks[i]->addSuccessor(*it);
|
||||
}
|
||||
|
||||
}
|
||||
} // load
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Private destructor (to make sure it is only called using the static
|
||||
* destroy function). Frees all check structures.
|
||||
*/
|
||||
CheckManager::~CheckManager()
|
||||
{
|
||||
for(unsigned int i=0; i<m_all_checks.size(); i++)
|
||||
{
|
||||
delete m_all_checks[i];
|
||||
}
|
||||
m_check_manager = NULL;
|
||||
} // ~CheckManager
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -83,3 +118,41 @@ void CheckManager::update(float dt)
|
||||
(*i)->update(dt);
|
||||
} // update
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns the index of the first check structures that triggers a new
|
||||
* lap to be counted. It aborts if no lap structure is defined.
|
||||
*/
|
||||
unsigned int CheckManager::getLapLineIndex() const
|
||||
{
|
||||
for (unsigned int i=0; i<getCheckStructureCount(); i++)
|
||||
{
|
||||
CheckStructure* c = getCheckStructure(i);
|
||||
|
||||
if (dynamic_cast<CheckLap*>(c) != NULL) return i;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Error, no lap line for track found, aborting.\n");
|
||||
exit(-1);
|
||||
} // getLapLineIndex
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Returns the check line index that is triggered when going from 'from'
|
||||
* to 'to'. If no check line is triggered, -1 will be returned.
|
||||
* \param from Coordinates to start from.
|
||||
* \param to Coordinates to go to.
|
||||
*/
|
||||
int CheckManager::getChecklineTriggering(const Vec3 &from,
|
||||
const Vec3 &to) const
|
||||
{
|
||||
for (unsigned int i=0; i<getCheckStructureCount(); i++)
|
||||
{
|
||||
CheckStructure* c = getCheckStructure(i);
|
||||
|
||||
// FIXME: why is the lapline skipped?
|
||||
if (dynamic_cast<CheckLap*>(c) != NULL) continue;
|
||||
|
||||
if (c->isTriggered(from, to, 0 /* kart id */))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
} // getChecklineTriggering
|
@ -19,33 +19,57 @@
|
||||
#ifndef HEADER_CHECK_MANAGER_HPP
|
||||
#define HEADER_CHECK_MANAGER_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "utils/no_copy.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class XMLNode;
|
||||
class CheckStructure;
|
||||
class Track;
|
||||
class XMLNode;
|
||||
class Vec3;
|
||||
|
||||
/**
|
||||
* \brief Controls all checks structures of a track.
|
||||
* \ingroup tracks
|
||||
*/
|
||||
class CheckManager
|
||||
class CheckManager : public NoCopy
|
||||
{
|
||||
private:
|
||||
std::vector<CheckStructure*> m_all_checks;
|
||||
static CheckManager *m_check_manager;
|
||||
/** Private constructor, to make sure it is only called via
|
||||
* the static create function. */
|
||||
CheckManager() {m_all_checks.clear();};
|
||||
~CheckManager();
|
||||
public:
|
||||
CheckManager(const XMLNode &node, Track *track);
|
||||
~CheckManager();
|
||||
void update(float dt);
|
||||
void reset(const Track &track);
|
||||
|
||||
int getCheckStructureCount() const { return m_all_checks.size(); }
|
||||
|
||||
/** Returns the nth. check structure. */
|
||||
CheckStructure *getCheckStructure(unsigned int n)
|
||||
void load(const XMLNode &node);
|
||||
void update(float dt);
|
||||
void reset(const Track &track);
|
||||
unsigned int getLapLineIndex() const;
|
||||
int getChecklineTriggering(const Vec3 &from, const Vec3 &to) const;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Creates an instance of the check manager. */
|
||||
static void create()
|
||||
{
|
||||
if (n >= m_all_checks.size()) return NULL;
|
||||
assert(!m_check_manager);
|
||||
m_check_manager = new CheckManager();
|
||||
} // create
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the instance of the check manager. */
|
||||
static CheckManager* get() { return m_check_manager; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Destroys the check manager. */
|
||||
static void destroy() { delete m_check_manager; m_check_manager = NULL; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of check structures defined. */
|
||||
unsigned int getCheckStructureCount() const { return m_all_checks.size(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the nth. check structure. */
|
||||
CheckStructure *getCheckStructure(unsigned int n) const
|
||||
{
|
||||
assert(n < m_all_checks.size());
|
||||
return m_all_checks[n];
|
||||
}
|
||||
}; // CheckManager
|
||||
|
@ -30,9 +30,8 @@
|
||||
* resetting e.g. new lap counters.
|
||||
* \param node XML node containing the parameters for this checkline.
|
||||
*/
|
||||
CheckSphere::CheckSphere(CheckManager *check_manager, const XMLNode &node,
|
||||
unsigned int index)
|
||||
: CheckStructure(check_manager, node, index)
|
||||
CheckSphere::CheckSphere(const XMLNode &node, unsigned int index)
|
||||
: CheckStructure(node, index)
|
||||
{
|
||||
m_radius2 = 1;
|
||||
|
||||
|
@ -45,8 +45,7 @@ private:
|
||||
* This saves some computations. */
|
||||
std::vector<float> m_distance2;
|
||||
public:
|
||||
CheckSphere(CheckManager *check_manager, const XMLNode &node,
|
||||
unsigned int index);
|
||||
CheckSphere(const XMLNode &node, unsigned int index);
|
||||
virtual ~CheckSphere() {};
|
||||
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
int kart_id);
|
||||
|
@ -28,11 +28,16 @@
|
||||
#include "tracks/check_manager.hpp"
|
||||
|
||||
|
||||
CheckStructure::CheckStructure(CheckManager *check_manager,
|
||||
const XMLNode &node, unsigned int index)
|
||||
CheckStructure::CheckStructure(const XMLNode &node, unsigned int index)
|
||||
{
|
||||
m_index = index;
|
||||
m_check_manager = check_manager;
|
||||
m_check_type = CT_NEW_LAP;
|
||||
|
||||
// This structure is actually filled by the check manager (necessary
|
||||
// in order to support track reversing).
|
||||
m_check_structures_to_change_state.clear();
|
||||
m_same_group.clear();
|
||||
|
||||
std::string kind;
|
||||
node.get("kind", &kind);
|
||||
if(kind=="lap")
|
||||
@ -47,14 +52,7 @@ CheckStructure::CheckStructure(CheckManager *check_manager,
|
||||
{
|
||||
printf("Unknown check structure '%s' - ignored.\n", kind.c_str());
|
||||
}
|
||||
m_check_structures_to_change_state.clear();
|
||||
node.get("other-ids", &m_check_structures_to_change_state);
|
||||
// Backwards compatibility to tracks exported with older versions of
|
||||
// the track exporter
|
||||
if(m_check_structures_to_change_state.size()==0)
|
||||
node.get("other-id", &m_check_structures_to_change_state);
|
||||
|
||||
m_same_group.clear();
|
||||
node.get("same-group", &m_same_group);
|
||||
// Make sure that the index of this check structure is included in
|
||||
// the same_group list. While this should be guaranteed by the
|
||||
@ -115,7 +113,7 @@ void CheckStructure::update(float dt)
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Changes the status (active/inactive) of all check structures contained
|
||||
* in the index list indices.
|
||||
* \param indices List of index of check structures in check_manager that
|
||||
* \param indices List of index of check structures in the CheckManager that
|
||||
* are to be changed.
|
||||
* \param int kart_index For which the status should be changed.
|
||||
* \param change_state How to change the state (active, deactivate, toggle).
|
||||
@ -131,7 +129,7 @@ void CheckStructure::changeStatus(const std::vector<int> indices,
|
||||
for(unsigned int i=0; i<indices.size(); i++)
|
||||
{
|
||||
CheckStructure *cs =
|
||||
m_check_manager->getCheckStructure(indices[i]);
|
||||
CheckManager::get()->getCheckStructure(indices[i]);
|
||||
if (cs == NULL) continue;
|
||||
|
||||
switch(change_state)
|
||||
@ -177,9 +175,9 @@ void CheckStructure::changeStatus(const std::vector<int> indices,
|
||||
|
||||
/*
|
||||
printf("--------\n");
|
||||
for (int n=0; n<m_check_manager->getCheckStructureCount(); n++)
|
||||
for (int n=0; n<CheckManager::get()->getCheckStructureCount(); n++)
|
||||
{
|
||||
CheckStructure *cs = m_check_manager->getCheckStructure(n);
|
||||
CheckStructure *cs = CheckManager::get()->getCheckStructure(n);
|
||||
if (dynamic_cast<CheckLap*>(cs) != NULL)
|
||||
printf("Checkline %i (LAP) : %i\n", n, (int)cs->m_is_active[kart_index]);
|
||||
else
|
||||
|
@ -73,9 +73,6 @@ protected:
|
||||
bool m_active_at_reset;
|
||||
|
||||
private:
|
||||
/** Stores a pointer to the check manager. */
|
||||
CheckManager *m_check_manager;
|
||||
|
||||
/** The type of this checkline. */
|
||||
CheckType m_check_type;
|
||||
|
||||
@ -100,8 +97,7 @@ private:
|
||||
ChangeState change_state);
|
||||
|
||||
public:
|
||||
CheckStructure(CheckManager *check_manager, const XMLNode &node,
|
||||
unsigned int index);
|
||||
CheckStructure(const XMLNode &node, unsigned int index);
|
||||
virtual ~CheckStructure() {};
|
||||
virtual void update(float dt);
|
||||
virtual void changeDebugColor(bool is_active) {}
|
||||
@ -112,13 +108,20 @@ public:
|
||||
* \param indx Index of the kart, can be used to store kart specific
|
||||
* additional data.
|
||||
*/
|
||||
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos, int indx)=0;
|
||||
virtual bool isTriggered(const Vec3 &old_pos, const Vec3 &new_pos,
|
||||
int indx)=0;
|
||||
virtual void trigger(unsigned int kart_index);
|
||||
virtual void reset(const Track &track);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the type of this check structure. */
|
||||
CheckType getType() const { return m_check_type; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Adds the index of a successor check structure which will get triggered
|
||||
* by this check structure. */
|
||||
void addSuccessor(unsigned int i) {
|
||||
m_check_structures_to_change_state.push_back(i);
|
||||
} // addSuccessor
|
||||
}; // CheckStructure
|
||||
|
||||
#endif
|
||||
|
@ -25,45 +25,41 @@
|
||||
#include "tracks/quad_graph.hpp"
|
||||
#include "tracks/quad_set.hpp"
|
||||
|
||||
|
||||
// A static variable that gives a single graph node easy access to
|
||||
// all quads and avoids unnecessary parameters in many calls.
|
||||
QuadSet *GraphNode::m_all_quads=NULL;
|
||||
|
||||
// This static variable gives a node access to the graph, and therefore
|
||||
// to the quad to which a graph node index belongs.
|
||||
QuadGraph *GraphNode::m_all_nodes=NULL;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Constructor. Saves the quad index which belongs to this graph node.
|
||||
* \param index Index of the quad to use for this node (in m_all_quads).
|
||||
* \param index Index of the quad to use for this node (in QuadSet).
|
||||
*/
|
||||
GraphNode::GraphNode(unsigned int quad_index, unsigned int node_index)
|
||||
{
|
||||
assert(quad_index<m_all_quads->getNumberOfQuads());
|
||||
assert(quad_index<QuadSet::get()->getNumberOfQuads());
|
||||
m_quad_index = quad_index;
|
||||
m_node_index = node_index;
|
||||
m_predecessor = -1;
|
||||
m_distance_from_start = 0;
|
||||
m_distance_from_start = -1.0f;
|
||||
|
||||
const Quad &quad = m_all_quads->getQuad(m_quad_index);
|
||||
// FIXME: the following values should depend on the actual orientation
|
||||
const Quad &quad = QuadSet::get()->getQuad(m_quad_index);
|
||||
// The following values should depend on the actual orientation
|
||||
// of the quad. ATM we always assume that indices 0,1 are the lower end,
|
||||
// and 2,3 are the upper end.
|
||||
// and 2,3 are the upper end (or the reverse if reverse mode is selected).
|
||||
// The width is the average width at the beginning and at the end.
|
||||
m_width = ( (quad[1]-quad[0]).length()
|
||||
+ (quad[3]-quad[2]).length() ) * 0.5f;
|
||||
m_lower_center = (quad[0]+quad[1]) * 0.5f;
|
||||
m_upper_center = (quad[2]+quad[3]) * 0.5f;
|
||||
if(QuadGraph::get()->isReverse())
|
||||
{
|
||||
m_lower_center = (quad[2]+quad[3]) * 0.5f;
|
||||
m_upper_center = (quad[0]+quad[1]) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lower_center = (quad[0]+quad[1]) * 0.5f;
|
||||
m_upper_center = (quad[2]+quad[3]) * 0.5f;
|
||||
}
|
||||
m_line = core::line2df(m_lower_center.getX(), m_lower_center.getZ(),
|
||||
m_upper_center.getX(), m_upper_center.getZ() );
|
||||
// Only this 2d point is needed later
|
||||
m_lower_center_2d = core::vector2df(m_lower_center.getX(),
|
||||
m_lower_center.getZ() );
|
||||
|
||||
// The vector from the center of the quad to the middle of the right
|
||||
// side of the quad
|
||||
m_center_to_right = (quad[1]+quad[2])*0.5f - quad.getCenter();
|
||||
} // GraphNode
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -75,50 +71,22 @@ GraphNode::GraphNode(unsigned int quad_index, unsigned int node_index)
|
||||
void GraphNode::addSuccessor(unsigned int to)
|
||||
{
|
||||
m_successor_node.push_back(to);
|
||||
// m_quad_index is the quad index, so we use m_all_quads
|
||||
const Quad &this_quad = m_all_quads->getQuad(m_quad_index);
|
||||
// to is the graph node, so we have to use m_all_nodes to get the right quad
|
||||
GraphNode &gn = m_all_nodes->getNode(to);
|
||||
const Quad &next_quad = m_all_nodes->getQuadOfNode(to);
|
||||
// m_quad_index is the quad index
|
||||
const Quad &this_quad = QuadSet::get()->getQuad(m_quad_index);
|
||||
// to is the graph node
|
||||
GraphNode &gn = QuadGraph::get()->getNode(to);
|
||||
const Quad &next_quad = QuadGraph::get()->getQuadOfNode(to);
|
||||
|
||||
// Keep the first predecessor, which is usually the most 'natural' one.
|
||||
if(gn.m_predecessor==-1)
|
||||
gn.m_predecessor = m_node_index;
|
||||
core::vector2df d2 = m_lower_center_2d
|
||||
- m_all_nodes->getNode(to).m_lower_center_2d;
|
||||
|
||||
Vec3 diff = next_quad.getCenter() - this_quad.getCenter();
|
||||
m_distance_to_next.push_back(d2.getLength());
|
||||
|
||||
float theta = atan2(diff.getX(), diff.getZ());
|
||||
m_angle_to_next.push_back(theta);
|
||||
Vec3 d = m_lower_center - QuadGraph::get()->getNode(to).m_lower_center;
|
||||
m_distance_to_next.push_back(d.length());
|
||||
|
||||
Vec3 diff = next_quad.getCenter() - this_quad.getCenter();
|
||||
m_angle_to_next.push_back(atan2(diff.getX(), diff.getZ()));
|
||||
|
||||
// The length of this quad is the average of the left and right side
|
||||
float distance_to_next = ( this_quad[2].distance(this_quad[1])
|
||||
+ this_quad[3].distance(this_quad[0]) ) *0.5f;
|
||||
// The distance from start for the successor node
|
||||
if(to!=0)
|
||||
{
|
||||
float distance_for_next = m_distance_from_start+distance_to_next;
|
||||
// If the successor node does not have a distance from start defined,
|
||||
// update its distance. Otherwise if the node already has a distance,
|
||||
// it is potentially necessary to update its distance from start:
|
||||
// without this the length of the track (as taken by the distance
|
||||
// from start of the last node) could be smaller than some of the
|
||||
// paths. This can result in incorrect results for the arrival time
|
||||
// estimation of the AI karts. See trac #354 for details.
|
||||
if(m_all_nodes->getNode(to).m_distance_from_start==0)
|
||||
{
|
||||
m_all_nodes->getNode(to).m_distance_from_start = distance_for_next;
|
||||
}
|
||||
else if(m_all_nodes->getNode(to).m_distance_from_start
|
||||
< distance_for_next)
|
||||
{
|
||||
float delta = distance_for_next
|
||||
- m_all_nodes->getNode(to).getDistanceFromStart();
|
||||
m_all_nodes->updateDistancesForAllSuccessors(to, delta);
|
||||
}
|
||||
}
|
||||
} // addSuccessor
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -203,7 +171,8 @@ void GraphNode::getDistances(const Vec3 &xyz, Vec3 *result)
|
||||
result->setX( (closest-xyz2d).getLength()); // to the right
|
||||
else
|
||||
result->setX(-(closest-xyz2d).getLength()); // to the left
|
||||
result->setZ( m_distance_from_start + (closest-m_lower_center_2d).getLength());
|
||||
result->setZ( m_distance_from_start +
|
||||
(closest-m_lower_center_2d).getLength());
|
||||
} // getDistances
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -109,13 +109,6 @@ class GraphNode
|
||||
std::vector< int > m_checkline_requirements;
|
||||
|
||||
public:
|
||||
/** Keep a shared pointer so that some asserts and tests can be
|
||||
* done without adding additional parameters. */
|
||||
static QuadSet *m_all_quads;
|
||||
/** Keep a shared pointer to the graph structure so that each node
|
||||
* has access to the actual quad to which a node points. */
|
||||
static QuadGraph *m_all_nodes;
|
||||
|
||||
GraphNode(unsigned int quad_index, unsigned int node_index);
|
||||
void addSuccessor (unsigned int to);
|
||||
void getDistances(const Vec3 &xyz, Vec3 *result);
|
||||
@ -136,14 +129,14 @@ public:
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the quad of this graph node. */
|
||||
const Quad& getQuad() const {return m_all_quads->getQuad(m_quad_index);}
|
||||
const Quad& getQuad() const {return QuadSet::get()->getQuad(m_quad_index);}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the i-th. point of a quad. ATM this just returns the vertices
|
||||
* from the quads, but if necessary this method will also consider
|
||||
* rotated quads. So index 0 will always be lower left point, then
|
||||
* counterclockwise. */
|
||||
const Vec3& operator[](int i) const
|
||||
{return m_all_quads->getQuad(m_quad_index)[i];}
|
||||
{return QuadSet::get()->getQuad(m_quad_index)[i];}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the distance to the j-th. successor. */
|
||||
float getDistanceToSuccessor(unsigned int j) const
|
||||
@ -183,7 +176,7 @@ public:
|
||||
* \param index Index of the successor. */
|
||||
bool ignoreSuccessorForAI(unsigned int i) const
|
||||
{
|
||||
return m_all_quads->getQuad(m_successor_node[i]).letAIIgnore();
|
||||
return QuadSet::get()->getQuad(m_successor_node[i]).letAIIgnore();
|
||||
};
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a predecessor for this node. */
|
||||
@ -200,10 +193,6 @@ public:
|
||||
return m_path_to_node.size()>0 ? m_path_to_node[n] : 0;
|
||||
} // getSuccesorToReach
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns a vector from the center of the node to the middle of the
|
||||
* right side. */
|
||||
const Vec3 &getCenterToRightVector() const { return m_center_to_right; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the checkline requirements of this graph node. */
|
||||
const std::vector<int>& getChecklineRequirements() const
|
||||
{ return m_checkline_requirements; }
|
||||
|
@ -131,3 +131,4 @@ void Quad::transform(const btTransform &t, Quad *result) const
|
||||
std::min(result->m_p[2].getY(),
|
||||
result->m_p[3].getY()) );
|
||||
} // transform
|
||||
|
||||
|
@ -75,5 +75,6 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** True if this quad should be ignored by the AI. */
|
||||
bool letAIIgnore() const { return m_ai_ignore; }
|
||||
|
||||
}; // class Quad
|
||||
#endif
|
||||
|
@ -43,16 +43,17 @@ QuadGraph *QuadGraph::m_quad_graph = NULL;
|
||||
* \param graph_file_name Name of the file describing the actual graph
|
||||
*/
|
||||
QuadGraph::QuadGraph(const std::string &quad_file_name,
|
||||
const std::string graph_file_name)
|
||||
const std::string graph_file_name,
|
||||
const bool reverse) : m_reverse(reverse)
|
||||
{
|
||||
m_node = NULL;
|
||||
m_mesh = NULL;
|
||||
m_mesh_buffer = NULL;
|
||||
m_lap_length = 0;
|
||||
m_all_quads = new QuadSet(quad_file_name);
|
||||
QuadSet::create();
|
||||
QuadSet::get()->init(quad_file_name);
|
||||
m_quad_filename = quad_file_name;
|
||||
GraphNode::m_all_quads = m_all_quads;
|
||||
GraphNode::m_all_nodes = this;
|
||||
m_quad_graph = this;
|
||||
load(graph_file_name);
|
||||
} // QuadGraph
|
||||
|
||||
@ -60,7 +61,7 @@ QuadGraph::QuadGraph(const std::string &quad_file_name,
|
||||
/** Destructor, removes all nodes of the graph. */
|
||||
QuadGraph::~QuadGraph()
|
||||
{
|
||||
delete m_all_quads;
|
||||
QuadSet::destroy();
|
||||
for(unsigned int i=0; i<m_all_nodes.size(); i++) {
|
||||
delete m_all_nodes[i];
|
||||
}
|
||||
@ -68,6 +69,15 @@ QuadGraph::~QuadGraph()
|
||||
cleanupDebugMesh();
|
||||
} // ~QuadGraph
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void QuadGraph::addSuccessor(unsigned int from, unsigned int to) {
|
||||
if(m_reverse)
|
||||
m_all_nodes[to]->addSuccessor(from);
|
||||
else
|
||||
m_all_nodes[from]->addSuccessor(to);
|
||||
} // addSuccessor
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Loads a quad graph from a file.
|
||||
* \param filename Name of the file to load.
|
||||
@ -81,7 +91,7 @@ void QuadGraph::load(const std::string &filename)
|
||||
// No graph file exist, assume a default loop X -> X+1
|
||||
// i.e. each quad is part of the graph exactly once.
|
||||
// First create an empty graph node for each quad:
|
||||
for(unsigned int i=0; i<m_all_quads->getNumberOfQuads(); i++)
|
||||
for(unsigned int i=0; i<QuadSet::get()->getNumberOfQuads(); i++)
|
||||
m_all_nodes.push_back(new GraphNode(i, m_all_nodes.size()));
|
||||
// Then set the default loop:
|
||||
setDefaultSuccessors();
|
||||
@ -137,7 +147,8 @@ void QuadGraph::load(const std::string &filename)
|
||||
for(unsigned int i=from; i<=to; i++)
|
||||
{
|
||||
assert(i!=to ? i+1 : from <m_all_nodes.size());
|
||||
m_all_nodes[i]->addSuccessor(i!=to ? i+1 : from);
|
||||
addSuccessor(i,(i!=to ? i+1 : from));
|
||||
//~ m_all_nodes[i]->addSuccessor(i!=to ? i+1 : from);
|
||||
}
|
||||
}
|
||||
else if(xml_node->getName()=="edge-line")
|
||||
@ -148,7 +159,8 @@ void QuadGraph::load(const std::string &filename)
|
||||
xml_node->get("to", &to);
|
||||
for(unsigned int i=from; i<to; i++)
|
||||
{
|
||||
m_all_nodes[i]->addSuccessor(i+1);
|
||||
addSuccessor(i,i+1);
|
||||
//~ m_all_nodes[i]->addSuccessor(i+1);
|
||||
}
|
||||
}
|
||||
else if(xml_node->getName()=="edge")
|
||||
@ -158,7 +170,8 @@ void QuadGraph::load(const std::string &filename)
|
||||
xml_node->get("from", &from);
|
||||
xml_node->get("to", &to);
|
||||
assert(to<m_all_nodes.size());
|
||||
m_all_nodes[from]->addSuccessor(to);
|
||||
addSuccessor(from,to);
|
||||
//~ m_all_nodes[from]->addSuccessor(to);
|
||||
} // edge
|
||||
else
|
||||
{
|
||||
@ -169,70 +182,62 @@ void QuadGraph::load(const std::string &filename)
|
||||
}
|
||||
delete xml;
|
||||
|
||||
// Define the track length
|
||||
setDefaultSuccessors();
|
||||
computeDistanceFromStart(getStartNode(), 0.0f);
|
||||
|
||||
// Define the track length as the maximum at the end of a quad
|
||||
// (i.e. distance_from_start + length till successor 0).
|
||||
m_lap_length = -1;
|
||||
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()
|
||||
float l = m_all_nodes[i]->getDistanceFromStart()
|
||||
+ m_all_nodes[i]->getDistanceToSuccessor(0);
|
||||
break;
|
||||
}
|
||||
if(l > m_lap_length)
|
||||
m_lap_length = l;
|
||||
}
|
||||
setDefaultSuccessors();
|
||||
} // load
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Finds which checklines must be visited before driving on this quad
|
||||
* (useful for rescue)
|
||||
*/
|
||||
void QuadGraph::setChecklineRequirements(GraphNode* node, int latest_checkline)
|
||||
/** Returns the index of the first graph node (i.e. the graph node which
|
||||
* will trigger a new lap when a kart first enters it). This is always
|
||||
* 0 for normal direction (this is guaranteed by the track exporter),
|
||||
* but in reverse mode (where node 0 is actually the end of the track)
|
||||
* this is 0's successor.
|
||||
*/
|
||||
unsigned int QuadGraph::getStartNode() const
|
||||
{
|
||||
Track* t = World::getWorld()->getTrack();
|
||||
CheckManager* cm = t->getCheckManager();
|
||||
assert(cm != NULL);
|
||||
|
||||
// Find lapline
|
||||
if (latest_checkline == -1)
|
||||
{
|
||||
for (int i=0; i<cm->getCheckStructureCount(); i++)
|
||||
{
|
||||
CheckStructure* c = cm->getCheckStructure(i);
|
||||
|
||||
if (dynamic_cast<CheckLap*>(c) != NULL)
|
||||
{
|
||||
latest_checkline = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_reverse ? m_all_nodes[0]->getSuccessor(0)
|
||||
: 0;
|
||||
} // getStartNode
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void QuadGraph::computeChecklineRequirements()
|
||||
{
|
||||
computeChecklineRequirements(m_all_nodes[0],
|
||||
CheckManager::get()->getLapLineIndex());
|
||||
} // computeChecklineRequirements
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Finds which checklines must be visited before driving on this quad
|
||||
* (useful for rescue)
|
||||
*/
|
||||
void QuadGraph::computeChecklineRequirements(GraphNode* node,
|
||||
int latest_checkline)
|
||||
{
|
||||
for (unsigned int n=0; n<node->getNumberOfSuccessors(); n++)
|
||||
{
|
||||
const int succ_id = node->getSuccessor(n);
|
||||
|
||||
// warp-around
|
||||
if (succ_id == 0) break;
|
||||
|
||||
int new_latest_checkline = latest_checkline;
|
||||
|
||||
GraphNode* succ = m_all_nodes[succ_id];
|
||||
for (int i=0; i<cm->getCheckStructureCount(); i++)
|
||||
{
|
||||
CheckStructure* c = cm->getCheckStructure(i);
|
||||
|
||||
// skip lapline
|
||||
if (dynamic_cast<CheckLap*>(c) != NULL) continue;
|
||||
|
||||
if (c->isTriggered(node->getCenter(), succ->getCenter(), 0 /* kart id */))
|
||||
{
|
||||
new_latest_checkline = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GraphNode* succ = m_all_nodes[succ_id];
|
||||
int new_latest_checkline =
|
||||
CheckManager::get()->getChecklineTriggering(node->getCenter(),
|
||||
succ->getCenter() );
|
||||
if(new_latest_checkline==-1)
|
||||
new_latest_checkline = latest_checkline;
|
||||
|
||||
/*
|
||||
printf("Quad %i : checkline %i\n", succ_id, new_latest_checkline);
|
||||
|
||||
@ -246,9 +251,9 @@ void QuadGraph::setChecklineRequirements(GraphNode* node, int latest_checkline)
|
||||
if (new_latest_checkline != -1)
|
||||
succ->setChecklineRequirements(new_latest_checkline);
|
||||
|
||||
setChecklineRequirements(succ, new_latest_checkline);
|
||||
computeChecklineRequirements(succ, new_latest_checkline);
|
||||
}
|
||||
}
|
||||
} // computeChecklineRequirements
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function defines the "path-to-nodes" for each graph node that has
|
||||
@ -280,7 +285,8 @@ void QuadGraph::setDefaultSuccessors()
|
||||
{
|
||||
for(unsigned int i=0; i<m_all_nodes.size(); i++) {
|
||||
if(m_all_nodes[i]->getNumberOfSuccessors()==0) {
|
||||
m_all_nodes[i]->addSuccessor(i+1>=m_all_nodes.size() ? 0 : i+1);
|
||||
addSuccessor(i,i+1>=m_all_nodes.size() ? 0 : i+1);
|
||||
//~ m_all_nodes[i]->addSuccessor(i+1>=m_all_nodes.size() ? 0 : i+1);
|
||||
} // if size==0
|
||||
} // for i<m_allNodes.size()
|
||||
} // setDefaultSuccessors
|
||||
@ -313,8 +319,9 @@ void QuadGraph::setDefaultStartPositions(AlignedArray<btTransform>
|
||||
float sidewards_distance,
|
||||
float upwards_distance) const
|
||||
{
|
||||
// Node 0 is always the node on which the start line is.
|
||||
int current_node = getNode(0).getPredecessor();
|
||||
// We start just before the start node (which will trigger lap
|
||||
// counting when reached).
|
||||
int current_node = m_all_nodes[getStartNode()]->getPredecessor();
|
||||
|
||||
float distance_from_start = 0.1f+forwards_distance;
|
||||
|
||||
@ -432,7 +439,7 @@ void QuadGraph::createMesh(bool show_invisible,
|
||||
ind[6*i+4] = 4*i+2;
|
||||
ind[6*i+5] = 4*i+3;
|
||||
i++;
|
||||
} // for i=1; i<m_all_quads
|
||||
} // for i=1; i<QuadSet::get()
|
||||
|
||||
m_mesh_buffer->append(new_v, n*4, ind, n*6);
|
||||
|
||||
@ -446,7 +453,7 @@ void QuadGraph::createMesh(bool show_invisible,
|
||||
// Now scale the length (distance between vertix 0 and 3
|
||||
// and between 1 and 2) to be 'length':
|
||||
Vec3 bb_min, bb_max;
|
||||
m_all_quads->getBoundingBox(&bb_min, &bb_max);
|
||||
QuadSet::get()->getBoundingBox(&bb_min, &bb_max);
|
||||
// Length of the lap line about 3% of the 'height'
|
||||
// of the track.
|
||||
const float length=(bb_max.getZ()-bb_min.getZ())*0.03f;
|
||||
@ -559,7 +566,57 @@ void QuadGraph::getSuccessors(int node_number,
|
||||
} // getSuccessors
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Increases
|
||||
/** Recursively determines the distance the beginning (lower end) of the quads
|
||||
* have from the start of the track.
|
||||
* \param node The node index for which to set the distance from start.
|
||||
* \param new_distance The new distance for the specified graph node.
|
||||
*/
|
||||
void QuadGraph::computeDistanceFromStart(unsigned int node, float new_distance)
|
||||
{
|
||||
GraphNode *gn = m_all_nodes[node];
|
||||
float current_distance = gn->getDistanceFromStart();
|
||||
|
||||
// If this node already has a distance defined, check if the new distance
|
||||
// is longer, and if so adjust all following nodes. Without this the
|
||||
// length of the track (as taken by the distance from start of the last
|
||||
// node) could be smaller than some of the paths. This can result in
|
||||
// incorrect results for the arrival time estimation of the AI karts.
|
||||
// See trac #354 for details.
|
||||
// Then there is no need to test/adjust any more nodes.
|
||||
if(current_distance>=0)
|
||||
{
|
||||
if(current_distance<new_distance)
|
||||
{
|
||||
float delta = new_distance - current_distance;
|
||||
updateDistancesForAllSuccessors(gn->getIndex(), delta);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise this node has no distance defined yet. Set the new
|
||||
// distance, and recursively update all following nodes.
|
||||
gn->setDistanceFromStart(new_distance);
|
||||
|
||||
for(unsigned int i=0; i<gn->getNumberOfSuccessors(); i++)
|
||||
{
|
||||
GraphNode *gn_next = m_all_nodes[gn->getSuccessor(i)];
|
||||
// The start node (only node with distance 0) is reached again,
|
||||
// recursion can stop now
|
||||
if(gn_next->getDistanceFromStart()==0)
|
||||
continue;
|
||||
|
||||
computeDistanceFromStart(gn_next->getIndex(),
|
||||
new_distance + gn->getDistanceToSuccessor(i));
|
||||
} // for i
|
||||
} // computeDistanceFromStart
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Increases the distance from start for all nodes that are directly or
|
||||
* indirectly a successor of the given node. This code is used when two
|
||||
* branches merge together, but since the latest 'fork' indicates a longer
|
||||
* distance from start.
|
||||
* \param indx Index of the node for which to increase the distance.
|
||||
* \param delta Amount by which to increase the distance.
|
||||
*/
|
||||
void QuadGraph::updateDistancesForAllSuccessors(unsigned int indx, float delta)
|
||||
{
|
||||
@ -568,11 +625,9 @@ void QuadGraph::updateDistancesForAllSuccessors(unsigned int indx, float delta)
|
||||
for(unsigned int i=0; i<g.getNumberOfSuccessors(); i++)
|
||||
{
|
||||
GraphNode &g_next = getNode(g.getSuccessor(i));
|
||||
// If we reach the beginning of the graph (usually node with index 0,
|
||||
// but just in case also test for nodes with distance 0), all nodes
|
||||
// are updated, so no need to recurse any further.
|
||||
if(g_next.getIndex()==0 ||
|
||||
g_next.getDistanceFromStart()==0)
|
||||
// Stop when we reach the start node, i.e. the only node with a
|
||||
// distance of 0
|
||||
if(g_next.getDistanceFromStart()==0)
|
||||
continue;
|
||||
|
||||
// Only increase the distance from start of a successor node, if
|
||||
@ -778,7 +833,7 @@ video::ITexture *QuadGraph::makeMiniMap(const core::dimension2du &dimension,
|
||||
// ---------------
|
||||
scene::ICameraSceneNode *camera = irr_driver->addCameraSceneNode();
|
||||
Vec3 bb_min, bb_max;
|
||||
m_all_quads->getBoundingBox(&bb_min, &bb_max);
|
||||
QuadSet::get()->getBoundingBox(&bb_min, &bb_max);
|
||||
Vec3 center = (bb_max+bb_min)*0.5f;
|
||||
|
||||
float dx = bb_max.getX()-bb_min.getX();
|
||||
|
@ -56,8 +56,6 @@ private:
|
||||
|
||||
/** The actual graph data structure. */
|
||||
std::vector<GraphNode*> m_all_nodes;
|
||||
/** The set of all quads. */
|
||||
QuadSet *m_all_quads;
|
||||
/** For debug mode only: the node of the debug mesh. */
|
||||
scene::ISceneNode *m_node;
|
||||
/** For debug only: the mesh of the debug mesh. */
|
||||
@ -76,16 +74,23 @@ private:
|
||||
|
||||
/** Stores the filename - just used for error messages. */
|
||||
std::string m_quad_filename;
|
||||
|
||||
/** Wether the graph should be reverted or not */
|
||||
bool m_reverse;
|
||||
|
||||
void setDefaultSuccessors();
|
||||
void setChecklineRequirements(GraphNode* node, int latest_checkline);
|
||||
void computeChecklineRequirements(GraphNode* node, int latest_checkline);
|
||||
|
||||
void addSuccessor(unsigned int from, unsigned int to);
|
||||
void load (const std::string &filename);
|
||||
void computeDistanceFromStart(unsigned int start_node, float distance);
|
||||
void createMesh(bool show_invisible=true,
|
||||
const video::SColor *track_color=NULL,
|
||||
const video::SColor *lap_color=NULL);
|
||||
unsigned int getStartNode() const;
|
||||
QuadGraph (const std::string &quad_file_name,
|
||||
const std::string graph_file_name);
|
||||
const std::string graph_file_name,
|
||||
const bool reverse);
|
||||
~QuadGraph ();
|
||||
public:
|
||||
static const int UNKNOWN_SECTOR;
|
||||
@ -116,7 +121,8 @@ public:
|
||||
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
|
||||
void updateDistancesForAllSuccessors(unsigned int indx, float delta);
|
||||
void setupPaths();
|
||||
// ----------------------------------------------------------------------
|
||||
void computeChecklineRequirements();
|
||||
// ----------------------------------------------------------------------
|
||||
/** Returns the one instance of this object. It is possible that there
|
||||
* is no instance created (e.g. in battle mode, since it doesn't have
|
||||
* a quad graph), so we don't assert that an instance exist, and we
|
||||
@ -125,10 +131,13 @@ public:
|
||||
// ----------------------------------------------------------------------
|
||||
/** Creates a QuadGraph instance. */
|
||||
static void create(const std::string &quad_file_name,
|
||||
const std::string graph_file_name)
|
||||
const std::string graph_file_name,
|
||||
const bool reverse)
|
||||
{
|
||||
assert(m_quad_graph==NULL);
|
||||
m_quad_graph = new QuadGraph(quad_file_name, graph_file_name);
|
||||
// assignment to m_quad_graph is done in the constructor, since
|
||||
// functions called from the constructor need it to be defined.
|
||||
new QuadGraph(quad_file_name, graph_file_name, reverse);
|
||||
} // create
|
||||
// ----------------------------------------------------------------------
|
||||
/** Cleans up the quad graph. It is possible that this function is called
|
||||
@ -161,7 +170,7 @@ public:
|
||||
// ----------------------------------------------------------------------
|
||||
/** Returns the quad that belongs to a graph node. */
|
||||
const Quad& getQuadOfNode(unsigned int j) const
|
||||
{ return m_all_quads->getQuad(m_all_nodes[j]->getIndex()); }
|
||||
{ return QuadSet::get()->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]; }
|
||||
@ -173,11 +182,8 @@ public:
|
||||
/** Returns the length of the main driveline. */
|
||||
float getLapLength() const {return m_lap_length; }
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void setChecklineRequirements()
|
||||
{
|
||||
setChecklineRequirements(m_all_nodes[0], -1);
|
||||
}
|
||||
/** Returns true if the graph is to be reversed. */
|
||||
bool isReverse() const {return m_reverse; }
|
||||
|
||||
}; // QuadGraph
|
||||
|
||||
|
@ -19,16 +19,20 @@
|
||||
#include "tracks/quad_set.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "io/file_manager.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
|
||||
/** Constructor, loads the quad set from a file.
|
||||
* \param filename filename to load.
|
||||
QuadSet *QuadSet::m_quad_set = NULL;
|
||||
|
||||
/** Constructor, loads the quad set from a file. Assigns a pointer
|
||||
* to this instance to m_quad_set, so that it can be accessed using get().
|
||||
*/
|
||||
QuadSet::QuadSet(const std::string& filename) {
|
||||
load(filename);
|
||||
QuadSet::QuadSet()
|
||||
{
|
||||
m_quad_set = this;
|
||||
} // QuadSet
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -41,9 +45,10 @@ QuadSet::~QuadSet()
|
||||
delete m_all_quads[i];
|
||||
}
|
||||
m_all_quads.clear();
|
||||
m_quad_set = NULL;
|
||||
} // ~QuadSet
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------}
|
||||
/** This function interprets a point specification as an attribute in the
|
||||
xml quadset file. It understands two different specifications:
|
||||
p1="n:p" : get point p from square n (n, p integers)
|
||||
@ -69,7 +74,10 @@ void QuadSet::getPoint(const XMLNode *xml, const std::string &attribute_name,
|
||||
|
||||
} // getPoint
|
||||
// -----------------------------------------------------------------------------
|
||||
void QuadSet::load(const std::string &filename)
|
||||
/** Loads the set of all quads from the speciified filename.
|
||||
* \param filename The absolute filename to load the quad file from.
|
||||
*/
|
||||
void QuadSet::init(const std::string &filename)
|
||||
{
|
||||
m_min = Vec3( 99999, 99999, 99999);
|
||||
m_max = Vec3(-99999, -99999, -99999);
|
||||
|
@ -36,29 +36,54 @@ private:
|
||||
/** The 2d bounding box, used for hashing. */
|
||||
Vec3 m_min;
|
||||
Vec3 m_max;
|
||||
|
||||
/** The list of all quads. */
|
||||
std::vector<Quad*> m_all_quads;
|
||||
void load (const std::string &filename);
|
||||
|
||||
/** Pointer to the one instance of a quad set. */
|
||||
static QuadSet *m_quad_set;
|
||||
|
||||
void getPoint(const XMLNode *xml, const std::string &attribute_name,
|
||||
Vec3 *result) const;
|
||||
QuadSet();
|
||||
~QuadSet();
|
||||
|
||||
public:
|
||||
static const int QUAD_NONE=-1;
|
||||
|
||||
QuadSet (const std::string& filename);
|
||||
~QuadSet ();
|
||||
int getCurrentQuad(const Vec3& p, int oldQuad) const;
|
||||
void init (const std::string &filename);
|
||||
// ------------------------------------------------------------------------
|
||||
/** Creates one instance of the quad set. */
|
||||
static void create()
|
||||
{
|
||||
assert(m_quad_set==NULL);
|
||||
m_quad_set = new QuadSet();
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Destroys the one instance of a quad set. */
|
||||
static void destroy()
|
||||
{
|
||||
delete m_quad_set; m_quad_set = NULL;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Static member function to access the QuadSet instance. */
|
||||
static QuadSet *get() { return m_quad_set; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the quad with a given index number. */
|
||||
const Quad& getQuad(int n) const {return *(m_all_quads[n]); }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Return the minimum and maximum coordinates of this quad set. */
|
||||
void getBoundingBox(Vec3 *min, Vec3 *max)
|
||||
{ *min=m_min; *max=m_max; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the number of quads. */
|
||||
unsigned int getNumberOfQuads() const
|
||||
{return (unsigned int)m_all_quads.size(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the center of quad n. */
|
||||
const Vec3& getCenterOfQuad(int n) const
|
||||
{return m_all_quads[n]->getCenter(); }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the n-th. quad. */
|
||||
const Quad& getQuad(int n) {return *(m_all_quads[n]); }
|
||||
}; // QuadSet
|
||||
|
@ -86,11 +86,11 @@ Track::Track(const std::string &filename)
|
||||
m_track_mesh = NULL;
|
||||
m_gfx_effect_mesh = NULL;
|
||||
m_internal = false;
|
||||
m_reverse_available = true;
|
||||
m_all_nodes.clear();
|
||||
m_all_cached_meshes.clear();
|
||||
m_is_arena = false;
|
||||
m_camera_far = 1000.0f;
|
||||
m_check_manager = NULL;
|
||||
m_mini_map = NULL;
|
||||
m_sky_particles = NULL;
|
||||
m_sky_dx = 0.05f;
|
||||
@ -120,8 +120,7 @@ Track::~Track()
|
||||
void Track::reset()
|
||||
{
|
||||
m_ambient_color = m_default_ambient_color;
|
||||
if(m_check_manager)
|
||||
m_check_manager->reset(*this);
|
||||
CheckManager::get()->reset(*this);
|
||||
item_manager->reset();
|
||||
m_track_object_manager->reset();
|
||||
} // reset
|
||||
@ -151,11 +150,7 @@ void Track::cleanup()
|
||||
|
||||
m_all_emitters.clearAndDeleteAll();
|
||||
|
||||
if(m_check_manager)
|
||||
{
|
||||
delete m_check_manager;
|
||||
m_check_manager=NULL;
|
||||
}
|
||||
CheckManager::destroy();
|
||||
|
||||
delete m_track_object_manager;
|
||||
m_track_object_manager = NULL;
|
||||
@ -204,7 +199,7 @@ void Track::cleanup()
|
||||
m_detached_cached_meshes.clear();
|
||||
|
||||
QuadGraph::destroy();
|
||||
if(m_check_manager) delete m_check_manager;
|
||||
|
||||
if(m_mini_map)
|
||||
{
|
||||
assert(m_mini_map->getReferenceCount()==1);
|
||||
@ -306,6 +301,7 @@ void Track::loadTrackInfo()
|
||||
root->get("arena", &m_is_arena);
|
||||
root->get("groups", &m_groups);
|
||||
root->get("internal", &m_internal);
|
||||
root->get("reverse", &m_reverse_available);
|
||||
|
||||
for(unsigned int i=0; i<root->getNumNodes(); i++)
|
||||
{
|
||||
@ -392,10 +388,11 @@ void Track::startMusic() const
|
||||
/** Loads the quad graph, i.e. the definition of all quads, and the way
|
||||
* they are connected to each other.
|
||||
*/
|
||||
void Track::loadQuadGraph(unsigned int mode_id)
|
||||
void Track::loadQuadGraph(unsigned int mode_id, const bool reverse)
|
||||
{
|
||||
QuadGraph::create(m_root+"/"+m_all_modes[mode_id].m_quad_name,
|
||||
m_root+"/"+m_all_modes[mode_id].m_graph_name);
|
||||
m_root+"/"+m_all_modes[mode_id].m_graph_name,
|
||||
reverse);
|
||||
|
||||
QuadGraph::get()->setupPaths();
|
||||
#ifdef DEBUG
|
||||
@ -1070,8 +1067,7 @@ void Track::update(float dt)
|
||||
{
|
||||
m_animated_textures[i]->update(dt);
|
||||
}
|
||||
if(m_check_manager)
|
||||
m_check_manager->update(dt);
|
||||
CheckManager::get()->update(dt);
|
||||
item_manager->update(dt);
|
||||
|
||||
} // update
|
||||
@ -1164,8 +1160,14 @@ void Track::createWater(const XMLNode &node)
|
||||
* scene, quad, and graph file to load.
|
||||
*/
|
||||
|
||||
void Track::loadTrackModel(World* parent, unsigned int mode_id)
|
||||
void Track::loadTrackModel(World* parent, bool reverse_track,
|
||||
unsigned int mode_id )
|
||||
{
|
||||
if(!m_reverse_available)
|
||||
{
|
||||
reverse_track = false;
|
||||
}
|
||||
CheckManager::create();
|
||||
assert(m_all_cached_meshes.size()==0);
|
||||
if(UserConfigParams::logMemory())
|
||||
{
|
||||
@ -1229,7 +1231,7 @@ void Track::loadTrackModel(World* parent, unsigned int mode_id)
|
||||
// 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.
|
||||
if (!m_is_arena) loadQuadGraph(mode_id);
|
||||
if (!m_is_arena) loadQuadGraph(mode_id, reverse_track);
|
||||
|
||||
// Set the default start positions. Node that later the default
|
||||
// positions can still be overwritten.
|
||||
@ -1330,7 +1332,7 @@ void Track::loadTrackModel(World* parent, unsigned int mode_id)
|
||||
}
|
||||
else if(name=="checks")
|
||||
{
|
||||
m_check_manager = new CheckManager(*node, this);
|
||||
CheckManager::get()->load(*node);
|
||||
}
|
||||
else if (name=="particle-emitter")
|
||||
{
|
||||
@ -1564,7 +1566,8 @@ void Track::loadTrackModel(World* parent, unsigned int mode_id)
|
||||
|
||||
// Only print warning if not in battle mode, since battle tracks don't have
|
||||
// any quads or check lines.
|
||||
if(!m_check_manager && race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES)
|
||||
if(CheckManager::get()->getCheckStructureCount()==0 &&
|
||||
race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES)
|
||||
{
|
||||
printf("WARNING: no check lines found in track '%s'.\n",
|
||||
m_ident.c_str());
|
||||
@ -1577,9 +1580,9 @@ void Track::loadTrackModel(World* parent, unsigned int mode_id)
|
||||
irr_driver->getSceneManager()->getMeshCache()->getMeshCount(),
|
||||
irr_driver->getVideoDriver()->getTextureCount());
|
||||
|
||||
if (World::getWorld()->computeChecklineRequirements())
|
||||
if (World::getWorld()->useChecklineRequirements())
|
||||
{
|
||||
QuadGraph::get()->setChecklineRequirements();
|
||||
QuadGraph::get()->computeChecklineRequirements();
|
||||
}
|
||||
} // loadTrackModel
|
||||
|
||||
@ -1858,8 +1861,8 @@ std::vector< std::vector<float> > Track::buildHeightMap()
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
core::vector3df Track::getSunRotation()
|
||||
/** Returns the rotation of the sun. */
|
||||
const core::vector3df& Track::getSunRotation()
|
||||
{
|
||||
return m_sun->getRotation();
|
||||
}
|
||||
|
@ -185,6 +185,9 @@ private:
|
||||
* in the track seelction screen
|
||||
*/
|
||||
bool m_internal;
|
||||
|
||||
/** Whether this track should be available in reverse version */
|
||||
bool m_reverse_available;
|
||||
|
||||
/** The type of sky to be used for the track. */
|
||||
enum {SKY_NONE, SKY_BOX,
|
||||
@ -282,13 +285,10 @@ private:
|
||||
/** List of all bezier curves in the track - for e.g. camera, ... */
|
||||
std::vector<BezierCurve*> m_all_curves;
|
||||
|
||||
/** Checkline manager. */
|
||||
CheckManager *m_check_manager;
|
||||
|
||||
void loadTrackInfo();
|
||||
void itemCommand(const Vec3 &xyz, Item::ItemType item_type,
|
||||
bool drop);
|
||||
void loadQuadGraph(unsigned int mode_id);
|
||||
void loadQuadGraph(unsigned int mode_id, const bool reverse);
|
||||
void convertTrackToBullet(scene::ISceneNode *node);
|
||||
bool loadMainTrack(const XMLNode &node);
|
||||
void createWater(const XMLNode &node);
|
||||
@ -300,6 +300,8 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
bool reverseAvailable() { return m_reverse_available; }
|
||||
|
||||
static const float NOHIT;
|
||||
|
||||
Track (const std::string &filename);
|
||||
@ -313,7 +315,7 @@ public:
|
||||
void reset();
|
||||
void adjustForFog(scene::ISceneNode *node);
|
||||
void adjustForFog(scene::IMesh* mesh, scene::ISceneNode* parent_scene_node);
|
||||
|
||||
const core::vector3df& getSunRotation();
|
||||
/** Sets the current ambient color for a kart with index k. */
|
||||
void setAmbientColor(const video::SColor &color,
|
||||
unsigned int k);
|
||||
@ -327,7 +329,9 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
bool isArena () const { return m_is_arena; }
|
||||
// ------------------------------------------------------------------------
|
||||
void loadTrackModel (World* parent, unsigned int mode_id=0);
|
||||
void loadTrackModel (World* parent,
|
||||
bool reverse_track = false,
|
||||
unsigned int mode_id=0);
|
||||
// ------------------------------------------------------------------------
|
||||
void addMusic (MusicInformation* mi)
|
||||
{m_music.push_back(mi); }
|
||||
@ -429,17 +433,13 @@ public:
|
||||
ParticleKind* getSkyParticles () { return m_sky_particles; }
|
||||
// ------------------------------------------------------------------------
|
||||
bool isFogEnabled() const { return m_use_fog; }
|
||||
|
||||
CheckManager* getCheckManager() { return m_check_manager; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Whether this is an "internal" track. If so it won't be offered
|
||||
* in the track seelction screen
|
||||
*/
|
||||
* in the track seelction screen. */
|
||||
bool isInternal() const { return m_internal; }
|
||||
|
||||
core::vector3df getSunRotation();
|
||||
|
||||
TrackObjectManager* getTrackObjectManager() { return m_track_object_manager; }
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
TrackObjectManager* getTrackObjectManager() {return m_track_object_manager;}
|
||||
|
||||
/** Get list of challenges placed on that world. Works only for overworld. */
|
||||
const std::vector<OverworldChallenge>& getChallengeList() const
|
||||
|
Loading…
Reference in New Issue
Block a user