Rename QuadGraph to DriveGraph, make it use the new Graph interface

This commit is contained in:
Benau 2016-09-17 14:30:28 +08:00
parent 606a5401d3
commit eeac5668d9
36 changed files with 641 additions and 1447 deletions

View File

@ -20,7 +20,7 @@
#include "karts/abstract_kart.hpp" #include "karts/abstract_kart.hpp"
#include "karts/kart_properties.hpp" #include "karts/kart_properties.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_graph.hpp"
#include "ICameraSceneNode.h" #include "ICameraSceneNode.h"
@ -62,7 +62,7 @@ void CameraEnd::readEndCamera(const XMLNode &root)
unsigned int index = i; unsigned int index = i;
// In reverse mode, reverse the order in which the // In reverse mode, reverse the order in which the
// end cameras are read. // end cameras are read.
if(QuadGraph::get()->isReverse()) if(DriveGraph::get()->isReverse())
index = root.getNumNodes() - 1 - i; index = root.getNumNodes() - 1 - i;
const XMLNode *node = root.getNode(index); const XMLNode *node = root.getNode(index);
EndCameraInformation eci; EndCameraInformation eci;

View File

@ -26,8 +26,6 @@
#include "karts/abstract_kart.hpp" #include "karts/abstract_kart.hpp"
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "utils/random_generator.hpp" #include "utils/random_generator.hpp"
#include "tracks/graph_node.hpp"
#include "tracks/quad_graph.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done #include "utils/log.hpp" //TODO: remove after debugging is done

View File

@ -26,8 +26,8 @@
#include "modes/three_strikes_battle.hpp" #include "modes/three_strikes_battle.hpp"
#include "modes/world.hpp" #include "modes/world.hpp"
#include "tracks/arena_graph.hpp" #include "tracks/arena_graph.hpp"
#include "tracks/graph_node.hpp" #include "tracks/drive_graph.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_node.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
#include "utils/vec3.hpp" #include "utils/vec3.hpp"
@ -145,15 +145,15 @@ void Item::initItem(ItemType type, const Vec3 &xyz)
{ {
Graph::get()->findRoadSector(xyz, &m_graph_node); Graph::get()->findRoadSector(xyz, &m_graph_node);
} }
if (Graph::get() && !ArenaGraph::get()) // Todo replace with driveline graph if (DriveGraph::get() && m_graph_node != Graph::UNKNOWN_SECTOR)
{ {
// Item is on quad graph. Pre-compute the distance from center // Item is on drive graph. Pre-compute the distance from center
// of this item, which is used by the AI (mostly for avoiding items) // of this item, which is used by the AI (mostly for avoiding items)
Vec3 distances; Vec3 distances;
QuadGraph::get()->spatialToTrack(&distances, m_xyz, m_graph_node); DriveGraph::get()->spatialToTrack(&distances, m_xyz, m_graph_node);
m_distance_from_center = distances.getX(); m_distance_from_center = distances.getX();
const GraphNode* gn = QuadGraph::get()->getNode(m_graph_node); const DriveNode* dn = DriveGraph::get()->getNode(m_graph_node);
const Vec3& right = gn->getRightUnitVector(); const Vec3& right = dn->getRightUnitVector();
// Give it 10% more space, since the kart will not always come // Give it 10% more space, since the kart will not always come
// parallel to the drive line. // parallel to the drive line.
Vec3 delta = right * sqrt(m_distance_2) * 1.3f; Vec3 delta = right * sqrt(m_distance_2) * 1.3f;

View File

@ -225,7 +225,7 @@ void ItemManager::insertItem(Item *item)
if(m_items_in_quads) if(m_items_in_quads)
{ {
int graph_node = item->getGraphNode(); int graph_node = item->getGraphNode();
// If the item is on the driveline, store it at the appropriate index // If the item is on the graph, store it at the appropriate index
if(graph_node > -1) if(graph_node > -1)
{ {
(*m_items_in_quads)[graph_node].push_back(item); (*m_items_in_quads)[graph_node].push_back(item);

View File

@ -82,7 +82,7 @@ private:
/** Stores which items are on which quad. m_items_in_quads[#quads] /** Stores which items are on which quad. m_items_in_quads[#quads]
* contains all items that are not on a quad. Note that this * contains all items that are not on a quad. Note that this
* field is undefined if no QuadGraph exist, e.g. in battle mode. */ * field is undefined if no Graph exist, e.g. arena without navmesh. */
std::vector< AllItemTypes > *m_items_in_quads; std::vector< AllItemTypes > *m_items_in_quads;
/** What item this item is switched to. */ /** What item this item is switched to. */

View File

@ -29,8 +29,8 @@
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "physics/btKart.hpp" #include "physics/btKart.hpp"
#include "physics/triangle_mesh.hpp" #include "physics/triangle_mesh.hpp"
#include "tracks/graph_node.hpp" #include "tracks/drive_graph.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_node.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/log.hpp" //TODO: remove after debugging is done #include "utils/log.hpp" //TODO: remove after debugging is done
@ -100,7 +100,7 @@ RubberBall::RubberBall(AbstractKart *kart)
// initialises the current graph node // initialises the current graph node
TrackSector::update(getXYZ()); TrackSector::update(getXYZ());
const Vec3& normal = const Vec3& normal =
QuadGraph::get()->getNode(getCurrentGraphNode())->getNormal(); DriveGraph::get()->getNode(getCurrentGraphNode())->getNormal();
TerrainInfo::update(getXYZ(), -normal); TerrainInfo::update(getXYZ(), -normal);
initializeControlPoints(m_owner->getXYZ()); initializeControlPoints(m_owner->getXYZ());
@ -136,7 +136,7 @@ void RubberBall::initializeControlPoints(const Vec3 &xyz)
// left or right when firing the ball off track. // left or right when firing the ball off track.
getNextControlPoint(); getNextControlPoint();
m_control_points[2] = m_control_points[2] =
QuadGraph::get()->getNode(m_last_aimed_graph_node)->getCenter(); DriveGraph::get()->getNode(m_last_aimed_graph_node)->getCenter();
// This updates m_last_aimed_graph_node, and sets m_control_points[3] // This updates m_last_aimed_graph_node, and sets m_control_points[3]
getNextControlPoint(); getNextControlPoint();
@ -201,12 +201,12 @@ unsigned int RubberBall::getSuccessorToHitTarget(unsigned int node_index,
unsigned int sect = unsigned int sect =
lin_world->getSectorForKart(m_target); lin_world->getSectorForKart(m_target);
succ = QuadGraph::get()->getNode(node_index)->getSuccessorToReach(sect); succ = DriveGraph::get()->getNode(node_index)->getSuccessorToReach(sect);
if(dist) if(dist)
*dist += QuadGraph::get()->getNode(node_index) *dist += DriveGraph::get()->getNode(node_index)
->getDistanceToSuccessor(succ); ->getDistanceToSuccessor(succ);
return QuadGraph::get()->getNode(node_index)->getSuccessor(succ); return DriveGraph::get()->getNode(node_index)->getSuccessor(succ);
} // getSuccessorToHitTarget } // getSuccessorToHitTarget
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -224,21 +224,21 @@ void RubberBall::getNextControlPoint()
// spline between the control points. // spline between the control points.
float dist=0; float dist=0;
float f = QuadGraph::get()->getDistanceFromStart(m_last_aimed_graph_node); float f = DriveGraph::get()->getDistanceFromStart(m_last_aimed_graph_node);
int next = getSuccessorToHitTarget(m_last_aimed_graph_node, &dist); int next = getSuccessorToHitTarget(m_last_aimed_graph_node, &dist);
float d = QuadGraph::get()->getDistanceFromStart(next)-f; float d = DriveGraph::get()->getDistanceFromStart(next)-f;
while(d<m_st_min_interpolation_distance && d>=0) while(d<m_st_min_interpolation_distance && d>=0)
{ {
next = getSuccessorToHitTarget(next, &dist); next = getSuccessorToHitTarget(next, &dist);
d = QuadGraph::get()->getDistanceFromStart(next)-f; d = DriveGraph::get()->getDistanceFromStart(next)-f;
} }
m_last_aimed_graph_node = next; m_last_aimed_graph_node = next;
m_length_cp_2_3 = dist; m_length_cp_2_3 = dist;
const GraphNode* gn = const DriveNode* dn =
QuadGraph::get()->getNode(m_last_aimed_graph_node); DriveGraph::get()->getNode(m_last_aimed_graph_node);
m_control_points[3] = gn->getCenter(); m_control_points[3] = dn->getCenter();
} // getNextControlPoint } // getNextControlPoint
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -25,7 +25,6 @@
#include "tracks/track_sector.hpp" #include "tracks/track_sector.hpp"
class AbstractKart; class AbstractKart;
class QuadGraph;
class SFXBase; class SFXBase;
/** /**

View File

@ -25,7 +25,7 @@
#include "karts/kart_properties.hpp" #include "karts/kart_properties.hpp"
#include "karts/controller/ai_properties.hpp" #include "karts/controller/ai_properties.hpp"
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_graph.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
@ -37,7 +37,7 @@ I.e. the controller that takes over from a player (or AI) when the race is
finished. finished.
This base class defines some basic operations: This base class defines some basic operations:
- It takes care on which part of the QuadGraph the AI currently is. - It takes care on which part of the DriveGraph the AI currently is.
- It determines which path the AI should take (in case of shortcuts - It determines which path the AI should take (in case of shortcuts
or forks in the road). or forks in the road).
@ -139,14 +139,14 @@ void AIBaseLapController::newLap(int lap)
*/ */
void AIBaseLapController::computePath() void AIBaseLapController::computePath()
{ {
m_next_node_index.resize(QuadGraph::get()->getNumNodes()); m_next_node_index.resize(DriveGraph::get()->getNumNodes());
m_successor_index.resize(QuadGraph::get()->getNumNodes()); m_successor_index.resize(DriveGraph::get()->getNumNodes());
std::vector<unsigned int> next; std::vector<unsigned int> next;
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++) for(unsigned int i=0; i<DriveGraph::get()->getNumNodes(); i++)
{ {
next.clear(); next.clear();
// Get all successors the AI is allowed to take. // Get all successors the AI is allowed to take.
QuadGraph::get()->getSuccessors(i, next, /*for_ai*/true); DriveGraph::get()->getSuccessors(i, next, /*for_ai*/true);
// In case of short cuts hidden for the AI it can be that a node // 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 // might not have a successor (since the first and last edge of
// a hidden shortcut is ignored). Since in the case that the AI // a hidden shortcut is ignored). Since in the case that the AI
@ -154,7 +154,7 @@ void AIBaseLapController::computePath()
// allowed way to drive, it should still be able to drive, so add // allowed way to drive, it should still be able to drive, so add
// the non-AI successors of that node in this case. // the non-AI successors of that node in this case.
if(next.size()==0) if(next.size()==0)
QuadGraph::get()->getSuccessors(i, next, /*for_ai*/false); DriveGraph::get()->getSuccessors(i, next, /*for_ai*/false);
// For now pick one part on random, which is not adjusted during the // For now pick one part on random, which is not adjusted during the
// race. Long term statistics might be gathered to determine the // race. Long term statistics might be gathered to determine the
// best way, potentially depending on race position etc. // best way, potentially depending on race position etc.
@ -171,12 +171,12 @@ void AIBaseLapController::computePath()
// Now compute for each node in the graph the list of the next 'look_ahead' // Now compute for each node in the graph the list of the next 'look_ahead'
// graph nodes. This is the list of node that is tested in checkCrashes. // graph nodes. This is the list of node that is tested in checkCrashes.
// If the look_ahead is too big, the AI can skip loops (see // If the look_ahead is too big, the AI can skip loops (see
// QuadGraph::findRoadSector for details), if it's too short the AI won't // Graph::findRoadSector for details), if it's too short the AI won't
// find too good a driveline. Note that in general this list should // find too good a driveline. Note that in general this list should
// be computed recursively, but since the AI for now is using only // be computed recursively, but since the AI for now is using only
// (randomly picked) path this is fine // (randomly picked) path this is fine
m_all_look_aheads.resize(QuadGraph::get()->getNumNodes()); m_all_look_aheads.resize(DriveGraph::get()->getNumNodes());
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++) for(unsigned int i=0; i<DriveGraph::get()->getNumNodes(); i++)
{ {
std::vector<int> l; std::vector<int> l;
int current = i; int current = i;
@ -199,24 +199,24 @@ void AIBaseLapController::computePath()
void AIBaseLapController::update(float dt) void AIBaseLapController::update(float dt)
{ {
AIBaseController::update(dt); AIBaseController::update(dt);
if(QuadGraph::get()) if(DriveGraph::get())
{ {
// Update the current node: // Update the current node:
int old_node = m_track_node; int old_node = m_track_node;
if(m_track_node!=QuadGraph::UNKNOWN_SECTOR) if(m_track_node!=Graph::UNKNOWN_SECTOR)
{ {
QuadGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node, DriveGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node,
&m_all_look_aheads[m_track_node]); &m_all_look_aheads[m_track_node]);
} }
// If we can't find a proper place on the track, to a broader search // If we can't find a proper place on the track, to a broader search
// on off-track locations. // on off-track locations.
if(m_track_node==QuadGraph::UNKNOWN_SECTOR) if(m_track_node==Graph::UNKNOWN_SECTOR)
{ {
m_track_node = QuadGraph::get()->findOutOfRoadSector(m_kart->getXYZ()); m_track_node = DriveGraph::get()->findOutOfRoadSector(m_kart->getXYZ());
} }
// IF the AI is off track (or on a branch of the track it did not // IF the AI is off track (or on a branch of the track it did not
// select to be on), keep the old position. // select to be on), keep the old position.
if(m_track_node==QuadGraph::UNKNOWN_SECTOR || if(m_track_node==Graph::UNKNOWN_SECTOR ||
m_next_node_index[m_track_node]==-1) m_next_node_index[m_track_node]==-1)
m_track_node = old_node; m_track_node = old_node;
} }
@ -233,7 +233,7 @@ void AIBaseLapController::update(float dt)
unsigned int AIBaseLapController::getNextSector(unsigned int index) unsigned int AIBaseLapController::getNextSector(unsigned int index)
{ {
std::vector<unsigned int> successors; std::vector<unsigned int> successors;
QuadGraph::get()->getSuccessors(index, successors); DriveGraph::get()->getSuccessors(index, successors);
return successors[0]; return successors[0];
} // getNextSector } // getNextSector
@ -245,8 +245,8 @@ unsigned int AIBaseLapController::getNextSector(unsigned int index)
float AIBaseLapController::steerToAngle(const unsigned int sector, float AIBaseLapController::steerToAngle(const unsigned int sector,
const float add_angle) const float add_angle)
{ {
float angle = QuadGraph::get()->getAngleToNext(sector, float angle = DriveGraph::get()->getAngleToNext(sector,
getNextSector(sector)); getNextSector(sector));
//Desired angle minus current angle equals how many angles to turn //Desired angle minus current angle equals how many angles to turn
float steer_angle = angle - m_kart->getHeading(); float steer_angle = angle - m_kart->getHeading();

View File

@ -22,7 +22,6 @@
class AIProperties; class AIProperties;
class LinearWorld; class LinearWorld;
class QuadGraph;
class Track; class Track;
class Vec3; class Vec3;

View File

@ -45,8 +45,8 @@
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "race/race_manager.hpp" #include "race/race_manager.hpp"
#include "states_screens/race_result_gui.hpp" #include "states_screens/race_result_gui.hpp"
#include "tracks/graph_node.hpp" #include "tracks/drive_graph.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_node.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
@ -63,14 +63,14 @@ EndController::EndController(AbstractKart *kart,
// with a path that always picks the first branch (i.e. it follows // with a path that always picks the first branch (i.e. it follows
// the main driveline). // the main driveline).
std::vector<unsigned int> next; std::vector<unsigned int> next;
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++) for(unsigned int i=0; i<DriveGraph::get()->getNumNodes(); i++)
{ {
// 0 is always a valid successor - so even if the kart should end // 0 is always a valid successor - so even if the kart should end
// up by accident on a non-selected path, it will keep on working. // up by accident on a non-selected path, it will keep on working.
m_successor_index[i] = 0; m_successor_index[i] = 0;
next.clear(); next.clear();
QuadGraph::get()->getSuccessors(i, next); DriveGraph::get()->getSuccessors(i, next);
m_next_node_index[i] = next[0]; m_next_node_index[i] = next[0];
} }
@ -78,11 +78,11 @@ EndController::EndController(AbstractKart *kart,
// Now compute for each node in the graph the list of the next 'look_ahead' // Now compute for each node in the graph the list of the next 'look_ahead'
// graph nodes. This is the list of node that is tested in checkCrashes. // graph nodes. This is the list of node that is tested in checkCrashes.
// If the look_ahead is too big, the AI can skip loops (see // If the look_ahead is too big, the AI can skip loops (see
// QuadGraph::findRoadSector for details), if it's too short the AI won't // DriveGraph::findRoadSector for details), if it's too short the AI won't
// find too good a driveline. Note that in general this list should // find too good a driveline. Note that in general this list should
// be computed recursively, but since the AI for now is using only // be computed recursively, but since the AI for now is using only
// (randomly picked) path this is fine // (randomly picked) path this is fine
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++) for(unsigned int i=0; i<DriveGraph::get()->getNumNodes(); i++)
{ {
std::vector<int> l; std::vector<int> l;
int current = i; int current = i;
@ -95,7 +95,7 @@ EndController::EndController(AbstractKart *kart,
} }
} // if not battle mode } // if not battle mode
// Reset must be called after QuadGraph::get() etc. is set up // Reset must be called after DriveGraph::get() etc. is set up
reset(); reset();
m_max_handicap_accel = 1.0f; m_max_handicap_accel = 1.0f;
@ -130,18 +130,18 @@ void EndController::reset()
m_crash_time = 0.0f; m_crash_time = 0.0f;
m_time_since_stuck = 0.0f; m_time_since_stuck = 0.0f;
m_track_node = QuadGraph::UNKNOWN_SECTOR; m_track_node = Graph::UNKNOWN_SECTOR;
// In battle mode there is no quad graph, so nothing to do in this case // In battle mode there is no quad graph, so nothing to do in this case
if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES && if(race_manager->getMinorMode()!=RaceManager::MINOR_MODE_3_STRIKES &&
race_manager->getMinorMode()!=RaceManager::MINOR_MODE_SOCCER) race_manager->getMinorMode()!=RaceManager::MINOR_MODE_SOCCER)
{ {
QuadGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node); DriveGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node);
// Node that this can happen quite easily, e.g. an AI kart is // Node that this can happen quite easily, e.g. an AI kart is
// taken over by the end controller while it is off track. // taken over by the end controller while it is off track.
if(m_track_node==QuadGraph::UNKNOWN_SECTOR) if(m_track_node==Graph::UNKNOWN_SECTOR)
{ {
m_track_node = QuadGraph::get()->findOutOfRoadSector(m_kart->getXYZ()); m_track_node = DriveGraph::get()->findOutOfRoadSector(m_kart->getXYZ());
} }
} }
} // reset } // reset
@ -212,10 +212,10 @@ void EndController::handleSteering(float dt)
*/ */
//Reaction to being outside of the road //Reaction to being outside of the road
if( fabsf(m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() )) > if( fabsf(m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() )) >
0.5f* QuadGraph::get()->getNode(m_track_node)->getPathWidth()+0.5f ) 0.5f* DriveGraph::get()->getNode(m_track_node)->getPathWidth()+0.5f )
{ {
const int next = m_next_node_index[m_track_node]; const int next = m_next_node_index[m_track_node];
target_point = QuadGraph::get()->getNode(next)->getCenter(); target_point = DriveGraph::get()->getNode(next)->getCenter();
#ifdef AI_DEBUG #ifdef AI_DEBUG
Log::debug("end_controller.cpp", "- Outside of road: steer to center point."); Log::debug("end_controller.cpp", "- Outside of road: steer to center point.");
#endif #endif
@ -275,7 +275,7 @@ void EndController::findNonCrashingPoint(Vec3 *result)
target_sector = m_next_node_index[sector]; target_sector = m_next_node_index[sector];
//direction is a vector from our kart to the sectors we are testing //direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getNode(target_sector)->getCenter() direction = DriveGraph::get()->getNode(target_sector)->getCenter()
- m_kart->getXYZ(); - m_kart->getXYZ();
float len=direction.length(); float len=direction.length();
@ -293,16 +293,16 @@ void EndController::findNonCrashingPoint(Vec3 *result)
{ {
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i); step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord, DriveGraph::get()->spatialToTrack(&step_track_coord, step_coord,
sector ); sector );
distance = fabsf(step_track_coord[0]); distance = fabsf(step_track_coord[0]);
//If we are outside, the previous sector is what we are looking for //If we are outside, the previous sector is what we are looking for
if ( distance + m_kart_width * 0.5f if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode(sector)->getPathWidth()*0.5f ) > DriveGraph::get()->getNode(sector)->getPathWidth()*0.5f )
{ {
*result = QuadGraph::get()->getNode(sector)->getCenter(); *result = DriveGraph::get()->getNode(sector)->getCenter();
return; return;
} }
} }

View File

@ -25,7 +25,6 @@
class Camera; class Camera;
class LinearWorld; class LinearWorld;
class QuadGraph;
class Track; class Track;
class Vec3; class Vec3;

View File

@ -41,7 +41,7 @@
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "modes/profile_world.hpp" #include "modes/profile_world.hpp"
#include "race/race_manager.hpp" #include "race/race_manager.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_graph.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
@ -171,22 +171,22 @@ void SkiddingAI::reset()
m_distance_behind = 0.0f; m_distance_behind = 0.0f;
m_current_curve_radius = 0.0f; m_current_curve_radius = 0.0f;
m_curve_center = Vec3(0,0,0); m_curve_center = Vec3(0,0,0);
m_current_track_direction = GraphNode::DIR_STRAIGHT; m_current_track_direction = DriveNode::DIR_STRAIGHT;
m_item_to_collect = NULL; m_item_to_collect = NULL;
m_avoid_item_close = false; m_avoid_item_close = false;
m_skid_probability_state = SKID_PROBAB_NOT_YET; m_skid_probability_state = SKID_PROBAB_NOT_YET;
m_last_item_random = NULL; m_last_item_random = NULL;
AIBaseLapController::reset(); AIBaseLapController::reset();
m_track_node = QuadGraph::UNKNOWN_SECTOR; m_track_node = Graph::UNKNOWN_SECTOR;
QuadGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node); DriveGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node);
if(m_track_node==QuadGraph::UNKNOWN_SECTOR) if(m_track_node==Graph::UNKNOWN_SECTOR)
{ {
Log::error(getControllerName().c_str(), Log::error(getControllerName().c_str(),
"Invalid starting position for '%s' - not on track" "Invalid starting position for '%s' - not on track"
" - can be ignored.", " - can be ignored.",
m_kart->getIdent().c_str()); m_kart->getIdent().c_str());
m_track_node = QuadGraph::get()->findOutOfRoadSector(m_kart->getXYZ()); m_track_node = DriveGraph::get()->findOutOfRoadSector(m_kart->getXYZ());
} }
AIBaseLapController::reset(); AIBaseLapController::reset();
@ -414,7 +414,7 @@ void SkiddingAI::handleBraking()
// If the kart is not facing roughly in the direction of the track, brake // If the kart is not facing roughly in the direction of the track, brake
// so that it is easier for the kart to turn in the right direction. // so that it is easier for the kart to turn in the right direction.
if(m_current_track_direction==GraphNode::DIR_UNDEFINED && if(m_current_track_direction==DriveNode::DIR_UNDEFINED &&
m_kart->getSpeed() > MIN_SPEED) m_kart->getSpeed() > MIN_SPEED)
{ {
#ifdef DEBUG #ifdef DEBUG
@ -426,8 +426,8 @@ void SkiddingAI::handleBraking()
m_controls->m_brake = true; m_controls->m_brake = true;
return; return;
} }
if(m_current_track_direction==GraphNode::DIR_LEFT || if(m_current_track_direction==DriveNode::DIR_LEFT ||
m_current_track_direction==GraphNode::DIR_RIGHT ) m_current_track_direction==DriveNode::DIR_RIGHT )
{ {
float max_turn_speed = float max_turn_speed =
m_kart->getSpeedForTurnRadius(m_current_curve_radius); m_kart->getSpeedForTurnRadius(m_current_curve_radius);
@ -476,13 +476,13 @@ void SkiddingAI::handleSteering(float dt)
m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() ); m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() );
if( fabsf(side_dist) > if( fabsf(side_dist) >
0.5f* QuadGraph::get()->getNode(m_track_node)->getPathWidth()+0.5f ) 0.5f* DriveGraph::get()->getNode(m_track_node)->getPathWidth()+0.5f )
{ {
steer_angle = steerToPoint(QuadGraph::get()->getNode(next) steer_angle = steerToPoint(DriveGraph::get()->getNode(next)
->getCenter()); ->getCenter());
#ifdef AI_DEBUG #ifdef AI_DEBUG
m_debug_sphere[0]->setPosition(QuadGraph::get()->getNode(next) m_debug_sphere[0]->setPosition(DriveGraph::get()->getNode(next)
->getCenter().toIrrVector()); ->getCenter().toIrrVector());
Log::debug(getControllerName().c_str(), Log::debug(getControllerName().c_str(),
"Outside of road: steer to center point."); "Outside of road: steer to center point.");
@ -530,7 +530,7 @@ void SkiddingAI::handleSteering(float dt)
{ {
m_start_kart_crash_direction = 0; m_start_kart_crash_direction = 0;
Vec3 aim_point; Vec3 aim_point;
int last_node = QuadGraph::UNKNOWN_SECTOR; int last_node = Graph::UNKNOWN_SECTOR;
switch(m_point_selection_algorithm) switch(m_point_selection_algorithm)
{ {
@ -623,7 +623,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
Vec3 kart_aim_direction = *aim_point - m_kart->getXYZ(); Vec3 kart_aim_direction = *aim_point - m_kart->getXYZ();
// Make sure we have a valid last_node // Make sure we have a valid last_node
if(last_node==QuadGraph::UNKNOWN_SECTOR) if(last_node==Graph::UNKNOWN_SECTOR)
last_node = m_next_node_index[m_track_node]; last_node = m_next_node_index[m_track_node];
int node = m_track_node; int node = m_track_node;
@ -636,7 +636,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
const float max_item_lookahead_distance = 30.f; const float max_item_lookahead_distance = 30.f;
while(distance < max_item_lookahead_distance) while(distance < max_item_lookahead_distance)
{ {
int n_index= QuadGraph::get()->getNode(node)->getNodeIndex(); int n_index= DriveGraph::get()->getNode(node)->getIndex();
const std::vector<Item *> &items_ahead = const std::vector<Item *> &items_ahead =
ItemManager::get()->getItemsInQuads(n_index); ItemManager::get()->getItemsInQuads(n_index);
for(unsigned int i=0; i<items_ahead.size(); i++) for(unsigned int i=0; i<items_ahead.size(); i++)
@ -644,7 +644,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
evaluateItems(items_ahead[i], kart_aim_direction, evaluateItems(items_ahead[i], kart_aim_direction,
&items_to_avoid, &items_to_collect); &items_to_avoid, &items_to_collect);
} // for i<items_ahead; } // for i<items_ahead;
distance += QuadGraph::get()->getDistanceToNext(node, distance += DriveGraph::get()->getDistanceToNext(node,
m_successor_index[node]); m_successor_index[node]);
node = m_next_node_index[node]; node = m_next_node_index[node];
// Stop when we have reached the last quad // Stop when we have reached the last quad
@ -781,7 +781,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
// so that it can potentially become a permanent target. // so that it can potentially become a permanent target.
Vec3 xyz = item_to_collect->getXYZ(); Vec3 xyz = item_to_collect->getXYZ();
Vec3 item_direction = xyz - m_kart->getXYZ(); Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node) Vec3 plane_normal = DriveGraph::get()->getNode(m_track_node)
->getNormal(); ->getNormal();
float dist_to_plane = item_direction.dot(plane_normal); float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
@ -865,7 +865,7 @@ bool SkiddingAI::handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point)
// the kart is. The current quad provides a good estimate of the kart's plane. // the kart is. The current quad provides a good estimate of the kart's plane.
const Vec3 &xyz = m_item_to_collect->getXYZ(); const Vec3 &xyz = m_item_to_collect->getXYZ();
Vec3 item_direction = xyz - m_kart->getXYZ(); Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node)->getNormal(); Vec3 plane_normal = DriveGraph::get()->getNode(m_track_node)->getNormal();
float dist_to_plane = item_direction.dot(plane_normal); float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
@ -926,7 +926,7 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
// rightmost point - if so, nothing to do. // rightmost point - if so, nothing to do.
Vec3 left(items_to_avoid[index_left_most]->getXYZ()); Vec3 left(items_to_avoid[index_left_most]->getXYZ());
int node_index = items_to_avoid[index_left_most]->getGraphNode(); int node_index = items_to_avoid[index_left_most]->getGraphNode();
Vec3 normal = QuadGraph::get()->getNode(node_index)->getNormal(); Vec3 normal = DriveGraph::get()->getNode(node_index)->getNormal();
Vec3 p1 = line_to_target.start, Vec3 p1 = line_to_target.start,
p2 = line_to_target.getMiddle() + normal.toIrrVector(), p2 = line_to_target.getMiddle() + normal.toIrrVector(),
p3 = line_to_target.end; p3 = line_to_target.end;
@ -946,7 +946,7 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
{ {
Vec3 left(items_to_avoid[index_left_most]->getXYZ()); Vec3 left(items_to_avoid[index_left_most]->getXYZ());
int node_index = items_to_avoid[index_left_most]->getGraphNode(); int node_index = items_to_avoid[index_left_most]->getGraphNode();
Vec3 normal = QuadGraph::get()->getNode(node_index)->getNormal(); Vec3 normal = DriveGraph::get()->getNode(node_index)->getNormal();
Vec3 p1 = line_to_target.start, Vec3 p1 = line_to_target.start,
p2 = line_to_target.getMiddle() + normal.toIrrVector(), p2 = line_to_target.getMiddle() + normal.toIrrVector(),
p3 = line_to_target.end; p3 = line_to_target.end;
@ -1104,7 +1104,7 @@ void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction,
// the kart is. The current quad provides a good estimate of the kart's plane. // the kart is. The current quad provides a good estimate of the kart's plane.
const Vec3 &xyz = item->getXYZ(); const Vec3 &xyz = item->getXYZ();
Vec3 item_direction = xyz - m_kart->getXYZ(); Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node)->getNormal(); Vec3 plane_normal = DriveGraph::get()->getNode(m_track_node)->getNormal();
float dist_to_plane = item_direction.dot(plane_normal); float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
@ -1714,14 +1714,14 @@ void SkiddingAI::handleNitroAndZipper()
m_kart->getSpeed()>1.0f && m_kart->getSpeed()>1.0f &&
m_kart->getSpeedIncreaseTimeLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0) m_kart->getSpeedIncreaseTimeLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0)
{ {
GraphNode::DirectionType dir; DriveNode::DirectionType dir;
unsigned int last; unsigned int last;
const GraphNode* gn = QuadGraph::get()->getNode(m_track_node); const DriveNode* dn = DriveGraph::get()->getNode(m_track_node);
gn->getDirectionData(m_successor_index[m_track_node], &dir, &last); dn->getDirectionData(m_successor_index[m_track_node], &dir, &last);
if(dir==GraphNode::DIR_STRAIGHT) if(dir==DriveNode::DIR_STRAIGHT)
{ {
float diff = QuadGraph::get()->getDistanceFromStart(last) float diff = DriveGraph::get()->getDistanceFromStart(last)
- QuadGraph::get()->getDistanceFromStart(m_track_node); - DriveGraph::get()->getDistanceFromStart(m_track_node);
if(diff<0) diff+=World::getWorld()->getTrack()->getTrackLength(); if(diff<0) diff+=World::getWorld()->getTrack()->getTrackLength();
if(diff>m_ai_properties->m_straight_length_for_zipper) if(diff>m_ai_properties->m_straight_length_for_zipper)
m_controls->m_fire = true; m_controls->m_fire = true;
@ -1812,12 +1812,12 @@ void SkiddingAI::checkCrashes(const Vec3& pos )
} }
/*Find if we crash with the drivelines*/ /*Find if we crash with the drivelines*/
if(current_node!=QuadGraph::UNKNOWN_SECTOR && if(current_node!=Graph::UNKNOWN_SECTOR &&
m_next_node_index[current_node]!=-1) m_next_node_index[current_node]!=-1)
QuadGraph::get()->findRoadSector(step_coord, &current_node, DriveGraph::get()->findRoadSector(step_coord, &current_node,
/* sectors to test*/ &m_all_look_aheads[current_node]); /* sectors to test*/ &m_all_look_aheads[current_node]);
if( current_node == QuadGraph::UNKNOWN_SECTOR) if( current_node == Graph::UNKNOWN_SECTOR)
{ {
m_crashes.m_road = true; m_crashes.m_road = true;
return; return;
@ -1865,23 +1865,23 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
*last_node = m_next_node_index[m_track_node]; *last_node = m_next_node_index[m_track_node];
const core::vector2df xz = m_kart->getXYZ().toIrrVector2d(); const core::vector2df xz = m_kart->getXYZ().toIrrVector2d();
const GraphNode* g = QuadGraph::get()->getNode(*last_node); const DriveNode* dn = DriveGraph::get()->getNode(*last_node);
// Index of the left and right end of a quad. // Index of the left and right end of a quad.
const unsigned int LEFT_END_POINT = 0; const unsigned int LEFT_END_POINT = 0;
const unsigned int RIGHT_END_POINT = 1; const unsigned int RIGHT_END_POINT = 1;
core::line2df left (xz, (*g)[LEFT_END_POINT ].toIrrVector2d()); core::line2df left (xz, (*dn)[LEFT_END_POINT ].toIrrVector2d());
core::line2df right(xz, (*g)[RIGHT_END_POINT].toIrrVector2d()); core::line2df right(xz, (*dn)[RIGHT_END_POINT].toIrrVector2d());
#if defined(AI_DEBUG) && defined(AI_DEBUG_NEW_FIND_NON_CRASHING) #if defined(AI_DEBUG) && defined(AI_DEBUG_NEW_FIND_NON_CRASHING)
const Vec3 eps1(0,0.5f,0); const Vec3 eps1(0,0.5f,0);
m_curve[CURVE_LEFT]->clear(); m_curve[CURVE_LEFT]->clear();
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_LEFT]->addPoint((*g)[LEFT_END_POINT]+eps1); m_curve[CURVE_LEFT]->addPoint((*dn)[LEFT_END_POINT]+eps1);
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_RIGHT]->clear(); m_curve[CURVE_RIGHT]->clear();
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_RIGHT]->addPoint((*g)[RIGHT_END_POINT]+eps1); m_curve[CURVE_RIGHT]->addPoint((*dn)[RIGHT_END_POINT]+eps1);
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1);
#endif #endif
#if defined(AI_DEBUG_KART_HEADING) || defined(AI_DEBUG_NEW_FIND_NON_CRASHING) #if defined(AI_DEBUG_KART_HEADING) || defined(AI_DEBUG_NEW_FIND_NON_CRASHING)
@ -1894,13 +1894,13 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
while(1) while(1)
{ {
unsigned int next_sector = m_next_node_index[*last_node]; unsigned int next_sector = m_next_node_index[*last_node];
const GraphNode* g_next = QuadGraph::get()->getNode(next_sector); const DriveNode* dn_next = DriveGraph::get()->getNode(next_sector);
// Test if the next left point is to the right of the left // Test if the next left point is to the right of the left
// line. If so, a new left line is defined. // line. If so, a new left line is defined.
if(left.getPointOrientation((*g_next)[LEFT_END_POINT].toIrrVector2d()) if(left.getPointOrientation((*dn_next)[LEFT_END_POINT].toIrrVector2d())
< 0 ) < 0 )
{ {
core::vector2df p = (*g_next)[LEFT_END_POINT].toIrrVector2d(); core::vector2df p = (*dn_next)[LEFT_END_POINT].toIrrVector2d();
// Stop if the new point is to the right of the right line // Stop if the new point is to the right of the right line
if(right.getPointOrientation(p)<0) if(right.getPointOrientation(p)<0)
break; break;
@ -1916,10 +1916,10 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
// Test if new right point is to the left of the right line. If // Test if new right point is to the left of the right line. If
// so, a new right line is defined. // so, a new right line is defined.
if(right.getPointOrientation((*g_next)[RIGHT_END_POINT].toIrrVector2d()) if(right.getPointOrientation((*dn_next)[RIGHT_END_POINT].toIrrVector2d())
> 0 ) > 0 )
{ {
core::vector2df p = (*g_next)[RIGHT_END_POINT].toIrrVector2d(); core::vector2df p = (*dn_next)[RIGHT_END_POINT].toIrrVector2d();
// Break if new point is to the left of left line // Break if new point is to the left of left line
if(left.getPointOrientation(p)>0) if(left.getPointOrientation(p)>0)
break; break;
@ -1941,7 +1941,7 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
// 0.5f*(left.end.Y+right.end.Y)); // 0.5f*(left.end.Y+right.end.Y));
//*result = ppp; //*result = ppp;
*result = QuadGraph::get()->getNode(*last_node)->getCenter(); *result = DriveGraph::get()->getNode(*last_node)->getCenter();
} // findNonCrashingPointNew } // findNonCrashingPointNew
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1978,7 +1978,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
target_sector = m_next_node_index[*last_node]; target_sector = m_next_node_index[*last_node];
//direction is a vector from our kart to the sectors we are testing //direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getNode(target_sector)->getCenter() direction = DriveGraph::get()->getNode(target_sector)->getCenter()
- m_kart->getXYZ(); - m_kart->getXYZ();
float len=direction.length(); float len=direction.length();
@ -2001,23 +2001,23 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
{ {
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i); step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord, DriveGraph::get()->spatialToTrack(&step_track_coord, step_coord,
*last_node ); *last_node );
float distance = fabsf(step_track_coord[0]); float distance = fabsf(step_track_coord[0]);
//If we are outside, the previous node is what we are looking for //If we are outside, the previous node is what we are looking for
if ( distance + m_kart_width * 0.5f if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode(*last_node)->getPathWidth()*0.5f ) > DriveGraph::get()->getNode(*last_node)->getPathWidth()*0.5f )
{ {
*aim_position = QuadGraph::get()->getNode(*last_node) *aim_position = DriveGraph::get()->getNode(*last_node)
->getCenter(); ->getCenter();
return; return;
} }
} }
*last_node = target_sector; *last_node = target_sector;
} // for i<100 } // for i<100
*aim_position = QuadGraph::get()->getNode(*last_node)->getCenter(); *aim_position = DriveGraph::get()->getNode(*last_node)->getCenter();
} // findNonCrashingPointFixed } // findNonCrashingPointFixed
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2025,14 +2025,14 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
* 1. the test: * 1. the test:
* *
* distance + m_kart_width * 0.5f * distance + m_kart_width * 0.5f
* > QuadGraph::get()->getNode(*last_node)->getPathWidth() ) * > DriveGraph::get()->getNode(*last_node)->getPathWidth() )
* *
* is incorrect, it should compare with getPathWith*0.5f (since distance * is incorrect, it should compare with getPathWith*0.5f (since distance
* is the distance from the center, i.e. it is half the path width if * is the distance from the center, i.e. it is half the path width if
* the point is at the edge). * the point is at the edge).
* 2. the test: * 2. the test:
* *
* QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord, * DriveGraph::get()->spatialToTrack(&step_track_coord, step_coord,
* *last_node ); * *last_node );
* in the for loop tests always against distance from the same * in the for loop tests always against distance from the same
* graph node (*last_node), while de-fact the loop will test points * graph node (*last_node), while de-fact the loop will test points
@ -2057,7 +2057,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw)+eps); m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw)+eps);
#endif #endif
*last_node = m_next_node_index[m_track_node]; *last_node = m_next_node_index[m_track_node];
float angle = QuadGraph::get()->getAngleToNext(m_track_node, float angle = DriveGraph::get()->getAngleToNext(m_track_node,
m_successor_index[m_track_node]); m_successor_index[m_track_node]);
int target_sector; int target_sector;
@ -2073,7 +2073,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
// target_sector is the sector at the longest distance that we can // target_sector is the sector at the longest distance that we can
// drive to without crashing with the track. // drive to without crashing with the track.
target_sector = m_next_node_index[*last_node]; target_sector = m_next_node_index[*last_node];
angle1 = QuadGraph::get()->getAngleToNext(target_sector, angle1 = DriveGraph::get()->getAngleToNext(target_sector,
m_successor_index[target_sector]); m_successor_index[target_sector]);
// In very sharp turns this algorithm tends to aim at off track points, // In very sharp turns this algorithm tends to aim at off track points,
// resulting in hitting a corner. So test for this special case and // resulting in hitting a corner. So test for this special case and
@ -2081,13 +2081,13 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
float diff = normalizeAngle(angle1-angle); float diff = normalizeAngle(angle1-angle);
if(fabsf(diff)>1.5f) if(fabsf(diff)>1.5f)
{ {
*aim_position = QuadGraph::get()->getNode(target_sector) *aim_position = DriveGraph::get()->getNode(target_sector)
->getCenter(); ->getCenter();
return; return;
} }
//direction is a vector from our kart to the sectors we are testing //direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getNode(target_sector)->getCenter() direction = DriveGraph::get()->getNode(target_sector)->getCenter()
- m_kart->getXYZ(); - m_kart->getXYZ();
float len=direction.length(); float len=direction.length();
@ -2110,16 +2110,16 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
{ {
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i); step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord, DriveGraph::get()->spatialToTrack(&step_track_coord, step_coord,
*last_node ); *last_node );
float distance = fabsf(step_track_coord[0]); float distance = fabsf(step_track_coord[0]);
//If we are outside, the previous node is what we are looking for //If we are outside, the previous node is what we are looking for
if ( distance + m_kart_width * 0.5f if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode(*last_node)->getPathWidth() ) > DriveGraph::get()->getNode(*last_node)->getPathWidth() )
{ {
*aim_position = QuadGraph::get()->getNode(*last_node) *aim_position = DriveGraph::get()->getNode(*last_node)
->getCenter(); ->getCenter();
return; return;
} }
@ -2127,7 +2127,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
angle = angle1; angle = angle1;
*last_node = target_sector; *last_node = target_sector;
} // for i<100 } // for i<100
*aim_position = QuadGraph::get()->getNode(*last_node)->getCenter(); *aim_position = DriveGraph::get()->getNode(*last_node)->getCenter();
} // findNonCrashingPoint } // findNonCrashingPoint
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2136,7 +2136,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
*/ */
void SkiddingAI::determineTrackDirection() void SkiddingAI::determineTrackDirection()
{ {
const QuadGraph *qg = QuadGraph::get(); const DriveGraph *qg = DriveGraph::get();
unsigned int succ = m_successor_index[m_track_node]; unsigned int succ = m_successor_index[m_track_node];
unsigned int next = qg->getNode(m_track_node)->getSuccessor(succ); unsigned int next = qg->getNode(m_track_node)->getSuccessor(succ);
@ -2165,7 +2165,7 @@ void SkiddingAI::determineTrackDirection()
// quicker be aligned with the track again). // quicker be aligned with the track again).
if(fabsf(angle_to_track) > 0.22222f * M_PI) if(fabsf(angle_to_track) > 0.22222f * M_PI)
{ {
m_current_track_direction = GraphNode::DIR_UNDEFINED; m_current_track_direction = DriveNode::DIR_UNDEFINED;
return; return;
} }
@ -2181,8 +2181,8 @@ void SkiddingAI::determineTrackDirection()
} }
#endif #endif
if(m_current_track_direction==GraphNode::DIR_LEFT || if(m_current_track_direction==DriveNode::DIR_LEFT ||
m_current_track_direction==GraphNode::DIR_RIGHT ) m_current_track_direction==DriveNode::DIR_RIGHT )
{ {
handleCurve(); handleCurve();
} // if(m_current_track_direction == DIR_LEFT || DIR_RIGHT ) } // if(m_current_track_direction == DIR_LEFT || DIR_RIGHT )
@ -2207,7 +2207,7 @@ void SkiddingAI::handleCurve()
// kart will already point towards the direction of the circle), and // kart will already point towards the direction of the circle), and
// the case that the kart is facing wrong was already tested for before // the case that the kart is facing wrong was already tested for before
const QuadGraph *qg = QuadGraph::get(); const DriveGraph *qg = DriveGraph::get();
Vec3 xyz = m_kart->getXYZ(); Vec3 xyz = m_kart->getXYZ();
Vec3 tangent = m_kart->getTrans()(Vec3(0,0,1)) - xyz; Vec3 tangent = m_kart->getTrans()(Vec3(0,0,1)) - xyz;
Vec3 last_xyz = qg->getNode(m_last_direction_node)->getCenter(); Vec3 last_xyz = qg->getNode(m_last_direction_node)->getCenter();
@ -2227,7 +2227,7 @@ void SkiddingAI::handleCurve()
{ {
i = m_next_node_index[i]; i = m_next_node_index[i];
// Pick either the lower left or right point: // Pick either the lower left or right point:
int index = m_current_track_direction==GraphNode::DIR_LEFT int index = m_current_track_direction==DriveNode::DIR_LEFT
? 0 : 1; ? 0 : 1;
float r = (m_curve_center - *(qg->getNode(i))[index]).length(); float r = (m_curve_center - *(qg->getNode(i))[index]).length();
if(m_current_curve_radius < r) if(m_current_curve_radius < r)
@ -2286,8 +2286,8 @@ bool SkiddingAI::canSkid(float steer_fraction)
} }
// No skidding on straights // No skidding on straights
if(m_current_track_direction==GraphNode::DIR_STRAIGHT || if(m_current_track_direction==DriveNode::DIR_STRAIGHT ||
m_current_track_direction==GraphNode::DIR_UNDEFINED ) m_current_track_direction==DriveNode::DIR_UNDEFINED )
{ {
#ifdef DEBUG #ifdef DEBUG
if(m_controls->m_skid && m_ai_debug) if(m_controls->m_skid && m_ai_debug)
@ -2301,7 +2301,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
} }
const float MIN_SKID_SPEED = 5.0f; const float MIN_SKID_SPEED = 5.0f;
const QuadGraph *qg = QuadGraph::get(); const DriveGraph *qg = DriveGraph::get();
Vec3 last_xyz = qg->getNode(m_last_direction_node)->getCenter(); Vec3 last_xyz = qg->getNode(m_last_direction_node)->getCenter();
// Only try skidding when a certain minimum speed is reached. // Only try skidding when a certain minimum speed is reached.
@ -2312,7 +2312,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
Vec3 diff_last = last_xyz - m_curve_center; Vec3 diff_last = last_xyz - m_curve_center;
float angle_kart = atan2(diff_kart.getX(), diff_kart.getZ()); float angle_kart = atan2(diff_kart.getX(), diff_kart.getZ());
float angle_last = atan2(diff_last.getX(), diff_last.getZ()); float angle_last = atan2(diff_last.getX(), diff_last.getZ());
float angle = m_current_track_direction == GraphNode::DIR_RIGHT float angle = m_current_track_direction == DriveNode::DIR_RIGHT
? angle_last - angle_kart ? angle_last - angle_kart
: angle_kart - angle_last; : angle_kart - angle_last;
angle = normalizeAngle(angle); angle = normalizeAngle(angle);
@ -2339,9 +2339,9 @@ bool SkiddingAI::canSkid(float steer_fraction)
// left turn steer right to avoid getting too close to the left // left turn steer right to avoid getting too close to the left
// vorder). In this case skidding will be useless. // vorder). In this case skidding will be useless.
else if( (steer_fraction > 0 && else if( (steer_fraction > 0 &&
m_current_track_direction==GraphNode::DIR_LEFT) || m_current_track_direction==DriveNode::DIR_LEFT) ||
(steer_fraction < 0 && (steer_fraction < 0 &&
m_current_track_direction==GraphNode::DIR_RIGHT) ) m_current_track_direction==DriveNode::DIR_RIGHT) )
{ {
#ifdef DEBUG #ifdef DEBUG
if(m_controls->m_skid && m_ai_debug) if(m_controls->m_skid && m_ai_debug)

View File

@ -45,11 +45,11 @@
#include "karts/controller/ai_base_lap_controller.hpp" #include "karts/controller/ai_base_lap_controller.hpp"
#include "race/race_manager.hpp" #include "race/race_manager.hpp"
#include "tracks/graph_node.hpp" #include "tracks/drive_node.hpp"
#include "utils/random_generator.hpp" #include "utils/random_generator.hpp"
class LinearWorld; class LinearWorld;
class QuadGraph; class DriveGraph;
class ShowCurve; class ShowCurve;
class Track; class Track;
@ -155,7 +155,7 @@ private:
int m_start_kart_crash_direction; int m_start_kart_crash_direction;
/** The direction of the track where the kart is on atm. */ /** The direction of the track where the kart is on atm. */
GraphNode::DirectionType m_current_track_direction; DriveNode::DirectionType m_current_track_direction;
/** The radius of the curve the kart is currently driving. Undefined /** The radius of the curve the kart is currently driving. Undefined
* when being on a straigt section. */ * when being on a straigt section. */

View File

@ -41,7 +41,7 @@
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "modes/profile_world.hpp" #include "modes/profile_world.hpp"
#include "race/race_manager.hpp" #include "race/race_manager.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_graph.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
@ -177,22 +177,22 @@ void SkiddingAI::reset()
m_distance_behind = 0.0f; m_distance_behind = 0.0f;
m_current_curve_radius = 0.0f; m_current_curve_radius = 0.0f;
m_curve_center = Vec3(0,0,0); m_curve_center = Vec3(0,0,0);
m_current_track_direction = GraphNode::DIR_STRAIGHT; m_current_track_direction = DriveNode::DIR_STRAIGHT;
m_item_to_collect = NULL; m_item_to_collect = NULL;
m_avoid_item_close = false; m_avoid_item_close = false;
m_skid_probability_state = SKID_PROBAB_NOT_YET; m_skid_probability_state = SKID_PROBAB_NOT_YET;
m_last_item_random = NULL; m_last_item_random = NULL;
AIBaseLapController::reset(); AIBaseLapController::reset();
m_track_node = QuadGraph::UNKNOWN_SECTOR; m_track_node = Graph::UNKNOWN_SECTOR;
QuadGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node); DriveGraph::get()->findRoadSector(m_kart->getXYZ(), &m_track_node);
if(m_track_node==QuadGraph::UNKNOWN_SECTOR) if(m_track_node==Graph::UNKNOWN_SECTOR)
{ {
Log::error(getControllerName().c_str(), Log::error(getControllerName().c_str(),
"Invalid starting position for '%s' - not on track" "Invalid starting position for '%s' - not on track"
" - can be ignored.", " - can be ignored.",
m_kart->getIdent().c_str()); m_kart->getIdent().c_str());
m_track_node = QuadGraph::get()->findOutOfRoadSector(m_kart->getXYZ()); m_track_node = DriveGraph::get()->findOutOfRoadSector(m_kart->getXYZ());
} }
AIBaseLapController::reset(); AIBaseLapController::reset();
@ -420,7 +420,7 @@ void SkiddingAI::handleBraking()
// If the kart is not facing roughly in the direction of the track, brake // If the kart is not facing roughly in the direction of the track, brake
// so that it is easier for the kart to turn in the right direction. // so that it is easier for the kart to turn in the right direction.
if(m_current_track_direction==GraphNode::DIR_UNDEFINED && if(m_current_track_direction==DriveNode::DIR_UNDEFINED &&
m_kart->getSpeed() > MIN_SPEED) m_kart->getSpeed() > MIN_SPEED)
{ {
#ifdef DEBUG #ifdef DEBUG
@ -432,8 +432,8 @@ void SkiddingAI::handleBraking()
m_controls->m_brake = true; m_controls->m_brake = true;
return; return;
} }
if(m_current_track_direction==GraphNode::DIR_LEFT || if(m_current_track_direction==DriveNode::DIR_LEFT ||
m_current_track_direction==GraphNode::DIR_RIGHT ) m_current_track_direction==DriveNode::DIR_RIGHT )
{ {
float max_turn_speed = float max_turn_speed =
m_kart->getSpeedForTurnRadius(m_current_curve_radius); m_kart->getSpeedForTurnRadius(m_current_curve_radius);
@ -482,13 +482,13 @@ void SkiddingAI::handleSteering(float dt)
m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() ); m_world->getDistanceToCenterForKart( m_kart->getWorldKartId() );
if( fabsf(side_dist) > if( fabsf(side_dist) >
0.5f* QuadGraph::get()->getNode(m_track_node)->getPathWidth()+0.5f ) 0.5f* DriveGraph::get()->getNode(m_track_node)->getPathWidth()+0.5f )
{ {
steer_angle = steerToPoint(QuadGraph::get()->getNode(next) steer_angle = steerToPoint(DriveGraph::get()->getNode(next)
->getCenter()); ->getCenter());
#ifdef AI_DEBUG #ifdef AI_DEBUG
m_debug_sphere[0]->setPosition(QuadGraph::get()->getNode(next) m_debug_sphere[0]->setPosition(DriveGraph::get()->getNode(next)
->getCenter().toIrrVector()); ->getCenter().toIrrVector());
Log::debug(getControllerName().c_str(), Log::debug(getControllerName().c_str(),
"Outside of road: steer to center point."); "Outside of road: steer to center point.");
@ -536,7 +536,7 @@ void SkiddingAI::handleSteering(float dt)
{ {
m_start_kart_crash_direction = 0; m_start_kart_crash_direction = 0;
Vec3 aim_point; Vec3 aim_point;
int last_node = QuadGraph::UNKNOWN_SECTOR; int last_node = Graph::UNKNOWN_SECTOR;
switch(m_point_selection_algorithm) switch(m_point_selection_algorithm)
{ {
@ -629,7 +629,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
Vec3 kart_aim_direction = *aim_point - m_kart->getXYZ(); Vec3 kart_aim_direction = *aim_point - m_kart->getXYZ();
// Make sure we have a valid last_node // Make sure we have a valid last_node
if(last_node==QuadGraph::UNKNOWN_SECTOR) if(last_node==Graph::UNKNOWN_SECTOR)
last_node = m_next_node_index[m_track_node]; last_node = m_next_node_index[m_track_node];
int node = m_track_node; int node = m_track_node;
@ -642,7 +642,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
const float max_item_lookahead_distance = 30.f; const float max_item_lookahead_distance = 30.f;
while(distance < max_item_lookahead_distance) while(distance < max_item_lookahead_distance)
{ {
int n_index= QuadGraph::get()->getNode(node)->getNodeIndex(); int n_index= DriveGraph::get()->getNode(node)->getIndex();
const std::vector<Item *> &items_ahead = const std::vector<Item *> &items_ahead =
ItemManager::get()->getItemsInQuads(n_index); ItemManager::get()->getItemsInQuads(n_index);
for(unsigned int i=0; i<items_ahead.size(); i++) for(unsigned int i=0; i<items_ahead.size(); i++)
@ -650,7 +650,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
evaluateItems(items_ahead[i], kart_aim_direction, evaluateItems(items_ahead[i], kart_aim_direction,
&items_to_avoid, &items_to_collect); &items_to_avoid, &items_to_collect);
} // for i<items_ahead; } // for i<items_ahead;
distance += QuadGraph::get()->getDistanceToNext(node, distance += DriveGraph::get()->getDistanceToNext(node,
m_successor_index[node]); m_successor_index[node]);
node = m_next_node_index[node]; node = m_next_node_index[node];
// Stop when we have reached the last quad // Stop when we have reached the last quad
@ -787,7 +787,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point,
// so that it can potentially become a permanent target. // so that it can potentially become a permanent target.
Vec3 xyz = item_to_collect->getXYZ(); Vec3 xyz = item_to_collect->getXYZ();
Vec3 item_direction = xyz - m_kart->getXYZ(); Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node) Vec3 plane_normal = DriveGraph::get()->getNode(m_track_node)
->getNormal(); ->getNormal();
float dist_to_plane = item_direction.dot(plane_normal); float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
@ -871,7 +871,7 @@ bool SkiddingAI::handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point)
// the kart is. The current quad provides a good estimate of the kart's plane. // the kart is. The current quad provides a good estimate of the kart's plane.
const Vec3 &xyz = m_item_to_collect->getXYZ(); const Vec3 &xyz = m_item_to_collect->getXYZ();
Vec3 item_direction = xyz - m_kart->getXYZ(); Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node)->getNormal(); Vec3 plane_normal = DriveGraph::get()->getNode(m_track_node)->getNormal();
float dist_to_plane = item_direction.dot(plane_normal); float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
@ -932,7 +932,7 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
// rightmost point - if so, nothing to do. // rightmost point - if so, nothing to do.
Vec3 left(items_to_avoid[index_left_most]->getXYZ()); Vec3 left(items_to_avoid[index_left_most]->getXYZ());
int node_index = items_to_avoid[index_left_most]->getGraphNode(); int node_index = items_to_avoid[index_left_most]->getGraphNode();
Vec3 normal = QuadGraph::get()->getNode(node_index)->getNormal(); Vec3 normal = DriveGraph::get()->getNode(node_index)->getNormal();
Vec3 p1 = line_to_target.start, Vec3 p1 = line_to_target.start,
p2 = line_to_target.getMiddle() + normal.toIrrVector(), p2 = line_to_target.getMiddle() + normal.toIrrVector(),
p3 = line_to_target.end; p3 = line_to_target.end;
@ -952,7 +952,7 @@ bool SkiddingAI::steerToAvoid(const std::vector<const Item *> &items_to_avoid,
{ {
Vec3 left(items_to_avoid[index_left_most]->getXYZ()); Vec3 left(items_to_avoid[index_left_most]->getXYZ());
int node_index = items_to_avoid[index_left_most]->getGraphNode(); int node_index = items_to_avoid[index_left_most]->getGraphNode();
Vec3 normal = QuadGraph::get()->getNode(node_index)->getNormal(); Vec3 normal = DriveGraph::get()->getNode(node_index)->getNormal();
Vec3 p1 = line_to_target.start, Vec3 p1 = line_to_target.start,
p2 = line_to_target.getMiddle() + normal.toIrrVector(), p2 = line_to_target.getMiddle() + normal.toIrrVector(),
p3 = line_to_target.end; p3 = line_to_target.end;
@ -1110,7 +1110,7 @@ void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction,
// the kart is. The current quad provides a good estimate of the kart's plane. // the kart is. The current quad provides a good estimate of the kart's plane.
const Vec3 &xyz = item->getXYZ(); const Vec3 &xyz = item->getXYZ();
Vec3 item_direction = xyz - m_kart->getXYZ(); Vec3 item_direction = xyz - m_kart->getXYZ();
Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node)->getNormal(); Vec3 plane_normal = DriveGraph::get()->getNode(m_track_node)->getNormal();
float dist_to_plane = item_direction.dot(plane_normal); float dist_to_plane = item_direction.dot(plane_normal);
Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; Vec3 projected_xyz = xyz - dist_to_plane*plane_normal;
@ -1763,14 +1763,14 @@ void SkiddingAI::handleNitroAndZipper()
m_kart->getSpeed()>1.0f && m_kart->getSpeed()>1.0f &&
m_kart->getSpeedIncreaseTimeLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0) m_kart->getSpeedIncreaseTimeLeft(MaxSpeed::MS_INCREASE_ZIPPER)<=0)
{ {
GraphNode::DirectionType dir; DriveNode::DirectionType dir;
unsigned int last; unsigned int last;
const GraphNode* gn = QuadGraph::get()->getNode(m_track_node); const DriveNode* dn = DriveGraph::get()->getNode(m_track_node);
gn->getDirectionData(m_successor_index[m_track_node], &dir, &last); dn->getDirectionData(m_successor_index[m_track_node], &dir, &last);
if(dir==GraphNode::DIR_STRAIGHT) if(dir==DriveNode::DIR_STRAIGHT)
{ {
float diff = QuadGraph::get()->getDistanceFromStart(last) float diff = DriveGraph::get()->getDistanceFromStart(last)
- QuadGraph::get()->getDistanceFromStart(m_track_node); - DriveGraph::get()->getDistanceFromStart(m_track_node);
if(diff<0) diff+=World::getWorld()->getTrack()->getTrackLength(); if(diff<0) diff+=World::getWorld()->getTrack()->getTrackLength();
if(diff>m_ai_properties->m_straight_length_for_zipper) if(diff>m_ai_properties->m_straight_length_for_zipper)
m_controls->m_fire = true; m_controls->m_fire = true;
@ -1861,12 +1861,12 @@ void SkiddingAI::checkCrashes(const Vec3& pos )
} }
/*Find if we crash with the drivelines*/ /*Find if we crash with the drivelines*/
if(current_node!=QuadGraph::UNKNOWN_SECTOR && if(current_node!=Graph::UNKNOWN_SECTOR &&
m_next_node_index[current_node]!=-1) m_next_node_index[current_node]!=-1)
QuadGraph::get()->findRoadSector(step_coord, &current_node, DriveGraph::get()->findRoadSector(step_coord, &current_node,
/* sectors to test*/ &m_all_look_aheads[current_node]); /* sectors to test*/ &m_all_look_aheads[current_node]);
if( current_node == QuadGraph::UNKNOWN_SECTOR) if( current_node == Graph::UNKNOWN_SECTOR)
{ {
m_crashes.m_road = true; m_crashes.m_road = true;
return; return;
@ -1914,23 +1914,23 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
*last_node = m_next_node_index[m_track_node]; *last_node = m_next_node_index[m_track_node];
const core::vector2df xz = m_kart->getXYZ().toIrrVector2d(); const core::vector2df xz = m_kart->getXYZ().toIrrVector2d();
const GraphNode* g = QuadGraph::get()->getNode(*last_node); const DriveNode* dn = DriveGraph::get()->getNode(*last_node);
// Index of the left and right end of a quad. // Index of the left and right end of a quad.
const unsigned int LEFT_END_POINT = 0; const unsigned int LEFT_END_POINT = 0;
const unsigned int RIGHT_END_POINT = 1; const unsigned int RIGHT_END_POINT = 1;
core::line2df left (xz, (*g)[LEFT_END_POINT ].toIrrVector2d()); core::line2df left (xz, (*dn)[LEFT_END_POINT ].toIrrVector2d());
core::line2df right(xz, (*g)[RIGHT_END_POINT].toIrrVector2d()); core::line2df right(xz, (*dn)[RIGHT_END_POINT].toIrrVector2d());
#if defined(AI_DEBUG) && defined(AI_DEBUG_NEW_FIND_NON_CRASHING) #if defined(AI_DEBUG) && defined(AI_DEBUG_NEW_FIND_NON_CRASHING)
const Vec3 eps1(0,0.5f,0); const Vec3 eps1(0,0.5f,0);
m_curve[CURVE_LEFT]->clear(); m_curve[CURVE_LEFT]->clear();
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_LEFT]->addPoint((*g)[LEFT_END_POINT]+eps1); m_curve[CURVE_LEFT]->addPoint((*dn)[LEFT_END_POINT]+eps1);
m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_RIGHT]->clear(); m_curve[CURVE_RIGHT]->clear();
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1);
m_curve[CURVE_RIGHT]->addPoint((*g)[RIGHT_END_POINT]+eps1); m_curve[CURVE_RIGHT]->addPoint((*dn)[RIGHT_END_POINT]+eps1);
m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1);
#endif #endif
#if defined(AI_DEBUG_KART_HEADING) || defined(AI_DEBUG_NEW_FIND_NON_CRASHING) #if defined(AI_DEBUG_KART_HEADING) || defined(AI_DEBUG_NEW_FIND_NON_CRASHING)
@ -1943,13 +1943,13 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
while(1) while(1)
{ {
unsigned int next_sector = m_next_node_index[*last_node]; unsigned int next_sector = m_next_node_index[*last_node];
const GraphNode* g_next = QuadGraph::get()->getNode(next_sector); const DriveNode* dn_next = DriveGraph::get()->getNode(next_sector);
// Test if the next left point is to the right of the left // Test if the next left point is to the right of the left
// line. If so, a new left line is defined. // line. If so, a new left line is defined.
if(left.getPointOrientation((*g_next)[LEFT_END_POINT].toIrrVector2d()) if(left.getPointOrientation((*dn_next)[LEFT_END_POINT].toIrrVector2d())
< 0 ) < 0 )
{ {
core::vector2df p = (*g_next)[LEFT_END_POINT].toIrrVector2d(); core::vector2df p = (*dn_next)[LEFT_END_POINT].toIrrVector2d();
// Stop if the new point is to the right of the right line // Stop if the new point is to the right of the right line
if(right.getPointOrientation(p)<0) if(right.getPointOrientation(p)<0)
break; break;
@ -1965,10 +1965,10 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
// Test if new right point is to the left of the right line. If // Test if new right point is to the left of the right line. If
// so, a new right line is defined. // so, a new right line is defined.
if(right.getPointOrientation((*g_next)[RIGHT_END_POINT].toIrrVector2d()) if(right.getPointOrientation((*dn_next)[RIGHT_END_POINT].toIrrVector2d())
> 0 ) > 0 )
{ {
core::vector2df p = (*g_next)[RIGHT_END_POINT].toIrrVector2d(); core::vector2df p = (*dn_next)[RIGHT_END_POINT].toIrrVector2d();
// Break if new point is to the left of left line // Break if new point is to the left of left line
if(left.getPointOrientation(p)>0) if(left.getPointOrientation(p)>0)
break; break;
@ -1990,7 +1990,7 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node)
// 0.5f*(left.end.Y+right.end.Y)); // 0.5f*(left.end.Y+right.end.Y));
//*result = ppp; //*result = ppp;
*result = QuadGraph::get()->getNode(*last_node)->getCenter(); *result = DriveGraph::get()->getNode(*last_node)->getCenter();
} // findNonCrashingPointNew } // findNonCrashingPointNew
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2027,7 +2027,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
target_sector = m_next_node_index[*last_node]; target_sector = m_next_node_index[*last_node];
//direction is a vector from our kart to the sectors we are testing //direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getNode(target_sector)->getCenter() direction = DriveGraph::get()->getNode(target_sector)->getCenter()
- m_kart->getXYZ(); - m_kart->getXYZ();
float len=direction.length(); float len=direction.length();
@ -2050,23 +2050,23 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
{ {
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i); step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord, DriveGraph::get()->spatialToTrack(&step_track_coord, step_coord,
*last_node ); *last_node );
float distance = fabsf(step_track_coord[0]); float distance = fabsf(step_track_coord[0]);
//If we are outside, the previous node is what we are looking for //If we are outside, the previous node is what we are looking for
if ( distance + m_kart_width * 0.5f if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode(*last_node)->getPathWidth()*0.5f ) > DriveGraph::get()->getNode(*last_node)->getPathWidth()*0.5f )
{ {
*aim_position = QuadGraph::get()->getNode(*last_node) *aim_position = DriveGraph::get()->getNode(*last_node)
->getCenter(); ->getCenter();
return; return;
} }
} }
*last_node = target_sector; *last_node = target_sector;
} // for i<100 } // for i<100
*aim_position = QuadGraph::get()->getNode(*last_node)->getCenter(); *aim_position = DriveGraph::get()->getNode(*last_node)->getCenter();
} // findNonCrashingPointFixed } // findNonCrashingPointFixed
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2074,14 +2074,14 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
* 1. the test: * 1. the test:
* *
* distance + m_kart_width * 0.5f * distance + m_kart_width * 0.5f
* > QuadGraph::get()->getNode(*last_node)->getPathWidth() ) * > DriveGraph::get()->getNode(*last_node)->getPathWidth() )
* *
* is incorrect, it should compare with getPathWith*0.5f (since distance * is incorrect, it should compare with getPathWith*0.5f (since distance
* is the distance from the center, i.e. it is half the path width if * is the distance from the center, i.e. it is half the path width if
* the point is at the edge). * the point is at the edge).
* 2. the test: * 2. the test:
* *
* QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord, * DriveGraph::get()->spatialToTrack(&step_track_coord, step_coord,
* *last_node ); * *last_node );
* in the for loop tests always against distance from the same * in the for loop tests always against distance from the same
* graph node (*last_node), while de-fact the loop will test points * graph node (*last_node), while de-fact the loop will test points
@ -2106,7 +2106,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw)+eps); m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw)+eps);
#endif #endif
*last_node = m_next_node_index[m_track_node]; *last_node = m_next_node_index[m_track_node];
float angle = QuadGraph::get()->getAngleToNext(m_track_node, float angle = DriveGraph::get()->getAngleToNext(m_track_node,
m_successor_index[m_track_node]); m_successor_index[m_track_node]);
int target_sector; int target_sector;
@ -2122,7 +2122,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
// target_sector is the sector at the longest distance that we can // target_sector is the sector at the longest distance that we can
// drive to without crashing with the track. // drive to without crashing with the track.
target_sector = m_next_node_index[*last_node]; target_sector = m_next_node_index[*last_node];
angle1 = QuadGraph::get()->getAngleToNext(target_sector, angle1 = DriveGraph::get()->getAngleToNext(target_sector,
m_successor_index[target_sector]); m_successor_index[target_sector]);
// In very sharp turns this algorithm tends to aim at off track points, // In very sharp turns this algorithm tends to aim at off track points,
// resulting in hitting a corner. So test for this special case and // resulting in hitting a corner. So test for this special case and
@ -2130,13 +2130,13 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
float diff = normalizeAngle(angle1-angle); float diff = normalizeAngle(angle1-angle);
if(fabsf(diff)>1.5f) if(fabsf(diff)>1.5f)
{ {
*aim_position = QuadGraph::get()->getNode(target_sector) *aim_position = DriveGraph::get()->getNode(target_sector)
->getCenter(); ->getCenter();
return; return;
} }
//direction is a vector from our kart to the sectors we are testing //direction is a vector from our kart to the sectors we are testing
direction = QuadGraph::get()->getNode(target_sector)->getCenter() direction = DriveGraph::get()->getNode(target_sector)->getCenter()
- m_kart->getXYZ(); - m_kart->getXYZ();
float len=direction.length(); float len=direction.length();
@ -2159,16 +2159,16 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
{ {
step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i); step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i);
QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord, DriveGraph::get()->spatialToTrack(&step_track_coord, step_coord,
*last_node ); *last_node );
float distance = fabsf(step_track_coord[0]); float distance = fabsf(step_track_coord[0]);
//If we are outside, the previous node is what we are looking for //If we are outside, the previous node is what we are looking for
if ( distance + m_kart_width * 0.5f if ( distance + m_kart_width * 0.5f
> QuadGraph::get()->getNode(*last_node)->getPathWidth() ) > DriveGraph::get()->getNode(*last_node)->getPathWidth() )
{ {
*aim_position = QuadGraph::get()->getNode(*last_node) *aim_position = DriveGraph::get()->getNode(*last_node)
->getCenter(); ->getCenter();
return; return;
} }
@ -2176,7 +2176,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
angle = angle1; angle = angle1;
*last_node = target_sector; *last_node = target_sector;
} // for i<100 } // for i<100
*aim_position = QuadGraph::get()->getNode(*last_node)->getCenter(); *aim_position = DriveGraph::get()->getNode(*last_node)->getCenter();
} // findNonCrashingPoint } // findNonCrashingPoint
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2185,7 +2185,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node)
*/ */
void SkiddingAI::determineTrackDirection() void SkiddingAI::determineTrackDirection()
{ {
const QuadGraph *qg = QuadGraph::get(); const DriveGraph *qg = DriveGraph::get();
unsigned int succ = m_successor_index[m_track_node]; unsigned int succ = m_successor_index[m_track_node];
unsigned int next = qg->getNode(m_track_node)->getSuccessor(succ); unsigned int next = qg->getNode(m_track_node)->getSuccessor(succ);
@ -2214,7 +2214,7 @@ void SkiddingAI::determineTrackDirection()
// quicker be aligned with the track again). // quicker be aligned with the track again).
if(fabsf(angle_to_track) > 0.22222f * M_PI) if(fabsf(angle_to_track) > 0.22222f * M_PI)
{ {
m_current_track_direction = GraphNode::DIR_UNDEFINED; m_current_track_direction = DriveNode::DIR_UNDEFINED;
return; return;
} }
@ -2230,8 +2230,8 @@ void SkiddingAI::determineTrackDirection()
} }
#endif #endif
if(m_current_track_direction==GraphNode::DIR_LEFT || if(m_current_track_direction==DriveNode::DIR_LEFT ||
m_current_track_direction==GraphNode::DIR_RIGHT ) m_current_track_direction==DriveNode::DIR_RIGHT )
{ {
handleCurve(); handleCurve();
} // if(m_current_track_direction == DIR_LEFT || DIR_RIGHT ) } // if(m_current_track_direction == DIR_LEFT || DIR_RIGHT )
@ -2256,7 +2256,7 @@ void SkiddingAI::handleCurve()
// kart will already point towards the direction of the circle), and // kart will already point towards the direction of the circle), and
// the case that the kart is facing wrong was already tested for before // the case that the kart is facing wrong was already tested for before
const QuadGraph *qg = QuadGraph::get(); const DriveGraph *qg = DriveGraph::get();
Vec3 xyz = m_kart->getXYZ(); Vec3 xyz = m_kart->getXYZ();
Vec3 tangent = m_kart->getTrans()(Vec3(0,0,1)) - xyz; Vec3 tangent = m_kart->getTrans()(Vec3(0,0,1)) - xyz;
Vec3 last_xyz = qg->getNode(m_last_direction_node)->getCenter(); Vec3 last_xyz = qg->getNode(m_last_direction_node)->getCenter();
@ -2276,7 +2276,7 @@ void SkiddingAI::handleCurve()
{ {
i = m_next_node_index[i]; i = m_next_node_index[i];
// Pick either the lower left or right point: // Pick either the lower left or right point:
int index = m_current_track_direction==GraphNode::DIR_LEFT int index = m_current_track_direction==DriveNode::DIR_LEFT
? 0 : 1; ? 0 : 1;
float r = (m_curve_center - *(qg->getNode(i))[index]).length(); float r = (m_curve_center - *(qg->getNode(i))[index]).length();
if(m_current_curve_radius < r) if(m_current_curve_radius < r)
@ -2335,8 +2335,8 @@ bool SkiddingAI::canSkid(float steer_fraction)
} }
// No skidding on straights // No skidding on straights
if(m_current_track_direction==GraphNode::DIR_STRAIGHT || if(m_current_track_direction==DriveNode::DIR_STRAIGHT ||
m_current_track_direction==GraphNode::DIR_UNDEFINED ) m_current_track_direction==DriveNode::DIR_UNDEFINED )
{ {
#ifdef DEBUG #ifdef DEBUG
if(m_controls->m_skid && m_ai_debug) if(m_controls->m_skid && m_ai_debug)
@ -2350,7 +2350,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
} }
const float MIN_SKID_SPEED = 5.0f; const float MIN_SKID_SPEED = 5.0f;
const QuadGraph *qg = QuadGraph::get(); const DriveGraph *qg = DriveGraph::get();
Vec3 last_xyz = qg->getNode(m_last_direction_node)->getCenter(); Vec3 last_xyz = qg->getNode(m_last_direction_node)->getCenter();
// Only try skidding when a certain minimum speed is reached. // Only try skidding when a certain minimum speed is reached.
@ -2361,7 +2361,7 @@ bool SkiddingAI::canSkid(float steer_fraction)
Vec3 diff_last = last_xyz - m_curve_center; Vec3 diff_last = last_xyz - m_curve_center;
float angle_kart = atan2(diff_kart.getX(), diff_kart.getZ()); float angle_kart = atan2(diff_kart.getX(), diff_kart.getZ());
float angle_last = atan2(diff_last.getX(), diff_last.getZ()); float angle_last = atan2(diff_last.getX(), diff_last.getZ());
float angle = m_current_track_direction == GraphNode::DIR_RIGHT float angle = m_current_track_direction == DriveNode::DIR_RIGHT
? angle_last - angle_kart ? angle_last - angle_kart
: angle_kart - angle_last; : angle_kart - angle_last;
angle = normalizeAngle(angle); angle = normalizeAngle(angle);
@ -2388,9 +2388,9 @@ bool SkiddingAI::canSkid(float steer_fraction)
// left turn steer right to avoid getting too close to the left // left turn steer right to avoid getting too close to the left
// vorder). In this case skidding will be useless. // vorder). In this case skidding will be useless.
else if( (steer_fraction > 0 && else if( (steer_fraction > 0 &&
m_current_track_direction==GraphNode::DIR_LEFT) || m_current_track_direction==DriveNode::DIR_LEFT) ||
(steer_fraction < 0 && (steer_fraction < 0 &&
m_current_track_direction==GraphNode::DIR_RIGHT) ) m_current_track_direction==DriveNode::DIR_RIGHT) )
{ {
#ifdef DEBUG #ifdef DEBUG
if(m_controls->m_skid && m_ai_debug) if(m_controls->m_skid && m_ai_debug)

View File

@ -46,7 +46,7 @@
#include "karts/controller/ai_base_lap_controller.hpp" #include "karts/controller/ai_base_lap_controller.hpp"
#include "race/race_manager.hpp" #include "race/race_manager.hpp"
#include "tracks/graph_node.hpp" #include "tracks/drive_node.hpp"
#include "utils/random_generator.hpp" #include "utils/random_generator.hpp"
#ifdef AI_DEBUG #ifdef AI_DEBUG
@ -111,7 +111,7 @@ private:
int m_start_kart_crash_direction; int m_start_kart_crash_direction;
/** The direction of the track where the kart is on atm. */ /** The direction of the track where the kart is on atm. */
GraphNode::DirectionType m_current_track_direction; DriveNode::DirectionType m_current_track_direction;
/** The radius of the curve the kart is currently driving. Undefined /** The radius of the curve the kart is currently driving. Undefined
* when being on a straigt section. */ * when being on a straigt section. */

View File

@ -64,8 +64,8 @@
#include "physics/physics.hpp" #include "physics/physics.hpp"
#include "race/history.hpp" #include "race/history.hpp"
#include "tracks/terrain_info.hpp" #include "tracks/terrain_info.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_graph.hpp"
#include "tracks/graph_node.hpp" #include "tracks/drive_node.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "tracks/track_manager.hpp" #include "tracks/track_manager.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
@ -1296,14 +1296,14 @@ void Kart::update(float dt)
// To be used later // To be used later
float dist_to_sector = 0.0f; float dist_to_sector = 0.0f;
if (QuadGraph::get()) if (DriveGraph::get())
{ {
const int sector = ((LinearWorld*)World::getWorld()) const int sector = ((LinearWorld*)World::getWorld())
->getTrackSector(getWorldKartId()).getCurrentGraphNode(); ->getTrackSector(getWorldKartId()).getCurrentGraphNode();
dist_to_sector = getXYZ().distance dist_to_sector = getXYZ().distance
(QuadGraph::get()->getNode(sector)->getCenter()); (DriveGraph::get()->getNode(sector)->getCenter());
const Vec3& quad_normal = QuadGraph::get()->getNode(sector) const Vec3& quad_normal = DriveGraph::get()->getNode(sector)
->getNormal(); ->getNormal();
const btQuaternion& q = getTrans().getRotation(); const btQuaternion& q = getTrans().getRotation();
const float roll = quad_normal.angle const float roll = quad_normal.angle
@ -1941,13 +1941,13 @@ void Kart::crashed(const Material *m, const Vec3 &normal)
World::getWorld()->getTrack()->isPushBackEnabled()) World::getWorld()->getTrack()->isPushBackEnabled())
{ {
int sector = lw->getSectorForKart(this); int sector = lw->getSectorForKart(this);
if(sector!=QuadGraph::UNKNOWN_SECTOR) if(sector!=Graph::UNKNOWN_SECTOR)
{ {
// Use the first predecessor node, which is the most // Use the first predecessor node, which is the most
// natural one (i.e. the one on the main driveline). // natural one (i.e. the one on the main driveline).
const GraphNode* gn = QuadGraph::get()->getNode( const DriveNode* dn = DriveGraph::get()->getNode(
QuadGraph::get()->getNode(sector)->getPredecessor(0)); DriveGraph::get()->getNode(sector)->getPredecessor(0));
Vec3 impulse = gn->getCenter() - getXYZ(); Vec3 impulse = dn->getCenter() - getXYZ();
impulse.setY(0); impulse.setY(0);
if(impulse.getX() || impulse.getZ()) if(impulse.getX() || impulse.getZ())
impulse.normalize(); impulse.normalize();

View File

@ -30,8 +30,8 @@
#include "physics/physics.hpp" #include "physics/physics.hpp"
#include "race/history.hpp" #include "race/history.hpp"
#include "states_screens/race_gui_base.hpp" #include "states_screens/race_gui_base.hpp"
#include "tracks/graph_node.hpp" #include "tracks/drive_graph.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_node.hpp"
#include "tracks/track_sector.hpp" #include "tracks/track_sector.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
@ -393,7 +393,7 @@ void LinearWorld::newLap(unsigned int kart_index)
int LinearWorld::getSectorForKart(const AbstractKart *kart) const int LinearWorld::getSectorForKart(const AbstractKart *kart) const
{ {
if(kart->getWorldKartId()>=m_kart_info.size()) if(kart->getWorldKartId()>=m_kart_info.size())
return QuadGraph::UNKNOWN_SECTOR; return Graph::UNKNOWN_SECTOR;
return m_kart_info[kart->getWorldKartId()].getTrackSector() return m_kart_info[kart->getWorldKartId()].getTrackSector()
->getCurrentGraphNode(); ->getCurrentGraphNode();
} // getSectorForKart } // getSectorForKart
@ -629,7 +629,7 @@ float LinearWorld::estimateFinishTimeForKart(AbstractKart* kart)
*/ */
unsigned int LinearWorld::getNumberOfRescuePositions() const unsigned int LinearWorld::getNumberOfRescuePositions() const
{ {
return QuadGraph::get()->getNumNodes(); return DriveGraph::get()->getNumNodes();
} // getNumberOfRescuePositions } // getNumberOfRescuePositions
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -647,8 +647,8 @@ unsigned int LinearWorld::getRescuePositionIndex(AbstractKart *kart)
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
btTransform LinearWorld::getRescueTransform(unsigned int index) const btTransform LinearWorld::getRescueTransform(unsigned int index) const
{ {
const Vec3 &xyz = QuadGraph::get()->getNode(index)->getCenter(); const Vec3 &xyz = DriveGraph::get()->getNode(index)->getCenter();
const Vec3 &normal = QuadGraph::get()->getNode(index)->getNormal(); const Vec3 &normal = DriveGraph::get()->getNode(index)->getNormal();
btTransform pos; btTransform pos;
pos.setOrigin(xyz); pos.setOrigin(xyz);
@ -866,11 +866,11 @@ void LinearWorld::checkForWrongDirection(unsigned int i, float dt)
// will be one direction in which it isn't going backwards anyway. // will be one direction in which it isn't going backwards anyway.
int sector = m_kart_info[i].getTrackSector()->getCurrentGraphNode(); int sector = m_kart_info[i].getTrackSector()->getCurrentGraphNode();
if (QuadGraph::get()->getNumberOfSuccessors(sector) > 1) if (DriveGraph::get()->getNumberOfSuccessors(sector) > 1)
return; return;
// check if the player is going in the wrong direction // check if the player is going in the wrong direction
const GraphNode* node = QuadGraph::get()->getNode(sector); const DriveNode* node = DriveGraph::get()->getNode(sector);
Vec3 center_line = node->getUpperCenter() - node->getLowerCenter(); Vec3 center_line = node->getUpperCenter() - node->getLowerCenter();
float angle_diff = kart->getVelocity().angle(center_line); float angle_diff = kart->getVelocity().angle(center_line);

View File

@ -49,8 +49,9 @@ ArenaGraph::ArenaGraph(const std::string &navmesh, const XMLNode *node)
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
ArenaNode* ArenaGraph::getNode(unsigned int i) const ArenaNode* ArenaGraph::getNode(unsigned int i) const
{ {
assert(i < m_all_nodes.size());
ArenaNode* n = dynamic_cast<ArenaNode*>(m_all_nodes[i]); ArenaNode* n = dynamic_cast<ArenaNode*>(m_all_nodes[i]);
assert(n!= NULL); assert(n != NULL);
return n; return n;
} // getNode } // getNode

View File

@ -28,6 +28,7 @@ class ArenaNode;
class XMLNode; class XMLNode;
/** /**
* \brief A graph made from navmesh
* \ingroup tracks * \ingroup tracks
*/ */
class ArenaGraph : public Graph class ArenaGraph : public Graph

View File

@ -28,7 +28,7 @@
#include "tracks/check_lap.hpp" #include "tracks/check_lap.hpp"
#include "tracks/check_line.hpp" #include "tracks/check_line.hpp"
#include "tracks/check_structure.hpp" #include "tracks/check_structure.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_graph.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
CheckManager *CheckManager::m_check_manager = NULL; CheckManager *CheckManager::m_check_manager = NULL;
@ -85,7 +85,7 @@ void CheckManager::load(const XMLNode &node)
for(it=check_structures_to_change_state.begin(); for(it=check_structures_to_change_state.begin();
it != check_structures_to_change_state.end(); it++) it != check_structures_to_change_state.end(); it++)
{ {
if(QuadGraph::get()->isReverse()) if(DriveGraph::get()->isReverse())
m_all_checks[*it]->addSuccessor(i); m_all_checks[*it]->addSuccessor(i);
else else
m_all_checks[i]->addSuccessor(*it); m_all_checks[i]->addSuccessor(*it);

View File

@ -16,64 +16,17 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, B // Foundation, Inc., 59 Temple Place - Suite 330, B
#include "tracks/quad_graph.hpp" #include "tracks/drive_graph.hpp"
#include "LinearMath/btTransform.h"
#include <IMesh.h>
#include <ICameraSceneNode.h>
#include "graphics/central_settings.hpp"
#include "config/user_config.hpp" #include "config/user_config.hpp"
#include "graphics/callbacks.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/screen_quad.hpp"
#include "graphics/shaders.hpp"
#include "graphics/rtts.hpp"
#include "io/file_manager.hpp" #include "io/file_manager.hpp"
#include "io/xml_node.hpp" #include "io/xml_node.hpp"
#include "modes/world.hpp" #include "modes/world.hpp"
#include "tracks/check_lap.hpp" #include "tracks/check_lap.hpp"
#include "tracks/check_line.hpp" #include "tracks/check_line.hpp"
#include "tracks/check_manager.hpp" #include "tracks/check_manager.hpp"
#include "tracks/node_2d.hpp" #include "tracks/drive_node.hpp"
#include "tracks/node_3d.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "graphics/glwrap.hpp"
const int QuadGraph::UNKNOWN_SECTOR = -1;
QuadGraph *QuadGraph::m_quad_graph = NULL;
/** Factory method to dynamic create 2d / 3d node */
GraphNode* createNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
const Vec3 &p3, unsigned int node_index,
bool invisible, bool ai_ignore)
{
// Find the normal of this node by computing the normal of two triangles
// and taking their average.
core::triangle3df tri1(p0.toIrrVector(), p1.toIrrVector(),
p2.toIrrVector());
core::triangle3df tri2(p0.toIrrVector(), p2.toIrrVector(),
p3.toIrrVector());
Vec3 normal1 = tri1.getNormal();
Vec3 normal2 = tri2.getNormal();
Vec3 normal = -0.5f * (normal1 + normal2);
normal.normalize();
// Use the angle between the normal and an up vector to choose 3d/2d node
const float angle = normal.angle(Vec3(0, 1, 0));
if (angle > 0.5f)
{
Log::debug("TrackNode", "3d node created, normal: %f, %f, %f",
normal.x(), normal.y(), normal.z());
return new Node3D(p0, p1, p2, p3, normal, node_index, invisible,
ai_ignore);
}
Log::debug("TrackNode", "2d node created, normal: %f, %f, %f",
normal.x(), normal.y(), normal.z());
return new Node2D(p0, p1, p2, p3, normal, node_index, invisible,
ai_ignore);
} // createNode
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Constructor, loads the graph information for a given set of quads /** Constructor, loads the graph information for a given set of quads
@ -81,36 +34,23 @@ GraphNode* createNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
* \param quad_file_name Name of the file of all quads * \param quad_file_name Name of the file of all quads
* \param graph_file_name Name of the file describing the actual graph * \param graph_file_name Name of the file describing the actual graph
*/ */
QuadGraph::QuadGraph(const std::string &quad_file_name, DriveGraph::DriveGraph(const std::string &quad_file_name,
const std::string &graph_file_name, const std::string &graph_file_name,
const bool reverse) : m_reverse(reverse) const bool reverse) : m_reverse(reverse)
{ {
m_lap_length = 0; m_lap_length = 0;
m_quad_filename = quad_file_name; m_quad_filename = quad_file_name;
m_quad_graph = this; Graph::setGraph(this);
load(quad_file_name, graph_file_name); load(quad_file_name, graph_file_name);
} // QuadGraph } // DriveGraph
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Destructor, removes all nodes of the graph. */ void DriveGraph::addSuccessor(unsigned int from, unsigned int to)
QuadGraph::~QuadGraph()
{
for(unsigned int i=0; i<m_all_nodes.size(); i++)
{
delete m_all_nodes[i];
}
if(UserConfigParams::m_track_debug)
cleanupDebugMesh();
GraphStructure::destroyRTT();
} // ~QuadGraph
// ----------------------------------------------------------------------------
void QuadGraph::addSuccessor(unsigned int from, unsigned int to)
{ {
if(m_reverse) if(m_reverse)
m_all_nodes[to]->addSuccessor(from); getNode(to)->addSuccessor(from);
else else
m_all_nodes[from]->addSuccessor(to); getNode(from)->addSuccessor(to);
} // addSuccessor } // addSuccessor
@ -120,8 +60,9 @@ void QuadGraph::addSuccessor(unsigned int from, unsigned int to)
p1="n:p" : get point p from square n (n, p integers) p1="n:p" : get point p from square n (n, p integers)
p1="p1,p2,p3" : make a 3d point out of these 3 floating point values p1="p1,p2,p3" : make a 3d point out of these 3 floating point values
*/ */
void QuadGraph::getPoint(const XMLNode *xml, const std::string &attribute_name, void DriveGraph::getPoint(const XMLNode *xml,
Vec3* result) const const std::string &attribute_name,
Vec3* result) const
{ {
std::string s; std::string s;
xml->get(attribute_name, &s); xml->get(attribute_name, &s);
@ -141,30 +82,28 @@ void QuadGraph::getPoint(const XMLNode *xml, const std::string &attribute_name,
} // getPoint } // getPoint
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Loads a quad graph from a file. /** Loads a drive graph from a file.
* \param filename Name of the quad file to load. * \param filename Name of the quad file to load.
* \param filename Name of the graph file to load. * \param filename Name of the graph file to load.
*/ */
void QuadGraph::load(const std::string &quad_file_name, void DriveGraph::load(const std::string &quad_file_name,
const std::string &filename) const std::string &filename)
{ {
XMLNode *quad = file_manager->createXMLTree(quad_file_name); XMLNode *quad = file_manager->createXMLTree(quad_file_name);
if (!quad || quad->getName() != "quads") if (!quad || quad->getName() != "quads")
{ {
Log::error("Quad Graph : Quad xml '%s' not found.", filename.c_str()); Log::error("DriveGraph : Quad xml '%s' not found.", filename.c_str());
delete quad; delete quad;
return; return;
} }
m_min = Vec3( 99999, 99999, 99999);
m_max = Vec3(-99999, -99999, -99999);
// Each quad is part of the graph exactly once now. // Each quad is part of the graph exactly once now.
for(unsigned int i=0; i<quad->getNumNodes(); i++) for(unsigned int i=0; i<quad->getNumNodes(); i++)
{ {
const XMLNode *xml_node = quad->getNode(i); const XMLNode *xml_node = quad->getNode(i);
if(xml_node->getName()!="quad") if(xml_node->getName()!="quad")
{ {
Log::warn("Quad Graph: Unsupported node type '%s' found in '%s' - ignored.", Log::warn("DriveGraph: Unsupported node type '%s' found in '%s' - ignored.",
xml_node->getName().c_str(), filename.c_str()); xml_node->getName().c_str(), filename.c_str());
continue; continue;
} }
@ -182,11 +121,10 @@ void QuadGraph::load(const std::string &quad_file_name,
xml_node->get("invisible", &invisible); xml_node->get("invisible", &invisible);
bool ai_ignore=false; bool ai_ignore=false;
xml_node->get("ai-ignore", &ai_ignore); xml_node->get("ai-ignore", &ai_ignore);
GraphNode* node = createQuad(p0, p1, p2, p3, m_all_nodes.size(), invisible, ai_ignore,
createNode(p0, p1, p2, p3, m_all_nodes.size(), invisible, ai_ignore); false/*is_arena*/);
m_max.max(p0);m_max.max(p1);m_max.max(p2);m_max.max(p3); m_bb_max.max(p0);m_bb_max.max(p1);m_bb_max.max(p2);m_bb_max.max(p3);
m_min.min(p0);m_min.min(p1);m_min.min(p2);m_min.min(p3); m_bb_min.min(p0);m_bb_min.min(p1);m_bb_min.min(p2);m_bb_min.min(p3);
m_all_nodes.push_back(node);
} }
delete quad; delete quad;
@ -201,12 +139,12 @@ void QuadGraph::load(const std::string &quad_file_name,
if (m_all_nodes.size() > 0) if (m_all_nodes.size() > 0)
{ {
m_lap_length = m_all_nodes[m_all_nodes.size()-1]->getDistanceFromStart() m_lap_length = getNode(m_all_nodes.size()-1)->getDistanceFromStart()
+ m_all_nodes[m_all_nodes.size()-1]->getDistanceToSuccessor(0); + getNode(m_all_nodes.size()-1)->getDistanceToSuccessor(0);
} }
else else
{ {
Log::error("Quad Graph", "No node in driveline graph."); Log::error("DriveGraph", "No node in driveline graph.");
m_lap_length = 10.0f; m_lap_length = 10.0f;
} }
@ -265,7 +203,7 @@ void QuadGraph::load(const std::string &quad_file_name,
} // edge } // edge
else else
{ {
Log::error("Quad Graph", "Incorrect specification in '%s': '%s' ignored.", Log::error("DriveGraph", "Incorrect specification in '%s': '%s' ignored.",
filename.c_str(), xml_node->getName().c_str()); filename.c_str(), xml_node->getName().c_str());
continue; continue;
} // incorrect specification } // incorrect specification
@ -281,8 +219,8 @@ void QuadGraph::load(const std::string &quad_file_name,
m_lap_length = -1; m_lap_length = -1;
for(unsigned int i=0; i<m_all_nodes.size(); i++) for(unsigned int i=0; i<m_all_nodes.size(); i++)
{ {
float l = m_all_nodes[i]->getDistanceFromStart() float l = getNode(i)->getDistanceFromStart()
+ m_all_nodes[i]->getDistanceToSuccessor(0); + getNode(i)->getDistanceToSuccessor(0);
if(l > m_lap_length) if(l > m_lap_length)
m_lap_length = l; m_lap_length = l;
} }
@ -296,18 +234,18 @@ void QuadGraph::load(const std::string &quad_file_name,
* but in reverse mode (where node 0 is actually the end of the track) * but in reverse mode (where node 0 is actually the end of the track)
* this is 0's successor. * this is 0's successor.
*/ */
unsigned int QuadGraph::getStartNode() const unsigned int DriveGraph::getStartNode() const
{ {
return m_reverse ? m_all_nodes[0]->getSuccessor(0) return m_reverse ? getNode(0)->getSuccessor(0)
: 0; : 0;
} // getStartNode } // getStartNode
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Sets the checkline requirements for all nodes in the graph. /** Sets the checkline requirements for all nodes in the graph.
*/ */
void QuadGraph::computeChecklineRequirements() void DriveGraph::computeChecklineRequirements()
{ {
computeChecklineRequirements(m_all_nodes[0], computeChecklineRequirements(getNode(0),
CheckManager::get()->getLapLineIndex()); CheckManager::get()->getLapLineIndex());
} // computeChecklineRequirements } // computeChecklineRequirements
@ -315,8 +253,8 @@ void QuadGraph::computeChecklineRequirements()
/** Finds which checklines must be visited before driving on this quad /** Finds which checklines must be visited before driving on this quad
* (useful for rescue) * (useful for rescue)
*/ */
void QuadGraph::computeChecklineRequirements(GraphNode* node, void DriveGraph::computeChecklineRequirements(DriveNode* node,
int latest_checkline) int latest_checkline)
{ {
for (unsigned int n=0; n<node->getNumberOfSuccessors(); n++) for (unsigned int n=0; n<node->getNumberOfSuccessors(); n++)
{ {
@ -325,7 +263,7 @@ void QuadGraph::computeChecklineRequirements(GraphNode* node,
// warp-around // warp-around
if (succ_id == 0) break; if (succ_id == 0) break;
GraphNode* succ = m_all_nodes[succ_id]; DriveNode* succ = getNode(succ_id);
int new_latest_checkline = int new_latest_checkline =
CheckManager::get()->getChecklineTriggering(node->getCenter(), CheckManager::get()->getChecklineTriggering(node->getCenter(),
succ->getCenter() ); succ->getCenter() );
@ -363,11 +301,11 @@ void QuadGraph::computeChecklineRequirements(GraphNode* node,
* (since on other graph nodes only one path can be used anyway, this * (since on other graph nodes only one path can be used anyway, this
* saves some memory). * saves some memory).
*/ */
void QuadGraph::setupPaths() void DriveGraph::setupPaths()
{ {
for(unsigned int i=0; i<getNumNodes(); i++) for(unsigned int i=0; i<getNumNodes(); i++)
{ {
m_all_nodes[i]->setupPathsToNode(); getNode(i)->setupPathsToNode();
} }
} // setupPaths } // setupPaths
@ -375,18 +313,18 @@ void QuadGraph::setupPaths()
/** This function sets a default successor for all graph nodes that currently /** This function sets a default successor for all graph nodes that currently
* don't have a successor defined. The default successor of node X is X+1. * don't have a successor defined. The default successor of node X is X+1.
*/ */
void QuadGraph::setDefaultSuccessors() void DriveGraph::setDefaultSuccessors()
{ {
for(unsigned int i=0; i<m_all_nodes.size(); i++) { for(unsigned int i=0; i<m_all_nodes.size(); i++) {
if(m_all_nodes[i]->getNumberOfSuccessors()==0) { if(getNode(i)->getNumberOfSuccessors()==0) {
addSuccessor(i,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); //~ getNode(i)->addSuccessor(i+1>=m_all_nodes.size() ? 0 : i+1);
} // if size==0 } // if size==0
} // for i<m_allNodes.size() } // for i<m_allNodes.size()
} // setDefaultSuccessors } // setDefaultSuccessors
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
/** Sets all start positions depending on the quad graph. The number of /** Sets all start positions depending on the drive graph. The number of
* entries needed is defined by the size of the start_transform (though all * entries needed is defined by the size of the start_transform (though all
* entries will be overwritten). * entries will be overwritten).
* E.g. the karts will be placed as: * E.g. the karts will be placed as:
@ -406,17 +344,17 @@ void QuadGraph::setDefaultSuccessors()
* \param sidewards_distance Distance in sidewards (X) direction between * \param sidewards_distance Distance in sidewards (X) direction between
* karts. * karts.
*/ */
void QuadGraph::setDefaultStartPositions(AlignedArray<btTransform> void DriveGraph::setDefaultStartPositions(AlignedArray<btTransform>
*start_transforms, *start_transforms,
unsigned int karts_per_row, unsigned int karts_per_row,
float forwards_distance, float forwards_distance,
float sidewards_distance, float sidewards_distance,
float upwards_distance) const float upwards_distance) const
{ {
// We start just before the start node (which will trigger lap // We start just before the start node (which will trigger lap
// counting when reached). The first predecessor is the one on // counting when reached). The first predecessor is the one on
// the main driveline. // the main driveline.
int current_node = m_all_nodes[getStartNode()]->getPredecessor(0); int current_node = getNode(getStartNode())->getPredecessor(0);
float distance_from_start = 0.1f+forwards_distance; float distance_from_start = 0.1f+forwards_distance;
@ -443,14 +381,14 @@ void QuadGraph::setDefaultStartPositions(AlignedArray<btTransform>
// Only follow the main driveline, i.e. first predecessor // Only follow the main driveline, i.e. first predecessor
current_node = getNode(current_node)->getPredecessor(0); current_node = getNode(current_node)->getPredecessor(0);
} }
const GraphNode* gn = getNode(current_node); const DriveNode* dn = getNode(current_node);
Vec3 center_line = gn->getLowerCenter() - gn->getUpperCenter(); Vec3 center_line = dn->getLowerCenter() - dn->getUpperCenter();
center_line.normalize(); center_line.normalize();
Vec3 horizontal_line = (*gn)[2] - (*gn)[3]; Vec3 horizontal_line = (*dn)[2] - (*dn)[3];
horizontal_line.normalize(); horizontal_line.normalize();
Vec3 start = gn->getUpperCenter() Vec3 start = dn->getUpperCenter()
+ center_line * distance_from_start + center_line * distance_from_start
+ horizontal_line * x_pos; + horizontal_line * x_pos;
// Add a certain epsilon to the height in case that the // Add a certain epsilon to the height in case that the
@ -458,7 +396,7 @@ void QuadGraph::setDefaultStartPositions(AlignedArray<btTransform>
(*start_transforms)[i].setOrigin(start+Vec3(0,upwards_distance,0)); (*start_transforms)[i].setOrigin(start+Vec3(0,upwards_distance,0));
(*start_transforms)[i].setRotation( (*start_transforms)[i].setRotation(
btQuaternion(btVector3(0, 1, 0), btQuaternion(btVector3(0, 1, 0),
gn->getAngleToSuccessor(0))); dn->getAngleToSuccessor(0)));
if(x_pos >= max_x_dist-sidewards_distance*0.5f) if(x_pos >= max_x_dist-sidewards_distance*0.5f)
{ {
x_pos = -max_x_dist; x_pos = -max_x_dist;
@ -482,17 +420,17 @@ void QuadGraph::setDefaultStartPositions(AlignedArray<btTransform>
* \param succ A vector of ints to which the successors are added. * \param succ A vector of ints to which the successors are added.
* \param for_ai true if only quads accessible by the AI should be returned. * \param for_ai true if only quads accessible by the AI should be returned.
*/ */
void QuadGraph::getSuccessors(int node_number, void DriveGraph::getSuccessors(int node_number,
std::vector<unsigned int>& succ, std::vector<unsigned int>& succ,
bool for_ai) const bool for_ai) const
{ {
const GraphNode *gn=m_all_nodes[node_number]; const DriveNode *dn=getNode(node_number);
for(unsigned int i=0; i<gn->getNumberOfSuccessors(); i++) for(unsigned int i=0; i<dn->getNumberOfSuccessors(); i++)
{ {
// If getSuccessor is called for the AI, only add // If getSuccessor is called for the AI, only add
// quads that are meant for the AI to be used. // quads that are meant for the AI to be used.
if(!for_ai || !gn->ignoreSuccessorForAI(i)) if(!for_ai || !dn->ignoreSuccessorForAI(i))
succ.push_back(gn->getSuccessor(i)); succ.push_back(dn->getSuccessor(i));
} }
} // getSuccessors } // getSuccessors
@ -502,10 +440,10 @@ void QuadGraph::getSuccessors(int node_number,
* \param node The node index for which to set the distance from start. * \param node The node index for which to set the distance from start.
* \param new_distance The new distance for the specified graph node. * \param new_distance The new distance for the specified graph node.
*/ */
void QuadGraph::computeDistanceFromStart(unsigned int node, float new_distance) void DriveGraph::computeDistanceFromStart(unsigned int node, float new_distance)
{ {
GraphNode *gn = m_all_nodes[node]; DriveNode *dn = getNode(node);
float current_distance = gn->getDistanceFromStart(); float current_distance = dn->getDistanceFromStart();
// If this node already has a distance defined, check if the new distance // 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 // is longer, and if so adjust all following nodes. Without this the
@ -519,25 +457,25 @@ void QuadGraph::computeDistanceFromStart(unsigned int node, float new_distance)
if(current_distance<new_distance) if(current_distance<new_distance)
{ {
float delta = new_distance - current_distance; float delta = new_distance - current_distance;
updateDistancesForAllSuccessors(gn->getNodeIndex(), delta, 0); updateDistancesForAllSuccessors(dn->getIndex(), delta, 0);
} }
return; return;
} }
// Otherwise this node has no distance defined yet. Set the new // Otherwise this node has no distance defined yet. Set the new
// distance, and recursively update all following nodes. // distance, and recursively update all following nodes.
gn->setDistanceFromStart(new_distance); dn->setDistanceFromStart(new_distance);
for(unsigned int i=0; i<gn->getNumberOfSuccessors(); i++) for(unsigned int i=0; i<dn->getNumberOfSuccessors(); i++)
{ {
GraphNode *gn_next = m_all_nodes[gn->getSuccessor(i)]; DriveNode *dn_next = getNode(dn->getSuccessor(i));
// The start node (only node with distance 0) is reached again, // The start node (only node with distance 0) is reached again,
// recursion can stop now // recursion can stop now
if(gn_next->getDistanceFromStart()==0) if(dn_next->getDistanceFromStart()==0)
continue; continue;
computeDistanceFromStart(gn_next->getNodeIndex(), computeDistanceFromStart(dn_next->getIndex(),
new_distance + gn->getDistanceToSuccessor(i)); new_distance + dn->getDistanceToSuccessor(i));
} // for i } // for i
} // computeDistanceFromStart } // computeDistanceFromStart
@ -551,35 +489,35 @@ void QuadGraph::computeDistanceFromStart(unsigned int node, float new_distance)
* \param recursive_count Counts how often this function was called * \param recursive_count Counts how often this function was called
* recursively in order to catch incorrect graphs that contain loops. * recursively in order to catch incorrect graphs that contain loops.
*/ */
void QuadGraph::updateDistancesForAllSuccessors(unsigned int indx, float delta, void DriveGraph::updateDistancesForAllSuccessors(unsigned int indx, float delta,
unsigned int recursive_count) unsigned int recursive_count)
{ {
if(recursive_count>getNumNodes()) if(recursive_count>getNumNodes())
{ {
Log::error("QuadGraph", Log::error("DriveGraph",
"Quad graph contains a loop (without start node)."); "DriveGraph contains a loop (without start node).");
Log::fatal("QuadGraph", Log::fatal("DriveGraph",
"Fix graph, check for directions of all shortcuts etc."); "Fix graph, check for directions of all shortcuts etc.");
} }
recursive_count++; recursive_count++;
GraphNode* g = getNode(indx); DriveNode* dn = getNode(indx);
g->setDistanceFromStart(g->getDistanceFromStart()+delta); dn->setDistanceFromStart(dn->getDistanceFromStart()+delta);
for(unsigned int i=0; i<g->getNumberOfSuccessors(); i++) for(unsigned int i=0; i<dn->getNumberOfSuccessors(); i++)
{ {
GraphNode* g_next = getNode(g->getSuccessor(i)); DriveNode* dn_next = getNode(dn->getSuccessor(i));
// Stop when we reach the start node, i.e. the only node with a // Stop when we reach the start node, i.e. the only node with a
// distance of 0 // distance of 0
if(g_next->getDistanceFromStart()==0) if(dn_next->getDistanceFromStart()==0)
continue; continue;
// Only increase the distance from start of a successor node, if // Only increase the distance from start of a successor node, if
// this successor has a distance from start that is smaller then // this successor has a distance from start that is smaller then
// the increased amount. // the increased amount.
if(g->getDistanceFromStart()+g->getDistanceToSuccessor(i) > if(dn->getDistanceFromStart()+dn->getDistanceToSuccessor(i) >
g_next->getDistanceFromStart()) dn_next->getDistanceFromStart())
{ {
updateDistancesForAllSuccessors(g->getSuccessor(i), delta, updateDistancesForAllSuccessors(dn->getSuccessor(i), delta,
recursive_count); recursive_count);
} }
} }
@ -600,12 +538,12 @@ void QuadGraph::updateDistancesForAllSuccessors(unsigned int indx, float delta,
* its data constantly, i.e. if it takes a different turn, it will be using * its data constantly, i.e. if it takes a different turn, it will be using
* the new data). * the new data).
*/ */
void QuadGraph::computeDirectionData() void DriveGraph::computeDirectionData()
{ {
for(unsigned int i=0; i<m_all_nodes.size(); i++) for(unsigned int i=0; i<m_all_nodes.size(); i++)
{ {
for(unsigned int succ_index=0; for(unsigned int succ_index=0;
succ_index<m_all_nodes[i]->getNumberOfSuccessors(); succ_index<getNode(i)->getNumberOfSuccessors();
succ_index++) succ_index++)
{ {
determineDirection(i, succ_index); determineDirection(i, succ_index);
@ -617,14 +555,14 @@ void QuadGraph::computeDirectionData()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Adjust the given angle to be in [-PI, PI]. /** Adjust the given angle to be in [-PI, PI].
*/ */
float QuadGraph::normalizeAngle(float f) float DriveGraph::normalizeAngle(float f)
{ {
if(f>M_PI) f -= 2*M_PI; if(f>M_PI) f -= 2*M_PI;
else if(f<-M_PI) f += 2*M_PI; else if(f<-M_PI) f += 2*M_PI;
return f; return f;
} // normalizeAngle } // normalizeAngle
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Determines the direction of the quad graph when driving to the specified /** Determines the direction of the drive graph when driving to the specified
* successor. It also determines the last graph node that is still following * successor. It also determines the last graph node that is still following
* the given direction. The computed data is saved in the corresponding * the given direction. The computed data is saved in the corresponding
* graph node. * graph node.
@ -640,8 +578,8 @@ float QuadGraph::normalizeAngle(float f)
* If there should be any other branches later, successor * If there should be any other branches later, successor
* 0 will always be tetsed. * 0 will always be tetsed.
*/ */
void QuadGraph::determineDirection(unsigned int current, void DriveGraph::determineDirection(unsigned int current,
unsigned int succ_index) unsigned int succ_index)
{ {
// The maximum angle which is still considered to be straight // The maximum angle which is still considered to be straight
const float max_straight_angle=0.1f; const float max_straight_angle=0.1f;
@ -681,11 +619,11 @@ void QuadGraph::determineDirection(unsigned int current,
next = getNode(next)->getSuccessor(0); next = getNode(next)->getSuccessor(0);
} // while(1) } // while(1)
GraphNode::DirectionType dir = DriveNode::DirectionType dir =
rel_angle==0 ? GraphNode::DIR_STRAIGHT rel_angle==0 ? DriveNode::DIR_STRAIGHT
: (rel_angle>0) ? GraphNode::DIR_RIGHT : (rel_angle>0) ? DriveNode::DIR_RIGHT
: GraphNode::DIR_LEFT; : DriveNode::DIR_LEFT;
m_all_nodes[current]->setDirectionData(succ_index, dir, next); getNode(current)->setDirectionData(succ_index, dir, next);
} // determineDirection } // determineDirection
@ -699,12 +637,12 @@ void QuadGraph::determineDirection(unsigned int current,
* \param xyz The position of the kart. * \param xyz The position of the kart.
* \param sector The graph node the position is on. * \param sector The graph node the position is on.
*/ */
void QuadGraph::spatialToTrack(Vec3 *dst, const Vec3& xyz, void DriveGraph::spatialToTrack(Vec3 *dst, const Vec3& xyz,
const int sector) const const int sector) const
{ {
if(sector == UNKNOWN_SECTOR ) if(sector == UNKNOWN_SECTOR )
{ {
Log::warn("Quad Graph", "UNKNOWN_SECTOR in spatialToTrack()."); Log::warn("Drive Graph", "UNKNOWN_SECTOR in spatialToTrack().");
return; return;
} }
@ -712,215 +650,47 @@ void QuadGraph::spatialToTrack(Vec3 *dst, const Vec3& xyz,
} // spatialToTrack } // spatialToTrack
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** findRoadSector returns in which sector on the road the position float DriveGraph::getDistanceToNext(int n, int j) const
* xyz is. If xyz is not on top of the road, it sets UNKNOWN_SECTOR as sector.
*
* \param xyz Position for which the segment should be determined.
* \param sector Contains the previous sector (as a shortcut, since usually
* the sector is the same as the last one), and on return the result
* \param all_sectors If this is not NULL, it is a list of all sectors to
* test. This is used by the AI to make sure that it ends up on the
* selected way in case of a branch, and also to make sure that it
* doesn't skip e.g. a loop (see explanation below for details).
*/
void QuadGraph::findRoadSector(const Vec3& xyz, int *sector,
std::vector<int> *all_sectors) const
{ {
// Most likely the kart will still be on the sector it was before, return getNode(n)->getDistanceToSuccessor(j);
// so this simple case is tested first.
if(*sector!=UNKNOWN_SECTOR && getNode(*sector)->pointInside(xyz) )
{
return;
} // if still on same quad
// Now we search through all graph nodes, starting with
// the current one
int indx = *sector;
// If a current sector is given, and max_lookahead is specify, only test
// the next max_lookahead graph nodes instead of testing the whole graph.
// This is necessary for the AI: if the track contains a loop, e.g.:
// -A--+---B---+----F--------
// E C
// +---D---+
// and the track is supposed to be driven: ABCDEBF, the AI might find
// the node on F, and then keep on going straight ahead instead of
// using the loop at all.
unsigned int max_count = (*sector!=UNKNOWN_SECTOR && all_sectors!=NULL)
? (unsigned int)all_sectors->size()
: (unsigned int)m_all_nodes.size();
*sector = UNKNOWN_SECTOR;
for(unsigned int i=0; i<max_count; i++)
{
if(all_sectors)
indx = (*all_sectors)[i];
else
indx = indx<(int)m_all_nodes.size()-1 ? indx +1 : 0;
const GraphNode* gn = getNode(indx);
if(gn->pointInside(xyz))
{
*sector = indx;
}
} // for i<m_all_nodes.size()
return;
} // findRoadSector
//-----------------------------------------------------------------------------
/** 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.
*/
int QuadGraph::findOutOfRoadSector(const Vec3& xyz,
const int curr_sector,
std::vector<int> *all_sectors) const
{
int count = (all_sectors!=NULL) ? (int) all_sectors->size() : getNumNodes();
int current_sector = 0;
if(curr_sector != UNKNOWN_SECTOR && !all_sectors)
{
// We have to test all nodes here: reason is that on track with
// shortcuts the n quads of the main drivelines is followed by
// the quads of the shortcuts. So after quad n-1 (the last one
// before the lap counting line) quad n will not be 0 (the first
// quad after the lap counting line), but one of the quads on a
// shortcut. If we only tested a limited number of quads to
// improve the performance the crossing of a lap might not be
// detected (because quad 0 is not tested, only quads on the
// shortcuts are tested). If this should become a performance
// bottleneck, we need to set up a graph of 'next' quads for each
// quad (similar to what the AI does), and only test the quads
// in this graph.
const int LIMIT = getNumNodes();
count = LIMIT;
// Start 10 quads before the current quad, so the quads closest
// to the current position are tested first.
current_sector = curr_sector -10;
if(current_sector<0) current_sector += getNumNodes();
}
int min_sector = UNKNOWN_SECTOR;
float min_dist_2 = 999999.0f*999999.0f;
// If a kart is falling and in between (or too far below)
// a driveline point it might not fulfill
// the height condition. So we run the test twice: first with height
// condition, then again without the height condition - just to make sure
// it always comes back with some kind of quad.
for(int phase=0; phase<2; phase++)
{
for(int j=0; j<count; j++)
{
int next_sector;
if(all_sectors)
next_sector = (*all_sectors)[j];
else
next_sector = current_sector+1 == (int)getNumNodes()
? 0
: current_sector+1;
// A first simple test uses the 2d distance to the center of the quad.
float dist_2 = m_all_nodes[next_sector]->getDistance2FromPoint(xyz);
if(dist_2<min_dist_2)
{
const GraphNode* gn = getNode(next_sector);
const bool is_3d = (dynamic_cast<const Node3D*>(gn) != NULL);
float dist = xyz.getY() - gn->getMinHeight();
// While negative distances are unlikely, we allow some small
// negative numbers in case that the kart is partly in the
// track. Only do the height test in phase==0, in phase==1
// accept any point, independent of height, or this node is 3d
// which already takes height into account
if(phase==1 || (dist < 5.0f && dist>-1.0f) || is_3d)
{
min_dist_2 = dist_2;
min_sector = next_sector;
}
}
current_sector = next_sector;
} // for j
// Leave in phase 0 if any sector was found.
if(min_sector!=UNKNOWN_SECTOR)
return min_sector;
} // phase
if(min_sector==UNKNOWN_SECTOR )
{
Log::info("Quad Graph", "unknown sector found.");
}
return min_sector;
} // findOutOfRoadSector
//-----------------------------------------------------------------------------
void QuadGraph::set3DVerticesOfGraph(int i, video::S3DVertex *v,
const video::SColor &color) const
{
m_all_nodes[i]->getVertices(v, color);
} // set3DVerticesOfGraph
//-----------------------------------------------------------------------------
const bool QuadGraph::isNodeInvisible(int n) const
{
return m_all_nodes[n]->isInvisible();
} // isNodeInvisible
//-----------------------------------------------------------------------------
float QuadGraph::getDistanceToNext(int n, int j) const
{
return m_all_nodes[n]->getDistanceToSuccessor(j);
} // getDistanceToNext } // getDistanceToNext
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
float QuadGraph::getAngleToNext(int n, int j) const float DriveGraph::getAngleToNext(int n, int j) const
{ {
return m_all_nodes[n]->getAngleToSuccessor(j); return getNode(n)->getAngleToSuccessor(j);
} // getAngleToNext } // getAngleToNext
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
int QuadGraph::getNumberOfSuccessors(int n) const int DriveGraph::getNumberOfSuccessors(int n) const
{ {
return m_all_nodes[n]->getNumberOfSuccessors(); return getNode(n)->getNumberOfSuccessors();
} // getNumberOfSuccessors } // getNumberOfSuccessors
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
float QuadGraph::getDistanceFromStart(int j) const float DriveGraph::getDistanceFromStart(int j) const
{ {
return m_all_nodes[j]->getDistanceFromStart(); return getNode(j)->getDistanceFromStart();
} // getDistanceFromStart } // getDistanceFromStart
//----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
const bool QuadGraph::differentNodeColor(int n, NodeColor* c) const void DriveGraph::differentNodeColor(int n, video::SColor* c) const
{ {
if (UserConfigParams::m_track_debug) if (UserConfigParams::m_track_debug)
{ {
if (dynamic_cast<Node3D*>(m_all_nodes[n]) != NULL) if (getNode(n)->is3DQuad())
*c = COLOR_GREEN; *c = video::SColor(255, 0, 255, 0);
else else
*c = COLOR_YELLOW; *c = video::SColor(255, 255, 255, 0);
return true;
} }
return n == 0;
} // differentNodeColor } // differentNodeColor
// -----------------------------------------------------------------------------
DriveNode* DriveGraph::getNode(unsigned int j) const
{
assert(j < m_all_nodes.size());
DriveNode* n = dynamic_cast<DriveNode*>(m_all_nodes[j]);
assert(n != NULL);
return n;
} // getNode

125
src/tracks/drive_graph.hpp Normal file
View File

@ -0,0 +1,125 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, B
#ifndef HEADER_DRIVE_GRAPH_HPP
#define HEADER_DRIVE_GRAPH_HPP
#include <vector>
#include <string>
#include "tracks/graph.hpp"
#include "utils/aligned_array.hpp"
#include "utils/cpp2011.hpp"
#include "LinearMath/btTransform.h"
class DriveNode;
class XMLNode;
/**
* \brief A graph made from driveline
* \ingroup tracks
*/
class DriveGraph : public Graph
{
private:
/** The length of the first loop. */
float m_lap_length;
/** 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 computeChecklineRequirements(DriveNode* node, int latest_checkline);
// ------------------------------------------------------------------------
void computeDirectionData();
// ------------------------------------------------------------------------
void determineDirection(unsigned int current, unsigned int succ_index);
// ------------------------------------------------------------------------
float normalizeAngle(float f);
// ------------------------------------------------------------------------
void addSuccessor(unsigned int from, unsigned int to);
// ------------------------------------------------------------------------
void load(const std::string &quad_file_name, const std::string &filename);
// ------------------------------------------------------------------------
void getPoint(const XMLNode *xml, const std::string &attribute_name,
Vec3 *result) const;
// ------------------------------------------------------------------------
void computeDistanceFromStart(unsigned int start_node, float distance);
// ------------------------------------------------------------------------
unsigned int getStartNode() const;
// ------------------------------------------------------------------------
virtual bool hasLapLine() const OVERRIDE { return true; }
// ------------------------------------------------------------------------
virtual void differentNodeColor(int n, video::SColor* c) const OVERRIDE;
public:
static DriveGraph* get() { return dynamic_cast<DriveGraph*>(m_graph); }
// ------------------------------------------------------------------------
DriveGraph(const std::string &quad_file_name,
const std::string &graph_file_name, const bool reverse);
// ------------------------------------------------------------------------
virtual ~DriveGraph() {}
// ------------------------------------------------------------------------
void getSuccessors(int node_number, std::vector<unsigned int>& succ,
bool for_ai=false) const;
// ------------------------------------------------------------------------
void spatialToTrack(Vec3 *dst, const Vec3& xyz, const int sector) const;
// ------------------------------------------------------------------------
void setDefaultStartPositions(AlignedArray<btTransform> *start_transforms,
unsigned int karts_per_row,
float forwards_distance = 1.5f,
float sidewards_distance = 1.5f,
float upwards_distance=0.0f) const;
// ------------------------------------------------------------------------
void updateDistancesForAllSuccessors(unsigned int indx, float delta,
unsigned int count);
// ------------------------------------------------------------------------
void setupPaths();
// ------------------------------------------------------------------------
void computeChecklineRequirements();
// ------------------------------------------------------------------------
/** Return the distance to the j-th successor of node n. */
float getDistanceToNext(int n, int j) const;
// ------------------------------------------------------------------------
/** Returns the angle of the line between node n and its j-th.
* successor. */
float getAngleToNext(int n, int j) const;
// ------------------------------------------------------------------------
/** Returns the number of successors of a node n. */
int getNumberOfSuccessors(int n) const;
// ------------------------------------------------------------------------
/** Returns the quad that belongs to a graph node. */
DriveNode* getNode(unsigned int j) const;
// ------------------------------------------------------------------------
/** Returns the distance from the start to the beginning of a quad. */
float getDistanceFromStart(int j) const;
// ------------------------------------------------------------------------
/** Returns the length of the main driveline. */
float getLapLength() const { return m_lap_length; }
// ------------------------------------------------------------------------
bool isReverse() const { return m_reverse; }
}; // DriveGraph
#endif

View File

@ -16,25 +16,22 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, B // Foundation, Inc., 59 Temple Place - Suite 330, B
#include "tracks/graph_node.hpp" #include "tracks/drive_node.hpp"
#include "io/file_manager.hpp" #include "io/file_manager.hpp"
#include "io/xml_node.hpp" #include "io/xml_node.hpp"
#include "matrix4.h" #include "matrix4.h"
#include "tracks/quad_graph.hpp" #include "tracks/drive_graph.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
GraphNode::GraphNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, DriveNode::DriveNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
const Vec3 &p3, const Vec3 &normal, const Vec3 &p3, const Vec3 &normal,
unsigned int node_index, bool invisible, unsigned int node_index, bool invisible,
bool ai_ignore) bool ai_ignore)
:Quad(p0, p1, p2, p3) :Quad(p0, p1, p2, p3, normal, node_index, invisible)
{ {
m_invisible = invisible;
m_ai_ignore = ai_ignore; m_ai_ignore = ai_ignore;
m_normal = normal;
m_node_index = node_index;
m_distance_from_start = -1.0f; m_distance_from_start = -1.0f;
// The following values should depend on the actual orientation // The following values should depend on the actual orientation
@ -48,7 +45,7 @@ GraphNode::GraphNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
m_width = ( (m_p[1]-m_p[0]).length() m_width = ( (m_p[1]-m_p[0]).length()
+ (m_p[3]-m_p[2]).length() ) * 0.5f; + (m_p[3]-m_p[2]).length() ) * 0.5f;
if(QuadGraph::get()->isReverse()) if(DriveGraph::get()->isReverse())
{ {
m_lower_center = (m_p[2]+m_p[3]) * 0.5f; m_lower_center = (m_p[2]+m_p[3]) * 0.5f;
m_upper_center = (m_p[0]+m_p[1]) * 0.5f; m_upper_center = (m_p[0]+m_p[1]) * 0.5f;
@ -60,53 +57,53 @@ GraphNode::GraphNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
m_upper_center = (m_p[2]+m_p[3]) * 0.5f; m_upper_center = (m_p[2]+m_p[3]) * 0.5f;
} }
} // GraphNode } // DriveNode
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Adds a successor to a node. This function will also pre-compute certain /** Adds a successor to a node. This function will also pre-compute certain
* values (like distance from this node to the successor, angle (in world) * values (like distance from this node to the successor, angle (in world)
* between this node and the successor. * between this node and the successor.
* \param to The index of the graph node of the successor. * \param to The index of the drive node of the successor.
*/ */
void GraphNode::addSuccessor(unsigned int to) void DriveNode::addSuccessor(unsigned int to)
{ {
m_successor_nodes.push_back(to); m_successor_nodes.push_back(to);
// to is the graph node // to is the drive node
GraphNode* gn_to = QuadGraph::get()->getNode(to); DriveNode* dn_to = DriveGraph::get()->getNode(to);
// Note that the first predecessor is (because of the way the quad graph // Note that the first predecessor is (because of the way the drive graph
// is exported) the most 'natural' one, i.e. the one on the main // is exported) the most 'natural' one, i.e. the one on the main
// driveline. // driveline.
gn_to->m_predecessor_nodes.push_back(m_node_index); dn_to->m_predecessor_nodes.push_back(m_index);
Vec3 d = m_lower_center - gn_to->m_lower_center; Vec3 d = m_lower_center - dn_to->m_lower_center;
m_distance_to_next.push_back(d.length()); m_distance_to_next.push_back(d.length());
Vec3 diff = gn_to->getCenter() - getCenter(); Vec3 diff = dn_to->getCenter() - getCenter();
core::CMatrix4<float> m; core::CMatrix4<float> m;
m.buildRotateFromTo(getNormal().toIrrVector(), m.buildRotateFromTo(getNormal().toIrrVector(),
Vec3(0, 1, 0).toIrrVector()); Vec3(0, 1, 0).toIrrVector());
core::vector3df diffRotated; core::vector3df diff_rotated;
m.rotateVect(diffRotated, diff.toIrrVector()); m.rotateVect(diff_rotated, diff.toIrrVector());
m_angle_to_next.push_back(atan2(diffRotated.X, diffRotated.Z)); m_angle_to_next.push_back(atan2(diff_rotated.X, diff_rotated.Z));
} // addSuccessor } // addSuccessor
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** If this node has more than one successor, it will set up a vector that /** If this node has more than one successor, it will set up a vector that
* contains the direction to use when a certain graph node X should be * contains the direction to use when a certain drive node X should be
* reached. * reached.
*/ */
void GraphNode::setupPathsToNode() void DriveNode::setupPathsToNode()
{ {
if(m_successor_nodes.size()<2) return; if(m_successor_nodes.size()<2) return;
const unsigned int num_nodes = QuadGraph::get()->getNumNodes(); const unsigned int num_nodes = DriveGraph::get()->getNumNodes();
m_path_to_node.resize(num_nodes); m_path_to_node.resize(num_nodes);
// Initialise each graph node with -1, indicating that // Initialise each drive node with -1, indicating that
// it hasn't been reached yet. // it hasn't been reached yet.
for(unsigned int i=0; i<num_nodes; i++) for(unsigned int i=0; i<num_nodes; i++)
m_path_to_node[i] = -1; m_path_to_node[i] = -1;
@ -114,24 +111,24 @@ void GraphNode::setupPathsToNode()
// Indicate that this node can be reached from this node by following // Indicate that this node can be reached from this node by following
// successor 0 - just a dummy value that might only be used during the // successor 0 - just a dummy value that might only be used during the
// recursion below. // recursion below.
m_path_to_node[m_node_index] = 0; m_path_to_node[m_index] = 0;
// A simple depth first search is used to determine which successor to // A simple depth first search is used to determine which successor to
// use to reach a certain graph node. Using Dijkstra's algorithm would // use to reach a certain drive node. Using Dijkstra's algorithm would
// give the shortest way to reach a certain node, but the shortest way // give the shortest way to reach a certain node, but the shortest way
// might involve some shortcuts which are hidden, and should therefore // might involve some shortcuts which are hidden, and should therefore
// not be used. // not be used.
for(unsigned int i=0; i<getNumberOfSuccessors(); i++) for(unsigned int i=0; i<getNumberOfSuccessors(); i++)
{ {
GraphNode* gn = QuadGraph::get()->getNode(getSuccessor(i)); DriveNode* dn = DriveGraph::get()->getNode(getSuccessor(i));
gn->markAllSuccessorsToUse(i, &m_path_to_node); dn->markAllSuccessorsToUse(i, &m_path_to_node);
} }
#ifdef DEBUG #ifdef DEBUG
for(unsigned int i = 0; i < m_path_to_node.size(); ++i) for(unsigned int i = 0; i < m_path_to_node.size(); ++i)
{ {
if(m_path_to_node[i] == -1) if(m_path_to_node[i] == -1)
Log::warn("GraphNode", "No path to node %d found on graph node %d.", Log::warn("DriveNode", "No path to node %d found on drive node %d.",
i, m_node_index); i, m_index);
} }
#endif #endif
} // setupPathsToNode } // setupPathsToNode
@ -145,22 +142,22 @@ void GraphNode::setupPathsToNode()
* \param path_to_node The path-to-node data structure of the node for * \param path_to_node The path-to-node data structure of the node for
* which the paths are currently determined. * which the paths are currently determined.
*/ */
void GraphNode::markAllSuccessorsToUse(unsigned int n, void DriveNode::markAllSuccessorsToUse(unsigned int n,
PathToNodeVector *path_to_node) PathToNodeVector *path_to_node)
{ {
// End recursion if the path to this node has already been found. // End recursion if the path to this node has already been found.
if( (*path_to_node)[m_node_index] >-1) return; if( (*path_to_node)[m_index] >-1) return;
(*path_to_node)[m_node_index] = n; (*path_to_node)[m_index] = n;
for(unsigned int i=0; i<getNumberOfSuccessors(); i++) for(unsigned int i=0; i<getNumberOfSuccessors(); i++)
{ {
GraphNode* gn = QuadGraph::get()->getNode(getSuccessor(i)); DriveNode* dn = DriveGraph::get()->getNode(getSuccessor(i));
gn->markAllSuccessorsToUse(n, path_to_node); dn->markAllSuccessorsToUse(n, path_to_node);
} }
} // markAllSuccesorsToUse } // markAllSuccesorsToUse
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void GraphNode::setDirectionData(unsigned int successor, DirectionType dir, void DriveNode::setDirectionData(unsigned int successor, DirectionType dir,
unsigned int last_node_index) unsigned int last_node_index)
{ {
if(m_direction.size()<successor+1) if(m_direction.size()<successor+1)
@ -173,7 +170,7 @@ void GraphNode::setDirectionData(unsigned int successor, DirectionType dir,
} // setDirectionData } // setDirectionData
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void GraphNode::setChecklineRequirements(int latest_checkline) void DriveNode::setChecklineRequirements(int latest_checkline)
{ {
m_checkline_requirements.push_back(latest_checkline); m_checkline_requirements.push_back(latest_checkline);
} // setChecklineRequirements } // setChecklineRequirements
@ -183,7 +180,7 @@ void GraphNode::setChecklineRequirements(int latest_checkline)
* is allowed to use. * is allowed to use.
* \param index Index of the successor. * \param index Index of the successor.
*/ */
bool GraphNode::ignoreSuccessorForAI(unsigned int i) const bool DriveNode::ignoreSuccessorForAI(unsigned int i) const
{ {
return QuadGraph::get()->getNode(m_successor_nodes[i])->letAIIgnore(); return DriveGraph::get()->getNode(m_successor_nodes[i])->letAIIgnore();
} // ignoreSuccessorForAI } // ignoreSuccessorForAI

View File

@ -16,19 +16,19 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, B // Foundation, Inc., 59 Temple Place - Suite 330, B
#ifndef HEADER_GRAPH_NODE_HPP #ifndef HEADER_DRIVE_NODE_HPP
#define HEADER_GRAPH_NODE_HPP #define HEADER_DRIVE_NODE_HPP
#include <vector> #include <vector>
#include "tracks/quad.hpp" #include "tracks/quad.hpp"
/** /**
* \brief This class stores a node of the graph, i.e. a list of successor * \brief This class stores a node of the drive graph, i.e. a list of
* edges, it can either be 2d or 3d. * successor edges, it can either be 2d or 3d.
* \ingroup tracks * \ingroup tracks
*/ */
class GraphNode : public Quad class DriveNode : public Quad
{ {
public: public:
/** To indiciate in which direction the track is going: /** To indiciate in which direction the track is going:
@ -37,29 +37,20 @@ public:
enum DirectionType {DIR_STRAIGHT, DIR_LEFT, DIR_RIGHT, enum DirectionType {DIR_STRAIGHT, DIR_LEFT, DIR_RIGHT,
DIR_UNDEFINED}; DIR_UNDEFINED};
protected: protected:
/** Lower center point of the graph node. */ /** Lower center point of the drive node. */
Vec3 m_lower_center; Vec3 m_lower_center;
/** Upper center point of the graph node. */ /** Upper center point of the drive node. */
Vec3 m_upper_center; Vec3 m_upper_center;
/** Distance from the start to the beginning of the graph node. */ /** Distance from the start to the beginning of the drive node. */
float m_distance_from_start; float m_distance_from_start;
private: private:
/** Normal of the graph node */ /** Set to true if this drive node should not be used by the AI. */
Vec3 m_normal;
/** Set to true if this graph node should not be shown in the minimap. */
bool m_invisible;
/** Set to true if this graph node should not be used by the AI. */
bool m_ai_ignore; bool m_ai_ignore;
/** Index of this graph node. */ /** The list of successor drive nodes. */
unsigned int m_node_index;
/** The list of successor graph nodes. */
std::vector<int> m_successor_nodes; std::vector<int> m_successor_nodes;
/** The list of predecessors of a node. */ /** The list of predecessors of a node. */
@ -79,18 +70,18 @@ private:
Vec3 m_center_to_right; Vec3 m_center_to_right;
typedef std::vector<int> PathToNodeVector; typedef std::vector<int> PathToNodeVector;
/** This vector is only used if the graph node has more than one /** This vector is only used if the drive node has more than one
* successor. In this case m_path_to_node[X] will contain the index * successor. In this case m_path_to_node[X] will contain the index
* of the successor to use in order to reach graph node X for this * of the successor to use in order to reach drive node X for this
* graph nodes. */ * drive nodes. */
PathToNodeVector m_path_to_node; PathToNodeVector m_path_to_node;
/** The direction for each of the successors. */ /** The direction for each of the successors. */
std::vector<DirectionType> m_direction; std::vector<DirectionType> m_direction;
/** Stores for each successor the index of the last graph node that /** Stores for each successor the index of the last drive node that
* has the same direction (i.e. if index 0 curves left, this vector * has the same direction (i.e. if index 0 curves left, this vector
* will store the index of the last graph node that is still turning * will store the index of the last drive node that is still turning
* left. */ * left. */
std::vector<unsigned int> m_last_index_same_direction; std::vector<unsigned int> m_last_index_same_direction;
@ -105,16 +96,17 @@ private:
*/ */
std::vector< int > m_checkline_requirements; std::vector< int > m_checkline_requirements;
// ------------------------------------------------------------------------
void markAllSuccessorsToUse(unsigned int n, void markAllSuccessorsToUse(unsigned int n,
PathToNodeVector *m_path_to_node); PathToNodeVector *m_path_to_node);
public: public:
GraphNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, DriveNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
const Vec3 &p3, const Vec3 &normal, const Vec3 &p3, const Vec3 &normal,
unsigned int node_index, bool invisible, unsigned int node_index, bool invisible,
bool ai_ignore); bool ai_ignore);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual ~GraphNode() {} virtual ~DriveNode() {}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void addSuccessor (unsigned int to); void addSuccessor (unsigned int to);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -131,7 +123,7 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the i-th successor node. */ /** Returns the i-th successor node. */
unsigned int getSuccessor(unsigned int i) const unsigned int getSuccessor(unsigned int i) const
{ return m_successor_nodes[i]; } { return m_successor_nodes[i]; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the number of predecessors. */ /** Returns the number of predecessors. */
unsigned int getNumberOfPredecessors() const unsigned int getNumberOfPredecessors() const
@ -140,47 +132,41 @@ public:
/** Returns a predecessor for this node. Note that the first predecessor /** Returns a predecessor for this node. Note that the first predecessor
* is the most 'natural' one, i.e. the one on the main driveline. * is the most 'natural' one, i.e. the one on the main driveline.
*/ */
int getPredecessor(unsigned int i) const {return m_predecessor_nodes[i]; } int getPredecessor(unsigned int i) const { return m_predecessor_nodes[i]; }
// ------------------------------------------------------------------------
/** Returns the node index of this node. */
unsigned int getNodeIndex() const { return m_node_index; }
// ------------------------------------------------------------------------
/** Returns the normal of this quad */
const Vec3& getNormal() const { return m_normal; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the distance to the j-th. successor. */ /** Returns the distance to the j-th. successor. */
float getDistanceToSuccessor(unsigned int j) const float getDistanceToSuccessor(unsigned int j) const
{ return m_distance_to_next[j]; } { return m_distance_to_next[j]; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the angle from this node to the j-th. successor. */ /** Returns the angle from this node to the j-th. successor. */
float getAngleToSuccessor(unsigned int j) const float getAngleToSuccessor(unsigned int j) const
{ return m_angle_to_next[j]; } { return m_angle_to_next[j]; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the distance from start. */ /** Returns the distance from start. */
float getDistanceFromStart() const float getDistanceFromStart() const
{ return m_distance_from_start; } { return m_distance_from_start; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Sets the distance from start for this node. */ /** Sets the distance from start for this node. */
void setDistanceFromStart(float d) {m_distance_from_start = d; } void setDistanceFromStart(float d) { m_distance_from_start = d; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the width of the part for this quad. */ /** Returns the width of the part for this quad. */
float getPathWidth() const { return m_width; } float getPathWidth() const { return m_width; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the center point of the lower edge of this graph node. */ /** Returns the center point of the lower edge of this drive node. */
const Vec3& getLowerCenter() const {return m_lower_center;} const Vec3& getLowerCenter() const { return m_lower_center; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the center point of the upper edge of this graph node. */ /** Returns the center point of the upper edge of this drive node. */
const Vec3& getUpperCenter() const {return m_upper_center;} const Vec3& getUpperCenter() const { return m_upper_center; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the length of the quad of this node. */ /** Returns the length of the quad of this node. */
float getNodeLength() const float getNodeLength() const
{return (m_lower_center-m_upper_center).length();} { return (m_lower_center-m_upper_center).length(); }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
bool ignoreSuccessorForAI(unsigned int i) const; bool ignoreSuccessorForAI(unsigned int i) const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns which successor node to use in order to be able to reach the /** Returns which successor node to use in order to be able to reach the
* given node n. * given node n.
* \param n Index of the graph node to reach. * \param n Index of the drive node to reach.
*/ */
int getSuccessorToReach(unsigned int n) int getSuccessorToReach(unsigned int n)
{ {
@ -189,7 +175,7 @@ public:
return m_path_to_node.size()>0 ? m_path_to_node[n] : 0; return m_path_to_node.size()>0 ? m_path_to_node[n] : 0;
} // getSuccesorToReach } // getSuccesorToReach
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the checkline requirements of this graph node. */ /** Returns the checkline requirements of this drive node. */
const std::vector<int>& getChecklineRequirements() const const std::vector<int>& getChecklineRequirements() const
{ return m_checkline_requirements; } { return m_checkline_requirements; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -201,17 +187,13 @@ public:
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns a unit vector pointing to the right side of the quad. */ /** Returns a unit vector pointing to the right side of the quad. */
const Vec3 &getRightUnitVector() const { return m_right_unit_vector; } const Vec3 &getRightUnitVector() const { return m_right_unit_vector; }
// ------------------------------------------------------------------------
/** Returns true of this node is invisible, i.e. not to be shown in
* the minimap. */
bool isInvisible() const { return m_invisible; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** True if this node should be ignored by the AI. */ /** True if this node should be ignored by the AI. */
bool letAIIgnore() const { return m_ai_ignore; } bool letAIIgnore() const { return m_ai_ignore; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual void getDistances(const Vec3 &xyz, Vec3 *result) const = 0; virtual void getDistances(const Vec3 &xyz, Vec3 *result) const = 0;
}; // GraphNode }; // DriveNode
#endif #endif

View File

@ -16,13 +16,15 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tracks/node_2d.hpp" #include "tracks/drive_node_2d.hpp"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
Node2D::Node2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, DriveNode2D::DriveNode2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
const Vec3 &normal, unsigned int node_index, bool invisible, const Vec3 &p3, const Vec3 &normal,
bool ai_ignore) unsigned int node_index, bool invisible,
: GraphNode(p0, p1, p2, p3, normal, node_index, invisible, ai_ignore) bool ai_ignore)
: DriveNode(p0, p1, p2, p3, normal, node_index, invisible,
ai_ignore)
{ {
m_line = core::line2df(m_upper_center.getX(), m_upper_center.getZ(), m_line = core::line2df(m_upper_center.getX(), m_upper_center.getZ(),
m_lower_center.getX(), m_lower_center.getZ()); m_lower_center.getX(), m_lower_center.getZ());
@ -30,7 +32,7 @@ Node2D::Node2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
// Only this 2d point is needed later // Only this 2d point is needed later
m_lower_center_2d = core::vector2df(m_lower_center.getX(), m_lower_center_2d = core::vector2df(m_lower_center.getX(),
m_lower_center.getZ()); m_lower_center.getZ());
} // Node2D } // DriveNode2D
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Returns the distance a point has from this node in forward and sidewards /** Returns the distance a point has from this node in forward and sidewards
@ -41,7 +43,7 @@ Node2D::Node2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
* \param result The X coordinate contains the sidewards distance, the * \param result The X coordinate contains the sidewards distance, the
* Z coordinate the forward distance. * Z coordinate the forward distance.
*/ */
void Node2D::getDistances(const Vec3 &xyz, Vec3 *result) const void DriveNode2D::getDistances(const Vec3 &xyz, Vec3 *result) const
{ {
core::vector2df xyz2d(xyz.getX(), xyz.getZ()); core::vector2df xyz2d(xyz.getX(), xyz.getZ());
core::vector2df closest = m_line.getClosestPoint(xyz2d); core::vector2df closest = m_line.getClosestPoint(xyz2d);
@ -61,7 +63,7 @@ void Node2D::getDistances(const Vec3 &xyz, Vec3 *result) const
* which belongs to this graph node. The value is computed in 2d only! * which belongs to this graph node. The value is computed in 2d only!
* \param xyz The point for which the distance to the line is computed. * \param xyz The point for which the distance to the line is computed.
*/ */
float Node2D::getDistance2FromPoint(const Vec3 &xyz) const float DriveNode2D::getDistance2FromPoint(const Vec3 &xyz) const
{ {
core::vector2df xyz2d(xyz.getX(), xyz.getZ()); core::vector2df xyz2d(xyz.getX(), xyz.getZ());
core::vector2df closest = m_line.getClosestPoint(xyz2d); core::vector2df closest = m_line.getClosestPoint(xyz2d);

View File

@ -16,10 +16,10 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_NODE_2D_HPP #ifndef HEADER_DRIVE_NODE_2D_HPP
#define HEADER_NODE_2D_HPP #define HEADER_DRIVE_NODE_2D_HPP
#include "tracks/graph_node.hpp" #include "tracks/drive_node.hpp"
#include "utils/cpp2011.hpp" #include "utils/cpp2011.hpp"
#include <line2d.h> #include <line2d.h>
@ -27,7 +27,7 @@
/** /**
* \ingroup tracks * \ingroup tracks
*/ */
class Node2D : public GraphNode class DriveNode2D : public DriveNode
{ {
private: private:
/** The center point of the lower two points (e.g. points 0 and 1). /** The center point of the lower two points (e.g. points 0 and 1).
@ -43,9 +43,9 @@ private:
core::line2df m_line; core::line2df m_line;
public: public:
Node2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, DriveNode2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
const Vec3 &normal, unsigned int node_index, bool invisible, const Vec3 &normal, unsigned int node_index, bool invisible,
bool ai_ignore); bool ai_ignore);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual void getDistances(const Vec3 &xyz, Vec3 *result) const OVERRIDE; virtual void getDistances(const Vec3 &xyz, Vec3 *result) const OVERRIDE;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -16,18 +16,20 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tracks/node_3d.hpp" #include "tracks/drive_node_3d.hpp"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
Node3D::Node3D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, DriveNode3D::DriveNode3D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
const Vec3 &normal, unsigned int node_index, bool invisible, const Vec3 &p3, const Vec3 &normal,
bool ai_ignore) unsigned int node_index, bool invisible,
: GraphNode(p0, p1, p2, p3, normal, node_index, invisible, ai_ignore) bool ai_ignore)
: DriveNode(p0, p1, p2, p3, normal, node_index, invisible,
ai_ignore)
{ {
BoundingBox3D::init(p0, p1, p2, p3, normal); BoundingBox3D::init(p0, p1, p2, p3, normal);
m_line = core::line3df(m_lower_center.toIrrVector(), m_line = core::line3df(m_lower_center.toIrrVector(),
m_upper_center.toIrrVector()); m_upper_center.toIrrVector());
} // Node3D } // DriveNode3D
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Returns the distance a point has from this node in forward and sidewards /** Returns the distance a point has from this node in forward and sidewards
@ -38,7 +40,7 @@ Node3D::Node3D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
* \param result The X coordinate contains the sidewards distance, the * \param result The X coordinate contains the sidewards distance, the
* Z coordinate the forward distance. * Z coordinate the forward distance.
*/ */
void Node3D::getDistances(const Vec3 &xyz, Vec3 *result) const void DriveNode3D::getDistances(const Vec3 &xyz, Vec3 *result) const
{ {
core::vector3df xyz_irr = xyz.toIrrVector(); core::vector3df xyz_irr = xyz.toIrrVector();
core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector()); core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector());
@ -59,7 +61,7 @@ void Node3D::getDistances(const Vec3 &xyz, Vec3 *result) const
* which belongs to this node. * which belongs to this node.
* \param xyz The point for which the distance to the line is computed. * \param xyz The point for which the distance to the line is computed.
*/ */
float Node3D::getDistance2FromPoint(const Vec3 &xyz) const float DriveNode3D::getDistance2FromPoint(const Vec3 &xyz) const
{ {
core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector()); core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector());
return (closest-xyz.toIrrVector()).getLengthSQ(); return (closest-xyz.toIrrVector()).getLengthSQ();

View File

@ -16,18 +16,18 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_NODE_3D_HPP #ifndef HEADER_DRIVE_NODE_3D_HPP
#define HEADER_NODE_3D_HPP #define HEADER_DRIVE_NODE_3D_HPP
#include "tracks/bounding_box_3d.hpp" #include "tracks/bounding_box_3d.hpp"
#include "tracks/graph_node.hpp" #include "tracks/drive_node.hpp"
#include "utils/cpp2011.hpp" #include "utils/cpp2011.hpp"
/** /**
* \ingroup tracks * \ingroup tracks
*/ */
class Node3D : public GraphNode, class DriveNode3D : public DriveNode,
public BoundingBox3D public BoundingBox3D
{ {
private: private:
/** Line between lower and upper center, saves computation in /** Line between lower and upper center, saves computation in
@ -36,9 +36,9 @@ private:
core::line3df m_line; core::line3df m_line;
public: public:
Node3D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, DriveNode3D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3,
const Vec3 &normal, unsigned int node_index, bool invisible, const Vec3 &normal, unsigned int node_index, bool invisible,
bool ai_ignore); bool ai_ignore);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual bool pointInside(const Vec3& p, virtual bool pointInside(const Vec3& p,
bool ignore_vertical = false) const OVERRIDE bool ignore_vertical = false) const OVERRIDE

View File

@ -30,8 +30,8 @@
#include "graphics/rtts.hpp" #include "graphics/rtts.hpp"
#include "modes/profile_world.hpp" #include "modes/profile_world.hpp"
#include "tracks/arena_node_3d.hpp" #include "tracks/arena_node_3d.hpp"
#include "tracks/node_2d.hpp" #include "tracks/drive_node_2d.hpp"
#include "tracks/node_3d.hpp" #include "tracks/drive_node_3d.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
const int Graph::UNKNOWN_SECTOR = -1; const int Graph::UNKNOWN_SECTOR = -1;
@ -426,7 +426,7 @@ void Graph::createQuad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
} }
else else
{ {
q = new Node3D(p0, p1, p2, p3, normal, node_index, invisible, q = new DriveNode3D(p0, p1, p2, p3, normal, node_index, invisible,
ai_ignore); ai_ignore);
} }
} }
@ -440,7 +440,7 @@ void Graph::createQuad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
} }
else else
{ {
q = new Node2D(p0, p1, p2, p3, normal, node_index, invisible, q = new DriveNode2D(p0, p1, p2, p3, normal, node_index, invisible,
ai_ignore); ai_ignore);
} }
} }
@ -614,5 +614,3 @@ int Graph::findOutOfRoadSector(const Vec3& xyz, const int curr_sector,
} }
return min_sector; return min_sector;
} // findOutOfRoadSector } // findOutOfRoadSector
//-----------------------------------------------------------------------------

View File

@ -40,8 +40,15 @@ class Quad;
class RTT; class RTT;
/** /**
* \ingroup tracks * \brief This class stores a graph of quads. It uses a 'simplified singleton'
*/ * design pattern: it has a static create function to create exactly instance,
* a destroy function, and a get function (that does not have the side effect
* of the 'normal singleton' design pattern to create an instance). Besides
* saving on the if statement in get(), this is necessary since certain race
* modes might not have a quad graph at all (e.g. arena without navmesh). So
* get() returns NULL in this case, and this is tested where necessary.
* \ingroup tracks
*/
class Graph : public NoCopy class Graph : public NoCopy
{ {
protected: protected:
@ -55,7 +62,8 @@ protected:
Vec3 m_bb_max; Vec3 m_bb_max;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Factory method to dynamic create 2d / 3d quad. */ /** Factory method to dynamic create 2d / 3d quad for drive and arena
* graph. */
void createQuad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, void createQuad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2,
const Vec3 &p3, unsigned int node_index, const Vec3 &p3, unsigned int node_index,
bool invisible, bool ai_ignore, bool is_arena); bool invisible, bool ai_ignore, bool is_arena);
@ -90,11 +98,11 @@ public:
static const int UNKNOWN_SECTOR; static const int UNKNOWN_SECTOR;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the one instance of this object. It is possible that there /** Returns the one instance of this object. It is possible that there
* is no instance created (e.g. battle mode without navmesh) so we don't * is no instance created (e.g. arena without navmesh) so we don't assert
* assert that an instance exist. */ * that an instance exist. */
static Graph* get() { return m_graph; } static Graph* get() { return m_graph; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Set the graph (either driveline or arena graph for now). */ /** Set the graph (either drive or arena graph for now). */
static void setGraph(Graph* graph) static void setGraph(Graph* graph)
{ {
assert(m_graph == NULL); assert(m_graph == NULL);
@ -102,8 +110,8 @@ public:
} // create } // create
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Cleans up the graph. It is possible that this function is called even /** Cleans up the graph. It is possible that this function is called even
* if no instance exists (e.g. in battle mode without navmesh). So it is * if no instance exists (e.g. arena without navmesh). So it is not an
* not an error if there is no instance. */ * error if there is no instance. */
static void destroy() static void destroy()
{ {
if (m_graph) if (m_graph)

View File

@ -1,386 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2015 SuperTuxKart Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tracks/graph_structure.hpp"
#include <ICameraSceneNode.h>
#include <IMesh.h>
#include <IMeshSceneNode.h>
#include <ISceneManager.h>
#include "graphics/irr_driver.hpp"
#include "graphics/glwrap.hpp"
#include "graphics/shaders.hpp"
#include "graphics/rtts.hpp"
#include "modes/world.hpp"
#include "modes/profile_world.hpp"
#include "utils/log.hpp"
// -----------------------------------------------------------------------------
GraphStructure::GraphStructure()
{
m_min_coord = 0;
m_scaling = 0;
m_node = NULL;
m_mesh = NULL;
m_mesh_buffer = NULL;
m_new_rtt = NULL;
} // GraphStructure
// -----------------------------------------------------------------------------
void GraphStructure::destroyRTT()
{
if (m_new_rtt != NULL)
{
delete m_new_rtt;
m_new_rtt = NULL;
}
} // destroyRTT
// -----------------------------------------------------------------------------
/** Cleans up the debug mesh */
void GraphStructure::cleanupDebugMesh()
{
if (m_node != NULL)
irr_driver->removeNode(m_node);
m_node = NULL;
// No need to call irr_driber->removeMeshFromCache, since the mesh
// was manually made and so never added to the mesh cache.
m_mesh->drop();
m_mesh = NULL;
}
// -----------------------------------------------------------------------------
/** Creates the debug mesh to display the graph on top of the track
* model. */
void GraphStructure::createDebugMesh()
{
if (getNumNodes() <= 0) return; // no debug output if not graph
createMesh(/*show_invisible*/true,
/*enable_transparency*/true);
video::S3DVertex *v = (video::S3DVertex*)m_mesh_buffer->getVertices();
for (unsigned int i = 0; i < m_mesh_buffer->getVertexCount(); i++)
{
// Swap the alpha and back
v[i].Color.setAlpha((i%2) ? 64 : 255);
}
m_node = irr_driver->addMesh(m_mesh, "track-debug-mesh");
#ifdef DEBUG
m_node->setName("track-debug-mesh");
#endif
} // createDebugMesh
// -----------------------------------------------------------------------------
/** Creates the actual mesh that is used by createDebugMesh() or makeMiniMap() */
void GraphStructure::createMesh(bool show_invisible,
bool enable_transparency,
const video::SColor *track_color)
{
// The debug track will not be lighted or culled.
video::SMaterial m;
m.BackfaceCulling = false;
m.Lighting = false;
if (enable_transparency)
m.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
m.setTexture(0, getUnicolorTexture(video::SColor(255, 255, 255, 255)));
m.setTexture(1, getUnicolorTexture(video::SColor(0, 0, 0, 0)));
m.setTexture(7, getUnicolorTexture(video::SColor(0, 0, 0, 0)));
m_mesh = irr_driver->createQuadMesh(&m);
m_mesh_buffer = m_mesh->getMeshBuffer(0);
assert(m_mesh_buffer->getVertexType()==video::EVT_STANDARD);
unsigned int n = 0;
const unsigned int total_nodes = getNumNodes();
// Count the number of quads to display (some quads might be invisible)
for (unsigned int i = 0; i < total_nodes; i++)
{
if (show_invisible || !isNodeInvisible(i))
n++;
}
// Four vertices for each of the n-1 remaining quads
video::S3DVertex *new_v = new video::S3DVertex[4*n];
// Each quad consists of 2 triangles with 3 elements, so
// we need 2*3 indices for each quad.
irr::u16 *ind = new irr::u16[6*n];
video::SColor c(255, 255, 0, 0);
if (track_color)
c = *track_color;
// Now add all quads
int i = 0;
for (unsigned int count = 0; count < total_nodes; count++)
{
// Ignore invisible quads
if (!show_invisible && isNodeInvisible(count))
continue;
// Swap the colours from red to blue and back
if (!track_color)
{
c.setRed ((i%2) ? 255 : 0);
c.setBlue((i%2) ? 0 : 255);
}
NodeColor nc = COLOR_RED;
const bool different_color = differentNodeColor(count, &nc);
// Transfer the 4 points of the current quad to the list of vertices
set3DVerticesOfGraph(count, new_v+4*i, (different_color ?
(nc == COLOR_RED ? video::SColor(255, 255, 0, 0) :
nc == COLOR_GREEN ? video::SColor(255, 0, 255, 0) :
nc == COLOR_BLUE ? video::SColor(255, 0, 0, 255) :
video::SColor(255, 255, 255, 0)) : c));
// Set up the indices for the triangles
// (note, afaik with opengl we could use quads directly, but the code
// would not be portable to directx anymore).
ind[6*i ] = 4*i+2; // First triangle: vertex 0, 1, 2
ind[6*i+1] = 4*i+1;
ind[6*i+2] = 4*i;
ind[6*i+3] = 4*i+3; // second triangle: vertex 0, 1, 3
ind[6*i+4] = 4*i+2;
ind[6*i+5] = 4*i;
i++;
}
m_mesh_buffer->append(new_v, n*4, ind, n*6);
if (0)
{
video::S3DVertex lap_v[4];
irr::u16 lap_ind[6];
video::SColor lap_color(128, 255, 0, 0);
set3DVerticesOfGraph(0, lap_v, lap_color);
// Now scale the length (distance between vertix 0 and 3
// and between 1 and 2) to be 'length':
Vec3 bb_min, bb_max;
getGraphBoundingBox(&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;
core::vector3df dl = lap_v[3].Pos-lap_v[0].Pos;
float ll2 = dl.getLengthSQ();
if (ll2 < 0.001)
lap_v[3].Pos = lap_v[0].Pos+core::vector3df(0, 0, 1);
else
lap_v[3].Pos = lap_v[0].Pos+dl*length/sqrt(ll2);
core::vector3df dr = lap_v[2].Pos-lap_v[1].Pos;
float lr2 = dr.getLengthSQ();
if (lr2 < 0.001)
lap_v[2].Pos = lap_v[1].Pos+core::vector3df(0, 0, 1);
else
lap_v[2].Pos = lap_v[1].Pos+dr*length/sqrt(lr2);
lap_ind[0] = 2;
lap_ind[1] = 1;
lap_ind[2] = 0;
lap_ind[3] = 3;
lap_ind[4] = 2;
lap_ind[5] = 0;
// Set it a bit higher to avoid issued with z fighting,
// i.e. part of the lap line might not be visible.
for (unsigned int i = 0; i < 4; i++)
lap_v[i].Pos.Y += 0.1f;
#ifndef USE_TEXTURED_LINE
m_mesh_buffer->append(lap_v, 4, lap_ind, 6);
#else
lap_v[0].TCoords = core::vector2df(0,0);
lap_v[1].TCoords = core::vector2df(3,0);
lap_v[2].TCoords = core::vector2df(3,1);
lap_v[3].TCoords = core::vector2df(0,1);
m_mesh_buffer->append(lap_v, 4, lap_ind, 6);
video::SMaterial &m = m_mesh_buffer->getMaterial();
video::ITexture *t = irr_driver->getTexture("chess.png");
m.setTexture(0, t);
#endif
}
// Instead of setting the bounding boxes, we could just disable culling,
// since the debug track should always be drawn.
//m_node->setAutomaticCulling(scene::EAC_OFF);
m_mesh_buffer->recalculateBoundingBox();
m_mesh->setBoundingBox(m_mesh_buffer->getBoundingBox());
m_mesh_buffer->getMaterial().setTexture(0, irr_driver->getTexture("unlit.png"));
delete[] ind;
delete[] new_v;
} // createMesh
// -----------------------------------------------------------------------------
/** Takes a snapshot of the graph so they can be used as minimap.
*/
void GraphStructure::makeMiniMap(const core::dimension2du &dimension,
const std::string &name,
const video::SColor &fill_color,
video::ITexture** oldRttMinimap,
FrameBuffer** newRttMinimap)
{
// Skip minimap when profiling
if (ProfileWorld::isNoGraphics()) return;
const video::SColor oldClearColor = World::getWorld()->getClearColor();
World::getWorld()->setClearbackBufferColor(video::SColor(0, 255, 255, 255));
World::getWorld()->forceFogDisabled(true);
*oldRttMinimap = NULL;
*newRttMinimap = NULL;
RTT* newRttProvider = NULL;
IrrDriver::RTTProvider* oldRttProvider = NULL;
if (CVS->isGLSL())
{
m_new_rtt = newRttProvider = new RTT(dimension.Width, dimension.Height);
}
else
{
oldRttProvider = new IrrDriver::RTTProvider(dimension, name, true);
}
irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 255, 255, 255));
createMesh(/*show_invisible part of the track*/ false,
/*enable_transparency*/ false,
/*track_color*/ &fill_color);
m_node = irr_driver->addMesh(m_mesh, "mini_map");
#ifdef DEBUG
m_node->setName("minimap-mesh");
#endif
m_node->setAutomaticCulling(0);
m_node->setMaterialFlag(video::EMF_LIGHTING, false);
// Add the camera:
// ---------------
scene::ICameraSceneNode *camera = irr_driver->addCameraSceneNode();
Vec3 bb_min, bb_max;
getGraphBoundingBox(&bb_min, &bb_max);
Vec3 center = (bb_max+bb_min)*0.5f;
float dx = bb_max.getX()-bb_min.getX();
float dz = bb_max.getZ()-bb_min.getZ();
// Set the scaling correctly. Also the center point (which is used
// as the camera position) needs to be adjusted: the track must
// be aligned to the left/top of the texture which is used (otherwise
// mapPoint2MiniMap doesn't work), so adjust the camera position
// that the track is properly aligned (view from the side):
// c camera
// / \ .
// / \ <--- camera angle
// / \ .
// { [-] } <--- track flat (viewed from the side)
// If [-] is the shorter side of the track, then the camera will
// actually render the area in { } - which is the length of the
// longer side of the track.
// To align the [-] side to the left, the camera must be moved
// the distance betwwen '{' and '[' to the right. This distance
// is exacly (longer_side - shorter_side) / 2.
// So, adjust the center point by this amount:
if (dz > dx)
{
center.setX(center.getX() + (dz-dx)*0.5f);
m_scaling = dimension.Width / dz;
}
else
{
center.setZ(center.getZ() + (dx-dz)*0.5f);
m_scaling = dimension.Width / dx;
}
float range = (dx>dz) ? dx : dz;
core::matrix4 projection;
projection.buildProjectionMatrixOrthoLH(range /* width */,
range /* height */,
-1, bb_max.getY()-bb_min.getY()+1);
camera->setProjectionMatrix(projection, true);
irr_driver->suppressSkyBox();
irr_driver->clearLights();
// Adjust Y position by +1 for max, -1 for min - this helps in case that
// the maximum Y coordinate is negative (otherwise the minimap is mirrored)
// and avoids problems for tracks which have a flat (max Y = min Y) minimap.
camera->setPosition(core::vector3df(center.getX(), bb_min.getY() + 1.0f, center.getZ()));
//camera->setPosition(core::vector3df(center.getX() - 5.0f, bb_min.getY() - 1 - 5.0f, center.getZ() - 15.0f));
camera->setUpVector(core::vector3df(0, 0, 1));
camera->setTarget(core::vector3df(center.getX(),bb_min.getY()-1,center.getZ()));
//camera->setAspectRatio(1.0f);
camera->updateAbsolutePosition();
video::ITexture* texture = NULL;
FrameBuffer* frame_buffer = NULL;
if (CVS->isGLSL())
{
frame_buffer = newRttProvider->render(camera, GUIEngine::getLatestDt());
}
else
{
texture = oldRttProvider->renderToTexture();
delete oldRttProvider;
}
cleanupDebugMesh();
irr_driver->removeCameraSceneNode(camera);
m_min_coord = bb_min;
if (texture == NULL && frame_buffer == NULL)
{
Log::error("Graph Structure", "[makeMiniMap] WARNING: RTT does not"
"appear to work, mini-map will not be available.");
}
*oldRttMinimap = texture;
*newRttMinimap = frame_buffer;
World::getWorld()->setClearbackBufferColor(oldClearColor);
World::getWorld()->forceFogDisabled(false);
irr_driver->getSceneManager()->clear();
VAOManager::kill();
irr_driver->clearGlowingNodes();
irr_driver->clearLights();
irr_driver->clearForcedBloom();
irr_driver->clearBackgroundNodes();
} // makeMiniMap
// -----------------------------------------------------------------------------
/** Returns the 2d coordinates of a point when drawn on the mini map
* texture.
* \param xyz Coordinates of the point to map.
* \param draw_at The coordinates in pixel on the mini map of the point,
* only the first two coordinates will be used.
*/
void GraphStructure::mapPoint2MiniMap(const Vec3 &xyz,Vec3 *draw_at) const
{
draw_at->setX((xyz.getX()-m_min_coord.getX())*m_scaling);
draw_at->setY((xyz.getZ()-m_min_coord.getZ())*m_scaling);
} // mapPoint

View File

@ -1,104 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2015 SuperTuxKart Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_GRAPH_STRUCTURE_HPP
#define HEADER_GRAPH_STRUCTURE_HPP
#include <string>
#include <dimension2d.h>
#include <SColor.h>
#include "utils/vec3.hpp"
#include "utils/no_copy.hpp"
namespace irr
{
namespace scene { class ISceneNode; class IMesh; class IMeshBuffer; }
namespace video { class ITexture; struct S3DVertex; }
}
using namespace irr;
class FrameBuffer;
class RTT;
/**
* \brief Virtual base class for a graph structure.
* This is mainly used for drawing minimap in game.
*
* \ingroup tracks
*/
class GraphStructure : public NoCopy
{
protected:
/** Used by soccer field with navmesh to draw goal line,
* or to determine 2d/3d nodes in driveline graph. */
enum NodeColor
{
COLOR_BLUE,
COLOR_GREEN,
COLOR_RED,
COLOR_YELLOW
};
void cleanupDebugMesh();
void destroyRTT();
private:
RTT* m_new_rtt;
/** The node of the graph mesh. */
scene::ISceneNode *m_node;
/** The mesh of the graph mesh. */
scene::IMesh *m_mesh;
/** The actual mesh buffer storing the graph. */
scene::IMeshBuffer *m_mesh_buffer;
/** The minimum coordinates of the graph. */
Vec3 m_min_coord;
/** Scaling for mini map. */
float m_scaling;
void createMesh(bool show_invisible=true,
bool enable_transparency=false,
const video::SColor *track_color=NULL);
virtual void set3DVerticesOfGraph(int i, video::S3DVertex *v,
const video::SColor &color) const = 0;
virtual void getGraphBoundingBox(Vec3 *min, Vec3 *max) const = 0;
virtual const bool isNodeInvisible(int n) const = 0;
virtual const bool hasLapLine() const = 0;
virtual const bool differentNodeColor(int n, NodeColor* c) const = 0;
public:
GraphStructure();
virtual ~GraphStructure() {};
void createDebugMesh();
void makeMiniMap(const core::dimension2du &where,
const std::string &name,
const video::SColor &fill_color,
video::ITexture** oldRttMinimap,
FrameBuffer** newRttMinimap);
void mapPoint2MiniMap(const Vec3 &xyz, Vec3 *out) const;
virtual const unsigned int getNumNodes() const = 0;
}; // GraphStructure
#endif

View File

@ -1,182 +0,0 @@
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, B
#ifndef HEADER_QUAD_GRAPH_HPP
#define HEADER_QUAD_GRAPH_HPP
#include <vector>
#include <string>
#include <set>
#include "tracks/graph_structure.hpp"
#include "utils/aligned_array.hpp"
#include "LinearMath/btTransform.h"
class GraphNode;
class XMLNode;
/**
* \brief This class stores a graph of quads. It uses a 'simplified singleton'
* design pattern: it has a static create function to create exactly instance,
* a destroy function, and a get function (that does not have the side effect
* of the 'normal singleton' design pattern to create an instance). Besides
* saving on the if statement in get(), this is necessary since certain race
* modes might not have a quad graph at all (e.g. battle mode). So get()
* returns NULL in this case, and this is tested where necessary.
* \ingroup tracks
*/
class QuadGraph : public GraphStructure
{
private:
static QuadGraph *m_quad_graph;
/** The 2d bounding box, used for hashing. */
Vec3 m_min;
Vec3 m_max;
/** The actual graph data structure. */
std::vector<GraphNode*> m_all_nodes;
/** The length of the first loop. */
float m_lap_length;
/** 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 computeChecklineRequirements(GraphNode* node, int latest_checkline);
void computeDirectionData();
void determineDirection(unsigned int current, unsigned int succ_index);
float normalizeAngle(float f);
void addSuccessor(unsigned int from, unsigned int to);
void load(const std::string &quad_file_name, const std::string &filename);
void getPoint(const XMLNode *xml, const std::string &attribute_name,
Vec3 *result) const;
void computeDistanceFromStart(unsigned int start_node, float distance);
unsigned int getStartNode() const;
QuadGraph(const std::string &quad_file_name,
const std::string &graph_file_name,
const bool reverse);
~QuadGraph();
// ------------------------------------------------------------------------
virtual void set3DVerticesOfGraph(int i, video::S3DVertex *v,
const video::SColor &color) const;
// ------------------------------------------------------------------------
virtual void getGraphBoundingBox(Vec3 *min, Vec3 *max) const
{ *min = m_min; *max = m_max; }
// ------------------------------------------------------------------------
virtual const bool isNodeInvisible(int n) const;
// ------------------------------------------------------------------------
virtual const bool hasLapLine() const
{ return true; }
// ------------------------------------------------------------------------
virtual const bool differentNodeColor(int n, NodeColor* c) const;
public:
static const int UNKNOWN_SECTOR;
void getSuccessors(int node_number,
std::vector<unsigned int>& succ,
bool for_ai=false) const;
void spatialToTrack(Vec3 *dst, const Vec3& xyz,
const int sector) const;
void findRoadSector(const Vec3& XYZ, int *sector,
std::vector<int> *all_sectors=NULL) const;
int findOutOfRoadSector(const Vec3& xyz,
const int curr_sector=UNKNOWN_SECTOR,
std::vector<int> *all_sectors=NULL
) const;
void setDefaultStartPositions(AlignedArray<btTransform>
*start_transforms,
unsigned int karts_per_row,
float forwards_distance=1.5f,
float sidewards_distance=1.5f,
float upwards_distance=0.0f) const;
void updateDistancesForAllSuccessors(unsigned int indx,
float delta,
unsigned int count);
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
* also don't create one if it doesn't exists. */
static QuadGraph *get() { return m_quad_graph; }
// ------------------------------------------------------------------------
/** Creates a QuadGraph instance. */
static void create(const std::string &quad_file_name,
const std::string &graph_file_name,
const bool reverse)
{
assert(m_quad_graph==NULL);
// 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
* even if no instance exists (e.g. in battle mode). So it is not an
* error if there is no instance. */
static void destroy()
{
if(m_quad_graph)
{
delete m_quad_graph;
m_quad_graph = NULL;
}
} // destroy
// ------------------------------------------------------------------------
/** Returns the number of nodes in the graph. */
virtual const unsigned int getNumNodes() const
{ return m_all_nodes.size(); }
// ------------------------------------------------------------------------
/** Return the distance to the j-th successor of node n. */
float getDistanceToNext(int n, int j) const;
// ------------------------------------------------------------------------
/** Returns the angle of the line between node n and its j-th.
* successor. */
float getAngleToNext(int n, int j) const;
// ------------------------------------------------------------------------
/** Returns the number of successors of a node n. */
int getNumberOfSuccessors(int n) const;
// ------------------------------------------------------------------------
/** Returns the quad that belongs to a graph node. */
GraphNode* getNode(unsigned int j) { return m_all_nodes[j]; }
// ------------------------------------------------------------------------
/** Returns the quad that belongs to a graph node (const version). */
const GraphNode* getNode(unsigned int j) const { return m_all_nodes[j]; }
// ------------------------------------------------------------------------
/** Returns the distance from the start to the beginning of a quad. */
float getDistanceFromStart(int j) const;
// ------------------------------------------------------------------------
/** Returns the length of the main driveline. */
float getLapLength() const { return m_lap_length; }
// ------------------------------------------------------------------------
bool isReverse() const { return m_reverse; }
}; // QuadGraph
#endif

View File

@ -56,9 +56,9 @@
#include "tracks/arena_graph.hpp" #include "tracks/arena_graph.hpp"
#include "tracks/bezier_curve.hpp" #include "tracks/bezier_curve.hpp"
#include "tracks/check_manager.hpp" #include "tracks/check_manager.hpp"
#include "tracks/drive_graph.hpp"
#include "tracks/drive_node.hpp"
#include "tracks/model_definition_loader.hpp" #include "tracks/model_definition_loader.hpp"
#include "tracks/node_3d.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/track_manager.hpp" #include "tracks/track_manager.hpp"
#include "tracks/track_object_manager.hpp" #include "tracks/track_object_manager.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
@ -277,7 +277,6 @@ void Track::reset()
*/ */
void Track::cleanup() void Track::cleanup()
{ {
QuadGraph::destroy();
Graph::destroy(); Graph::destroy();
ItemManager::destroy(); ItemManager::destroy();
VAOManager::kill(); VAOManager::kill();
@ -374,7 +373,7 @@ void Track::cleanup()
} }
if (m_new_rtt_mini_map) if (m_new_rtt_mini_map)
{ {
m_new_rtt_mini_map = NULL; // already deleted by QuadGraph::~QuadGraph m_new_rtt_mini_map = NULL; // already deleted by Graph::~Graph
} }
for(unsigned int i=0; i<m_sky_textures.size(); i++) for(unsigned int i=0; i<m_sky_textures.size(); i++)
@ -715,24 +714,25 @@ btQuaternion Track::getArenaStartRotation(const Vec3& xyz, float heading)
} // getArenaStartRotation } // getArenaStartRotation
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Loads the quad graph, i.e. the definition of all quads, and the way /** Loads the drive graph, i.e. the definition of all quads, and the way
* they are connected to each other. * they are connected to each other.
*/ */
void Track::loadQuadGraph(unsigned int mode_id, const bool reverse) void Track::loadDriveGraph(unsigned int mode_id, const bool reverse)
{ {
QuadGraph::create(m_root+m_all_modes[mode_id].m_quad_name, new DriveGraph(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);
reverse);
QuadGraph::get()->setupPaths(); // setGraph is done in DriveGraph constructor
assert(DriveGraph::get());
DriveGraph::get()->setupPaths();
#ifdef DEBUG #ifdef DEBUG
for(unsigned int i=0; i<QuadGraph::get()->getNumNodes(); i++) for(unsigned int i=0; i<DriveGraph::get()->getNumNodes(); i++)
{ {
assert(QuadGraph::get()->getNode(i)->getPredecessor(0)!=-1); assert(DriveGraph::get()->getNode(i)->getPredecessor(0)!=-1);
} }
#endif #endif
if(QuadGraph::get()->getNumNodes()==0) if(DriveGraph::get()->getNumNodes()==0)
{ {
Log::warn("track", "No graph nodes defined for track '%s'\n", Log::warn("track", "No graph nodes defined for track '%s'\n",
m_filename.c_str()); m_filename.c_str());
@ -746,16 +746,13 @@ void Track::loadQuadGraph(unsigned int mode_id, const bool reverse)
{ {
loadMinimap(); loadMinimap();
} }
} // loadQuadGraph } // loadDriveGraph
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void Track::mapPoint2MiniMap(const Vec3 &xyz, Vec3 *draw_at) const void Track::mapPoint2MiniMap(const Vec3 &xyz, Vec3 *draw_at) const
{ {
if ((m_is_arena || m_is_soccer) && m_has_navmesh) Graph::get()->mapPoint2MiniMap(xyz, draw_at);
Graph::get()->mapPoint2MiniMap(xyz, draw_at);
else
QuadGraph::get()->mapPoint2MiniMap(xyz, draw_at);
draw_at->setX(draw_at->getX() * m_minimap_x_scale); draw_at->setX(draw_at->getX() * m_minimap_x_scale);
draw_at->setY(draw_at->getY() * m_minimap_y_scale); draw_at->setY(draw_at->getY() * m_minimap_y_scale);
} }
@ -1058,16 +1055,8 @@ void Track::loadMinimap()
core::dimension2du size = m_mini_map_size core::dimension2du size = m_mini_map_size
.getOptimalSize(!nonpower,!nonsquare); .getOptimalSize(!nonpower,!nonsquare);
if ((m_is_arena || m_is_soccer) && m_has_navmesh) Graph::get()->makeMiniMap(size, "minimap::" + m_ident, video::SColor(127, 255, 255, 255),
{ &m_old_rtt_mini_map, &m_new_rtt_mini_map);
Graph::get()->makeMiniMap(size, "minimap::" + m_ident, video::SColor(127, 255, 255, 255),
&m_old_rtt_mini_map, &m_new_rtt_mini_map);
}
else
{
QuadGraph::get()->makeMiniMap(size, "minimap::" + m_ident, video::SColor(127, 255, 255, 255),
&m_old_rtt_mini_map, &m_new_rtt_mini_map);
}
if (m_old_rtt_mini_map) if (m_old_rtt_mini_map)
{ {
@ -1686,7 +1675,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
// the race gui was created. The race gui is needed since it stores // 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 // the information about the size of the texture to render the mini
// map to. // map to.
if (!m_is_arena && !m_is_soccer && !m_is_cutscene) loadQuadGraph(mode_id, reverse_track); if (!m_is_arena && !m_is_soccer && !m_is_cutscene) loadDriveGraph(mode_id, reverse_track);
else if ((m_is_arena || m_is_soccer) && !m_is_cutscene && m_has_navmesh) else if ((m_is_arena || m_is_soccer) && !m_is_cutscene && m_has_navmesh)
loadArenaGraph(*root); loadArenaGraph(*root);
@ -1718,7 +1707,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
} }
else else
m_start_transforms.resize(race_manager->getNumberOfKarts()); m_start_transforms.resize(race_manager->getNumberOfKarts());
QuadGraph::get()->setDefaultStartPositions(&m_start_transforms, DriveGraph::get()->setDefaultStartPositions(&m_start_transforms,
karts_per_row, karts_per_row,
forwards_distance, forwards_distance,
sidewards_distance, sidewards_distance,
@ -1929,7 +1918,7 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
World *world = World::getWorld(); World *world = World::getWorld();
if (world->useChecklineRequirements()) if (world->useChecklineRequirements())
{ {
QuadGraph::get()->computeChecklineRequirements(); DriveGraph::get()->computeChecklineRequirements();
} }
EasterEggHunt *easter_world = dynamic_cast<EasterEggHunt*>(world); EasterEggHunt *easter_world = dynamic_cast<EasterEggHunt*>(world);
@ -2282,30 +2271,26 @@ void Track::itemCommand(const XMLNode *node)
// Test if the item lies on a 3d node, if so adjust the normal // Test if the item lies on a 3d node, if so adjust the normal
// Also do a raycast if drop item is given // Also do a raycast if drop item is given
Vec3 normal(0, 1, 0); Vec3 normal(0, 1, 0);
Vec3 quad_normal = normal;
Vec3 hit_point = loc; Vec3 hit_point = loc;
Node3D* node_3d = NULL; if (Graph::get())
if (QuadGraph::get())
{ {
int road_sector = QuadGraph::UNKNOWN_SECTOR; int road_sector = Graph::UNKNOWN_SECTOR;
QuadGraph::get()->findRoadSector(xyz, &road_sector); Graph::get()->findRoadSector(xyz, &road_sector);
// Only do custom direction of raycast if item is on quad graph // Only do custom direction of raycast if item is on quad graph
if (road_sector != QuadGraph::UNKNOWN_SECTOR) if (road_sector != Graph::UNKNOWN_SECTOR)
{ {
node_3d = quad_normal = Graph::get()->getQuad(road_sector)->getNormal();
dynamic_cast<Node3D*>(QuadGraph::get()->getNode(road_sector));
} }
} }
Vec3 quad_normal = node_3d ? node_3d->getNormal() : Vec3(0, 1, 0); if (drop)
if (node_3d || drop)
{ {
const Material *m; const Material *m;
// If raycast is used, increase the start position slightly // If raycast is used, increase the start position slightly
// in case that the point is too close to the actual surface // in case that the point is too close to the actual surface
// (e.g. floating point errors can cause a problem here). // (e.g. floating point errors can cause a problem here).
// Only do so for 2d node loc += quad_normal * 0.1;
if (node_3d == NULL)
loc += Vec3(0.0f, 0.1f, 0.0f);
#ifndef DEBUG #ifndef DEBUG
m_track_mesh->castRay(loc, loc + (-10000 * quad_normal), &hit_point, m_track_mesh->castRay(loc, loc + (-10000 * quad_normal), &hit_point,
@ -2323,8 +2308,7 @@ void Track::itemCommand(const XMLNode *node)
#endif #endif
} }
ItemManager::get()->newItem(type, drop ? hit_point : loc, ItemManager::get()->newItem(type, drop ? hit_point : loc, normal);
node_3d ? normal : Vec3(0, 1, 0));
} // itemCommand } // itemCommand
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -2434,11 +2418,11 @@ bool Track::findGround(AbstractKart *kart)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
float Track::getTrackLength() const float Track::getTrackLength() const
{ {
return QuadGraph::get()->getLapLength(); return DriveGraph::get()->getLapLength();
} // getTrackLength } // getTrackLength
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
float Track::getAngle(int n) const float Track::getAngle(int n) const
{ {
return QuadGraph::get()->getAngleToNext(n, 0); return DriveGraph::get()->getAngleToNext(n, 0);
} // getAngle } // getAngle

View File

@ -373,7 +373,7 @@ private:
int m_actual_number_of_laps; int m_actual_number_of_laps;
void loadTrackInfo(); void loadTrackInfo();
void loadQuadGraph(unsigned int mode_id, const bool reverse); void loadDriveGraph(unsigned int mode_id, const bool reverse);
void loadArenaGraph(const XMLNode &node); void loadArenaGraph(const XMLNode &node);
btQuaternion getArenaStartRotation(const Vec3& xyz, float heading); btQuaternion getArenaStartRotation(const Vec3& xyz, float heading);
void convertTrackToBullet(scene::ISceneNode *node); void convertTrackToBullet(scene::ISceneNode *node);

View File

@ -16,15 +16,16 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "tracks/track_sector.hpp"
#include "modes/linear_world.hpp" #include "modes/linear_world.hpp"
#include "modes/world.hpp" #include "modes/world.hpp"
#include "tracks/check_manager.hpp" #include "tracks/check_manager.hpp"
#include "tracks/check_structure.hpp" #include "tracks/check_structure.hpp"
#include "tracks/track_sector.hpp"
#include "tracks/arena_graph.hpp" #include "tracks/arena_graph.hpp"
#include "tracks/arena_node.hpp" #include "tracks/arena_node.hpp"
#include "tracks/quad_graph.hpp" #include "tracks/drive_graph.hpp"
#include "tracks/graph_node.hpp" #include "tracks/drive_node.hpp"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** Initialises the object, and sets the current graph node to be undefined. /** Initialises the object, and sets the current graph node to be undefined.
@ -37,8 +38,8 @@ TrackSector::TrackSector()
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void TrackSector::reset() void TrackSector::reset()
{ {
m_current_graph_node = QuadGraph::UNKNOWN_SECTOR; m_current_graph_node = Graph::UNKNOWN_SECTOR;
m_last_valid_graph_node = QuadGraph::UNKNOWN_SECTOR; m_last_valid_graph_node = Graph::UNKNOWN_SECTOR;
m_on_road = false; m_on_road = false;
m_last_triggered_checkline = -1; m_last_triggered_checkline = -1;
} // reset } // reset
@ -79,8 +80,8 @@ void TrackSector::update(const Vec3 &xyz, bool ignore_vertical)
if (ag) return; if (ag) return;
// keep the current quad as the latest valid one IF the player has one // keep the current quad as the latest valid one IF the player has one
// of the required checklines // of the required checklines
const GraphNode* gn = QuadGraph::get()->getNode(m_current_graph_node); const DriveNode* dn = DriveGraph::get()->getNode(m_current_graph_node);
const std::vector<int>& checkline_requirements = gn->getChecklineRequirements(); const std::vector<int>& checkline_requirements = dn->getChecklineRequirements();
if (checkline_requirements.size() == 0) if (checkline_requirements.size() == 0)
{ {
@ -107,8 +108,8 @@ void TrackSector::update(const Vec3 &xyz, bool ignore_vertical)
// Now determine the 'track' coords, i.e. ow far from the start of the // Now determine the 'track' coords, i.e. ow far from the start of the
// track, and how far to the left or right of the center driveline. // track, and how far to the left or right of the center driveline.
QuadGraph::get()->spatialToTrack(&m_current_track_coords, xyz, DriveGraph::get()->spatialToTrack(&m_current_track_coords, xyz,
m_current_graph_node); m_current_graph_node);
} // update } // update
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -116,7 +117,7 @@ void TrackSector::update(const Vec3 &xyz, bool ignore_vertical)
*/ */
void TrackSector::rescue() void TrackSector::rescue()
{ {
if (m_last_valid_graph_node != QuadGraph::UNKNOWN_SECTOR) if (m_last_valid_graph_node != Graph::UNKNOWN_SECTOR)
m_current_graph_node = m_last_valid_graph_node; m_current_graph_node = m_last_valid_graph_node;
// Using the predecessor has the additional advantage (besides punishing // Using the predecessor has the additional advantage (besides punishing
@ -124,10 +125,10 @@ void TrackSector::rescue()
// rescue loop since the kart moves back on each attempt. At this stage // rescue loop since the kart moves back on each attempt. At this stage
// STK does not keep track of where the kart is coming from, so always // STK does not keep track of where the kart is coming from, so always
// use the first predecessor, which is the one on the main driveline. // use the first predecessor, which is the one on the main driveline.
m_current_graph_node = QuadGraph::get()->getNode(m_current_graph_node) m_current_graph_node = DriveGraph::get()->getNode(m_current_graph_node)
->getPredecessor(0); ->getPredecessor(0);
m_last_valid_graph_node = QuadGraph::get()->getNode(m_current_graph_node) m_last_valid_graph_node = DriveGraph::get()->getNode(m_current_graph_node)
->getPredecessor(0); ->getPredecessor(0);
} // rescue } // rescue
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -137,7 +138,7 @@ void TrackSector::rescue()
*/ */
float TrackSector::getRelativeDistanceToCenter() const float TrackSector::getRelativeDistanceToCenter() const
{ {
float w = QuadGraph::get()->getNode(m_current_graph_node)->getPathWidth(); float w = DriveGraph::get()->getNode(m_current_graph_node)->getPathWidth();
// w * 0.5 is the distance from center of the quad to the left or right // w * 0.5 is the distance from center of the quad to the left or right
// This way we get a value between -1 and 1. // This way we get a value between -1 and 1.
float ratio = getDistanceToCenter()/(w*0.5f); float ratio = getDistanceToCenter()/(w*0.5f);