From a168f51fbdf8ff99adae07467e86055e54e2ed7e Mon Sep 17 00:00:00 2001 From: det-fys Date: Fri, 29 Dec 2023 20:03:34 +0100 Subject: [PATCH] pathfinding --- main/scripts/autoexec.lua | 7 +- main/scripts/definitions/tsrecsmeta.lua | 31 +++++- main/scripts/npc.lua | 71 ++++++++++++ main/scripts/player.lua | 2 +- src/tsr/camera.cpp | 10 +- src/tsr/entity.cpp | 16 +++ src/tsr/entity_cct.cpp | 72 +++++++++++-- src/tsr/entity_cct.hpp | 12 ++- src/tsr/game.cpp | 22 +++- src/tsr/game.hpp | 12 ++- src/tsr/paths.cpp | 138 ++++++++++++++++++++++++ src/tsr/paths.hpp | 33 ++++++ src/tsr/renderer.cpp | 10 ++ src/tsr/renderer.hpp | 5 + src/tsr/tsr.hpp | 3 + src/tsr/worldmap.cpp | 70 ++++++++---- src/tsr/worldmap.hpp | 23 ++-- tsrecs.vcxproj | 2 + tsrecs.vcxproj.filters | 6 ++ 19 files changed, 496 insertions(+), 49 deletions(-) create mode 100644 main/scripts/npc.lua create mode 100644 src/tsr/paths.cpp create mode 100644 src/tsr/paths.hpp diff --git a/main/scripts/autoexec.lua b/main/scripts/autoexec.lua index a812d1a..aeafde4 100644 --- a/main/scripts/autoexec.lua +++ b/main/scripts/autoexec.lua @@ -1,6 +1,7 @@ g_require("scripts/thread.lua") g_require("scripts/input.lua") g_require("scripts/player.lua") +g_require("scripts/npc.lua") print("autoexec") @@ -24,4 +25,8 @@ onkeypress["KEY_T"] = function () end playercamera = not playercamera -end \ No newline at end of file +end + +for i = 1, 10 do + spawnnpc(1 + i, 1, 0, player) +end diff --git a/main/scripts/definitions/tsrecsmeta.lua b/main/scripts/definitions/tsrecsmeta.lua index ca4b07b..36ee9c9 100644 --- a/main/scripts/definitions/tsrecsmeta.lua +++ b/main/scripts/definitions/tsrecsmeta.lua @@ -64,6 +64,18 @@ function i_setcontrolcallback(callback) end ---@return number function ent_spawn(x, y, z, pitch, yaw, roll, sx, sy, sz) end +---@param ent1 number +---@param ent2 number +---@return number +function ent_distance(ent1, ent2) end + +---@param ent number +---@param x number +---@param y number +---@param z number +---@return number +function ent_distanceto(ent, x, y, z) end + --- Model ---@param ent number @@ -120,11 +132,10 @@ function cct_getforwardxz(ent) end ---@param ent number ---@param x number ----@param y number ---@param z number ---@param speed number ---@return nil -function cct_turnto(ent, x, y, z, speed) end +function cct_turnto(ent, x, z, speed) end ---@param ent number ---@param angle number @@ -137,4 +148,18 @@ function cct_turntoangle(ent, angle, speed) end ---@param y number ---@param z number ---@return nil -function cct_move(ent, x, y, z) end \ No newline at end of file +function cct_move(ent, x, y, z) end + +---@param ent number +---@param x number +---@param y number +---@param z number +---@return boolean +function cct_findpath(ent, x, y, z) end + +---@param ent number +---@return boolean found +---@return number x +---@return number y +---@return number z +function cct_getnextpathnode(ent) end \ No newline at end of file diff --git a/main/scripts/npc.lua b/main/scripts/npc.lua new file mode 100644 index 0000000..a6faf71 --- /dev/null +++ b/main/scripts/npc.lua @@ -0,0 +1,71 @@ +g_require("scripts/thread.lua") + +function spawnnpc(x, y, z, follow) + local npc = ent_spawn(x, y, z, 0, 0, 0, 1, 1, 1) + mdl_set(npc, "models/test_skeletal.mdl.json") + mdl_anim(npc, "init", 0, 0) + mdl_anim(npc, "stand", 0, 0) + cct_add(npc, 0.25, 1.2) + + local tick = 1 / g_gettps() + + local function disttonode(ent, node_x, node_z) + local _, ent_y, _ = cct_getpos(ent) + return ent_distanceto(ent, node_x, ent_y, node_z) + end + + thread(function () + while true do + wait(1) + + if ent_distance(npc, follow) > 10 then + local follow_x, follow_y, follow_z = cct_getpos(follow) + local path_found = cct_findpath(npc, follow_x, follow_y, follow_z) + + print("path found: ", path_found) + if path_found then + mdl_anim(npc, "walk2", 6, 0.2) + + local walk = true + while walk do + local next_node, node_x, node_y, node_z = cct_getnextpathnode(npc) + print("nextnode: ", next_node, node_x, node_y, node_z) + + if not next_node then + break + end + + while disttonode(npc, node_x, node_z) > 1 do + if ent_distance(npc, follow) < 5 then + walk = false + break + end + + + cct_turnto(npc, node_x, node_z, 3) + local move_x = 0 + local move_y = -3.0 + local move_z = 0 + + move_x, move_z = cct_getforwardxz(npc) + + cct_move(npc, move_x * tick * 3, move_y * tick * 3, move_z * tick * 3) + local new_x, new_y, new_z = cct_getpos(npc) + local dist = ent_distanceto(npc, new_x, new_y, new_z) + + -- blocked + if dist < tick * 0.2 then + walk = false + break + end + + + wait(0) + end + end + mdl_stopanim(npc, "walk2", 0.1) + end + end + end + end) +end diff --git a/main/scripts/player.lua b/main/scripts/player.lua index dcf610e..0a750ee 100644 --- a/main/scripts/player.lua +++ b/main/scripts/player.lua @@ -31,7 +31,7 @@ function setupplayer(ent) local move_y = -3.0 local move_z = 0 - local movespeed = 3.0 + local movespeed = 10.0 if fb ~= 0 or rl ~= 0 then local foward_x, forward_z = g_getcameraforwardxz() diff --git a/src/tsr/camera.cpp b/src/tsr/camera.cpp index 86adfdd..7a9c6a8 100644 --- a/src/tsr/camera.cpp +++ b/src/tsr/camera.cpp @@ -3,7 +3,7 @@ using namespace TSR; -void TSR::Camera::UpdateVectors() { +void Camera::UpdateVectors() { auto yaw_rad = glm::radians(yaw); auto pitch_rad = glm::radians(pitch); front_vector = glm::normalize(glm::vec3(cos(yaw_rad) * glm::cos(pitch_rad), glm::sin(pitch_rad), glm::sin(yaw_rad) * glm::cos(pitch_rad))); @@ -12,7 +12,7 @@ void TSR::Camera::UpdateVectors() { up_vector = glm::normalize(glm::cross(right_vector, front_vector)); } -TSR::Camera::Camera(glm::vec3 i_position, float i_movement_speed, float i_mouse_sensitivity, float i_third_person_distance, float i_yaw, float i_pitch) : +Camera::Camera(glm::vec3 i_position, float i_movement_speed, float i_mouse_sensitivity, float i_third_person_distance, float i_yaw, float i_pitch) : position(i_position), movement_speed(i_movement_speed), mouse_sensitivity(i_mouse_sensitivity), @@ -24,7 +24,7 @@ TSR::Camera::Camera(glm::vec3 i_position, float i_movement_speed, float i_mouse_ UpdateVectors(); } -glm::mat4 TSR::Camera::GetViewMatrix(bool firstperson) { +glm::mat4 Camera::GetViewMatrix(bool firstperson) { float space = 0.3f; auto dist = firstperson ? 0.0f : third_person_distance; @@ -48,7 +48,7 @@ glm::mat4 TSR::Camera::GetViewMatrix(bool firstperson) { return glm::lookAt(position - front_vector * dist, position + front_vector, up_vector); } -void TSR::Camera::ProcessMovement(Movement direction, float time) { +void Camera::ProcessMovement(Movement direction, float time) { float diff = movement_speed * time; switch (direction) { case Movement::FORWARD: @@ -72,7 +72,7 @@ void TSR::Camera::ProcessMovement(Movement direction, float time) { } } -void TSR::Camera::ProcessMouse(float x_offset, float y_offset) { +void Camera::ProcessMouse(float x_offset, float y_offset) { yaw += x_offset * mouse_sensitivity; //pitch = std::min(89.0f, std::max(-89.0f, pitch + y_offset * mouse_sensitivity)); pitch = std::min(89.9f, std::max(-89.9f, pitch + y_offset * mouse_sensitivity)); diff --git a/src/tsr/entity.cpp b/src/tsr/entity.cpp index 54ba2de..1dd9f4a 100644 --- a/src/tsr/entity.cpp +++ b/src/tsr/entity.cpp @@ -30,4 +30,20 @@ void EntitySystem::RegisterLuaFunctions() { LuaAPI::RegisterFunction("ent_despawn", [](entt::entity ent) { EntitySystem::Despawn(ent); }); + + LuaAPI::RegisterFunction("ent_distance", [](entt::entity ent, entt::entity other) { + auto& reg = Game::Registry(); + auto& trans1 = reg.get(ent); + auto& trans2 = reg.get(other); + + return glm::distance(trans1.trans.pos, trans2.trans.pos); + }); + + LuaAPI::RegisterFunction("ent_distanceto", [](entt::entity ent, float x, float y, float z) { + auto& reg = Game::Registry(); + auto& trans1 = reg.get(ent); + glm::vec3 pos(x, y, z); + + return glm::distance(trans1.trans.pos, pos); + }); } diff --git a/src/tsr/entity_cct.cpp b/src/tsr/entity_cct.cpp index 33e0e95..ac7ead5 100644 --- a/src/tsr/entity_cct.cpp +++ b/src/tsr/entity_cct.cpp @@ -58,9 +58,10 @@ static bool CCTTurnToAngle(CCTComponent& comp, float target, float speed) { } } -static bool CCTTurnTo(CCTComponent& comp, const glm::vec3& pos, float step) { - auto diff = pos - CCTGetPos(comp); - auto target = std::atan2(pos.x, pos.z); +static bool CCTTurnTo(CCTComponent& comp, const glm::vec2& pos, float step) { + auto self_pos = CCTGetPos(comp); + auto diff = pos - glm::vec2(self_pos.x, self_pos.z); + auto target = std::atan2(diff.x, diff.y); return CCTTurnToAngle(comp, target, step); } @@ -135,7 +136,7 @@ glm::vec3 CCTSystem::GetForward(entt::entity ent) { return glm::vec3(std::sin(comp.angle), 0.0f, std::cos(comp.angle)); } -bool CCTSystem::TurnTo(entt::entity ent, const glm::vec3& pos, float speed) { +bool CCTSystem::TurnTo(entt::entity ent, const glm::vec2& pos, float speed) { auto& reg = Game::Registry(); auto& comp = reg.get(ent); @@ -149,6 +150,30 @@ bool CCTSystem::TurnToAngle(entt::entity ent, float target, float speed) { return CCTTurnToAngle(comp, target, speed); } +bool CCTSystem::FindPath(entt::entity ent, const glm::vec3& end) { + auto& reg = Game::Registry(); + auto& comp = reg.get(ent); + + auto start = CCTGetPos(comp); + start.y += 0.5f; + + return Game::Map().GetNodeGraph().FindPath(start, end, comp.path); +} + +bool CCTSystem::GetNextPathNode(entt::entity ent, glm::vec3& node) { + auto& reg = Game::Registry(); + auto& comp = reg.get(ent); + + if (comp.path.empty()) + return false; + + node = comp.path.back(); + comp.path.pop_back(); + + return true; +} + + void CCTSystem::Update() { auto& reg = Game::Registry(); @@ -161,7 +186,26 @@ void CCTSystem::Update() { } -void TSR::CCTSystem::RegisterLuaFunctions() { +void CCTSystem::DebugDraw(Renderer& renderer) { + auto& reg = Game::Registry(); + + auto v = reg.view(); + for (auto [ent, cct, trans] : v.each()) { + if (cct.path.empty()) + return; + + glm::vec3 start_pos = CCTGetPos(cct); + + for (int i = cct.path.size() - 1; i > 0; --i) { + auto& node = cct.path[i]; + renderer.AddDebugLine(start_pos, node, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f)); + start_pos = node; + } + } + +} + +void CCTSystem::RegisterLuaFunctions() { LuaAPI::RegisterFunction("cct_add", [](entt::entity ent, float radius, float height) { CCTSystem::AddCCT(ent, radius, height); }); @@ -190,12 +234,24 @@ void TSR::CCTSystem::RegisterLuaFunctions() { return std::make_tuple(forward.x, forward.z); }); - LuaAPI::RegisterFunction("cct_turnto", [](entt::entity ent, float x, float y, float z, float speed) { - auto pos = glm::vec3(x, y, z); - return CCTSystem::TurnTo(ent, pos, speed); + LuaAPI::RegisterFunction("cct_turnto", [](entt::entity ent, float x, float z, float speed) { + return CCTSystem::TurnTo(ent, glm::vec2(x, z), speed); }); LuaAPI::RegisterFunction("cct_turntoangle", [](entt::entity ent, float angle, float speed) { return CCTSystem::TurnToAngle(ent, angle, speed); }); + + LuaAPI::RegisterFunction("cct_findpath", [](entt::entity ent, float x, float y, float z) { + auto pos = glm::vec3(x, y, z); + return CCTSystem::FindPath(ent, pos); + }); + + LuaAPI::RegisterFunction("cct_getnextpathnode", [](entt::entity ent) { + glm::vec3 node; + if (CCTSystem::GetNextPathNode(ent, node)) + return std::make_tuple(true, node.x, node.y, node.z); + else + return std::make_tuple(false, 0.0f, 0.0f, 0.0f); + }); } diff --git a/src/tsr/entity_cct.hpp b/src/tsr/entity_cct.hpp index 6d99351..919ab0d 100644 --- a/src/tsr/entity_cct.hpp +++ b/src/tsr/entity_cct.hpp @@ -1,5 +1,6 @@ #pragma once #include "entity.hpp" +#include "paths.hpp" namespace TSR { @@ -14,6 +15,8 @@ namespace TSR { PxController* cct; float angle; + std::vector path; + CCTComponent(float radius, float height, const glm::vec3& pos); CCTComponent(const CCTComponent& other) = delete; ~CCTComponent(); @@ -24,17 +27,22 @@ namespace TSR { public: static void AddCCT(entt::entity ent, float radius, float height); static void RemoveCCT(entt::entity ent); + static int Move(entt::entity ent, const glm::vec3& disp, float dt); static void SetPos(entt::entity ent, const glm::vec3& pos); static glm::vec3 GetPos(entt::entity ent); - static glm::vec3 GetForward(entt::entity ent); - static bool TurnTo(entt::entity ent, const glm::vec3& pos, float step); + static bool TurnTo(entt::entity ent, const glm::vec2& pos, float step); static bool TurnToAngle(entt::entity ent, float target, float step); + static bool FindPath(entt::entity ent, const glm::vec3& end); + static bool GetNextPathNode(entt::entity ent, glm::vec3& node); + static void Update(); + static void DebugDraw(Renderer& renderer); + static void RegisterLuaFunctions(); }; diff --git a/src/tsr/game.cpp b/src/tsr/game.cpp index c2e5245..20c7c21 100644 --- a/src/tsr/game.cpp +++ b/src/tsr/game.cpp @@ -25,6 +25,7 @@ float Game::s_frame_t = 0.0f; int Game::s_tps = 50; bool Game::s_debug_draw = false; +int Game::s_debug_mode = DEBUG_ALL; static Camera cam; @@ -164,6 +165,19 @@ void Game::Run() { s_physics_scene->EnableDebug(s_debug_draw); break; } + + if (key != GLFW_KEY_F1 && Window::KeyDown(GLFW_KEY_F1)) { + switch (key) { + case GLFW_KEY_P: + s_debug_mode ^= DEBUG_PHYSICS; + break; + case GLFW_KEY_C: + s_debug_mode ^= DEBUG_CCT; + break; + } + + } + } if (action == GLFW_PRESS || action == GLFW_RELEASE) @@ -250,9 +264,15 @@ void Game::ClFrame(Renderer& renderer, float frame_t) { ModelSystem::Render(renderer); s_map->Draw(renderer); - if (s_debug_draw) + if (DebugEnabled(DEBUG_PHYSICS)) s_physics_scene->DrawDebug(renderer); + if (DebugEnabled(DEBUG_CCT)) + CCTSystem::DebugDraw(renderer); + + if (DebugEnabled(DEBUG_NODES)) + s_map->GetNodeGraph().DebugDraw(renderer); + if (s_skybox_model) s_skybox_model->Draw(renderer, nullptr); diff --git a/src/tsr/game.hpp b/src/tsr/game.hpp index cde4824..d26b0b5 100644 --- a/src/tsr/game.hpp +++ b/src/tsr/game.hpp @@ -19,6 +19,14 @@ namespace TSR { LuaReference callback; }; + enum DebugMode : int { + DEBUG_NONE, + DEBUG_PHYSICS = 1 << 0, + DEBUG_CCT = 1 << 1, + DEBUG_NODES = 1 << 2, + DEBUG_ALL = DEBUG_PHYSICS | DEBUG_CCT | DEBUG_NODES + }; + class Game { static entt::registry s_registry; @@ -32,22 +40,24 @@ namespace TSR { static int s_tps; static bool s_debug_draw; + static int s_debug_mode; static void StartGame(const std::string& map_name); static void EndGame(); public: - static void Run(); static void SvFrame(); static void ClFrame(Renderer& renderer, float frame_t); static entt::registry& Registry() { return s_registry; } static PhysicsScene& Physics() { return *s_physics_scene; } + static const WorldMap& Map() { return *s_map; } static uint64_t FrameNum() { return s_sv_frame; } static float FrameT() { return s_frame_t; } static int TPS() { return s_tps; } + static bool DebugEnabled(DebugMode mode) { return s_debug_draw && (s_debug_mode & mode); } static void RegisterLuaFunctions(); diff --git a/src/tsr/paths.cpp b/src/tsr/paths.cpp new file mode 100644 index 0000000..89631db --- /dev/null +++ b/src/tsr/paths.cpp @@ -0,0 +1,138 @@ +#include "paths.hpp" +#include + +using namespace TSR; + +int NodeGraph::FindClosestNode(const glm::vec3& position) const { + float min_dist = std::numeric_limits::max(); + int min_node = -1; + + for (int i = 0; i < m_nodes.size(); ++i) { + auto& node = m_nodes[i]; + auto dist = glm::distance(node.position, position); + + if (dist < min_dist) { + min_dist = dist; + min_node = i; + } + } + + return min_node; +} + +// This is a helper function to calculate the heuristic cost between two vectors +static float Heuristic(const glm::vec3& a, const glm::vec3& b) { + //return std::sqrt(std::pow(a.x - b.x, 2) + std::pow(a.y - b.y, 2) + std::pow(a.z - b.z, 2)); + return glm::distance(a, b); +} + +//using Heuristic = glm::distance; + + +NodeGraph::NodeGraph() { + + +} + +void NodeGraph::AddNode(const glm::vec3& position) { + m_nodes.push_back(PathNode(position)); +} + +void NodeGraph::Build(std::function test_reach_cb) { + for (int i = 0; i < m_nodes.size(); ++i) { + for (int j = 0; j < m_nodes.size(); ++j) { + if (i == j) + continue; + + auto& node = m_nodes[i]; + auto& other_node = m_nodes[j]; + + if (glm::distance(node.position, other_node.position) > 10.0f) + continue; + + if (test_reach_cb(node.position, other_node.position)) + node.reachable_nodes[node.num_reachable_nodes++] = j; + + if (node.num_reachable_nodes == TSR_MAX_REACHABLE_PATHNODES) + break; + } + + + } + +} + +bool NodeGraph::FindPath(const glm::vec3& start, const glm::vec3& end, std::vector& path) const { + auto start_id = FindClosestNode(start); + auto end_id = FindClosestNode(end); + + // Create a map to store the costs of visiting each node + std::unordered_map cost_so_far; + + // Create a map to store the best known path to each node + std::unordered_map came_from; + + // Create a priority queue to store the nodes to be explored, + // with the cost as the priority + std::priority_queue, std::vector>, std::greater>> frontier; + + // Add the start node to the queue with a cost of 0 + frontier.emplace(0, start_id); + cost_so_far[start_id] = 0; + + // Loop until the queue is empty + while (!frontier.empty()) { + // Get the node with the lowest cost + int current_id = frontier.top().second; + frontier.pop(); + + // If we have reached the end, construct the path and return it + if (current_id == end_id) { + //std::vector path; + path.clear(); + while (current_id != start_id) { + path.emplace_back(m_nodes[current_id].position); + current_id = came_from[current_id]; + } + //path.emplace_back(m_nodes[start_id].position); + //std::reverse(path.begin(), path.end()); + return true; + } + + // Explore all of the reachable nodes from the current node + for (int i = 0; i < m_nodes[current_id].num_reachable_nodes; ++i) { + int next_id = m_nodes[current_id].reachable_nodes[i]; + + // Calculate the cost to reach this node + float new_cost = cost_so_far[current_id] + 1; // Add 1 as a simple distance heuristic + + // If this node has not been visited or if the new cost is lower than the previous cost, + // update the cost and add it to the queue + if (!cost_so_far.contains(next_id) || new_cost < cost_so_far[next_id]) { + cost_so_far[next_id] = new_cost; + float priority = new_cost + Heuristic(m_nodes[end_id].position, m_nodes[next_id].position); // Add the heuristic cost to the priority queue + frontier.emplace(priority, next_id); + came_from[next_id] = current_id; + } + } + + } + + // If we couldn't find a path, return an empty vector + return {}; + + + return false; +} + +void NodeGraph::DebugDraw(Renderer& renderer) const { + for (int i = 0; i < m_nodes.size(); ++i) { + auto& node = m_nodes[i]; + renderer.AddDebugPoint(node.position, glm::vec3(1.0f, 0.0f, 1.0f)); + + for (int j = 0; j < node.num_reachable_nodes; ++j) { + auto& other_node = m_nodes[node.reachable_nodes[j]]; + renderer.AddDebugLine(node.position, other_node.position, glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + } + } +} diff --git a/src/tsr/paths.hpp b/src/tsr/paths.hpp new file mode 100644 index 0000000..54fa2de --- /dev/null +++ b/src/tsr/paths.hpp @@ -0,0 +1,33 @@ +#pragma once +#include "tsr.hpp" +#include "renderer.hpp" + +namespace TSR { + + struct PathNode { + glm::vec3 position; + int num_reachable_nodes; + int reachable_nodes[TSR_MAX_REACHABLE_PATHNODES]; + + PathNode(const glm::vec3& position) : position(position), num_reachable_nodes(0) {} + }; + + class NodeGraph { + std::vector m_nodes; + + int FindClosestNode(const glm::vec3& position) const; + + public: + NodeGraph(); + + void AddNode(const glm::vec3& position); + void Build(std::function test_reach_cb); + + //void FindPath(const glm::vec3& start, const glm::vec3& end, std::vector& path) const; + + bool FindPath(const glm::vec3& start, const glm::vec3& end, std::vector& path) const; + const glm::vec3& GetNodePosition(int id) const { return m_nodes[id].position; } + + void DebugDraw(Renderer& renderer) const; + }; +} diff --git a/src/tsr/renderer.cpp b/src/tsr/renderer.cpp index 9f83f4b..9f47b9c 100644 --- a/src/tsr/renderer.cpp +++ b/src/tsr/renderer.cpp @@ -586,6 +586,15 @@ void Renderer::Render(int width, int height) { m_debug_vao.Draw(m_debug_lines, true); } + if (!m_debug_points.empty()) { + //glStencilFunc(GL_ALWAYS, 0, 0xFF); + m_shader_debug.Use(); + glUniformMatrix4fv(m_shader_debug.U(SU_VP), 1, GL_FALSE, glm::value_ptr(mat_vp)); + + glPointSize(10); + m_debug_vao.Draw(m_debug_points, false); + } + // SKYBOX if (!m_draw_lists[RT_SKYBOX].empty()) { m_shader_skybox.Use(); @@ -647,4 +656,5 @@ void Renderer::Render(int width, int height) { m_draw_lists[i].clear(); m_debug_lines.clear(); + m_debug_points.clear(); } diff --git a/src/tsr/renderer.hpp b/src/tsr/renderer.hpp index 14c708c..42fe78b 100644 --- a/src/tsr/renderer.hpp +++ b/src/tsr/renderer.hpp @@ -288,6 +288,7 @@ namespace TSR { std::vector m_draw_lists[RT_COUNT]; std::vector m_debug_lines; + std::vector m_debug_points; Shader m_shader_basic; Shader m_shader_basic_instanced; @@ -328,6 +329,10 @@ namespace TSR { m_debug_lines.push_back({ p2, color2 }); } + void AddDebugPoint(const glm::vec3& p, const glm::vec3& color = glm::vec3(1.0f)) { + m_debug_points.push_back({ p, color }); + } + void SetViewMatrix(const glm::mat4& view_matrix) { m_view_matrix = view_matrix; } diff --git a/src/tsr/tsr.hpp b/src/tsr/tsr.hpp index f6b7580..9f759c4 100644 --- a/src/tsr/tsr.hpp +++ b/src/tsr/tsr.hpp @@ -24,6 +24,9 @@ #define TSR_NUM_COLORS 4 +#define TSR_MAX_REACHABLE_PATHNODES 32 + + #define U8(_S) (const char*)u8##_S namespace TSR { diff --git a/src/tsr/worldmap.cpp b/src/tsr/worldmap.cpp index f6d998c..be395d2 100644 --- a/src/tsr/worldmap.cpp +++ b/src/tsr/worldmap.cpp @@ -48,9 +48,9 @@ int WorldMap::LoadNext() { PhysicalObject phyobj; ctx.model_matrix = glm::rotate(glm::translate(glm::mat4(1.0f), pos), glm::radians(rot), glm::vec3(0.0f, 1.0f, 0.0f)); - phyobj.m_transform = PxTransform(PxMat44(glm::value_ptr(ctx.model_matrix))); + phyobj.transform = PxTransform(PxMat44(glm::value_ptr(ctx.model_matrix))); ctx.model_matrix = glm::scale(ctx.model_matrix, glm::vec3(scale)); - phyobj.m_scale = scale; + phyobj.scale = scale; for (int i = 0; i < 4; ++i) { auto& cns = color_strs[i]; @@ -58,8 +58,8 @@ int WorldMap::LoadNext() { ctx.colors[i] = JsonGetVec<4>(j_object.at(cns)); } - model_instances.m_contexts.push_back(ctx); - model_instances.m_physical_objects.push_back(phyobj); + model_instances.contexts.push_back(ctx); + model_instances.physical_object.push_back(phyobj); } m_loading_iter = m_loading_obj_data.cbegin(); @@ -73,7 +73,7 @@ int WorldMap::LoadNext() { case LoadingPhase::MODELS: { if (m_loading_iter == m_loading_obj_data.cend()) { - m_loading_phase = LoadingPhase::FINISHED; + m_loading_phase = LoadingPhase::PATHNODES; m_loading_obj_data.clear(); return 100; } @@ -83,21 +83,21 @@ int WorldMap::LoadNext() { auto s = AssetMap::Get(models.first); - if (models.second.m_contexts.size() > 4) { + if (models.second.contexts.size() > 4) { MapObject obj; - obj.m_model = s; - obj.m_ctx.ssbo = std::make_unique(models.second.m_contexts); + obj.model = s; + obj.ctx.ssbo = std::make_unique(models.second.contexts); m_objects_instanced.push_back(std::move(obj)); } else { - for (const auto& instance : models.second.m_contexts) { + for (const auto& instance : models.second.contexts) { MapObject obj; - obj.m_model = s; - obj.m_ctx.model_matrix = instance.model_matrix; + obj.model = s; + obj.ctx.model_matrix = instance.model_matrix; for (int i = 0; i < 4; i++) - obj.m_ctx.colors[i] = instance.colors[i]; + obj.ctx.colors[i] = instance.colors[i]; m_objects.push_back(std::move(obj)); } @@ -108,9 +108,9 @@ int WorldMap::LoadNext() { auto material = AssetMap::Get("physics/default.material.json"); auto& shape = s->TriMesh(); - for (const auto& phyobj : models.second.m_physical_objects) { - PxRigidStatic* actor = Physics::GetPhysics()->createRigidStatic(phyobj.m_transform); - PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxTriangleMeshGeometry(shape.Get(), PxMeshScale(phyobj.m_scale)), *material->Get()); + for (const auto& phyobj : models.second.physical_object) { + PxRigidStatic* actor = Physics::GetPhysics()->createRigidStatic(phyobj.transform); + PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxTriangleMeshGeometry(shape.Get(), PxMeshScale(phyobj.scale)), *material->Get()); m_physics_scene->GetScene()->addActor(*actor); @@ -121,15 +121,15 @@ int WorldMap::LoadNext() { else if (s->Shape() == SHAPE_BOX) { auto material = AssetMap::Get("physics/default.material.json"); - for (const auto& phyobj : models.second.m_physical_objects) { - auto transform = phyobj.m_transform; + for (const auto& phyobj : models.second.physical_object) { + auto transform = phyobj.transform; auto size = s->ShapeSize(); auto offset = s->ShapeOffset(); - transform.p = transform.p + PxVec3(offset.x * phyobj.m_scale, offset.y * phyobj.m_scale, offset.z * phyobj.m_scale); + transform.p = transform.p + PxVec3(offset.x * phyobj.scale, offset.y * phyobj.scale, offset.z * phyobj.scale); PxRigidStatic* actor = Physics::GetPhysics()->createRigidStatic(transform); - PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxBoxGeometry(size.x * phyobj.m_scale, size.y * phyobj.m_scale, size.z * phyobj.m_scale), *material->Get()); + PxShape* px_shape = PxRigidActorExt::createExclusiveShape(*actor, PxBoxGeometry(size.x * phyobj.scale, size.y * phyobj.scale, size.z * phyobj.scale), *material->Get()); m_physics_scene->GetScene()->addActor(*actor); } @@ -142,6 +142,38 @@ int WorldMap::LoadNext() { break; } + case LoadingPhase::PATHNODES: + { + auto j_map = nlohmann::json::parse(Filesystem::Read(m_map_path)); + + if (j_map.contains("pathnodes")) { + auto j_pathnodes = j_map.at("pathnodes"); + + for (const auto& j_pathnode : j_pathnodes) { + auto pos = JsonGetVec<3>(j_pathnode); + m_node_graph.AddNode(pos); + } + + m_node_graph.Build([this](const glm::vec3& a, const glm::vec3& b) { + auto dir = glm::normalize(b - a); + auto dist = glm::distance(a, b); + + PxRaycastBuffer hit; + bool status = m_physics_scene->GetScene()->raycast(PxVec3(a.x, a.y, a.z), PxVec3(dir.x, dir.y, dir.z), dist, hit); + + if (status) + return false; + + return true; + }); + + } + + m_loading_phase = LoadingPhase::FINISHED; + return 100; + break; + } + case LoadingPhase::FINISHED: return 100; break; diff --git a/src/tsr/worldmap.hpp b/src/tsr/worldmap.hpp index a7a0af9..8c1f291 100644 --- a/src/tsr/worldmap.hpp +++ b/src/tsr/worldmap.hpp @@ -5,6 +5,7 @@ #include "window.hpp" #include "tsr.hpp" #include "physics.hpp" +#include "paths.hpp" namespace TSR { @@ -18,17 +19,18 @@ namespace TSR { FIRST, PARSE, MODELS, + PATHNODES, FINISHED, } m_loading_phase; struct PhysicalObject { - PxTransform m_transform; - float m_scale; + PxTransform transform; + float scale; }; struct ModelInstances { - std::vector m_contexts; - std::vector m_physical_objects; + std::vector contexts; + std::vector physical_object; }; using LoadingObjData = std::map; @@ -39,13 +41,15 @@ namespace TSR { // final struct MapObject { - DrawCtx m_ctx; - AssetPtr m_model; + DrawCtx ctx; + AssetPtr model; }; std::vector m_objects; std::vector m_objects_instanced; + NodeGraph m_node_graph; + public: WorldMap(const std::string& map_path, PhysicsScene* physics_scene); @@ -56,11 +60,14 @@ namespace TSR { void Draw(Renderer& r) const { for (const auto& obj : m_objects) - obj.m_model->Draw(r, &obj.m_ctx); + obj.model->Draw(r, &obj.ctx); for (const auto& obj : m_objects_instanced) - obj.m_model->DrawInstanced(r, &obj.m_ctx); + obj.model->DrawInstanced(r, &obj.ctx); } + + const NodeGraph& GetNodeGraph() const { return m_node_graph; } + }; diff --git a/tsrecs.vcxproj b/tsrecs.vcxproj index 1c86ea3..434886b 100644 --- a/tsrecs.vcxproj +++ b/tsrecs.vcxproj @@ -129,6 +129,7 @@ + @@ -147,6 +148,7 @@ + diff --git a/tsrecs.vcxproj.filters b/tsrecs.vcxproj.filters index 038e269..c62a964 100644 --- a/tsrecs.vcxproj.filters +++ b/tsrecs.vcxproj.filters @@ -63,6 +63,9 @@ Source Files + + Source Files + @@ -116,5 +119,8 @@ Header Files + + Header Files + \ No newline at end of file