From 21dc569f703e6e26c7e6df31c83205f0f1a103c6 Mon Sep 17 00:00:00 2001 From: Benau Date: Sun, 4 Sep 2016 11:56:03 +0800 Subject: [PATCH] Start to clean up quad and graph node --- sources.cmake | 2 +- src/graphics/slip_stream.cpp | 2 +- src/items/bowling.cpp | 3 +- src/items/item.cpp | 2 + src/items/item_manager.cpp | 7 +- src/items/rubber_ball.cpp | 9 +- .../controller/ai_base_lap_controller.cpp | 2 +- src/karts/controller/end_controller.cpp | 7 +- src/karts/controller/skidding_ai.cpp | 172 +++++------- src/karts/controller/skidding_ai.hpp | 10 +- src/karts/controller/test_ai.cpp | 213 +++++++++------ src/karts/controller/test_ai.hpp | 7 +- src/karts/kart.cpp | 8 +- src/modes/linear_world.cpp | 7 +- src/physics/physical_object.cpp | 1 + src/scriptengine/script_engine.hpp | 2 + src/tracks/battle_graph.cpp | 15 +- src/tracks/battle_graph.hpp | 2 +- src/tracks/check_manager.cpp | 3 +- src/tracks/graph_node.cpp | 254 +++--------------- src/tracks/graph_node.hpp | 171 +++++------- src/tracks/navmesh.cpp | 8 + src/tracks/node_2d.cpp | 69 +++++ src/tracks/node_2d.hpp | 55 ++++ src/tracks/node_3d.cpp | 94 +++++++ src/tracks/node_3d.hpp | 64 +++++ src/tracks/quad.cpp | 91 +------ src/tracks/quad.hpp | 55 ++-- src/tracks/quad_graph.cpp | 244 +++++++++++------ src/tracks/quad_graph.hpp | 69 ++--- src/tracks/quad_set.cpp | 124 --------- src/tracks/quad_set.hpp | 90 ------- src/tracks/track.cpp | 13 +- src/tracks/track.hpp | 16 +- src/tracks/track_sector.cpp | 4 +- 35 files changed, 867 insertions(+), 1028 deletions(-) create mode 100644 src/tracks/node_2d.cpp create mode 100644 src/tracks/node_2d.hpp create mode 100644 src/tracks/node_3d.cpp create mode 100644 src/tracks/node_3d.hpp delete mode 100644 src/tracks/quad_set.cpp delete mode 100644 src/tracks/quad_set.hpp diff --git a/sources.cmake b/sources.cmake index f484b15d5..ddc029d4f 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") diff --git a/src/graphics/slip_stream.cpp b/src/graphics/slip_stream.cpp index aebb95134..dea3781c6 100644 --- a/src/graphics/slip_stream.cpp +++ b/src/graphics/slip_stream.cpp @@ -457,7 +457,7 @@ void SlipStream::update(float dt) } // Real test: if in slipstream quad of other kart if(m_target_kart->getSlipstream()->m_slipstream_quad - ->pointInQuad(m_kart->getXYZ())) + ->pointInside(m_kart->getXYZ())) { is_sstreaming = true; break; diff --git a/src/items/bowling.cpp b/src/items/bowling.cpp index aa3070ae1..dd2971fcf 100644 --- a/src/items/bowling.cpp +++ b/src/items/bowling.cpp @@ -26,6 +26,7 @@ #include "karts/abstract_kart.hpp" #include "modes/linear_world.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 @@ -63,7 +64,7 @@ Bowling::Bowling(AbstractKart *kart) { unsigned int sector = ((LinearWorld*)World::getWorld())-> getTrackSector(kart->getWorldKartId()).getCurrentGraphNode(); - quadNormal = QuadGraph::get()->getQuadOfNode(sector).getNormal(); + quadNormal = QuadGraph::get()->getNode(sector).getNormal(); } else quadNormal = btVector3(.0f, 1.0f, .0f); diff --git a/src/items/item.cpp b/src/items/item.cpp index 8f5a0c07b..d1dd8ca0e 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -25,6 +25,8 @@ #include "modes/easter_egg_hunt.hpp" #include "modes/three_strikes_battle.hpp" #include "modes/world.hpp" +#include "tracks/graph_node.hpp" +#include "tracks/quad_graph.hpp" #include "tracks/track.hpp" #include "utils/constants.hpp" #include "utils/vec3.hpp" diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp index 3141547f3..6d72e8d87 100644 --- a/src/items/item_manager.cpp +++ b/src/items/item_manager.cpp @@ -32,8 +32,9 @@ #include "modes/linear_world.hpp" #include "network/network_config.hpp" #include "network/race_event_manager.hpp" -#include "tracks/quad_graph.hpp" #include "tracks/battle_graph.hpp" +#include "tracks/graph_node.hpp" +#include "tracks/quad_graph.hpp" #include "tracks/track.hpp" #include "utils/string_utils.hpp" @@ -162,7 +163,7 @@ ItemManager::ItemManager() m_items_in_quads = new std::vector; // Entries 0 to n-1 are for the quads, entry // n is for all items that are not on a quad. - m_items_in_quads->resize(QuadSet::get()->getNumberOfQuads()+1); + m_items_in_quads->resize(QuadGraph::get()->getNumNodes()+1); } else { @@ -227,7 +228,7 @@ void ItemManager::insertItem(Item *item) // If the item is on the driveline, store it at the appropriate index if(graph_node > -1) { - int sector = QuadGraph::get()->getNode(graph_node).getQuadIndex(); + int sector = QuadGraph::get()->getNode(graph_node).getNodeIndex(); (*m_items_in_quads)[sector].push_back(item); } else // otherwise store it in the 'outside' index diff --git a/src/items/rubber_ball.cpp b/src/items/rubber_ball.cpp index c46611daf..961c2fbfe 100644 --- a/src/items/rubber_ball.cpp +++ b/src/items/rubber_ball.cpp @@ -29,6 +29,8 @@ #include "modes/linear_world.hpp" #include "physics/btKart.hpp" #include "physics/triangle_mesh.hpp" +#include "tracks/graph_node.hpp" +#include "tracks/quad_graph.hpp" #include "tracks/track.hpp" #include "utils/log.hpp" //TODO: remove after debugging is done @@ -97,7 +99,8 @@ RubberBall::RubberBall(AbstractKart *kart) // initialises the current graph node TrackSector::update(getXYZ()); - Vec3 normal = QuadGraph::get()->getQuadOfNode(getCurrentGraphNode()).getNormal(); + const Vec3& normal = + QuadGraph::get()->getNode(getCurrentGraphNode()).getNormal(); TerrainInfo::update(getXYZ(), -normal); initializeControlPoints(m_owner->getXYZ()); @@ -133,7 +136,7 @@ void RubberBall::initializeControlPoints(const Vec3 &xyz) // left or right when firing the ball off track. getNextControlPoint(); m_control_points[2] = - QuadGraph::get()->getQuadOfNode(m_last_aimed_graph_node).getCenter(); + QuadGraph::get()->getNode(m_last_aimed_graph_node).getCenter(); // This updates m_last_aimed_graph_node, and sets m_control_points[3] getNextControlPoint(); @@ -234,7 +237,7 @@ void RubberBall::getNextControlPoint() m_last_aimed_graph_node = next; m_length_cp_2_3 = dist; const Quad &quad = - QuadGraph::get()->getQuadOfNode(m_last_aimed_graph_node); + QuadGraph::get()->getNode(m_last_aimed_graph_node); m_control_points[3] = quad.getCenter(); } // getNextControlPoint diff --git a/src/karts/controller/ai_base_lap_controller.cpp b/src/karts/controller/ai_base_lap_controller.cpp index 899cfb5ed..23c5f0647 100644 --- a/src/karts/controller/ai_base_lap_controller.cpp +++ b/src/karts/controller/ai_base_lap_controller.cpp @@ -25,7 +25,7 @@ #include "karts/kart_properties.hpp" #include "karts/controller/ai_properties.hpp" #include "modes/linear_world.hpp" -#include "tracks/track.hpp" +#include "tracks/quad_graph.hpp" #include "utils/constants.hpp" diff --git a/src/karts/controller/end_controller.cpp b/src/karts/controller/end_controller.cpp index efe1f6134..5881c23a8 100644 --- a/src/karts/controller/end_controller.cpp +++ b/src/karts/controller/end_controller.cpp @@ -45,6 +45,7 @@ #include "modes/linear_world.hpp" #include "race/race_manager.hpp" #include "states_screens/race_result_gui.hpp" +#include "tracks/graph_node.hpp" #include "tracks/quad_graph.hpp" #include "tracks/track.hpp" #include "utils/constants.hpp" @@ -214,7 +215,7 @@ void EndController::handleSteering(float dt) 0.5f* QuadGraph::get()->getNode(m_track_node).getPathWidth()+0.5f ) { const int next = m_next_node_index[m_track_node]; - target_point = QuadGraph::get()->getQuadOfNode(next).getCenter(); + target_point = QuadGraph::get()->getNode(next).getCenter(); #ifdef AI_DEBUG Log::debug("end_controller.cpp", "- Outside of road: steer to center point."); #endif @@ -274,7 +275,7 @@ void EndController::findNonCrashingPoint(Vec3 *result) target_sector = m_next_node_index[sector]; //direction is a vector from our kart to the sectors we are testing - direction = QuadGraph::get()->getQuadOfNode(target_sector).getCenter() + direction = QuadGraph::get()->getNode(target_sector).getCenter() - m_kart->getXYZ(); float len=direction.length_2d(); @@ -301,7 +302,7 @@ void EndController::findNonCrashingPoint(Vec3 *result) if ( distance + m_kart_width * 0.5f > QuadGraph::get()->getNode(sector).getPathWidth()*0.5f ) { - *result = QuadGraph::get()->getQuadOfNode(sector).getCenter(); + *result = QuadGraph::get()->getNode(sector).getCenter(); return; } } diff --git a/src/karts/controller/skidding_ai.cpp b/src/karts/controller/skidding_ai.cpp index 5c311258e..49ec74084 100644 --- a/src/karts/controller/skidding_ai.cpp +++ b/src/karts/controller/skidding_ai.cpp @@ -224,10 +224,7 @@ void SkiddingAI::update(float dt) // This is used to enable firing an item backwards. m_controls->m_look_back = false; m_controls->m_nitro = false; - - //Vec3 gravity = m_kart->getBody()->getGravity(); - //Log::info("Sector", "%f %f %f %d", gravity[0], gravity[1], gravity[2],m_track_node); - + // Don't do anything if there is currently a kart animations shown. if(m_kart->getKartAnimation()) return; @@ -378,7 +375,7 @@ void SkiddingAI::update(float dt) m_controls->m_fire = true; } } - + /*And obviously general kart stuff*/ AIBaseLapController::update(dt); } // update @@ -481,11 +478,11 @@ void SkiddingAI::handleSteering(float dt) if( fabsf(side_dist) > 0.5f* QuadGraph::get()->getNode(m_track_node).getPathWidth()+0.5f ) { - steer_angle = steerToPoint(QuadGraph::get()->getQuadOfNode(next) + steer_angle = steerToPoint(QuadGraph::get()->getNode(next) .getCenter()); #ifdef AI_DEBUG - m_debug_sphere[0]->setPosition(QuadGraph::get()->getQuadOfNode(next) + m_debug_sphere[0]->setPosition(QuadGraph::get()->getNode(next) .getCenter().toIrrVector()); Log::debug(getControllerName().c_str(), "Outside of road: steer to center point."); @@ -622,10 +619,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, #ifdef AI_DEBUG m_item_sphere->setVisible(false); #endif - // Angle of line from kart to aim_point - float kart_aim_angle = atan2(aim_point->getX()-m_kart->getXYZ().getX(), - aim_point->getZ()-m_kart->getXYZ().getZ()); - + // Angle to aim_point Vec3 kart_aim_direction = *aim_point - m_kart->getXYZ(); // Make sure we have a valid last_node @@ -642,9 +636,9 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, const float max_item_lookahead_distance = 30.f; while(distance < max_item_lookahead_distance) { - int q_index= QuadGraph::get()->getNode(node).getQuadIndex(); + int n_index= QuadGraph::get()->getNode(node).getNodeIndex(); const std::vector &items_ahead = - ItemManager::get()->getItemsInQuads(q_index); + ItemManager::get()->getItemsInQuads(n_index); for(unsigned int i=0; i0; - core::line2df line_to_target(aim_point->getX(), - aim_point->getZ(), - m_kart->getXYZ().getX(), - m_kart->getXYZ().getZ()); - - core::line3df line_to_target_3d((*aim_point).toIrrVector(), + core::line3df line_to_target_3d((*aim_point).toIrrVector(), m_kart->getXYZ().toIrrVector()); - + // 2) If the kart is aiming for an item, but (suddenly) detects // some close-by items to avoid (e.g. behind the item, which was too // far away to be considered earlier, or because the item was switched @@ -792,7 +781,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, // so that it can potentially become a permanent target. Vec3 xyz = item_to_collect->getXYZ(); Vec3 item_direction = xyz - m_kart->getXYZ(); - Vec3 plane_normal = QuadGraph::get()->getQuadOfNode(m_track_node) + Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node) .getNormal(); float dist_to_plane = item_direction.dot(plane_normal); Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; @@ -840,7 +829,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, bool SkiddingAI::hitBadItemWhenAimAt(const Item *item, const std::vector &items_to_avoid) { - core::line3df to_item(m_kart->getXYZ().toIrrVector(), + core::line3df to_item(m_kart->getXYZ().toIrrVector(), item->getXYZ().toIrrVector()); for(unsigned int i=0; igetXYZ(); Vec3 item_direction = xyz - m_kart->getXYZ(); - Vec3 plane_normal = QuadGraph::get()->getQuadOfNode(m_track_node) - .getNormal(); + Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node).getNormal(); float dist_to_plane = item_direction.dot(plane_normal); Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; @@ -936,12 +924,9 @@ bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, // Check if we would drive left of the leftmost or right of the // rightmost point - if so, nothing to do. - - //core::vector2df left(items_to_avoid[index_left_most]->getXYZ().getX(), - // items_to_avoid[index_left_most]->getXYZ().getZ()); Vec3 left(items_to_avoid[index_left_most]->getXYZ()); int node_index = items_to_avoid[index_left_most]->getGraphNode(); - Vec3 normal = QuadGraph::get()->getQuadOfNode(node_index).getNormal(); + Vec3 normal = QuadGraph::get()->getNode(node_index).getNormal(); Vec3 p1 = line_to_target.start, p2 = line_to_target.getMiddle() + normal.toIrrVector(), p3 = line_to_target.end; @@ -959,11 +944,9 @@ bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, } else { - //core::vector2df right(items_to_avoid[index_right_most]->getXYZ().getX(), - // items_to_avoid[index_right_most]->getXYZ().getZ()); Vec3 left(items_to_avoid[index_left_most]->getXYZ()); int node_index = items_to_avoid[index_left_most]->getGraphNode(); - Vec3 normal = QuadGraph::get()->getQuadOfNode(node_index).getNormal(); + Vec3 normal = QuadGraph::get()->getNode(node_index).getNormal(); Vec3 p1 = line_to_target.start, p2 = line_to_target.getMiddle() + normal.toIrrVector(), p3 = line_to_target.end; @@ -1121,11 +1104,10 @@ 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. const Vec3 &xyz = item->getXYZ(); Vec3 item_direction = xyz - m_kart->getXYZ(); - Vec3 plane_normal = QuadGraph::get()->getQuadOfNode(m_track_node) - .getNormal(); + Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node).getNormal(); float dist_to_plane = item_direction.dot(plane_normal); Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; - + float angle_to_item = (projected_xyz - m_kart->getXYZ()) .angle(kart_aim_direction); @@ -1879,23 +1861,23 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node) *last_node = m_next_node_index[m_track_node]; const core::vector2df xz = m_kart->getXYZ().toIrrVector2d(); - const Quad &q = QuadGraph::get()->getQuadOfNode(*last_node); + const GraphNode &g = QuadGraph::get()->getNode(*last_node); // Index of the left and right end of a quad. const unsigned int LEFT_END_POINT = 0; const unsigned int RIGHT_END_POINT = 1; - core::line2df left (xz, q[LEFT_END_POINT ].toIrrVector2d()); - core::line2df right(xz, q[RIGHT_END_POINT].toIrrVector2d()); + core::line2df left (xz, g[LEFT_END_POINT ].toIrrVector2d()); + core::line2df right(xz, g[RIGHT_END_POINT].toIrrVector2d()); #if defined(AI_DEBUG) && defined(AI_DEBUG_NEW_FIND_NON_CRASHING) const Vec3 eps1(0,0.5f,0); m_curve[CURVE_LEFT]->clear(); m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1); - m_curve[CURVE_LEFT]->addPoint(q[LEFT_END_POINT]+eps1); + m_curve[CURVE_LEFT]->addPoint(g[LEFT_END_POINT]+eps1); m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_RIGHT]->clear(); m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1); - m_curve[CURVE_RIGHT]->addPoint(q[RIGHT_END_POINT]+eps1); + m_curve[CURVE_RIGHT]->addPoint(g[RIGHT_END_POINT]+eps1); m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1); #endif #if defined(AI_DEBUG_KART_HEADING) || defined(AI_DEBUG_NEW_FIND_NON_CRASHING) @@ -1908,13 +1890,13 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node) while(1) { unsigned int next_sector = m_next_node_index[*last_node]; - const Quad &q_next = QuadGraph::get()->getQuadOfNode(next_sector); + const GraphNode &g_next = QuadGraph::get()->getNode(next_sector); // Test if the next left point is to the right of the left // line. If so, a new left line is defined. - if(left.getPointOrientation(q_next[LEFT_END_POINT].toIrrVector2d()) + if(left.getPointOrientation(g_next[LEFT_END_POINT].toIrrVector2d()) < 0 ) { - core::vector2df p = q_next[LEFT_END_POINT].toIrrVector2d(); + core::vector2df p = g_next[LEFT_END_POINT].toIrrVector2d(); // Stop if the new point is to the right of the right line if(right.getPointOrientation(p)<0) break; @@ -1930,10 +1912,10 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node) // Test if new right point is to the left of the right line. If // so, a new right line is defined. - if(right.getPointOrientation(q_next[RIGHT_END_POINT].toIrrVector2d()) + if(right.getPointOrientation(g_next[RIGHT_END_POINT].toIrrVector2d()) > 0 ) { - core::vector2df p = q_next[RIGHT_END_POINT].toIrrVector2d(); + core::vector2df p = g_next[RIGHT_END_POINT].toIrrVector2d(); // Break if new point is to the left of left line if(left.getPointOrientation(p)>0) break; @@ -1955,7 +1937,7 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node) // 0.5f*(left.end.Y+right.end.Y)); //*result = ppp; - *result = QuadGraph::get()->getQuadOfNode(*last_node).getCenter(); + *result = QuadGraph::get()->getNode(*last_node).getCenter(); } // findNonCrashingPointNew //----------------------------------------------------------------------------- @@ -1992,10 +1974,10 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node) target_sector = m_next_node_index[*last_node]; //direction is a vector from our kart to the sectors we are testing - direction = QuadGraph::get()->getQuadOfNode(target_sector).getCenter() + direction = QuadGraph::get()->getNode(target_sector).getCenter() - m_kart->getXYZ(); - float len=direction.length_2d(); + float len=direction.length(); unsigned int steps = (unsigned int)( len / m_kart_length ); if( steps < 3 ) steps = 3; @@ -2024,20 +2006,28 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node) if ( distance + m_kart_width * 0.5f > QuadGraph::get()->getNode(*last_node).getPathWidth()*0.5f ) { - *aim_position = QuadGraph::get()->getQuadOfNode(*last_node) + *aim_position = QuadGraph::get()->getNode(*last_node) .getCenter(); return; } } *last_node = target_sector; } // for i<100 - *aim_position = QuadGraph::get()->getQuadOfNode(*last_node).getCenter(); + *aim_position = QuadGraph::get()->getNode(*last_node).getCenter(); } // findNonCrashingPointFixed //----------------------------------------------------------------------------- /** This is basically the original AI algorithm. It is clearly buggy: * 1. the test: * + * distance + m_kart_width * 0.5f + * > QuadGraph::get()->getNode(*last_node).getPathWidth() ) + * + * 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 + * the point is at the edge). + * 2. the test: + * * QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord, * *last_node ); * in the for loop tests always against distance from the same @@ -2050,17 +2040,10 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node) * which takes some time - so it is actually mostly on track. * Since this algoritm (so far) ends up with by far the best AI behaviour, * it is for now the default). - * - * GSoC 2014: This algorithm has been updated so that the AI can drive on - * upside-down tracks. Because steering only works in 2D, you can steer left and - * right but not up and down, but the track might not be 2D. So for every quad, - * we have a set of k unrolled quads starting from the current quad. The AI uses - * these unrolled quads to search for a suitable aim point. - * * \param aim_position On exit contains the point the AI should aim at. * \param last_node On exit contais the graph node the AI is aiming at. */ -void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node) + void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node) { #ifdef AI_DEBUG_KART_HEADING const Vec3 eps(0,0.5f,0); @@ -2069,7 +2052,7 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node) Vec3 forw(0, 0, 50); m_curve[CURVE_KART]->addPoint(m_kart->getTrans()(forw)+eps); #endif - *last_node = m_track_node; + *last_node = m_next_node_index[m_track_node]; float angle = QuadGraph::get()->getAngleToNext(m_track_node, m_successor_index[m_track_node]); int target_sector; @@ -2078,30 +2061,14 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node) Vec3 step_track_coord; float angle1; - - // We need to find out if there is an alternate path that the kart might take. - // This is done in advance so that the right set of unrolled quads are used - // and the AI finds aim_points on the alternate path. future_successor_idx - // is successor index of a future node. 0 is the default, but if there is an - // alternate path coming up, this will be set to 1. - int future_successor_idx = 0; - int current = m_track_node; - for (unsigned int j = 0; j < QuadGraph::get()->getNumberOfUnrolledQuads(); j++) - { - if (m_successor_index[current] != 0) - future_successor_idx = m_successor_index[current]; - - current = m_next_node_index[current]; - } - - // This for loop runs till it runs out of unrolled quads or breaks when the - // aim point is outside one of the unrolled quads. - for(unsigned int j=0; jgetNumberOfUnrolledQuads(); j++) + // The original while(1) loop is replaced with a for loop to avoid + // infinite loops (which we had once or twice). Usually the number + // of iterations in the while loop is less than 7. + for(unsigned int j=0; j<100; j++) { // target_sector is the sector at the longest distance that we can // drive to without crashing with the track. target_sector = m_next_node_index[*last_node]; - angle1 = QuadGraph::get()->getAngleToNext(target_sector, m_successor_index[target_sector]); // In very sharp turns this algorithm tends to aim at off track points, @@ -2110,17 +2077,16 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node) float diff = normalizeAngle(angle1-angle); if(fabsf(diff)>1.5f) { - *aim_position = QuadGraph::get()->getQuadOfNode(target_sector) - .getCenter(); + *aim_position = QuadGraph::get()->getNode(target_sector) + .getCenter(); return; } - Quad target_quad_unrolled = QuadGraph::get()->getNode(m_track_node). - getUnrolledQuad(future_successor_idx,j + 1); + //direction is a vector from our kart to the sectors we are testing + direction = QuadGraph::get()->getNode(target_sector).getCenter() + - m_kart->getXYZ(); - direction = target_quad_unrolled.getCenter() - m_kart->getXYZ(); - - float len = direction.length(); + float len=direction.length(); unsigned int steps = (unsigned int)( len / m_kart_length ); if( steps < 3 ) steps = 3; @@ -2130,38 +2096,34 @@ void SkiddingAI::findNonCrashingPoint(Vec3 *aim_position, int *last_node) if( steps>1000) steps = 1000; // Protection against having vel_normal with nan values - if(len>0.0f) - { + if(len>0.0f) { direction*= 1.0f/len; } Vec3 step_coord; - //Test if we crash if we drive towards the target sector (unrolled set) + //Test if we crash if we drive towards the target sector for(unsigned int i = 2; i < steps; ++i ) { step_coord = m_kart->getXYZ()+direction*m_kart_length * float(i); - QuadGraph::get()->spatialToTrackUnrolled(&step_track_coord, step_coord, - m_track_node, j, future_successor_idx); + QuadGraph::get()->spatialToTrack(&step_track_coord, step_coord, + *last_node ); - float distance = 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 ( distance + m_kart_width * 0.5f - > QuadGraph::get()->getNode((*last_node+j)%QuadGraph::get()->getNumNodes() ).getPathWidth()*0.5f ) + > QuadGraph::get()->getNode(*last_node).getPathWidth() ) { - *aim_position = QuadGraph::get()->getUnrolledQuadOfNode(m_track_node,future_successor_idx,j+1) + *aim_position = QuadGraph::get()->getNode(*last_node) .getCenter(); return; } } angle = angle1; *last_node = target_sector; - } - // If we are inside entire unrolled set then set the aim_point to be center of the last unrolled quad - *aim_position = QuadGraph::get()->getNode(m_track_node). - getUnrolledQuad(future_successor_idx,QuadGraph::get()->getNumberOfUnrolledQuads()).getCenter(); - + } // for i<100 + *aim_position = QuadGraph::get()->getNode(*last_node).getCenter(); } // findNonCrashingPoint //----------------------------------------------------------------------------- @@ -2176,9 +2138,9 @@ void SkiddingAI::determineTrackDirection() //float angle_to_track = qg->getNode(m_track_node).getAngleToSuccessor(succ) // - m_kart->getHeading(); - Vec3 track_direction = -qg->getQuadOfNode(m_track_node).getCenter() - + qg->getQuadOfNode(next).getCenter(); - //Vec3 kart_direction = qg->getQuadOfNode(m_track_node).getCenter() + m_kart->getVelocity(); + Vec3 track_direction = -qg->getNode(m_track_node).getCenter() + + qg->getNode(next).getCenter(); + //Vec3 kart_direction = qg->getNode(m_track_node).getCenter() + m_kart->getVelocity(); float angle_to_track = 0; if (m_kart->getVelocity().length() > 0.0f) @@ -2203,8 +2165,6 @@ void SkiddingAI::determineTrackDirection() return; } - - qg->getNode(next).getDirectionData(m_successor_index[next], &m_current_track_direction, &m_last_direction_node); @@ -2265,10 +2225,10 @@ void SkiddingAI::handleCurve() // Pick either the lower left or right point: int index = m_current_track_direction==GraphNode::DIR_LEFT ? 0 : 1; - float r = (m_curve_center - qg->getQuadOfNode(i)[index]).length(); + float r = (m_curve_center - qg->getNode(i)[index]).length(); if(m_current_curve_radius < r) { - last_xyz = qg->getQuadOfNode(i)[index]; + last_xyz = qg->getNode(i)[index]; determineTurnRadius(xyz, tangent, last_xyz, &m_curve_center, &m_current_curve_radius); m_last_direction_node = i; diff --git a/src/karts/controller/skidding_ai.hpp b/src/karts/controller/skidding_ai.hpp index 7762c3ba4..cfbbd4863 100644 --- a/src/karts/controller/skidding_ai.hpp +++ b/src/karts/controller/skidding_ai.hpp @@ -31,15 +31,15 @@ #ifdef DEBUG // Enable AI graphical debugging -# undef AI_DEBUG +# define AI_DEBUG // Shows left and right lines when using new findNonCrashing function -# undef AI_DEBUG_NEW_FIND_NON_CRASHING +# define AI_DEBUG_NEW_FIND_NON_CRASHING // Show the predicted turn circles -# undef AI_DEBUG_CIRCLES +# define AI_DEBUG_CIRCLES // Show the heading of the kart -# undef AI_DEBUG_KART_HEADING +# define AI_DEBUG_KART_HEADING // Shows line from kart to its aim point -# undef AI_DEBUG_KART_AIM +# define AI_DEBUG_KART_AIM #endif diff --git a/src/karts/controller/test_ai.cpp b/src/karts/controller/test_ai.cpp index 8033db4b4..15cf5303f 100644 --- a/src/karts/controller/test_ai.cpp +++ b/src/karts/controller/test_ai.cpp @@ -484,11 +484,11 @@ void SkiddingAI::handleSteering(float dt) if( fabsf(side_dist) > 0.5f* QuadGraph::get()->getNode(m_track_node).getPathWidth()+0.5f ) { - steer_angle = steerToPoint(QuadGraph::get()->getQuadOfNode(next) + steer_angle = steerToPoint(QuadGraph::get()->getNode(next) .getCenter()); #ifdef AI_DEBUG - m_debug_sphere[0]->setPosition(QuadGraph::get()->getQuadOfNode(next) + m_debug_sphere[0]->setPosition(QuadGraph::get()->getNode(next) .getCenter().toIrrVector()); Log::debug(getControllerName().c_str(), "Outside of road: steer to center point."); @@ -621,13 +621,12 @@ void SkiddingAI::handleSteering(float dt) */ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, int last_node) -{/* +{ #ifdef AI_DEBUG m_item_sphere->setVisible(false); #endif - // Angle of line from kart to aim_point - float kart_aim_angle = atan2(aim_point->getX()-m_kart->getXYZ().getX(), - aim_point->getZ()-m_kart->getXYZ().getZ()); + // Angle to aim_point + Vec3 kart_aim_direction = *aim_point - m_kart->getXYZ(); // Make sure we have a valid last_node if(last_node==QuadGraph::UNKNOWN_SECTOR) @@ -643,12 +642,12 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, const float max_item_lookahead_distance = 30.f; while(distance < max_item_lookahead_distance) { - int q_index= QuadGraph::get()->getNode(node).getQuadIndex(); + int n_index= QuadGraph::get()->getNode(node).getNodeIndex(); const std::vector &items_ahead = - ItemManager::get()->getItemsInQuads(q_index); + ItemManager::get()->getItemsInQuads(n_index); for(unsigned int i=0; igetDistanceToNext(node, @@ -660,10 +659,8 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, m_avoid_item_close = items_to_avoid.size()>0; - core::line2df line_to_target(aim_point->getX(), - aim_point->getZ(), - m_kart->getXYZ().getX(), - m_kart->getXYZ().getZ()); + core::line3df line_to_target_3d((*aim_point).toIrrVector(), + m_kart->getXYZ().toIrrVector()); // 2) If the kart is aiming for an item, but (suddenly) detects // some close-by items to avoid (e.g. behind the item, which was too @@ -676,7 +673,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, for(unsigned int i=0; i< items_to_avoid.size(); i++) { Vec3 d = items_to_avoid[i]->getXYZ()-m_item_to_collect->getXYZ(); - if( d.length2_2d()>m_ai_properties->m_bad_item_closeness_2) + if( d.length2()>m_ai_properties->m_bad_item_closeness_2) continue; // It could make sense to also test if the bad item would // actually be hit, not only if it is close (which can result @@ -696,7 +693,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, // ------------------------------------- if(m_item_to_collect) { - if(handleSelectedItem(kart_aim_angle, aim_point)) + if(handleSelectedItem(kart_aim_direction, aim_point)) { // Still aim at the previsouly selected item. *aim_point = m_item_to_collect->getXYZ(); @@ -721,7 +718,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, { // If we need to steer to avoid an item, this takes priority, // ignore items to collect and return the new aim_point. - if(steerToAvoid(items_to_avoid, line_to_target, aim_point)) + if(steerToAvoid(items_to_avoid, line_to_target_3d, aim_point)) { #ifdef AI_DEBUG m_item_sphere->setVisible(true); @@ -770,7 +767,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, // it's on a good enough driveline, so make this item a permanent // target. Otherwise only try to get closer (till hopefully this // item s on our driveline) - if(item_to_collect->hitLine(line_to_target, m_kart)) + if(item_to_collect->hitLine(line_to_target_3d, m_kart)) { #ifdef AI_DEBUG m_item_sphere->setVisible(true); @@ -789,9 +786,15 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, // Kart will not hit item, try to get closer to this item // so that it can potentially become a permanent target. Vec3 xyz = item_to_collect->getXYZ(); - float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(), - xyz.getZ() - m_kart->getXYZ().getZ()); - float angle = normalizeAngle(kart_aim_angle - item_angle); + Vec3 item_direction = xyz - m_kart->getXYZ(); + Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node) + .getNormal(); + float dist_to_plane = item_direction.dot(plane_normal); + Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; + + float angle_to_item = (projected_xyz - m_kart->getXYZ()) + .angle(kart_aim_direction); + float angle = normalizeAngle(angle_to_item); if(fabsf(angle) < 0.3) { @@ -818,7 +821,7 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, } // kart will not hit item } // does hit hit bad item } // if item to consider was found -*/ + } // handleItemCollectionAndAvoidance //----------------------------------------------------------------------------- @@ -832,13 +835,13 @@ void SkiddingAI::handleItemCollectionAndAvoidance(Vec3 *aim_point, bool SkiddingAI::hitBadItemWhenAimAt(const Item *item, const std::vector &items_to_avoid) { -/* core::line2df to_item(m_kart->getXYZ().getX(), m_kart->getXYZ().getZ(), - item->getXYZ().getX(), item->getXYZ().getZ() ); + core::line3df to_item(m_kart->getXYZ().toIrrVector(), + item->getXYZ().toIrrVector()); for(unsigned int i=0; ihitLine(to_item, m_kart)) return true; - }*/ + } return false; } // hitBadItemWhenAimAt @@ -854,7 +857,7 @@ bool SkiddingAI::hitBadItemWhenAimAt(const Item *item, * \param last_node * \return True if th AI should still aim for the pre-selected item. */ -bool SkiddingAI::handleSelectedItem(float kart_aim_angle, Vec3 *aim_point) +bool SkiddingAI::handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point) { // If the item is unavailable keep on testing. It is not necessary // to test if an item has turned bad, this was tested before this @@ -862,11 +865,21 @@ bool SkiddingAI::handleSelectedItem(float kart_aim_angle, Vec3 *aim_point) if(m_item_to_collect->getDisableTime()>0) return false; + // Project the item's location onto the plane of the current quad. + // This is necessary because the kart's aim point may not be on the track + // in 3D curves. So we project the item's location onto the plane in which + // the kart is. The current quad provides a good estimate of the kart's plane. const Vec3 &xyz = m_item_to_collect->getXYZ(); - float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(), - xyz.getZ() - m_kart->getXYZ().getZ()); + Vec3 item_direction = xyz - m_kart->getXYZ(); + Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node).getNormal(); + float dist_to_plane = item_direction.dot(plane_normal); + Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; + + float angle_to_item = (projected_xyz - m_kart->getXYZ()) + .angle(kart_aim_direction); + + float angle = normalizeAngle(angle_to_item); - float angle = normalizeAngle(kart_aim_angle - item_angle); if(fabsf(angle)>1.5) { // We (likely) have passed the item we were aiming for @@ -891,10 +904,10 @@ bool SkiddingAI::handleSelectedItem(float kart_aim_angle, Vec3 *aim_point) * \return True if steering is necessary to avoid an item. */ bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, - const core::line2df &line_to_target, + const core::line3df &line_to_target, Vec3 *aim_point) { -/* // First determine the left-most and right-most item. + // First determine the left-most and right-most item. float left_most = items_to_avoid[0]->getDistanceFromCenter(); float right_most = items_to_avoid[0]->getDistanceFromCenter(); int index_left_most = 0; @@ -917,14 +930,19 @@ bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, // Check if we would drive left of the leftmost or right of the // rightmost point - if so, nothing to do. - core::vector2df left(items_to_avoid[index_left_most]->getXYZ().getX(), - items_to_avoid[index_left_most]->getXYZ().getZ()); + Vec3 left(items_to_avoid[index_left_most]->getXYZ()); + int node_index = items_to_avoid[index_left_most]->getGraphNode(); + Vec3 normal = QuadGraph::get()->getNode(node_index).getNormal(); + Vec3 p1 = line_to_target.start, + p2 = line_to_target.getMiddle() + normal.toIrrVector(), + p3 = line_to_target.end; + int item_index = -1; bool is_left = false; // >=0 means the point is to the right of the line, or the line is // to the left of the point. - if(line_to_target.getPointOrientation(left)>=0) + if(left.sideofPlane(p1,p2,p3) <= 0) { // Left of leftmost point item_index = index_left_most; @@ -932,9 +950,14 @@ bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, } else { - core::vector2df right(items_to_avoid[index_right_most]->getXYZ().getX(), - items_to_avoid[index_right_most]->getXYZ().getZ()); - if(line_to_target.getPointOrientation(right)<=0) + Vec3 left(items_to_avoid[index_left_most]->getXYZ()); + int node_index = items_to_avoid[index_left_most]->getGraphNode(); + Vec3 normal = QuadGraph::get()->getNode(node_index).getNormal(); + Vec3 p1 = line_to_target.start, + p2 = line_to_target.getMiddle() + normal.toIrrVector(), + p3 = line_to_target.end; + + if (left.sideofPlane(p1, p2, p3) >= 0) { // Right of rightmost point item_index = index_right_most; @@ -975,20 +998,20 @@ bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, float min_distance[2] = {99999.9f, 99999.9f}; int index[2] = {-1, -1}; - core::vector2df closest2d[2]; + core::vector3df closest3d[2]; for(unsigned int i=0; igetXYZ(); core::vector2df item2d = xyz.toIrrVector2d(); - core::vector2df point2d = line_to_target.getClosestPoint(item2d); - float d = (xyz.toIrrVector2d() - point2d).getLengthSQ(); - float direction = line_to_target.getPointOrientation(item2d); - int ind = direction<0 ? 0 : 1; + core::vector3df point3d = line_to_target.getClosestPoint(xyz.toIrrVector()); + float d = (xyz.toIrrVector() - point3d).getLengthSQ(); + float direction = xyz.sideofPlane(p1,p2,p3); + int ind = direction<0 ? 1 : 0; if(d &items_to_avoid, // We are driving between item_to_avoid[index[0]] and ...[1]. // If we don't hit any of them, just keep on driving as normal - bool hit_left = items_to_avoid[index[0]]->hitKart(closest2d[0], m_kart); - bool hit_right = items_to_avoid[index[1]]->hitKart(closest2d[1], m_kart); + bool hit_left = items_to_avoid[index[0]]->hitKart(closest3d[0], m_kart); + bool hit_right = items_to_avoid[index[1]]->hitKart(closest3d[1], m_kart); if( !hit_left && !hit_right) return false; -*/ + // If we hit the left item, aim at the right avoidance point // of the left item. We might still hit the right item ... this might // still be better than going too far off track - //if(hit_left) - //{ - // *aim_point = - // *(items_to_avoid[index[0]]->getAvoidancePoint(/*left*/false)); - // return true; - //} + if(hit_left) + { + *aim_point = + *(items_to_avoid[index[0]]->getAvoidancePoint(/*left*/false)); + return true; + } // Now we must be hitting the right item, so try aiming at the left // avoidance point of the right item. - //*aim_point = *(items_to_avoid[index[1]]->getAvoidancePoint(/*left*/true)); - + *aim_point = *(items_to_avoid[index[1]]->getAvoidancePoint(/*left*/true)); return true; } // steerToAvoid @@ -1034,7 +1056,7 @@ bool SkiddingAI::steerToAvoid(const std::vector &items_to_avoid, * (NULL if no item was avoided so far). * \param item_to_collect A pointer to a previously selected item to collect. */ -void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle, +void SkiddingAI::evaluateItems(const Item *item, Vec3 kart_aim_direction, std::vector *items_to_avoid, std::vector *items_to_collect) { @@ -1082,13 +1104,20 @@ void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle, // to avoid are collected). if(!avoid) { - // item_angle The angle of the item (relative to the forward axis, - // so 0 means straight ahead in world coordinates!). + // Project the item's location onto the plane of the current quad. + // This is necessary because the kart's aim point may not be on the track + // in 3D curves. So we project the item's location onto the plane in which + // the kart is. The current quad provides a good estimate of the kart's plane. const Vec3 &xyz = item->getXYZ(); - float item_angle = atan2(xyz.getX() - m_kart->getXYZ().getX(), - xyz.getZ() - m_kart->getXYZ().getZ()); + Vec3 item_direction = xyz - m_kart->getXYZ(); + Vec3 plane_normal = QuadGraph::get()->getNode(m_track_node).getNormal(); + float dist_to_plane = item_direction.dot(plane_normal); + Vec3 projected_xyz = xyz - dist_to_plane*plane_normal; - float diff = normalizeAngle(kart_aim_angle-item_angle); + float angle_to_item = (projected_xyz - m_kart->getXYZ()) + .angle(kart_aim_direction); + + float diff = normalizeAngle(angle_to_item); // The kart is driving at high speed, when the current max speed // is higher than the max speed of the kart (which is caused by @@ -1117,14 +1146,14 @@ void SkiddingAI::evaluateItems(const Item *item, float kart_aim_angle, else list = items_to_collect; - float new_distance = (item->getXYZ() - m_kart->getXYZ()).length2_2d(); + float new_distance = (item->getXYZ() - m_kart->getXYZ()).length2(); // This list is usually very short, so use a simple bubble sort list->push_back(item); int i; for(i=(int)list->size()-2; i>=0; i--) { - float d = ((*list)[i]->getXYZ() - m_kart->getXYZ()).length2_2d(); + float d = ((*list)[i]->getXYZ() - m_kart->getXYZ()).length2(); if(d<=new_distance) { break; @@ -1881,23 +1910,23 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node) *last_node = m_next_node_index[m_track_node]; const core::vector2df xz = m_kart->getXYZ().toIrrVector2d(); - const Quad &q = QuadGraph::get()->getQuadOfNode(*last_node); + const GraphNode &g = QuadGraph::get()->getNode(*last_node); // Index of the left and right end of a quad. const unsigned int LEFT_END_POINT = 0; const unsigned int RIGHT_END_POINT = 1; - core::line2df left (xz, q[LEFT_END_POINT ].toIrrVector2d()); - core::line2df right(xz, q[RIGHT_END_POINT].toIrrVector2d()); + core::line2df left (xz, g[LEFT_END_POINT ].toIrrVector2d()); + core::line2df right(xz, g[RIGHT_END_POINT].toIrrVector2d()); #if defined(AI_DEBUG) && defined(AI_DEBUG_NEW_FIND_NON_CRASHING) const Vec3 eps1(0,0.5f,0); m_curve[CURVE_LEFT]->clear(); m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1); - m_curve[CURVE_LEFT]->addPoint(q[LEFT_END_POINT]+eps1); + m_curve[CURVE_LEFT]->addPoint(g[LEFT_END_POINT]+eps1); m_curve[CURVE_LEFT]->addPoint(m_kart->getXYZ()+eps1); m_curve[CURVE_RIGHT]->clear(); m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1); - m_curve[CURVE_RIGHT]->addPoint(q[RIGHT_END_POINT]+eps1); + m_curve[CURVE_RIGHT]->addPoint(g[RIGHT_END_POINT]+eps1); m_curve[CURVE_RIGHT]->addPoint(m_kart->getXYZ()+eps1); #endif #if defined(AI_DEBUG_KART_HEADING) || defined(AI_DEBUG_NEW_FIND_NON_CRASHING) @@ -1910,13 +1939,13 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node) while(1) { unsigned int next_sector = m_next_node_index[*last_node]; - const Quad &q_next = QuadGraph::get()->getQuadOfNode(next_sector); + const GraphNode &g_next = QuadGraph::get()->getNode(next_sector); // Test if the next left point is to the right of the left // line. If so, a new left line is defined. - if(left.getPointOrientation(q_next[LEFT_END_POINT].toIrrVector2d()) + if(left.getPointOrientation(g_next[LEFT_END_POINT].toIrrVector2d()) < 0 ) { - core::vector2df p = q_next[LEFT_END_POINT].toIrrVector2d(); + core::vector2df p = g_next[LEFT_END_POINT].toIrrVector2d(); // Stop if the new point is to the right of the right line if(right.getPointOrientation(p)<0) break; @@ -1932,10 +1961,10 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node) // Test if new right point is to the left of the right line. If // so, a new right line is defined. - if(right.getPointOrientation(q_next[RIGHT_END_POINT].toIrrVector2d()) + if(right.getPointOrientation(g_next[RIGHT_END_POINT].toIrrVector2d()) > 0 ) { - core::vector2df p = q_next[RIGHT_END_POINT].toIrrVector2d(); + core::vector2df p = g_next[RIGHT_END_POINT].toIrrVector2d(); // Break if new point is to the left of left line if(left.getPointOrientation(p)>0) break; @@ -1957,7 +1986,7 @@ void SkiddingAI::findNonCrashingPointNew(Vec3 *result, int *last_node) // 0.5f*(left.end.Y+right.end.Y)); //*result = ppp; - *result = QuadGraph::get()->getQuadOfNode(*last_node).getCenter(); + *result = QuadGraph::get()->getNode(*last_node).getCenter(); } // findNonCrashingPointNew //----------------------------------------------------------------------------- @@ -1994,10 +2023,10 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node) target_sector = m_next_node_index[*last_node]; //direction is a vector from our kart to the sectors we are testing - direction = QuadGraph::get()->getQuadOfNode(target_sector).getCenter() + direction = QuadGraph::get()->getNode(target_sector).getCenter() - m_kart->getXYZ(); - float len=direction.length_2d(); + float len=direction.length(); unsigned int steps = (unsigned int)( len / m_kart_length ); if( steps < 3 ) steps = 3; @@ -2026,14 +2055,14 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node) if ( distance + m_kart_width * 0.5f > QuadGraph::get()->getNode(*last_node).getPathWidth()*0.5f ) { - *aim_position = QuadGraph::get()->getQuadOfNode(*last_node) + *aim_position = QuadGraph::get()->getNode(*last_node) .getCenter(); return; } } *last_node = target_sector; } // for i<100 - *aim_position = QuadGraph::get()->getQuadOfNode(*last_node).getCenter(); + *aim_position = QuadGraph::get()->getNode(*last_node).getCenter(); } // findNonCrashingPointFixed //----------------------------------------------------------------------------- @@ -2097,16 +2126,16 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node) float diff = normalizeAngle(angle1-angle); if(fabsf(diff)>1.5f) { - *aim_position = QuadGraph::get()->getQuadOfNode(target_sector) - .getCenter(); + *aim_position = QuadGraph::get()->getNode(target_sector) + .getCenter(); return; } //direction is a vector from our kart to the sectors we are testing - direction = QuadGraph::get()->getQuadOfNode(target_sector).getCenter() + direction = QuadGraph::get()->getNode(target_sector).getCenter() - m_kart->getXYZ(); - float len=direction.length_2d(); + float len=direction.length(); unsigned int steps = (unsigned int)( len / m_kart_length ); if( steps < 3 ) steps = 3; @@ -2135,7 +2164,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node) if ( distance + m_kart_width * 0.5f > QuadGraph::get()->getNode(*last_node).getPathWidth() ) { - *aim_position = QuadGraph::get()->getQuadOfNode(*last_node) + *aim_position = QuadGraph::get()->getNode(*last_node) .getCenter(); return; } @@ -2143,7 +2172,7 @@ void SkiddingAI::findNonCrashingPointFixed(Vec3 *aim_position, int *last_node) angle = angle1; *last_node = target_sector; } // for i<100 - *aim_position = QuadGraph::get()->getQuadOfNode(*last_node).getCenter(); + *aim_position = QuadGraph::get()->getNode(*last_node).getCenter(); } // findNonCrashingPoint //----------------------------------------------------------------------------- @@ -2154,8 +2183,18 @@ void SkiddingAI::determineTrackDirection() { const QuadGraph *qg = QuadGraph::get(); unsigned int succ = m_successor_index[m_track_node]; - float angle_to_track = qg->getNode(m_track_node).getAngleToSuccessor(succ) - - m_kart->getHeading(); + unsigned int next = qg->getNode(m_track_node).getSuccessor(succ); + + //float angle_to_track = qg->getNode(m_track_node).getAngleToSuccessor(succ) + // - m_kart->getHeading(); + Vec3 track_direction = -qg->getNode(m_track_node).getCenter() + + qg->getNode(next).getCenter(); + //Vec3 kart_direction = qg->getNode(m_track_node).getCenter() + m_kart->getVelocity(); + + float angle_to_track = 0; + if (m_kart->getVelocity().length() > 0.0f) + angle_to_track = track_direction.angle(m_kart->getVelocity().normalized()); + angle_to_track = normalizeAngle(angle_to_track); // In certain circumstances (esp. S curves) it is possible that the @@ -2175,8 +2214,6 @@ void SkiddingAI::determineTrackDirection() return; } - unsigned int next = qg->getNode(m_track_node).getSuccessor(succ); - qg->getNode(next).getDirectionData(m_successor_index[next], &m_current_track_direction, &m_last_direction_node); @@ -2237,10 +2274,10 @@ void SkiddingAI::handleCurve() // Pick either the lower left or right point: int index = m_current_track_direction==GraphNode::DIR_LEFT ? 0 : 1; - float r = (m_curve_center - qg->getQuadOfNode(i)[index]).length(); + float r = (m_curve_center - qg->getNode(i)[index]).length(); if(m_current_curve_radius < r) { - last_xyz = qg->getQuadOfNode(i)[index]; + last_xyz = qg->getNode(i)[index]; determineTurnRadius(xyz, tangent, last_xyz, &m_curve_center, &m_current_curve_radius); m_last_direction_node = i; diff --git a/src/karts/controller/test_ai.hpp b/src/karts/controller/test_ai.hpp index 7befd2b7a..8d1ffb277 100644 --- a/src/karts/controller/test_ai.hpp +++ b/src/karts/controller/test_ai.hpp @@ -66,7 +66,6 @@ namespace irr * stage) identical to the Skidding AI. \ingroup controller */ - class TestAI : public AIBaseLapController { private: @@ -205,13 +204,13 @@ private: void computeNearestKarts(); void handleItemCollectionAndAvoidance(Vec3 *aim_point, int last_node); - bool handleSelectedItem(float kart_aim_angle, Vec3 *aim_point); + bool handleSelectedItem(Vec3 kart_aim_direction, Vec3 *aim_point); bool steerToAvoid(const std::vector &items_to_avoid, - const core::line2df &line_to_target, + const core::line3df &line_to_target, Vec3 *aim_point); bool hitBadItemWhenAimAt(const Item *item, const std::vector &items_to_avoid); - void evaluateItems(const Item *item, float kart_aim_angle, + void evaluateItems(const Item *item, Vec3 kart_aim_direction, std::vector *items_to_avoid, std::vector *items_to_collect); diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index e07932147..597fe1136 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -64,6 +64,8 @@ #include "physics/physics.hpp" #include "race/history.hpp" #include "tracks/terrain_info.hpp" +#include "tracks/quad_graph.hpp" +#include "tracks/graph_node.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/constants.hpp" @@ -1292,7 +1294,7 @@ void Kart::update(float dt) if (QuadGraph::get()) { sector = ((LinearWorld*)World::getWorld())->getTrackSector(getWorldKartId()).getCurrentGraphNode(); - quadNormal = QuadGraph::get()->getQuadOfNode(sector).getNormal(); + quadNormal = QuadGraph::get()->getNode(sector).getNormal(); btQuaternion q = getTrans().getRotation(); float roll = quadNormal.angle((Vec3(0, 1, 0).rotate(q.getAxis(), q.getAngle()))); @@ -1374,7 +1376,7 @@ void Kart::update(float dt) // We do this for now because dist_to_sector is not defined float dist_to_sector; if (QuadGraph::get()) - dist_to_sector = getXYZ().distance(QuadGraph::get()->getQuadOfNode(sector).getCenter()); + dist_to_sector = getXYZ().distance(QuadGraph::get()->getNode(sector).getCenter()); else dist_to_sector = 0; @@ -2421,7 +2423,7 @@ void Kart::updateSliding() if (QuadGraph::get()) { int sector = ((LinearWorld*)World::getWorld())->getTrackSector(getWorldKartId()).getCurrentGraphNode(); - Vec3 quadNormal = QuadGraph::get()->getQuadOfNode(sector).getNormal(); + Vec3 quadNormal = QuadGraph::get()->getNode(sector).getNormal(); Vec3 kart_up = m.getColumn(1); distanceFromUp = kart_up.dot(quadNormal); } diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index 0d880c597..ca72db1f0 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -26,9 +26,12 @@ #include "karts/abstract_kart.hpp" #include "karts/controller/controller.hpp" #include "karts/kart_properties.hpp" +#include "graphics/material.hpp" #include "physics/physics.hpp" #include "race/history.hpp" #include "states_screens/race_gui_base.hpp" +#include "tracks/graph_node.hpp" +#include "tracks/quad_graph.hpp" #include "tracks/track_sector.hpp" #include "tracks/track.hpp" #include "utils/constants.hpp" @@ -644,8 +647,8 @@ unsigned int LinearWorld::getRescuePositionIndex(AbstractKart *kart) // ------------------------------------------------------------------------ btTransform LinearWorld::getRescueTransform(unsigned int index) const { - const Vec3 &xyz = QuadGraph::get()->getQuadOfNode(index).getCenter(); - const Vec3 &normal = QuadGraph::get()->getQuadOfNode(index).getNormal(); + const Vec3 &xyz = QuadGraph::get()->getNode(index).getCenter(); + const Vec3 &normal = QuadGraph::get()->getNode(index).getNormal(); btTransform pos; pos.setOrigin(xyz); diff --git a/src/physics/physical_object.cpp b/src/physics/physical_object.cpp index 9e7abd0fc..7480563eb 100644 --- a/src/physics/physical_object.cpp +++ b/src/physics/physical_object.cpp @@ -24,6 +24,7 @@ using namespace irr; +#include "graphics/material.hpp" #include "graphics/material_manager.hpp" #include "graphics/mesh_tools.hpp" #include "io/file_manager.hpp" diff --git a/src/scriptengine/script_engine.hpp b/src/scriptengine/script_engine.hpp index e03ebaf62..7ea19f96c 100644 --- a/src/scriptengine/script_engine.hpp +++ b/src/scriptengine/script_engine.hpp @@ -22,8 +22,10 @@ #include #include #include +#include #include "scriptengine/script_utils.hpp" +#include "utils/no_copy.hpp" #include "utils/ptr_vector.hpp" class TrackObjectPresentation; diff --git a/src/tracks/battle_graph.cpp b/src/tracks/battle_graph.cpp index 14803b134..300b38e8c 100644 --- a/src/tracks/battle_graph.cpp +++ b/src/tracks/battle_graph.cpp @@ -1,3 +1,4 @@ + // // SuperTuxKart - a fun racing game with go-kart // Copyright (C) 2009-2015 Joerg Henrichs @@ -223,7 +224,7 @@ void BattleGraph::findItemsOnGraphNodes() for (unsigned int j = 0; j < this->getNumNodes(); ++j) { - if (getQuadOfNode(j).pointInQuad(xyz, false)) + if (getQuadOfNode(j).pointInside(xyz, false)) polygon = j; } @@ -248,7 +249,7 @@ int BattleGraph::pointToNode(const int cur_node, for (unsigned int node = 0; node < this->getNumNodes(); node++) { const Quad& quad = this->getQuadOfNode(node); - if (quad.pointInQuad(cur_point, ignore_vertical)) + if (quad.pointInside(cur_point, ignore_vertical)) { return node; } @@ -258,7 +259,7 @@ int BattleGraph::pointToNode(const int cur_node, { // Check if the point is still on the same node const Quad& cur_quad = this->getQuadOfNode(cur_node); - if (cur_quad.pointInQuad(cur_point, ignore_vertical)) return cur_node; + if (cur_quad.pointInside(cur_point, ignore_vertical)) return cur_node; // If not then check all nearby quads (8 quads) // Skip the same node @@ -267,7 +268,7 @@ int BattleGraph::pointToNode(const int cur_node, { const int test_node = m_nearby_quads[cur_node][i]; const Quad& quad = this->getQuadOfNode(test_node); - if (quad.pointInQuad(cur_point, ignore_vertical)) + if (quad.pointInside(cur_point, ignore_vertical)) { return test_node; } @@ -465,9 +466,3 @@ void BattleGraph::set3DVerticesOfGraph(int i, video::S3DVertex *v, { NavMesh::get()->getQuad(i).getVertices(v, color); } // set3DVerticesOfGraph - -// ---------------------------------------------------------------------------- -const bool BattleGraph::isNodeInvisible(int n) const -{ - return NavMesh::get()->getQuad(n).isInvisible(); -} // isNodeInvisible diff --git a/src/tracks/battle_graph.hpp b/src/tracks/battle_graph.hpp index b99fb607c..ed809fd22 100644 --- a/src/tracks/battle_graph.hpp +++ b/src/tracks/battle_graph.hpp @@ -76,7 +76,7 @@ private: virtual void getGraphBoundingBox(Vec3 *min, Vec3 *max) const { NavMesh::get()->getBoundingBox(min, max); } // ------------------------------------------------------------------------ - virtual const bool isNodeInvisible(int n) const; + virtual const bool isNodeInvisible(int n) const { return false; } // ------------------------------------------------------------------------ virtual const bool hasLapLine() const { return false; } diff --git a/src/tracks/check_manager.cpp b/src/tracks/check_manager.cpp index 264b40ce1..3f9b4f4fa 100644 --- a/src/tracks/check_manager.cpp +++ b/src/tracks/check_manager.cpp @@ -28,7 +28,8 @@ #include "tracks/check_lap.hpp" #include "tracks/check_line.hpp" #include "tracks/check_structure.hpp" -#include "tracks/track.hpp" +#include "tracks/quad_graph.hpp" +#include "utils/log.hpp" CheckManager *CheckManager::m_check_manager = NULL; diff --git a/src/tracks/graph_node.cpp b/src/tracks/graph_node.cpp index 0ff4cfaff..7e838ad5d 100644 --- a/src/tracks/graph_node.cpp +++ b/src/tracks/graph_node.cpp @@ -22,51 +22,44 @@ #include "io/xml_node.hpp" #include "matrix4.h" #include "tracks/quad_graph.hpp" -#include "tracks/quad_set.hpp" #include "utils/log.hpp" // ---------------------------------------------------------------------------- -/** Constructor. Saves the quad index which belongs to this graph node. - * \param index Index of the quad to use for this node (in QuadSet). - */ -GraphNode::GraphNode(unsigned int quad_index, unsigned int node_index) +GraphNode::GraphNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, + const Vec3 &p3, const Vec3 &normal, + unsigned int node_index, bool invisible, + bool ai_ignore) + :Quad(p0, p1, p2, p3) { - if (quad_index >= QuadSet::get()->getNumberOfQuads()) - Log::fatal("GraphNode", "No driveline found, or empty driveline."); - - m_quad_index = quad_index; + m_invisible = invisible; + m_ai_ignore = ai_ignore; + m_normal = normal; m_node_index = node_index; m_distance_from_start = -1.0f; - const Quad &quad = QuadSet::get()->getQuad(m_quad_index); // The following values should depend on the actual orientation // of the quad. ATM we always assume that indices 0,1 are the lower end, // and 2,3 are the upper end (or the reverse if reverse mode is selected). // The width is the average width at the beginning and at the end. - m_right_unit_vector = ( quad[0]-quad[1] - +quad[3]-quad[2]) * 0.5f; + m_right_unit_vector = ( m_p[0]-m_p[1] + +m_p[3]-m_p[2]) * 0.5f; m_right_unit_vector.normalize(); - m_width = ( (quad[1]-quad[0]).length() - + (quad[3]-quad[2]).length() ) * 0.5f; + m_width = ( (m_p[1]-m_p[0]).length() + + (m_p[3]-m_p[2]).length() ) * 0.5f; if(QuadGraph::get()->isReverse()) { - m_lower_center = (quad[2]+quad[3]) * 0.5f; - m_upper_center = (quad[0]+quad[1]) * 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_right_unit_vector *= -1.0f; } else { - m_lower_center = (quad[0]+quad[1]) * 0.5f; - m_upper_center = (quad[2]+quad[3]) * 0.5f; + m_lower_center = (m_p[0]+m_p[1]) * 0.5f; + m_upper_center = (m_p[2]+m_p[3]) * 0.5f; } - m_line = core::line3df(m_lower_center.toIrrVector(), - m_upper_center.toIrrVector()); - // Only this 2d point is needed later - m_lower_center_2d = core::vector2df(m_lower_center.getX(), - m_lower_center.getZ() ); - + } // GraphNode // ---------------------------------------------------------------------------- @@ -78,28 +71,25 @@ GraphNode::GraphNode(unsigned int quad_index, unsigned int node_index) void GraphNode::addSuccessor(unsigned int to) { m_successor_nodes.push_back(to); - // m_quad_index is the quad index - const Quad &this_quad = QuadSet::get()->getQuad(m_quad_index); // to is the graph node - GraphNode &gn = QuadGraph::get()->getNode(to); - const Quad &next_quad = QuadGraph::get()->getQuadOfNode(to); + GraphNode &gn_to = QuadGraph::get()->getNode(to); // Note that the first predecessor is (because of the way the quad graph // is exported) the most 'natural' one, i.e. the one on the main // driveline. - gn.m_predecessor_nodes.push_back(m_node_index); + gn_to.m_predecessor_nodes.push_back(m_node_index); - Vec3 d = m_lower_center - QuadGraph::get()->getNode(to).m_lower_center; + Vec3 d = m_lower_center - gn_to.m_lower_center; m_distance_to_next.push_back(d.length()); - - Vec3 diff = next_quad.getCenter() - this_quad.getCenter(); - + + Vec3 diff = gn_to.getCenter() - getCenter(); + core::CMatrix4 m; - m.buildRotateFromTo(this_quad.getNormal().toIrrVector(), + m.buildRotateFromTo(getNormal().toIrrVector(), Vec3(0, 1, 0).toIrrVector()); core::vector3df diffRotated; m.rotateVect(diffRotated, diff.toIrrVector()); - + m_angle_to_next.push_back(atan2(diffRotated.X, diffRotated.Z)); } // addSuccessor @@ -183,197 +173,17 @@ void GraphNode::setDirectionData(unsigned int successor, DirectionType dir, } // setDirectionData // ---------------------------------------------------------------------------- -/** Returns the distance a point has from this quad in forward and sidewards - * direction, i.e. how far forwards the point is from the beginning of the - * quad, and how far to the side from the line connecting the center points - * is it. - * \param xyz The coordinates of the point. - * \param result The X coordinate contains the sidewards distance, the - * Z coordinate the forward distance. - */ -void GraphNode::getDistances(const Vec3 &xyz, Vec3 *result) -{ - core::vector3df xyz_irr = xyz.toIrrVector(); - core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector()); - core::vector3df normal = getQuad().getNormal().toIrrVector(); - - if(xyz.sideofPlane(closest, closest+normal, m_line.end)<0) - result->setX( (closest-xyz_irr).getLength()); // to the right - else - result->setX(-(closest-xyz_irr).getLength()); // to the left - result->setZ( m_distance_from_start + - (closest-m_lower_center.toIrrVector()).getLength()); -} // getDistances - -// ---------------------------------------------------------------------------- -/** Returns the distance a point has from an unrolled quad in forward and sidewards - * direction, i.e. how far forwards the point is from the beginning of the - * quad, and how far to the side from the line connecting the center points - * is it. - * \param xyz The coordinates of the point. - * \param fork_number The fork on which the unrolled quad lies. - * \param quad_idx The index of the unrolled quad to find distances from. - * \param result The X coordinate contains the sidewards distance, the - * Z coordinate the forward distance. - */ -void GraphNode::getDistancesUnrolled(const Vec3 &xyz, const int fork_number, unsigned int quad_idx, Vec3 *result) -{ - - const Quad& unrolled = getUnrolledQuad(fork_number,quad_idx); - Vec3 upper_center, lower_center; - if (!QuadGraph::get()->isReverse()) - { - upper_center = 0.5f*(unrolled[2] + unrolled[3]), - lower_center = 0.5f*(unrolled[0] + unrolled[1]); - } - else - { - upper_center = 0.5f*(unrolled[0] + unrolled[1]), - lower_center = 0.5f*(unrolled[2] + unrolled[3]); - } - // center_line is from A to B, or lower_center to upper_center - core::vector3df A = lower_center.toIrrVector(), B = upper_center.toIrrVector(); - result->setX(((B - A).crossProduct(xyz.toIrrVector() - A)).getLength() / (B - A).getLength()); - - result->setZ(QuadGraph::get()->getNode((m_node_index + quad_idx)%QuadGraph::get()->getNumNodes()).getDistanceFromStart() - + (xyz - lower_center).length()); -} // getDistancesUnrolled - -// ---------------------------------------------------------------------------- -/** Returns the square of the distance between the given point and any point - * on the 'centre' line, i.e. the finite line from the middle point of the - * lower end of the quad node to the middle point of the upper end of the - * quad 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. - */ -float GraphNode::getDistance2FromPoint(const Vec3 &xyz) -{ - core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector()); - return (closest-xyz.toIrrVector()).getLengthSQ(); -} // getDistance2FromPoint - -// ---------------------------------------------------------------------------- - void GraphNode::setChecklineRequirements(int latest_checkline) { m_checkline_requirements.push_back(latest_checkline); -} - - -const Vec3 GraphNode::getPointTransformedToFlatQuad(Vec3 xyz) -{ - Quad thisQuad = getQuad(); - core::CMatrix4 m; - m.buildRotateFromTo(thisQuad.getNormal().toIrrVector(), core::vector3df(0, 1, 0)); - - core::vector3df result; - // Translate the input point into the Quads frame of reference, then rotate - m.rotateVect(result, (xyz - thisQuad.getCenter()).toIrrVector()); - - return (Vec3)result; -} +} // setChecklineRequirements // ---------------------------------------------------------------------------- -/** This functions builds unrolled quads for this node. This takes into account - * if there is a fork in coming up. In this case there will be two sets of - * unrolled quads for this node. One for each fork. - * \param unroll_quad_count The length of the unrolled set of quads per node. +/** Returns true if the index-successor of this node is one that the AI + * is allowed to use. + * \param index Index of the successor. */ -void GraphNode::buildUnrolledQuads(unsigned int unroll_quad_count) +bool GraphNode::ignoreSuccessorForAI(unsigned int i) const { - m_unrolled_quads.clear(); - - unsigned int numberOfForks = 1; - GraphNode* currentNode = this; - for (unsigned i = 0; i < unroll_quad_count+1; i++) - { - unsigned int successorCount = currentNode->getNumberOfSuccessors(); - if (successorCount >= 2) - { - numberOfForks = successorCount; - break; - } - else - { - currentNode = &QuadGraph::get()->getNode(currentNode->getSuccessor(0)); - - } - } - - m_unrolled_quads.resize(numberOfForks); - - for (unsigned i = 0; i < numberOfForks; i++) - { - Quad thisQuad = getQuad(); - m_unrolled_quads[i].push_back(thisQuad); - GraphNode& next = QuadGraph::get()->getNode(getSuccessor(i%getNumberOfSuccessors())); - addUnrolledQuad(next , i , unroll_quad_count); - } -} // buildUnrolledQuads - -// ---------------------------------------------------------------------------- -/** This function is called recursively to build one set of unrolled quads. Each - * call adds one unrolled quad to the existing set. - * \param unroll_quad_count The length of the unrolled set of quads per node. - */ -void GraphNode::addUnrolledQuad(const GraphNode& next_node, int fork_number, int k) -{ - if (k == 0) return; - - Quad next_quad = next_node.getQuad(); - Quad next_quad_to_push = next_quad.getFlattenedQuad(); - Quad last_pushed_quad = m_unrolled_quads[fork_number].back(); - - - core::CMatrix4 m; - core::vector3df new_points[4]; - - // First rotate the next_quad_to_push so that it aligns with last quad - // in the vector of unrolled quads - m.buildRotateFromTo(next_quad_to_push.getNormal().toIrrVector(), - last_pushed_quad.getNormal().toIrrVector()); - - for (unsigned int i = 0; i < 4; i++) - m.rotateVect(new_points[i], next_quad_to_push[i].toIrrVector()); - - Vec3 endEdge, beginEdge; - if (!QuadGraph::get()->isReverse()) - { - endEdge = (last_pushed_quad[2] - last_pushed_quad[3]); - beginEdge = (new_points[1] - new_points[0]); - } - else - { - endEdge = (last_pushed_quad[1] - last_pushed_quad[0]); - beginEdge = (new_points[2] - new_points[3]); - } - - m.buildRotateFromTo(beginEdge.toIrrVector(), endEdge.toIrrVector()); - for (unsigned int i = 0; i < 4; i++) - m.rotateVect(new_points[i]); - - // Next translate the new quad to be pushed to the correct position infront - // of the last quad in the vector of unrolled quads - Vec3 lower_center, upper_center; - if (!QuadGraph::get()->isReverse()) - { - lower_center = 0.5f*(new_points[0] + new_points[1]); - upper_center = 0.5f*(last_pushed_quad[2] + last_pushed_quad[3]); - } - else - { - lower_center = 0.5f*(new_points[2] + new_points[3]); - upper_center = 0.5f*(last_pushed_quad[0] + last_pushed_quad[1]); - } - m.setTranslation((upper_center-lower_center).toIrrVector()); - - for (unsigned int i = 0; i < 4; i++) - m.translateVect(new_points[i]); - - // Push the quad into the vector of unrolled quads - m_unrolled_quads[fork_number].push_back(Quad(new_points[0], new_points[1], new_points[2], new_points[3])); - k = k - 1; - // Recurisvely build the vector of unrolled quads till k reduces to 0 - GraphNode& next = QuadGraph::get()->getNode(next_node.getSuccessor(fork_number%next_node.getNumberOfSuccessors())); - addUnrolledQuad(next, fork_number, k); -} // addUnrolledQuad + return QuadGraph::get()->getNode(m_successor_nodes[i]).letAIIgnore(); +} // ignoreSuccessorForAI diff --git a/src/tracks/graph_node.hpp b/src/tracks/graph_node.hpp index 10666b7f5..c8850540e 100644 --- a/src/tracks/graph_node.hpp +++ b/src/tracks/graph_node.hpp @@ -21,22 +21,14 @@ #include -#include -#include -#include - #include "tracks/quad.hpp" -#include "tracks/quad_set.hpp" -#include "utils/vec3.hpp" - -class QuadGraph; /** * \brief This class stores a node of the graph, i.e. a list of successor - * edges. + * edges, it can either be 2d or 3d. * \ingroup tracks */ -class GraphNode +class GraphNode : public Quad { public: /** To indiciate in which direction the track is going: @@ -44,12 +36,25 @@ public: * AI only. */ enum DirectionType {DIR_STRAIGHT, DIR_LEFT, DIR_RIGHT, DIR_UNDEFINED}; +protected: + /** Lower center point of the graph node. */ + Vec3 m_lower_center; + + /** Upper center point of the graph node. */ + Vec3 m_upper_center; + + /** Distance from the start to the beginning of the graph node. */ + float m_distance_from_start; private: - /** Index of this node in the set of quads. Several graph nodes can use - * the same quad, meaning it is possible to use a quad more than once, - * e.g. a figure 8 like track. */ - unsigned int m_quad_index; + /** Normal of the graph node */ + 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; /** Index of this graph node. */ unsigned int m_node_index; @@ -66,83 +71,59 @@ private: /** The angle of the line from this node to each neighbour. */ std::vector m_angle_to_next; - /** Distance from the start to the beginning of this quad. */ - float m_distance_from_start; - /** Width of the track, which is the average of the width at the - * beginning and at the end. FIXME: for now the width is independent - * of the orientation (e.g. a quad used more than once might once - * be used from top to bottom, one from left to right, so it should - * have a different width then). */ - float m_width; + * beginning and at the end. */ + float m_width; - /** The center point of the lower two points (e.g. points 0 and 1). - * This saves some computations in getDistances later. Only the - * start point is needed, and only in 2d. */ - core::vector2df m_lower_center_2d; + /** A vector from the center of the quad to the right edge. */ + Vec3 m_center_to_right; - /** Lower center point of the graph node. */ - Vec3 m_lower_center; + typedef std::vector PathToNodeVector; + /** This vector is only used if the graph node has more than one + * 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 + * graph nodes. */ + PathToNodeVector m_path_to_node; - /** Upper center point of the graph node. */ - Vec3 m_upper_center; + /** The direction for each of the successors. */ + std::vector m_direction; - /** A vector from the center of the quad to the right edge. */ - Vec3 m_center_to_right; + /** Stores for each successor the index of the last graph node that + * 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 + * left. */ + std::vector m_last_index_same_direction; - /** Line between lower and upper center, saves computation in - * getDistanceFromLine() later. The line is 2d only since otherwise - * taller karts would have a larger distance from the center. It also - * saves computation, and it is only needed to determine the distance - * from the center of the drivelines anyway. */ - core::line3df m_line; - - typedef std::vector PathToNodeVector; - /** This vector is only used if the graph node has more than one - * 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 - * graph nodes. */ - PathToNodeVector m_path_to_node; - - /** The direction for each of the successors. */ - std::vector m_direction; - - /** Stores for each successor the index of the last graph node that - * 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 - * left. */ - std::vector m_last_index_same_direction; - - /** A unit vector pointing from the center to the right side, orthogonal - * to the driving direction. */ - Vec3 m_right_unit_vector; + /** A unit vector pointing from the center to the right side, orthogonal + * to the driving direction. */ + Vec3 m_right_unit_vector; /** - * Sets of checklines you should have activated when you are driving on - * this node (there is a possibility of more than one set because of - * alternate ways) - */ - std::vector< int > m_checkline_requirements; + * Sets of checklines you should have activated when you are driving on + * this node (there is a possibility of more than one set because of + * alternate ways) + */ + std::vector< int > m_checkline_requirements; - std::vector< std::vector >m_unrolled_quads; - - void markAllSuccessorsToUse(unsigned int n, + void markAllSuccessorsToUse(unsigned int n, PathToNodeVector *m_path_to_node); - void addUnrolledQuad(const GraphNode& next_node, int fork_number, int k); - public: - GraphNode(unsigned int quad_index, unsigned int node_index); + GraphNode(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, + const Vec3 &p3, const Vec3 &normal, + unsigned int node_index, bool invisible, + bool ai_ignore); + // ------------------------------------------------------------------------ + virtual ~GraphNode() {} + // ------------------------------------------------------------------------ void addSuccessor (unsigned int to); - void getDistances(const Vec3 &xyz, Vec3 *result); - void getDistancesUnrolled(const Vec3 &xyz, const int fork_number, - unsigned int quad_idx, Vec3 *result); - float getDistance2FromPoint(const Vec3 &xyz); + // ------------------------------------------------------------------------ void setupPathsToNode(); + // ------------------------------------------------------------------------ void setChecklineRequirements(int latest_checkline); + // ------------------------------------------------------------------------ void setDirectionData(unsigned int successor, DirectionType dir, unsigned int last_node_index); - void buildUnrolledQuads(unsigned int unroll_quad_count); // ------------------------------------------------------------------------ /** Returns the number of successors. */ unsigned int getNumberOfSuccessors() const @@ -161,23 +142,15 @@ public: */ int getPredecessor(unsigned int i) const {return m_predecessor_nodes[i]; } // ------------------------------------------------------------------------ - /** Returns the quad_index in the quad_set of this node. */ - int getQuadIndex() const { return m_quad_index; } + /** Returns the node index of this node. */ + unsigned int getNodeIndex() const { return m_node_index; } // ------------------------------------------------------------------------ - /** Returns the quad of this graph node. */ - const Quad& getQuad() const {return QuadSet::get()->getQuad(m_quad_index);} - // ------------------------------------------------------------------------ - /** Returns the i-th. point of a quad. ATM this just returns the vertices - * from the quads, but if necessary this method will also consider - * rotated quads. So index 0 will always be lower left point, then - * counterclockwise. */ - const Vec3& operator[](int i) const - {return QuadSet::get()->getQuad(m_quad_index)[i];} + /** Returns the normal of this quad */ + const Vec3& getNormal() const { return m_normal; } // ------------------------------------------------------------------------ /** Returns the distance to the j-th. successor. */ float getDistanceToSuccessor(unsigned int j) const { return m_distance_to_next[j]; } - // ------------------------------------------------------------------------ /** Returns the angle from this node to the j-th. successor. */ float getAngleToSuccessor(unsigned int j) const @@ -199,21 +172,11 @@ public: /** Returns the center point of the upper edge of this graph node. */ const Vec3& getUpperCenter() const {return m_upper_center;} // ------------------------------------------------------------------------ - /** Returns the center point of this graph node. */ - const Vec3 getCenter() const - {return (m_upper_center + m_lower_center) / 2.0f;} - // ------------------------------------------------------------------------ /** Returns the length of the quad of this node. */ float getNodeLength() const {return (m_lower_center-m_upper_center).length();} // ------------------------------------------------------------------------ - /** Returns true if the index-successor of this node is one that the AI - * is allowed to use. - * \param index Index of the successor. */ - bool ignoreSuccessorForAI(unsigned int i) const - { - return QuadSet::get()->getQuad(m_successor_nodes[i]).letAIIgnore(); - }; + bool ignoreSuccessorForAI(unsigned int i) const; // ------------------------------------------------------------------------ /** Returns which successor node to use in order to be able to reach the * given node n. @@ -239,10 +202,18 @@ public: // ------------------------------------------------------------------------ /** Returns a unit vector pointing to the right side of the quad. */ 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. */ + bool letAIIgnore() const { return m_ai_ignore; } + // ------------------------------------------------------------------------ + virtual float getDistance2FromPoint(const Vec3 &xyz) = 0; + // ------------------------------------------------------------------------ + virtual void getDistances(const Vec3 &xyz, Vec3 *result) = 0; - const Vec3 getPointTransformedToFlatQuad(Vec3 xyz); - - const Quad& getUnrolledQuad(int succ_idx, int i) const { return m_unrolled_quads[succ_idx][i]; } }; // GraphNode #endif diff --git a/src/tracks/navmesh.cpp b/src/tracks/navmesh.cpp index 74d525add..1da2bc574 100644 --- a/src/tracks/navmesh.cpp +++ b/src/tracks/navmesh.cpp @@ -95,6 +95,14 @@ NavMesh::NavMesh(const std::string &filename) m_quads.push_back(new Quad( all_vertices[quad_index[0]], all_vertices[quad_index[1]], all_vertices[quad_index[2]], all_vertices[quad_index[3]])); + +/*(AbstractNode* tn = createNode( + all_vertices[quad_index[0]], all_vertices[quad_index[1]], + all_vertices[quad_index[2]], all_vertices[quad_index[3]],false,false); + +Vec3 pp(0,0,0); +tn->pointInNode(pp);*/ + } } } diff --git a/src/tracks/node_2d.cpp b/src/tracks/node_2d.cpp new file mode 100644 index 000000000..ad6dcba61 --- /dev/null +++ b/src/tracks/node_2d.cpp @@ -0,0 +1,69 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2016 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/node_2d.hpp" + +// ---------------------------------------------------------------------------- +Node2D::Node2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, + const Vec3 &normal, unsigned int node_index, bool invisible, + bool ai_ignore) + : GraphNode(p0, p1, p2, p3, normal, node_index, invisible, ai_ignore) +{ + m_line = core::line2df(m_upper_center.getX(), m_upper_center.getZ(), + m_lower_center.getX(), m_lower_center.getZ()); + + // Only this 2d point is needed later + m_lower_center_2d = core::vector2df(m_lower_center.getX(), + m_lower_center.getZ()); +} // Node2D + +// ---------------------------------------------------------------------------- +/** Returns the distance a point has from this node in forward and sidewards + * direction, i.e. how far forwards the point is from the beginning of the + * node, and how far to the side from the line connecting the center points + * is it. All these computations are done in 2D only. + * \param xyz The coordinates of the point. + * \param result The X coordinate contains the sidewards distance, the + * Z coordinate the forward distance. + */ +void Node2D::getDistances(const Vec3 &xyz, Vec3 *result) +{ + core::vector2df xyz2d(xyz.getX(), xyz.getZ()); + core::vector2df closest = m_line.getClosestPoint(xyz2d); + if (m_line.getPointOrientation(xyz2d) > 0) + result->setX( (closest-xyz2d).getLength()); // to the right + else + result->setX(-(closest-xyz2d).getLength()); // to the left + + result->setZ(m_distance_from_start + + (closest-m_lower_center_2d).getLength()); +} // getDistances + +// ---------------------------------------------------------------------------- +/** Returns the square of the distance between the given point and any point + * on the 'centre' line, i.e. the finite line from the middle point of the + * lower end of the node to the middle point of the upper end of the node + * 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. + */ +float Node2D::getDistance2FromPoint(const Vec3 &xyz) +{ + core::vector2df xyz2d(xyz.getX(), xyz.getZ()); + core::vector2df closest = m_line.getClosestPoint(xyz2d); + return (closest-xyz2d).getLengthSQ(); +} // getDistance2FromPoint diff --git a/src/tracks/node_2d.hpp b/src/tracks/node_2d.hpp new file mode 100644 index 000000000..cb6bb3874 --- /dev/null +++ b/src/tracks/node_2d.hpp @@ -0,0 +1,55 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2016 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_NODE_2D_HPP +#define HEADER_NODE_2D_HPP + +#include "tracks/graph_node.hpp" +#include "utils/cpp2011.hpp" + +#include + +/** + * \ingroup tracks + */ +class Node2D : public GraphNode +{ +private: + /** The center point of the lower two points (e.g. points 0 and 1). + * This saves some computations in getDistances later. Only the + * start point is needed, and only in 2d. */ + core::vector2df m_lower_center_2d; + + /** Line between lower and upper center, saves computation in + * getDistance() later. The line is 2d only since otherwise taller karts + * would have a larger distance from the center. It also saves + * computation, and it is only needed to determine the distance from the + * center of the drivelines anyway. */ + core::line2df m_line; + +public: + Node2D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, + const Vec3 &normal, unsigned int node_index, bool invisible, + bool ai_ignore); + // ------------------------------------------------------------------------ + virtual void getDistances(const Vec3 &xyz, Vec3 *result) OVERRIDE; + // ------------------------------------------------------------------------ + virtual float getDistance2FromPoint(const Vec3 &xyz) OVERRIDE; + +}; +#endif diff --git a/src/tracks/node_3d.cpp b/src/tracks/node_3d.cpp new file mode 100644 index 000000000..9593e5666 --- /dev/null +++ b/src/tracks/node_3d.cpp @@ -0,0 +1,94 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2016 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/node_3d.hpp" + +// ---------------------------------------------------------------------------- +Node3D::Node3D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, + const Vec3 &normal, unsigned int node_index, bool invisible, + bool ai_ignore) + : GraphNode(p0, p1, p2, p3, normal, node_index, invisible, ai_ignore) +{ + // Compute the node bounding box used for pointInNode + Vec3 box_corners[8]; + float box_high = 5.0f; + float box_low = 1.0f; + box_corners[0] = m_p[0] + box_high * normal; + box_corners[1] = m_p[1] + box_high * normal; + box_corners[2] = m_p[2] + box_high * normal; + box_corners[3] = m_p[3] + box_high * normal; + box_corners[4] = m_p[0] - box_low * normal; + box_corners[5] = m_p[1] - box_low * normal; + box_corners[6] = m_p[2] - box_low * normal; + box_corners[7] = m_p[3] - box_low * normal; + + Vec3 box_faces[6][4] = + { + { box_corners[0], box_corners[1], box_corners[2], box_corners[3] }, + { box_corners[3], box_corners[2], box_corners[6], box_corners[7] }, + { box_corners[7], box_corners[6], box_corners[5], box_corners[4] }, + { box_corners[1], box_corners[0], box_corners[4], box_corners[5] }, + { box_corners[4], box_corners[0], box_corners[3], box_corners[7] }, + { box_corners[1], box_corners[5], box_corners[6], box_corners[2] } + }; + + for (unsigned int i = 0; i < 6 ; i++) + { + for (unsigned int j = 0; j < 4; j++) + m_box_faces[i][j] = box_faces[i][j]; + } + + m_line = core::line3df(m_lower_center.toIrrVector(), + m_upper_center.toIrrVector()); +} // Node3D + +// ---------------------------------------------------------------------------- +/** Returns the distance a point has from this node in forward and sidewards + * direction, i.e. how far forwards the point is from the beginning of the + * node, and how far to the side from the line connecting the center points + * is it. + * \param xyz The coordinates of the point. + * \param result The X coordinate contains the sidewards distance, the + * Z coordinate the forward distance. + */ +void Node3D::getDistances(const Vec3 &xyz, Vec3 *result) +{ + core::vector3df xyz_irr = xyz.toIrrVector(); + core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector()); + core::vector3df normal = getNormal().toIrrVector(); + + if (xyz.sideofPlane(closest, closest + normal, m_line.end) < 0) + result->setX( (closest-xyz_irr).getLength()); // to the right + else + result->setX(-(closest-xyz_irr).getLength()); // to the left + result->setZ(m_distance_from_start + + (closest-m_lower_center.toIrrVector()).getLength()); +} // getDistances + +// ---------------------------------------------------------------------------- +/** Returns the square of the distance between the given point and any point + * on the 'centre' line, i.e. the finite line from the middle point of the + * lower end of the node to the middle point of the upper end of the node + * which belongs to this node. + * \param xyz The point for which the distance to the line is computed. + */ +float Node3D::getDistance2FromPoint(const Vec3 &xyz) +{ + core::vector3df closest = m_line.getClosestPoint(xyz.toIrrVector()); + return (closest-xyz.toIrrVector()).getLengthSQ(); +} // getDistance2FromPoint diff --git a/src/tracks/node_3d.hpp b/src/tracks/node_3d.hpp new file mode 100644 index 000000000..bd395fabd --- /dev/null +++ b/src/tracks/node_3d.hpp @@ -0,0 +1,64 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2016 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_NODE_3D_HPP +#define HEADER_NODE_3D_HPP + +#include "tracks/graph_node.hpp" +#include "utils/cpp2011.hpp" + +/** + * \ingroup tracks + */ +class Node3D : public GraphNode +{ +private: + /** For each node, construct a 3D box to check if a point lies inside it. + */ + Vec3 m_box_faces[6][4]; + + /** Line between lower and upper center, saves computation in + * getDistance() later. + */ + core::line3df m_line; + +public: + Node3D(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, + const Vec3 &normal, unsigned int node_index, bool invisible, + bool ai_ignore); + // ------------------------------------------------------------------------ + virtual bool pointInside(const Vec3& p, + bool ignore_vertical = false) const OVERRIDE + { + float side = p.sideofPlane(m_box_faces[0][0], m_box_faces[0][1], + m_box_faces[0][2]); + for (int i = 1; i < 6; i++) + { + if (side * p.sideofPlane(m_box_faces[i][0], m_box_faces[i][1], + m_box_faces[i][2]) < 0) + return false; + } + return true; + } + // ------------------------------------------------------------------------ + virtual void getDistances(const Vec3 &xyz, Vec3 *result) OVERRIDE; + // ------------------------------------------------------------------------ + virtual float getDistance2FromPoint(const Vec3 &xyz) OVERRIDE; + +}; +#endif diff --git a/src/tracks/quad.cpp b/src/tracks/quad.cpp index 44763f397..d6a697ec7 100644 --- a/src/tracks/quad.cpp +++ b/src/tracks/quad.cpp @@ -20,56 +20,21 @@ #include "utils/log.hpp" #include -#include #include #include #include "LinearMath/btTransform.h" /** Constructor, takes 4 points. */ -Quad::Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, - bool invisible, bool ai_ignore) - { - +Quad::Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3) +{ m_p[0]=p0; m_p[1]=p1; m_p[2]=p2; m_p[3]=p3; - + m_center = 0.25f*(p0+p1+p2+p3); m_min_height = std::min ( std::min(p0.getY(), p1.getY()), std::min(p2.getY(), p3.getY()) ); m_max_height = std::max ( std::max(p0.getY(), p1.getY()), std::max(p2.getY(), p3.getY()) ); - m_invisible = invisible; - m_ai_ignore = ai_ignore; - - findNormal(); - - // Compute the quad bounding box used for pointInQuad - Vec3 boxCorners[8]; - Vec3 normal = getNormal(); - float boxHigh = 5.0f; - float boxLow = 1.0f; - boxCorners[0] = m_p[0] + boxHigh*normal; - boxCorners[1] = m_p[1] + boxHigh*normal; - boxCorners[2] = m_p[2] + boxHigh*normal; - boxCorners[3] = m_p[3] + boxHigh*normal; - boxCorners[4] = m_p[0] - boxLow*normal; - boxCorners[5] = m_p[1] - boxLow*normal; - boxCorners[6] = m_p[2] - boxLow*normal; - boxCorners[7] = m_p[3] - boxLow*normal; - - Vec3 boxFaces[6][4] = { - { boxCorners[0], boxCorners[1], boxCorners[2], boxCorners[3] }, - { boxCorners[3], boxCorners[2], boxCorners[6], boxCorners[7] }, - { boxCorners[7], boxCorners[6], boxCorners[5], boxCorners[4] }, - { boxCorners[1], boxCorners[0], boxCorners[4], boxCorners[5] }, - { boxCorners[4], boxCorners[0], boxCorners[3], boxCorners[7] }, - { boxCorners[1], boxCorners[5], boxCorners[6], boxCorners[2] } - }; - - for (unsigned int i = 0; i < 6 ; i++) - for (unsigned int j = 0; j < 4; j++) - m_box_faces[i][j] = boxFaces[i][j]; - } // Quad // ---------------------------------------------------------------------------- @@ -108,7 +73,7 @@ void Quad::getVertices(video::S3DVertex *v, const video::SColor &color) const } // setVertices // ---------------------------------------------------------------------------- -bool Quad::pointInQuad(const Vec3& p, bool ignore_vertical) const +bool Quad::pointInside(const Vec3& p, bool ignore_vertical) const { // In case that a kart can validly run too high over one driveline // and it should not be considered to be on that driveline. Example: @@ -136,20 +101,7 @@ bool Quad::pointInQuad(const Vec3& p, bool ignore_vertical) const return p.sideOfLine2D(m_p[2], m_p[3]) > 0.0 && p.sideOfLine2D(m_p[3], m_p[0]) >= 0.0; } -} // pointInQuad - -// ---------------------------------------------------------------------------- -/** Checks if a given point p lies in the bounding box of this quad */ -bool Quad::pointInQuad3D(const Vec3& p) const -{ - float side = p.sideofPlane(m_box_faces[0][0], m_box_faces[0][1], m_box_faces[0][2]); - for (int i = 1; i < 6; i++) - { - if (side*p.sideofPlane(m_box_faces[i][0], m_box_faces[i][1], m_box_faces[i][2]) < 0) return false; - } - return true; -} // pointInQuad3D - +} // pointInside // ---------------------------------------------------------------------------- /** Transforms a quad by a given transform (i.e. translation+rotation). This @@ -171,36 +123,3 @@ void Quad::transform(const btTransform &t, Quad *result) const std::min(result->m_p[2].getY(), result->m_p[3].getY()) ); } // transform - -// ---------------------------------------------------------------------------- -/** Find the normal of this quad by computing the normal of two triangles and taking - * their average. - */ -void Quad::findNormal() -{ - core::triangle3df tri1(m_p[0].toIrrVector(), m_p[1].toIrrVector(), m_p[2].toIrrVector()); - core::triangle3df tri2(m_p[0].toIrrVector(), m_p[2].toIrrVector(), m_p[3].toIrrVector()); - Vec3 normal1 = tri1.getNormal(); - Vec3 normal2 = tri2.getNormal(); - m_normal = -0.5f*(normal1 + normal2); - m_normal.normalize(); - -} // findNormal - -// ---------------------------------------------------------------------------- -/** Return a flattened version of this quad. */ -Quad Quad::getFlattenedQuad() -{ - core::CMatrix4 m; - m.buildRotateFromTo(m_normal.toIrrVector(), core::vector3df(0, 1, 0)); - Vec3 m_p_flat[4]; - for (unsigned int i = 0; i < 4; i++) - { - m.rotateVect(m_p_flat[i], (m_p[i] - m_center).toIrrVector()); - - m_p_flat[i].setY(0); - } - - return Quad(m_p_flat[0], m_p_flat[1], m_p_flat[2], m_p_flat[3]); - -} // getFlattenedQuad diff --git a/src/tracks/quad.hpp b/src/tracks/quad.hpp index 4ca8d8033..cd164fb7c 100644 --- a/src/tracks/quad.hpp +++ b/src/tracks/quad.hpp @@ -20,9 +20,10 @@ #define HEADER_QUAD_HPP #include -#include "utils/vec3.hpp" -#include +#include "utils/leak_check.hpp" +#include "utils/no_copy.hpp" +#include "utils/vec3.hpp" namespace irr { @@ -35,9 +36,9 @@ class btTransform; /** * \ingroup tracks */ -class Quad +class Quad : public NoCopy { -private: +protected: /** The four points of a quad. */ Vec3 m_p[4]; @@ -45,8 +46,7 @@ private: * This saves some computations at runtime. */ Vec3 m_center; - Vec3 m_normal; - +private: /** The minimum height of the quad, used in case that several quads * are on top of each other when determining the sector a kart is on. */ float m_min_height; @@ -55,47 +55,28 @@ private: * to distinguish between quads which are on top of each other. */ float m_max_height; - /** Set to true if this quad should not be shown in the minimap. */ - bool m_invisible; - - /** Set if this quad should not be used by the AI. */ - bool m_ai_ignore; - - /** For each quad, construct a 3D box to check if a point lies inside it. */ - Vec3 m_box_faces[6][4]; - - /** Find the normal of this quad */ - void findNormal(); - public: - Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3, - bool invis=false, bool ai_ignore=false); + LEAK_CHECK() + // ------------------------------------------------------------------------ + Quad(const Vec3 &p0, const Vec3 &p1, const Vec3 &p2, const Vec3 &p3); + // ------------------------------------------------------------------------ + virtual ~Quad() {} + // ------------------------------------------------------------------------ void getVertices(video::S3DVertex *v, const video::SColor &color) const; - bool pointInQuad(const Vec3& p, bool ignore_vertical = false) const; - bool pointInQuad3D(const Vec3& p) const; + // ------------------------------------------------------------------------ void transform(const btTransform &t, Quad *result) const; // ------------------------------------------------------------------------ /** Returns the i-th. point of a quad. */ - const Vec3& operator[](int i) const {return m_p[i]; } + const Vec3& operator[](int i) const { return m_p[i]; } // ------------------------------------------------------------------------ /** Returns the center of a quad. */ - const Vec3& getCenter () const {return m_center; } + const Vec3& getCenter () const { return m_center; } // ------------------------------------------------------------------------ /** Returns the minimum height of a quad. */ - float getMinHeight() const { return m_min_height; } + float getMinHeight() const { return m_min_height; } // ------------------------------------------------------------------------ - /** Returns true of this quad is invisible, i.e. not to be shown in - * the minimap. */ - bool isInvisible() const { return m_invisible; } - // ------------------------------------------------------------------------ - /** True if this quad should be ignored by the AI. */ - bool letAIIgnore() const { return m_ai_ignore; } - // ------------------------------------------------------------------------ - /** Returns the normal of this quad */ - const Vec3& getNormal() const { return m_normal; } - // ------------------------------------------------------------------------ - /** Return a flattened version of this quad */ - Quad getFlattenedQuad(); + virtual bool pointInside(const Vec3& p, + bool ignore_vertical = false) const; }; // class Quad #endif diff --git a/src/tracks/quad_graph.cpp b/src/tracks/quad_graph.cpp index 6fcfac3fc..00cdb3f72 100644 --- a/src/tracks/quad_graph.cpp +++ b/src/tracks/quad_graph.cpp @@ -35,13 +35,47 @@ #include "tracks/check_lap.hpp" #include "tracks/check_line.hpp" #include "tracks/check_manager.hpp" -#include "tracks/quad_set.hpp" +#include "tracks/node_2d.hpp" +#include "tracks/node_3d.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 * from a graph file. * \param quad_file_name Name of the file of all quads @@ -52,20 +86,17 @@ QuadGraph::QuadGraph(const std::string &quad_file_name, const bool reverse) : m_reverse(reverse) { m_lap_length = 0; - m_unroll_quad_count = 6; - QuadSet::create(); - QuadSet::get()->init(quad_file_name); m_quad_filename = quad_file_name; m_quad_graph = this; - load(graph_file_name); + load(quad_file_name, graph_file_name); } // QuadGraph -// ----------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- /** Destructor, removes all nodes of the graph. */ QuadGraph::~QuadGraph() { - QuadSet::destroy(); - for(unsigned int i=0; iaddSuccessor(from); else m_all_nodes[from]->addSuccessor(to); + } // addSuccessor -// ----------------------------------------------------------------------------- -/** Loads a quad graph from a file. - * \param filename Name of the file to load. - */ -void QuadGraph::load(const std::string &filename) +// ---------------------------------------------------------------------------- +/** This function interprets a point specification as an attribute in the + xml quad file. It understands two different specifications: + 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 +*/ +void QuadGraph::getPoint(const XMLNode *xml, const std::string &attribute_name, + Vec3* result) const { + std::string s; + xml->get(attribute_name, &s); + int pos=(int)s.find_first_of(":"); + if(pos>0) // n:p specification + { + std::vector l = StringUtils::split(s, ':'); + int n=atoi(l[0].c_str()); + int p=atoi(l[1].c_str()); + *result=(*m_all_nodes[n])[p]; + } + else + { + xml->get(attribute_name, result); + } + +} // getPoint + +// ---------------------------------------------------------------------------- +/** Loads a quad graph from a file. + * \param filename Name of the quad file to load. + * \param filename Name of the graph file to load. + */ +void QuadGraph::load(const std::string &quad_file_name, + const std::string &filename) +{ + XMLNode *quad = file_manager->createXMLTree(quad_file_name); + if (!quad || quad->getName() != "quads") + { + Log::error("Quad Graph : Quad xml '%s' not found.", filename.c_str()); + delete quad; + return; + } + + m_min = Vec3( 99999, 99999, 99999); + m_max = Vec3(-99999, -99999, -99999); + // Each quad is part of the graph exactly once now. + for(unsigned int i=0; igetNumNodes(); i++) + { + const XMLNode *xml_node = quad->getNode(i); + if(xml_node->getName()!="quad") + { + Log::warn("Quad Graph: Unsupported node type '%s' found in '%s' - ignored.", + xml_node->getName().c_str(), filename.c_str()); + continue; + } + + // Note that it's not easy to do the reading of the parameters here + // in quad, since the specification in the xml can contain references + // to previous points. E.g.: + // get("invisible", &invisible); + bool ai_ignore=false; + xml_node->get("ai-ignore", &ai_ignore); + GraphNode* node = + createNode(p0, p1, p2, p3, m_all_nodes.size(), invisible, ai_ignore); + m_max.max(p0);m_max.max(p1);m_max.max(p2);m_max.max(p3); + m_min.min(p0);m_min.min(p1);m_min.min(p2);m_min.min(p3); + m_all_nodes.push_back(node); + } + delete quad; + const XMLNode *xml = file_manager->createXMLTree(filename); if(!xml) { // No graph file exist, assume a default loop X -> X+1 - // i.e. each quad is part of the graph exactly once. - // First create an empty graph node for each quad: - for(unsigned int i=0; igetNumberOfQuads(); i++) - m_all_nodes.push_back(new GraphNode(i, (unsigned int) m_all_nodes.size())); - // Then set the default loop: + // Set the default loop: setDefaultSuccessors(); computeDirectionData(); @@ -120,29 +218,13 @@ void QuadGraph::load(const std::string &filename) for(unsigned int node_index=0; node_indexgetNumNodes(); node_index++) { const XMLNode *xml_node = xml->getNode(node_index); - // First graph node definitions: - // ----------------------------- + // Load the definition of edges between the graph nodes: + // ----------------------------------------------------- if(xml_node->getName()=="node-list") { - // A list of quads is connected to a list of graph nodes: - unsigned int from, to; - xml_node->get("from-quad", &from); - xml_node->get("to-quad", &to); - for(unsigned int i=from; i<=to; i++) - { - m_all_nodes.push_back(new GraphNode(i, (unsigned int) m_all_nodes.size())); - } + // Each quad is part of the graph exactly once now. + continue; } - else if(xml_node->getName()=="node") - { - // A single quad is connected to a single graph node. - unsigned int id; - xml_node->get("quad", &id); - m_all_nodes.push_back(new GraphNode(id, (unsigned int) m_all_nodes.size())); - } - - // Then the definition of edges between the graph nodes: - // ----------------------------------------------------- else if(xml_node->getName()=="edge-loop") { // A closed loop: @@ -202,11 +284,6 @@ void QuadGraph::load(const std::string &filename) m_lap_length = l; } - // Build unrolled quads - for (unsigned int i = 0; i < m_all_nodes.size(); i++) - { - m_all_nodes[i]->buildUnrolledQuads(m_unroll_quad_count); - } } // load // ---------------------------------------------------------------------------- @@ -439,7 +516,7 @@ void QuadGraph::computeDistanceFromStart(unsigned int node, float new_distance) if(current_distancegetQuadIndex(), delta, 0); + updateDistancesForAllSuccessors(gn->getNodeIndex(), delta, 0); } return; } @@ -456,7 +533,7 @@ void QuadGraph::computeDistanceFromStart(unsigned int node, float new_distance) if(gn_next->getDistanceFromStart()==0) continue; - computeDistanceFromStart(gn_next->getQuadIndex(), + computeDistanceFromStart(gn_next->getNodeIndex(), new_distance + gn->getDistanceToSuccessor(i)); } // for i } // computeDistanceFromStart @@ -631,21 +708,6 @@ void QuadGraph::spatialToTrack(Vec3 *dst, const Vec3& xyz, getNode(sector).getDistances(xyz, dst); } // spatialToTrack -//----------------------------------------------------------------------------- -void QuadGraph::spatialToTrackUnrolled(Vec3 *dst, const Vec3& xyz, - const int parent_sector, - const int unroll_qd_idx, - const int fork_number) const -{ - if (parent_sector == UNKNOWN_SECTOR) - { - Log::warn("Quad Graph", "UNKNOWN_SECTOR in spatialToTrackUnrolled()."); - return; - } - getNode(parent_sector).getDistancesUnrolled(xyz, fork_number, - unroll_qd_idx, dst); -} // spatialToTrackUnrolled - //----------------------------------------------------------------------------- /** findRoadSector returns in which sector on the road the position * xyz is. If xyz is not on top of the road, it sets UNKNOWN_SECTOR as sector. @@ -663,7 +725,7 @@ void QuadGraph::findRoadSector(const Vec3& xyz, int *sector, { // Most likely the kart will still be on the sector it was before, // so this simple case is tested first. - if(*sector!=UNKNOWN_SECTOR && getQuadOfNode(*sector).pointInQuad3D(xyz) ) + if(*sector!=UNKNOWN_SECTOR && getNode(*sector).pointInside(xyz) ) { return; } // if still on same quad @@ -671,9 +733,6 @@ void QuadGraph::findRoadSector(const Vec3& xyz, int *sector, // Now we search through all graph nodes, starting with // the current one int indx = *sector; - // This was used to check the vertical distance of kart from sector - // but because now karts are checked in a 3D space, this is not required - //float min_dist = 999999.9f; // 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. @@ -694,13 +753,9 @@ void QuadGraph::findRoadSector(const Vec3& xyz, int *sector, indx = (*all_sectors)[i]; else indx = indx<(int)m_all_nodes.size()-1 ? indx +1 : 0; - const Quad &q = getQuadOfNode(indx); - float dist = xyz.getY() - q.getMinHeight(); - // While negative distances are unlikely, we allow some small negative - // numbers in case that the kart is partly in the track. - if(q.pointInQuad3D(xyz))// && dist < min_dist && dist>-1.0f) + const GraphNode &gn = getNode(indx); + if(gn.pointInside(xyz)) { - //min_dist = dist; *sector = indx; } } // for igetDistance2FromPoint(xyz); if(dist_2getVertices(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 + +//----------------------------------------------------------------------------- +float QuadGraph::getAngleToNext(int n, int j) const +{ + return m_all_nodes[n]->getAngleToSuccessor(j); +} // getAngleToNext + +//----------------------------------------------------------------------------- +int QuadGraph::getNumberOfSuccessors(int n) const +{ + return m_all_nodes[n]->getNumberOfSuccessors(); +} // getNumberOfSuccessors + +//----------------------------------------------------------------------------- +float QuadGraph::getDistanceFromStart(int j) const +{ + return m_all_nodes[j]->getDistanceFromStart(); +} // getDistanceFromStart diff --git a/src/tracks/quad_graph.hpp b/src/tracks/quad_graph.hpp index 24937a1fe..eaa3634f7 100644 --- a/src/tracks/quad_graph.hpp +++ b/src/tracks/quad_graph.hpp @@ -23,12 +23,13 @@ #include #include -#include "tracks/graph_node.hpp" #include "tracks/graph_structure.hpp" -#include "tracks/quad_set.hpp" #include "utils/aligned_array.hpp" -class CheckLine; +#include "LinearMath/btTransform.h" + +class GraphNode; +class XMLNode; /** * \brief This class stores a graph of quads. It uses a 'simplified singleton' @@ -46,6 +47,10 @@ 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 m_all_nodes; @@ -58,9 +63,6 @@ private: /** Wether the graph should be reverted or not */ bool m_reverse; - /** Number of unrolled quads to compute per quad */ - unsigned int m_unroll_quad_count; - void setDefaultSuccessors(); void computeChecklineRequirements(GraphNode* node, int latest_checkline); void computeDirectionData(); @@ -68,7 +70,9 @@ private: float normalizeAngle(float f); void addSuccessor(unsigned int from, unsigned int to); - void load (const std::string &filename); + 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, @@ -78,14 +82,12 @@ private: // ------------------------------------------------------------------------ virtual void set3DVerticesOfGraph(int i, video::S3DVertex *v, - const video::SColor &color) const - { m_all_nodes[i]->getQuad().getVertices(v, color); } + const video::SColor &color) const; // ------------------------------------------------------------------------ virtual void getGraphBoundingBox(Vec3 *min, Vec3 *max) const - { QuadSet::get()->getBoundingBox(min, max); } + { *min = m_min; *max = m_max; } // ------------------------------------------------------------------------ - virtual const bool isNodeInvisible(int n) const - { return m_all_nodes[n]->getQuad().isInvisible(); } + virtual const bool isNodeInvisible(int n) const; // ------------------------------------------------------------------------ virtual const bool hasLapLine() const { return true; } @@ -101,12 +103,6 @@ public: bool for_ai=false) const; void spatialToTrack(Vec3 *dst, const Vec3& xyz, const int sector) const; - void spatialToTrackUnrolled(Vec3 *dst, - const Vec3& xyz, - const int parent_sector, - const int unroll_qd_idx, - const int fork_number) const; - void findRoadSector(const Vec3& XYZ, int *sector, std::vector *all_sectors=NULL) const; int findOutOfRoadSector(const Vec3& xyz, @@ -124,13 +120,13 @@ public: 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, @@ -156,45 +152,28 @@ public: // ------------------------------------------------------------------------ /** Returns the number of nodes in the graph. */ virtual const unsigned int getNumNodes() const - { return (unsigned int)m_all_nodes.size();} + { return m_all_nodes.size(); } // ------------------------------------------------------------------------ /** Return the distance to the j-th successor of node n. */ - float getDistanceToNext(int n, int j) const - { return m_all_nodes[n]->getDistanceToSuccessor(j);} + 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 - { return m_all_nodes[n]->getAngleToSuccessor(j); } + float getAngleToNext(int n, int j) const; // ------------------------------------------------------------------------ /** Returns the number of successors of a node n. */ - int getNumberOfSuccessors(int n) const - { return m_all_nodes[n]->getNumberOfSuccessors(); } + int getNumberOfSuccessors(int n) const; // ------------------------------------------------------------------------ /** Returns the quad that belongs to a graph node. */ - const Quad& getQuadOfNode(unsigned int j) const - { return QuadSet::get()->getQuad(m_all_nodes[j]->getQuadIndex()); } - // ------------------------------------------------------------------------ - /** Returns the quad that belongs to a graph node. */ - GraphNode& getNode(unsigned int j) const{ return *m_all_nodes[j]; } + GraphNode& getNode(unsigned int j) const { return *m_all_nodes[j]; } // ------------------------------------------------------------------------ /** Returns the distance from the start to the beginning of a quad. */ - float getDistanceFromStart(int j) const - { return m_all_nodes[j]->getDistanceFromStart(); } + float getDistanceFromStart(int j) const; // ------------------------------------------------------------------------ /** Returns the length of the main driveline. */ - float getLapLength() const {return m_lap_length; } + float getLapLength() const { return m_lap_length; } // ------------------------------------------------------------------------ - bool isReverse() const {return m_reverse; } - // ---------------------------------------------------------------------- - /** Returns a unrolled quad of a node. */ - const Quad& getUnrolledQuadOfNode(unsigned int node, - unsigned int fork_number, - unsigned int quad_number) - { return getNode(node).getUnrolledQuad(fork_number,quad_number); } - // ---------------------------------------------------------------------- - /** Returns the number of forward quads that are unrolled for each quad **/ - unsigned int getNumberOfUnrolledQuads() const { return m_unroll_quad_count; } + bool isReverse() const { return m_reverse; } }; // QuadGraph diff --git a/src/tracks/quad_set.cpp b/src/tracks/quad_set.cpp deleted file mode 100644 index 0fa8d2d34..000000000 --- a/src/tracks/quad_set.cpp +++ /dev/null @@ -1,124 +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, Boston, MA 02111-1307, USA. - -#include "tracks/quad_set.hpp" - -#include -#include - -#include "io/file_manager.hpp" -#include "io/xml_node.hpp" -#include "utils/string_utils.hpp" - -QuadSet *QuadSet::m_quad_set = NULL; - -/** Constructor, loads the quad set from a file. Assigns a pointer - * to this instance to m_quad_set, so that it can be accessed using get(). - */ -QuadSet::QuadSet() -{ - m_quad_set = this; -} // QuadSet - -// ----------------------------------------------------------------------------- -/** Destructor, frees all memory. - */ -QuadSet::~QuadSet() -{ - for(unsigned int i=0; iget(attribute_name, &s); - int pos=(int)s.find_first_of(":"); - if(pos>0) // n:p specification - { - std::vector l = StringUtils::split(s, ':'); - int n=atoi(l[0].c_str()); - int p=atoi(l[1].c_str()); - *result=(*m_all_quads[n])[p]; - } - else - { - xml->get(attribute_name, result); - } - -} // getPoint -// ----------------------------------------------------------------------------- -/** Loads the set of all quads from the specified filename. - * \param filename The absolute filename to load the quad file from. - */ -void QuadSet::init(const std::string &filename) -{ - m_min = Vec3( 99999, 99999, 99999); - m_max = Vec3(-99999, -99999, -99999); - - XMLNode *xml = file_manager->createXMLTree(filename); - if(!xml || xml->getName()!="quads") - { - Log::error("[QuadSet::load] ERROR : QuadSet '%s' not found.", filename.c_str()); - delete xml; - return; - } - for(unsigned int i=0; igetNumNodes(); i++) - { - const XMLNode *xml_node = xml->getNode(i); - if(xml_node->getName()!="quad") - { - Log::warn("[QuadSet::load] WARNING: Unsupported node type '%s' found in '%s' - ignored.", - xml_node->getName().c_str(), filename.c_str()); - continue; - } - - // Note that it's not easy to do the reading of the parameters here - // in quad, since the specification in the xml can contain references - // to previous points. E.g.: - // get("invisible", &invisible); - bool ai_ignore=false; - xml_node->get("ai-ignore", &ai_ignore); - Quad* q=new Quad(p0,p1,p2,p3, invisible, ai_ignore); - m_all_quads.push_back(q); - m_max.max(p0);m_max.max(p1);m_max.max(p2);m_max.max(p3); - m_min.min(p0);m_min.min(p1);m_min.min(p2);m_min.min(p3); - - } - delete xml; -} // load - -// ----------------------------------------------------------------------------- diff --git a/src/tracks/quad_set.hpp b/src/tracks/quad_set.hpp deleted file mode 100644 index 8e646ae4e..000000000 --- a/src/tracks/quad_set.hpp +++ /dev/null @@ -1,90 +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, Boston, MA 02111-1307, USA. - -#ifndef HEADER_QUAD_SET_HPP -#define HEADER_QUAD_SET_HPP - -#include -#include - -#include "tracks/quad.hpp" -#include "utils/vec3.hpp" - -class XMLNode; - -/** - * \ingroup tracks - */ -class QuadSet -{ -private: - /** The 2d bounding box, used for hashing. */ - Vec3 m_min; - Vec3 m_max; - - /** The list of all quads. */ - std::vector m_all_quads; - - /** Pointer to the one instance of a quad set. */ - static QuadSet *m_quad_set; - - void getPoint(const XMLNode *xml, const std::string &attribute_name, - Vec3 *result) const; - QuadSet(); - ~QuadSet(); - -public: - static const int QUAD_NONE=-1; - - void init (const std::string &filename); - // ------------------------------------------------------------------------ - /** Creates one instance of the quad set. */ - static void create() - { - assert(m_quad_set==NULL); - m_quad_set = new QuadSet(); - } - // ------------------------------------------------------------------------ - /** Destroys the one instance of a quad set. */ - static void destroy() - { - delete m_quad_set; m_quad_set = NULL; - } - // ------------------------------------------------------------------------ - /** Static member function to access the QuadSet instance. */ - static QuadSet *get() { return m_quad_set; } - // ------------------------------------------------------------------------ - /** Returns the quad with a given index number. */ - const Quad& getQuad(int n) const {return *(m_all_quads[n]); } - // ------------------------------------------------------------------------ - /** Return the minimum and maximum coordinates of this quad set. */ - void getBoundingBox(Vec3 *min, Vec3 *max) - { *min=m_min; *max=m_max; } - // ------------------------------------------------------------------------ - /** Returns the number of quads. */ - unsigned int getNumberOfQuads() const - {return (unsigned int)m_all_quads.size(); } - // ------------------------------------------------------------------------ - /** Returns the center of quad n. */ - const Vec3& getCenterOfQuad(int n) const - {return m_all_quads[n]->getCenter(); } - // ------------------------------------------------------------------------ - /** Returns the n-th. quad. */ - const Quad& getQuad(int n) {return *(m_all_quads[n]); } -}; // QuadSet -#endif diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 38c01d387..0b215a1d0 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -32,6 +32,7 @@ #include "graphics/glwrap.hpp" #include "graphics/irr_driver.hpp" #include "graphics/lod_node.hpp" +#include "graphics/material.hpp" #include "graphics/material_manager.hpp" #include "graphics/mesh_tools.hpp" #include "graphics/moving_texture.hpp" @@ -54,10 +55,10 @@ #include "tracks/bezier_curve.hpp" #include "tracks/battle_graph.hpp" #include "tracks/check_manager.hpp" +#include "tracks/graph_node.hpp" #include "tracks/model_definition_loader.hpp" #include "tracks/track_manager.hpp" #include "tracks/quad_graph.hpp" -#include "tracks/quad_set.hpp" #include "tracks/track_object_manager.hpp" #include "utils/constants.hpp" #include "utils/log.hpp" @@ -2291,8 +2292,8 @@ void Track::itemCommand(const XMLNode *node) // If a valid road_sector is not found if (road_sector == QuadGraph::UNKNOWN_SECTOR) road_sector = QuadGraph::get()->findOutOfRoadSector(xyz, road_sector); - Vec3 quadnormal = QuadGraph::get()->getQuadOfNode(road_sector).getNormal(); - + const Vec3& quadnormal = QuadGraph::get()->getNode(road_sector).getNormal(); + const Material *m; Vec3 hit_point; m_track_mesh->castRay(loc, loc + -1.0f*quadnormal, &hit_point, &m, &normal); @@ -2384,7 +2385,7 @@ bool Track::findGround(AbstractKart *kart) { int sector = ((LinearWorld*)World::getWorld())->getTrackSector(kart->getWorldKartId()).getCurrentGraphNode(); if (sector != QuadGraph::UNKNOWN_SECTOR) - quadNormal = QuadGraph::get()->getQuadOfNode(sector).getNormal(); + quadNormal = QuadGraph::get()->getNode(sector).getNormal(); } to = to + -1000.0f*quadNormal; @@ -2436,3 +2437,7 @@ bool Track::findGround(AbstractKart *kart) return true; } // findGround + + +float Track::getTrackLength() const {return QuadGraph::get()->getLapLength();} +float Track::getAngle(int n) const { return QuadGraph::get()->getAngleToNext(n, 0); } \ No newline at end of file diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index 185bdd759..f258ac997 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -26,31 +26,31 @@ * objects. */ +#include #include #include namespace irr { - namespace video { class ITexture; class SColor; } - namespace scene { class IMesh; class ILightSceneNode; } + namespace video { class ITexture; } + namespace scene { class IMesh; class ILightSceneNode; class ISceneNode; } } using namespace irr; class ModelDefinitionLoader; #include "LinearMath/btTransform.h" -#include "graphics/material.hpp" -#include "items/item.hpp" #include "scriptengine/script_engine.hpp" -#include "tracks/quad_graph.hpp" #include "utils/aligned_array.hpp" #include "utils/translation.hpp" #include "utils/vec3.hpp" #include "utils/ptr_vector.hpp" +class AbstractKart; class AnimationManager; class BezierCurve; class CheckManager; +class FrameBuffer; class MovingTexture; class MusicInformation; class ParticleEmitter; @@ -473,8 +473,7 @@ public: int getVersion () const {return m_version; } // ------------------------------------------------------------------------ /** Returns the length of the main driveline. */ - float getTrackLength () const - {return QuadGraph::get()->getLapLength();} + float getTrackLength () const; // ------------------------------------------------------------------------ /** Returns a unique identifier for this track (the directory name). */ const std::string& getIdent () const {return m_ident; } @@ -511,8 +510,7 @@ public: * in the direction of the default way on the track. * \param n Number of the quad for which the angle is asked. */ - float getAngle(int n) const - { return QuadGraph::get()->getAngleToNext(n, 0); } + float getAngle(int n) const; // ------------------------------------------------------------------------ /** Returns the 2d coordinates of a point when drawn on the mini map * texture. diff --git a/src/tracks/track_sector.cpp b/src/tracks/track_sector.cpp index 279511bc8..a7a325e9d 100644 --- a/src/tracks/track_sector.cpp +++ b/src/tracks/track_sector.cpp @@ -20,9 +20,9 @@ #include "modes/world.hpp" #include "tracks/check_manager.hpp" #include "tracks/check_structure.hpp" -#include "tracks/track.hpp" #include "tracks/track_sector.hpp" #include "tracks/quad_graph.hpp" +#include "tracks/graph_node.hpp" // ---------------------------------------------------------------------------- /** Initialises the object, and sets the current graph node to be undefined. @@ -65,7 +65,7 @@ void TrackSector::update(const Vec3 &xyz) { // keep the current quad as the latest valid one IF the player has one // of the required checklines - GraphNode gn = QuadGraph::get()->getNode(m_current_graph_node); + const GraphNode& gn = QuadGraph::get()->getNode(m_current_graph_node); const std::vector& checkline_requirements = gn.getChecklineRequirements(); if (checkline_requirements.size() == 0)