diff --git a/.travis.yml b/.travis.yml index 5cdbe2ecc..ae4e22d25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,17 +21,21 @@ addons: apt: packages: - build-essential - - libogg-dev - - libvorbis-dev - - libopenal-dev - - libxxf86vm-dev - - libcurl4-openssl-dev - - libfribidi-dev - - libbluetooth-dev - - libgl1-mesa-dev - - libglu1-mesa-dev - - libglew-dev - cmake + - libbluetooth-dev + - libcurl4-gnutls-dev + - libfreetype6-dev + - libfribidi-dev + - libgl1-mesa-dev + - libjpeg-dev + - libogg-dev + - libopenal-dev + - libpng-dev + - libvorbis-dev + - libxrandr-dev + - mesa-common-dev + - pkg-config + - zlib1g-dev before_script: - export THREADS=$((`nproc` + 1)) diff --git a/data/supertuxkart.appdata.xml b/data/supertuxkart.appdata.xml index bed5375cb..412961b51 100644 --- a/data/supertuxkart.appdata.xml +++ b/data/supertuxkart.appdata.xml @@ -25,7 +25,7 @@ against the computer or your friends, and more!

- http://supertuxkart.sourceforge.net/ + http://supertuxkart.net/ http://supertuxkart.sourceforge.net/persistent/images/4/4e/Supertuxkart-0.9-screenshot-2.jpg http://supertuxkart.sourceforge.net/persistent/images/a/a9/Supertuxkart-0.9-screenshot-1.jpg diff --git a/doc/conventions.txt b/doc/conventions.txt index 1926e07d7..11f79b04d 100644 --- a/doc/conventions.txt +++ b/doc/conventions.txt @@ -12,7 +12,7 @@ Coding style ============ The coding style used in Super Tux Kart can be found at -http://supertuxkart.sourceforge.net/Coding_Style +http://supertuxkart.net/Coding_Style Documentation line length diff --git a/src/font/font_manager.cpp b/src/font/font_manager.cpp index 772c7de22..df237fb0b 100644 --- a/src/font/font_manager.cpp +++ b/src/font/font_manager.cpp @@ -52,17 +52,21 @@ void FontManager::loadFonts() m_digit_ttf = new FaceTTF(stk_config->m_digit_ttf); // Now load fonts with settings of ttf file + unsigned int font_loaded = 0; RegularFace* regular = new RegularFace(m_normal_ttf); regular->init(); m_fonts.push_back(regular); + m_font_type_map[std::type_index(typeid(RegularFace))] = font_loaded++; BoldFace* bold = new BoldFace(m_normal_ttf); bold->init(); m_fonts.push_back(bold); + m_font_type_map[std::type_index(typeid(BoldFace))] = font_loaded++; DigitFace* digit = new DigitFace(m_digit_ttf); digit->init(); m_fonts.push_back(digit); + m_font_type_map[std::type_index(typeid(DigitFace))] = font_loaded++; } // loadFonts // ---------------------------------------------------------------------------- diff --git a/src/font/font_manager.hpp b/src/font/font_manager.hpp index 68f2118cc..aae90c0f3 100644 --- a/src/font/font_manager.hpp +++ b/src/font/font_manager.hpp @@ -25,6 +25,8 @@ #include "utils/ptr_vector.hpp" #include +#include +#include #include #include FT_FREETYPE_H @@ -35,13 +37,15 @@ class FontWithFace; class FontManager : public NoCopy { private: - PtrVector m_fonts; + PtrVector m_fonts; - FT_Library m_ft_library; + FT_Library m_ft_library; - FaceTTF* m_normal_ttf; + FaceTTF* m_normal_ttf; - FaceTTF* m_digit_ttf; + FaceTTF* m_digit_ttf; + + std::unordered_map m_font_type_map; public: LEAK_CHECK() @@ -53,11 +57,11 @@ public: template T* getFont() { T* out = NULL; - for (unsigned int i = 0; i < m_fonts.size(); i++) + const unsigned int n = m_font_type_map[std::type_index(typeid(T))]; + out = dynamic_cast(m_fonts.get(n)); + if (out != NULL) { - out = dynamic_cast(m_fonts.get(i)); - if (out != NULL) - return out; + return out; } Log::fatal("FontManager", "Can't get a font!"); return out; diff --git a/src/font/font_with_face.cpp b/src/font/font_with_face.cpp index 579169131..0e1659ae0 100644 --- a/src/font/font_with_face.cpp +++ b/src/font/font_with_face.cpp @@ -26,7 +26,7 @@ #include "guiengine/skin.hpp" #include "utils/string_utils.hpp" -#include +#include FT_OUTLINE_H // ---------------------------------------------------------------------------- FontWithFace::FontWithFace(const std::string& name, FaceTTF* ttf) @@ -145,10 +145,11 @@ void FontWithFace::insertGlyph(wchar_t c, const GlyphInfo& gi) font_manager->checkFTError(FT_Load_Glyph(cur_face, gi.glyph_index, FT_LOAD_DEFAULT), "loading a glyph"); - if (dynamic_cast(this)) + if (dynamic_cast(this) != NULL) { // Embolden the outline of the glyph - FT_Outline_Embolden(&(slot->outline), getDPI() * 2); + font_manager->checkFTError(FT_Outline_Embolden(&(slot->outline), + getDPI() * 2), "embolden a glyph"); } font_manager->checkFTError(FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL), @@ -321,7 +322,7 @@ void FontWithFace::dumpGlyphPage() // ---------------------------------------------------------------------------- void FontWithFace::setDPI() { - // Get face dpi: + // Set face dpi: // Font size is resolution-dependent. // Normal text will range from 0.8, in 640x* resolutions (won't scale // below that) to 1.0, in 1024x* resolutions, and linearly up @@ -445,7 +446,7 @@ void FontWithFace::render(const core::stringw& text, FontSettings* font_settings, FontCharCollector* char_collector) { - const bool is_bold_face = dynamic_cast(this); + const bool is_bold_face = (dynamic_cast(this) != NULL); const bool black_border = font_settings ? font_settings->useBlackBorder() : false; const bool rtl = font_settings ? font_settings->isRTL() : false; @@ -513,7 +514,7 @@ void FontWithFace::render(const core::stringw& text, if (c==L'\r' && text[i+1]==L'\n') c = text[++i]; offset.Y += m_font_max_height * scale; - offset.X = position.UpperLeftCorner.X; + offset.X = float(position.UpperLeftCorner.X); if (hcenter) offset.X += (position.getWidth() - text_dimension.Width) >> 1; continue; diff --git a/src/graphics/material.cpp b/src/graphics/material.cpp index 8966fb51a..fc2c37379 100644 --- a/src/graphics/material.cpp +++ b/src/graphics/material.cpp @@ -19,8 +19,9 @@ #include "graphics/material.hpp" -#include +#include #include +#include #include "audio/sfx_base.hpp" #include "audio/sfx_buffer.hpp" diff --git a/src/items/powerup.cpp b/src/items/powerup.cpp index 93ef5e802..930c8c1bb 100644 --- a/src/items/powerup.cpp +++ b/src/items/powerup.cpp @@ -407,7 +407,7 @@ void Powerup::hitBonusBox(const Item &item, int add_info) { new_powerup = powerup_manager->getRandomPowerup(position, &n); if(new_powerup != PowerupManager::POWERUP_RUBBERBALL || - ( World::getWorld()->getTime() - powerup_manager->getBallCollectTime()) > + ( World::getWorld()->getTimeSinceStart() - powerup_manager->getBallCollectTime()) > RubberBall::getTimeBetweenRubberBalls() ) break; } diff --git a/src/karts/controller/ai_base_controller.cpp b/src/karts/controller/ai_base_controller.cpp index 085addbaa..ce8307808 100644 --- a/src/karts/controller/ai_base_controller.cpp +++ b/src/karts/controller/ai_base_controller.cpp @@ -241,7 +241,7 @@ void AIBaseController::crashed(const Material *m) const unsigned int NUM_COLLISION = 3; const float COLLISION_TIME = 1.5f; - float time = World::getWorld()->getTime(); + float time = World::getWorld()->getTimeSinceStart(); if(m_collision_times.size()==0) { m_collision_times.push_back(time); diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index 633a54da6..802a9e19c 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -1001,7 +1001,7 @@ void Kart::collectedItem(Item *item, int add_info) */ float Kart::getStartupBoost() const { - float t = World::getWorld()->getTime(); + float t = World::getWorld()->getTimeSinceStart(); std::vector startup_times = m_kart_properties->getStartupTime(); for (unsigned int i = 0; i < startup_times.size(); i++) { @@ -1991,9 +1991,9 @@ void Kart::crashed(const Material *m, const Vec3 &normal) */ void Kart::playCrashSFX(const Material* m, AbstractKart *k) { - if(World::getWorld()->getTime()-m_time_last_crash < 0.5f) return; + if(World::getWorld()->getTimeSinceStart()-m_time_last_crash < 0.5f) return; - m_time_last_crash = World::getWorld()->getTime(); + m_time_last_crash = World::getWorld()->getTimeSinceStart(); // After a collision disable the engine for a short time so that karts // can 'bounce back' a bit (without this the engine force will prevent // karts from bouncing back, they will instead stuck towards the obstable). diff --git a/src/main.cpp b/src/main.cpp index d8958f1c2..39efb33b1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -194,6 +194,7 @@ #include "states_screens/state_manager.hpp" #include "states_screens/user_screen.hpp" #include "states_screens/dialogs/message_dialog.hpp" +#include "tracks/battle_graph.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" #include "utils/command_line.hpp" @@ -591,7 +592,7 @@ void cmdLineHelp() " --shadows=n Set shadow quality (0 to disable shadows).\n" "\n" "You can visit SuperTuxKart's homepage at " - "http://supertuxkart.sourceforge.net\n\n", + "http://supertuxkart.net\n\n", CommandLine::getExecName().c_str() ); } // cmdLineHelp @@ -1843,12 +1844,12 @@ void runUnitTests() { Log::info("UnitTest", "Starting unit testing"); Log::info("UnitTest", "====================="); - Log::info("UnitTest", "- GraphicsRestrictions"); + Log::info("UnitTest", "GraphicsRestrictions"); GraphicsRestrictions::unitTesting(); - Log::info("UnitTest", " - NetworkString"); + Log::info("UnitTest", "NetworkString"); NetworkString::unitTesting(); - Log::info("UnitTest", " - Easter detection"); + Log::info("UnitTest", "Easter detection"); // Test easter mode: in 2015 Easter is 5th of April - check with 0 days // before and after int saved_easter_mode = UserConfigParams::m_easter_ear_mode; @@ -1880,9 +1881,12 @@ void runUnitTests() UserConfigParams::m_easter_ear_mode = saved_easter_mode; - Log::info("UnitTest", " - Kart characteristics"); + Log::info("UnitTest", "Kart characteristics"); CombinedCharacteristic::unitTesting(); + Log::info("UnitTest", "Battle Graph"); + BattleGraph::unitTesting(); + Log::info("UnitTest", "====================="); Log::info("UnitTest", "Testing successful "); Log::info("UnitTest", "====================="); diff --git a/src/modes/follow_the_leader.cpp b/src/modes/follow_the_leader.cpp index 7b29a8653..626d1260a 100644 --- a/src/modes/follow_the_leader.cpp +++ b/src/modes/follow_the_leader.cpp @@ -113,15 +113,6 @@ const btTransform &FollowTheLeaderRace::getStartTransform(int index) return m_track->getStartTransform(start_index); } // getStartTransform -//----------------------------------------------------------------------------- -/** Returns the original time at which the countdown timer started. This is - * used by the race_gui to display the music credits in FTL mode correctly. - */ -float FollowTheLeaderRace::getClockStartTime() const -{ - return m_leader_intervals[0]; -} // getClockStartTime - //----------------------------------------------------------------------------- /** Called when a kart must be eliminated. */ diff --git a/src/modes/follow_the_leader.hpp b/src/modes/follow_the_leader.hpp index 37e395b8f..dcfaa62be 100644 --- a/src/modes/follow_the_leader.hpp +++ b/src/modes/follow_the_leader.hpp @@ -49,7 +49,6 @@ public: virtual void reset() OVERRIDE; virtual const std::string& getIdent() const OVERRIDE; virtual const btTransform &getStartTransform(int index) OVERRIDE; - virtual float getClockStartTime() const; virtual void getKartsDisplayInfo( std::vector *info) OVERRIDE; virtual void init() OVERRIDE; diff --git a/src/modes/soccer_world.cpp b/src/modes/soccer_world.cpp index 0879e475e..381500eba 100644 --- a/src/modes/soccer_world.cpp +++ b/src/modes/soccer_world.cpp @@ -34,6 +34,7 @@ #include "karts/controller/soccer_ai.hpp" #include "physics/physics.hpp" #include "states_screens/race_gui_base.hpp" +#include "tracks/battle_graph.hpp" #include "tracks/track.hpp" #include "tracks/track_object_manager.hpp" #include "utils/constants.hpp" diff --git a/src/modes/three_strikes_battle.cpp b/src/modes/three_strikes_battle.cpp index c770d82a0..83282c045 100644 --- a/src/modes/three_strikes_battle.cpp +++ b/src/modes/three_strikes_battle.cpp @@ -17,9 +17,6 @@ #include "modes/three_strikes_battle.hpp" -#include -#include - #include "main_loop.hpp" #include "audio/music_manager.hpp" #include "config/user_config.hpp" @@ -31,10 +28,14 @@ #include "karts/kart_properties.hpp" #include "physics/physics.hpp" #include "states_screens/race_gui_base.hpp" +#include "tracks/battle_graph.hpp" #include "tracks/track.hpp" #include "tracks/track_object_manager.hpp" #include "utils/constants.hpp" +#include +#include + //----------------------------------------------------------------------------- /** Constructor. Sets up the clock mode etc. */ diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 2cbd03982..413c8d3c5 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -461,6 +461,7 @@ World::~World() race_manager->setRaceGhostKarts(false); race_manager->setRecordRace(false); race_manager->setWatchingReplay(false); + race_manager->setTimeTarget(0.0f); Camera::removeAllCameras(); diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index 880a18175..81e066a0e 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -70,7 +70,8 @@ void WorldStatus::reset() { m_time = 0.0f; m_auxiliary_timer = 0.0f; - + m_count_up_timer = 0.0f; + m_engines_started = false; // Using SETUP_PHASE will play the track into sfx first, and has no @@ -340,16 +341,19 @@ void WorldStatus::update(const float dt) { case CLOCK_CHRONO: m_time += dt; + m_count_up_timer += dt; break; case CLOCK_COUNTDOWN: // stop countdown when race is over if (m_phase == RESULT_DISPLAY_PHASE || m_phase == FINISH_PHASE) { m_time = 0.0f; + m_count_up_timer = 0.0f; break; } m_time -= dt; + m_count_up_timer += dt; if(m_time <= 0.0) { diff --git a/src/modes/world_status.hpp b/src/modes/world_status.hpp index 736dcfb6b..0a329d8f9 100644 --- a/src/modes/world_status.hpp +++ b/src/modes/world_status.hpp @@ -114,6 +114,8 @@ private: */ float m_auxiliary_timer; + float m_count_up_timer; + bool m_engines_started; void startEngines(); public: @@ -172,6 +174,10 @@ public: /** Called when the race actually starts. */ virtual void onGo() {}; + // ------------------------------------------------------------------------ + /** Get the time since start regardless of which way the clock counts */ + float getTimeSinceStart() const { return m_count_up_timer; } + }; // WorldStatus diff --git a/src/states_screens/race_gui_base.cpp b/src/states_screens/race_gui_base.cpp index 5d69851e8..03606a355 100644 --- a/src/states_screens/race_gui_base.cpp +++ b/src/states_screens/race_gui_base.cpp @@ -41,7 +41,7 @@ #include "karts/kart_properties.hpp" #include "karts/kart_properties_manager.hpp" #include "karts/rescue_animation.hpp" -#include "modes/follow_the_leader.hpp" +#include "modes/linear_world.hpp" #include "modes/world.hpp" #include "tracks/track.hpp" #include "utils/constants.hpp" @@ -457,15 +457,7 @@ void RaceGUIBase::drawGlobalMusicDescription() gui::IGUIFont* font = GUIEngine::getFont(); - float race_time = World::getWorld()->getTime(); - // In the modes that the clock counts backwards, convert the - // countdown time to time since start: - if(race_manager->getMinorMode()==RaceManager::MINOR_MODE_FOLLOW_LEADER) - race_time = ((FollowTheLeaderRace*)World::getWorld())->getClockStartTime() - - race_time; - else if (race_manager->getMinorMode()==RaceManager::MINOR_MODE_SOCCER && - race_manager->hasTimeTarget()) - race_time = race_manager->getTimeTarget() - World::getWorld()->getTime(); + float race_time = World::getWorld()->getTimeSinceStart(); // ---- Manage pulsing effect // 3.0 is the duration of ready/set (TODO: don't hardcode) diff --git a/src/tracks/battle_graph.cpp b/src/tracks/battle_graph.cpp index 232d70321..2f7a9ab8a 100644 --- a/src/tracks/battle_graph.cpp +++ b/src/tracks/battle_graph.cpp @@ -23,12 +23,17 @@ #include #include "config/user_config.hpp" +#include "io/file_manager.hpp" #include "io/xml_node.hpp" #include "items/item_manager.hpp" #include "race/race_manager.hpp" #include "tracks/navmesh.hpp" +#include "tracks/track.hpp" +#include "tracks/track_manager.hpp" #include "utils/log.hpp" +#include + const int BattleGraph::UNKNOWN_POLY = -1; BattleGraph * BattleGraph::m_battle_graph = NULL; @@ -36,15 +41,19 @@ BattleGraph * BattleGraph::m_battle_graph = NULL; * then runs shortest path algorithm to find and store paths to be used * by the AI. */ BattleGraph::BattleGraph(const std::string &navmesh_file_name, - const XMLNode& node) + const XMLNode *node) { m_items_on_graph.clear(); NavMesh::create(navmesh_file_name); m_navmesh_file = navmesh_file_name; buildGraph(NavMesh::get()); - computeFloydWarshall(); - if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) + + // Compute shortest distance from all nodes + for(unsigned int i=0; i < NavMesh::get()->getNumberOfPolys(); i++) + computeDijkstra(i); + + if (node && race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER) loadGoalNodes(node); } // BattleGraph @@ -59,21 +68,23 @@ BattleGraph::~BattleGraph(void) cleanupDebugMesh(); } // ~BattleGraph -// ----------------------------------------------------------------------------- -/** Builds a graph from an existing NavMesh. The graph is stored as an adjacency -* matrix. */ +// ---------------------------------------------------------------------------- +/** Builds a graph from an existing NavMesh. The graph is stored as an + * adjacency matrix. */ void BattleGraph::buildGraph(NavMesh* navmesh) { unsigned int n_polys = navmesh->getNumberOfPolys(); - m_distance_matrix = std::vector< std::vector > (n_polys, std::vector(n_polys, 9999.9f)); + m_distance_matrix = std::vector< std::vector > + (n_polys, std::vector(n_polys, 9999.9f)); for(unsigned int i=0; igetNavPoly(i); - std::vector adjacents = navmesh->getAdjacentPolys(i); + const std::vector &adjacents = navmesh->getAdjacentPolys(i); for(unsigned int j=0; jgetCenterOfPoly(adjacents[j]) - currentPoly.getCenter(); + Vec3 diff = navmesh->getCenterOfPoly(adjacents[j]) + - currentPoly.getCenter(); float distance = diff.length(); m_distance_matrix[i][adjacents[j]] = distance; //m_distance_matrix[adjacents[j]][i] = distance; @@ -81,14 +92,88 @@ void BattleGraph::buildGraph(NavMesh* navmesh) m_distance_matrix[i][i] = 0.0f; } + // Allocate and initialise the previous node data structure: + unsigned int n = getNumNodes(); + m_parent_poly = std::vector< std::vector > + (n, std::vector(n, BattleGraph::UNKNOWN_POLY)); + for(unsigned int i=0; i=9899.9f) + m_parent_poly[i][j]=-1; + else + m_parent_poly[i][j] = i; + } // for j + } // for i + } // buildGraph -// ----------------------------------------------------------------------------- -/** computeFloydWarshall() computes the shortest distance between any two nodes. - * At the end of the computation, m_distance_matrix[i][j] stores the shortest path - * distance from i to j and m_parent_poly[i][j] stores the last vertex visited on the - * shortest path from i to j before visiting j. Suppose the shortest path from i to j is - * i->......->k->j then m_parent_poly[i][j] = k +// ---------------------------------------------------------------------------- +/** Dijkstra shortest path computation. It computes the shortest distance from + * the specified node 'source' to all other nodes. At the end of the + * computation, m_distance_matrix[i][j] stores the shortest path distance from + * source to j and m_parent_poly[source][j] stores the last vertex visited on + * the shortest path from i to j before visiting j. Suppose the shortest path + * from i to j is i->......->k->j then m_parent_poly[i][j] = k + */ +void BattleGraph::computeDijkstra(int source) +{ + // Stores the distance (float) to 'source' from a specified node (int) + typedef std::pair IndDistPair; + + class Shortest + { + public: + bool operator()(const IndDistPair &p1, const IndDistPair &p2) + { + return p1.second > p2.second; + } + }; + std::priority_queue, Shortest> queue; + IndDistPair begin(source, 0.0f); + queue.push(begin); + const unsigned int n=getNumNodes(); + std::vector visited; + visited.resize(n, false); + NavMesh *navmesh = NavMesh::get(); + while(!queue.empty()) + { + // Get element with shortest path + IndDistPair current = queue.top(); + queue.pop(); + int cur_index = current.first; + if(visited[cur_index]) continue; + visited[cur_index] = true; + const NavPoly ¤t_poly = navmesh->getNavPoly(cur_index); + const std::vector &adjacents = current_poly.getAdjacents(); + for(unsigned int j=0; j......->k->j then + * m_parent_poly[i][j] = k */ void BattleGraph::computeFloydWarshall() { @@ -244,12 +329,12 @@ const bool BattleGraph::differentNodeColor(int n, NodeColor* c) const } // differentNodeColor // ----------------------------------------------------------------------------- -void BattleGraph::loadGoalNodes(const XMLNode& node) +void BattleGraph::loadGoalNodes(const XMLNode *node) { m_red_node.clear(); m_blue_node.clear(); - const XMLNode *check_node = node.getNode("checks"); + const XMLNode *check_node = node->getNode("checks"); for (unsigned int i = 0; i < check_node->getNumNodes(); i++) { const XMLNode *goal = check_node->getNode(i); @@ -277,3 +362,97 @@ void BattleGraph::loadGoalNodes(const XMLNode& node) } } } // loadGoalNodes + +// ============================================================================ +/** Unit testing for battle graph distance and parent node computation. + * Instead of using hand-tuned test cases we use the tested, verified and + * easier to understand Floyd-Warshall algorithm to compute the distances, + * and check if the (significanty faster) Dijkstra algorithm gives the same + * results. For now we use the cave mesh as test case. + */ +void BattleGraph::unitTesting() +{ + Track *track = track_manager->getTrack("cave"); + std::string navmesh_file_name=track->getTrackFile("navmesh.xml"); + + double s = StkTime::getRealTime(); + BattleGraph *bg = new BattleGraph(navmesh_file_name); + double e = StkTime::getRealTime(); + Log::error("Time", "Dijkstra %lf", e-s); + + // Save the Dijkstra results + std::vector< std::vector< float > > distance_matrix = bg->m_distance_matrix; + std::vector< std::vector< int > > parent_poly = bg->m_parent_poly; + bg->buildGraph(NavMesh::get()); + + // Now compute results with Floyd-Warshall + s = StkTime::getRealTime(); + bg->computeFloydWarshall(); + e = StkTime::getRealTime(); + Log::error("Time", "Floyd-Warshall %lf", e-s); + + int error_count = 0; + for(unsigned int i=0; im_distance_matrix.size(); i++) + { + for(unsigned int j=0; jm_distance_matrix[i].size(); j++) + { + if(bg->m_distance_matrix[i][j] - distance_matrix[i][j] > 0.001f) + { + Log::error("BattleGraph", + "Incorrect distance %d, %d: Dijkstra: %f F.W.: %f", + i, j, distance_matrix[i][j], bg->m_distance_matrix[i][j]); + error_count++; + } // if distance is too different + + // Unortunately it happens frequently that there are different + // shortest path with the same length. And Dijkstra might find + // a different path then Floyd-Warshall. So the test for parent + // polygon often results in false positives, so it is disabled, + // but I leave the code in place in case it is useful for some + // debugging in the feature +#undef TEST_PARENT_POLY_EVEN_THOUGH_MANY_FALSE_POSITIVES +#ifdef TEST_PARENT_POLY_EVEN_THOUGH_MANY_FALSE_POSITIVES + if(bg->m_parent_poly[i][j] != parent_poly[i][j]) + { + error_count++; + std::vector dijkstra_path = getPathFromTo(i, j, parent_poly); + std::vector floyd_path = getPathFromTo(i, j, bg->m_parent_poly); + if(dijkstra_path.size()!=floyd_path.size()) + { + Log::error("BattleGraph", + "Incorrect path length %d, %d: Dijkstra: %d F.W.: %d", + i, j, parent_poly[i][j], bg->m_parent_poly[i][j]); + continue; + } + Log::error("BattleGraph", "Path problems from %d to %d:", + i, j); + for (unsigned k = 0; k < dijkstra_path.size(); k++) + { + if(dijkstra_path[k]!=floyd_path[k]) + Log::error("BattleGraph", "%d/%d dijkstra: %d floyd %d", + k, dijkstra_path.size(), dijkstra_path[k], + floyd_path[k]); + } // for k BattleGraph::getPathFromTo(int from, int to, + const std::vector< std::vector< int > > parent_poly) +{ + std::vector path; + path.push_back(to); + while(from!=to) + { + to = parent_poly[from][to]; + path.push_back(to); + } + return path; +} // getPathFromTo \ No newline at end of file diff --git a/src/tracks/battle_graph.hpp b/src/tracks/battle_graph.hpp index 03774e49b..da62e7c4e 100644 --- a/src/tracks/battle_graph.hpp +++ b/src/tracks/battle_graph.hpp @@ -63,9 +63,9 @@ private: void buildGraph(NavMesh*); void computeFloydWarshall(); - void loadGoalNodes(const XMLNode& node); + void loadGoalNodes(const XMLNode *node); - BattleGraph(const std::string &navmesh_file_name, const XMLNode& node); + BattleGraph(const std::string &navmesh_file_name, const XMLNode *node=NULL); ~BattleGraph(void); // ------------------------------------------------------------------------ @@ -86,17 +86,27 @@ private: { return false; } // ------------------------------------------------------------------------ virtual const bool differentNodeColor(int n, NodeColor* c) const; + void computeDijkstra(int n); + static std::vector getPathFromTo(int from, int to, + const std::vector< std::vector< int > > parent_poly); public: static const int UNKNOWN_POLY; + void findItemsOnGraphNodes(); + int pointToNode(const int cur_node, + const Vec3& cur_point, + bool ignore_vertical) const; + static void unitTesting(); + + /** Returns the one instance of this object. */ static BattleGraph *get() { return m_battle_graph; } // ---------------------------------------------------------------------- /** Asserts that no BattleGraph instance exists. Then * creates a BattleGraph instance. */ static void create(const std::string &navmesh_file_name, - const XMLNode& node) + const XMLNode *node) { assert(m_battle_graph==NULL); m_battle_graph = new BattleGraph(navmesh_file_name, node); @@ -149,11 +159,6 @@ public: void insertItems(Item* item, int polygon) { m_items_on_graph.push_back(std::make_pair(item, polygon)); } // ------------------------------------------------------------------------ - void findItemsOnGraphNodes(); - // ------------------------------------------------------------------------ - int pointToNode(const int cur_node, - const Vec3& cur_point, - bool ignore_vertical) const; }; //BattleGraph #endif diff --git a/src/tracks/track.cpp b/src/tracks/track.cpp index 426f777dd..f50bb5c93 100644 --- a/src/tracks/track.cpp +++ b/src/tracks/track.cpp @@ -660,7 +660,7 @@ void Track::startMusic() const */ void Track::loadBattleGraph(const XMLNode &node) { - BattleGraph::create(m_root+"navmesh.xml", node); + BattleGraph::create(m_root+"navmesh.xml", &node); if(BattleGraph::get()->getNumNodes()==0) { diff --git a/src/tracks/track.hpp b/src/tracks/track.hpp index 344806358..87bebcf0c 100644 --- a/src/tracks/track.hpp +++ b/src/tracks/track.hpp @@ -43,7 +43,6 @@ class ModelDefinitionLoader; #include "items/item.hpp" #include "scriptengine/script_engine.hpp" #include "tracks/quad_graph.hpp" -#include "tracks/battle_graph.hpp" #include "utils/aligned_array.hpp" #include "utils/translation.hpp" #include "utils/vec3.hpp" diff --git a/tools/build-linux-travis.sh b/tools/build-linux-travis.sh index 94d1ee305..741eb636e 100755 --- a/tools/build-linux-travis.sh +++ b/tools/build-linux-travis.sh @@ -1,7 +1,7 @@ #!/bin/sh # # Automate the build process on Linux based on -# http://supertuxkart.sourceforge.net/Build_STK_on_Linux +# http://supertuxkart.net/Build_STK_on_Linux # CMake build type BUILDTYPE=Debug