diff --git a/.gitignore b/.gitignore index 2ce6cc3..a5294f0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build* -*.user \ No newline at end of file +*.user +data/* diff --git a/src/main.cpp b/src/main.cpp index a8806c3..f727634 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,16 +7,18 @@ #include "tools/graph.h" #include "tools/pathfinder.h" +#include "tools/loader.h" int main(){ SceneTree scene("testScene"); Engine engine; + engine.createWindow("test"); engine.setScene("testScene"); engine.start(); - GraphNode n1 = GraphNode(); + /* GraphNode n1 = GraphNode(); n1.setValue(1); GraphNode n2 = GraphNode(); n2.setValue(2); @@ -24,15 +26,24 @@ int main(){ n3.setValue(3); GraphNode n4 = GraphNode(); n4.setValue(4); + GraphNode n5 = GraphNode(); + n5.setValue(5); - n1.addNeighbours(&n2,2); - n1.addNeighbours(&n3,3); - n2.addNeighbours(&n3,5); - n3.addNeighbours(&n4,2); + n1.addNeighbours(&n2); + n1.addNeighbours(&n3); + n2.addNeighbours(&n4); + n3.addNeighbours(&n4); + n3.addNeighbours(&n2); + n3.addNeighbours(&n5); - std::vector path = PathFinder::a_star(&n1,&n4); + std::vector path = PathFinder::a_star(&n1,&n4,true); std::cout << "Path Size: " << path.size() << std::endl; for(GraphNode* gn: path){ std::cout << gn->getValue() << std::endl; - } + }*/ + + Loader::setObjDirectory("../data/"); + Loader::setMtlDirectory("../data/"); + Loader::setTexDirectory("../data/"); + std::vector meshes = Loader::loadMesh("sword.obj"); } diff --git a/src/message.cpp b/src/message.cpp new file mode 100644 index 0000000..3a27417 --- /dev/null +++ b/src/message.cpp @@ -0,0 +1,7 @@ +#include "message.h" + + +Message::Message(std::string id, SystemType sender):m_id(id),m_sender(sender) +{ + +} diff --git a/src/message.h b/src/message.h new file mode 100644 index 0000000..61f9192 --- /dev/null +++ b/src/message.h @@ -0,0 +1,18 @@ +#ifndef MESSAGE_H +#define MESSAGE_H + +#include +#include +#include "system.h" + +class Message +{ + std::string m_id; + SystemType m_sender; +public: + Message(std::string,SystemType); +}; + + + +#endif // MESSAGE_H diff --git a/src/messagebus.cpp b/src/messagebus.cpp new file mode 100644 index 0000000..057003b --- /dev/null +++ b/src/messagebus.cpp @@ -0,0 +1,29 @@ +#include "messagebus.h" +#include "system.h" + +MessageBus::MessageBus() +{ + +} + +void MessageBus::registerSystem(SystemType type, System* system){ + systems[type] = system; +} + +void MessageBus::update() +{ + while (!message_list.empty()){ + Message* msg = message_list.front(); + message_list.pop(); + for(auto const &entity : systems){ + entity.second->handleMessage(msg); + } + } +} + +void MessageBus::postMessage(Message *msg) +{ + message_list.push(msg); +} + + diff --git a/src/messagebus.h b/src/messagebus.h new file mode 100644 index 0000000..46e1d60 --- /dev/null +++ b/src/messagebus.h @@ -0,0 +1,26 @@ +#ifndef MESSAGEBUS_H +#define MESSAGEBUS_H + +#include +#include +#include + +#include "system.h" + +class Message; +class System; + +class MessageBus +{ + std::map systems; + std::queue message_list; //message file + +public: + MessageBus(); + void registerSystem(SystemType,System*); + void postMessage(Message* msg); + void update(); + void handleMessage(); +}; + +#endif // MESSAGEBUS_H diff --git a/src/sparrowshell.cpp b/src/sparrowshell.cpp new file mode 100644 index 0000000..42d7602 --- /dev/null +++ b/src/sparrowshell.cpp @@ -0,0 +1,51 @@ +#include "sparrowshell.h" + +#include "message.h" +#include "input.h" + +const int SparrowShell::BUFFER_MAX_LENGTH = 50; +const int SparrowShell::BUFFER_DISPLAYED_NUMBER = 10; +const int SparrowShell::SCROLLBAR_PIXEL_WIDTH = 2; + +SparrowShell::SparrowShell(sf::Window* window, Input* input): m_position(glm::ivec2(0,0)),m_window(window),m_input(input),m_scrollbar(this) +{ + //m_dimension = glm::ivec2();// +} + +void SparrowShell::out(std::string s) +{ + if (m_buffer.size() == BUFFER_MAX_LENGTH) + m_buffer.pop_back(); + m_buffer.push_front(s); +} + +void SparrowShell::scrollUp(){ + if (m_index + BUFFER_DISPLAYED_NUMBER < m_buffer.size()) m_index++; +} + +void SparrowShell::scrollDown(){ + if (m_index > 0) m_index--; +} + +void SparrowShell::update() +{ + //TODO : update TextMesh + m_scrollbar.update(); +} + +SparrowShell::ScrollBar::ScrollBar(SparrowShell* shell):m_shell(shell){ + m_position = glm::ivec2(m_shell->m_dimension.x - SCROLLBAR_PIXEL_WIDTH,0); + m_dimension = glm::ivec2(SCROLLBAR_PIXEL_WIDTH,m_shell->m_dimension.y); +} + +void SparrowShell::ScrollBar::update(){ + m_position.y = m_shell->m_position.y; + m_dimension.y = m_shell->m_dimension.y; + + if (m_shell->m_buffer.size() > BUFFER_DISPLAYED_NUMBER){ + float cran = ((float)m_shell->m_dimension.y/(float)m_shell->m_buffer.size()); + int indexCursor = m_shell->m_buffer.size()-(m_shell->m_index+SCROLLBAR_PIXEL_WIDTH); + m_position.y += (int)(cran * indexCursor); + m_dimension.y = (int)(cran * BUFFER_DISPLAYED_NUMBER); + } +} diff --git a/src/sparrowshell.h b/src/sparrowshell.h new file mode 100644 index 0000000..baa89e2 --- /dev/null +++ b/src/sparrowshell.h @@ -0,0 +1,55 @@ +#ifndef SPARROWSHELL_H +#define SPARROWSHELL_H + +#include + +#include "system.h" +#include "scene.h" +#include "glm/glm.hpp" + +class Input; + +namespace sf { +class Window; +} + +class SparrowShell : public SceneNode +{ +private: + class ScrollBar{ + SparrowShell* m_shell; + glm::ivec2 m_position; + glm::ivec2 m_dimension; + //TODO : Add rectangle mesh + + public: + ScrollBar(); + ScrollBar(SparrowShell* shell); + void update(); + }; + + static const int BUFFER_MAX_LENGTH; + static const int BUFFER_DISPLAYED_NUMBER; + static const int SCROLLBAR_PIXEL_WIDTH; + + std::list m_buffer; + sf::Window* m_window; + Input* m_input; + int m_index = 0; + + glm::ivec2 m_position; + glm::ivec2 m_dimension; + + //textMesh + ScrollBar m_scrollbar; + +public: + SparrowShell(sf::Window*, Input*); + + void update(); + void scrollUp(); + void scrollDown(); + void out(std::string); +}; + +#endif // SPARROWSHELL_H diff --git a/src/system.cpp b/src/system.cpp new file mode 100644 index 0000000..feee297 --- /dev/null +++ b/src/system.cpp @@ -0,0 +1,28 @@ +#include "system.h" + +#include "messagebus.h" +#include "message.h" +#include "input.h" +#include + +System::System() +{ + +} + +InputSystem::InputSystem(){ + +} + +void InputSystem::initInput(sf::Window *window){ + m_input = new Input(window); +} + +void InputSystem::update(){ + int action; + Message* message; + while (action = m_input->getAction() != NO_ACTION){ + message = new Message(std::to_string(action),SystemType::INPUT_SYSTEM); + m_msgBus->postMessage(message); + } +} diff --git a/src/system.h b/src/system.h new file mode 100644 index 0000000..915a4dc --- /dev/null +++ b/src/system.h @@ -0,0 +1,36 @@ +#ifndef SYSTEM_H +#define SYSTEM_H + +class MessageBus; +class Message; +class Input; + +namespace sf{ +class Window; +} + +//TODO:complete this part with other existing system, +enum SystemType {INPUT_SYSTEM, RENDERER_SYSTEM, IA_SYSTEM,GAME_SYSTEM,LENGTH}; + +class System +{ + SystemType m_type; +protected: + MessageBus* m_msgBus; + +public: + System(); + virtual void handleMessage(Message* message) = 0; +}; + +class InputSystem : public System{ +private: + Input* m_input; +public: + InputSystem(); + ~InputSystem(); + void initInput(sf::Window* window); + void update(); +}; + +#endif // SYSTEM_H diff --git a/src/tools/graph.cpp b/src/tools/graph.cpp index cc97225..9e04a8e 100644 --- a/src/tools/graph.cpp +++ b/src/tools/graph.cpp @@ -5,27 +5,22 @@ using namespace std; GraphNode::GraphNode() { - m_neighbours = vector(); + m_neighbours = vector(); } -GraphNode::GraphNode(vector neighbours):m_neighbours(neighbours) +GraphNode::GraphNode(vector neighbours):m_neighbours(neighbours) { } -void GraphNode::addNeighbours(GraphNode* n,float f){ - GraphEdge edge = GraphEdge(n,f); - addNeighbours(edge); -} - -void GraphNode::addNeighbours(GraphEdge edge){ - m_neighbours.push_back(edge); +void GraphNode::addNeighbours(GraphNode* node){ + m_neighbours.push_back(node); } int GraphNode::getNbNeighbours(){ return m_neighbours.size(); } -vector GraphNode::getNeighbours(){ +vector GraphNode::getNeighbours(){ return m_neighbours; } @@ -33,11 +28,6 @@ void GraphNode::print(std::string prefix) { cout << prefix << "Node_id : "; cout << prefix << m_testvalue << endl; -// cout << prefix << "Neighbours list :" << endl; - //prefix += "\t"; - //for_each (m_neighbours.begin(), m_neighbours.end(),[prefix](GraphEdge voisin) { - // voisin.getTarget()->print(prefix); - //}); } void GraphNode::setValue(int a){ @@ -48,15 +38,11 @@ int GraphNode::getValue(){ return m_testvalue; } - - -GraphEdge::GraphEdge(GraphNode* gn,float v):m_target(gn),m_weight(v) -{} - -GraphNode* GraphEdge::getTarget(){ - return m_target; +void GraphNode::setPriority(float priority){ + m_priority = priority; } -float GraphEdge::getWeight(){ - return m_weight; +float GraphNode::getPriority(){ + return m_priority; } + diff --git a/src/tools/graph.h b/src/tools/graph.h index 42f670d..541967c 100644 --- a/src/tools/graph.h +++ b/src/tools/graph.h @@ -8,32 +8,31 @@ class GraphEdge; class GraphNode { - std::vector m_neighbours; + std::vector m_neighbours; int m_testvalue; //temp variable + float m_priority; + public: GraphNode(); - GraphNode(std::vector); + GraphNode(std::vector); - std::vector getNeighbours(); - void addNeighbours(GraphNode*,float); - void addNeighbours(GraphEdge); + std::vector getNeighbours(); + void addNeighbours(GraphNode*); int getNbNeighbours(); - virtual float heuristic(GraphNode*){return 1;}; + virtual float cost(GraphNode*){ + std::cout << "WARNING : You're using the default cost function. For better result, redefine the cost function in GraphNode." << std::endl; + return 1; + } + virtual float heuristic(GraphNode*){ + std::cout << "WARNING : You're using the default heuristic function. For better result, redefine the heuristic function in GraphNode." << std::endl; + return 0; + } void setValue(int); int getValue(); + void setPriority(float); + float getPriority(); void print(std::string prefix); }; -class GraphEdge -{ - GraphNode* m_target; - float m_weight; - -public: - GraphEdge(GraphNode*,float); - GraphNode* getTarget(); - float getWeight(); -}; - #endif // GRAPH_H diff --git a/src/tools/loader.cpp b/src/tools/loader.cpp index 102bf4e..70a9be5 100644 --- a/src/tools/loader.cpp +++ b/src/tools/loader.cpp @@ -1,8 +1,20 @@ #include "loader.h" #include #include +#include #include +#include "../resourcemanager.h" #include +#include +#include +#include "../sparrowrenderer/src/texture.h" + +#include + +std::string Loader::obj_directory = ""; +std::string Loader::mtl_directory = ""; +std::string Loader::tex_directory = ""; + std::string* Loader::loadTextFile(const std::string &filename) { @@ -21,7 +33,7 @@ std::string* Loader::loadTextFile(const std::string &filename) Image* Loader::loadImage(const std::string &filename, bool hasAlpha) { sf::Image sfImg; - sfImg.loadFromFile(filename); + sfImg.loadFromFile(tex_directory+filename); Image* img = new Image(); img->depth = hasAlpha ? 32 : 24; img->width = sfImg.getSize().x; @@ -39,3 +51,285 @@ Image* Loader::loadImage(const std::string &filename, bool hasAlpha) } return img; } + +std::vector Loader::loadMesh(const std::string &filename){ + std::vector meshes; + + std::vector pos; + std::vector norm; + std::vector tex; + + std::string line; + + Material* defaultMat = RESOURCE_GET(Material, "default"); + + if(defaultMat == NULL) + { + defaultMat = new PhongMaterial(); + RESOURCE_ADD(defaultMat,Material,"default"); + } + Material* currentMat = defaultMat; + std::ifstream file(obj_directory + filename); + + if(!file.is_open()) + { + fprintf(stderr, "can't load %s.\n", filename.c_str()); + return meshes; + } + + Mesh* currentMesh = new Mesh(); + meshes.push_back(currentMesh); + currentMesh->setMaterial(currentMat); + + std::getline(file, line); + while(!file.eof()) + { + if(line.length() == 0) // line vide + { + std::getline(file, line); + continue; + } + + switch(line[0]) + { + case 'v': + //vertex attribute + switch(line[1]) + { + case ' ': // vertex position + { + glm::vec3 p; + std::sscanf(line.c_str(),"v %f %f %f",&(p.x),&(p.y),&(p.z)); + pos.push_back(p); + break; + } + case 't': // texCoord + { + glm::vec2 t; + std::sscanf(line.c_str(),"vt %f %f",&(t.x),&(t.y)); + tex.push_back(t); + break; + } + case 'n': // normal + { + glm::vec3 n; + std::sscanf(line.c_str(),"vn %f %f %f",&(n.x),&(n.y),&(n.z)); + norm.push_back(n); + break; + } + } + break; + case 'f': // face + { + int tab[9]; + std::sscanf(line.c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d",tab,tab+1,tab+2,tab+3,tab+4,tab+5,tab+6,tab+7,tab+8); + //TODO: check sscanf success + + int nb_vertices = currentMesh->positions3D.size(); + + currentMesh->addTriangle(nb_vertices, nb_vertices+1, nb_vertices+2); + for(int i=0; i<3; ++i) + { + if(norm.size() == 0) + { + if(tex.size() == 0) + currentMesh->addVertex(pos[tab[i]-1]); + else + currentMesh->addVertex(pos[tab[i]-1], tex[tab[i+1]-1]); + } + else + { + if(tex.size() == 0) + currentMesh->addVertex(pos[tab[i]-1], norm[tab[i+2]-1]); + else + currentMesh->addVertex(pos[tab[i]-1], norm[tab[i+2]-1], tex[tab[i+1]-1]); + } + } + } + break; + case 'g': + currentMesh = new Mesh(); + meshes.push_back(currentMesh); + currentMesh->setMaterial(currentMat); + break; + case 'm': // mtllib + { + char mat_filename[256]; + std::sscanf(line.c_str(),"mtllib %s",mat_filename); + loadMTL(std::string(mat_filename)); + break; + } + case 'u': + { + // usemtl + char mat_name[256]; + std::sscanf(line.c_str(),"usemtl %s",mat_name); + std::string material_name(mat_name); + currentMat = RESOURCE_GET(Material, material_name); + if(currentMat == NULL) + { + fprintf(stderr, "cannot find any material named : %s.\n", material_name.c_str()); + currentMat = new PhongMaterial(); + RESOURCE_ADD(currentMat,Material,material_name); + } + currentMesh->setMaterial(currentMat); + } + break; + default: + case '#': + // comment + break; + } + std::getline(file,line); + } + + for(std::size_t i=0; iindices.size() == 0) + { + meshes[i] = meshes.back(); + meshes.pop_back(); + --i; + } + } + return meshes; +} + + +//move this to an utils file ? +std::vector split(const std::string &line, char sep){ + std::vector tokens; + std::size_t start=0, end=0; + while((end = line.find(sep,start)) != std::string::npos){ + tokens.push_back(line.substr(start,end-start)); + start=end+1; + } + tokens.push_back(line.substr(start)); + return tokens; +} + +//load MTL +bool Loader::loadMTL(const std::string &filename) +{ + std::string line; + std::ifstream file(mtl_directory + filename); + + if(!file.is_open()) + { + fprintf(stderr, "can't load %s.\n", filename.c_str()); + return false; + } + + PhongMaterial* mat = NULL; + bool hasNormalMap = false; + + std::getline(file,line); + + while(!file.eof()) + { + if(line.length() == 0) + { + std::getline(file,line); + continue; + } + //QStringList tokens = line.split(' '); + std::vector tokens = split(line,' '); + + if(tokens[0].substr(0,1) == "#") + { + // this is a comment + } + else if((tokens[0] == "newmtl") && tokens.size() == 2) + { + mat = new PhongMaterial(); + RESOURCE_ADD(mat,Material,tokens[1]); + } + else if((tokens[0].compare("Ka") == 0) && tokens.size() == 4) + { + mat->ambient.r = std::stof(tokens[1]); + mat->ambient.g = std::stof(tokens[2]); + mat->ambient.b = std::stof(tokens[3]); + } + else if(tokens[0].compare("Kd") == 0 && tokens.size() == 4) + { + mat->diffuse.r = std::stof(tokens[1]); + mat->diffuse.g = std::stof(tokens[2]); + mat->diffuse.b = std::stof(tokens[3]); + } + else if(tokens[0].compare("Ks") == 0 && tokens.size() == 4) + { + mat->specular.r = std::stof(tokens[1]); + mat->specular.g = std::stof(tokens[2]); + mat->specular.b = std::stof(tokens[3]); + } + else if(tokens[0].compare("Ns") == 0 && tokens.size() == 2) + { + mat->shininess = std::stof(tokens[1]); + } + else if((tokens[0].substr(0,4) == "map_") && tokens.size() == 2) + { + if(tokens[0].compare("map_Ka") == 0){ + mat->ambient_texture = RESOURCE_GET(Texture,tokens[1]); + if (mat->ambient_texture == NULL){ + mat->ambient_texture = new Texture(loadImage(tokens[1])); + RESOURCE_ADD(mat->ambient_texture,Texture,tokens[1]); + } + } else if(tokens[0].compare("map_Kd") == 0) { + mat->diffuse_texture = RESOURCE_GET(Texture,tokens[1]); + if (mat->diffuse_texture == NULL){ + mat->diffuse_texture = new Texture(loadImage(tokens[1])); + RESOURCE_ADD(mat->diffuse_texture,Texture,tokens[1]); + } + } else if(tokens[0].compare("map_Ks") == 0) { + mat->specular_texture = RESOURCE_GET(Texture,tokens[1]); + if (mat->specular_texture == NULL){ + mat->specular_texture = new Texture(loadImage(tokens[1])); + RESOURCE_ADD(mat->specular_texture,Texture,tokens[1]); + } + } else if(tokens[0].compare("map_Normal") == 0) { + mat->normal_map = RESOURCE_GET(Texture,tokens[1]); + if (mat->normal_map == NULL){ + mat->normal_map = new Texture(loadImage(tokens[1])); + RESOURCE_ADD(mat->normal_map,Texture,tokens[1]); + } + hasNormalMap = true; + } else if(tokens[0].compare("map_d") == 0) { + mat->alpha_mask = RESOURCE_GET(Texture,tokens[1]); + if (mat->alpha_mask == NULL){ + mat->alpha_mask = new Texture(loadImage(tokens[1])); + RESOURCE_ADD(mat->alpha_mask,Texture,tokens[1]); + } + } else + fprintf(stderr, "unsupported material property : \"%s\"\n", tokens[0].c_str()); + } + else + fprintf(stderr, "unsupported material property : \"%s\"\n", tokens[0].c_str()); + + std::getline(file,line); + } + return hasNormalMap; +} + +void Loader::setObjDirectory(std::string dir_){ + obj_directory = dir_; +} +void Loader::setMtlDirectory(std::string dir_){ + mtl_directory = dir_; +} +void Loader::setTexDirectory(std::string dir_){ + tex_directory = dir_; +} + +/* +//glfinish +void temp_glfinish(){ + for(std::size_t i=0; iinitGL(); + todos[i].target = images[i]->texture; + delete images[i]; + } + } +} +*/ diff --git a/src/tools/loader.h b/src/tools/loader.h index 3afef05..7214602 100644 --- a/src/tools/loader.h +++ b/src/tools/loader.h @@ -2,14 +2,26 @@ #define LOADER_H #include +#include class Image; +class Mesh; class Loader { + static std::string obj_directory; + static std::string mtl_directory; + static std::string tex_directory; + public: static std::string* loadTextFile(const std::string &filename); static Image* loadImage(const std::string &filename, bool hasAlpha = true); + static std::vector loadMesh(const std::string &filename); + static bool loadMTL(const std::string &filename); + + static void setObjDirectory(std::string); + static void setMtlDirectory(std::string); + static void setTexDirectory(std::string); }; #endif // LOADER_H diff --git a/src/tools/pathfinder.cpp b/src/tools/pathfinder.cpp index e692459..f386b6d 100644 --- a/src/tools/pathfinder.cpp +++ b/src/tools/pathfinder.cpp @@ -3,59 +3,128 @@ #include #include #include +#include + //#include "fiboheap.h" PathFinder::PathFinder(){ } -std::vector PathFinder::a_star(GraphNode* start,GraphNode* goal) +std::vector PathFinder::a_star(GraphNode* start, GraphNode* goal, bool debug) { // Check if priorityqueue sort value in right order. - std::priority_queue frontier = std::priority_queue(); + std::priority_queue,ComparePriority> frontier = std::priority_queue,ComparePriority>(); std::map cost = std::map(); //cost of visited node std::map pred = std::map(); //pred of visited node + std::set visited = std::set(); + // init frontier, cost, and pred with value for start - PriorityNode* pn = new PriorityNode(); - pn->node = std::pair(start,0); - frontier.push(pn); + frontier.push(start); cost.insert(std::pair(start,0)); pred.insert(std::pair(start,NULL)); GraphNode* current; while(!frontier.empty()){ //pick best element from frontier (with priority queue the best is in front) - pn = frontier.top(); - current = pn->node.first; + current = frontier.top(); + //current = pn->node.first; frontier.pop(); + if (visited.count(current) == 0) + visited.insert(current); + else + continue; + if(debug) std::cout << "Exploring node " << current->getValue() << std::endl; // goal reached, end of a-star if (current == goal){ break; } // for all neighbours of current node - for (GraphEdge next : current->getNeighbours()){ - float new_cost = cost[current] + next.getWeight(); + for (GraphNode* next : current->getNeighbours()){ + float new_cost = cost[current] + current->cost(next); + if(debug) std::cout << "\tExploring neighbours node " << next->getValue() << " with cost " << new_cost << std::endl; - if ((cost.count(next.getTarget()) == 0) || (new_cost < cost[next.getTarget()])){ + if ((cost.count(next) == 0) || (new_cost < cost[next])){ // affect processed cost to next node in cost_map - cost[next.getTarget()] = new_cost; + cost[next] = new_cost; // calcul priority of node with heuristic,and add it to frontier - float priority = new_cost; //+ heuristic(next.getTarget(), goal); - PriorityNode* pn = new PriorityNode(); - pn->node = std::pair(next.getTarget(),priority); - frontier.push(pn); - + float priority = new_cost + next->heuristic(goal); + if(debug) std::cout << "\t\t Priority: " << priority << std::endl; + next->setPriority(priority); + visited.erase(next); + frontier.push(next); // memorize predecessor for next - pred[next.getTarget()] = current; + pred[next] = current; } } } + if(debug) std::cout << "path cost :" << cost[goal] << std::endl; + return backtrack_path(start,goal,pred); +} + +std::vector PathFinder::a_star_min_max(GraphNode* start,GraphNode* goal,bool debug) +{ + std::priority_queue,ComparePriority> frontier = std::priority_queue,ComparePriority>(); + std::map cost = std::map(); //cost of visited node + std::map pred = std::map(); //pred of visited node + + std::set visited = std::set(); + + // init frontier, cost, and pred with value for start + frontier.push(start); + cost.insert(std::pair(start,0)); + pred.insert(std::pair(start,NULL)); + + GraphNode* current; + while(!frontier.empty()){ + //pick best element from frontier (with priority queue the best is in front) + current = frontier.top(); + //current = pn->node.first; + frontier.pop(); + if (visited.count(current) == 0) + visited.insert(current); + else + continue; + + if(debug) std::cout << "Exploring node " << current->getValue() << std::endl; + // goal reached, end of a-star + if (current == goal){ + break; + } + + // for all neighbours of current node + for (GraphNode* next : current->getNeighbours()){ + float new_cost = std::max(cost[current],current->cost(next)); + if(debug) std::cout << "\tExploring neighbours node " << next->getValue() << " with cost " << new_cost << std::endl; + + if ((cost.count(next) == 0) || (new_cost < cost[next])){ + // affect processed cost to next node in cost_map + cost[next] = new_cost; + + // calcul priority of node with heuristic,and add it to frontier + float priority = new_cost + next->heuristic(goal); + if(debug) std::cout << "\t\t Priority: " << priority << std::endl; + next->setPriority(priority); + visited.erase(next); + frontier.push(next); + // memorize predecessor for next + pred[next] = current; + } + } + } + + if(debug) std::cout << "path cost :" << cost[goal] << std::endl; + return backtrack_path(start,goal,pred); +} + +std::vector PathFinder::backtrack_path(GraphNode* start,GraphNode* goal, std::map pred){ // reconstruct path by backtracking from goal to start std::vector path = std::vector(); + GraphNode* current = goal; while(current != start){ path.push_back(current); current = pred[current]; @@ -65,4 +134,7 @@ std::vector PathFinder::a_star(GraphNode* start,GraphNode* goal) return path; } - +bool ComparePriority::operator ()(GraphNode* a, GraphNode* b) +{ + return a->getPriority() > b->getPriority(); +} diff --git a/src/tools/pathfinder.h b/src/tools/pathfinder.h index d4a3d94..45a429f 100644 --- a/src/tools/pathfinder.h +++ b/src/tools/pathfinder.h @@ -2,22 +2,23 @@ #define PATHFINDER_H #include +#include #include "graph.h" class PathFinder { +private: + static std::vector backtrack_path(GraphNode* start,GraphNode* goal, std::map pred); + public: PathFinder(); - static std::vector a_star(GraphNode* start,GraphNode* goal); + static std::vector a_star(GraphNode* start,GraphNode* goal,bool debug = false); + static std::vector a_star_min_max(GraphNode* start,GraphNode* goal,bool debug = false); + }; -struct PriorityNode -{ - std::pair node; - bool operator<(PriorityNode other) const - { - return node.second < other.node.second; - } +class ComparePriority{ +public: + bool operator() (GraphNode*,GraphNode*s); }; - #endif // PATHFINDER_H