diff options
| -rw-r--r-- | include/utils.hpp | 32 | ||||
| -rw-r--r-- | src/main.cpp | 29 | ||||
| -rw-r--r-- | src/utils.cpp | 90 |
3 files changed, 143 insertions, 8 deletions
diff --git a/include/utils.hpp b/include/utils.hpp index 52f3297..cbc92b3 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -1,11 +1,11 @@ -#ifndef __UTILS_HPP_ -#define __UTILS_HPP_ +#pragma once #include <vector> #include <functional> +#include <unordered_map> +#include <string> std::vector<uint8_t> read_file(const char* path); -std::vector<uint8_t> read_file(std::string& path); #define PI 3.14159265359 #define EPSILON 0.000001 @@ -36,6 +36,28 @@ inline float clamp(float x, float min, float max) { return x; } -void watch_file(std::filesystem::path&& filepath, std::function<void()>&& callback); +#include <windows.h> -#endif // !__UTILS_HPP_ +#if defined(WINDOWS) +void log_last_error(); +#endif + +class watcher { +public: + static bool watch_file(std::filesystem::path&& filepath, std::function<void()> callback); + + static bool watch_dir(std::filesystem::path&& dir_path); + + static void pull_changes(); + +private: + + struct watch_data { + HANDLE dir_handle; + OVERLAPPED overlapped; + DWORD buffer[512]; + }; + + inline static std::unordered_map<std::string, std::function<void()>> callbacks; + inline static std::unordered_map<std::string, watch_data> watched_dirs; +}; diff --git a/src/main.cpp b/src/main.cpp index 1c83ce8..368a429 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ #include "scene.hpp" #include "vk-renderer.hpp" #include "window.hpp" +#include "utils.hpp" #include "Tracy.hpp" @@ -79,7 +80,31 @@ int main() { auto main_scene = scene(cam, width, height, renderer); auto *raytracing_pass = renderer.create_compute_renderpass(); - raytracing_pass->set_pipeline(raytracing_shader_name); + raytracing_pass->set_pipeline("compute"); + + watcher::watch_file(std::filesystem::path("../shaders/compute.comp"), [&]() { + LPSTR cmd_line = "glslc.exe --target-env=vulkan1.2 -std=460 ../shaders/compute.comp -o shaders/compute.comp.spv -I \"../shaders/include\"\0"; + STARTUPINFO start_info {}; + PROCESS_INFORMATION proc_info {}; + if (FAILED(CreateProcessA( + nullptr, + cmd_line, + nullptr, + nullptr, + FALSE, + 0, + nullptr, + nullptr, + &start_info, + &proc_info + ))) + log_last_error(); + WaitForSingleObject(proc_info.hProcess, INFINITE); + CloseHandle(proc_info.hProcess); + CloseHandle(proc_info.hThread); + + raytracing_pass->set_pipeline("compute"); + }); auto *accumulation_texture = renderer.create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT); auto *output_texture = renderer.create_2d_texture(width, height, VK_FORMAT_R32G32B32A32_SFLOAT); @@ -124,6 +149,8 @@ int main() { io.DeltaTime = delta_time; + watcher::pull_changes(); + wnd.poll_events(); for (auto &event : wnd.events) { diff --git a/src/utils.cpp b/src/utils.cpp index dc5791c..9994064 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -45,6 +45,92 @@ std::vector<uint8_t> read_file(const char* path) { return file_content; } -std::vector<uint8_t> read_file(std::string& path) { - return read_file(path.c_str()); + +#ifdef WINDOWS +void log_last_error() { + auto error_code = GetLastError(); + const char* error_message = nullptr; + + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + error_code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &error_message, + 0, + nullptr + ); + + std::cerr << error_message << std::endl; } + +bool watcher::watch_file(std::filesystem::path&& filepath, std::function<void()> callback) { + if (!std::filesystem::exists(filepath)) + return false; + + if (!watcher::watch_dir(filepath.parent_path())) + return false; + + auto [_, is_inserted] = watcher::callbacks.emplace(filepath.filename().string(), callback); + + return is_inserted; +} + +bool watcher::watch_dir(std::filesystem::path&& dir_path) { + if (!std::filesystem::exists(dir_path)) + return false; + + if (watcher::watched_dirs.find(dir_path.string()) != watcher::watched_dirs.end()) + return true; + + HANDLE dir_handle = CreateFileW( + dir_path.c_str(), + FILE_LIST_DIRECTORY, + FILE_SHARE_WRITE | FILE_SHARE_READ, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, + nullptr + ); + + if(dir_handle == INVALID_HANDLE_VALUE) { + log_last_error(); + return false; + } + + auto [dir, _] = watcher::watched_dirs.emplace(dir_path.string(), watch_data{ .dir_handle = dir_handle }); + + if (FAILED(ReadDirectoryChangesW(dir_handle, dir->second.buffer, sizeof(watch_data::buffer), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, nullptr, &dir->second.overlapped, nullptr))) { + log_last_error(); + return false; + } + + return true; +} + +void watcher::pull_changes() { + for (auto& dir : watcher::watched_dirs) { + auto& watch_data = dir.second; + if (!HasOverlappedIoCompleted(&watch_data.overlapped)) + continue; + + auto* dir_event = (PFILE_NOTIFY_INFORMATION)watch_data.buffer; + do { + if (dir_event->Action == FILE_ACTION_MODIFIED) { + auto w_filename = std::wstring{ dir_event->FileName, dir_event->FileNameLength / sizeof(wchar_t) }; + auto filename = std::string{w_filename.begin(), w_filename.end()}; + if (callbacks.contains(filename)) + callbacks[filename](); + } + + dir_event += dir_event->NextEntryOffset; + } while(dir_event->NextEntryOffset != 0); + + if (FAILED(ReadDirectoryChangesW(watch_data.dir_handle, watch_data.buffer, sizeof(watch_data::buffer), FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, nullptr, &watch_data.overlapped, nullptr))) { + log_last_error(); + } + } +} +#endif |
