From 3897bb4326e3bbe850b2bcda34f44b610c4ff52b Mon Sep 17 00:00:00 2001 From: Rene Date: Thu, 21 Nov 2024 16:43:47 +0100 Subject: [PATCH 1/2] Add Pathfinder Code to resolve files instead of hard coding paths. --- CMakeLists.txt | 20 ++--- resources/config.h.in | 4 + src/Colormap.cpp | 9 +-- src/PathFinder.cpp | 97 ++++++++++++++++++++++++ src/PathFinder.h | 9 +++ src/Renderer.cpp | 4 - src/main.cpp | 7 +- src/pipelines/ImagePipeline.cpp | 7 +- src/pipelines/InstancingPipeline.cpp | 7 +- src/pipelines/LinePipeline.cpp | 7 +- src/pipelines/PostProcessingPipeline.cpp | 7 +- 11 files changed, 132 insertions(+), 46 deletions(-) create mode 100644 resources/config.h.in create mode 100644 src/PathFinder.cpp create mode 100644 src/PathFinder.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 29ae811..e242b17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ option(USE_HIGH_PERFORMANCE_GPU "Use high performance GPU, most likely a discret if (USE_HIGH_PERFORMANCE_GPU) add_compile_definitions(WGPU_GPU_HIGH_PERFORMANCE="ON") endif() +configure_file(resources/config.h.in config/config.h) add_executable(Template src/implementations.cpp @@ -37,6 +38,7 @@ add_executable(Template src/Camera.cpp src/Colormap.h src/Colormap.cpp + src/PathFinder.cpp ) target_compile_definitions(Template PRIVATE @@ -71,24 +73,12 @@ file(GLOB_RECURSE UTIL_HEADERS ) target_sources(Template PRIVATE ${UTIL_SOURCES} ${UTIL_HEADERS}) -if(DEV_MODE) - # In dev mode, we load resources from the source tree, so that when we - # dynamically edit resources (like shaders), these are correctly - # versionned. - target_compile_definitions(Template PRIVATE - RESOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}/resources" - ) -else() - # In release mode, we just load resources relatively to wherever the - # executable is launched from, so that the binary is portable - target_compile_definitions(Template PRIVATE - RESOURCE_DIR="./resources" - ) -endif() - target_include_directories(Template PRIVATE .) target_include_directories(Template PRIVATE src) target_include_directories(Template PRIVATE thirdparty) +target_include_directories(Template PRIVATE ${CMAKE_BINARY_DIR}) +# message(STATUS ${CMAKE_CURRENT_SOURCE_DIR}) +# message(STATUS ${CMAKE_BINARY_DIR}) target_link_libraries(Template PRIVATE glfw webgpu glfw3webgpu imgui) diff --git a/resources/config.h.in b/resources/config.h.in new file mode 100644 index 0000000..544364a --- /dev/null +++ b/resources/config.h.in @@ -0,0 +1,4 @@ +#pragma once +#include +std::string sourceDirectory = "@CMAKE_SOURCE_DIR@"; +std::string buildDirectory = "@CMAKE_BINARY_DIR@"; diff --git a/src/Colormap.cpp b/src/Colormap.cpp index 832d3cd..e7be16a 100644 --- a/src/Colormap.cpp +++ b/src/Colormap.cpp @@ -3,10 +3,6 @@ #include #include -#ifndef RESOURCE_DIR -#define RESOURCE_DIR "this will be defined by cmake depending on the build type. This define is to disable error squiggles" -#endif - std::map Colormap::indices; std::vector Colormap::names; ResourceManager::Image Colormap::colormaps; @@ -42,9 +38,10 @@ glm::vec3 Colormap::operator()(float value) return color(value); } +#include "PathFinder.h" void Colormap::init() { - std::filesystem::path path = RESOURCE_DIR "/colormaps.txt"; + std::filesystem::path path = resolveFile("resources/colormaps.txt"); std::ifstream file(path); if (!file.is_open()) { @@ -62,6 +59,6 @@ void Colormap::init() indices[line] = offset; offset++; } - path = RESOURCE_DIR "/colormaps.png"; + path = resolveFile("resources/colormaps.png"); colormaps = ResourceManager::loadImage(path); } diff --git a/src/PathFinder.cpp b/src/PathFinder.cpp new file mode 100644 index 0000000..4dc69e3 --- /dev/null +++ b/src/PathFinder.cpp @@ -0,0 +1,97 @@ +#include +#include +#include +#include "PathFinder.h" +#include + +std::filesystem::path expand(std::filesystem::path in) { + namespace fs = std::filesystem; +#ifndef _WIN32 + if (in.string().size() < 1) return in; + + const char * home = getenv("HOME"); + if (home == NULL) { + std::cerr << "error: HOME variable not set." << std::endl; + throw std::invalid_argument("error: HOME environment variable not set."); + } + + std::string s = in.string(); + if (s[0] == '~') { + s = std::string(home) + s.substr(1, s.size() - 1); + return fs::path(s); + } + else { + return in; + } +#else + if (in.string().size() < 1) return in; + + const char * home = getenv("USERPROFILE"); + if (home == NULL) { + std::cerr << "error: USERPROFILE variable not set." << std::endl; + throw std::invalid_argument("error: USERPROFILE environment variable not set."); + } + + std::string s = in.string(); + if (s[0] == '~') { + s = std::string(home) + s.substr(1, s.size() - 1); + return fs::path(s); + } + else { + return in; + } +#endif + +} + +std::filesystem::path workingDirectory; +std::filesystem::path binaryDirectory; + +std::filesystem::path resolveFile(std::string fileName, std::vector search_paths) { + namespace fs = std::filesystem; + fs::path working_dir = workingDirectory; + fs::path binary_dir = binaryDirectory; + fs::path source_dir = sourceDirectory; + fs::path build_dir = buildDirectory; + + fs::path expanded = expand(fs::path(fileName)); + + fs::path base_path = ""; + if (fs::exists(expand(fs::path(fileName)))) + return expand(fs::path(fileName)); + for (const auto& path : search_paths){ + auto p = expand(fs::path(path)); + if (fs::exists(p / fileName)) + return p.string() + std::string("/") + fileName; +} + + if (fs::exists(fileName)) return fs::path(fileName); + if (fs::exists(expanded)) + return expanded; + + for (const auto &pathi : search_paths) { + auto path = expand(fs::path(pathi)); + if (fs::exists(working_dir / path / fileName)) + return (working_dir / path / fileName).string(); + if (fs::exists(binary_dir / path / fileName)) + return (binary_dir / path / fileName).string(); + if (fs::exists(source_dir / path / fileName)) + return (source_dir / path / fileName).string(); + if (fs::exists(build_dir / path / fileName)) + return (build_dir / path / fileName).string(); + } + + if (fs::exists(working_dir / fileName)) + return (working_dir / fileName); + if (fs::exists(binary_dir / fileName)) + return (binary_dir / fileName); + if (fs::exists(source_dir / fileName)) + return (source_dir / fileName); + if (fs::exists(build_dir / fileName)) + return (build_dir / fileName); + + std::stringstream sstream; + sstream << "File '" << fileName << "' could not be found in any provided search path" << std::endl; + std::cerr << sstream.str(); + throw std::runtime_error(sstream.str().c_str()); +} diff --git a/src/PathFinder.h b/src/PathFinder.h new file mode 100644 index 0000000..2320b9b --- /dev/null +++ b/src/PathFinder.h @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +std::filesystem::path expand(std::filesystem::path in); +std::filesystem::path resolveFile(std::string fileName, std::vector search_paths = {}); + +extern std::filesystem::path workingDirectory; +extern std::filesystem::path binaryDirectory; \ No newline at end of file diff --git a/src/Renderer.cpp b/src/Renderer.cpp index eca32f2..0b66c2d 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -13,10 +13,6 @@ using namespace wgpu; -#ifndef RESOURCE_DIR -#define RESOURCE_DIR "this will be defined by cmake depending on the build type. This define is to disable error squiggles" -#endif - Renderer::Renderer() { initWindowAndDevice(); diff --git a/src/main.cpp b/src/main.cpp index 0ce42ed..b225378 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,13 @@ #include "Renderer.h" #include "Simulator.h" +#include "PathFinder.h" -int main(int, char **) +int main(int argc, char ** argv) { + namespace fs = std::filesystem; + workingDirectory = fs::absolute(fs::path(argv[0])).remove_filename(); + binaryDirectory = fs::current_path(); + Renderer renderer = Renderer(); Simulator simulator(renderer); diff --git a/src/pipelines/ImagePipeline.cpp b/src/pipelines/ImagePipeline.cpp index 198a2e8..41e6a33 100644 --- a/src/pipelines/ImagePipeline.cpp +++ b/src/pipelines/ImagePipeline.cpp @@ -1,9 +1,6 @@ #include "ImagePipeline.h" #include "Colormap.h" - -#ifndef RESOURCE_DIR -#define RESOURCE_DIR "this will be defined by cmake depending on the build type. This define is to disable error squiggles" -#endif +#include "PathFinder.h" using namespace wgpu; @@ -12,7 +9,7 @@ bool ImagePipeline::init(Device &device, TextureFormat &swapChainFormat, Queue & this->device = device; this->queue = queue; this->swapChainFormat = swapChainFormat; - shaderModule = ResourceManager::loadShaderModule(RESOURCE_DIR "/image_shader.wgsl", device); + shaderModule = ResourceManager::loadShaderModule(resolveFile("resources/image_shader.wgsl"), device); RenderPipelineDescriptor pipelineDesc; pipelineDesc.label = "Image pipeline"; diff --git a/src/pipelines/InstancingPipeline.cpp b/src/pipelines/InstancingPipeline.cpp index 9b6bbd0..5ea6608 100644 --- a/src/pipelines/InstancingPipeline.cpp +++ b/src/pipelines/InstancingPipeline.cpp @@ -1,12 +1,9 @@ #include "InstancingPipeline.h" #include "Renderer.h" +#include "PathFinder.h" #include #include -#ifndef RESOURCE_DIR -#define RESOURCE_DIR "this will be defined by cmake depending on the build type. This define is to disable error squiggles" -#endif - using namespace wgpu; using PrimitiveVertexAttributes = ResourceManager::PrimitiveVertexAttributes; using InstancedVertexAttributes = ResourceManager::InstancedVertexAttributes; @@ -17,7 +14,7 @@ void InstancingPipeline::init(Device &device, Queue &queue, TextureFormat &swapC this->lightingUniforms = lightingUniforms; this->device = device; this->queue = queue; - shaderModule = ResourceManager::loadShaderModule(RESOURCE_DIR "/instancing_shader.wgsl", device); + shaderModule = ResourceManager::loadShaderModule(resolveFile("resources/instancing_shader.wgsl"), device); RenderPipelineDescriptor pipelineDesc; std::vector lineVertexAttribs(2); diff --git a/src/pipelines/LinePipeline.cpp b/src/pipelines/LinePipeline.cpp index 4ca391b..eb122e2 100644 --- a/src/pipelines/LinePipeline.cpp +++ b/src/pipelines/LinePipeline.cpp @@ -1,9 +1,6 @@ #include "LinePipeline.h" #include "Renderer.h" - -#ifndef RESOURCE_DIR -#define RESOURCE_DIR "this will be defined by cmake depending on the build type. This define is to disable error squiggles" -#endif +#include "PathFinder.h" using namespace wgpu; using LineVertexAttributes = ResourceManager::LineVertexAttributes; @@ -14,7 +11,7 @@ void LinePipeline::init(Device &device, Queue &queue, TextureFormat &swapChainFo this->lightingUniforms = lightingUniforms; this->device = device; this->queue = queue; - shaderModule = ResourceManager::loadShaderModule(RESOURCE_DIR "/line_shader.wgsl", device); + shaderModule = ResourceManager::loadShaderModule(resolveFile("resources/line_shader.wgsl"), device); RenderPipelineDescriptor pipelineDesc; // This is for instanced rendering diff --git a/src/pipelines/PostProcessingPipeline.cpp b/src/pipelines/PostProcessingPipeline.cpp index 731d63f..d00e0fe 100644 --- a/src/pipelines/PostProcessingPipeline.cpp +++ b/src/pipelines/PostProcessingPipeline.cpp @@ -1,16 +1,13 @@ #include "PostProcessingPipeline.h" #include "ResourceManager.h" - -#ifndef RESOURCE_DIR -#define RESOURCE_DIR "this will be defined by cmake depending on the build type. This define is to disable error squiggles" -#endif +#include "PathFinder.h" using namespace wgpu; bool PostProcessingPipeline::init(Device &device, TextureFormat &swapChainFormat, TextureView &textureView) { this->device = device; - shaderModule = ResourceManager::loadShaderModule(RESOURCE_DIR "/post_processing.wgsl", device); + shaderModule = ResourceManager::loadShaderModule(resolveFile("resources/post_processing.wgsl"), device); RenderPipelineDescriptor pipelineDesc; pipelineDesc.label = "Post process pipeline"; From bdaeffc605ab458fa6bfce56ccf027797ce924e4 Mon Sep 17 00:00:00 2001 From: Rene Date: Wed, 11 Dec 2024 15:17:36 +0100 Subject: [PATCH 2/2] Fixed collision detection that just returned the closest vertex to the origin in most cases. This was obviously wrong. --- src/util/CollisionDetection.cpp | 38 +++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/util/CollisionDetection.cpp b/src/util/CollisionDetection.cpp index fb027a2..9553ffe 100644 --- a/src/util/CollisionDetection.cpp +++ b/src/util/CollisionDetection.cpp @@ -184,14 +184,14 @@ namespace collisionTools } } - vec3 handleVertexToface(const mat4 &worldFromObj, const vec3 &toCenter) - { + vec3 handleVertexToface(const mat4 &worldFromObj, const vec3 &toCenter, const vec3 &normal) { std::vector corners = getCorners(worldFromObj); - float min = 1000; + float min = std::numeric_limits::max(); vec3 vertex; for (int i = 0; i < corners.size(); i++) { - float value = glm::dot(corners[i], toCenter); + auto relativePosition = corners[i] - toCenter; + float value = glm::dot(relativePosition, normal); if (value < min) { vertex = corners[i]; @@ -213,25 +213,33 @@ namespace collisionTools int fromWhere = -1; bool bestSingleAxis = false; vec3 toCenter = getVectorConnnectingCenters(worldFromObj_A, worldFromObj_B); + const vec3 worldCenter_A = worldFromObj_A * vec4(0, 0, 0, 1); + const vec3 worldCenter_B = worldFromObj_B * vec4(0, 0, 0, 1); + std::vector axes1 = getAxisNormalToFaces(worldFromObj_A); std::vector axes2 = getAxisNormalToFaces(worldFromObj_B); std::vector axes3 = getPairOfEdges(worldFromObj_A, worldFromObj_B); // loop over the axes1 + std::vector overlappingAxes; + std::vector overlaps; for (int i = 0; i < axes1.size(); i++) { // project both shapes onto the axis Projection p1 = project(worldFromObj_A, axes1[i]); Projection p2 = project(worldFromObj_B, axes1[i]); // do the projections overlap? - if (!overlap(p1, p2)) + auto overlapping = overlap(p1, p2); + if (!overlapping) { // then we can guarantee that the shapes do not overlap - return info; + //return info; } else { // get the overlap float o = getOverlap(p1, p2); + overlaps.push_back(o); + overlappingAxes.push_back(i); // check for minimum if (o < smallOverlap) { @@ -253,12 +261,14 @@ namespace collisionTools if (!overlap(p1, p2)) { // then we can guarantee that the shapes do not overlap - return info; + // return info; } else { // get the overlap float o = getOverlap(p1, p2); + overlaps.push_back(o); + overlappingAxes.push_back(i + axes1.size()); // check for minimum if (o < smallOverlap) { @@ -282,12 +292,14 @@ namespace collisionTools if (!overlap(p1, p2)) { // then we can guarantee that the shapes do not overlap - return info; + // return info; } else { // get the overlap float o = getOverlap(p1, p2); + overlaps.push_back(o); + overlappingAxes.push_back(i + axes1.size() + axes2.size()); // check for minimum if (o < smallOverlap) { @@ -300,6 +312,10 @@ namespace collisionTools } } } + if (overlappingAxes.size() != axes1.size() + axes2.size() + axes3.size()) + { + return info; + } // if we get here then we know that every axis had overlap on it // so we can guarantee an intersection vec3 normal; @@ -308,11 +324,11 @@ namespace collisionTools case 0: { normal = axis; - if (glm::dot(axis, toCenter) <= 0) + if (glm::dot(axis, toCenter) >= 0) { normal = -normal; } - collisionPoint = handleVertexToface(worldFromObj_B, toCenter); + collisionPoint = handleVertexToface(worldFromObj_B, worldCenter_A, -normal); } break; case 1: @@ -322,7 +338,7 @@ namespace collisionTools { normal = -normal; } - collisionPoint = handleVertexToface(worldFromObj_A, toCenter * -1.0f); + collisionPoint = handleVertexToface(worldFromObj_A, worldCenter_B, -normal); } break; case 2: